blockdev.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  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. //applet:IF_BLOCKDEV(APPLET(blockdev, BB_DIR_SBIN, BB_SUID_DROP))
  9. //kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o
  10. //config:config BLOCKDEV
  11. //config: bool "blockdev"
  12. //config: default y
  13. //config: help
  14. //config: Performs some ioctls with block devices.
  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. #include "libbb.h"
  30. #include <linux/fs.h>
  31. enum {
  32. ARG_NONE = 0,
  33. ARG_INT = 1,
  34. ARG_ULONG = 2,
  35. /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */
  36. ARG_U64 = 3,
  37. ARG_MASK = 3,
  38. FL_USRARG = 4, /* argument is provided by user */
  39. FL_NORESULT = 8,
  40. FL_SCALE512 = 16,
  41. };
  42. struct bdc {
  43. uint32_t ioc; /* ioctl code */
  44. const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
  45. uint8_t flags;
  46. int8_t argval; /* default argument value */
  47. };
  48. static const struct bdc bdcommands[] = {
  49. {
  50. .ioc = BLKROSET,
  51. .name = "setro",
  52. .flags = ARG_INT + FL_NORESULT,
  53. .argval = 1,
  54. },{
  55. .ioc = BLKROSET,
  56. .name = "setrw",
  57. .flags = ARG_INT + FL_NORESULT,
  58. .argval = 0,
  59. },{
  60. .ioc = BLKROGET,
  61. .name = "getro",
  62. .flags = ARG_INT,
  63. .argval = -1,
  64. },{
  65. .ioc = BLKSSZGET,
  66. .name = "getss",
  67. .flags = ARG_INT,
  68. .argval = -1,
  69. },{
  70. .ioc = BLKBSZGET,
  71. .name = "getbsz",
  72. .flags = ARG_INT,
  73. .argval = -1,
  74. },{
  75. .ioc = BLKBSZSET,
  76. .name = "setbsz",
  77. .flags = ARG_INT + FL_NORESULT + FL_USRARG,
  78. .argval = 0,
  79. },{
  80. .ioc = BLKGETSIZE64,
  81. .name = "getsz",
  82. .flags = ARG_U64 + FL_SCALE512,
  83. .argval = -1,
  84. },{
  85. .ioc = BLKGETSIZE,
  86. .name = "getsize",
  87. .flags = ARG_ULONG,
  88. .argval = -1,
  89. },{
  90. .ioc = BLKGETSIZE64,
  91. .name = "getsize64",
  92. .flags = ARG_U64,
  93. .argval = -1,
  94. },{
  95. .ioc = BLKFLSBUF,
  96. .name = "flushbufs",
  97. .flags = ARG_NONE + FL_NORESULT,
  98. .argval = 0,
  99. },{
  100. .ioc = BLKRRPART,
  101. .name = "rereadpt",
  102. .flags = ARG_NONE + FL_NORESULT,
  103. .argval = 0,
  104. }
  105. };
  106. static const struct bdc *find_cmd(const char *s)
  107. {
  108. const struct bdc *bdcmd = bdcommands;
  109. if (s[0] == '-' && s[1] == '-') {
  110. s += 2;
  111. do {
  112. if (strcmp(s, bdcmd->name) == 0)
  113. return bdcmd;
  114. bdcmd++;
  115. } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
  116. }
  117. bb_show_usage();
  118. }
  119. int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  120. int blockdev_main(int argc UNUSED_PARAM, char **argv)
  121. {
  122. const struct bdc *bdcmd;
  123. int fd;
  124. uint64_t u64;
  125. union {
  126. int i;
  127. unsigned long lu;
  128. uint64_t u64;
  129. } ioctl_val_on_stack;
  130. argv++;
  131. if (!argv[0] || !argv[1]) /* must have at least 2 args */
  132. bb_show_usage();
  133. bdcmd = find_cmd(*argv);
  134. u64 = (int)bdcmd->argval;
  135. if (bdcmd->flags & FL_USRARG)
  136. u64 = xatoi_positive(*++argv);
  137. argv++;
  138. if (!argv[0] || argv[1])
  139. bb_show_usage();
  140. fd = xopen(argv[0], O_RDONLY);
  141. ioctl_val_on_stack.u64 = u64;
  142. #if BB_BIG_ENDIAN
  143. /* Store data properly wrt data size.
  144. * (1) It's no-op for little-endian.
  145. * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
  146. * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
  147. * Thus, we don't need to handle ARG_ULONG.
  148. */
  149. switch (bdcmd->flags & ARG_MASK) {
  150. case ARG_INT:
  151. ioctl_val_on_stack.i = (int)u64;
  152. break;
  153. # if 0 /* unused */
  154. case ARG_ULONG:
  155. ioctl_val_on_stack.lu = (unsigned long)u64;
  156. break;
  157. # endif
  158. }
  159. #endif
  160. if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
  161. bb_simple_perror_msg_and_die(*argv);
  162. /* Fetch it into register(s) */
  163. u64 = ioctl_val_on_stack.u64;
  164. if (bdcmd->flags & FL_SCALE512)
  165. u64 >>= 9;
  166. /* Zero- or one-extend the value if needed, then print */
  167. switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
  168. case ARG_INT:
  169. /* Smaller code when we use long long
  170. * (gcc tail-merges printf call)
  171. */
  172. printf("%lld\n", (long long)(int)u64);
  173. break;
  174. case ARG_ULONG:
  175. u64 = (unsigned long)u64;
  176. /* FALLTHROUGH */
  177. case ARG_U64:
  178. printf("%llu\n", (unsigned long long)u64);
  179. break;
  180. }
  181. if (ENABLE_FEATURE_CLEAN_UP)
  182. close(fd);
  183. return EXIT_SUCCESS;
  184. }