Coverage Report

Created: 2026-10-13 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/commands/menu.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-only
2
// SPDX-FileCopyrightText: © 2009-2010 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
3
4
#include <common.h>
5
#include <command.h>
6
#include <readkey.h>
7
#include <menu.h>
8
#include <getopt.h>
9
#include <errno.h>
10
#include <libbb.h>
11
#include <linux/err.h>
12
13
typedef enum {
14
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
15
  action_add,
16
  action_remove,
17
  action_select,
18
#endif
19
  action_list,
20
  action_show,
21
} menu_action;
22
23
struct cmd_menu {
24
  char    *menu;
25
  menu_action action;
26
  char    *description;
27
  int   auto_select;
28
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
29
  int   entry;
30
  int   re_entrant;
31
  char    *command;
32
  char    *submenu;
33
  int   num;
34
  menu_entry_type type;
35
  int   box_state;
36
#endif
37
};
38
39
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
40
0
#define OPTS    "m:earlc:d:RsSn:u:A:b:B:"
41
0
#define is_entry(x) ((x)->entry)
42
#else
43
#define OPTS    "m:lsA:d:"
44
#define is_entry(x) (0)
45
#endif
46
47
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
48
/*
49
 * menu -e -a -m <menu> -c <command> [-R] [-b 0|1 ] -d <description>
50
 * menu -e -a -m <menu> -u submenu -d [-b 0|1] <description>
51
 */
52
static int do_menu_entry_add(struct cmd_menu *cm)
53
0
{
54
0
  struct menu_entry *me;
55
0
  struct menu *m;
56
57
0
  if (!cm->menu || (!cm->command && !cm->submenu) || !cm->description)
58
0
    return -EINVAL;
59
60
0
  m = menu_get_by_name(cm->menu);
61
62
0
  if (!m) {
63
0
    eprintf("Menu '%s' not found\n", cm->menu);
64
0
    return -EINVAL;
65
0
  }
66
67
0
  if (cm->submenu)
68
0
    me = menu_add_submenu(m, cm->submenu, cm->description);
69
0
  else
70
0
    me = menu_add_command_entry(m, cm->description, cm->command,
71
0
              cm->type);
72
0
  if (IS_ERR(me))
73
0
    return PTR_ERR(me);
74
75
0
  me->box_state = cm->box_state > 0 ? 1 : 0;
76
77
0
  if (!cm->submenu)
78
0
    me->non_re_ent = !cm->re_entrant;
79
80
0
  return 0;
81
0
}
82
83
/*
84
 * menu -e -r -m <name> -n <num>
85
 */
86
static int do_menu_entry_remove(struct cmd_menu *cm)
87
0
{
88
0
  struct menu *m;
89
0
  struct menu_entry *me;
90
91
0
  if (!cm->menu || cm->num < 0)
92
0
    return -EINVAL;
93
94
0
  m = menu_get_by_name(cm->menu);
95
96
0
  if (!m) {
97
0
    eprintf("Menu '%s' not found\n", cm->menu);
98
0
    return -EINVAL;
99
0
  }
100
101
0
  me = menu_entry_get_by_num(m, cm->num);
102
103
0
  if (!me) {
104
0
    eprintf("Entry '%i' not found\n", cm->num);
105
0
    return -EINVAL;
106
0
  }
107
108
0
  menu_remove_entry(m, me);
109
110
0
  menu_entry_free(me);
111
112
0
  return 0;
113
0
}
114
115
/*
116
 * menu -a -m <name> -d <description>
117
 */
118
static int do_menu_add(struct cmd_menu *cm)
119
0
{
120
0
  struct menu *m;
121
0
  int ret = -ENOMEM;
122
123
0
  if (!cm->menu || !cm->description)
124
0
    return -EINVAL;
125
126
0
  m = menu_alloc();
127
128
0
  if (!m)
129
0
    goto free;
130
131
0
  m->name = strdup_const(cm->menu);
132
0
  if (!m->name)
133
0
    goto free;
134
135
0
  menu_add_title(m, cm->description);
136
137
0
  ret = menu_add(m);
138
139
0
  if (ret)
140
0
    goto free;
141
142
0
  return 0;
143
144
0
free:
145
0
  eprintf("Menu '%s' add fail", cm->menu);
146
0
  if (ret == -EEXIST)
147
0
    eprintf(" already exist");
148
0
  eprintf("\n");
149
150
0
  menu_free(m);
151
152
0
  return ret;
153
0
}
154
/*
155
 * menu -r -m <name>
156
 */
