blob: 3b550220a124c12d0f8abf32d2e0f5fc5898618e [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"
Denys Vlasenko46d315a2021-06-16 17:00:56 +020028///////: "\n --getsize Get device size in sectors (deprecated)"
29///////^^^^^ supported, but not shown in help ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sergey Naumov289aff82010-09-06 13:35:58 +020030//usage: "\n --getsize64 Get device size in bytes"
Denys Vlasenko46d315a2021-06-16 17:00:56 +020031//usage: "\n --getra Get readahead in 512-byte sectors"
32//usage: "\n --setra SECTORS Set readahead"
Sergey Naumov289aff82010-09-06 13:35:58 +020033//usage: "\n --flushbufs Flush buffers"
34//usage: "\n --rereadpt Reread partition table"
Denys Vlasenko023ae752019-06-08 08:57:11 +020035// util-linux 2.31 also has:
36// --getdiscardzeroes BLKDISCARDZEROES Get discard zeroes support status
37// --getpbsz BLKPBSZGET Get physical block (sector) size
38// --getiomin BLKIOMIN Get minimum I/O size
39// --getioopt BLKIOOPT Get optimal I/O size
40// --getalignoff BLKALIGNOFF Get alignment offset in bytes
41// --getmaxsect BLKSECTGET Get max sectors per request
42// --setra SECTORS BLKRASET Set readahead
43// --getra BLKRAGET Get readahead
44// --setfra SECTORS BLKFRASET Set filesystem readahead
45// --getfra BLKFRAGET Get filesystem readahead
Sergey Naumov289aff82010-09-06 13:35:58 +020046
47#include "libbb.h"
48#include <linux/fs.h>
49
Denys Vlasenko35082fc2019-03-30 20:07:21 +010050/* Takes less space is separate arrays than one array of struct */
51static const char bdcmd_names[] ALIGN1 =
52 "setro" "\0"
53#define CMD_SETRO 0
54 "setrw" "\0"
55 "getro" "\0"
56 "getss" "\0"
57 "getbsz" "\0"
58 "setbsz" "\0"
59#define CMD_SETBSZ 5
60 "getsz" "\0"
61 "getsize" "\0"
62 "getsize64" "\0"
Denys Vlasenko46d315a2021-06-16 17:00:56 +020063 "getra" "\0"
64 "setra" "\0"
65#define CMD_SETRA 10
Denys Vlasenko35082fc2019-03-30 20:07:21 +010066 "flushbufs" "\0"
67 "rereadpt" "\0"
68;
Denys Vlasenko6cc49622020-11-30 14:58:02 +010069static const uint32_t bdcmd_ioctl[] ALIGN4 = {
Denys Vlasenko35082fc2019-03-30 20:07:21 +010070 BLKROSET, //setro
71 BLKROSET, //setrw
72 BLKROGET, //getro
73 BLKSSZGET, //getss
74 BLKBSZGET, //getbsz
75 BLKBSZSET, //setbsz
76 BLKGETSIZE64, //getsz
77 BLKGETSIZE, //getsize
78 BLKGETSIZE64, //getsize64
Denys Vlasenko46d315a2021-06-16 17:00:56 +020079 BLKRAGET, //getra
80 BLKRASET, //setra
Denys Vlasenko35082fc2019-03-30 20:07:21 +010081 BLKFLSBUF, //flushbufs
82 BLKRRPART, //rereadpt
83};
Sergey Naumov289aff82010-09-06 13:35:58 +020084enum {
85 ARG_NONE = 0,
86 ARG_INT = 1,
87 ARG_ULONG = 2,
Denys Vlasenko571c5ab2010-09-06 17:37:52 +020088 /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
89 ARG_U64 = 3,
Sergey Naumov289aff82010-09-06 13:35:58 +020090 ARG_MASK = 3,
91
92 FL_USRARG = 4, /* argument is provided by user */
93 FL_NORESULT = 8,
Dan Fandrichf303bdd2011-02-20 04:15:43 +010094 FL_SCALE512 = 16,
Sergey Naumov289aff82010-09-06 13:35:58 +020095};
Denys Vlasenko35082fc2019-03-30 20:07:21 +010096static const uint8_t bdcmd_flags[] ALIGN1 = {
97 ARG_INT + FL_NORESULT, //setro
98 ARG_INT + FL_NORESULT, //setrw
99 ARG_INT, //getro
100 ARG_INT, //getss
101 ARG_INT, //getbsz
102 ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
103 ARG_U64 + FL_SCALE512, //getsz
104 ARG_ULONG, //getsize
105 ARG_U64, //getsize64
Denys Vlasenko46d315a2021-06-16 17:00:56 +0200106 ARG_ULONG, //getra
107 ARG_ULONG + FL_NORESULT, //setra
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100108 ARG_NONE + FL_NORESULT, //flushbufs
109 ARG_NONE + FL_NORESULT, //rereadpt
Sergey Naumov289aff82010-09-06 13:35:58 +0200110};
111
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100112static unsigned find_cmd(const char *s)
Sergey Naumov289aff82010-09-06 13:35:58 +0200113{
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200114 if (s[0] == '-' && s[1] == '-') {
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100115 int n = index_in_strings(bdcmd_names, s + 2);
116 if (n >= 0)
117 return n;
Denys Vlasenko264bdad2010-09-06 15:34:15 +0200118 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200119 bb_show_usage();
120}
121
122int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100123int blockdev_main(int argc UNUSED_PARAM, char **argv)
Sergey Naumov289aff82010-09-06 13:35:58 +0200124{
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100125 unsigned bdcmd;
126 unsigned flags;
Sergey Naumov289aff82010-09-06 13:35:58 +0200127 int fd;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200128 uint64_t u64;
129 union {
130 int i;
131 unsigned long lu;
132 uint64_t u64;
133 } ioctl_val_on_stack;
Sergey Naumov289aff82010-09-06 13:35:58 +0200134
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100135 argv++;
136 if (!argv[0] || !argv[1]) /* must have at least 2 args */
Sergey Naumov289aff82010-09-06 13:35:58 +0200137 bb_show_usage();
138
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100139 bdcmd = find_cmd(*argv);
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100140 /* setrw translates to BLKROSET(0), most other ioctls don't care... */
141 /* ...setro will do BLKROSET(1) */
142 u64 = (bdcmd == CMD_SETRO);
Denys Vlasenko46d315a2021-06-16 17:00:56 +0200143 if (bdcmd == CMD_SETBSZ || bdcmd == CMD_SETRA) {
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100144 /* ...setbsz is BLKBSZSET(bytes) */
Denys Vlasenko46d315a2021-06-16 17:00:56 +0200145 /* ...setra is BLKRASET(512 bytes) */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200146 u64 = xatoi_positive(*++argv);
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100147 }
Sergey Naumov289aff82010-09-06 13:35:58 +0200148
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100149 argv++;
150 if (!argv[0] || argv[1])
Sergey Naumov289aff82010-09-06 13:35:58 +0200151 bb_show_usage();
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100152 fd = xopen(argv[0], O_RDONLY);
Sergey Naumov289aff82010-09-06 13:35:58 +0200153
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200154 ioctl_val_on_stack.u64 = u64;
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100155 flags = bdcmd_flags[bdcmd];
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200156#if BB_BIG_ENDIAN
157 /* Store data properly wrt data size.
158 * (1) It's no-op for little-endian.
Denys Vlasenko46d315a2021-06-16 17:00:56 +0200159 * (2) it's no-op for 0 and -1.
160 * --setro uses arg != 0 and != -1, and it is ARG_INT
161 * --setbsz USER_VAL is also ARG_INT
162 * --setra USER_VAL is ARG_ULONG, but it is passed by value,
163 * not reference (see below in ioctl call).
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200164 * Thus, we don't need to handle ARG_ULONG.
165 */
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100166 switch (flags & ARG_MASK) {
Sergey Naumov289aff82010-09-06 13:35:58 +0200167 case ARG_INT:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200168 ioctl_val_on_stack.i = (int)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200169 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200170# if 0 /* unused */
Sergey Naumov289aff82010-09-06 13:35:58 +0200171 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200172 ioctl_val_on_stack.lu = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200173 break;
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200174# endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200175 }
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200176#endif
Sergey Naumov289aff82010-09-06 13:35:58 +0200177
Denys Vlasenko46d315a2021-06-16 17:00:56 +0200178 if (ioctl(fd, bdcmd_ioctl[bdcmd],
179 bdcmd == CMD_SETRA
180 ? (void*)(uintptr_t)u64 /* BLKRASET passes _value_, not pointer to it */
181 : &ioctl_val_on_stack.u64
182 ) == -1)
Sergey Naumov289aff82010-09-06 13:35:58 +0200183 bb_simple_perror_msg_and_die(*argv);
184
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200185 /* Fetch it into register(s) */
186 u64 = ioctl_val_on_stack.u64;
187
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100188 if (flags & FL_SCALE512)
Dan Fandrichf303bdd2011-02-20 04:15:43 +0100189 u64 >>= 9;
190
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200191 /* Zero- or one-extend the value if needed, then print */
Denys Vlasenko35082fc2019-03-30 20:07:21 +0100192 switch (flags & (ARG_MASK+FL_NORESULT)) {
Sergey Naumov289aff82010-09-06 13:35:58 +0200193 case ARG_INT:
194 /* Smaller code when we use long long
195 * (gcc tail-merges printf call)
196 */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200197 printf("%lld\n", (long long)(int)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200198 break;
199 case ARG_ULONG:
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200200 u64 = (unsigned long)u64;
Sergey Naumov289aff82010-09-06 13:35:58 +0200201 /* FALLTHROUGH */
Denys Vlasenko571c5ab2010-09-06 17:37:52 +0200202 case ARG_U64:
203 printf("%llu\n", (unsigned long long)u64);
Sergey Naumov289aff82010-09-06 13:35:58 +0200204 break;
205 }
206
207 if (ENABLE_FEATURE_CLEAN_UP)
208 close(fd);
209 return EXIT_SUCCESS;
210}