]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/blockdev.c
scriptreplay: fix uninitialized value [coverity scan]
[thirdparty/util-linux.git] / disk-utils / blockdev.c
index 338ecf176effa7d29fccf32bba6648aa72eb5561..55b47acf61a7a04342b941745afa6dff3fef8504 100644 (file)
@@ -1,8 +1,16 @@
 /*
+ * 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.
+ *
  * blockdev.c --- Do various simple block device ioctls from the command line
  * aeb, 991028
+ *
+ * Copyright (C) 2007-2023 Karel Zak <kzak@redhat.com>
  */
-
 #include <stdio.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#ifdef HAVE_LINUX_BLKZONED_H
+#include <linux/blkzoned.h>
+#endif
 
 #include "c.h"
 #include "nls.h"
 #include "blkdev.h"
 #include "pathnames.h"
+#include "closestream.h"
+#include "strutils.h"
+#include "sysfs.h"
 
 struct bdc {
        long            ioc;            /* ioctl code */
@@ -126,7 +140,7 @@ static const struct bdc bdcms[] =
                .argname = "<bytes>",
                .argtype = ARG_INT,
                .flags = FL_NORESULT,
-               .help = N_("set blocksize")
+               .help = N_("set blocksize on file descriptor opening the block device")
        },{
                IOCTL_ENTRY(BLKGETSIZE),
                .name = "--getsize",
@@ -166,6 +180,20 @@ static const struct bdc bdcms[] =
                .argval = -1,
                .help = N_("get filesystem readahead")
        },{
+               IOCTL_ENTRY(BLKGETDISKSEQ),
+               .name = "--getdiskseq",
+               .argtype = ARG_ULLONG,
+               .argval = -1,
+               .help = N_("get disk sequence number")
+       },{
+#ifdef BLKGETZONESZ
+               IOCTL_ENTRY(BLKGETZONESZ),
+               .name = "--getzonesz",
+               .argtype = ARG_UINT,
+               .argval = -1,
+               .help = N_("get zone size")
+       },{
+#endif
                IOCTL_ENTRY(BLKFLSBUF),
                .name = "--flushbufs",
                .help = N_("flush buffers")
@@ -176,27 +204,42 @@ static const struct bdc bdcms[] =
        }
 };
 
-static void __attribute__ ((__noreturn__)) usage(FILE * out)
+static void __attribute__((__noreturn__)) usage(void)
 {
        size_t i;
-       fprintf(out, _("\nUsage:\n"
-                      " %1$s -V\n"
-                      " %1$s --report [devices]\n"
-                      " %1$s [-v|-q] commands devices\n\n"
-                      "Available commands:\n"), program_invocation_short_name);
 
-       fprintf(out, _(" %-25s get size in 512-byte sectors\n"), "--getsz");
+       fputs(USAGE_HEADER, stdout);
+       fprintf(stdout, _(
+                " %1$s [-v|-q] commands devices\n"
+                " %1$s --report [devices]\n"
+                " %1$s -h|-V\n"
+               ), program_invocation_short_name);
+
+       fputs(USAGE_SEPARATOR, stdout);
+       fputsln(  _("Call block device ioctls from the command line."), stdout);
+
+       fputs(USAGE_OPTIONS, stdout);
+       fputsln(  _(" -q             quiet mode"), stdout);
+       fputsln(  _(" -v             verbose mode"), stdout);
+       fputsln(  _("     --report   print report for specified (or all) devices"), stdout);
+       fputs(USAGE_SEPARATOR, stdout);
+       fprintf(stdout, USAGE_HELP_OPTIONS(16));
+
+       fputs(USAGE_SEPARATOR, stdout);
+       fputsln(  _("Available commands:"), stdout);
+       fprintf(stdout, _(" %-25s get size in 512-byte sectors\n"), "--getsz");
        for (i = 0; i < ARRAY_SIZE(bdcms); i++) {
                if (bdcms[i].argname)
-                       fprintf(out, " %s %-*s %s\n", bdcms[i].name,
+                       fprintf(stdout, " %s %-*s %s\n", bdcms[i].name,
                                (int)(24 - strlen(bdcms[i].name)),
                                bdcms[i].argname, _(bdcms[i].help));
                else
-                       fprintf(out, " %-25s %s\n", bdcms[i].name,
+                       fprintf(stdout, " %-25s %s\n", bdcms[i].name,
                                _(bdcms[i].help));
        }
-       fputc('\n', out);
-       exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
+
+       fprintf(stdout, USAGE_MAN_TAIL("blockdev(8)"));
+       exit(EXIT_SUCCESS);
 }
 
 static int find_cmd(char *s)
@@ -209,10 +252,10 @@ static int find_cmd(char *s)
        return -1;
 }
 
-void do_commands(int fd, char **argv, int d);
-void report_header(void);
-void report_device(char *device, int quiet);
-void report_all_devices(void);
+static void do_commands(int fd, char **argv, int d);
+static void report_header(void);
+static int report_device(char *device, int quiet);
+static int report_all_devices(void);
 
 int main(int argc, char **argv)
 {
@@ -221,29 +264,30 @@ int main(int argc, char **argv)
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
+       close_stdout_atexit();
 
-       if (argc < 2)
-               usage(stderr);
+       if (argc < 2) {
+               warnx(_("not enough arguments"));
+               errtryhelp(EXIT_FAILURE);
+       }
 
        /* -V not together with commands */
-       if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version")) {
-               printf(_("%s (%s)\n"), program_invocation_short_name,
-                      PACKAGE_STRING);
-               return EXIT_SUCCESS;
-       }
+       if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))
+               print_version(EXIT_SUCCESS);
        if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