157
static int do_menu_remove(struct cmd_menu *cm)
158
0
{
159
0
  struct menu *m;
160
161
0
  m = menu_get_by_name(cm->menu);
162
163
0
  if (!m) {
164
0
    eprintf("Menu '%s' not found\n", cm->menu);
165
0
    return -EINVAL;
166
0
  }
167
168
0
  menu_remove(m);
169
170
0
  menu_free(m);
171
172
0
  return 0;
173
0
}
174
175
/*
176
 * menu -m <menu> -S -n <entry num starting at 1>
177
 */
178
static int do_menu_select(struct cmd_menu *cm)
179
0
{
180
0
  struct menu *m;
181
182
0
  if (cm->num < 0)
183
0
    return -EINVAL;
184
185
0
  m = menu_get_by_name(cm->menu);
186
187
0
  if (!m) {
188
0
    eprintf("Menu '%s' not found\n", cm->menu);
189
0
    return -EINVAL;
190
0
  }
191
192
0
  if (menu_set_selected(m, cm->num) < 0) {
193
0
    eprintf("Entry '%d' not found\n", cm->num);
194
0
    return -EINVAL;
195
0
  }
196
197
0
  return 0;
198
0
}
199
#endif
200
201
/*
202
 * menu -s -m <menu> [-A <auto select delay>] [-d <display]
203
 */
204
static int do_menu_show(struct cmd_menu *cm)
205
0
{
206
0
  struct menu *m;
207
208
0
  if (cm->menu)
209
0
    m = menu_get_by_name(cm->menu);
210
0
  else
211
0
    m = menu_get_by_name("boot");
212
213
0
  if (!m)
214
0
    return -EINVAL;
215
216
0
  if (cm->auto_select != -EINVAL) {
217
0
    menu_set_auto_select(m, cm->auto_select);
218
219
0
    free_const(m->auto_display);
220
221
0
    m->auto_display = strdup_const(cm->description);
222
0
  }
223
224
0
  return menu_show(m);
225
0
}
226
227
static void print_entries(struct menu *m)
228
0
{
229
0
  struct menu_entry *me;
230
231
0
  list_for_each_entry(me, &m->entries, list)
232
0
    printf("%d: %s\n", me->num, me->display);
233
0
}
234
235
/*
236
 * menu -l
237
 * menu -e -l [menu]
238
 */
