123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /*
- * blockdev implementation for busybox
- *
- * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
- *
- * Licensed under GPLv2, see file LICENSE in this source tree.
- */
- //config:config BLOCKDEV
- //config: bool "blockdev (2.3 kb)"
- //config: default y
- //config: help
- //config: Performs some ioctls with block devices.
- //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
- //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
- //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"
- ///////: "\n --getsize Get device size in sectors (deprecated)"
- ///////^^^^^ supported, but not shown in help ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- //usage: "\n --getsize64 Get device size in bytes"
- //usage: "\n --getra Get readahead in 512-byte sectors"
- //usage: "\n --setra SECTORS Set readahead"
- //usage: "\n --flushbufs Flush buffers"
- //usage: "\n --rereadpt Reread partition table"
- // util-linux 2.31 also has:
- // --getdiscardzeroes BLKDISCARDZEROES Get discard zeroes support status
- // --getpbsz BLKPBSZGET Get physical block (sector) size
- // --getiomin BLKIOMIN Get minimum I/O size
- // --getioopt BLKIOOPT Get optimal I/O size
- // --getalignoff BLKALIGNOFF Get alignment offset in bytes
- // --getmaxsect BLKSECTGET Get max sectors per request
- // --setra SECTORS BLKRASET Set readahead
- // --getra BLKRAGET Get readahead
- // --setfra SECTORS BLKFRASET Set filesystem readahead
- // --getfra BLKFRAGET Get filesystem readahead
- #include "libbb.h"
- #include <linux/fs.h>
- /* Takes less space is separate arrays than one array of struct */
- static const char bdcmd_names[] ALIGN1 =
- "setro" "\0"
- #define CMD_SETRO 0
- "setrw" "\0"
- "getro" "\0"
- "getss" "\0"
- "getbsz" "\0"
- "setbsz" "\0"
- #define CMD_SETBSZ 5
- "getsz" "\0"
- "getsize" "\0"
- "getsize64" "\0"
- "getra" "\0"
- "setra" "\0"
- #define CMD_SETRA 10
- "flushbufs" "\0"
- "rereadpt" "\0"
- ;
- static const uint32_t bdcmd_ioctl[] ALIGN4 = {
- BLKROSET, //setro
- BLKROSET, //setrw
- BLKROGET, //getro
- BLKSSZGET, //getss
- BLKBSZGET, //getbsz
- BLKBSZSET, //setbsz
- BLKGETSIZE64, //getsz
- BLKGETSIZE, //getsize
- BLKGETSIZE64, //getsize64
- BLKRAGET, //getra
- BLKRASET, //setra
- BLKFLSBUF, //flushbufs
- BLKRRPART, //rereadpt
- };
- 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,
- };
- static const uint8_t bdcmd_flags[] ALIGN1 = {
- ARG_INT + FL_NORESULT, //setro
- ARG_INT + FL_NORESULT, //setrw
- ARG_INT, //getro
- ARG_INT, //getss
- ARG_INT, //getbsz
- ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
- ARG_U64 + FL_SCALE512, //getsz
- ARG_ULONG, //getsize
- ARG_U64, //getsize64
- ARG_ULONG, //getra
- ARG_ULONG + FL_NORESULT, //setra
- ARG_NONE + FL_NORESULT, //flushbufs
- ARG_NONE + FL_NORESULT, //rereadpt
- };
- static unsigned find_cmd(const char *s)
- {
- if (s[0] == '-' && s[1] == '-') {
- int n = index_in_strings(bdcmd_names, s + 2);
- if (n >= 0)
- return n;
- }
- bb_show_usage();
- }
- int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
- int blockdev_main(int argc UNUSED_PARAM, char **argv)
- {
- unsigned bdcmd;
- unsigned flags;
- 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);
- /* setrw translates to BLKROSET(0), most other ioctls don't care... */
- /* ...setro will do BLKROSET(1) */
- u64 = (bdcmd == CMD_SETRO);
- if (bdcmd == CMD_SETBSZ || bdcmd == CMD_SETRA) {
- /* ...setbsz is BLKBSZSET(bytes) */
- /* ...setra is BLKRASET(512 bytes) */
- 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;
- flags = bdcmd_flags[bdcmd];
- #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.
- * --setro uses arg != 0 and != -1, and it is ARG_INT
- * --setbsz USER_VAL is also ARG_INT
- * --setra USER_VAL is ARG_ULONG, but it is passed by value,
- * not reference (see below in ioctl call).
- * Thus, we don't need to handle ARG_ULONG.
- */
- switch (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_ioctl[bdcmd],
- bdcmd == CMD_SETRA
- ? (void*)(uintptr_t)u64 /* BLKRASET passes _value_, not pointer to it */
- : &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 (flags & FL_SCALE512)
- u64 >>= 9;
- /* Zero- or one-extend the value if needed, then print */
- switch (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;
- }
|