blockdev.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  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. /*//usage: "\n --getsize Get device size in sectors (deprecated)"*/
  26. //usage: "\n --getsize64 Get device size in bytes"
  27. //usage: "\n --flushbufs Flush buffers"
  28. //usage: "\n --rereadpt Reread partition table"
  29. // util-linux 2.31 also has:
  30. // --getdiscardzeroes BLKDISCARDZEROES Get discard zeroes support status
  31. // --getpbsz BLKPBSZGET Get physical block (sector) size
  32. // --getiomin BLKIOMIN Get minimum I/O size
  33. // --getioopt BLKIOOPT Get optimal I/O size
  34. // --getalignoff BLKALIGNOFF Get alignment offset in bytes
  35. // --getmaxsect BLKSECTGET Get max sectors per request
  36. // --setra SECTORS BLKRASET Set readahead
  37. // --getra BLKRAGET Get readahead
  38. // --setfra SECTORS BLKFRASET Set filesystem readahead
  39. // --getfra BLKFRAGET Get filesystem readahead
  40. #include "libbb.h"
  41. #include <linux/fs.h>
  42. /* Takes less space is separate arrays than one array of struct */
  43. static const char bdcmd_names[] ALIGN1 =
  44. "setro" "\0"
  45. #define CMD_SETRO 0
  46. "setrw" "\0"
  47. "getro" "\0"
  48. "getss" "\0"
  49. "getbsz" "\0"
  50. "setbsz" "\0"
  51. #define CMD_SETBSZ 5
  52. "getsz" "\0"
  53. "getsize" "\0"
  54. "getsize64" "\0"
  55. "flushbufs" "\0"
  56. "rereadpt" "\0"
  57. ;
  58. static const uint32_t bdcmd_ioctl[] = {
  59. BLKROSET, //setro
  60. BLKROSET, //setrw
  61. BLKROGET, //getro
  62. BLKSSZGET, //getss
  63. BLKBSZGET, //getbsz
  64. BLKBSZSET, //setbsz
  65. BLKGETSIZE64, //getsz
  66. BLKGETSIZE, //getsize
  67. BLKGETSIZE64, //getsize64
  68. BLKFLSBUF, //flushbufs
  69. BLKRRPART, //rereadpt
  70. };
  71. enum {
  72. ARG_NONE = 0,
  73. ARG_INT = 1,
  74. ARG_ULONG = 2,
  75. /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
  76. ARG_U64 = 3,
  77. ARG_MASK = 3,
  78. FL_USRARG = 4, /* argument is provided by user */
  79. FL_NORESULT = 8,
  80. FL_SCALE512 = 16,
  81. };
  82. static const uint8_t bdcmd_flags[] ALIGN1 = {
  83. ARG_INT + FL_NORESULT, //setro
  84. ARG_INT + FL_NORESULT, //setrw
  85. ARG_INT, //getro
  86. ARG_INT, //getss
  87. ARG_INT, //getbsz
  88. ARG_INT + FL_NORESULT + FL_USRARG, //setbsz
  89. ARG_U64 + FL_SCALE512, //getsz
  90. ARG_ULONG, //getsize
  91. ARG_U64, //getsize64
  92. ARG_NONE + FL_NORESULT, //flushbufs
  93. ARG_NONE + FL_NORESULT, //rereadpt
  94. };
  95. static unsigned find_cmd(const char *s)
  96. {
  97. if (s[0] == '-' && s[1] == '-') {
  98. int n = index_in_strings(bdcmd_names, s + 2);
  99. if (n >= 0)
  100. return n;
  101. }
  102. bb_show_usage();
  103. }
  104. int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  105. int blockdev_main(int argc UNUSED_PARAM, char **argv)
  106. {
  107. unsigned bdcmd;
  108. unsigned flags;
  109. int fd;
  110. uint64_t u64;
  111. union {
  112. int i;
  113. unsigned long lu;
  114. uint64_t u64;
  115. } ioctl_val_on_stack;
  116. argv++;
  117. if (!argv[0] || !argv[1]) /* must have at least 2 args */
  118. bb_show_usage();
  119. bdcmd = find_cmd(*argv);
  120. /* setrw translates to BLKROSET(0), most other ioctls don't care... */
  121. /* ...setro will do BLKROSET(1) */
  122. u64 = (bdcmd == CMD_SETRO);
  123. if (bdcmd == CMD_SETBSZ) {
  124. /* ...setbsz is BLKBSZSET(bytes) */
  125. u64 = xatoi_positive(*++argv);
  126. }
  127. argv++;
  128. if (!argv[0] || argv[1])
  129. bb_show_usage();
  130. fd = xopen(argv[0], O_RDONLY);
  131. ioctl_val_on_stack.u64 = u64;
  132. flags = bdcmd_flags[bdcmd];
  133. #if BB_BIG_ENDIAN
  134. /* Store data properly wrt data size.
  135. * (1) It's no-op for little-endian.
  136. * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
  137. * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
  138. * Thus, we don't need to handle ARG_ULONG.
  139. */
  140. switch (flags & ARG_MASK) {
  141. case ARG_INT:
  142. ioctl_val_on_stack.i = (int)u64;
  143. break;
  144. # if 0 /* unused */
  145. case ARG_ULONG:
  146. ioctl_val_on_stack.lu = (unsigned long)u64;
  147. break;
  148. # endif
  149. }
  150. #endif
  151. if (ioctl(fd, bdcmd_ioctl[bdcmd], &ioctl_val_on_stack.u64) == -1)
  152. bb_simple_perror_msg_and_die(*argv);
  153. /* Fetch it into register(s) */
  154. u64 = ioctl_val_on_stack.u64;
  155. if (flags & FL_SCALE512)
  156. u64 >>= 9;
  157. /* Zero- or one-extend the value if needed, then print */
  158. switch (flags & (ARG_MASK+FL_NORESULT)) {
  159. case ARG_INT:
  160. /* Smaller code when we use long long
  161. * (gcc tail-merges printf call)
  162. */
  163. printf("%lld\n", (long long)(int)u64);
  164. break;
  165. case ARG_ULONG:
  166. u64 = (unsigned long)u64;
  167. /* FALLTHROUGH */
  168. case ARG_U64:
  169. printf("%llu\n", (unsigned long long)u64);
  170. break;
  171. }
  172. if (ENABLE_FEATURE_CLEAN_UP)
  173. close(fd);
  174. return EXIT_SUCCESS;
  175. }