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