]> git.ipfire.org Git - thirdparty/util-linux.git/blame - fdisks/fdisk-menu.c
fdisk: move sun commands to sun menu callback
[thirdparty/util-linux.git] / fdisks / fdisk-menu.c
CommitLineData
161b0d1a
KZ
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <ctype.h>
6#include <stdint.h>
7
8#include "c.h"
9#include "fdisk.h"
9f280903 10#include "pt-sun.h"
161b0d1a
KZ
11
12struct menu_entry {
13 const char key;
14 const char *title;
15 unsigned int normal : 1,
16 expert : 1,
17 hidden : 1;
18
19 enum fdisk_labeltype exclude;
20};
21
22#define IS_MENU_SEP(e) ((e)->key == '-')
23#define IS_MENU_HID(e) ((e)->hidden)
24
25struct menu {
26 enum fdisk_labeltype label; /* only for this label */
27 enum fdisk_labeltype exclude; /* all labels except this */
28
a410f8df
KZ
29 int (*callback)(struct fdisk_context *,
30 const struct menu *,
31 const struct menu_entry *);
161b0d1a
KZ
32
33 struct menu_entry entries[]; /* NULL terminated array */
34};
35
36struct menu_context {
37 size_t menu_idx; /* the current menu */
38 size_t entry_idx; /* index with in the current menu */
39};
40
41#define MENU_CXT_EMPTY { 0, 0 }
8e40a677
KZ
42#define DECLARE_MENU_CB(x) \
43 static int x(struct fdisk_context *, \
44 const struct menu *, \
45 const struct menu_entry *)
161b0d1a 46
8e40a677 47DECLARE_MENU_CB(gpt_menu_cb);
9f280903 48DECLARE_MENU_CB(sun_menu_cb);
8e40a677 49DECLARE_MENU_CB(geo_menu_cb);
b9e94cd7 50
161b0d1a
KZ
51/*
52 * Menu entry macros:
53 * MENU_X* expert mode only
54 * MENU_B* both -- expert + normal mode
55 *
56 * *_E exclude
57 * *_H hidden
58 */
59
60/* separator */
61#define MENU_SEP(t) { .title = t, .key = '-', .normal = 1 }
62#define MENU_XSEP(t) { .title = t, .key = '-', .expert = 1 }
63#define MENU_BSEP(t) { .title = t, .key = '-', .expert = 1, .normal = 1 }
64
65/* entry */
66#define MENU_ENT(k, t) { .title = t, .key = k, .normal = 1 }
67#define MENU_ENT_E(k, t, l) { .title = t, .key = k, .normal = 1, .exclude = l }
68
69#define MENU_XENT(k, t) { .title = t, .key = k, .expert = 1 }
70#define MENU_XENT_H(k, t) { .title = t, .key = k, .expert = 1, .hidden = 1 }
71
72#define MENU_BENT(k, t) { .title = t, .key = k, .expert = 1, .normal = 1 }
73
74
75/* Generic menu */
76struct menu menu_generic = {
77/* .callback = generic_menu_cb,*/
78 .entries = {
6ae5e1e0 79 MENU_BSEP(N_("Generic")),
161b0d1a
KZ
80 MENU_ENT ('d', N_("delete a partition")),
81 MENU_ENT ('l', N_("list known partition types")),
82 MENU_ENT ('n', N_("add a new partition")),
83 MENU_BENT ('p', N_("print the partition table")),
6ae5e1e0 84 MENU_ENT ('t', N_("change a partition type")),
161b0d1a
KZ
85 MENU_ENT ('v', N_("verify the partition table")),
86
6ae5e1e0
KZ
87 MENU_XENT('d', N_("print the raw data of the first sector")),
88
161b0d1a
KZ
89 MENU_SEP(N_("Misc")),
90 MENU_BENT ('m', N_("print this menu")),
91 MENU_ENT_E('u', N_("change display/entry units"), FDISK_DISKLABEL_GPT),
92 MENU_ENT ('x', N_("extra functionality (experts only)")),
93
2a1a67df 94 MENU_BSEP(N_("Save & Exit")),
161b0d1a
KZ
95 MENU_ENT_E('w', N_("write table to disk and exit"), FDISK_DISKLABEL_OSF),
96 MENU_BENT ('q', N_("quit without saving changes")),
97 MENU_XENT ('r', N_("return to main menu")),
98
99 { 0, NULL }
100 }
101};
102
103struct menu menu_createlabel = {
104/* .callback = createlabel_menu_cb, */
105 .exclude = FDISK_DISKLABEL_OSF,
106 .entries = {
107 MENU_SEP(N_("Create a new label")),
108 MENU_ENT('g', N_("create a new empty GPT partition table")),
109 MENU_ENT('G', N_("create a new empty SGI (IRIX) partition table")),
110 MENU_ENT('o', N_("create a new empty DOS partition table")),
111 MENU_ENT('s', N_("create a new empty Sun partition table")),
112
113 /* backward compatibility -- be sensitive to 'g', but don't
114 * print it in the expert menu */
115 MENU_XENT_H('g', N_("create an IRIX (SGI) partition table")),
116 { 0, NULL }
117 }
118};
119
be9ba6f3 120struct menu menu_geo = {
8e40a677 121 .callback = geo_menu_cb,
be9ba6f3
KZ
122 .exclude = FDISK_DISKLABEL_GPT,
123 .entries = {
124 MENU_XSEP(N_("Geometry")),
125 MENU_XENT('c', N_("change number of cylinders")),
126 MENU_XENT('h', N_("change number of heads")),
127 MENU_XENT('s', N_("change number of sectors/track")),
128 { 0, NULL }
129 }
130};
131
161b0d1a 132struct menu menu_gpt = {
b9e94cd7 133 .callback = gpt_menu_cb,
161b0d1a
KZ
134 .label = FDISK_DISKLABEL_GPT,
135 .entries = {
136 MENU_XSEP(N_("GPT")),
137 MENU_XENT('u', N_("change partition UUID")),
138 MENU_XENT('n', N_("change partition name")),
139 { 0, NULL }
140 }
141};
142
2a1a67df 143struct menu menu_sun = {
9f280903 144 .callback = sun_menu_cb,
2a1a67df
KZ
145 .label = FDISK_DISKLABEL_SUN,
146 .entries = {
147 MENU_BSEP(N_("Sun")),
148 MENU_ENT('a', N_("toggle a read only flag")),
149 MENU_ENT('c', N_("toggle the mountable flag")),
150
151 MENU_XENT('a', N_("change number of alternate cylinders")),
2a1a67df 152 MENU_XENT('e', N_("change number of extra sectors per cylinder")),
2a1a67df
KZ
153 MENU_XENT('i', N_("change interleave factor")),
154 MENU_XENT('o', N_("change rotation speed (rpm)")),
2a1a67df
KZ
155 MENU_XENT('y', N_("change number of physical cylinders")),
156 { 0, NULL }
157 }
158};
159
6ae5e1e0
KZ
160struct menu menu_sgi = {
161/* .callback = sgi_menu_cb, */
162 .label = FDISK_DISKLABEL_SGI,
163 .entries = {
164 MENU_SEP(N_("SGI")),
165 MENU_ENT('a', N_("select bootable partition")),
166 MENU_ENT('b', N_("edit bootfile entry")),
167 MENU_ENT('c', N_("select sgi swap partition")),
168 { 0, NULL }
169 }
170};
171
172struct menu menu_dos = {
173/* .callback = dos_menu_cb, */
174 .label = FDISK_DISKLABEL_DOS,
175 .entries = {
176 MENU_BSEP(N_("DOS (MBR)")),
177 MENU_ENT('a', N_("toggle a bootable flag")),
178 MENU_ENT('b', N_("edit nested BSD disklabel")),
179 MENU_ENT('c', N_("toggle the dos compatibility flag")),
180
181 MENU_XENT('b', N_("move beginning of data in a partition")),
be9ba6f3 182 MENU_XENT('e', N_("list extended partitions")),
6ae5e1e0 183 MENU_XENT('f', N_("fix partition order")),
6ae5e1e0 184 MENU_XENT('i', N_("change the disk identifier")),
6ae5e1e0
KZ
185 { 0, NULL }
186 }
187};
188
189struct menu menu_bsd = {
190/* .callback = bsd_menu_cb, */
191 .label = FDISK_DISKLABEL_OSF,
192 .entries = {
193 MENU_SEP(N_("BSD")),
194 MENU_ENT('e', N_("edit drive data")),
195 MENU_ENT('i', N_("install bootstrap")),
196 MENU_ENT('s', N_("show complete disklabel")),
197 MENU_ENT('w', N_("write disklabel to disk")),
198#if !defined (__alpha__)
199 MENU_ENT('x', N_("link BSD partition to non-BSD partition")),
200#endif
201 { 0, NULL }
202 }
203};
204
161b0d1a 205static const struct menu *menus[] = {
6ae5e1e0
KZ
206 &menu_gpt,
207 &menu_sun,
208 &menu_sgi,
209 &menu_dos,
210 &menu_bsd,
be9ba6f3 211 &menu_geo,
161b0d1a
KZ
212 &menu_generic,
213 &menu_createlabel,
161b0d1a
KZ
214};
215
216static const struct menu_entry *next_menu_entry(
217 struct fdisk_context *cxt,
218 struct menu_context *mc)
219{
220 while (mc->menu_idx < ARRAY_SIZE(menus)) {
221 const struct menu *m = menus[mc->menu_idx];
222 const struct menu_entry *e = &(m->entries[mc->entry_idx]);
223
be9ba6f3 224 /* no more entries */
161b0d1a 225 if (e->title == NULL ||
be9ba6f3
KZ
226 /* menu wanted for specified labels only */
227 (m->label && cxt->label && !(m->label & cxt->label->id)) ||
228 /* menu excluded for specified labels */
229 (m->exclude && cxt->label && (m->exclude & cxt->label->id))) {
161b0d1a
KZ
230 mc->menu_idx++;
231 mc->entry_idx = 0;
232 continue;
233 }
234
235 /* is the entry excluded for the current label? */
236 if ((e->exclude && cxt->label &&
237 e->exclude & cxt->label->id) ||
238 /* exclude non-expert entries in expect mode */
239 (e->expert == 0 && fdisk_context_display_details(cxt)) ||
240 /* exclude non-normal entries in normal mode */
241 (e->normal == 0 && !fdisk_context_display_details(cxt))) {
242
243 mc->entry_idx++;
244 continue;
245 }
246 mc->entry_idx++;
247 return e;
248
249 }
250 return NULL;
251}
252
3b4f9f16
KZ
253/* returns @menu and menu entry for then @key */
254static const struct menu_entry *get_fdisk_menu_entry(
255 struct fdisk_context *cxt,
256 int key,
257 const struct menu **menu)
258{
259 struct menu_context mc = MENU_CXT_EMPTY;
260 const struct menu_entry *e;
261
262 while ((e = next_menu_entry(cxt, &mc))) {
263 if (IS_MENU_SEP(e) || e->key != key)
264 continue;
265
266 if (menu)
267 *menu = menus[mc.menu_idx];
268 return e;
269 }
270
271 return NULL;
272}
273
274static int menu_detect_collisions(struct fdisk_context *cxt)
275{
276 struct menu_context mc = MENU_CXT_EMPTY;
277 const struct menu_entry *e, *r;
278
279 while ((e = next_menu_entry(cxt, &mc))) {
280 if (IS_MENU_SEP(e))
281 continue;
282
283 r = get_fdisk_menu_entry(cxt, e->key, NULL);
284 if (!r) {
36050e70 285 DBG(FRONTEND, dbgprint("warning: not found "
3b4f9f16
KZ
286 "entry for %c", e->key));
287 return -1;
288 }
289 if (r != e) {
36050e70 290 DBG(FRONTEND, dbgprint("warning: duplicate key '%c'",
3b4f9f16 291 e->key));
36050e70
KZ
292 DBG(FRONTEND, dbgprint(" %s", e->title));
293 DBG(FRONTEND, dbgprint(" %s", r->title));
3b4f9f16
KZ
294 abort();
295 }
296 }
297
298 return 0;
299}
300
39f01b7b 301int print_fdisk_menu(struct fdisk_context *cxt)
161b0d1a
KZ
302{
303 struct menu_context mc = MENU_CXT_EMPTY;
304 const struct menu_entry *e;
305
36050e70 306 ON_DBG(FRONTEND, menu_detect_collisions(cxt));
3b4f9f16 307
161b0d1a 308 if (fdisk_context_display_details(cxt))
39f01b7b 309 printf(_("\nHelp (expert commands):\n"));
161b0d1a 310 else
39f01b7b 311 printf(_("\nHelp:\n"));
161b0d1a
KZ
312
313 while ((e = next_menu_entry(cxt, &mc))) {
314 if (IS_MENU_HID(e))
315 continue; /* hidden entry */
316 if (IS_MENU_SEP(e))
317 printf("\n %s\n", _(e->title));
318 else
319 printf(" %c %s\n", e->key, _(e->title));
320 }
321 fputc('\n', stdout);
322
323 return 0;
324}
325
a410f8df
KZ
326/* Asks for command, verify the key and perform the command or
327 * returns the command key if no callback for the command is
328 * implemented.
329 *
330 * Returns: <0 on error
331 * 0 on success (the command performed)
332 * >0 if no callback (then returns the key)
333 */
334int process_fdisk_menu(struct fdisk_context *cxt)
335{
336 const struct menu_entry *ent;
337 const struct menu *menu;
338 int key, rc;
339 const char *prompt;
340 char buf[BUFSIZ];
341
342 if (fdisk_context_display_details(cxt))
343 prompt = _("Expert command (m for help): ");
344 else
345 prompt = _("Command (m for help): ");
346
347 fputc('\n',stdout);
348 rc = get_user_reply(cxt, prompt, buf, sizeof(buf));
349 if (rc)
350 return rc;
351
352 key = buf[0];
353 ent = get_fdisk_menu_entry(cxt, key, &menu);
354 if (!ent) {
355 fdisk_warnx(cxt, _("%c: unknown command"), key);
356 return -EINVAL;
357 }
358
36050e70 359 DBG(FRONTEND, dbgprint("selected: key=%c, entry='%s'",
a410f8df
KZ
360 key, ent->title));
361 /* hardcoded help */
362 if (key == 'm') {
363 print_fdisk_menu(cxt);
364 return 0;
365
366 /* menu has implemented callback, use it */
367 } else if (menu->callback)
368 return menu->callback(cxt, menu, ent);
369
370 /* no callback, return the key */
371 return key;
372}
373
8e40a677 374
b9e94cd7
KZ
375/*
376 * This is fdisk frontend for GPT specific libfdisk functions that
377 * are not expported by generic libfdisk API.
378 */
379static int gpt_menu_cb(struct fdisk_context *cxt,
380 const struct menu *menu __attribute__((__unused__)),
381 const struct menu_entry *ent)
382{
383 size_t n;
384 int rc;
385
386 assert(cxt);
387 assert(ent);
388 assert(fdisk_is_disklabel(cxt, GPT));
389
36050e70 390 DBG(FRONTEND, dbgprint("enter GPT menu"));
b9e94cd7
KZ
391
392 rc = fdisk_ask_partnum(cxt, &n, FALSE);
393 if (rc)
394 return rc;
395
396 switch(ent->key) {
397 case 'u':
398 rc = fdisk_gpt_partition_set_uuid(cxt, n);
399 break;
400 case 'n':
1054699c 401 rc = fdisk_gpt_partition_set_name(cxt, n);
b9e94cd7
KZ
402 break;
403 }
404 return rc;
405}
406
9f280903
KZ
407static int sun_menu_cb(struct fdisk_context *cxt,
408 const struct menu *menu __attribute__((__unused__)),
409 const struct menu_entry *ent)
410{
411 int rc = 0;
412
413 assert(cxt);
414 assert(ent);
415 assert(fdisk_is_disklabel(cxt, SUN));
416
417 DBG(FRONTEND, dbgprint("enter SUN menu"));
418
419 /* normal mode */
420 if (!ent->expert) {
421 size_t n;
422
423 rc = fdisk_ask_partnum(cxt, &n, FALSE);
424 if (rc)
425 return rc;
426 switch (ent->key) {
427 case 'a':
428 rc = fdisk_partition_toggle_flag(cxt, n, SUN_FLAG_RONLY);
429 break;
430 case 'c':
431 rc = fdisk_partition_toggle_flag(cxt, n, SUN_FLAG_UNMNT);
432 break;
433 }
434 return rc;
435 }
436
437 /* expert mode */
438 switch (ent->key) {
439 case 'a':
440 rc = fdisk_sun_set_alt_cyl(cxt);
441 break;
442 case 'e':
443 rc = fdisk_sun_set_xcyl(cxt);
444 break;
445 case 'i':
446 rc = fdisk_sun_set_ilfact(cxt);
447 break;
448 case 'o':
449 rc = fdisk_sun_set_rspeed(cxt);
450 break;
451 case 'y':
452 rc = fdisk_sun_set_pcylcount(cxt);
453 break;
454 }
455 return rc;
456}
457
8e40a677
KZ
458/* C/H/S commands */
459static int geo_menu_cb(struct fdisk_context *cxt,
460 const struct menu *menu __attribute__((__unused__)),
461 const struct menu_entry *ent)
462{
463 int rc = -EINVAL;
464 uintmax_t c = 0, h = 0, s = 0;
465
466 assert(cxt);
467 assert(ent);
468
469 switch (ent->key) {
470 case 'c':
471 rc = fdisk_ask_number(cxt, 1, cxt->geom.cylinders,
472 1048576, _("Number of cylinders"), &c);
473 break;
474 case 'h':
475 rc = fdisk_ask_number(cxt, 1, cxt->geom.heads,
476 256, _("Number of heads"), &h);
477 break;
478 case 's':
479 rc = fdisk_ask_number(cxt, 1, cxt->geom.sectors,
480 63, _("Number of sectors"), &s);
481 break;
482 }
483
484 if (!rc)
485 fdisk_override_geometry(cxt, c, h, s);
486 return rc;
487}
488
161b0d1a
KZ
489#ifdef TEST_PROGRAM
490struct fdisk_label *fdisk_new_dos_label(struct fdisk_context *cxt) { return NULL; }
491struct fdisk_label *fdisk_new_bsd_label(struct fdisk_context *cxt) { return NULL; }
492struct fdisk_label *fdisk_new_mac_label(struct fdisk_context *cxt) { return NULL; }
493struct fdisk_label *fdisk_new_sgi_label(struct fdisk_context *cxt) { return NULL; }
494
495int main(int argc, char *argv[])
496{
497 struct fdisk_context *cxt;
498 int idx = 1;
499
500 fdisk_init_debug(0);
501 cxt = fdisk_new_context();
502
503 if (argc > idx && strcmp(argv[idx], "--expert") == 0) {
504 fdisk_context_enable_details(cxt, 1);
505 idx++;
506 }
507 fdisk_context_switch_label(cxt, argc > idx ? argv[idx] : "gpt");
508
509 print_fdisk_menu(cxt);
510 return 0;
511}
512#endif