]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
cfdisk: provide extra partinfo with "x"
authorOndrej Oprala <ooprala@redhat.com>
Fri, 20 Feb 2015 08:41:19 +0000 (09:41 +0100)
committerKarel Zak <kzak@redhat.com>
Fri, 27 Mar 2015 13:04:44 +0000 (14:04 +0100)
The new 'extra' info provides:

 * filesystem information from libblkid (TYPE, UUID, LABEL)

   This feature is based on libblkid ability to probe specified area
   on the device. It allows to probe for filesystems although the
   partition devices (e.g. /dev/sda2) does not exist. For example from
   disk image:

    # cfdisk /home/archive/fs-images/disk.img

 * additional information from libfdisk (partition UUID, Name, ...)

 * mount information from libmount (from fstab or mountinfo)

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
Co-Author: Karel Zak <kzak@redhat.com>

disk-utils/Makemodule.am
disk-utils/cfdisk.8
disk-utils/cfdisk.c

index 0cedb966b12f966daef9e2b33f94c6ee7fe9b437..3a2b36dd040afc68f425b1c5c8440fcf42f76af9 100644 (file)
@@ -194,22 +194,25 @@ if BUILD_CFDISK
 sbin_PROGRAMS += cfdisk
 dist_man_MANS += disk-utils/cfdisk.8
 cfdisk_SOURCES = disk-utils/cfdisk.c
-cfdisk_LDADD = $(LDADD) libcommon.la libfdisk.la libtcolors.la
-cfdisk_CFLAGS = $(AM_CFLAGS) -I$(ul_libfdisk_incdir)
-
-if BUILD_LIBUUID
-cfdisk_CFLAGS += -I$(ul_libuuid_incdir)
-cfdisk_LDADD += libuuid.la
-endif
+cfdisk_LDADD = \
+       $(LDADD) \
+       libsmartcols.la \
+       libcommon.la \
+       libfdisk.la \
+       libtcolors.la
+cfdisk_CFLAGS = \
+       $(AM_CFLAGS) \
+       -I$(ul_libfdisk_incdir) \
+       -I$(ul_libsmartcols_incdir)
 
 if BUILD_LIBBLKID
 cfdisk_CFLAGS += -I$(ul_libblkid_incdir)
 cfdisk_LDADD += libblkid.la
 endif
 
-if BUILD_LIBSMARTCOLS
-cfdisk_CFLAGS += -I$(ul_libsmartcols_incdir)
-cfdisk_LDADD += libsmartcols.la
+if BUILD_LIBMOUNT
+cfdisk_CFLAGS += -I$(ul_libmount_incdir)
+cfdisk_LDADD += libmount.la
 endif
 
 if HAVE_SLANG
index 79f85cf5b660e4fc5f3176946beaea76abf09a07..ff95aa9dc073c0537754e66b9021ad76913adb3b 100644 (file)
@@ -143,6 +143,9 @@ or
 .BR partx (8),
 or by rebooting the system.
 .TP
+.B x
+Toggle extra information about a partition.
+.TP
 .IR "Up Arrow" , " Down Arrow"
 Move the cursor to the previous or next partition.  If there are more
 partitions than can be displayed on a screen, you can display the next
index e60d9e400c2c6f2b237ec169d7540ebaeec863a8..f4642c26e25e012c924a316789e783e3f7b5b820 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * cfdisk.c - Display or manipulate a disk partition table.
  *
- *     Copyright (C) 2014 Karel Zak <kzak@redhat.com>
+ *     Copyright (C) 2014-2015 Karel Zak <kzak@redhat.com>
  *     Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu)
  *
  *     The original cfdisk was inspired by the fdisk program
 #include <sys/ioctl.h>
 #include <libfdisk.h>
 
+#ifdef HAVE_LIBBLKID
+# include <blkid.h>    /* keep it optional */
+#endif
+
+#ifdef HAVE_LIBMOUNT
+# include <libmount.h> /* keep it optional for non-linux systems */
+#endif
+
 #ifdef HAVE_SLANG_H
 # include <slang.h>
 #elif defined(HAVE_SLANG_SLANG_H)
@@ -54,6 +62,7 @@
 #include "mbsalign.h"
 #include "colors.h"
 #include "debug.h"
+#include "list.h"
 
 #ifdef __GNU__
 # define DEFAULT_DEVICE "/dev/hd0"