239
static int do_menu_list(struct cmd_menu *cm)
240
0
{
241
0
  struct menu* m = NULL;
242
0
  struct menu* menus = menu_get_menus();
243
244
0
  if (!menus)
245
0
    return 0;
246
247
0
  if (is_entry(cm)) {
248
0
    if (cm->menu)
249
0
      m = menu_get_by_name(cm->menu);
250
251
0
    if (m) {
252
0
      print_entries(m);
253
0
      return 0;
254
0
    }
255
0
  }
256
257
0
  list_for_each_entry(m, &menus->list, list) {
258
0
    printf("%s: ", m->name);
259
0
    if (m->display_lines) {
260
0
      static char outstr[256];
261
0
      int i;
262
263
0
      printf("\n");
264
0
      for (i = 0; i < m->display_lines; i++)
265
        /* Conform to menu rendering logic */
266
0
        if (IS_ENABLED(CONFIG_SHELL_HUSH)) {
267
0
          process_escape_sequence(m->display[i], outstr, 256);
268
0
          printf("\t%s\n", outstr);
269
0
        } else {
270
0
          printf("\t%s\n", m->display[i]);
271
0
        }
272
0
    } else {
273
0
      printf("%s\n", m->name);
274
0
    }
275
0
    if (is_entry(cm))
276
0
      print_entries(m);
277
0
  }
278
279
0
  return 0;
280
0
}
281
282
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
283
static int do_menu_entry(struct cmd_menu *cm)
284
0
{
285
0
  switch(cm->action) {
286
0
  case action_list:
287
0
    return do_menu_list(cm);
288
0
  case action_remove:
289
0
    return do_menu_entry_remove(cm);
290
0
  case action_add:
291
0
    return do_menu_entry_add(cm);
292
0
  case action_select:
293
0
  case action_show:
294
0
    break;
295
0
  }
296
0
  return -EINVAL;
297
0
}
298
#else
299
static int do_menu_entry(struct cmd_menu *cm)
300
{
301
  return -EINVAL;
302
}
303
#endif
304
305
static int do_menu(int argc, char *argv[])
306
0
{
307
0
  struct cmd_menu cm;
308
0
  int opt;
309
0
  int ret = -EINVAL;
310
311
0
  if (!argc)
312
0
    return COMMAND_ERROR_USAGE;
313
314
0
  memset(&cm, 0, sizeof(struct cmd_menu));
315
0
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
316
0
  cm.num = -EINVAL;
317
0
  cm.auto_select = -EINVAL;
318
0
#endif
319
320
0
  cm.action = action_show;
321
322
0
  while((opt = getopt(argc, argv, OPTS)) > 0) {
323
0
    switch(opt) {
324
0
    case 'm':
325
0
      cm.menu = optarg;
326
0
      break;
327
0
    case 'l':
328
0
      cm.action = action_list;
329
0
      break;
330
0
    case 's':
331
0
      cm.action = action_show;
332
0
      break;
333
0
    case 'A':
334
0
      cm.auto_select = simple_strtoul(optarg, NULL, 10);
335
0
      break;
336
0
    case 'd':
337
0
      cm.description = optarg;
338
0
      break;
339
0
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
340
0
    case 'e':
341
0
      cm.entry = 1;
342
0
      break;
343
0
    case 'a':
344
0
      cm.action = action_add;
345
0
      break;
346
0
    case 'r':
347
0
      cm.action = action_remove;
348
0
      break;
349
0
    case 'c':
350
0
      cm.command = optarg;
351
0
      break;
352
0
    case 'u':
353
0
      cm.submenu = optarg;
354
0
      break;
355
0
    case 'R':
356
0
      cm.re_entrant = 1;
357
0
      break;
358
0
    case 'S':
359
0
      cm.action = action_select;
360
0
      break;
361
0
    case 'n':
362
0
      cm.num = simple_strtoul(optarg, NULL, 10);
363
0
      break;
364
0
    case 'b':
365
0
      cm.type = MENU_ENTRY_BOX;
366
0
      cm.box_state = simple_strtoul(optarg, NULL, 10);
367
0
      break;
368
0
    case 'B':
369
0
      cm.command = optarg;
370
0
      break;
371
0
#endif
372
0
    default:
373
0
      return 1;
374
0
    }
375
0
  }
376
377
0
  if (is_entry(&cm)) {
378
0
    ret = do_menu_entry(&cm);
379
0
    goto end;
380
0
  }
381
382
0
  switch(cm.action) {
383
0
  case action_list:
384
0
    ret = do_menu_list(&cm);
385
0
    break;
386
0
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
387
0
  case action_remove:
388
0
    ret = do_menu_remove(&cm);
389
0
    break;
390
0
  case action_add:
391
0
    ret = do_menu_add(&cm);
392
0
    break;
393
0
  case action_select:
394
0
    ret = do_menu_select(&cm);
395
0
    break;
396
0
#endif
397
0
  case action_show:
398
0
    ret = do_menu_show(&cm);
399
0
    break;
400
0
  }
401
402
0
end:
403
0
  if (ret)
404
0
    return 0;
405
406
0
  return 1;
407
0
}
408
409
BAREBOX_CMD_HELP_START(menu)
410
BAREBOX_CMD_HELP_TEXT("Manage Menu:")
411
BAREBOX_CMD_HELP_OPT ("-m", "menu")
412
BAREBOX_CMD_HELP_OPT ("-l", "list")
413
BAREBOX_CMD_HELP_OPT ("-s", "show")
414
BAREBOX_CMD_HELP_TEXT("")
415
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
416
BAREBOX_CMD_HELP_TEXT("Advanced menu management:")
417
BAREBOX_CMD_HELP_OPT ("-e", "menu entry")
418
BAREBOX_CMD_HELP_OPT ("-a", "add")
419
BAREBOX_CMD_HELP_OPT ("-r", "remove")
420
BAREBOX_CMD_HELP_OPT ("-S", "select")
421
BAREBOX_CMD_HELP_TEXT("")
422
#endif
423
BAREBOX_CMD_HELP_TEXT("Show menu:")
424
BAREBOX_CMD_HELP_OPT ("-A", "auto select delay")
425
BAREBOX_CMD_HELP_OPT ("-d", "auto select description")
426
BAREBOX_CMD_HELP_TEXT("\tmenu -s -m MENU [-A delay] [-d auto_display]")
427
BAREBOX_CMD_HELP_TEXT("")
428
BAREBOX_CMD_HELP_TEXT("List menu:")
429
BAREBOX_CMD_HELP_TEXT("\tmenu -l\n")
430
BAREBOX_CMD_HELP_TEXT("")
431
#if defined(CONFIG_CMD_MENU_MANAGEMENT)
432
BAREBOX_CMD_HELP_TEXT("Add a menu:")
433
BAREBOX_CMD_HELP_TEXT("\tmenu -a -m NAME -d DESC")
434
BAREBOX_CMD_HELP_TEXT("")
435
BAREBOX_CMD_HELP_TEXT("Remove a menu:")
436
BAREBOX_CMD_HELP_TEXT("\tmenu -r -m NAME")
437
BAREBOX_CMD_HELP_TEXT("")
438
BAREBOX_CMD_HELP_TEXT("Add an entry:")
439
BAREBOX_CMD_HELP_TEXT("\t(-R for do no exit the menu after executing the command)")
440
BAREBOX_CMD_HELP_TEXT("\t(-b for box style 1 for selected)")
441
BAREBOX_CMD_HELP_TEXT("\t(and optional -c for the command to run when we change the state)")
442
BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m MENU -c COMMAND [-R] [-b 0|1] -d DESC")
443
BAREBOX_CMD_HELP_TEXT("")
444
BAREBOX_CMD_HELP_TEXT("Add a submenu entry:")
445
BAREBOX_CMD_HELP_TEXT("\t(-R is not needed)")
446
BAREBOX_CMD_HELP_TEXT("\t(-b for box style 1 for selected)")
447
BAREBOX_CMD_HELP_TEXT("\t(and -c is not needed)")
448
BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m MENU -u submenu -d [-b 0|1] DESC")
449
BAREBOX_CMD_HELP_TEXT("")
450
BAREBOX_CMD_HELP_TEXT("Remove an entry:")
451
BAREBOX_CMD_HELP_TEXT("\tmenu -e -r -m NAME -n ENTRY")
452
BAREBOX_CMD_HELP_TEXT("")
453
BAREBOX_CMD_HELP_TEXT("Select an entry:")
454
BAREBOX_CMD_HELP_TEXT("\tmenu -m <menu> -S -n ENTRY")
455
BAREBOX_CMD_HELP_TEXT("")
456
BAREBOX_CMD_HELP_TEXT("List menu:")
457
BAREBOX_CMD_HELP_TEXT("\tmenu -e -l [menu]")
458
BAREBOX_CMD_HELP_TEXT("")
459
BAREBOX_CMD_HELP_TEXT("Menu examples:")
460
BAREBOX_CMD_HELP_TEXT("\tmenu -a -m boot -d \"Boot Menu\"")
461
BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m boot -c boot -d \"Boot\"")
462
BAREBOX_CMD_HELP_TEXT("\tmenu -e -a -m boot -c reset -d \"Reset\"")
463
#else
464
BAREBOX_CMD_HELP_TEXT("Menu example:")
465
#endif
466
BAREBOX_CMD_HELP_TEXT("\tmenu -s -m boot")
467
BAREBOX_CMD_HELP_END
468
469
BAREBOX_CMD_START(menu)
470
  .cmd    = do_menu,
471
  BAREBOX_CMD_DESC("create and display menus")
472
  BAREBOX_CMD_GROUP(CMD_GRP_CONSOLE)
473
  BAREBOX_CMD_HELP(cmd_menu_help)
474
BAREBOX_CMD_END