]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/cfdisk.c
include/pidfd-utils: remove hardcoded syscall fallback
[thirdparty/util-linux.git] / disk-utils / cfdisk.c
index b549fe95ba18003fb0c93c468b1a5e1842b93f20..7b61929614cfa61e5c9ce51cc78358217a6e7060 100644 (file)
@@ -1,16 +1,18 @@
 /*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
  * cfdisk.c - Display or manipulate a disk partition table.
  *
- *     Copyright (C) 2014-2015 Karel Zak <kzak@redhat.com>
+ *     Copyright (C) 2014-2023 Karel Zak <kzak@redhat.com>
  *     Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
  *
  *     The original cfdisk was inspired by the fdisk program
  *           by A. V. Le Blanc (leblanc@mcc.ac.uk.
- *
- * cfdisk is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
  */
 #include <stdlib.h>
 #include <stdio.h>
@@ -21,6 +23,7 @@
 #include <assert.h>
 #include <libsmartcols.h>
 #include <sys/ioctl.h>
+#include <rpmatch.h>
 #include <libfdisk.h>
 
 #ifdef HAVE_LIBMOUNT
@@ -124,12 +127,14 @@ enum {
        CFDISK_CL_FREESPACE,
        CFDISK_CL_INFO
 };
+#ifdef HAVE_USE_DEFAULT_COLORS
 static const int color_pairs[][2] = {
        /* color            foreground, background */
        [CFDISK_CL_WARNING]   = { COLOR_RED, -1 },
        [CFDISK_CL_FREESPACE] = { COLOR_GREEN, -1 },
        [CFDISK_CL_INFO]      = { COLOR_BLUE, -1 }
 };
+#endif
 
 struct cfdisk;
 
@@ -141,9 +146,14 @@ static void menu_refresh_size(struct cfdisk *cf);
 
 static int ui_end(void);
 static int ui_refresh(struct cfdisk *cf);
-static void ui_warnx(const char *fmt, ...);
-static void ui_warn(const char *fmt, ...);
-static void ui_info(const char *fmt, ...);
+
+static void ui_warnx(const char *fmt, ...)
+                       __attribute__((__format__ (__printf__, 1, 2)));
+static void ui_warn(const char *fmt, ...)
+                       __attribute__((__format__ (__printf__, 1, 2)));
+static void ui_info(const char *fmt, ...)
+                       __attribute__((__format__ (__printf__, 1, 2)));
+
 static void ui_draw_menu(struct cfdisk *cf);
 static int ui_menu_move(struct cfdisk *cf, int key);
 static void ui_menu_resize(struct cfdisk *cf);
@@ -201,14 +211,6 @@ static struct cfdisk_menuitem main_menuitems[] = {
        { 0, NULL, NULL }
 };
 