-               usage(stdout);
+               usage();
 
        /* --report not together with other commands */
        if (!strcmp(argv[1], "--report")) {
+               int rc = 0;
                report_header();
                if (argc > 2) {
                        for (d = 2; d < argc; d++)
-                               report_device(argv[d], 0);
+                               rc += report_device(argv[d], 0);
                } else {
-                       report_all_devices();
+                       rc = report_all_devices();
                }
-               return EXIT_SUCCESS;
+               return rc ? EXIT_FAILURE : EXIT_SUCCESS;
        }
 
        /* do each of the commands on each of the devices */
@@ -265,8 +309,10 @@ int main(int argc, char **argv)
                        break;
        }
 
-       if (d >= argc)
-               usage(stderr);
+       if (d >= argc) {
+               warnx(_("no device specified"));
+               errtryhelp(EXIT_FAILURE);
+       }
 
        for (k = d; k < argc; k++) {
                fd = open(argv[k], O_RDONLY, 0);
@@ -278,16 +324,16 @@ int main(int argc, char **argv)
        return EXIT_SUCCESS;
 }
 
-void do_commands(int fd, char **argv, int d)
+static void do_commands(int fd, char **argv, int d)
 {
        int res, i, j;
-       int iarg;
-       unsigned int uarg;
-       unsigned short huarg;
-       long larg;
-       long long llarg;
-       unsigned long lu;
-       unsigned long long llu;
+       int iarg = 0;
+       unsigned int uarg = 0;
+       unsigned short huarg = 0;
+       long larg = 0;
+       long long llarg = 0;
+       unsigned long lu = 0;
+       unsigned long long llu = 0;
        int verbose = 0;
 
        for (i = 1; i < d; i++) {
@@ -302,8 +348,11 @@ void do_commands(int fd, char **argv, int d)
 
                if (!strcmp(argv[i], "--getsz")) {
                        res = blkdev_get_sectors(fd, &llu);
-                       if (res == 0)
+                       if (res == 0) {
+                               if (verbose)
+                                       printf(_("get size in 512-byte sectors: "));
                                printf("%lld\n", llu);
+                       }
                        else
                                errx(EXIT_FAILURE,
                                     _("could not get device size"));
@@ -313,7 +362,7 @@ void do_commands(int fd, char **argv, int d)
                j = find_cmd(argv[i]);
                if (j == -1) {
                        warnx(_("Unknown command: %s"), argv[i]);
-                       usage(stderr);
+                       errtryhelp(EXIT_FAILURE);
                }
 
                switch (bdcms[j].argtype) {
@@ -330,9 +379,9 @@ void do_commands(int fd, char **argv, int d)
                                if (i == d - 1) {
                                        warnx(_("%s requires an argument"),
                                              bdcms[j].name);
-                                       usage(stderr);
+                                       errtryhelp(EXIT_FAILURE);
                                }
-                               iarg = atoi(argv[++i]);
+                               iarg = strtos32_or_err(argv[++i], _("failed to parse command argument"));
                        } else
                                iarg = bdcms[j].argval;
 
@@ -363,7 +412,7 @@ void do_commands(int fd, char **argv, int d)
                }
 
                if (res == -1) {
-                       perror(bdcms[j].iocname);
+                       warn(_("ioctl error on %s"), bdcms[j].iocname);
                        if (verbose)
                                printf(_("%s failed.\n"), _(bdcms[j].help));
                        exit(EXIT_FAILURE);
@@ -405,13 +454,14 @@ void do_commands(int fd, char **argv, int d)
        }
 }
 
-void report_all_devices(void)
+static int report_all_devices(void)
 {
        FILE *procpt;
        char line[200];
-       char ptname[200];
+       char ptname[200 + 1];
        char device[210];
        int ma, mi, sz;
+       int rc = 0;
 
        procpt = fopen(_PATH_PROC_PARTITIONS, "r");
        if (!procpt)
@@ -422,47 +472,70 @@ void report_all_devices(void)
                           &ma, &mi, &sz, ptname) != 4)
                        continue;
 
