ash: parser: Fix old-style command substitution here-document crash
[oweals/busybox.git] / util-linux / blockdev.c
1 /*
2  * blockdev implementation for busybox
3  *
4  * Copyright (C) 2010 Sergey Naumov <sknaumov@gmail.com>
5  *
6  * Licensed under GPLv2, see file LICENSE in this source tree.
7  */
8 //config:config BLOCKDEV
9 //config:       bool "blockdev (2.3 kb)"
10 //config:       default y
11 //config:       help
12 //config:       Performs some ioctls with block devices.
13
14 //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
15
16 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
17
18 //usage:#define blockdev_trivial_usage
19 //usage:        "OPTION BLOCKDEV"
20 //usage:#define blockdev_full_usage "\n\n"
21 //usage:       "        --setro         Set ro"
22 //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"
27 //usage:     "\n        --getsz         Get device size in 512-byte sectors"
28 /*//usage:     "\n      --getsize       Get device size in sectors (deprecated)"*/
29 //usage:     "\n        --getsize64     Get device size in bytes"
30 //usage:     "\n        --flushbufs     Flush buffers"
31 //usage:     "\n        --rereadpt      Reread partition table"
32 // 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
43
44 #include "libbb.h"
45 #include <linux/fs.h>
46
47 /* Takes less space is separate arrays than one array of struct */
48 static 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 ;
63 static 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 };
76 enum {
77         ARG_NONE   = 0,
78         ARG_INT    = 1,
79         ARG_ULONG  = 2,
80         /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
81         ARG_U64    = 3,
82         ARG_MASK   = 3,
83
84         FL_USRARG   = 4, /* argument is provided by user */
85         FL_NORESULT = 8,
86         FL_SCALE512 = 16,
87 };
88 static 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
100 };
101
102 static unsigned find_cmd(const char *s)
103 {
104         if (s[0] == '-' && s[1] == '-') {
105                 int n = index_in_strings(bdcmd_names, s + 2);
106                 if (n >= 0)
107                         return n;
108         }
109         bb_show_usage();
110 }
111
112 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113 int blockdev_main(int argc UNUSED_PARAM, char **argv)
114 {
115         unsigned bdcmd;
116         unsigned flags;
117         int fd;
118         uint64_t u64;
119         union {
120                 int i;
121                 unsigned long lu;
122                 uint64_t u64;
123         } ioctl_val_on_stack;
124
125         argv++;
126         if (!argv[0] || !argv[1]) /* must have at least 2 args */
127                 bb_show_usage();
128
129         bdcmd = find_cmd(*argv);
130         /* 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) */
135                 u64 = xatoi_positive(*++argv);
136         }
137
138         argv++;
139         if (!argv[0] || argv[1])
140                 bb_show_usage();
141         fd = xopen(argv[0], O_RDONLY);
142
143         ioctl_val_on_stack.u64 = u64;
144         flags = bdcmd_flags[bdcmd];
145 #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          */
152         switch (flags & ARG_MASK) {
153         case ARG_INT:
154                 ioctl_val_on_stack.i = (int)u64;
155                 break;
156 # if 0 /* unused */
157         case ARG_ULONG:
158                 ioctl_val_on_stack.lu = (unsigned long)u64;
159                 break;
160 # endif
161         }
162 #endif
163
164         if (ioctl(fd, bdcmd_ioctl[bdcmd], &ioctl_val_on_stack.u64) == -1)
165                 bb_simple_perror_msg_and_die(*argv);
166
167         /* Fetch it into register(s) */
168         u64 = ioctl_val_on_stack.u64;
169
170         if (flags & FL_SCALE512)
171                 u64 >>= 9;
172
173         /* Zero- or one-extend the value if needed, then print */
174         switch (flags & (ARG_MASK+FL_NORESULT)) {
175         case ARG_INT:
176                 /* Smaller code when we use long long
177                  * (gcc tail-merges printf call)
178                  */
179                 printf("%lld\n", (long long)(int)u64);
180                 break;
181         case ARG_ULONG:
182                 u64 = (unsigned long)u64;
183                 /* FALLTHROUGH */
184         case ARG_U64:
185                 printf("%llu\n", (unsigned long long)u64);
186                 break;
187         }
188
189         if (ENABLE_FEATURE_CLEAN_UP)
190                 close(fd);
191         return EXIT_SUCCESS;
192 }