-/* extra partinfo in name:value pairs */
-struct cfdisk_extra {
-       char *name;
-       char *data;
-
-       struct list_head exs;
-};
-
 /* line and extra partinfo list_head */
 struct cfdisk_line {
        char                    *data;          /* line data */
@@ -630,13 +632,13 @@ static int ask_callback(struct fdisk_context *cxt __attribute__((__unused__)),
 
        switch(fdisk_ask_get_type(ask)) {
        case FDISK_ASKTYPE_INFO:
-               ui_info(fdisk_ask_print_get_mesg(ask));
+               ui_info("%s", fdisk_ask_print_get_mesg(ask));
                break;
        case FDISK_ASKTYPE_WARNX:
-               ui_warnx(fdisk_ask_print_get_mesg(ask));
+               ui_warnx("%s", fdisk_ask_print_get_mesg(ask));
                break;
        case FDISK_ASKTYPE_WARN:
-               ui_warn(fdisk_ask_print_get_mesg(ask));
+               ui_warn("%s", fdisk_ask_print_get_mesg(ask));
                break;
        case FDISK_ASKTYPE_MENU:
                ask_menu(ask, (struct cfdisk *) data);
@@ -668,7 +670,8 @@ static int ui_end(void)
        return 0;
 }
 
-static void ui_vprint_center(size_t line, int attrs, const char *fmt, va_list ap)
+static void __attribute__((__format__ (__printf__, 3, 0)))
+       ui_vprint_center(size_t line, int attrs, const char *fmt, va_list ap)
 {
        size_t width;
        char *buf = NULL;
@@ -698,7 +701,8 @@ static void ui_vprint_center(size_t line, int attrs, const char *fmt, va_list ap
        free(buf);
 }
 
-static void ui_center(size_t line, const char *fmt, ...)
+static void __attribute__((__format__ (__printf__, 2, 3)))
+       ui_center(size_t line, const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
@@ -706,7 +710,8 @@ static void ui_center(size_t line, const char *fmt, ...)
        va_end(ap);
 }
 
-static void ui_warnx(const char *fmt, ...)
+static void __attribute__((__format__ (__printf__, 1, 2)))
+       ui_warnx(const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
@@ -721,7 +726,8 @@ static void ui_warnx(const char *fmt, ...)
        va_end(ap);
 }
 
-static void ui_warn(const char *fmt, ...)
+static void __attribute__((__format__ (__printf__, 1, 2)))
+       ui_warn(const char *fmt, ...)
 {
        char *fmt_m;
        va_list ap;
@@ -747,8 +753,10 @@ static void ui_clean_warn(void)
        clrtoeol();
 }
 
-static int __attribute__((__noreturn__)) ui_err(int rc, const char *fmt, ...)
-               {
+static int __attribute__((__noreturn__))
+          __attribute__((__format__ (__printf__, 2, 3)))
+       ui_err(int rc, const char *fmt, ...)
+{
        va_list ap;
        ui_end();
 
@@ -761,7 +769,9 @@ static int __attribute__((__noreturn__)) ui_err(int rc, const char *fmt, ...)
        exit(rc);
 }
 
-static int __attribute__((__noreturn__)) ui_errx(int rc, const char *fmt, ...)
+static int __attribute__((__noreturn__))
+          __attribute__((__format__ (__printf__, 2, 3)))
+       ui_errx(int rc, const char *fmt, ...)
                {
        va_list ap;
        ui_end();
@@ -775,7 +785,8 @@ static int __attribute__((__noreturn__)) ui_errx(int rc, const char *fmt, ...)
        exit(rc);
 }
 
-static void ui_info(const char *fmt, ...)
+static void __attribute__((__format__ (__printf__, 1, 2)))
+       ui_info(const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
@@ -796,7 +807,8 @@ static void ui_clean_info(void)
        clrtoeol();
 }
 
-static void ui_hint(const char *fmt, ...)
+static void __attribute__((__format__ (__printf__, 1, 2)))
+       ui_hint(const char *fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
@@ -1130,7 +1142,7 @@ static void ui_draw_menuitem(struct cfdisk *cf,
        if (cf->menu->idx == idx) {
                standend();
                if (d->desc)
-                       ui_hint(_(d->desc));
+                       ui_hint("%s", _(d->desc));
        }
 }
 
@@ -1307,6 +1319,34 @@ static char *get_mountpoint(struct cfdisk *cf, const char *tagname, const char *
 }
 #endif /* HAVE_LIBMOUNT */
 
+static inline int iszero(const char *str)
+{
+       const char *p;
+
+       for (p = str; p && *p == '0'; p++);
+
+       return !p || *p == '\0';
+}
+
+static int has_uuid(struct fdisk_table *tb, const char *uuid)
+{
+       struct fdisk_partition *pa;
+       struct fdisk_iter *itr;
+       int rc = 0;
+
+       if (!tb || !uuid || fdisk_table_is_empty(tb))
+               return 0;
+
+       itr = fdisk_new_iter(FDISK_ITER_FORWARD);
+       while (rc == 0 && fdisk_table_next_partition(tb, itr, &pa) == 0) {
+               const char *x = fdisk_partition_get_uuid(pa);
+               if (x)
+                       rc = strcmp(x, uuid) == 0;
+       }
+       fdisk_free_iter(itr);
+       return rc;
+}
+
 static void extra_prepare_data(struct cfdisk *cf)
 {
        struct fdisk_partition *pa = get_current_partition(cf);
@@ -1326,7 +1366,14 @@ static void extra_prepare_data(struct cfdisk *cf)
 
        if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_UUID, &data) && data) {
                extra_insert_pair(l, _("Partition UUID:"), data);
-               if (!mountpoint)
+
+               /* Search for mountpoint by PARTUUID= means that we need to
+                * check fstab and convert PARTUUID to the device name. This is
+                * unnecessary and overkill for newly created partitions. Let's
+                * check if the UUID already exist in the old layout, otherwise
+                * ignore it.
+                */
+               if (!mountpoint && has_uuid(cf->original_layout, data))
                        mountpoint = get_mountpoint(cf, "PARTUUID", data);
                free(data);
        }
@@ -1350,19 +1397,19 @@ static void extra_prepare_data(struct cfdisk *cf)
 
        /* for numeric data, only show non-zero rows */
        if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_BSIZE, &data) && data) {
-               if (atoi(data))
+               if (!iszero(data))
                        extra_insert_pair(l, "BSIZE:", data);
                free(data);
        }
 
        if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_CPG, &data) && data) {
-               if (atoi(data))
+               if (!iszero(data))
                        extra_insert_pair(l, "CPG:", data);
                free(data);
        }
 
        if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSIZE, &data) && data) {
-               if (atoi(data))
+               if (!iszero(data))
                        extra_insert_pair(l, "FSIZE:", data);
                free(data);
        }
