]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/lsblk.c
hwclock: free temporary variable before return
[thirdparty/util-linux.git] / misc-utils / lsblk.c
index 164e38291c22acae0b56488f7de564f3a742393c..2df7752670744e9676d8b5106f5e6f25c0d2ba65 100644 (file)
@@ -53,6 +53,7 @@
 #include "loopdev.h"
 #include "buffer.h"
 #include "colors.h"
+#include "column-list-table.h"
 
 #include "lsblk.h"
 
@@ -175,15 +176,15 @@ static const struct colinfo infos[] = {
        [COL_IDLINK] = { "ID-LINK", 0.1, SCOLS_FL_NOEXTREMES, N_("the shortest udev /dev/disk/by-id link name") },
        [COL_DALIGN] = { "DISC-ALN", 6, SCOLS_FL_RIGHT, N_("discard alignment offset"), COLTYPE_NUM },
        [COL_DAX] = { "DAX", 1, SCOLS_FL_RIGHT, N_("dax-capable device"), COLTYPE_BOOL },
-       [COL_DGRAN] = { "DISC-GRAN", 6, SCOLS_FL_RIGHT, N_("discard granularity"), COLTYPE_SIZE },
+       [COL_DGRAN] = { "DISC-GRAN", 6, SCOLS_FL_RIGHT, N_("discard granularity, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_DISKSEQ] = { "DISK-SEQ", 1, SCOLS_FL_RIGHT, N_("disk sequence number"), COLTYPE_NUM },
-       [COL_DMAX] = { "DISC-MAX", 6, SCOLS_FL_RIGHT, N_("discard max bytes"), COLTYPE_SIZE },
+       [COL_DMAX] = { "DISC-MAX", 6, SCOLS_FL_RIGHT, N_("discard max bytes, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_DZERO] = { "DISC-ZERO", 1, SCOLS_FL_RIGHT, N_("discard zeroes data"), COLTYPE_BOOL },
-       [COL_FSAVAIL] = { "FSAVAIL", 5, SCOLS_FL_RIGHT, N_("filesystem size available"), COLTYPE_SIZE },
+       [COL_FSAVAIL] = { "FSAVAIL", 5, SCOLS_FL_RIGHT, N_("filesystem size available for unprivileged users, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_FSROOTS] = { "FSROOTS", 0.1, SCOLS_FL_WRAP, N_("mounted filesystem roots") },
-       [COL_FSSIZE] = { "FSSIZE", 5, SCOLS_FL_RIGHT, N_("filesystem size"), COLTYPE_SIZE },
+       [COL_FSSIZE] = { "FSSIZE", 5, SCOLS_FL_RIGHT, N_("filesystem size, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_FSTYPE] = { "FSTYPE", 0.1, SCOLS_FL_TRUNC, N_("filesystem type") },
-       [COL_FSUSED] = { "FSUSED", 5, SCOLS_FL_RIGHT, N_("filesystem size used"), COLTYPE_SIZE },
+       [COL_FSUSED] = { "FSUSED", 5, SCOLS_FL_RIGHT, N_("filesystem size used, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_FSUSEPERC] = { "FSUSE%", 3, SCOLS_FL_RIGHT, N_("filesystem use percentage") },
        [COL_FSVERSION] = { "FSVER", 0.1, SCOLS_FL_TRUNC, N_("filesystem version") },
        [COL_GROUP] = { "GROUP", 0.1, SCOLS_FL_TRUNC, N_("group name") },
@@ -222,8 +223,8 @@ static const struct colinfo infos[] = {
        [COL_RQ_SIZE]= { "RQ-SIZE", 5, SCOLS_FL_RIGHT, N_("request queue size"), COLTYPE_NUM },
        [COL_SCHED] = { "SCHED", 0.1, 0, N_("I/O scheduler name") },
        [COL_SERIAL] = { "SERIAL", 0.1, SCOLS_FL_TRUNC, N_("disk serial number") },
-       [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("size of the device"), COLTYPE_SIZE },
-       [COL_START] = { "START", 5, SCOLS_FL_RIGHT, N_("partition start offset"), COLTYPE_NUM },
+       [COL_SIZE] = { "SIZE", 5, SCOLS_FL_RIGHT, N_("size of the device, use <number> if --bytes is given"), COLTYPE_SIZE },
+       [COL_START] = { "START", 5, SCOLS_FL_RIGHT, N_("partition start offset (in 512-byte sectors)"), COLTYPE_NUM },
        [COL_STATE] = { "STATE", 7, SCOLS_FL_TRUNC, N_("state of the device") },
        [COL_SUBSYS] = { "SUBSYSTEMS", 0.1, SCOLS_FL_NOEXTREMES, N_("de-duplicated chain of subsystems") },
        [COL_TARGETS] = { "MOUNTPOINTS", 0.10, SCOLS_FL_WRAP | SCOLS_FL_NOEXTREMES,  N_("all locations where device is mounted") },
@@ -232,12 +233,12 @@ static const struct colinfo infos[] = {
        [COL_TYPE] = { "TYPE", 4, 0, N_("device type") },
        [COL_UUID] = { "UUID", 36,  0, N_("filesystem UUID") },
        [COL_VENDOR] = { "VENDOR", 0.1, SCOLS_FL_TRUNC, N_("device vendor") },
-       [COL_WSAME] = { "WSAME", 6, SCOLS_FL_RIGHT, N_("write same max bytes"), COLTYPE_SIZE },
+       [COL_WSAME] = { "WSAME", 6, SCOLS_FL_RIGHT, N_("write same max bytes, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_WWN] = { "WWN", 18, 0, N_("unique storage identifier") },
        [COL_ZONED] = { "ZONED", 0.3, 0, N_("zone model") },
-       [COL_ZONE_SZ] = { "ZONE-SZ", 9, SCOLS_FL_RIGHT, N_("zone size"), COLTYPE_SIZE },
-       [COL_ZONE_WGRAN] = { "ZONE-WGRAN", 10, SCOLS_FL_RIGHT, N_("zone write granularity"), COLTYPE_SIZE },
-       [COL_ZONE_APP] = { "ZONE-APP", 11, SCOLS_FL_RIGHT, N_("zone append max bytes"), COLTYPE_SIZE },
+       [COL_ZONE_SZ] = { "ZONE-SZ", 9, SCOLS_FL_RIGHT, N_("zone size, use <number> if --bytes is given"), COLTYPE_SIZE },
+       [COL_ZONE_WGRAN] = { "ZONE-WGRAN", 10, SCOLS_FL_RIGHT, N_("zone write granularity, use <number> if --bytes is given"), COLTYPE_SIZE },
+       [COL_ZONE_APP] = { "ZONE-APP", 11, SCOLS_FL_RIGHT, N_("zone append max bytes, use <number> if --bytes is given"), COLTYPE_SIZE },
        [COL_ZONE_NR] = { "ZONE-NR", 8, SCOLS_FL_RIGHT, N_("number of zones"), COLTYPE_NUM },
        [COL_ZONE_OMAX] = { "ZONE-OMAX", 10, SCOLS_FL_RIGHT, N_("maximum number of open zones"), COLTYPE_NUM },
        [COL_ZONE_AMAX] = { "ZONE-AMAX", 10, SCOLS_FL_RIGHT, N_("maximum number of active zones"), COLTYPE_NUM },
@@ -654,7 +655,25 @@ static void str2u64(const char *str, uint64_t *data)
        *data = num;
 }
 
-static void unref_rawdata(struct libscols_table *tb)
+static void unref_line_rawdata(struct libscols_line *ln, struct libscols_table *tb)
+{
+       size_t i;
+
+       for (i = 0; i < ncolumns; i++) {
+               struct libscols_column *cl = scols_table_get_column(tb, i);
+               struct libscols_cell *ce;
+               void *data;
+
+               if (cl != lsblk->sort_col && !scols_column_has_data_func(cl))
+                       continue;
+
+               ce = scols_line_get_column_cell(ln, cl);
+               data = scols_cell_get_userdata(ce);
+               free(data);
+       }
+}
+
+static void unref_table_rawdata(struct libscols_table *tb)
 {
        struct libscols_iter *itr;
        struct libscols_line *ln;
@@ -665,23 +684,8 @@ static void unref_rawdata(struct libscols_table *tb)
        itr = scols_new_iter(SCOLS_ITER_FORWARD);
        if (!itr)
                return;
-
-       while (scols_table_next_line(tb, itr, &ln) == 0) {
-               size_t i;
-
-               for (i = 0; i < ncolumns; i++) {
-                       struct libscols_column *cl = scols_table_get_column(tb, i);
-                       struct libscols_cell *ce;
-                       void *data;
-
-                       if (cl != lsblk->sort_col && !scols_column_has_datafunc(cl))
-                               continue;
-
-                       ce = scols_line_get_column_cell(ln, cl);
-                       data = scols_cell_get_userdata(ce);
-                       free(data);
-               }
-       }
+       while (scols_table_next_line(tb, itr, &ln) == 0)
+               unref_line_rawdata(ln, tb);
 
        scols_free_iter(itr);
 }
@@ -888,13 +892,13 @@ static char *device_get_data(
                break;
        case COL_MAJ:
                xasprintf(&str, "%u", dev->maj);
-               if (sortdata)
-                       *sortdata = dev->maj;
+               if (rawdata)
+                       *rawdata = dev->maj;
                break;
        case COL_MIN:
                xasprintf(&str, "%u", dev->min);
-               if (sortdata)
-                       *sortdata = dev->min;
+               if (rawdata)
+                       *rawdata = dev->min;
                break;
        case COL_FSTYPE:
                prop = lsblk_device_get_properties(dev);
@@ -931,8 +935,7 @@ static char *device_get_data(
                                ul_buffer_append_string(&buf, "[SWAP]");
                        else
                                ul_buffer_append_string(&buf, mnt_fs_get_target(fs));
-                       if (i + 1 < n)
-                               ul_buffer_append_data(&buf, "\0", 1);
+                       ul_buffer_append_data(&buf, "\0", 1);
                }
                str = ul_buffer_get_data(&buf, datasiz, NULL);
                break;
@@ -949,8 +952,7 @@ static char *device_get_data(
                        if (mnt_fs_is_swaparea(fs))
                                continue;
                        ul_buffer_append_string(&buf, root ? root : "/");
-                       if (i + 1 < n)
-                               ul_buffer_append_data(&buf, "\0", 1);
+                       ul_buffer_append_data(&buf, "\0", 1);
                }
                str = ul_buffer_get_data(&buf, datasiz, NULL);
                break;
@@ -1257,7 +1259,7 @@ static void device_fill_scols_cell(struct lsblk_device *dev,
        size_t datasiz = 0;
        int rc, id = get_column_id(colnum);
 
-       if (lsblk->sort_id == id || scols_column_has_datafunc(cl)) {
+       if (lsblk->sort_id == id || scols_column_has_data_func(cl)) {
                uint64_t rawdata = (uint64_t) -1;
 
                data = device_get_data(dev, parent, id, &rawdata, &datasiz);
@@ -1272,7 +1274,7 @@ static void device_fill_scols_cell(struct lsblk_device *dev,
        ce = scols_line_get_cell(ln, colnum);
        if (!ce)
                return;
-       rc = datasiz ? scols_cell_refer_memory(ce, data, datasiz + 1)
+       rc = datasiz ? scols_cell_refer_memory(ce, data, datasiz)
                     : scols_cell_refer_data(ce, data);
        if (rc)
                err(EXIT_FAILURE, _("failed to add output data"));
@@ -1303,7 +1305,7 @@ static void device_to_scols(
        struct libscols_line *ln;
        struct lsblk_iter itr;
        struct lsblk_device *child = NULL;
-       int link_group = 0;
+       int link_group = 0, nocount = 0;
 
 
        DBG(DEV, ul_debugobj(dev, "add '%s' to scols", dev->name));
@@ -1346,6 +1348,7 @@ static void device_to_scols(
 
                        if (x)
                                scols_line_remove_child(x, ln);
+                       unref_line_rawdata(ln, tab);
                        scols_table_remove_line(tab, ln);
                        ln = NULL;
                }
@@ -1379,6 +1382,10 @@ static void device_to_scols(
                scols_line_link_group(ln, gr, 0);
        }
 
+       /* The same device could be printed more than once, don't use it in counter */
+       if (dev->scols_line)
+               nocount = 1;
+
        dev->scols_line = ln;
 
        if (dev->npartitions == 0)
@@ -1403,8 +1410,10 @@ static void device_to_scols(
        }
 
        /* apply counters */
-       for (i = 0; ln && i < lsblk->ncts; i++)
-               scols_line_apply_filter(ln, lsblk->ct_filters[i], NULL);
+       if (!nocount) {
+               for (i = 0; ln && i < lsblk->ncts; i++)
+                       scols_line_apply_filter(ln, lsblk->ct_filters[i], NULL);
+       }
 
        /* Let's be careful with number of open files */
        ul_path_close_dirfd(dev->sysfs);
@@ -2253,7 +2262,7 @@ static void init_scols_filter(struct libscols_table *tb, struct libscols_filter
                }
                if (!col) {
                        add_column(id);
-                       col = scols_table_new_column(lsblk->table, ci->name,
+                       col = scols_table_new_column(tb, ci->name,
                                                     ci->whint, SCOLS_FL_HIDDEN);
                        if (!col)
                                err(EXIT_FAILURE,_("failed to allocate output column"));
@@ -2264,10 +2273,10 @@ static void init_scols_filter(struct libscols_table *tb, struct libscols_filter
                /* For sizes use rawdata (u64) rather than strings from table */
                if (ci->type == COLTYPE_SIZE
                    && !lsblk->bytes
-                   && !scols_column_has_datafunc(col)) {
+                   && !scols_column_has_data_func(col)) {
 
                        scols_column_set_data_type(col, SCOLS_DATA_U64);
-                       scols_column_set_datafunc(col, get_u64_cell, NULL);
+                       scols_column_set_data_func(col, get_u64_cell, NULL);
                        lsblk->rawdata = 1;
                }
 
@@ -2286,7 +2295,6 @@ static void init_scols_filter(struct libscols_table *tb, struct libscols_filter
 static void __attribute__((__noreturn__)) usage(void)
 {
        FILE *out = stdout;
-       size_t i;
 
        fputs(USAGE_HEADER, out);
        fprintf(out, _(" %s [options] [<device> ...]\n"), program_invocation_short_name);
@@ -2303,10 +2311,10 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -M, --merge          group parents of sub-trees (usable for RAIDs, Multi-path)\n"), out);
        fputs(_(" -O, --output-all     output all columns\n"), out);
        fputs(_(" -P, --pairs          use key=\"value\" output format\n"), out);
-       fputs(_(" -Q, --filter <query> restrict output\n"), out);
-       fputs(_(" -H, --highlight <query> colorize lines maching the query\n"), out);
-       fputs(_("     --ct-filter <query> restrict the next counters\n"), out);
-       fputs(_("     --ct <name>[:<param>[:<function>]] define custom counter\n"), out);
+       fputs(_(" -Q, --filter <expr>  print only lines maching the expression\n"), out);
+       fputs(_("     --highlight <expr> colorize lines maching the expression\n"), out);
+       fputs(_("     --ct-filter <expr> restrict the next counter\n"), out);
+       fputs(_("     --ct <name>[:<param>[:<func>]] define a custom counter\n"), out);
        fputs(_(" -S, --scsi           output info about SCSI devices\n"), out);
        fputs(_(" -N, --nvme           output info about NVMe devices\n"), out);
        fputs(_(" -v, --virtio         output info about virtio devices\n"), out);
@@ -2320,7 +2328,7 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -l, --list           use list format output\n"), out);
        fputs(_(" -m, --perms          output info about permissions\n"), out);
        fputs(_(" -n, --noheadings     don't print headings\n"), out);
-       fputs(_(" -o, --output <list>  output columns\n"), out);
+       fputs(_(" -o, --output <list>  output columns (see --list-columns)\n"), out);
        fputs(_(" -p, --paths          print complete device path\n"), out);
        fputs(_(" -r, --raw            use raw output format\n"), out);
        fputs(_(" -s, --inverse        inverse dependencies\n"), out);
@@ -2330,15 +2338,40 @@ static void __attribute__((__noreturn__)) usage(void)
        fputs(_(" -y, --shell          use column names to be usable as shell variable identifiers\n"), out);
        fputs(_(" -z, --zoned          print zone related information\n"), out);
        fputs(_("     --sysroot <dir>  use specified directory as system root\n"), out);
+
        fputs(USAGE_SEPARATOR, out);
+       fputs(_(" -H, --list-columns   list the available columns\n"), out);
        fprintf(out, USAGE_HELP_OPTIONS(22));
 
-       fputs(USAGE_COLUMNS, out);
+       fprintf(out, USAGE_MAN_TAIL("lsblk(8)"));
+
+       exit(EXIT_SUCCESS);
+}
 
-       for (i = 0; i < ARRAY_SIZE(infos); i++)
-               fprintf(out, " %12s  %s\n", infos[i].name, _(infos[i].help));
 
-       fprintf(out, USAGE_MAN_TAIL("lsblk(8)"));
+static void __attribute__((__noreturn__)) list_colunms(void)
+{
+       size_t i;
+       struct libscols_table *tb = xcolumn_list_table_new("lsblk-columns", stdout,
+                                               lsblk->flags & LSBLK_RAW,
+                                               lsblk->flags & LSBLK_JSON);
+
+       for (i = 0; i < ARRAY_SIZE(infos); i++) {
+               const struct colinfo *ci = &infos[i];
+
+               xcolumn_list_table_append_line(tb, ci->name,
+                       ci->type == COLTYPE_SIZE ? -1 :
+                       ci->type == COLTYPE_NUM  ? SCOLS_JSON_NUMBER :
+                       ci->type == COLTYPE_BOOL ? SCOLS_JSON_BOOLEAN :
+                       ci->flags & SCOLS_FL_WRAP ? SCOLS_JSON_ARRAY_STRING :
+                               SCOLS_JSON_STRING,
+                       ci->type == COLTYPE_SIZE ? "<string|number>" : NULL,
+                      _(ci->help));
+       }
+
+
+       scols_print_table(tb);
+       scols_unref_table(tb);
 
        exit(EXIT_SUCCESS);
 }
@@ -2359,7 +2392,7 @@ int main(int argc, char *argv[])
                .tree_id = COL_NAME
        };
        struct lsblk_devtree *tr = NULL;
-       int c, status = EXIT_FAILURE;
+       int c, status = EXIT_FAILURE, collist = 0;
        char *outarg = NULL;
        size_t i;
        unsigned int width = 0;
@@ -2368,7 +2401,8 @@ int main(int argc, char *argv[])
        enum {
                OPT_SYSROOT = CHAR_MAX + 1,
                OPT_COUNTER_FILTER,
-               OPT_COUNTER
+               OPT_COUNTER,
+               OPT_HIGHLIGHT,
        };
 
        static const struct option longopts[] = {
@@ -2384,7 +2418,7 @@ int main(int argc, char *argv[])
                { "output",     required_argument, NULL, 'o' },
                { "output-all", no_argument,       NULL, 'O' },
                { "filter",     required_argument, NULL, 'Q' },
-               { "highlight",  required_argument, NULL, 'H' },
+               { "highlight",  required_argument, NULL, OPT_HIGHLIGHT },
                { "merge",      no_argument,       NULL, 'M' },
                { "perms",      no_argument,       NULL, 'm' },
                { "noheadings", no_argument,       NULL, 'n' },
@@ -2409,6 +2443,7 @@ int main(int argc, char *argv[])
                { "width",      required_argument, NULL, 'w' },
                { "ct-filter",  required_argument, NULL, OPT_COUNTER_FILTER },
                { "ct",         required_argument, NULL, OPT_COUNTER },
+               { "list-columns", no_argument,     NULL, 'H' },
                { NULL, 0, NULL, 0 },
        };
 
@@ -2437,7 +2472,7 @@ int main(int argc, char *argv[])
        scols_init_debug(0);
 
        while((c = getopt_long(argc, argv,
-                               "AabdDzE:e:fH:hJlNnMmo:OpPQ:iI:rstVvST::w:x:y",
+                               "AabdDzE:e:fHhJlNnMmo:OpPQ:iI:rstVvST::w:x:y",
                                longopts, NULL)) != -1) {
 
                err_exclusive_options(c, longopts, excl, excl_st);
@@ -2475,9 +2510,6 @@ int main(int argc, char *argv[])
                case 'e':
                        parse_excludes(optarg);
                        break;
-               case 'H':
-                       lsblk->hlighter = new_filter(optarg);
-                       break;
                case 'J':
                        lsblk->flags |= LSBLK_JSON;
                        break;
@@ -2622,7 +2654,13 @@ int main(int argc, char *argv[])
                case OPT_COUNTER:
                        set_counter_properties(optarg);
                        break;
+               case OPT_HIGHLIGHT:
+                       lsblk->hlighter = new_filter(optarg);
+                       break;
 
+               case 'H':
+                       collist = 1;
+                       break;
                case 'h':
                        usage();
                case 'V':
@@ -2632,6 +2670,9 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (collist)
+               list_colunms();        /* print end exit */
+
        if (force_tree)
                lsblk->flags |= LSBLK_TREE;
 
@@ -2799,7 +2840,7 @@ int main(int argc, char *argv[])
                print_counters();
 leave:
        if (lsblk->rawdata)
-               unref_rawdata(lsblk->table);
+               unref_table_rawdata(lsblk->table);
 
        scols_unref_table(lsblk->table);
        scols_unref_filter(lsblk->filter);