@@ -180,10 +189,26 @@ 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 */
+       struct libscols_table   *extra;         /* extra info ('X') */
+       WINDOW                  *w;             /* window with extra info */
+};
+
 /* top level control struct */
 struct cfdisk {
        struct fdisk_context    *cxt;   /* libfdisk context */
        struct fdisk_table      *table; /* partition table */
+
        struct cfdisk_menu      *menu;  /* the current menu */
 
        int     *fields;        /* output columns IDs */
@@ -192,15 +217,24 @@ struct cfdisk {
        char    *linesbuf;      /* table as string */
        size_t  linesbufsz;     /* size of the tb_buf */
 
-       char    **lines;        /* array with lines */
+       struct  cfdisk_line     *lines; /* list of lines */
+
        size_t  nlines;         /* number of lines */
        size_t  lines_idx;      /* current line <0..N>, exclude header */
        size_t  page_sz;
 
        unsigned int nwrites;   /* fdisk_write_disklabel() counter */
 
+       WINDOW  *act_win;       /* the window currently on the screen */
+
+#ifdef HAVE_LIBMOUNT
+       struct libmnt_table *mtab;
+       struct libmnt_table *fstab;
+       struct libmnt_cache *mntcache;
+#endif
        unsigned int    wrong_order :1,         /* PT not in right order */
-                       zero_start :1;          /* ignore existing partition table */
+                       zero_start :1,          /* ignore existing partition table */
+                       show_extra :1;          /* show extra partinfo */
 };
 
 
@@ -400,6 +434,21 @@ done:
        return res;
 }
 
+static void cfdisk_free_lines(struct cfdisk *cf)
+{
+       size_t i = 0;
+       while(i < cf->nlines) {
+               scols_unref_table(cf->lines[i].extra);
+
+               DBG(UI, ul_debug("delete window: %p",
+                               cf->lines[i].w));
+
+               delwin(cf->lines[i].w);
+               ++i;
+       }
+       cf->act_win = NULL;
+       free(cf->lines);
+}
 /*
  * Read data about partitions from libfdisk and prepare output lines.
  */
@@ -414,7 +463,7 @@ static int lines_refresh(struct cfdisk *cf)
        DBG(TABLE, ul_debug("refreshing buffer"));
 
        free(cf->linesbuf);
-       free(cf->lines);
+       cfdisk_free_lines(cf);
        cf->linesbuf = NULL;
        cf->linesbufsz = 0;
        cf->lines = NULL;
@@ -442,15 +491,19 @@ static int lines_refresh(struct cfdisk *cf)
        if (MENU_START_LINE - TABLE_START_LINE < cf->nlines)
                cf->page_sz = MENU_START_LINE - TABLE_START_LINE - 1;
 
-       cf->lines = xcalloc(cf->nlines, sizeof(char *));
+       cf->lines = xcalloc(cf->nlines, sizeof(struct cfdisk_line));
 
        for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) {
-               cf->lines[i] = p;
+               cf->lines[i].data = p;
                p = strchr(p, '\n');
                if (p) {
                        *p = '\0';
                        p++;
                }
+               cf->lines[i].extra = scols_new_table();
+               scols_table_enable_noheadings(cf->lines[i].extra, 1);
+               scols_table_new_column(cf->lines[i].extra, NULL, 0, SCOLS_FL_RIGHT);
+               scols_table_new_column(cf->lines[i].extra, NULL, 0, SCOLS_FL_TRUNC);
        }
 
        return 0;
@@ -1119,6 +1172,264 @@ static void ui_draw_menu(struct cfdisk *cf)
        DBG(MENU, ul_debug("draw end."));
 }
 