@@ -1778,7 +1825,7 @@ static ssize_t ui_get_string(const char *prompt,
        mbs_edit_goto(edit, MBS_EDIT_END);
 
        if (hint)
-               ui_hint(hint);
+               ui_hint("%s", hint);
        else
                ui_clean_hint();
 
@@ -2030,7 +2077,7 @@ done:
        }
        free(cm);
        DBG(UI, ul_debug("get parrtype done [type=%s] ", t ?
-                               fdisk_parttype_get_name(t) : NULL));
+                               fdisk_parttype_get_name(t) : ""));
        return t;
 }
 
@@ -2150,7 +2197,7 @@ static int ui_create_label(struct cfdisk *cf)
 
                if (refresh_menu) {
                        ui_draw_menu(cf);
-                       ui_hint(_("Select a type to create a new label or press 'L' to load script file."));
+                       ui_hint(_("Select a type to create a new label, press 'L' to load script file, 'Q' quits."));
                        refresh();
                        refresh_menu = 0;
                }
@@ -2204,11 +2251,13 @@ static int ui_help(void)
                "  ",
                N_("Command      Meaning"),
                N_("-------      -------"),
-               N_("  b          Toggle bootable flag of the current partition"),
+               N_("  b          Toggle bootable flag of the current partition;"),
+               N_("               implemented for DOS (MBR) and SGI labels only"),
                N_("  d          Delete the current partition"),
                N_("  h          Print this screen"),
                N_("  n          Create new partition from free space"),
                N_("  q          Quit program without writing partition table"),
+               N_("  r          Reduce or enlarge the current partition"),
                N_("  s          Fix partitions order (only when in disarray)"),
                N_("  t          Change the partition type"),
                N_("  u          Dump disk layout to sfdisk compatible script file"),
@@ -2227,7 +2276,7 @@ static int ui_help(void)
                N_("Use lsblk(8) or partx(8) to see more details about the device."),
                "  ",
                "  ",
