nsenter,unshare: work around older header
[oweals/busybox.git] / util-linux / blockdev.c
index eb5914b58227b5e6cc274883f1235a3abc9e6e81..e25e529db2ddf273a380f82c32fe7c8944bf4c03 100644 (file)
@@ -3,10 +3,10 @@
  *
  * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
  *
- * Licensed under GPLv2, see file License in this tarball for details.
+ * Licensed under GPLv2, see file LICENSE in this source tree.
  */
 
-//applet:IF_BLOCKDEV(APPLET(blockdev, _BB_DIR_SBIN, _BB_SUID_DROP))
+//applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
 
 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
 
 //config:        Performs some ioctls with block devices.
 
 //usage:#define blockdev_trivial_usage
-//usage:       "OPTION [OPTARG] DEVICE"
+//usage:       "OPTION BLOCKDEV"
 //usage:#define blockdev_full_usage "\n\n"
-//usage:       "Options:"
-//usage:     "\n       --setro         Set ro"
+//usage:       "       --setro         Set ro"
 //usage:     "\n       --setrw         Set rw"
 //usage:     "\n       --getro         Get ro"
 //usage:     "\n       --getss         Get sector size"
 //usage:     "\n       --getbsz        Get block size"
 //usage:     "\n       --setbsz BYTES  Set block size"
-//usage:     "\n       --getsize       Get device size in 512-byte sectors"
+//usage:     "\n       --getsz         Get device size in 512-byte sectors"
+/*//usage:     "\n     --getsize       Get device size in sectors (deprecated)"*/
 //usage:     "\n       --getsize64     Get device size in bytes"
 //usage:     "\n       --flushbufs     Flush buffers"
 //usage:     "\n       --rereadpt      Reread partition table"
@@ -39,11 +39,13 @@ enum {
        ARG_NONE   = 0,
        ARG_INT    = 1,
        ARG_ULONG  = 2,
-       ARG_ULLONG = 3,
+       /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
+       ARG_U64    = 3,
        ARG_MASK   = 3,
 
        FL_USRARG   = 4, /* argument is provided by user */
        FL_NORESULT = 8,
+       FL_SCALE512 = 16,
 };
 
 struct bdc {
@@ -84,6 +86,11 @@ static const struct bdc bdcommands[] = {
                .name = "setbsz",
                .flags = ARG_INT + FL_NORESULT + FL_USRARG,
                .argval = 0,
+       },{
+               .ioc = BLKGETSIZE64,
+               .name = "getsz",
+               .flags = ARG_U64 + FL_SCALE512,
+               .argval = -1,
        },{
                .ioc = BLKGETSIZE,
                .name = "getsize",
@@ -92,7 +99,7 @@ static const struct bdc bdcommands[] = {
        },{
                .ioc = BLKGETSIZE64,
                .name = "getsize64",
-               .flags = ARG_ULLONG,
+               .flags = ARG_U64,
                .argval = -1,
        },{
                .ioc = BLKFLSBUF,
@@ -109,68 +116,87 @@ static const struct bdc bdcommands[] = {
 
 static const struct bdc *find_cmd(const char *s)
 {
-       int j;
-       if (*s++ == '-')
-               if (*s++ == '-')
-                       for (j = 0; j < ARRAY_SIZE(bdcommands); j++)
-                               if (strcmp(s, bdcommands[j].name) == 0)
-                                       return &bdcommands[j];
+       const struct bdc *bdcmd = bdcommands;
+       if (s[0] == '-' && s[1] == '-') {
+               s += 2;
+               do {
+                       if (strcmp(s, bdcmd->name) == 0)
+                               return bdcmd;
+                       bdcmd++;
+               } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
+       }
        bb_show_usage();
 }
 
 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int blockdev_main(int argc, char **argv)
+int blockdev_main(int argc UNUSED_PARAM, char **argv)
 {
        const struct bdc *bdcmd;
-       void *ioctl_ptr;
        int fd;
-       int iarg;
-       unsigned long lu;
-       unsigned long long llu;
-
-       if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */
+       uint64_t u64;
+       union {
+               int i;
+               unsigned long lu;
+               uint64_t u64;
+       } ioctl_val_on_stack;
+
+       argv++;
+       if (!argv[0] || !argv[1]) /* must have at least 2 args */
                bb_show_usage();
 
-       bdcmd = find_cmd(*++argv);
+       bdcmd = find_cmd(*argv);
 
-       llu = (int)bdcmd->argval;
+       u64 = (int)bdcmd->argval;
        if (bdcmd->flags & FL_USRARG)
-               llu = xatoi_positive(*++argv);
-       lu = llu;
-       iarg = llu;
+               u64 = xatoi_positive(*++argv);
 
-       if (!*++argv)
+       argv++;
+       if (!argv[0] || argv[1])
                bb_show_usage();
-       fd = xopen(*argv, O_RDONLY);
-
-       ioctl_ptr = NULL;
+       fd = xopen(argv[0], O_RDONLY);
+
+       ioctl_val_on_stack.u64 = u64;
+#if BB_BIG_ENDIAN
+       /* Store data properly wrt data size.
+        * (1) It's no-op for little-endian.
+        * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
+        * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
+        * Thus, we don't need to handle ARG_ULONG.
+        */
        switch (bdcmd->flags & ARG_MASK) {
        case ARG_INT:
-               ioctl_ptr =  &iarg;
+               ioctl_val_on_stack.i = (int)u64;
                break;
+# if 0 /* unused */
        case ARG_ULONG:
-               ioctl_ptr = &lu;
-               break;
-       case ARG_ULLONG:
-               ioctl_ptr = &llu;
+               ioctl_val_on_stack.lu = (unsigned long)u64;
                break;
+# endif
        }
+#endif
 
-       if (ioctl(fd, bdcmd->ioc, ioctl_ptr) == -1)
+       if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
                bb_simple_perror_msg_and_die(*argv);
 
+       /* Fetch it into register(s) */
+       u64 = ioctl_val_on_stack.u64;
+
+       if (bdcmd->flags & FL_SCALE512)
+               u64 >>= 9;
+
+       /* Zero- or one-extend the value if needed, then print */
        switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
        case ARG_INT:
                /* Smaller code when we use long long
                 * (gcc tail-merges printf call)
                 */
-               printf("%lld\n", (long long)iarg);
+               printf("%lld\n", (long long)(int)u64);
                break;
        case ARG_ULONG:
-               llu = lu;
+               u64 = (unsigned long)u64;
                /* FALLTHROUGH */
-       case ARG_ULLONG:
-               printf("%llu\n", llu);
+       case ARG_U64:
+               printf("%llu\n", (unsigned long long)u64);
                break;
        }