blob: e60bbe60944ec486c57c4bf8d0440746d8c772ee [file] [log] [blame]
Sergey Naumov289aff82010-09-06 13:35:58 +02001/*
2 * blockdev implementation for busybox
3 *
4 * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
5 *
Denys Vlasenkof38b9122010-09-06 17:41:46 +02006 * Licensed under GPLv2, see file LICENSE in this source tree.
Sergey Naumov289aff82010-09-06 13:35:58 +02007 */
Sergey Naumov289aff82010-09-06 13:35:58 +02008//config:config BLOCKDEV
Denys Vlasenkob097a842018-12-28 03:20:17 +01009//config: bool "blockdev (2.3 kb)"
Sergey Naumov289aff82010-09-06 13:35:58 +020010//config: default y
11//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020012//config: Performs some ioctls with block devices.
Sergey Naumov289aff82010-09-06 13:35:58 +020013
Denys Vlasenko9f598492017-08-05 01:29:12 +020014//applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
Denys Vlasenkodd898c92016-11-23 11:46:32 +010015
16//kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
17
Sergey Naumov289aff82010-09-06 13:35:58 +020018//usage:#define blockdev_trivial_usage
Denys Vlasenkob4e6b412010-09-06 14:15:46 +020019//usage: "OPTION BLOCKDEV"
Sergey Naumov289aff82010-09-06 13:35:58 +020020//usage:#define blockdev_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020021//usage: " --setro Set ro"
Sergey Naumov289aff82010-09-06 13:35:58 +020022//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"
Dan Fandrichf303bdd2011-02-20 04:15:43 +010027//usage: "\n --getsz Get device size in 512-byte sectors"
28/*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
Sergey Naumov289aff82010-09-06 13:35:58 +020029//usage: "\n --getsize64 Get device size in bytes"
30//usage: "\n --flushbufs Flush buffers"
31//usage: "\n --rereadpt Reread partition table"
Denys Vlasenko023ae752019-06-08 08:57:11 +020032// util-linux 2.31 also has:
33// --getdiscardzeroes BLKDISCARDZEROES Get discard zeroes support status
34// --getpbsz BLKPBSZGET Get physical block (sector) size
35// --getiomin BLKIOMIN Get minimum I/O size
36// --getioopt BLKIOOPT Get optimal I/O size
37// --getalignoff BLKALIGNOFF Get alignment offset in bytes
38// --getmaxsect BLKSECTGET Get max sectors per request
39// --setra SECTORS BLKRASET Set readahead
40// --getra BLKRAGET Get readahead
41// --setfra SECTORS BLKFRASET Set filesystem readahead
42// --getfra BLKFRAGET Get filesystem readahead
Sergey Naumov289aff82010-09-06 13:35:58 +020043
44#include "libbb.h"
45#include <linux/fs.h>
46
Denys Vlasenko35082fc2019-03-30 20:07:21 +010047/* Takes less space is separate arrays than one array of struct */
48static const char bdcmd_names[] ALIGN1 =
49 "setro" "\0"
50#define CMD_SETRO 0
51 "setrw" "\0"
52 "getro" "\0"
53 "getss" "\0"
54 "getbsz" "\0"
55 "setbsz" "\0"
56#define CMD_SETBSZ 5
57 "getsz" "\0"
58 "getsize" "\0"
59 "getsize64" "\0"
60 "flushbufs" "\0"
61 "rereadpt" "\0"
62;
63static const uint32_t bdcmd_ioctl[] = {
64 BLKROSET, //setro
65 BLKROSET, //setrw
66 BLKROGET, //getro
67 BLKSSZGET, //getss
68 BLKBSZGET, //getbsz
69 BLKBSZSET, //setbsz
70 BLKGETSIZE64, //getsz
71 BLKGETSIZE, //getsize
72 BLKGETSIZE64, //getsize64
73 BLKFLSBUF, //flushbufs
74 BLKRRPART, //rereadpt
75};
Sergey Naumov289aff82010-09-06 13:35:58 +020076enum {
77 ARG_NONE = 0,
78 ARG_INT = 1,
79 ARG_ULONG = 2,
Denys Vlasenko571c5ab2010-09-06 17:37:52 +020080 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
81 ARG_U64 = 3,
Sergey Naumov289aff82010-09-06 13:35:58 +020082 ARG_MASK = 3,
83
84 FL_USRARG = 4, /* argument is provided by user */
85 FL_NORESULT = 8,
Dan Fandrichf303bdd2011-02-20 04:15:43 +010086 FL_SCALE512 = 16,
Sergey Naumov289aff82010-09-06 13:35:58 +020087};
Denys Vlasenko35082fc2019-03-30 20:07:21 +010088static const uint8_t bdcmd_flags[] ALIGN1 = {
89 ARG_INT + FL_NORESULT, //setro
90 ARG_INT + FL_NORESULT, //setrw
91 ARG_INT, //getro
92 ARG_INT, //getss
93 ARG_INT, //getbsz
94 ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
95 ARG_U64 + FL_SCALE512, //getsz
96 ARG_ULONG, //getsize
97 ARG_U64, //getsize64
98 ARG_NONE + FL_NORESULT, //flushbufs
99 ARG_NONE + FL_NORESULT, //rereadpt
Sergey Naumov289aff82010-09-06 13:35:58 +0200100};
101
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100102static unsigned find_cmd(const char *s)
Sergey Naumov289aff82010-09-06 13:35:58 +0200103{
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200104 if (s[0] == '-' && s[1] == '-') {
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100105 int n = index_in_strings(bdcmd_names, s + 2);
106 if (n >= 0)
107 return n;
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200108 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200109 bb_show_usage();
110}
111
112int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100113int blockdev_main(int argc UNUSED_PARAM, char **argv)
Sergey Naumov289aff82010-09-06 13:35:58 +0200114{
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100115 unsigned bdcmd;
116 unsigned flags;
Sergey Naumov289aff82010-09-06 13:35:58 +0200117 int fd;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200118 uint64_t u64;
119 union {
120 int i;
121 unsigned long lu;
122 uint64_t u64;
123 } ioctl_val_on_stack;
Sergey Naumov289aff82010-09-06 13:35:58 +0200124
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100125 argv++;
126 if (!argv[0] || !argv[1]) /* must have at least 2 args */
Sergey Naumov289aff82010-09-06 13:35:58 +0200127 bb_show_usage();
128
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100129 bdcmd = find_cmd(*argv);
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100130 /* setrw translates to BLKROSET(0), most other ioctls don't care... */
131 /* ...setro will do BLKROSET(1) */
132 u64 = (bdcmd == CMD_SETRO);
133 if (bdcmd == CMD_SETBSZ) {
134 /* ...setbsz is BLKBSZSET(bytes) */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200135 u64 = xatoi_positive(*++argv);
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100136 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200137
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100138 argv++;
139 if (!argv[0] || argv[1])
Sergey Naumov289aff82010-09-06 13:35:58 +0200140 bb_show_usage();
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100141 fd = xopen(argv[0], O_RDONLY);
Sergey Naumov289aff82010-09-06 13:35:58 +0200142
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200143 ioctl_val_on_stack.u64 = u64;
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100144 flags = bdcmd_flags[bdcmd];
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200145#if BB_BIG_ENDIAN
146 /* Store data properly wrt data size.
147 * (1) It's no-op for little-endian.
148 * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
149 * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
150 * Thus, we don't need to handle ARG_ULONG.
151 */
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100152 switch (flags & ARG_MASK) {
Sergey Naumov289aff82010-09-06 13:35:58 +0200153 case ARG_INT:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200154 ioctl_val_on_stack.i = (int)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200155 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200156# if 0 /* unused */
Sergey Naumov289aff82010-09-06 13:35:58 +0200157 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200158 ioctl_val_on_stack.lu = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200159 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200160# endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200161 }
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200162#endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200163
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100164 if (ioctl(fd, bdcmd_ioctl[bdcmd], &ioctl_val_on_stack.u64) == -1)
Sergey Naumov289aff82010-09-06 13:35:58 +0200165 bb_simple_perror_msg_and_die(*argv);
166
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200167 /* Fetch it into register(s) */
168 u64 = ioctl_val_on_stack.u64;
169
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100170 if (flags & FL_SCALE512)
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100171 u64 >>= 9;
172
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200173 /* Zero- or one-extend the value if needed, then print */
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100174 switch (flags & (ARG_MASK+FL_NORESULT)) {
Sergey Naumov289aff82010-09-06 13:35:58 +0200175 case ARG_INT:
176 /* Smaller code when we use long long
177 * (gcc tail-merges printf call)
178 */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200179 printf("%lld\n", (long long)(int)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200180 break;
181 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200182 u64 = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200183 /* FALLTHROUGH */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200184 case ARG_U64:
185 printf("%llu\n", (unsigned long long)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200186 break;
187 }
188
189 if (ENABLE_FEATURE_CLEAN_UP)
190 close(fd);
191 return EXIT_SUCCESS;
192}