made 3 license strings to follow the usual form ("or later" bit is not changed!)
[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
9 //applet:IF_BLOCKDEV(APPLET(blockdev, _BB_DIR_SBIN, _BB_SUID_DROP))
10
11 //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
12
13 //config:config BLOCKDEV
14 //config:       bool "blockdev"
15 //config:       default y
16 //config:       help
17 //config:         Performs some ioctls with block devices.
18
19 //usage:#define blockdev_trivial_usage
20 //usage:        "OPTION BLOCKDEV"
21 //usage:#define blockdev_full_usage "\n\n"
22 //usage:       "Options:"
23 //usage:     "\n        --setro         Set ro"
24 //usage:     "\n        --setrw         Set rw"
25 //usage:     "\n        --getro         Get ro"
26 //usage:     "\n        --getss         Get sector size"
27 //usage:     "\n        --getbsz        Get block size"
28 //usage:     "\n        --setbsz BYTES  Set block size"
29 //usage:     "\n        --getsize       Get device size in 512-byte sectors"
30 //usage:     "\n        --getsize64     Get device size in bytes"
31 //usage:     "\n        --flushbufs     Flush buffers"
32 //usage:     "\n        --rereadpt      Reread partition table"
33
34
35 #include "libbb.h"
36 #include <linux/fs.h>
37
38 enum {
39         ARG_NONE   = 0,
40         ARG_INT    = 1,
41         ARG_ULONG  = 2,
42         ARG_ULLONG = 3,
43         ARG_MASK   = 3,
44
45         FL_USRARG   = 4, /* argument is provided by user */
46         FL_NORESULT = 8,
47 };
48
49 struct bdc {
50         uint32_t   ioc;                       /* ioctl code */
51         const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
52         uint8_t    flags;
53         int8_t     argval;                    /* default argument value */
54 };
55
56 static const struct bdc bdcommands[] = {
57         {
58                 .ioc = BLKROSET,
59                 .name = "setro",
60                 .flags = ARG_INT + FL_NORESULT,
61                 .argval = 1,
62         },{
63                 .ioc = BLKROSET,
64                 .name = "setrw",
65                 .flags = ARG_INT + FL_NORESULT,
66                 .argval = 0,
67         },{
68                 .ioc = BLKROGET,
69                 .name = "getro",
70                 .flags = ARG_INT,
71                 .argval = -1,
72         },{
73                 .ioc = BLKSSZGET,
74                 .name = "getss",
75                 .flags = ARG_INT,
76                 .argval = -1,
77         },{
78                 .ioc = BLKBSZGET,
79                 .name = "getbsz",
80                 .flags = ARG_INT,
81                 .argval = -1,
82         },{
83                 .ioc = BLKBSZSET,
84                 .name = "setbsz",
85                 .flags = ARG_INT + FL_NORESULT + FL_USRARG,
86                 .argval = 0,
87         },{
88                 .ioc = BLKGETSIZE,
89                 .name = "getsize",
90                 .flags = ARG_ULONG,
91                 .argval = -1,
92         },{
93                 .ioc = BLKGETSIZE64,
94                 .name = "getsize64",
95                 .flags = ARG_ULLONG,
96                 .argval = -1,
97         },{
98                 .ioc = BLKFLSBUF,
99                 .name = "flushbufs",
100                 .flags = ARG_NONE + FL_NORESULT,
101                 .argval = 0,
102         },{
103                 .ioc = BLKRRPART,
104                 .name = "rereadpt",
105                 .flags = ARG_NONE + FL_NORESULT,
106                 .argval = 0,
107         }
108 };
109
110 static const struct bdc *find_cmd(const char *s)
111 {
112         const struct bdc *bdcmd = bdcommands;
113         if (s[0] == '-' && s[1] == '-') {
114                 s += 2;
115                 do {
116                         if (strcmp(s, bdcmd->name) == 0)
117                                 return bdcmd;
118                         bdcmd++;
119                 } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
120         }
121         bb_show_usage();
122 }
123
124 int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
125 int blockdev_main(int argc, char **argv)
126 {
127         const struct bdc *bdcmd;
128         void *ioctl_ptr;
129         int fd;
130         int iarg;
131         unsigned long lu;
132         unsigned long long llu;
133
134         if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */
135                 bb_show_usage();
136
137         bdcmd = find_cmd(*++argv);
138
139         llu = (int)bdcmd->argval;
140         if (bdcmd->flags & FL_USRARG)
141                 llu = xatoi_positive(*++argv);
142         lu = llu;
143         iarg = llu;
144
145         if (!*++argv)
146                 bb_show_usage();
147         fd = xopen(*argv, O_RDONLY);
148
149         ioctl_ptr = NULL;
150         switch (bdcmd->flags & ARG_MASK) {
151         case ARG_INT:
152                 ioctl_ptr =  &iarg;
153                 break;
154         case ARG_ULONG:
155                 ioctl_ptr = &lu;
156                 break;
157         case ARG_ULLONG:
158                 ioctl_ptr = &llu;
159                 break;
160         }
161
162         if (ioctl(fd, bdcmd->ioc, ioctl_ptr) == -1)
163                 bb_simple_perror_msg_and_die(*argv);
164
165         switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
166         case ARG_INT:
167                 /* Smaller code when we use long long
168                  * (gcc tail-merges printf call)
169                  */
170                 printf("%lld\n", (long long)iarg);
171                 break;
172         case ARG_ULONG:
173                 llu = lu;
174                 /* FALLTHROUGH */
175         case ARG_ULLONG:
176                 printf("%llu\n", llu);
177                 break;
178         }
179
180         if (ENABLE_FEATURE_CLEAN_UP)
181                 close(fd);
182         return EXIT_SUCCESS;
183 }