blockdev.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. //applet:IF_BLOCKDEV(APPLET_NOEXEC(blockdev, blockdev, BB_DIR_SBIN, BB_SUID_DROP, blockdev))
  14. //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
  15. //usage:#define blockdev_trivial_usage
  16. //usage: "OPTION BLOCKDEV"
  17. //usage:#define blockdev_full_usage "\n\n"
  18. //usage: " --setro Set ro"
  19. //usage: "\n --setrw Set rw"
  20. //usage: "\n --getro Get ro"
  21. //usage: "\n --getss Get sector size"
  22. //usage: "\n --getbsz Get block size"
  23. //usage: "\n --setbsz BYTES Set block size"
  24. //usage: "\n --getsz Get device size in 512-byte sectors"
  25. ///////: "\n --getsize Get device size in sectors (deprecated)"
  26. ///////^^^^^ supported, but not shown in help ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  27. //usage: "\n --getsize64 Get device size in bytes"
  28. //usage: "\n --getra Get readahead in 512-byte sectors"
  29. //usage: "\n --setra SECTORS Set readahead"
  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. #include "libbb.h"
  44. #include <linux/fs.h>
  45. /* Takes less space is separate arrays than one array of struct */
  46. static const char bdcmd_names[] ALIGN1 =
  47. "setro" "\0"
  48. #define CMD_SETRO 0
  49. "setrw" "\0"
  50. "getro" "\0"
  51. "getss" "\0"
  52. "getbsz" "\0"
  53. "setbsz" "\0"
  54. #define CMD_SETBSZ 5
  55. "getsz" "\0"
  56. "getsize" "\0"
  57. "getsize64" "\0"
  58. "getra" "\0"
  59. "setra" "\0"
  60. #define CMD_SETRA 10
  61. "flushbufs" "\0"
  62. "rereadpt" "\0"
  63. ;
  64. static const uint32_t bdcmd_ioctl[] ALIGN4 = {
  65. BLKROSET, //setro
  66. BLKROSET, //setrw
  67. BLKROGET, //getro
  68. BLKSSZGET, //getss
  69. BLKBSZGET, //getbsz
  70. BLKBSZSET, //setbsz
  71. BLKGETSIZE64, //getsz
  72. BLKGETSIZE, //getsize
  73. BLKGETSIZE64, //getsize64
  74. BLKRAGET, //getra
  75. BLKRASET, //setra
  76. BLKFLSBUF, //flushbufs
  77. BLKRRPART, //rereadpt
  78. };
  79. enum {
  80. ARG_NONE = 0,
  81. ARG_INT = 1,
  82. ARG_ULONG = 2,
  83. /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
  84. ARG_U64 = 3,
  85. ARG_MASK = 3,
  86. FL_USRARG = 4, /* argument is provided by user */
  87. FL_NORESULT = 8,
  88. FL_SCALE512 = 16,
  89. };
  90. static const uint8_t bdcmd_flags[] ALIGN1 = {
  91. ARG_INT + FL_NORESULT, //setro
  92. ARG_INT + FL_NORESULT, //setrw
  93. ARG_INT, //getro
  94. ARG_INT, //getss
  95. ARG_INT, //getbsz
  96. ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
  97. ARG_U64 + FL_SCALE512, //getsz
  98. ARG_ULONG, //getsize
  99. ARG_U64, //getsize64
  100. ARG_ULONG, //getra
  101. ARG_ULONG + FL_NORESULT, //setra
  102. ARG_NONE + FL_NORESULT, //flushbufs
  103. ARG_NONE + FL_NORESULT, //rereadpt
  104. };
  105. static unsigned find_cmd(const char *s)
  106. {
  107. if (s[0] == '-' && s[1] == '-') {
  108. int n = index_in_strings(bdcmd_names, s + 2);
  109. if (n >= 0)
  110. return n;
  111. }
  112. bb_show_usage();
  113. }
  114. int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  115. int blockdev_main(int argc UNUSED_PARAM, char **argv)
  116. {
  117. unsigned bdcmd;
  118. unsigned flags;
  119. int fd;
  120. uint64_t u64;
  121. union {
  122. int i;
  123. unsigned long lu;
  124. uint64_t u64;
  125. } ioctl_val_on_stack;
  126. argv++;
  127. if (!argv[0] || !argv[1]) /* must have at least 2 args */
  128. bb_show_usage();
  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 || bdcmd == CMD_SETRA) {
  134. /* ...setbsz is BLKBSZSET(bytes) */
  135. /* ...setra is BLKRASET(512 bytes) */
  136. u64 = xatoi_positive(*++argv);
  137. }
  138. argv++;
  139. if (!argv[0] || argv[1])
  140. bb_show_usage();
  141. fd = xopen(argv[0], O_RDONLY);
  142. ioctl_val_on_stack.u64 = u64;
  143. flags = bdcmd_flags[bdcmd];
  144. #if BB_BIG_ENDIAN
  145. /* Store data properly wrt data size.
  146. * (1) It's no-op for little-endian.
  147. * (2) it's no-op for 0 and -1.
  148. * --setro uses arg != 0 and != -1, and it is ARG_INT
  149. * --setbsz USER_VAL is also ARG_INT
  150. * --setra USER_VAL is ARG_ULONG, but it is passed by value,
  151. * not reference (see below in ioctl call).
  152. * Thus, we don't need to handle ARG_ULONG.
  153. */
  154. switch (flags & ARG_MASK) {
  155. case ARG_INT:
  156. ioctl_val_on_stack.i = (int)u64;
  157. break;
  158. # if 0 /* unused */
  159. case ARG_ULONG:
  160. ioctl_val_on_stack.lu = (unsigned long)u64;
  161. break;
  162. # endif
  163. }
  164. #endif
  165. if (ioctl(fd, bdcmd_ioctl[bdcmd],
  166. bdcmd == CMD_SETRA
  167. ? (void*)(uintptr_t)u64 /* BLKRASET passes _value_, not pointer to it */
  168. : &ioctl_val_on_stack.u64
  169. ) == -1)
  170. bb_simple_perror_msg_and_die(*argv);
  171. /* Fetch it into register(s) */
  172. u64 = ioctl_val_on_stack.u64;
  173. if (flags & FL_SCALE512)
  174. u64 >>= 9;
  175. /* Zero- or one-extend the value if needed, then print */
  176. switch (flags & (ARG_MASK+FL_NORESULT)) {
  177. case ARG_INT:
  178. /* Smaller code when we use long long
  179. * (gcc tail-merges printf call)
  180. */
  181. printf("%lld\n", (long long)(int)u64);
  182. break;
  183. case ARG_ULONG:
  184. u64 = (unsigned long)u64;
  185. /* FALLTHROUGH */
  186. case ARG_U64:
  187. printf("%llu\n", (unsigned long long)u64);
  188. break;
  189. }
  190. if (ENABLE_FEATURE_CLEAN_UP)
  191. close(fd);
  192. return EXIT_SUCCESS;
  193. }