-               "Copyright (C) 2014-2017 Karel Zak <kzak@redhat.com>"
+               "Copyright (C) 2014-2023 Karel Zak <kzak@redhat.com>"
        };
 
        erase();
@@ -2401,18 +2450,17 @@ static int main_menu_action(struct cfdisk *cf, int key)
        }
        case 'r': /* resize */
        {
-               struct fdisk_partition *npa, *next;
                uint64_t size, max_size, secs;
+               struct fdisk_partition *npa;
 
                if (fdisk_partition_is_freespace(pa) || !fdisk_partition_has_start(pa))
                        return -EINVAL;
 
-               size = fdisk_partition_get_size(pa);
-
-               /* is the next freespace? */
-               next = fdisk_table_get_partition(cf->table, cf->lines_idx + 1);
-               if (next && fdisk_partition_is_freespace(next))
-                       size += fdisk_partition_get_size(next);
+               rc = fdisk_partition_get_max_size(cf->cxt,
+                                                 fdisk_partition_get_partno(pa),
+                                                 &size);
+               if (rc)
+                       return rc;
 
                size *= fdisk_get_sector_size(cf->cxt);
                max_size = size;
@@ -2470,11 +2518,15 @@ static int main_menu_action(struct cfdisk *cf, int key)
                if (rc)
                        warn = _("Failed to write disklabel.");
                else {
+                       size_t q_idx = 0;
+
                        if (cf->device_is_used)
                                fdisk_reread_changes(cf->cxt, cf->original_layout);
                        else
                                fdisk_reread_partition_table(cf->cxt);
                        info = _("The partition table has been altered.");
+                       if (menu_get_menuitem_by_key(cf, 'q', &q_idx))
+                               ui_menu_goto(cf, q_idx);
                }
                cf->nwrites++;
                break;
@@ -2534,11 +2586,17 @@ static int ui_run(struct cfdisk *cf)
        DBG(UI, ul_debug("start cols=%zu, lines=%zu", ui_cols, ui_lines));
 
        if (fdisk_get_collision(cf->cxt)) {
-               ui_warnx(_("Device already contains a %s signature; it will be removed by a write command."),
-                               fdisk_get_collision(cf->cxt));
-               fdisk_enable_wipe(cf->cxt, 1);
-               ui_hint(_("Press a key to continue."));
-               getch();
+               ui_warnx(_("Device already contains a %s signature."), fdisk_get_collision(cf->cxt));
+               if (fdisk_is_readonly(cf->cxt)) {
+                       ui_hint(_("Press a key to continue."));
+                       getch();
+               } else {
+                       char buf[64] = { 0 };
+                       rc = ui_get_string(_("Do you want to remove it? [Y]es/[N]o: "), NULL,
+                                       buf, sizeof(buf));
+                       fdisk_enable_wipe(cf->cxt,
+                                       rc > 0 && rpmatch(buf) == RPMATCH_YES ? 1 : 0);
+               }
        }
 
        if (!fdisk_has_label(cf->cxt) || cf->zero_start) {
@@ -2569,6 +2627,8 @@ static int ui_run(struct cfdisk *cf)
 
        if (fdisk_is_readonly(cf->cxt))
                ui_warnx(_("Device is open in read-only mode. Changes will remain in memory only."));
+       else if (cf->device_is_used)
+               ui_warnx(_("Device is currently in use, repartitioning is probably a bad idea."));
        else if (cf->wrong_order)
                ui_info(_("Note that partition table entries are not in disk order now."));
 
@@ -2670,9 +2730,9 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -r, --read-only          forced open cfdisk in read-only mode\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
-       printf(USAGE_HELP_OPTIONS(26));
+       fprintf(out, USAGE_HELP_OPTIONS(26));
 
-       printf(USAGE_MAN_TAIL("cfdisk(8)"));
+       fprintf(out, USAGE_MAN_TAIL("cfdisk(8)"));
        exit(EXIT_SUCCESS);
 }