]> git.ipfire.org Git - thirdparty/util-linux.git/blame - disk-utils/fdisk-menu.c
docs: fix grammar and punctuation and typos in 2.26 release notes
[thirdparty/util-linux.git] / disk-utils / 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"
f02fecd1
KZ
11#include "pt-mbr.h"
12
161b0d1a 13struct menu_entry {
7e937b77
KZ
14 const char key; /* command key */
15 const char *title; /* help string */
16 unsigned int normal : 1, /* normal mode */
17 expert : 1, /* expert mode */
18 hidden : 1; /* be sensitive for this key,
19 but don't print it in help */
161b0d1a 20
7e937b77
KZ
21 enum fdisk_labeltype label; /* only for this label */
22 enum fdisk_labeltype exclude; /* all labels except this */
f92e1810 23 enum fdisk_labeltype parent; /* for nested PT */
161b0d1a
KZ
24};
25
26#define IS_MENU_SEP(e) ((e)->key == '-')
27#define IS_MENU_HID(e) ((e)->hidden)
28
29struct menu {
30 enum fdisk_labeltype label; /* only for this label */
31 enum fdisk_labeltype exclude; /* all labels except this */
32
f92e1810
KZ
33 unsigned int nonested : 1; /* don't make this menu active in nested PT */
34
a47fec81 35 int (*callback)(struct fdisk_context **,
a410f8df
KZ
36 const struct menu *,
37 const struct menu_entry *);
161b0d1a
KZ
38
39 struct menu_entry entries[]; /* NULL terminated array */
40};
41
42struct menu_context {
43 size_t menu_idx; /* the current menu */
44 size_t entry_idx; /* index with in the current menu */
45};
46
47#define MENU_CXT_EMPTY { 0, 0 }
8e40a677 48#define DECLARE_MENU_CB(x) \
a47fec81 49 static int x(struct fdisk_context **, \
8e40a677
KZ
50 const struct menu *, \
51 const struct menu_entry *)
161b0d1a 52
8e40a677 53DECLARE_MENU_CB(gpt_menu_cb);
9f280903 54DECLARE_MENU_CB(sun_menu_cb);
aae727f2 55DECLARE_MENU_CB(sgi_menu_cb);
8e40a677 56DECLARE_MENU_CB(geo_menu_cb);
f02fecd1 57DECLARE_MENU_CB(dos_menu_cb);
b529ea2a 58DECLARE_MENU_CB(bsd_menu_cb);
b3ac22ef 59DECLARE_MENU_CB(createlabel_menu_cb);
89309968 60DECLARE_MENU_CB(generic_menu_cb);
b9e94cd7 61
161b0d1a
KZ
62/*
63 * Menu entry macros:
64 * MENU_X* expert mode only
65 * MENU_B* both -- expert + normal mode
66 *
7e937b77
KZ
67 * *_E exclude this label
68 * *_H hidden
69 * *_L only for this label
161b0d1a
KZ
70 */
71
72/* separator */
73#define MENU_SEP(t) { .title = t, .key = '-', .normal = 1 }
74#define MENU_XSEP(t) { .title = t, .key = '-', .expert = 1 }
75#define MENU_BSEP(t) { .title = t, .key = '-', .expert = 1, .normal = 1 }
76
77/* entry */
78#define MENU_ENT(k, t) { .title = t, .key = k, .normal = 1 }
79#define MENU_ENT_E(k, t, l) { .title = t, .key = k, .normal = 1, .exclude = l }
7e937b77 80#define MENU_ENT_L(k, t, l) { .title = t, .key = k, .normal = 1, .label = l }
161b0d1a
KZ
81
82#define MENU_XENT(k, t) { .title = t, .key = k, .expert = 1 }
83#define MENU_XENT_H(k, t) { .title = t, .key = k, .expert = 1, .hidden = 1 }
84
85#define MENU_BENT(k, t) { .title = t, .key = k, .expert = 1, .normal = 1 }
27ddd4f1 86#define MENU_BENT_E(k, t, l) { .title = t, .key = k, .expert = 1, .normal = 1, .exclude = l }
161b0d1a 87
f92e1810
KZ
88#define MENU_ENT_NEST(k, t, l, p) { .title = t, .key = k, .normal = 1, .label = l, .parent = p }
89#define MENU_XENT_NEST(k, t, l, p) { .title = t, .key = k, .expert = 1, .label = l, .parent = p }
161b0d1a
KZ
90
91/* Generic menu */
92struct menu menu_generic = {
89309968 93 .callback = generic_menu_cb,
161b0d1a 94 .entries = {
6ae5e1e0 95 MENU_BSEP(N_("Generic")),
161b0d1a
KZ
96 MENU_ENT ('d', N_("delete a partition")),
97 MENU_ENT ('l', N_("list known partition types")),
98 MENU_ENT ('n', N_("add a new partition")),
99 MENU_BENT ('p', N_("print the partition table")),
6ae5e1e0 100 MENU_ENT ('t', N_("change a partition type")),
27ddd4f1 101 MENU_BENT_E('v', N_("verify the partition table"), FDISK_DISKLABEL_BSD),
161b0d1a 102
e916600f
KZ
103 MENU_XENT('d', N_("print the raw data of the first sector from the device")),
104 MENU_XENT('D', N_("print the raw data of the disklabel from the device")),
dd7ba604 105 MENU_XENT('f', N_("fix partitions order")),
6ae5e1e0 106
161b0d1a
KZ
107 MENU_SEP(N_("Misc")),
108 MENU_BENT ('m', N_("print this menu")),
109 MENU_ENT_E('u', N_("change display/entry units"), FDISK_DISKLABEL_GPT),
22ddf547 110 MENU_ENT_E('x', N_("extra functionality (experts only)"), FDISK_DISKLABEL_BSD),
161b0d1a 111
a30e4ef4 112 MENU_SEP(N_("Script")),
5cb9918d
KZ
113 MENU_ENT ('I', N_("load disk layout from sfdisk script file")),
114 MENU_ENT ('O', N_("dump disk layout to sfdisk script file")),
a30e4ef4 115
2a1a67df 116 MENU_BSEP(N_("Save & Exit")),
22ddf547
KZ
117 MENU_ENT_E('w', N_("write table to disk and exit"), FDISK_DISKLABEL_BSD),
118 MENU_ENT_L('w', N_("write table to disk"), FDISK_DISKLABEL_BSD),
161b0d1a
KZ
119 MENU_BENT ('q', N_("quit without saving changes")),
120 MENU_XENT ('r', N_("return to main menu")),
f92e1810
KZ
121
122 MENU_ENT_NEST('r', N_("return from BSD to DOS"), FDISK_DISKLABEL_BSD, FDISK_DISKLABEL_DOS),
161b0d1a
KZ
123
124 { 0, NULL }
125 }
126};
127
128struct menu menu_createlabel = {
b3ac22ef 129 .callback = createlabel_menu_cb,
22ddf547 130 .exclude = FDISK_DISKLABEL_BSD,
f92e1810 131 .nonested = 1,
161b0d1a
KZ
132 .entries = {
133 MENU_SEP(N_("Create a new label")),
134 MENU_ENT('g', N_("create a new empty GPT partition table")),
135 MENU_ENT('G', N_("create a new empty SGI (IRIX) partition table")),
136 MENU_ENT('o', N_("create a new empty DOS partition table")),
137 MENU_ENT('s', N_("create a new empty Sun partition table")),
138
139 /* backward compatibility -- be sensitive to 'g', but don't
140 * print it in the expert menu */
141 MENU_XENT_H('g', N_("create an IRIX (SGI) partition table")),
142 { 0, NULL }
143 }
144};
145
be9ba6f3 146struct menu menu_geo = {
8e40a677 147 .callback = geo_menu_cb,
22ddf547 148 .exclude = FDISK_DISKLABEL_GPT | FDISK_DISKLABEL_BSD,
be9ba6f3
KZ
149 .entries = {
150 MENU_XSEP(N_("Geometry")),
151 MENU_XENT('c', N_("change number of cylinders")),
152 MENU_XENT('h', N_("change number of heads")),
153 MENU_XENT('s', N_("change number of sectors/track")),
154 { 0, NULL }
155 }
156};
157
161b0d1a 158struct menu menu_gpt = {
b9e94cd7 159 .callback = gpt_menu_cb,
161b0d1a
KZ
160 .label = FDISK_DISKLABEL_GPT,
161 .entries = {
162 MENU_XSEP(N_("GPT")),
35b1f0a4 163 MENU_XENT('i', N_("change disk GUID")),
161b0d1a 164 MENU_XENT('n', N_("change partition name")),
35b1f0a4 165 MENU_XENT('u', N_("change partition UUID")),
f92e1810 166 MENU_XENT('M', N_("enter protective/hybrid MBR")),
f362d863
KZ
167
168 MENU_XSEP(""),
169 MENU_XENT('A', N_("toggle the legacy BIOS bootable flag")),
170 MENU_XENT('B', N_("toggle the no block IO protocol flag")),
171 MENU_XENT('R', N_("toggle the required partition flag")),
172 MENU_XENT('S', N_("toggle the GUID specific bits")),
173
161b0d1a
KZ
174 { 0, NULL }
175 }
176};
177
2a1a67df 178struct menu menu_sun = {
9f280903 179 .callback = sun_menu_cb,
2a1a67df
KZ
180 .label = FDISK_DISKLABEL_SUN,
181 .entries = {
182 MENU_BSEP(N_("Sun")),
aaa43826 183 MENU_ENT('a', N_("toggle the read-only flag")),
2a1a67df
KZ
184 MENU_ENT('c', N_("toggle the mountable flag")),
185
186 MENU_XENT('a', N_("change number of alternate cylinders")),
2a1a67df 187 MENU_XENT('e', N_("change number of extra sectors per cylinder")),
2a1a67df
KZ
188 MENU_XENT('i', N_("change interleave factor")),
189 MENU_XENT('o', N_("change rotation speed (rpm)")),
2a1a67df
KZ
190 MENU_XENT('y', N_("change number of physical cylinders")),
191 { 0, NULL }
192 }
193};
194
6ae5e1e0 195struct menu menu_sgi = {
aae727f2 196 .callback = sgi_menu_cb,
6ae5e1e0
KZ
197 .label = FDISK_DISKLABEL_SGI,
198 .entries = {
199 MENU_SEP(N_("SGI")),
200 MENU_ENT('a', N_("select bootable partition")),
201 MENU_ENT('b', N_("edit bootfile entry")),
202 MENU_ENT('c', N_("select sgi swap partition")),
aae727f2 203 MENU_ENT('i', N_("create SGI info")),
6ae5e1e0
KZ
204 { 0, NULL }
205 }
206};
207
208struct menu menu_dos = {
f02fecd1 209 .callback = dos_menu_cb,
6ae5e1e0
KZ
210 .label = FDISK_DISKLABEL_DOS,
211 .entries = {
212 MENU_BSEP(N_("DOS (MBR)")),
213 MENU_ENT('a', N_("toggle a bootable flag")),
214 MENU_ENT('b', N_("edit nested BSD disklabel")),
215 MENU_ENT('c', N_("toggle the dos compatibility flag")),
216
217 MENU_XENT('b', N_("move beginning of data in a partition")),
6ae5e1e0 218 MENU_XENT('i', N_("change the disk identifier")),
f92e1810
KZ
219
220 MENU_XENT_NEST('M', N_("return from protective/hybrid MBR to GPT"),
221 FDISK_DISKLABEL_DOS, FDISK_DISKLABEL_GPT),
6ae5e1e0
KZ
222 { 0, NULL }
223 }
224};
225
226struct menu menu_bsd = {
b529ea2a 227 .callback = bsd_menu_cb,
22ddf547 228 .label = FDISK_DISKLABEL_BSD,
6ae5e1e0
KZ
229 .entries = {
230 MENU_SEP(N_("BSD")),
231 MENU_ENT('e', N_("edit drive data")),
232 MENU_ENT('i', N_("install bootstrap")),
233 MENU_ENT('s', N_("show complete disklabel")),
6ae5e1e0 234 MENU_ENT('x', N_("link BSD partition to non-BSD partition")),
6ae5e1e0
KZ
235 { 0, NULL }
236 }
237};
238
161b0d1a 239static const struct menu *menus[] = {
6ae5e1e0
KZ
240 &menu_gpt,
241 &menu_sun,
242 &menu_sgi,
243 &menu_dos,
244 &menu_bsd,
be9ba6f3 245 &menu_geo,
161b0d1a
KZ
246 &menu_generic,
247 &menu_createlabel,
161b0d1a
KZ
248};
249
250static const struct menu_entry *next_menu_entry(
251 struct fdisk_context *cxt,
252 struct menu_context *mc)
253{
8eccde20
KZ
254 struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
255 struct fdisk_context *parent = fdisk_get_parent(cxt);
256 unsigned int type = 0, pr_type = 0;
257
258 assert(cxt);
259
260 type = fdisk_label_get_type(lb);
261 if (parent)
262 pr_type = fdisk_label_get_type(fdisk_get_label(parent, NULL));
263
161b0d1a
KZ
264 while (mc->menu_idx < ARRAY_SIZE(menus)) {
265 const struct menu *m = menus[mc->menu_idx];
266 const struct menu_entry *e = &(m->entries[mc->entry_idx]);
267
f92e1810
KZ
268 /*
269 * whole-menu filter
270 */
271
be9ba6f3 272 /* no more entries */
161b0d1a 273 if (e->title == NULL ||
be9ba6f3 274 /* menu wanted for specified labels only */
8eccde20 275 (m->label && lb && !(m->label & type)) ||
f92e1810 276 /* unwanted for nested PT */
8eccde20 277 (m->nonested && parent) ||
be9ba6f3 278 /* menu excluded for specified labels */
8eccde20 279 (m->exclude && lb && (m->exclude & type))) {
161b0d1a
KZ
280 mc->menu_idx++;
281 mc->entry_idx = 0;
282 continue;
283 }
284
f92e1810
KZ
285 /*
286 * per entry filter
287 */
288
7e937b77 289 /* excluded for the current label */
8eccde20 290 if ((e->exclude && lb && e->exclude & type) ||
7e937b77 291 /* entry wanted for specified labels only */
8eccde20 292 (e->label && lb && !(e->label & type)) ||
161b0d1a 293 /* exclude non-expert entries in expect mode */
6a632136 294 (e->expert == 0 && fdisk_is_details(cxt)) ||
f92e1810 295 /* nested only */
8eccde20 296 (e->parent && (!parent || pr_type != e->parent)) ||
161b0d1a 297 /* exclude non-normal entries in normal mode */
6a632136 298 (e->normal == 0 && !fdisk_is_details(cxt))) {
161b0d1a
KZ
299 mc->entry_idx++;
300 continue;
301 }
302 mc->entry_idx++;
303 return e;
304
305 }
306 return NULL;
307}
308
3b4f9f16
KZ
309/* returns @menu and menu entry for then @key */
310static const struct menu_entry *get_fdisk_menu_entry(
311 struct fdisk_context *cxt,
312 int key,
313 const struct menu **menu)
314{
315 struct menu_context mc = MENU_CXT_EMPTY;
316 const struct menu_entry *e;
317
318 while ((e = next_menu_entry(cxt, &mc))) {
319 if (IS_MENU_SEP(e) || e->key != key)
320 continue;
321
322 if (menu)
323 *menu = menus[mc.menu_idx];
324 return e;
325 }
326
327 return NULL;
328}
329
330static int menu_detect_collisions(struct fdisk_context *cxt)
331{
332 struct menu_context mc = MENU_CXT_EMPTY;
333 const struct menu_entry *e, *r;
334
335 while ((e = next_menu_entry(cxt, &mc))) {
336 if (IS_MENU_SEP(e))
337 continue;
338
339 r = get_fdisk_menu_entry(cxt, e->key, NULL);
340 if (!r) {
e6d0c4c1 341 DBG(MENU, ul_debug("warning: not found "
3b4f9f16
KZ
342 "entry for %c", e->key));
343 return -1;
344 }
345 if (r != e) {
e6d0c4c1 346 DBG(MENU, ul_debug("warning: duplicate key '%c'",
3b4f9f16 347 e->key));
e6d0c4c1
KZ
348 DBG(MENU, ul_debug(" : %s", e->title));
349 DBG(MENU, ul_debug(" : %s", r->title));
3b4f9f16
KZ
350 abort();
351 }
352 }
353
354 return 0;
355}
356
1f75d1ce 357static int print_fdisk_menu(struct fdisk_context *cxt)
161b0d1a
KZ
358{
359 struct menu_context mc = MENU_CXT_EMPTY;
360 const struct menu_entry *e;
361
e6d0c4c1 362 ON_DBG(MENU, menu_detect_collisions(cxt));
3b4f9f16 363
6a632136 364 if (fdisk_is_details(cxt))
39f01b7b 365 printf(_("\nHelp (expert commands):\n"));
161b0d1a 366 else
39f01b7b 367 printf(_("\nHelp:\n"));
161b0d1a
KZ
368
369 while ((e = next_menu_entry(cxt, &mc))) {
370 if (IS_MENU_HID(e))
371 continue; /* hidden entry */
f362d863
KZ
372 if (IS_MENU_SEP(e) && (!e->title || !*e->title))
373 printf("\n");
374 else if (IS_MENU_SEP(e)) {
496c979a 375 color_scheme_enable("help-title", UL_COLOR_BOLD);
161b0d1a 376 printf("\n %s\n", _(e->title));
80a1712f
KZ
377 color_disable();
378 } else
161b0d1a
KZ
379 printf(" %c %s\n", e->key, _(e->title));
380 }
381 fputc('\n', stdout);
382
8eccde20
KZ
383 if (fdisk_get_parent(cxt)) {
384 struct fdisk_label *l = fdisk_get_label(cxt, NULL),
385 *p = fdisk_get_label(fdisk_get_parent(cxt), NULL);
386
f92e1810
KZ
387 fdisk_info(cxt, _("You're editing nested '%s' partition table, "
388 "primary partition table is '%s'."),
8eccde20
KZ
389 fdisk_label_get_name(l),
390 fdisk_label_get_name(p));
391 }
f92e1810 392
161b0d1a
KZ
393 return 0;
394}
395
a410f8df
KZ
396/* Asks for command, verify the key and perform the command or
397 * returns the command key if no callback for the command is
398 * implemented.
399 *
a47fec81
KZ
400 * Note that this function might exchange the context pointer to
401 * switch to another (nested) context.
402 *
a410f8df
KZ
403 * Returns: <0 on error
404 * 0 on success (the command performed)
405 * >0 if no callback (then returns the key)
406 */
a47fec81 407int process_fdisk_menu(struct fdisk_context **cxt0)
a410f8df 408{
a47fec81 409 struct fdisk_context *cxt = *cxt0;
a410f8df
KZ
410 const struct menu_entry *ent;
411 const struct menu *menu;
412 int key, rc;
413 const char *prompt;
414 char buf[BUFSIZ];
415
6a632136 416 if (fdisk_is_details(cxt))
a410f8df
KZ
417 prompt = _("Expert command (m for help): ");
418 else
419 prompt = _("Command (m for help): ");
420
421 fputc('\n',stdout);
422 rc = get_user_reply(cxt, prompt, buf, sizeof(buf));
423 if (rc)
424 return rc;
425
426 key = buf[0];
427 ent = get_fdisk_menu_entry(cxt, key, &menu);
428 if (!ent) {
429 fdisk_warnx(cxt, _("%c: unknown command"), key);
430 return -EINVAL;
431 }
432
a47fec81 433 rc = 0;
e6d0c4c1 434 DBG(MENU, ul_debug("selected: key=%c, entry='%s'",
a410f8df 435 key, ent->title));
a410f8df
KZ
436
437 /* menu has implemented callback, use it */
27ddd4f1 438 if (menu->callback)
a47fec81
KZ
439 rc = menu->callback(cxt0, menu, ent);
440 else {
e6d0c4c1 441 DBG(MENU, ul_debug("no callback for key '%c'", key));
27ddd4f1 442 rc = -EINVAL;
a47fec81 443 }
a410f8df 444
e6d0c4c1 445 DBG(MENU, ul_debug("process menu done [rc=%d]", rc));
a47fec81 446 return rc;
a410f8df
KZ
447}
448
a30e4ef4
KZ
449static int script_read(struct fdisk_context *cxt)
450{
451 struct fdisk_script *sc = NULL;
452 char *filename = NULL;
453 int rc;
454
455 rc = fdisk_ask_string(cxt, _("Enter script file name"), &filename);
456 if (rc)
457 return rc;
458
459 errno = 0;
460 sc = fdisk_new_script_from_file(cxt, filename);
461 if (!sc && errno)
462 fdisk_warn(cxt, _("Cannot open: %s"), filename);
463 else if (!sc)
464 fdisk_warnx(cxt, _("Failed to parse script file %s"), filename);
465 else if (fdisk_apply_script(cxt, sc) != 0)
466 fdisk_warnx(cxt, _("Failed to apply script %s"), filename);
467 else
468 fdisk_info(cxt, _("Script successfully applied."));
469
470 fdisk_unref_script(sc);
471 free(filename);
472 return rc;
473}
474
475static int script_write(struct fdisk_context *cxt)
476{
477 struct fdisk_script *sc = NULL;
478 char *filename = NULL;
479 FILE *f = NULL;
480 int rc;
481
482 rc = fdisk_ask_string(cxt, _("Enter script file name"), &filename);
483 if (rc)
484 return rc;
485
486 sc = fdisk_new_script(cxt);
487 if (!sc) {
488 fdisk_warn(cxt, _("Failed to allocate script handler"));
489 goto done;
490 }
491
492 rc = fdisk_script_read_context(sc, NULL);
493 if (rc) {
494 fdisk_warnx(cxt, _("Failed to read disk layout into script."));
495 goto done;
496 }
497
498 f = fopen(filename, "w");
499 if (!f) {
500 fdisk_warn(cxt, _("Cannot open: %s"), filename);
501 goto done;
502 }
503
504 rc = fdisk_script_write_file(sc, f);
505 if (rc)
506 fdisk_warn(cxt, _("Failed to write script %s"), filename);
507 else
508 fdisk_info(cxt, _("Script successfully saved."));
509done:
510 if (f)
511 fclose(f);
512 fdisk_unref_script(sc);
513 free(filename);
514 return rc;
515}
516
89309968
KZ
517/*
518 * Basic fdisk actions
519 */
520static int generic_menu_cb(struct fdisk_context **cxt0,
521 const struct menu *menu __attribute__((__unused__)),
522 const struct menu_entry *ent)
523{
524 struct fdisk_context *cxt = *cxt0;
525 int rc = 0;
27ddd4f1 526 size_t n;
89309968 527
27ddd4f1 528 /* actions shared between expert and normal mode */
89309968 529 switch (ent->key) {
89309968
KZ
530 case 'p':
531 list_disk_geometry(cxt);
9f670072 532 list_disklabel(cxt);
89309968 533 break;
df4bfa97 534 case 'w':
6a632136 535 if (fdisk_is_readonly(cxt)) {
e146ae4e
KZ
536 fdisk_warnx(cxt, _("Device open in read-only mode."));
537 break;
538 }
df4bfa97
KZ
539 rc = fdisk_write_disklabel(cxt);
540 if (rc)
fd56121a 541 err(EXIT_FAILURE, _("failed to write disklabel"));
8eccde20 542 if (fdisk_get_parent(cxt))
df4bfa97
KZ
543 break; /* nested PT, don't leave */
544 fdisk_info(cxt, _("The partition table has been altered."));
a57639e1
KZ
545 rc = fdisk_reread_partition_table(cxt);
546 if (!rc)
6a632136 547 rc = fdisk_deassign_device(cxt, 0);
a57639e1 548 /* fallthrough */
89309968 549 case 'q':
c7119037 550 fdisk_unref_context(cxt);
a57639e1
KZ
551 fputc('\n', stdout);
552 exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
27ddd4f1
KZ
553 case 'm':
554 rc = print_fdisk_menu(cxt);
555 break;
89309968
KZ
556 case 'v':
557 rc = fdisk_verify_disklabel(cxt);
558 break;
27ddd4f1
KZ
559 }
560
561 /* expert mode */
562 if (ent->expert) {
563 switch (ent->key) {
564 case 'd':
e916600f
KZ
565 dump_firstsector(cxt);
566 break;
567 case 'D':
568 dump_disklabel(cxt);
27ddd4f1 569 break;
dd7ba604
KZ
570 case 'f':
571 rc = fdisk_reorder_partitions(cxt);
572 break;
27ddd4f1 573 case 'r':
6a632136 574 rc = fdisk_enable_details(cxt, 0);
27ddd4f1
KZ
575 break;
576 }
577 return rc;
578 }
579
580 /* normal mode */
581 switch (ent->key) {
582 case 'd':
583 rc = fdisk_ask_partnum(cxt, &n, FALSE);
584 if (!rc)
585 rc = fdisk_delete_partition(cxt, n);
586 if (rc)
48d4d931 587 fdisk_warnx(cxt, _("Could not delete partition %zu"), n + 1);
27ddd4f1 588 else
48d4d931 589 fdisk_info(cxt, _("Partition %zu has been deleted."), n + 1);
27ddd4f1 590 break;
a30e4ef4
KZ
591 case 'I':
592 script_read(cxt);
593 break;
594 case 'O':
595 script_write(cxt);
596 break;
27ddd4f1
KZ
597 case 'l':
598 list_partition_types(cxt);
599 break;
600 case 'n':
c3bc7483 601 rc = fdisk_add_partition(cxt, NULL, NULL);
27ddd4f1
KZ
602 break;
603 case 't':
604 change_partition_type(cxt);
605 break;
606 case 'u':
6a632136
KZ
607 fdisk_set_unit(cxt,
608 fdisk_use_cylinders(cxt) ? "sectors" :
27ddd4f1 609 "cylinders");
6a632136 610 if (fdisk_use_cylinders(cxt))
27ddd4f1
KZ
611 fdisk_info(cxt, _("Changing display/entry units to cylinders (DEPRECATED!)."));
612 else
613 fdisk_info(cxt, _("Changing display/entry units to sectors."));
614 break;
615 case 'x':
6a632136 616 fdisk_enable_details(cxt, 1);
27ddd4f1
KZ
617 break;
618 case 'r':
f92e1810 619 /* return from nested BSD to DOS */
8eccde20
KZ
620 if (fdisk_get_parent(cxt)) {
621 *cxt0 = fdisk_get_parent(cxt);
27ddd4f1 622
fd56121a 623 fdisk_info(cxt, _("Leaving nested disklabel."));
c7119037 624 fdisk_unref_context(cxt);
b5729667 625 cxt = *cxt0;
27ddd4f1
KZ
626 }
627 break;
89309968 628 }
27ddd4f1 629
89309968
KZ
630 return rc;
631}
632
8e40a677 633
b9e94cd7
KZ
634/*
635 * This is fdisk frontend for GPT specific libfdisk functions that
636 * are not expported by generic libfdisk API.
637 */
a47fec81 638static int gpt_menu_cb(struct fdisk_context **cxt0,
b9e94cd7
KZ
639 const struct menu *menu __attribute__((__unused__)),
640 const struct menu_entry *ent)
641{
a47fec81 642 struct fdisk_context *cxt = *cxt0;
f92e1810 643 struct fdisk_context *mbr;
6936c081 644 struct fdisk_partition *pa = NULL;
b9e94cd7 645 size_t n;
f92e1810 646 int rc = 0;
b9e94cd7
KZ
647
648 assert(cxt);
649 assert(ent);
aa36c2cf 650 assert(fdisk_is_label(cxt, GPT));
b9e94cd7 651
e6d0c4c1 652 DBG(MENU, ul_debug("enter GPT menu"));
b9e94cd7 653
f92e1810
KZ
654 if (ent->expert) {
655 switch (ent->key) {
656 case 'i':
657 return fdisk_set_disklabel_id(cxt);
658 case 'M':
659 mbr = fdisk_new_nested_context(cxt, "dos");
660 if (!mbr)
661 return -ENOMEM;
662 *cxt0 = cxt = mbr;
6a632136 663 fdisk_enable_details(cxt, 1); /* keep us in expert mode */
0477369a 664 fdisk_info(cxt, _("Entering protective/hybrid MBR disklabel."));
f92e1810
KZ
665 return 0;
666 }
35b1f0a4 667
f92e1810
KZ
668 /* actions where is necessary partnum */
669 rc = fdisk_ask_partnum(cxt, &n, FALSE);
670 if (rc)
671 return rc;
b9e94cd7 672
f92e1810
KZ
673 switch(ent->key) {
674 case 'u':
6936c081
KZ
675 pa = fdisk_new_partition(); /* new template */
676 if (!pa)
677 rc = -ENOMEM;
678 else {
679 char *str = NULL;
680 rc = fdisk_ask_string(cxt, _("New UUID (in 8-4-4-4-12 format)"), &str);
681 if (!rc)
682 rc = fdisk_partition_set_uuid(pa, str);
683 if (!rc)
684 rc = fdisk_set_partition(cxt, n, pa);
685 free(str);
686 fdisk_unref_partition(pa);
687 }
f92e1810
KZ
688 break;
689 case 'n':
6936c081
KZ
690 pa = fdisk_new_partition(); /* new template */
691 if (!pa)
692 rc = -ENOMEM;
693 else {
694 char *str = NULL;
695 rc = fdisk_ask_string(cxt, _("New name"), &str);
696 if (!rc)
697 rc = fdisk_partition_set_name(pa, str);
698 if (!rc)
699 rc = fdisk_set_partition(cxt, n, pa);
700 free(str);
701 fdisk_unref_partition(pa);
702 }
f92e1810 703 break;
f362d863 704 case 'A':
a1ef792f 705 rc = fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_LEGACYBOOT);
f362d863
KZ
706 break;
707 case 'B':
a1ef792f 708 rc = fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_NOBLOCK);
f362d863
KZ
709 break;
710 case 'R':
a1ef792f 711 rc = fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_REQUIRED);
f362d863
KZ
712 break;
713 case 'S':
a1ef792f 714 rc = fdisk_toggle_partition_flag(cxt, n, GPT_FLAG_GUIDSPECIFIC);
f362d863 715 break;
f92e1810 716 }
b9e94cd7 717 }
6936c081 718
b9e94cd7
KZ
719 return rc;
720}
721
f02fecd1
KZ
722
723/*
724 * This is fdisk frontend for MBR specific libfdisk functions that
725 * are not expported by generic libfdisk API.
726 */
a47fec81 727static int dos_menu_cb(struct fdisk_context **cxt0,
f02fecd1
KZ
728 const struct menu *menu __attribute__((__unused__)),
729 const struct menu_entry *ent)
730{
a47fec81 731 struct fdisk_context *cxt = *cxt0;
f02fecd1
KZ
732 int rc = 0;
733
e6d0c4c1 734 DBG(MENU, ul_debug("enter DOS menu"));
a47fec81 735
f02fecd1
KZ
736 if (!ent->expert) {
737 switch (ent->key) {
738 case 'a':
739 {
740 size_t n;
741 rc = fdisk_ask_partnum(cxt, &n, FALSE);
742 if (!rc)
a1ef792f 743 rc = fdisk_toggle_partition_flag(cxt, n, DOS_FLAG_ACTIVE);
f02fecd1
KZ
744 break;
745 }
746 case 'b':
747 {
748 struct fdisk_context *bsd
749 = fdisk_new_nested_context(cxt, "bsd");
818d7924
KZ
750 if (!bsd)
751 return -ENOMEM;
aa36c2cf 752 if (!fdisk_has_label(bsd))
818d7924 753 rc = fdisk_create_disklabel(bsd, "bsd");
a47fec81 754 if (rc)
c7119037 755 fdisk_unref_context(bsd);
27ddd4f1 756 else {
a47fec81 757 *cxt0 = cxt = bsd;
0477369a 758 fdisk_info(cxt, _("Entering nested BSD disklabel."));
27ddd4f1 759 }
f02fecd1
KZ
760 break;
761 }
762 case 'c':
763 toggle_dos_compatibility_flag(cxt);
764 break;
765 }
766 return rc;
767 }
768
769 /* expert mode */
770 switch (ent->key) {
771 case 'b':
772 {
773 size_t n;
774 rc = fdisk_ask_partnum(cxt, &n, FALSE);
775 if (!rc)
f8ad3899 776 rc = fdisk_dos_move_begin(cxt, n);
f02fecd1
KZ
777 break;
778 }
f02fecd1
KZ
779 case 'i':
780 rc = fdisk_set_disklabel_id(cxt);
781 break;
f92e1810
KZ
782 case 'M':
783 /* return from nested MBR to GPT */
8eccde20
KZ
784 if (fdisk_get_parent(cxt)) {
785 *cxt0 = fdisk_get_parent(cxt);
f92e1810
KZ
786
787 fdisk_info(cxt, _("Leaving nested disklabel."));
c7119037 788 fdisk_unref_context(cxt);
f92e1810
KZ
789 cxt = *cxt0;
790 }
791 break;
f02fecd1
KZ
792 }
793 return rc;
794}
795
a47fec81 796static int sun_menu_cb(struct fdisk_context **cxt0,
9f280903
KZ
797 const struct menu *menu __attribute__((__unused__)),
798 const struct menu_entry *ent)
799{
a47fec81 800 struct fdisk_context *cxt = *cxt0;
9f280903
KZ
801 int rc = 0;
802
e6d0c4c1 803 DBG(MENU, ul_debug("enter SUN menu"));
a47fec81 804
9f280903
KZ
805 assert(cxt);
806 assert(ent);
aa36c2cf 807 assert(fdisk_is_label(cxt, SUN));
9f280903 808
e6d0c4c1 809 DBG(MENU, ul_debug("enter SUN menu"));
9f280903
KZ
810
811 /* normal mode */
812 if (!ent->expert) {
813 size_t n;
814
815 rc = fdisk_ask_partnum(cxt, &n, FALSE);
816 if (rc)
817 return rc;
818 switch (ent->key) {
819 case 'a':
a1ef792f 820 rc = fdisk_toggle_partition_flag(cxt, n, SUN_FLAG_RONLY);
9f280903
KZ
821 break;
822 case 'c':
a1ef792f 823 rc = fdisk_toggle_partition_flag(cxt, n, SUN_FLAG_UNMNT);
9f280903
KZ
824 break;
825 }
826 return rc;
827 }
828
829 /* expert mode */
830 switch (ent->key) {
831 case 'a':
832 rc = fdisk_sun_set_alt_cyl(cxt);
833 break;
834 case 'e':
835 rc = fdisk_sun_set_xcyl(cxt);
836 break;
837 case 'i':
838 rc = fdisk_sun_set_ilfact(cxt);
839 break;
840 case 'o':
841 rc = fdisk_sun_set_rspeed(cxt);
842 break;
843 case 'y':
844 rc = fdisk_sun_set_pcylcount(cxt);
845 break;
846 }
847 return rc;
848}
849
aae727f2
KZ
850static int sgi_menu_cb(struct fdisk_context **cxt0,
851 const struct menu *menu __attribute__((__unused__)),
852 const struct menu_entry *ent)
853{
854 struct fdisk_context *cxt = *cxt0;
855 int rc = -EINVAL;
856 size_t n = 0;
857
e6d0c4c1 858 DBG(MENU, ul_debug("enter SGI menu"));
aae727f2
KZ
859
860 assert(cxt);
861 assert(ent);
aa36c2cf 862 assert(fdisk_is_label(cxt, SGI));
aae727f2
KZ
863
864 if (ent->expert)
865 return rc;
866
867 switch (ent->key) {
868 case 'a':
869 rc = fdisk_ask_partnum(cxt, &n, FALSE);
870 if (!rc)
a1ef792f 871 rc = fdisk_toggle_partition_flag(cxt, n, SGI_FLAG_BOOT);
aae727f2
KZ
872 break;
873 case 'b':
ac84272d 874 fdisk_sgi_set_bootfile(cxt);
aae727f2
KZ
875 break;
876 case 'c':
877 rc = fdisk_ask_partnum(cxt, &n, FALSE);
878 if (!rc)
a1ef792f 879 rc = fdisk_toggle_partition_flag(cxt, n, SGI_FLAG_SWAP);
aae727f2
KZ
880 break;
881 case 'i':
ac84272d 882 rc = fdisk_sgi_create_info(cxt);
aae727f2
KZ
883 break;
884 }
885
886 return rc;
887}
888
b529ea2a
KZ
889/*
890 * This is fdisk frontend for BSD specific libfdisk functions that
891 * are not expported by generic libfdisk API.
892 */
893static int bsd_menu_cb(struct fdisk_context **cxt0,
894 const struct menu *menu __attribute__((__unused__)),
895 const struct menu_entry *ent)
896{
897 struct fdisk_context *cxt = *cxt0;
e563f055 898 int rc = 0, org;
b529ea2a
KZ
899
900 assert(cxt);
901 assert(ent);
aa36c2cf 902 assert(fdisk_is_label(cxt, BSD));
b529ea2a 903
e6d0c4c1 904 DBG(MENU, ul_debug("enter BSD menu"));
b529ea2a
KZ
905
906 switch(ent->key) {
907 case 'e':
908 rc = fdisk_bsd_edit_disklabel(cxt);
909 break;
910 case 'i':
911 rc = fdisk_bsd_write_bootstrap(cxt);
912 break;
913 case 's':
6a632136 914 org = fdisk_is_details(cxt);
e563f055 915
6a632136 916 fdisk_enable_details(cxt, 1);
9f670072 917 list_disklabel(cxt);
6a632136 918 fdisk_enable_details(cxt, org);
b529ea2a
KZ
919 break;
920 case 'x':
921 rc = fdisk_bsd_link_partition(cxt);
922 break;
923 }
924 return rc;
925}
926
8e40a677 927/* C/H/S commands */
a47fec81 928static int geo_menu_cb(struct fdisk_context **cxt0,
8e40a677
KZ
929 const struct menu *menu __attribute__((__unused__)),
930 const struct menu_entry *ent)
931{
a47fec81 932 struct fdisk_context *cxt = *cxt0;
8e40a677
KZ
933 int rc = -EINVAL;
934 uintmax_t c = 0, h = 0, s = 0;
935
e6d0c4c1 936 DBG(MENU, ul_debug("enter GEO menu"));
a47fec81 937
8e40a677
KZ
938 assert(cxt);
939 assert(ent);
940
941 switch (ent->key) {
942 case 'c':
8eccde20 943 rc = fdisk_ask_number(cxt, 1, fdisk_get_geom_cylinders(cxt),
8e40a677
KZ
944 1048576, _("Number of cylinders"), &c);
945 break;
946 case 'h':
8eccde20 947 rc = fdisk_ask_number(cxt, 1, fdisk_get_geom_heads(cxt),
8e40a677
KZ
948 256, _("Number of heads"), &h);
949 break;
950 case 's':
8eccde20 951 rc = fdisk_ask_number(cxt, 1, fdisk_get_geom_sectors(cxt),
8e40a677
KZ
952 63, _("Number of sectors"), &s);
953 break;
954 }
955
956 if (!rc)
957 fdisk_override_geometry(cxt, c, h, s);
958 return rc;
959}
960
b3ac22ef
KZ
961static int createlabel_menu_cb(struct fdisk_context **cxt0,
962 const struct menu *menu __attribute__((__unused__)),
963 const struct menu_entry *ent)
964{
965 struct fdisk_context *cxt = *cxt0;
966 int rc = -EINVAL;
967
e6d0c4c1 968 DBG(MENU, ul_debug("enter Create label menu"));
b3ac22ef
KZ
969
970 assert(cxt);
971 assert(ent);
972
aae727f2
KZ
973 if (ent->expert) {
974 switch (ent->key) {
975 case 'g':
976 /* Deprecated, use 'G' in main menu, just for backward
977 * compatibility only. */
978 rc = fdisk_create_disklabel(cxt, "sgi");
979 break;
980 }
981 return rc;
982 }
983
b3ac22ef
KZ
984 switch (ent->key) {
985 case 'g':
986 fdisk_create_disklabel(cxt, "gpt");
987 break;
988 case 'G':
989 fdisk_create_disklabel(cxt, "sgi");
990 break;
991 case 'o':
992 fdisk_create_disklabel(cxt, "dos");
993 break;
994 case 's':
995 fdisk_create_disklabel(cxt, "sun");
996 break;
997 }
998 return rc;
999}