+inline static int extra_insert_pair(struct cfdisk_line *l, const char *name, const char *data)
+{
+       struct libscols_line *lsl;
+
+       assert(l);
+
+       if (!data && !*data)
+               return 0;
+
+       lsl = scols_table_new_line(l->extra, NULL);
+       if (!lsl)
+               return -ENOMEM;
+
+       scols_line_set_data(lsl, 0, name);
+       scols_line_set_data(lsl, 1, data);
+
+       return 0;
+}
+
+#ifdef HAVE_LIBMOUNT
+static char *get_mountpoint(struct cfdisk *cf, const char *uuid, const char *label)
+{
+       struct libmnt_fs *fs = NULL;
+       char *target = NULL;
+       int mounted = 0;
+
+       assert(uuid || label);
+
+       DBG(UI, ul_debug("asking for mountpoint [uuid=%s, label=%s]", uuid, label));
+
+       if (!cf->mntcache)
+               cf->mntcache = mnt_new_cache();
+
+       /* 1st try between mounted filesystems */
+       if (!cf->mtab) {
+               cf->mtab = mnt_new_table();
+               if (cf->mtab) {
+                       mnt_table_set_cache(cf->mtab, cf->mntcache);
+                       mnt_table_parse_mtab(cf->mtab, NULL);
+               }
+       }
+
+       if (cf->mtab)
+               fs = mnt_table_find_tag(cf->mtab,
+                                       uuid ? "UUID" : "LABEL",
+                                       uuid ? : label, MNT_ITER_FORWARD);
+
+       /* 2nd try fstab */
+       if (!fs) {
+               if (!cf->fstab) {
+                       cf->fstab = mnt_new_table();
+                       if (cf->fstab) {
+                               mnt_table_set_cache(cf->fstab, cf->mntcache);
+                               mnt_table_parse_fstab(cf->fstab, NULL);
+                       }
+               }
+               if (cf->fstab)
+                       fs = mnt_table_find_tag(cf->fstab,
+                                       uuid ? "UUID" : "LABEL",
+                                       uuid ? : label, MNT_ITER_FORWARD);
+       } else
+               mounted = 1;
+
+       if (fs) {
+               if (mounted)
+                       xasprintf(&target, _("%s (mounted)"), mnt_fs_get_target(fs));
+               else
+                       target = xstrdup(mnt_fs_get_target(fs));
+       }
+
+       return target;
+}
+#endif /* HAVE_LIBMOUNT */
+
+static void extra_prepare_data(struct cfdisk *cf)
+{
+       struct fdisk_partition *pa = get_current_partition(cf);
+       struct cfdisk_line *l = &cf->lines[cf->lines_idx];
+       char *data = NULL;
+       char *devuuid = NULL, *devlabel = NULL;
+
+       DBG(UI, ul_debug("preparing extra data"));
+
+       /* string data should not equal an empty string */
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_NAME, &data) && data) {
+               extra_insert_pair(l, _("Partition name:"), data);
+               free(data);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_UUID, &data) && data) {
+               extra_insert_pair(l, _("Partition UUID:"), data);
+               free(data);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_TYPE, &data) && data) {
+               char *code = NULL, *type = NULL;
+
+               fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_TYPEID, &code);
+               xasprintf(&type, "%s (%s)", data, code);
+
+               extra_insert_pair(l, _("Partition type:"), type);
+               free(data);
+               free(code);
+               free(type);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_ATTR, &data) && data) {
+               extra_insert_pair(l, _("Attributes:"), data);
+               free(data);
+       }
+
+       /* for numeric data, only show non-zero rows */
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_BSIZE, &data) && data) {
+               if (atoi(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))
+                       extra_insert_pair(l, "CPG:", data);
+               free(data);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_FSIZE, &data) && data) {
+               if (atoi(data))
+                       extra_insert_pair(l, "FSIZE:", data);
+               free(data);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_SADDR, &data) && data) {
+               extra_insert_pair(l, _("Start C/H/S:"), data);
+               free(data);
+       }
+
+       if (!fdisk_partition_to_string(pa, cf->cxt, FDISK_FIELD_EADDR, &data) && data) {
+               extra_insert_pair(l, _("End C/H/S:"), data);
+               free(data);
+       }
+
+#ifdef HAVE_LIBBLKID
+       if (fdisk_partition_has_start(pa) && fdisk_partition_has_size(pa)) {
+               int fd;
+               uintmax_t start, size;
+               blkid_probe pr = blkid_new_probe();
+
+               if (!pr)
+                       goto done;
+
+               DBG(UI, ul_debug("blkid prober: %p", pr));
+
+               start = fdisk_partition_get_start(pa) * fdisk_get_sector_size(cf->cxt);
+               size = fdisk_partition_get_size(pa) * fdisk_get_sector_size(cf->cxt);
+               fd = fdisk_get_devfd(cf->cxt);
+
+               if (blkid_probe_set_device(pr, fd, start, size) == 0 &&
+                   blkid_do_fullprobe(pr) == 0) {
+                       const char *bdata = NULL;
+
+                       if (!blkid_probe_lookup_value(pr, "TYPE", &bdata, NULL))
+                               extra_insert_pair(l, _("Filesystem:"), bdata);
+                       if (!blkid_probe_lookup_value(pr, "LABEL", &bdata, NULL)) {
+                               extra_insert_pair(l, _("Filesystem LABEL:"), bdata);
+                               devlabel = xstrdup(bdata);
+                       }
+                       if (!blkid_probe_lookup_value(pr, "UUID", &bdata, NULL)) {
+                               extra_insert_pair(l, _("Filesystem UUID:"), bdata);
+                               devuuid = xstrdup(bdata);
+                       }
+               }
+               blkid_free_probe(pr);
+       }
+#endif /* HAVE_LIBBLKID */
+
+#ifdef HAVE_LIBMOUNT
+       if (devuuid || devlabel) {
+               data = get_mountpoint(cf, devuuid, devlabel);
+               if (data) {
+                       extra_insert_pair(l, _("Mountpoint:"), data);
+                       free(data);
+               }
+       }
+#endif /* HAVE_LIBMOUNT */
+done:
+       free(devlabel);
+       free(devuuid);
+}
+
+static void ui_clear_extra(struct cfdisk *cf)
+{
+       DBG(UI, ul_debug("clear window: %p", cf->act_win));
+
+       wclear(cf->act_win);
+       wrefresh(cf->act_win);
+}
+
+static int ui_draw_extra(struct cfdisk *cf)
+{
+       WINDOW *win_ex;
+       int wline = 1;
+       struct cfdisk_line *ln = &cf->lines[cf->lines_idx];
+       char *tbstr = NULL, *end;
+       int win_ex_start_line, win_height, tblen;
+       int ndatalines;
+
+       if (scols_table_is_empty(ln->extra))
+               extra_prepare_data(cf);
+
+       ndatalines = fdisk_table_get_nents(cf->table) + 1;
+
+       /* nents + header + one free line */
+       win_ex_start_line = TABLE_START_LINE + ndatalines;
+       win_height = MENU_START_LINE - win_ex_start_line;
+       tblen = scols_table_get_nlines(ln->extra);
+
+       /* we can't get a single line of data under the partlist*/
+       if (win_height < 3)
+               return 1;
+
+       /* number of data lines + 2 for top/bottom lines */
+       win_height = win_height < tblen + 2 ? win_height : tblen + 2;
+
+       if ((size_t) win_ex_start_line + win_height + 1 < MENU_START_LINE)
+               win_ex_start_line = MENU_START_LINE - win_height;
+
+       win_ex = newwin(win_height, ui_cols - 2, win_ex_start_line, 1);
+
+       scols_table_reduce_termwidth(ln->extra, 4);
+       scols_print_table_to_string(ln->extra, &tbstr);
+
+       end = tbstr;
+       while ((end = strchr(end, '\n')))
+               *end++ = '\0';
+
+       box(win_ex, 0, 0);
+
+       end = tbstr;
+       while (--win_height > 1) {
+               mvwaddstr(win_ex, wline++, 1 /* window column*/, tbstr);
+               tbstr += strlen(tbstr) + 1;
+       }
+       free(end);
+
+#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H)
+       /* clear the currently shown extra window */
+       ui_clear_extra(cf);
+#endif
+
+       DBG(UI, ul_debug("delete window: %p", ln->w));
+       delwin(ln->w);
+
+       DBG(UI, ul_debug("draw window: %p", win_ex));
+       wrefresh(win_ex);
+
+       cf->act_win = ln->w = win_ex;
+       return 0;
+}
+
 static void ui_menu_goto(struct cfdisk *cf, int where)
 {
        struct cfdisk_menuitem *d;
@@ -1155,6 +1466,7 @@ static void ui_menu_goto(struct cfdisk *cf, int where)
 
        d = menu_get_menuitem(cf, where);
        ui_draw_menuitem(cf, d, where);
+
 }
 
 static int ui_menu_move(struct cfdisk *cf, int key)
