busybox/util-linux/blockdev.c
<<
>>
Prefs
   1/*
   2 * blockdev implementation for busybox
   3 *
   4 * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
   5 *
   6 * Licensed under GPLv2, see file LICENSE in this source tree.
   7 */
   8
   9//applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
  10
  11//kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
  12
  13//config:config BLOCKDEV
  14//config:       bool "blockdev"
  15//config:       default y
  16//config:       help
  17//config:         Performs some ioctls with block devices.
  18
  19//usage:#define blockdev_trivial_usage
  20//usage:        "OPTION BLOCKDEV"
  21//usage:#define blockdev_full_usage "\n\n"
  22//usage:       "        --setro         Set ro"
  23//usage:     "\n        --setrw         Set rw"
  24//usage:     "\n        --getro         Get ro"
  25//usage:     "\n        --getss         Get sector size"
  26//usage:     "\n        --getbsz        Get block size"
  27//usage:     "\n        --setbsz BYTES  Set block size"
  28//usage:     "\n        --getsz         Get device size in 512-byte sectors"
  29/*//usage:     "\n      --getsize       Get device size in sectors (deprecated)"*/
  30//usage:     "\n        --getsize64     Get device size in bytes"
  31//usage:     "\n        --flushbufs     Flush buffers"
  32//usage:     "\n        --rereadpt      Reread partition table"
  33
  34
  35#include "libbb.h"
  36#include <linux/fs.h>
  37
  38enum {
  39        ARG_NONE   = 0,
  40        ARG_INT    = 1,
  41        ARG_ULONG  = 2,
  42        /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
  43        ARG_U64    = 3,
  44        ARG_MASK   = 3,
  45
  46        FL_USRARG   = 4, /* argument is provided by user */
  47        FL_NORESULT = 8,
  48        FL_SCALE512 = 16,
  49};
  50
  51struct bdc {
  52        uint32_t   ioc;                       /* ioctl code */
  53        const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
  54        uint8_t    flags;
  55        int8_t     argval;                    /* default argument value */
  56};
  57
  58static const struct bdc bdcommands[] = {
  59        {
  60                .ioc = BLKROSET,
  61                .name = "setro",
  62                .flags = ARG_INT + FL_NORESULT,
  63                .argval = 1,
  64        },{
  65                .ioc = BLKROSET,
  66                .name = "setrw",
  67                .flags = ARG_INT + FL_NORESULT,
  68                .argval = 0,
  69        },{
  70                .ioc = BLKROGET,
  71                .name = "getro",
  72                .flags = ARG_INT,
  73                .argval = -1,
  74        },{
  75                .ioc = BLKSSZGET,
  76                .name = "getss",
  77                .flags = ARG_INT,
  78                .argval = -1,
  79        },{
  80                .ioc = BLKBSZGET,
  81                .name = "getbsz",
  82                .flags = ARG_INT,
  83                .argval = -1,
  84        },{
  85                .ioc = BLKBSZSET,
  86                .name = "setbsz",
  87                .flags = ARG_INT + FL_NORESULT + FL_USRARG,
  88                .argval = 0,
  89        },{
  90                .ioc = BLKGETSIZE64,
  91                .name = "getsz",
  92                .flags = ARG_U64 + FL_SCALE512,
  93                .argval = -1,
  94        },{
  95                .ioc = BLKGETSIZE,
  96                .name = "getsize",
  97                .flags = ARG_ULONG,
  98                .argval = -1,
  99        },{
 100                .ioc = BLKGETSIZE64,
 101                .name = "getsize64",
 102                .flags = ARG_U64,
 103                .argval = -1,
 104        },{
 105                .ioc = BLKFLSBUF,
 106                .name = "flushbufs",
 107                .flags = ARG_NONE + FL_NORESULT,
 108                .argval = 0,
 109        },{
 110                .ioc = BLKRRPART,
 111                .name = "rereadpt",
 112                .flags = ARG_NONE + FL_NORESULT,
 113                .argval = 0,
 114        }
 115};
 116
 117static const struct bdc *find_cmd(const char *s)
 118{
 119        const struct bdc *bdcmd = bdcommands;
 120        if (s[0] == '-' && s[1] == '-') {
 121                s += 2;
 122                do {
 123                        if (strcmp(s, bdcmd->name) == 0)
 124                                return bdcmd;
 125                        bdcmd++;
 126                } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
 127        }
 128        bb_show_usage();
 129}
 130
 131int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 132int blockdev_main(int argc UNUSED_PARAM, char **argv)
 133{
 134        const struct bdc *bdcmd;
 135        int fd;
 136        uint64_t u64;
 137        union {
 138                int i;
 139                unsigned long lu;
 140                uint64_t u64;
 141        } ioctl_val_on_stack;
 142
 143        argv++;
 144        if (!argv[0] || !argv[1]) /* must have at least 2 args */
 145                bb_show_usage();
 146
 147        bdcmd = find_cmd(*argv);
 148
 149        u64 = (int)bdcmd->argval;
 150        if (bdcmd->flags & FL_USRARG)
 151                u64 = xatoi_positive(*++argv);
 152
 153        argv++;
 154        if (!argv[0] || argv[1])
 155                bb_show_usage();
 156        fd = xopen(argv[0], O_RDONLY);
 157
 158        ioctl_val_on_stack.u64 = u64;
 159#if BB_BIG_ENDIAN
 160        /* Store data properly wrt data size.
 161         * (1) It's no-op for little-endian.
 162         * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
 163         * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
 164         * Thus, we don't need to handle ARG_ULONG.
 165         */
 166        switch (bdcmd->flags & ARG_MASK) {
 167        case ARG_INT:
 168                ioctl_val_on_stack.i = (int)u64;
 169                break;
 170# if 0 /* unused */
 171        case ARG_ULONG:
 172                ioctl_val_on_stack.lu = (unsigned long)u64;
 173                break;
 174# endif
 175        }
 176#endif
 177
 178        if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
 179                bb_simple_perror_msg_and_die(*argv);
 180
 181        /* Fetch it into register(s) */
 182        u64 = ioctl_val_on_stack.u64;
 183
 184        if (bdcmd->flags & FL_SCALE512)
 185                u64 >>= 9;
 186
 187        /* Zero- or one-extend the value if needed, then print */
 188        switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
 189        case ARG_INT:
 190                /* Smaller code when we use long long
 191                 * (gcc tail-merges printf call)
 192                 */
 193                printf("%lld\n", (long long)(int)u64);
 194                break;
 195        case ARG_ULONG:
 196                u64 = (unsigned long)u64;
 197                /* FALLTHROUGH */
 198        case ARG_U64:
 199                printf("%llu\n", (unsigned long long)u64);
 200                break;
 201        }
 202
 203        if (ENABLE_FEATURE_CLEAN_UP)
 204                close(fd);
 205        return EXIT_SUCCESS;
 206}
 207