#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"
+ "flushbufs" "\0"
+ "rereadpt" "\0"
+;
+static const uint32_t bdcmd_ioctl[] = {
+ BLKROSET, //setro
+ BLKROSET, //setrw
+ BLKROGET, //getro
+ BLKSSZGET, //getss
+ BLKBSZGET, //getbsz
+ BLKBSZSET, //setbsz
+ BLKGETSIZE64, //getsz
+ BLKGETSIZE, //getsize
+ BLKGETSIZE64, //getsize64
+ BLKFLSBUF, //flushbufs
+ BLKRRPART, //rereadpt
+};
enum {
ARG_NONE = 0,
ARG_INT = 1,
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 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_NONE + FL_NORESULT, //flushbufs
+ ARG_NONE + FL_NORESULT, //rereadpt
};
-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)
+static unsigned 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));
+ 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)
{
- const struct bdc *bdcmd;
+ unsigned bdcmd;
+ unsigned flags;
int fd;
uint64_t u64;
union {
bb_show_usage();
bdcmd = find_cmd(*argv);
-
- u64 = (int)bdcmd->argval;
- if (bdcmd->flags & FL_USRARG)
+ /* setrw translates to BLKROSET(0), most other ioctls don't care... */
+ /* ...setro will do BLKROSET(1) */
+ u64 = (bdcmd == CMD_SETRO);
+ if (bdcmd == CMD_SETBSZ) {
+ /* ...setbsz is BLKBSZSET(bytes) */
u64 = xatoi_positive(*++argv);
+ }
argv++;
if (!argv[0] || argv[1])
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.
* 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) {
+ switch (flags & ARG_MASK) {
case ARG_INT:
ioctl_val_on_stack.i = (int)u64;
break;
}
#endif
- if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
+ if (ioctl(fd, bdcmd_ioctl[bdcmd], &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)
+ if (flags & FL_SCALE512)
u64 >>= 9;
/* Zero- or one-extend the value if needed, then print */
- switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
+ switch (flags & (ARG_MASK+FL_NORESULT)) {
case ARG_INT:
/* Smaller code when we use long long
* (gcc tail-merges printf call)