]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/fdisk-menu.c
wipefs: add --lock and LOCK_BLOCK_DEVICE
[thirdparty/util-linux.git] / disk-utils / fdisk-menu.c
index 9245bac8a0998ff17d0584fdea9b699ad483acf3..51ae7b5e6e912eeefeab203bd83c76ae530232b0 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdint.h>
 
 #include "c.h"
+#include "rpmatch.h"
 #include "fdisk.h"
 #include "pt-sun.h"
 #include "pt-mbr.h"
@@ -86,7 +87,7 @@ DECLARE_MENU_CB(generic_menu_cb);
 #define MENU_BENT_E(k, t, l)   { .title = t, .key = k, .expert = 1, .normal = 1, .exclude = l }
 
 #define MENU_ENT_NEST(k, t, l, p)      { .title = t, .key = k, .normal = 1, .label = l, .parent = p }
-#define MENU_XENT_NEST(k, t, l, p)     { .title = t, .key = k, .expert = 1, .label = l, .parent = p }
+#define MENU_BENT_NEST_H(k, t, l, p)   { .title = t, .key = k, .expert = 1, .normal = 1, .label = l, .parent = p, .hidden = 1 }
 
 /* Generic menu */
 static const struct menu menu_generic = {
@@ -123,6 +124,8 @@ static const struct menu menu_generic = {
 
                MENU_ENT_NEST('r', N_("return from BSD to DOS"), FDISK_DISKLABEL_BSD, FDISK_DISKLABEL_DOS),
 
+               MENU_ENT_NEST('r', N_("return from protective/hybrid MBR to GPT"), FDISK_DISKLABEL_DOS, FDISK_DISKLABEL_GPT),
+
                { 0, NULL }
        }
 };