@@ -1261,7 +1573,7 @@ static void ui_draw_partition(struct cfdisk *cf, size_t i)
        if (cur) {
                attron(A_REVERSE);
                mvaddstr(ln, 0, ARROW_CURSOR_STRING);
-               mvaddstr(ln, cl, cf->lines[i + 1]);
+               mvaddstr(ln, cl, cf->lines[i + 1].data);
                attroff(A_REVERSE);
        } else {
                int at = 0;
@@ -1271,9 +1583,9 @@ static void ui_draw_partition(struct cfdisk *cf, size_t i)
                        at = 1;
                }
                mvaddstr(ln, 0, ARROW_CURSOR_DUMMY);
-               mvaddstr(ln, cl, cf->lines[i + 1]);
+               mvaddstr(ln, cl, cf->lines[i + 1].data);
                if (at)
-                        attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
+                       attroff(COLOR_PAIR(CFDISK_CL_FREESPACE));
        }
 
        if ((size_t) ln == MENU_START_LINE - 1 &&
@@ -1285,6 +1597,7 @@ static void ui_draw_partition(struct cfdisk *cf, size_t i)
                if (cur)
                        attroff(A_REVERSE);
        }
+
 }
 
 static int ui_draw_table(struct cfdisk *cf)
@@ -1305,7 +1618,7 @@ static int ui_draw_table(struct cfdisk *cf)
 
        /* print header */
        attron(A_BOLD);
