]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/partx.c
fstrim shouldn't run inside a container
[thirdparty/util-linux.git] / disk-utils / partx.c
index 44d38fd0eaf0f1c2ca72e6ae44bba8322604442f..949278eb79854bb00588268115efde477903ca4a 100644 (file)
 #include <dirent.h>
 
 #include <blkid.h>
+#include <libsmartcols.h>
 
 #include "c.h"
 #include "pathnames.h"
 #include "nls.h"
-#include "tt.h"
 #include "blkdev.h"
 #include "strutils.h"
 #include "xalloc.h"
 #include "partx.h"
 #include "sysfs.h"
 #include "loopdev.h"
-#include "at.h"
 #include "closestream.h"
 #include "optutils.h"
 
 /* this is the default upper limit, could be modified by --nr */
 #define SLICES_MAX     256
 
+/* basic table settings */
+enum {
+       PARTX_RAW =             (1 << 0),
+       PARTX_NOHEADINGS =      (1 << 1),
+       PARTX_EXPORT =          (1 << 2),
+};
+
 /* all the columns (-o option) */
 enum {
        COL_PARTNO,
@@ -71,28 +77,29 @@ enum {
 struct colinfo {
        const char      *name;  /* header */
        double          whint;  /* width hint (N < 1 is in percent of termwidth) */
-       int             flags;  /* TT_FL_* */
+       int             flags;  /* SCOLS_FL_* */
        const char      *help;
 };
 
 /* columns descriptions */
-struct colinfo infos[] = {
-       [COL_PARTNO]   = { "NR",    0.25, TT_FL_RIGHT, N_("partition number") },
-       [COL_START]    = { "START",   0.30, TT_FL_RIGHT, N_("start of the partition in sectors") },
-       [COL_END]      = { "END",     0.30, TT_FL_RIGHT, N_("end of the partition in sectors") },
-       [COL_SECTORS]  = { "SECTORS", 0.30, TT_FL_RIGHT, N_("number of sectors") },
-       [COL_SIZE]     = { "SIZE",    0.30, TT_FL_RIGHT, N_("human readable size") },
-       [COL_NAME]     = { "NAME",    0.30, TT_FL_TRUNC, N_("partition name") },
+static struct colinfo infos[] = {
+       [COL_PARTNO]   = { "NR",    0.25, SCOLS_FL_RIGHT, N_("partition number") },
+       [COL_START]    = { "START",   0.30, SCOLS_FL_RIGHT, N_("start of the partition in sectors") },
+       [COL_END]      = { "END",     0.30, SCOLS_FL_RIGHT, N_("end of the partition in sectors") },
+       [COL_SECTORS]  = { "SECTORS", 0.30, SCOLS_FL_RIGHT, N_("number of sectors") },
+       [COL_SIZE]     = { "SIZE",    0.30, SCOLS_FL_RIGHT, N_("human readable size") },
+       [COL_NAME]     = { "NAME",    0.30, SCOLS_FL_TRUNC, N_("partition name") },
        [COL_UUID]     = { "UUID",    36, 0, N_("partition UUID")},
-       [COL_SCHEME]   = { "SCHEME",  0.1, TT_FL_TRUNC, N_("partition table type (dos, gpt, ...)")},
-       [COL_FLAGS]    = { "FLAGS",   0.1, TT_FL_TRUNC, N_("partition flags")},
-       [COL_TYPE]     = { "TYPE",    1, TT_FL_RIGHT, N_("partition type (a string, a UUID, or hex)")},
+       [COL_SCHEME]   = { "SCHEME",  0.1, SCOLS_FL_TRUNC, N_("partition table type (dos, gpt, ...)")},
+       [COL_FLAGS]    = { "FLAGS",   0.1, SCOLS_FL_TRUNC, N_("partition flags")},
+       [COL_TYPE]     = { "TYPE",    1, SCOLS_FL_RIGHT, N_("partition type (a string, a UUID, or hex)")},
 };
 
 #define NCOLS ARRAY_SIZE(infos)
 
 /* array with IDs of enabled columns */
-static int columns[NCOLS], ncolumns;
+static int columns[NCOLS];
+static size_t ncolumns;
 
 static int verbose;
 static int partx_flags;
@@ -129,7 +136,7 @@ static void assoc_loopdev(const char *fname)
 static inline int get_column_id(int num)
 {
        assert(ARRAY_SIZE(columns) == NCOLS);
-       assert(num < ncolumns);
+       assert((size_t)num < ncolumns);
        assert(columns[num] < (int) NCOLS);
        return columns[num];
 }
@@ -170,14 +177,15 @@ static int get_partno_from_device(char *partition, dev_t devno)
        assert(partition);
 
        if (devno) {
-               struct sysfs_cxt cxt;
+               struct path_cxt *pc;
                int rc;
 
-               if (sysfs_init(&cxt, devno, NULL))
+               pc = ul_new_sysfs_path(devno, NULL, NULL);
+               if (!pc)
                        goto err;
 
-               rc = sysfs_read_int(&cxt, "partition", &partno);
-               sysfs_deinit(&cxt);
+               rc = ul_path_read_s32(pc, &partno, "partition");
+               ul_unref_path(pc);
 
                if (rc == 0)
                        return partno;
@@ -186,10 +194,10 @@ static int get_partno_from_device(char *partition, dev_t devno)
        sz = strlen(partition);
        p = partition + sz - 1;
 
-       if (!isdigit((unsigned int) *p))
+       if (!isdigit((unsigned char) *p))
                goto err;
 
-       while (isdigit((unsigned int) *(p - 1))) p--;
+       while (isdigit((unsigned char) *(p - 1))) p--;
 
        errno = 0;
        partno = strtol(p, &end, 10);
@@ -241,7 +249,7 @@ static int get_max_partno(const char *disk, dev_t devno)
                        continue;
                snprintf(path, sizeof(path), "%s/partition", d->d_name);
 
-               fd = open_at(dirfd(dir), dirname, path, O_RDONLY);
+               fd = openat(dirfd(dir), path, O_RDONLY);
                if (fd) {
                        int x = 0;
                        FILE *f = fdopen(fd, "r");
@@ -260,6 +268,30 @@ dflt:
        return SLICES_MAX;
 }
 
+static int recount_range_by_pt(blkid_partlist ls, int *lower, int *upper)
+{
+       int n = 0, i, nparts = blkid_partlist_numof_partitions(ls);
+
+       for (i = 0; i < nparts; i++) {
+               blkid_partition par = blkid_partlist_get_partition(ls, i);
+               int partno = blkid_partition_get_partno(par);
+               n = max(partno, n);
+       }
+
+       if (*lower < 0)
+               *lower = n + *lower + 1;
+       if (*upper < 0)
+               *upper = n + *upper + 1;
+
+       if (*lower > *upper && *upper != 0) {
+               warnx(_("specified range <%d:%d> does not make sense"), *lower, *upper);
+               return -EINVAL;
+       }
+       if (verbose)
+               printf(_("range recount: max partno=%d, lower=%d, upper=%d\n"), n, *lower, *upper);
+       return 0;
+}
+
 static void del_parts_warnx(const char *device, int first, int last)
 {
        if (first == last)
@@ -277,6 +309,7 @@ static int del_parts(int fd, const char *device, dev_t devno,
        assert(fd >= 0);
        assert(device);
 
+       /* recount range by information in /sys */
        if (!lower)
                lower = 1;
        if (!upper || lower < 0 || upper < 0) {
@@ -302,7 +335,7 @@ static int del_parts(int fd, const char *device, dev_t devno,
                        continue;
                } else if (errno == ENXIO) {
                        if (verbose)
-                               printf(_("%s: partition #%d already doesn't exist\n"), device, i);
+                               printf(_("%s: partition #%d doesn't exist\n"), device, i);
                        continue;
                }
                rc = -1;
@@ -336,12 +369,16 @@ static void add_parts_warnx(const char *device, int first, int last)
 static int add_parts(int fd, const char *device,
                     blkid_partlist ls, int lower, int upper)
 {
-       int i, nparts, rc = 0, errfirst = 0, errlast = 0;
+       int i, nparts, rc, errfirst = 0, errlast = 0;
 
        assert(fd >= 0);
        assert(device);
        assert(ls);
 
+       rc = recount_range_by_pt(ls, &lower, &upper);
+       if (rc)
+               return rc;
+
        nparts = blkid_partlist_numof_partitions(ls);
 
        for (i = 0; i < nparts; i++) {
@@ -423,6 +460,8 @@ static int upd_parts(int fd, const char *device, dev_t devno,
        assert(device);
        assert(ls);
 
+       /* recount range by information in /sys, if on disk number of
+        * partitions is greater than in /sys the use on-disk limit */
        nparts = blkid_partlist_numof_partitions(ls);
        if (!lower)
                lower = 1;
@@ -498,10 +537,14 @@ static int upd_parts(int fd, const char *device, dev_t devno,
 
 static int list_parts(blkid_partlist ls, int lower, int upper)
 {
-       int i, nparts;
+       int i, nparts, rc;
 
        assert(ls);
 
+       rc = recount_range_by_pt(ls, &lower, &upper);
+       if (rc)
+               return rc;
+
        nparts = blkid_partlist_numof_partitions(ls);
 
        for (i = 0; i < nparts; i++) {
@@ -526,22 +569,23 @@ static int list_parts(blkid_partlist ls, int lower, int upper)
        return 0;
 }
 
-static void add_tt_line(struct tt *tt, blkid_partition par)
+static int add_scols_line(struct libscols_table *table, blkid_partition par)
 {
-       struct tt_line *line;
-       int i;
+       struct libscols_line *line;
+       int i, rc = 0;
 
-       assert(tt);
+       assert(table);
        assert(par);
 
-       line = tt_add_line(tt, NULL);
+       line = scols_table_new_line(table, NULL);
        if (!line) {
-               warn(_("failed to add line to output"));
-               return;
+               warn(_("failed to allocate output line"));
+               return -ENOMEM;
        }
 
-       for (i = 0; i < ncolumns; i++) {
-               char *str = NULL;
+       for (i = 0; (size_t)i < ncolumns; i++) {
+               char *str = NULL;                       /* allocated string */
+               const char *cstr = NULL;                /* foreign string */
 
                switch (get_column_id(i)) {
                case COL_PARTNO:
@@ -567,14 +611,14 @@ static void add_tt_line(struct tt *tt, blkid_partition par)
                                        blkid_partition_get_size(par) << 9);
                        break;
                case COL_NAME:
-                       str = xstrdup(blkid_partition_get_name(par));
+                       cstr = blkid_partition_get_name(par);
                        break;
                case COL_UUID:
-                       str = xstrdup(blkid_partition_get_uuid(par));
+                       cstr = blkid_partition_get_uuid(par);
                        break;
                case COL_TYPE:
                        if (blkid_partition_get_type_string(par))
-                               str = xstrdup(blkid_partition_get_type_string(par));
+                               cstr = blkid_partition_get_type_string(par);
                        else
                                xasprintf(&str, "0x%x",
                                        blkid_partition_get_type(par));
@@ -586,22 +630,30 @@ static void add_tt_line(struct tt *tt, blkid_partition par)
                {
                        blkid_parttable tab = blkid_partition_get_table(par);
                        if (tab)
-                               str = xstrdup(blkid_parttable_get_type(tab));
+                               cstr = blkid_parttable_get_type(tab);
                        break;
                }
                default:
                        break;
                }
 
-               if (str)
-                       tt_line_set_data(line, i, str);
+               if (cstr)
+                       rc = scols_line_set_data(line, i, cstr);
+               else if (str)
+                       rc = scols_line_refer_data(line, i, str);
+               if (rc) {
+                       warn(_("failed to add output data"));
+                       break;
+               }
        }
+
+       return rc;
 }
 
-static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
+static int show_parts(blkid_partlist ls, int scols_flags, int lower, int upper)
 {
        int i, rc = -1;
-       struct tt *tt;
+       struct libscols_table *table;
        int nparts;
 
        assert(ls);
@@ -610,21 +662,29 @@ static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
        if (!nparts)
                return 0;
 
-       tt = tt_new_table(tt_flags | TT_FL_FREEDATA);
-       if (!tt) {
-               warn(_("failed to initialize output table"));
+       scols_init_debug(0);
+       table = scols_new_table();
+       if (!table) {
+               warn(_("failed to allocate output table"));
                return -1;
        }
+       scols_table_enable_raw(table, !!(scols_flags & PARTX_RAW));
+       scols_table_enable_export(table, !!(scols_flags & PARTX_EXPORT));
+       scols_table_enable_noheadings(table, !!(scols_flags & PARTX_NOHEADINGS));
 
-       for (i = 0; i < ncolumns; i++) {
+       for (i = 0; (size_t)i < ncolumns; i++) {
                struct colinfo *col = get_column_info(i);
 
-               if (!tt_define_column(tt, col->name, col->whint, col->flags)) {
-                       warnx(_("failed to initialize output column"));
+               if (!scols_table_new_column(table, col->name, col->whint, col->flags)) {
+                       warnx(_("failed to allocate output column"));
                        goto done;
                }
        }
 
+       rc = recount_range_by_pt(ls, &lower, &upper);
+       if (rc)
+               goto done;
+
        for (i = 0; i < nparts; i++) {
                blkid_partition par = blkid_partlist_get_partition(ls, i);
                int n = blkid_partition_get_partno(par);
@@ -634,13 +694,15 @@ static int show_parts(blkid_partlist ls, int tt_flags, int lower, int upper)
                if (upper && n > upper)
                        continue;
 
-               add_tt_line(tt, par);
+               rc = add_scols_line(table, par);
+               if (rc)
+                       break;
        }
 
        rc = 0;
-       tt_print_table(tt);
+       scols_print_table(table);
 done:
-       tt_free_table(tt);
+       scols_unref_table(table);
        return rc;
 }
 
@@ -682,8 +744,9 @@ static blkid_partlist get_partlist(blkid_probe pr,
        return ls;
 }
 
-static void __attribute__((__noreturn__)) usage(FILE *out)
+static void __attribute__((__noreturn__)) usage(void)
 {
+       FILE *out = stdout;
        size_t i;
 
        fputs(USAGE_HEADER, out);
@@ -691,6 +754,9 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
              _(" %s [-a|-d|-s|-u] [--nr <n:m> | <partition>] <disk>\n"),
                program_invocation_short_name);
 
+       fputs(USAGE_SEPARATOR, out);
+       fputs(_("Tell the kernel about the presence and numbering of partitions.\n"), out);
+
        fputs(USAGE_OPTIONS, out);
        fputs(_(" -a, --add            add specified partitions or all of them\n"), out);
        fputs(_(" -d, --delete         delete specified partitions or all of them\n"), out);
@@ -700,35 +766,41 @@ static void __attribute__((__noreturn__)) usage(FILE *out)
        fputs(_(" -g, --noheadings     don't print headings for --show\n"), out);
        fputs(_(" -n, --nr <n:m>       specify the range of partitions (e.g. --nr 2:4)\n"), out);
        fputs(_(" -o, --output <list>  define which output columns to use\n"), out);
+       fputs(_("     --output-all     output all columns\n"), out);
        fputs(_(" -P, --pairs          use key=\"value\" output format\n"), out);
        fputs(_(" -r, --raw            use raw output format\n"), out);
-       fputs(_(" -t, --type <type>    specify the partition type (dos, bsd, solaris, etc.)\n"), out);
+       fputs(_(" -S, --sector-size <num>  overwrite sector size\n"), out);
+       fputs(_(" -t, --type <type>    specify the partition type\n"), out);
+       fputs(_("     --list-types     list supported partition types and exit\n"), out);
        fputs(_(" -v, --verbose        verbose mode\n"), out);
 
        fputs(USAGE_SEPARATOR, out);
-       fputs(USAGE_HELP, out);
-       fputs(USAGE_VERSION, out);
-
-       fputs(_("\nAvailable columns (for --show, --raw or --pairs):\n"), out);
+       printf(USAGE_HELP_OPTIONS(22));
 
+       fputs(USAGE_COLUMNS, out);
        for (i = 0; i < NCOLS; i++)
                fprintf(out, " %10s  %s\n", infos[i].name, _(infos[i].help));
 
-       fprintf(out, USAGE_MAN_TAIL("partx(8)"));
+       printf(USAGE_MAN_TAIL("partx(8)"));
 
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+       exit(EXIT_SUCCESS);
 }
 
 int main(int argc, char **argv)
 {
        int fd, c, what = ACT_NONE, lower = 0, upper = 0, rc = 0;
-       int tt_flags = 0;
+       int scols_flags = 0;
        char *type = NULL;
        char *device = NULL; /* pointer to argv[], ie: /dev/sda1 */
        char *wholedisk = NULL; /* allocated, ie: /dev/sda */
        char *outarg = NULL;
        dev_t disk_devno = 0, part_devno = 0;
+       unsigned int sector_size = 0;
 
+       enum {
+               OPT_LIST_TYPES = CHAR_MAX + 1,
+               OPT_OUTPUT_ALL
+       };
        static const struct option long_opts[] = {
                { "bytes",      no_argument,       NULL, 'b' },
                { "noheadings", no_argument,       NULL, 'g' },
@@ -739,17 +811,20 @@ int main(int argc, char **argv)
                { "delete",     no_argument,       NULL, 'd' },
                { "update",     no_argument,       NULL, 'u' },
                { "type",       required_argument, NULL, 't' },
+               { "list-types", no_argument,       NULL, OPT_LIST_TYPES },
                { "nr",         required_argument, NULL, 'n' },
                { "output",     required_argument, NULL, 'o' },
+               { "output-all", no_argument,       NULL, OPT_OUTPUT_ALL },
                { "pairs",      no_argument,       NULL, 'P' },
+               { "sector-size",required_argument, NULL, 'S' },
                { "help",       no_argument,       NULL, 'h' },
                { "version",    no_argument,       NULL, 'V' },
                { "verbose",    no_argument,       NULL, 'v' },
                { NULL, 0, NULL, 0 }
        };
 
-       static const ul_excl_t excl[] = {       /* rows and cols in in ASCII order */
-               { 'P','a','d','l','r','s' },
+       static const ul_excl_t excl[] = {       /* rows and cols in ASCII order */
+               { 'P','a','d','l','r','s','u' },
                { 0 }
        };
        int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
@@ -757,10 +832,10 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
-       atexit(close_stdout);
+       close_stdout_atexit();
 
        while ((c = getopt_long(argc, argv,
-                               "abdglrsuvn:t:o:PhV", long_opts, NULL)) != -1) {
+                               "abdglrsuvn:t:o:PS:hV", long_opts, NULL)) != -1) {
 
                err_exclusive_options(c, long_opts, excl, excl_st);
 
@@ -775,7 +850,7 @@ int main(int argc, char **argv)
                        what = ACT_DELETE;
                        break;
                case 'g':
-                       tt_flags |= TT_FL_NOHEADINGS;
+                       scols_flags |= PARTX_NOHEADINGS;
                        break;
                case 'l':
                        what = ACT_LIST;
@@ -787,17 +862,24 @@ int main(int argc, char **argv)
                case 'o':
                        outarg = optarg;
                        break;
+               case OPT_OUTPUT_ALL:
+                       for (ncolumns = 0; ncolumns < ARRAY_SIZE(infos); ncolumns++)
+                               columns[ncolumns] = ncolumns;
+                       break;
                case 'P':
-                       tt_flags |= TT_FL_EXPORT;
+                       scols_flags |= PARTX_EXPORT;
                        what = ACT_SHOW;
                        break;
                case 'r':
-                       tt_flags |= TT_FL_RAW;
+                       scols_flags |= PARTX_RAW;
                        what = ACT_SHOW;
                        break;
                case 's':
                        what = ACT_SHOW;
                        break;
+               case 'S':
+                       sector_size = strtou32_or_err(optarg, _("invalid sector size argument"));
+                       break;
                case 't':
                        type = optarg;
                        break;
@@ -807,14 +889,21 @@ int main(int argc, char **argv)
                case 'v':
                        verbose = 1;
                        break;
+               case OPT_LIST_TYPES:
+               {
+                       size_t idx = 0;
+                       const char *name = NULL;
+
+                       while (blkid_partitions_get_name(idx++, &name) == 0)
+                               puts(name);
+                       return EXIT_SUCCESS;
+               }
                case 'h':
-                       usage(stdout);
+                       usage();
                case 'V':
-                       printf(UTIL_LINUX_VERSION);
-                       return EXIT_SUCCESS;
-               case '?':
+                       print_version(EXIT_SUCCESS);
                default:
-                       usage(stderr);
+                       errtryhelp(EXIT_FAILURE);
                }
        }
 
@@ -855,6 +944,9 @@ int main(int argc, char **argv)
                } else {
                        device = argv[optind];
                        wholedisk = xstrdup(argv[optind + 1]);
+
+                       if (device && wholedisk && !startswith(device, wholedisk))
+                               errx(EXIT_FAILURE, _("partition and disk name do not match"));
                }
        } else if (optind == argc - 1) {
                /* passed only one arg (ie: /dev/sda3 or /dev/sda) */
@@ -863,7 +955,7 @@ int main(int argc, char **argv)
                device = argv[optind];
 
                if (stat(device, &sb))
-                       err(EXIT_FAILURE, _("stat failed %s"), device);
+                       err(EXIT_FAILURE, _("stat of %s failed"), device);
 
                part_devno = sb.st_rdev;
 
@@ -878,9 +970,10 @@ int main(int argc, char **argv)
                        device = NULL;
                        part_devno = 0;
                }
-       } else
-               usage(stderr);
-
+       } else {
+               warnx(_("bad usage"));
+               errtryhelp(EXIT_FAILURE);
+       }
        if (device && (upper || lower))
                errx(EXIT_FAILURE, _("--nr and <partition> are mutually exclusive"));
 
@@ -935,25 +1028,17 @@ int main(int argc, char **argv)
                if (!pr || blkid_probe_set_device(pr, fd, 0, 0))
                        warnx(_("%s: failed to initialize blkid prober"),
                                        wholedisk);
-               else
+               else {
+                       if (sector_size)
+                               blkid_probe_set_sectorsize(pr, sector_size);
+
                        ls = get_partlist(pr, wholedisk, type);
+               }
 
                if (ls) {
-                       int n = blkid_partlist_numof_partitions(ls);
-
-                       if (lower < 0)
-                               lower = n + lower + 1;
-                       if (upper < 0)
-                               upper = n + upper + 1;
-                       if (lower > upper) {
-                               warnx(_("specified range <%d:%d> "
-                                       "does not make sense"), lower, upper);
-                               rc = -1, what = ACT_NONE;
-                       }
-
                        switch (what) {
                        case ACT_SHOW:
-                               rc = show_parts(ls, tt_flags, lower, upper);
+                               rc = show_parts(ls, scols_flags, lower, upper);
                                break;
                        case ACT_LIST:
                                rc = list_parts(ls, lower, upper);
@@ -963,12 +1048,15 @@ int main(int argc, char **argv)
                                break;
                        case ACT_UPD:
                                rc = upd_parts(fd, wholedisk, disk_devno, ls, lower, upper);
+                               break;
                        case ACT_NONE:
                                break;
                        default:
                                abort();
                        }
-               }
+               } else
+                       rc = 1;
+
                blkid_free_probe(pr);
        }