@@ -149,7 +152,7 @@ static const struct menu menu_geo = {
        .callback = geo_menu_cb,
        .exclude = FDISK_DISKLABEL_GPT | FDISK_DISKLABEL_BSD,
        .entries = {
-               MENU_XSEP(N_("Geometry")),
+               MENU_XSEP(N_("Geometry (for the current label)")),
                MENU_XENT('c', N_("change number of cylinders")),
                MENU_XENT('h', N_("change number of heads")),
                MENU_XENT('s', N_("change number of sectors/track")),
@@ -161,12 +164,12 @@ static const struct menu menu_gpt = {
        .callback = gpt_menu_cb,
        .label = FDISK_DISKLABEL_GPT,
        .entries = {
-               MENU_XSEP(N_("GPT")),
+               MENU_BSEP(N_("GPT")),
                MENU_XENT('i', N_("change disk GUID")),
                MENU_XENT('n', N_("change partition name")),
                MENU_XENT('u', N_("change partition UUID")),
                MENU_XENT('l', N_("change table length")),
-               MENU_XENT('M', N_("enter protective/hybrid MBR")),
+               MENU_BENT('M', N_("enter protective/hybrid MBR")),
 
                MENU_XSEP(""),
                MENU_XENT('A', N_("toggle the legacy BIOS bootable flag")),
@@ -220,8 +223,8 @@ static const struct menu menu_dos = {
                MENU_XENT('b', N_("move beginning of data in a partition")),
                MENU_XENT('i', N_("change the disk identifier")),
 
-               MENU_XENT_NEST('M', N_("return from protective/hybrid MBR to GPT"),
-                                       FDISK_DISKLABEL_DOS, FDISK_DISKLABEL_GPT),
+               MENU_BENT_NEST_H('M', N_("return from protective/hybrid MBR to GPT"), FDISK_DISKLABEL_DOS, FDISK_DISKLABEL_GPT),
+
                { 0, NULL }
        }
 };
@@ -276,7 +279,7 @@ static const struct menu_entry *next_menu_entry(
                /* no more entries */
                if (e->title == NULL ||
                /* menu wanted for specified labels only */
-                   (m->label && lb && !(m->label & type)) ||
+                   (m->label && (!lb || !(m->label & type))) ||
                /* unwanted for nested PT */
                    (m->nonested && parent) ||
                /* menu excluded for specified labels */
@@ -293,7 +296,7 @@ static const struct menu_entry *next_menu_entry(
                /* excluded for the current label */
                if ((e->exclude && lb && e->exclude & type) ||
                /* entry wanted for specified labels only */
-                   (e->label && lb && !(e->label & type)) ||
+                   (e->label && (!lb || !(e->label & type))) ||
                /* exclude non-expert entries in expect mode */
                    (e->expert == 0 && fdisk_is_details(cxt)) ||
                /* nested only */
@@ -415,7 +418,7 @@ int process_fdisk_menu(struct fdisk_context **cxt0)
        const struct menu *menu;
        int key, rc;
        const char *prompt;
-       char buf[BUFSIZ];
+       char buf[BUFSIZ] = { '\0' };
 
        if (fdisk_is_details(cxt))
                prompt = _("Expert command (m for help): ");
@@ -423,11 +426,24 @@ int process_fdisk_menu(struct fdisk_context **cxt0)
                prompt = _("Command (m for help): ");
 
        fputc('\n',stdout);
-       rc = get_user_reply(cxt, prompt, buf, sizeof(buf));
-       if (rc)
+       rc = get_user_reply(prompt, buf, sizeof(buf));
+
+       if (rc == -ECANCELED) {
+               /* Map ^C and ^D in main menu to 'q' */
+               if (is_interactive
+                   && fdisk_label_is_changed(fdisk_get_label(cxt, NULL))) {
+                       rc = get_user_reply(
+                               _("\nAll unwritten changes will be lost, do you really want to quit? "),
+                               buf, sizeof(buf));
+                       if (rc || !rpmatch(buf))
+                               return 0;
+               }
+               key = 'q';
+       } else if (rc) {
                return rc;
+       } else
+               key = buf[0];
 
-       key = buf[0];
        ent = get_fdisk_menu_entry(cxt, key, &menu);
        if (!ent) {
                fdisk_warnx(cxt, _("%c: unknown command"), key);
@@ -579,10 +595,15 @@ static int generic_menu_cb(struct fdisk_context **cxt0,
                rc = fdisk_write_disklabel(cxt);
                if (rc)
                        err(EXIT_FAILURE, _("failed to write disklabel"));
+
+               fdisk_info(cxt, _("The partition table has been altered."));
                if (fdisk_get_parent(cxt))
                        break; /* nested PT, don't leave */
-               fdisk_info(cxt, _("The partition table has been altered."));
-               rc = fdisk_reread_partition_table(cxt);
+
+               if (device_is_used)
+                       rc = fdisk_reread_changes(cxt, original_layout);
+               else
+                       rc = fdisk_reread_partition_table(cxt);
                if (!rc)
                        rc = fdisk_deassign_device(cxt, 0);
                /* fallthrough */
@@ -631,8 +652,10 @@ static int generic_menu_cb(struct fdisk_context **cxt0,
        switch (ent->key) {
        case 'd':
                rc = fdisk_ask_partnum(cxt, &n, FALSE);
-               if (!rc)
-                       rc = fdisk_delete_partition(cxt, n);
+               if (rc)
+                       break; /* no partitions yet (or ENOMEM, ...) */
+
+               rc = fdisk_delete_partition(cxt, n);
                if (rc)
                        fdisk_warnx(cxt, _("Could not delete partition %zu"), n + 1);
                else
@@ -671,7 +694,7 @@ static int generic_menu_cb(struct fdisk_context **cxt0,
                fdisk_enable_details(cxt, 1);
                break;
        case 'r':
-               /* return from nested BSD to DOS */
+               /* return from nested BSD to DOS or MBR to GPT */
                if (fdisk_get_parent(cxt)) {
                        *cxt0 = fdisk_get_parent(cxt);
 
@@ -721,7 +744,8 @@ static int gpt_menu_cb(struct fdisk_context **cxt0,
                        if (!mbr)
                                return -ENOMEM;
                        *cxt0 = cxt = mbr;
-                       fdisk_enable_details(cxt, 1);   /* keep us in expert mode */
+                       if (fdisk_is_details(cxt))
+                               fdisk_enable_details(cxt, 1);   /* keep us in expert mode */
                        fdisk_info(cxt, _("Entering protective/hybrid MBR disklabel."));
                        return 0;
                }
@@ -841,7 +865,7 @@ static int dos_menu_cb(struct fdisk_context **cxt0,
                rc = fdisk_set_disklabel_id(cxt);
                break;
        case 'M':
-               /* return from nested MBR to GPT */
+               /* return from nested MBR to GPT (backward compatibility only) */
                if (fdisk_get_parent(cxt)) {
                        *cxt0 = fdisk_get_parent(cxt);
 
@@ -984,32 +1008,50 @@ static int bsd_menu_cb(struct fdisk_context **cxt0,
        return rc;
 }
 
-/* C/H/S commands */
+/* C/H/S commands
+ *
+ * The geometry setting from this dialog is not persistent and maybe reset by
+ * fdisk_reset_device_properties() (for example when you create a new disk
+ * label). Note that on command line specified -C/-H/-S setting is persistent
+ * as it's based on fdisk_save_user_geometry().
+ */
 static int geo_menu_cb(struct fdisk_context **cxt0,
                       const struct menu *menu __attribute__((__unused__)),
                       const struct menu_entry *ent)
 {
        struct fdisk_context *cxt = *cxt0;
+       struct fdisk_label *lb = fdisk_get_label(cxt, NULL);
        int rc = -EINVAL;
        uintmax_t c = 0, h = 0, s = 0;
+       fdisk_sector_t mi, ma;
 
        DBG(MENU, ul_debug("enter GEO menu"));
 
        assert(cxt);
        assert(ent);
 
+       /* default */
+       if (!lb)
+               lb = fdisk_get_label(cxt, "dos");
+
        switch (ent->key) {
        case 'c':
-               rc =  fdisk_ask_number(cxt, 1, fdisk_get_geom_cylinders(cxt),
-                               1048576, _("Number of cylinders"), &c);
+               fdisk_label_get_geomrange_cylinders(lb, &mi, &ma);
+               rc =  fdisk_ask_number(cxt, mi, fdisk_get_geom_cylinders(cxt),
+                               ma, _("Number of cylinders"), &c);
                break;
        case 'h':
-               rc =  fdisk_ask_number(cxt, 1, fdisk_get_geom_heads(cxt),
-                               256, _("Number of heads"), &h);
+       {
+               unsigned int i, a;
+               fdisk_label_get_geomrange_heads(lb, &i, &a);
+               rc =  fdisk_ask_number(cxt, i, fdisk_get_geom_heads(cxt),
+                               a, _("Number of heads"), &h);
                break;
+       }
        case 's':
-               rc =  fdisk_ask_number(cxt, 1, fdisk_get_geom_sectors(cxt),
-                               63, _("Number of sectors"), &s);
+               fdisk_label_get_geomrange_sectors(lb, &mi, &ma);
+               rc =  fdisk_ask_number(cxt, mi, fdisk_get_geom_sectors(cxt),
+                               ma, _("Number of sectors"), &s);
                break;
        }