]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - disk-utils/blockdev.c
kill: add missing ifdefs
[thirdparty/util-linux.git] / disk-utils / blockdev.c
index bb11981db46ab4878e8317b754bb4986e3ef3937..f1067c8152b2390345f673a39ffeb40e90f27f52 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <errno.h>
 
+#include "c.h"
 #include "nls.h"
+#include "blkdev.h"
+#include "pathnames.h"
+#include "closestream.h"
+#include "sysfs.h"
 
-/* Since it is impossible to include <linux/fs.h>, let us
-   give the ioctls explicitly. */
-
-#ifndef BLKROSET
-#define BLKROSET   _IO(0x12,93)
-#define BLKROGET   _IO(0x12,94)
-#define BLKRRPART  _IO(0x12,95)
-#define BLKGETSIZE _IO(0x12,96)
-#define BLKFLSBUF  _IO(0x12,97)
-#define BLKRASET   _IO(0x12,98)
-#define BLKRAGET   _IO(0x12,99)
-#define BLKSSZGET  _IO(0x12,104)
-#define BLKBSZGET  _IOR(0x12,112,size_t)
-#define BLKBSZSET  _IOW(0x12,113,size_t)
-#define BLKGETSIZE64 _IOR(0x12,114,size_t)
-#endif
-
-/* Maybe <linux/hdreg.h> could be included */
-#ifndef HDIO_GETGEO
-#define HDIO_GETGEO 0x0301
-struct hd_geometry {
-       unsigned char heads;
-       unsigned char sectors;
-       unsigned short cylinders;       /* truncated */
-       unsigned long start;
+struct bdc {
+       long            ioc;            /* ioctl code */
+       const char      *iocname;       /* ioctl name (e.g. BLKROSET) */
+       long            argval;         /* default argument */
+
+       const char      *name;          /* --setfoo */
+       const char      *argname;       /* argument name or NULL */
+
+       const char      *help;
+
+       int             argtype;
+       int             flags;
 };
-#endif
 
-const char *progname;
+/* command flags */
+enum {
+       FL_NOPTR        = (1 << 1),     /* does not assume pointer (ARG_INT only)*/
+       FL_NORESULT     = (1 << 2)      /* does not return any data */
+};
 
-struct bdc {
-       char *name;
-       char *iocname;
-       long ioc;
-       int argtype;
-#define ARGNONE        0
-#define ARGINTA        1
-#define ARGINTAP 2
-#define        ARGINTP 3
-#define ARGINTG        4
-#define ARGLINTG 5
-#define ARGLLINTG 6
-       long argval;
-       char *argname;
-       char *help;
-} bdcms[] = {
-#ifdef BLKROSET
-       { "--setro", "BLKROSET", BLKROSET, ARGINTP, 1, NULL, N_("set read-only") },
-       { "--setrw", "BLKROSET", BLKROSET, ARGINTP, 0, NULL, N_("set read-write") },
-#endif
-#ifdef BLKROGET
-       { "--getro", "BLKROGET", BLKROGET, ARGINTG, -1, NULL, N_("get read-only") },
-#endif
-#ifdef BLKSSZGET
-       { "--getss", "BLKSSZGET", BLKSSZGET, ARGINTG, -1, NULL, N_("get sectorsize") },
-#endif
-#ifdef BLKBSZGET
-       { "--getbsz", "BLKBSZGET", BLKBSZGET, ARGINTG, -1, NULL, N_("get blocksize") },
-#endif
-#ifdef BLKBSZSET
-       { "--setbsz", "BLKBSZSET", BLKBSZSET, ARGINTAP, 0, "BLOCKSIZE", N_("set blocksize") },
-#endif
-#ifdef BLKGETSIZE
-       { "--getsize", "BLKGETSIZE", BLKGETSIZE, ARGLINTG, -1, NULL, N_("get 32-bit sector count") },
-#endif
-#ifdef BLKGETSIZE64
-       { "--getsize64", "BLKGETSIZE64", BLKGETSIZE64, ARGLLINTG, -1, NULL, N_("get size in bytes") },
-#endif
-#ifdef BLKRASET
-       { "--setra", "BLKRASET", BLKRASET, ARGINTA, 0, "READAHEAD", N_("set readahead") },
-#endif
-#ifdef BLKRAGET
-       { "--getra", "BLKRAGET", BLKRAGET, ARGLINTG, -1, NULL, N_("get readahead") },
-#endif
-#ifdef BLKFLSBUF
-       { "--flushbufs", "BLKFLSBUF", BLKFLSBUF, ARGNONE, 0, NULL, N_("flush buffers") },
-#endif
-#ifdef BLKRRPART
-       { "--rereadpt", "BLKRRPART", BLKRRPART, ARGNONE, 0, NULL,
-         N_("reread partition table") },
-#endif
+/* ioctl argument types */
+enum {
+       ARG_NONE,
+       ARG_USHRT,
+       ARG_INT,
+       ARG_UINT,
+       ARG_LONG,
+       ARG_ULONG,
+       ARG_LLONG,
+       ARG_ULLONG
 };
 
-#define SIZE(a)        (sizeof(a)/sizeof((a)[0]))
-
-static void
-usage(void) {
-       int i;
-       fprintf(stderr, _("Usage:\n"));
-       fprintf(stderr, "  %s -V\n", progname);
-       fprintf(stderr, _("  %s --report [devices]\n"), progname);
-       fprintf(stderr, _("  %s [-v|-q] commands devices\n"), progname);
-       fprintf(stderr, _("Available commands:\n"));
-       fprintf(stderr, "\t--getsz\t(%s)\n", "get size in 512-byte sectors");
-       for (i = 0; i < SIZE(bdcms); i++) {
-               fprintf(stderr, "\t%s", bdcms[i].name);
+#define IOCTL_ENTRY( io )      .ioc = io, .iocname = # io
+
+static const struct bdc bdcms[] =
+{
+       {
+               IOCTL_ENTRY(BLKROSET),
+               .name = "--setro",
+               .argtype = ARG_INT,
+               .argval = 1,
+               .flags = FL_NORESULT,
+               .help = N_("set read-only")
+       },{
+               IOCTL_ENTRY(BLKROSET),
+               .name = "--setrw",
+               .argtype = ARG_INT,
+               .argval = 0,
+               .flags = FL_NORESULT,
+               .help = N_("set read-write")
+       },{
+               IOCTL_ENTRY(BLKROGET),
+               .name = "--getro",
+               .argtype = ARG_INT,
+               .argval = -1,
+               .help = N_("get read-only")
+       },{
+               IOCTL_ENTRY(BLKDISCARDZEROES),
+               .name = "--getdiscardzeroes",
+               .argtype = ARG_UINT,
+               .argval = -1,
+               .help = N_("get discard zeroes support status")
+       },{
+               IOCTL_ENTRY(BLKSSZGET),
+               .name = "--getss",
+               .argtype = ARG_INT,
+               .argval = -1,
+               .help = N_("get logical block (sector) size")
+       },{
+               IOCTL_ENTRY(BLKPBSZGET),
+               .name = "--getpbsz",
+               .argtype = ARG_UINT,
+               .argval = -1,
+               .help = N_("get physical block (sector) size")
+       },{
+               IOCTL_ENTRY(BLKIOMIN),
+               .name = "--getiomin",
+               .argtype = ARG_UINT,
+               .argval = -1,
+               .help = N_("get minimum I/O size")
+       },{
+               IOCTL_ENTRY(BLKIOOPT),
+               .name = "--getioopt",
+               .argtype = ARG_UINT,
+               .argval = -1,
+               .help = N_("get optimal I/O size")
+       },{
+               IOCTL_ENTRY(BLKALIGNOFF),
+               .name = "--getalignoff",
+               .argtype = ARG_INT,
+               .argval = -1,
+               .help = N_("get alignment offset in bytes")
+       },{
+               IOCTL_ENTRY(BLKSECTGET),
+               .name = "--getmaxsect",
+               .argtype = ARG_USHRT,
+               .argval = -1,
+               .help = N_("get max sectors per request")
+       },{
+               IOCTL_ENTRY(BLKBSZGET),
+               .name = "--getbsz",
+               .argtype = ARG_INT,
+               .argval = -1,
+               .help = N_("get blocksize")
+       },{
+               IOCTL_ENTRY(BLKBSZSET),
+               .name = "--setbsz",
+               .argname = "<bytes>",
+               .argtype = ARG_INT,
+               .flags = FL_NORESULT,
+               .help = N_("set blocksize on file descriptor opening the block device")
+       },{
+               IOCTL_ENTRY(BLKGETSIZE),
+               .name = "--getsize",
+               .argtype = ARG_ULONG,
+               .argval = -1,
+               .help = N_("get 32-bit sector count (deprecated, use --getsz)")
+       },{
+               IOCTL_ENTRY(BLKGETSIZE64),
+               .name = "--getsize64",
+               .argtype = ARG_ULLONG,
+               .argval = -1,
+               .help = N_("get size in bytes")
+       },{
+               IOCTL_ENTRY(BLKRASET),
+               .name = "--setra",
+               .argname = "<sectors>",
+               .argtype = ARG_INT,
+               .flags = FL_NOPTR | FL_NORESULT,
+               .help = N_("set readahead")
+       },{
+               IOCTL_ENTRY(BLKRAGET),
+               .name = "--getra",
+               .argtype = ARG_LONG,
+               .argval = -1,
+               .help = N_("get readahead")
+       },{
+               IOCTL_ENTRY(BLKFRASET),
+               .name = "--setfra",
+               .argname = "<sectors>",
+               .argtype = ARG_INT,
+               .flags = FL_NOPTR | FL_NORESULT,
+               .help = N_("set filesystem readahead")
+       },{
+               IOCTL_ENTRY(BLKFRAGET),
+               .name = "--getfra",
+               .argtype = ARG_LONG,
+               .argval = -1,
+               .help = N_("get filesystem readahead")
+       },{
+               IOCTL_ENTRY(BLKFLSBUF),
+               .name = "--flushbufs",
+               .help = N_("flush buffers")
+       },{
+               IOCTL_ENTRY(BLKRRPART),
+               .name = "--rereadpt",
+               .help = N_("reread partition table")
+       }
+};
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+       size_t i;
+
+       fputs(USAGE_HEADER, stdout);
+       printf(_(
+                " %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);
+       puts(  _("Call block device ioctls from the command line."));
+
+       fputs(USAGE_OPTIONS, stdout);
+       puts(  _(" -q             quiet mode"));
+       puts(  _(" -v             verbose mode"));
+       puts(  _("     --report   print report for specified (or all) devices"));
+       fputs(USAGE_SEPARATOR, stdout);
+       printf(USAGE_HELP_OPTIONS(16));
+
+       fputs(USAGE_SEPARATOR, stdout);
+       puts(  _("Available commands:"));
+       printf(_(" %-25s get size in 512-byte sectors\n"), "--getsz");
+       for (i = 0; i < ARRAY_SIZE(bdcms); i++) {
                if (bdcms[i].argname)
-                       fprintf(stderr, " %s", bdcms[i].argname);
-               if (bdcms[i].help)
-                       fprintf(stderr, "\t(%s)", _(bdcms[i].help));
-               fprintf(stderr, "\n");
+                       printf(" %s %-*s %s\n", bdcms[i].name,
+                               (int)(24 - strlen(bdcms[i].name)),
+                               bdcms[i].argname, _(bdcms[i].help));
+               else
+                       printf(" %-25s %s\n", bdcms[i].name,
+                               _(bdcms[i].help));
        }
-       exit(1);
+
+       printf(USAGE_MAN_TAIL("blockdev(8)"));
+       exit(EXIT_SUCCESS);
 }
 
-static int
-find_cmd(char *s) {
-       int j;
+static int find_cmd(char *s)
+{
+       size_t j;
 
-       for (j = 0; j < SIZE(bdcms); j++)
+       for (j = 0; j < ARRAY_SIZE(bdcms); j++)
                if (!strcmp(s, bdcms[j].name))
                        return j;
        return -1;
 }
 
-static int
-getsize(int fd, long long *sectors) {
-       int err;
-       long sz;
-       long long b;
-
-       err = ioctl (fd, BLKGETSIZE, &sz);
-       if (err)
-               return err;
-       err = ioctl(fd, BLKGETSIZE64, &b);
-       if (err || b == 0 || b == sz)
-               *sectors = sz;
-       else
-               *sectors = (b >> 9);
-       return 0;
-}
-
-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 void report_device(char *device, int quiet);
+static void report_all_devices(void);
 
-int
-main(int argc, char **argv) {
+int main(int argc, char **argv)
+{
        int fd, d, j, k;
-       char *p;
-
-       /* egcs-2.91.66 is buggy and says:
-          blockdev.c:93: warning: `d' might be used uninitialized */
-       d = 0;
-
-       progname = argv[0];
-       if ((p = strrchr(progname, '/')) != NULL)
-               progname = p+1;
 
        setlocale(LC_ALL, "");
        bindtextdomain(PACKAGE, LOCALEDIR);
        textdomain(PACKAGE);
+       close_stdout_atexit();
 
-       if (argc < 2)
-               usage();
+       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 from %s\n", progname, util_linux_version);
-               exit(0);
-       }
+       if (!strcmp(argv[1], "-V") || !strcmp(argv[1], "--version"))
+               print_version(EXIT_SUCCESS);
+       if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))
+               usage();
 
        /* --report not together with other commands */
        if (!strcmp(argv[1], "--report")) {
@@ -184,7 +260,7 @@ main(int argc, char **argv) {
                } else {
                        report_all_devices();
                }
-               exit(0);
+               return EXIT_SUCCESS;
        }
 
        /* do each of the commands on each of the devices */
@@ -192,8 +268,7 @@ main(int argc, char **argv) {
        for (d = 1; d < argc; d++) {
                j = find_cmd(argv[d]);
                if (j >= 0) {
-                       if (bdcms[j].argtype == ARGINTA ||
-                           bdcms[j].argtype == ARGINTAP)
+                       if (bdcms[j].argname)
                                d++;
                        continue;
                }
@@ -207,27 +282,31 @@ main(int argc, char **argv) {
                        break;
        }
 
-       if (d >= argc)
-               usage();
+       if (d >= argc) {
+               warnx(_("no device specified"));
+               errtryhelp(EXIT_FAILURE);
+       }
 
        for (k = d; k < argc; k++) {
                fd = open(argv[k], O_RDONLY, 0);
-               if (fd < 0) {
-                       perror(argv[k]);
-                       exit(1);
-               }
+               if (fd < 0)
+                       err(EXIT_FAILURE, _("cannot open %s"), argv[k]);
                do_commands(fd, argv, d);
                close(fd);
        }
-       return 0;
+       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;
-       long larg;
-       long long llarg;
+       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++) {
@@ -241,152 +320,184 @@ do_commands(int fd, char **argv, int d) {
                }
 
                if (!strcmp(argv[i], "--getsz")) {
-                       res = getsize(fd, &llarg);
+                       res = blkdev_get_sectors(fd, &llu);
                        if (res == 0)
-                               printf("%lld\n", llarg);
+                               printf("%lld\n", llu);
                        else
-                               exit(1);
+                               errx(EXIT_FAILURE,
+                                    _("could not get device size"));
                        continue;
                }
 
                j = find_cmd(argv[i]);
                if (j == -1) {
-                       fprintf(stderr, _("%s: Unknown command: %s\n"),
-                               progname, argv[i]);
-                       usage();
+                       warnx(_("Unknown command: %s"), argv[i]);
+                       errtryhelp(EXIT_FAILURE);
                }
 
-               switch(bdcms[j].argtype) {
+               switch (bdcms[j].argtype) {
                default:
-               case ARGNONE:
+               case ARG_NONE:
                        res = ioctl(fd, bdcms[j].ioc, 0);
                        break;
-               case ARGINTA:
-                       if (i == d-1) {
-                               fprintf(stderr, _("%s requires an argument\n"),
-                                       bdcms[j].name);
-                               usage();
-                       }
-                       iarg = atoi(argv[++i]);
-                       res = ioctl(fd, bdcms[j].ioc, iarg);
+               case ARG_USHRT:
+                       huarg = bdcms[j].argval;
+                       res = ioctl(fd, bdcms[j].ioc, &huarg);
                        break;
-               case ARGINTAP:
-                       if (i == d-1) {
-                               fprintf(stderr, _("%s requires an argument\n"),
-                                       bdcms[j].name);
-                               usage();
-                       }
-                       iarg = atoi(argv[++i]);
-                       res = ioctl(fd, bdcms[j].ioc, &iarg);
+               case ARG_INT:
+                       if (bdcms[j].argname) {
+                               if (i == d - 1) {
+                                       warnx(_("%s requires an argument"),
+                                             bdcms[j].name);
+                                       errtryhelp(EXIT_FAILURE);
+                               }
+                               iarg = atoi(argv[++i]);
+                       } else
+                               iarg = bdcms[j].argval;
+
+                       res = bdcms[j].flags & FL_NOPTR ?
+                           ioctl(fd, bdcms[j].ioc, iarg) :
+                           ioctl(fd, bdcms[j].ioc, &iarg);
                        break;
-               case ARGINTP:
-               case ARGINTG:
-                       iarg = bdcms[j].argval;
-                       res = ioctl(fd, bdcms[j].ioc, &iarg);
+               case ARG_UINT:
+                       uarg = bdcms[j].argval;
+                       res = ioctl(fd, bdcms[j].ioc, &uarg);
                        break;
-               case ARGLINTG:
+               case ARG_LONG:
                        larg = bdcms[j].argval;
                        res = ioctl(fd, bdcms[j].ioc, &larg);
                        break;
-               case ARGLLINTG:
+               case ARG_LLONG:
                        llarg = bdcms[j].argval;
                        res = ioctl(fd, bdcms[j].ioc, &llarg);
                        break;
+               case ARG_ULONG:
+                       lu = bdcms[j].argval;
+                       res = ioctl(fd, bdcms[j].ioc, &lu);
+                       break;
+               case ARG_ULLONG:
+                       llu = bdcms[j].argval;
+                       res = ioctl(fd, bdcms[j].ioc, &llu);
+                       break;
                }
+
                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(1);
+                               printf(_("%s failed.\n"), _(bdcms[j].help));
+                       exit(EXIT_FAILURE);
                }
-               switch(bdcms[j].argtype) {
-               case ARGINTG:
+
+               if (bdcms[j].argtype == ARG_NONE ||
+                   (bdcms[j].flags & FL_NORESULT)) {
                        if (verbose)
-                               printf("%s: %d\n", _(bdcms[j].help), iarg);
-                       else
-                               printf("%d\n", iarg);
+                               printf(_("%s succeeded.\n"), _(bdcms[j].help));
+                       continue;
+               }
+
+               if (verbose)
+                       printf("%s: ", _(bdcms[j].help));
+
+               switch (bdcms[j].argtype) {
+               case ARG_USHRT:
+                       printf("%hu\n", huarg);
                        break;
-               case ARGLINTG:
-                       if (verbose)
-                               printf("%s: %ld\n", _(bdcms[j].help), larg);
-                       else
-                               printf("%ld\n", larg);
+               case ARG_INT:
+                       printf("%d\n", iarg);
                        break;
-               case ARGLLINTG:
-                       if (verbose)
-                               printf("%s: %lld\n", _(bdcms[j].help), llarg);
-                       else
-                               printf("%lld\n", llarg);
+               case ARG_UINT:
+                       printf("%u\n", uarg);
                        break;
-               default:
-                       if (verbose)
-                               printf(_("%s succeeded.\n"), _(bdcms[j].help));
+               case ARG_LONG:
+                       printf("%ld\n", larg);
+                       break;
+               case ARG_LLONG:
+                       printf("%lld\n", llarg);
+                       break;
+               case ARG_ULONG:
+                       printf("%lu\n", lu);
+                       break;
+               case ARG_ULLONG:
+                       printf("%llu\n", llu);
                        break;
                }
        }
 }
 
-#define PROC_PARTITIONS "/proc/partitions"
-
-void
-report_all_devices(void) {
+static void report_all_devices(void)
+{
        FILE *procpt;
        char line[200];
-       char ptname[200];
+       char ptname[200 + 1];
        char device[210];
        int ma, mi, sz;
 
-       procpt = fopen(PROC_PARTITIONS, "r");
-       if (!procpt) {
-               fprintf(stderr, _("%s: cannot open %s\n"),
-                       progname, PROC_PARTITIONS);
-               exit(1);
-       }
+       procpt = fopen(_PATH_PROC_PARTITIONS, "r");
+       if (!procpt)
+               err(EXIT_FAILURE, _("cannot open %s"), _PATH_PROC_PARTITIONS);
 
        while (fgets(line, sizeof(line), procpt)) {
-               if (sscanf (line, " %d %d %d %[^\n ]",
-                           &ma, &mi, &sz, ptname) != 4)
+               if (sscanf(line, " %d %d %d %200[^\n ]",
+                          &ma, &mi, &sz, ptname) != 4)
                        continue;
 
                sprintf(device, "/dev/%s", ptname);
                report_device(device, 1);
        }
+
+       fclose(procpt);
 }
 
-void
-report_device(char *device, int quiet) {
+static void report_device(char *device, int quiet)
+{
        int fd;
        int ro, ssz, bsz;
-       long ra, ss;
-       long long bytes;
-       struct hd_geometry g;
+       long ra;
+       unsigned long long bytes;
+       uint64_t start = 0;
+       struct stat st;
 
        fd = open(device, O_RDONLY | O_NONBLOCK);
        if (fd < 0) {
                if (!quiet)
-                       fprintf(stderr, _("%s: cannot open %s\n"),
-                               progname, device);
+                       warn(_("cannot open %s"), device);
                return;
        }
 
        ro = ssz = bsz = 0;
-       g.start = ra = ss = 0;
-       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 &&
-           getsize (fd, &bytes) == 0) {
-               printf("%s %5ld %5d %5d %10ld %10lld  %s\n",
-                      ro ? "ro" : "rw", ra, ssz, bsz, g.start, bytes, device);
+       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)
+                               err(EXIT_FAILURE,
+                                       _("%s: failed to read partition start from sysfs"),
+                                       device);
+               }
+               ul_unref_path(pc);
+       }
+       if (ioctl(fd, BLKROGET, &ro) == 0 &&
+           ioctl(fd, BLKRAGET, &ra) == 0 &&
+           ioctl(fd, BLKSSZGET, &ssz) == 0 &&
+           ioctl(fd, BLKBSZGET, &bsz) == 0 &&
+           blkdev_get_size(fd, &bytes) == 0) {
+               printf("%s %5ld %5d %5d %10ju %15lld   %s\n",
+                      ro ? "ro" : "rw", ra, ssz, bsz, start, bytes, device);
        } else {
                if (!quiet)
-                       fprintf(stderr, _("%s: ioctl error on %s\n"),
-                               progname, device);
+                       warnx(_("ioctl error on %s"), device);
        }
+
+       close(fd);
 }
 
-void
-report_header() {
-       printf(_("RO    RA   SSZ   BSZ   StartSec     Size    Device\n"));
+static void report_header(void)
+{
+       printf(_("RO    RA   SSZ   BSZ   StartSec            Size   Device\n"));
 }