123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- /*
- * blockdev implementation for busybox
- *
- * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
- //applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
- //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
- //config:config BLOCKDEV
- //config: bool "blockdev"
- //config: default y
- //config: help
- //config: Performs some ioctls with block devices.
- //usage:#define blockdev_trivial_usage
- //usage: "OPTION BLOCKDEV"
- //usage:#define blockdev_full_usage "\n\n"
- //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 --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"
- #include "libbb.h"
- #include <linux/fs.h>
- enum {
- ARG_NONE = 0,
- ARG_INT = 1,
- ARG_ULONG = 2,
- /* 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 {
- uint32_t ioc; /* ioctl code */
- const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
- uint8_t flags;
- int8_t argval; /* default argument value */
- };
- static const struct bdc bdcommands[] = {
- {
- .ioc = BLKROSET,
- .name = "setro",
- .flags = ARG_INT + FL_NORESULT,
- .argval = 1,
- },{
- .ioc = BLKROSET,
- .name = "setrw",
- .flags = ARG_INT + FL_NORESULT,
- .argval = 0,
- },{
- .ioc = BLKROGET,
- .name = "getro",
- .flags = ARG_INT,
- .argval = -1,
- },{
- .ioc = BLKSSZGET,
- .name = "getss",
- .flags = ARG_INT,
- .argval = -1,
- },{
- .ioc = BLKBSZGET,
- .name = "getbsz",
- .flags = ARG_INT,
- .argval = -1,
- },{
- .ioc = BLKBSZSET,
- .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",
- .flags = ARG_ULONG,
- .argval = -1,
- },{
- .ioc = BLKGETSIZE64,
- .name = "getsize64",
- .flags = ARG_U64,
- .argval = -1,
- },{
- .ioc = BLKFLSBUF,
- .name = "flushbufs",
- .flags = ARG_NONE + FL_NORESULT,
- .argval = 0,
- },{
- .ioc = BLKRRPART,
- .name = "rereadpt",
- .flags = ARG_NONE + FL_NORESULT,
- .argval = 0,
- }
- };
- static const struct bdc *find_cmd(const char *s)
- {
- 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 UNUSED_PARAM, char **argv)
- {
- const struct bdc *bdcmd;
- int fd;
- 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);
- u64 = (int)bdcmd->argval;
- if (bdcmd->flags & FL_USRARG)
- u64 = xatoi_positive(*++argv);
- argv++;
- if (!argv[0] || argv[1])
- bb_show_usage();
- 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_val_on_stack.i = (int)u64;
- break;
- # if 0 /* unused */
- case ARG_ULONG:
- ioctl_val_on_stack.lu = (unsigned long)u64;
- break;
- # endif
- }
- #endif
- 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)(int)u64);
- break;
- case ARG_ULONG:
- u64 = (unsigned long)u64;
- /* FALLTHROUGH */
- case ARG_U64:
- printf("%llu\n", (unsigned long long)u64);
- break;
- }
- if (ENABLE_FEATURE_CLEAN_UP)
- close(fd);
- return EXIT_SUCCESS;
- }
|