-       mvaddstr(TABLE_START_LINE, cl, cf->lines[0]);
+       mvaddstr(TABLE_START_LINE, cl, cf->lines[0].data);
        attroff(A_BOLD);
 
        /* print partitions */
@@ -1350,6 +1663,9 @@ static int ui_table_goto(struct cfdisk *cf, int where)
        ui_clean_info();
        ui_draw_menu(cf);
        refresh();
+
+       if (cf->show_extra)
+               ui_draw_extra(cf);
        return 0;
 }
 
@@ -1850,6 +2166,7 @@ static int ui_help(void)
                N_("  W          Write partition table to disk (you must enter uppercase W);"),
                N_("               since this might destroy data on the disk, you must either"),
                N_("               confirm or deny the write by entering 'yes' or 'no'"),
+               N_("  x          Display/hide extra information about a partition"),
                N_("Up Arrow     Move cursor to the previous partition"),
                N_("Down Arrow   Move cursor to the next partition"),
                N_("Left Arrow   Move cursor to the previous menu item"),
@@ -1898,6 +2215,7 @@ static int main_menu_ignore_keys(struct cfdisk *cf, char *ignore,
 
        if (fdisk_is_readonly(cf->cxt))
                ignore[i++] = 'W';
+
        return i;
 }
 
@@ -2034,6 +2352,10 @@ static int main_menu_action(struct cfdisk *cf, int key)
        case 'u': /* dUmp */
                ui_script_write(cf);
                break;
+       case 'x': /* Extra */
+               cf->show_extra = cf->show_extra ? 0 : 1;
+               ref = 1;
+               break;
        case 'W': /* Write */
        {
                char buf[64] = { 0 };
@@ -2075,6 +2397,9 @@ static int main_menu_action(struct cfdisk *cf, int key)
        } else
                ui_draw_menu(cf);
 
+       if (cf->show_extra)
+               ui_draw_extra(cf);
+
        ui_clean_hint();
 
        if (warn)
@@ -2093,6 +2418,9 @@ static void ui_resize_refresh(struct cfdisk *cf)
        menu_refresh_size(cf);
        lines_refresh(cf);
        ui_refresh(cf);
+
+       if (cf->show_extra)
+               ui_draw_extra(cf);
 }
 
 static int ui_run(struct cfdisk *cf)
@@ -2120,16 +2448,27 @@ static int ui_run(struct cfdisk *cf)
        menu_push(cf, main_menuitems);
        cf->menu->ignore_cb = main_menu_ignore_keys;
 
+
        rc = ui_refresh(cf);
        if (rc)
                return rc;
 
+       cf->show_extra = 1;
+               ui_draw_extra(cf);
+
        if (fdisk_is_readonly(cf->cxt))
                ui_warnx(_("Device open in read-only mode."));
        else if (cf->wrong_order)
                 ui_info(_("Note that partition table entries are not in disk order now."));
 
        do {
+#if defined(HAVE_SLANG_H) || defined(HAVE_SLCURSES_H)
+               /* slang getch() seems to clear
+                * the extra window from the screen,
+                * so turn off the flag as well
+                */
+               cf->show_extra = 0;
+#endif
                int key = getch();
 
                rc = 0;
@@ -2285,10 +2624,15 @@ int main(int argc, char *argv[])
        ui_run(cf);
        ui_end();
 
-       free(cf->lines);
+       cfdisk_free_lines(cf);
        free(cf->linesbuf);
-       fdisk_unref_table(cf->table);
 
+       fdisk_unref_table(cf->table);
+#ifdef HAVE_LIBMOUNT
+       mnt_unref_table(cf->fstab);
+       mnt_unref_table(cf->mtab);
+       mnt_unref_cache(cf->mntcache);
+#endif
        rc = fdisk_deassign_device(cf->cxt, cf->nwrites == 0);
        fdisk_unref_context(cf->cxt);
        DBG(MISC, ul_debug("bye! [rc=%d]", rc));