summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Oprala2015-02-20 09:41:19 +0100
committerKarel Zak2015-03-27 14:04:44 +0100
commitdda7fe12acff6613f23c67de15905848b7521767 (patch)
tree37aa0891825d69ddef40b030d711fc90d46824ab
parentlibfdisk: don't return empty strings from fdisk_partition_to_string() (diff)
downloadkernel-qcow2-util-linux-dda7fe12acff6613f23c67de15905848b7521767.tar.gz
kernel-qcow2-util-linux-dda7fe12acff6613f23c67de15905848b7521767.tar.xz
kernel-qcow2-util-linux-dda7fe12acff6613f23c67de15905848b7521767.zip
cfdisk: provide extra partinfo with "x"
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>
-rw-r--r--disk-utils/Makemodule.am23
-rw-r--r--disk-utils/cfdisk.83
-rw-r--r--disk-utils/cfdisk.c368
3 files changed, 372 insertions, 22 deletions
diff --git a/disk-utils/Makemodule.am b/disk-utils/Makemodule.am
index 0cedb966b..3a2b36dd0 100644
--- a/disk-utils/Makemodule.am
+++ b/disk-utils/Makemodule.am
@@ -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
diff --git a/disk-utils/cfdisk.8 b/disk-utils/cfdisk.8
index 79f85cf5b..ff95aa9dc 100644
--- a/disk-utils/cfdisk.8
+++ b/disk-utils/cfdisk.8
@@ -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
diff --git a/disk-utils/cfdisk.c b/disk-utils/cfdisk.c
index e60d9e400..f4642c26e 100644
--- a/disk-utils/cfdisk.c
+++ b/disk-utils/cfdisk.c
@@ -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
@@ -23,6 +23,14 @@
#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));