-               sprintf(device, "/dev/%s", ptname);
-               report_device(device, 1);
+               snprintf(device, sizeof(device), "/dev/%s", ptname);
+               rc += report_device(device, 1);
        }
 
        fclose(procpt);
+       return rc;
 }
 
-void report_device(char *device, int quiet)
+static int report_device(char *device, int quiet)
 {
        int fd;
        int ro, ssz, bsz;
+       int rc = 0;
        long ra;
        unsigned long long bytes;
-       struct hd_geometry g;
+       uint64_t start = 0;
+       char start_str[16] = { "\0" };
+       struct stat st;
 
        fd = open(device, O_RDONLY | O_NONBLOCK);
        if (fd < 0) {
                if (!quiet)
                        warn(_("cannot open %s"), device);
-               return;
+               return 1;
        }
 
        ro = ssz = bsz = 0;
-       g.start = ra = 0;
+       ra = 0;
+       if (fstat(fd, &st) == 0) {
+               dev_t disk;
+               struct path_cxt *pc;
+
+               pc = ul_new_sysfs_path(st.st_rdev, NULL, NULL);
+               if (pc &&
+                   sysfs_blkdev_get_wholedisk(pc, NULL, 0, &disk) == 0 &&
+                   disk != st.st_rdev) {
+
+                       if (ul_path_read_u64(pc, &start, "start") != 0)
+                               /* TRANSLATORS: Start sector not available. Max. 15 letters. */
+                               snprintf(start_str, sizeof(start_str), "%15s", _("N/A"));
+               }
+               ul_unref_path(pc);
+       }
+       if (!*start_str)
+               snprintf(start_str, sizeof(start_str), "%15ju", start);
+
        if (ioctl(fd, BLKROGET, &ro) == 0 &&
            ioctl(fd, BLKRAGET, &ra) == 0 &&
            ioctl(fd, BLKSSZGET, &ssz) == 0 &&
            ioctl(fd, BLKBSZGET, &bsz) == 0 &&
-           ioctl(fd, HDIO_GETGEO, &g) == 0 &&
            blkdev_get_size(fd, &bytes) == 0) {
-               printf("%s %5ld %5d %5d %10ld %15lld   %s\n",
-                      ro ? "ro" : "rw", ra, ssz, bsz, g.start, bytes, device);
+               printf("%s %5ld %5d %5d %s %15lld   %s\n",
+                       ro ? "ro" : "rw", ra, ssz, bsz, start_str, bytes, device);
        } else {
                if (!quiet)
                        warnx(_("ioctl error on %s"), device);
+               rc = 1;
        }
 
        close(fd);
+       return rc;
 }
 
-void report_header()
+static void report_header(void)
 {
-       printf(_("RO    RA   SSZ   BSZ   StartSec            Size   Device\n"));
+       printf(_("RO    RA   SSZ   BSZ        StartSec            Size   Device\n"));
 }