blockdev.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  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: "Options:"
  19. //usage: "\n --setro Set ro"
  20. //usage: "\n --setrw Set rw"
  21. //usage: "\n --getro Get ro"
  22. //usage: "\n --getss Get sector size"
  23. //usage: "\n --getbsz Get block size"
  24. //usage: "\n --setbsz BYTES Set block size"
  25. //usage: "\n --getsize Get device size in 512-byte sectors"
  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. };
  41. struct bdc {
  42. uint32_t ioc; /* ioctl code */
  43. const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */
  44. uint8_t flags;
  45. int8_t argval; /* default argument value */
  46. };
  47. static const struct bdc bdcommands[] = {
  48. {
  49. .ioc = BLKROSET,
  50. .name = "setro",
  51. .flags = ARG_INT + FL_NORESULT,
  52. .argval = 1,
  53. },{
  54. .ioc = BLKROSET,
  55. .name = "setrw",
  56. .flags = ARG_INT + FL_NORESULT,
  57. .argval = 0,
  58. },{
  59. .ioc = BLKROGET,
  60. .name = "getro",
  61. .flags = ARG_INT,
  62. .argval = -1,
  63. },{
  64. .ioc = BLKSSZGET,
  65. .name = "getss",
  66. .flags = ARG_INT,
  67. .argval = -1,
  68. },{
  69. .ioc = BLKBSZGET,
  70. .name = "getbsz",
  71. .flags = ARG_INT,
  72. .argval = -1,
  73. },{
  74. .ioc = BLKBSZSET,
  75. .name = "setbsz",
  76. .flags = ARG_INT + FL_NORESULT + FL_USRARG,
  77. .argval = 0,
  78. },{
  79. .ioc = BLKGETSIZE,
  80. .name = "getsize",
  81. .flags = ARG_ULONG,
  82. .argval = -1,
  83. },{
  84. .ioc = BLKGETSIZE64,
  85. .name = "getsize64",
  86. .flags = ARG_U64,
  87. .argval = -1,
  88. },{
  89. .ioc = BLKFLSBUF,
  90. .name = "flushbufs",
  91. .flags = ARG_NONE + FL_NORESULT,
  92. .argval = 0,
  93. },{
  94. .ioc = BLKRRPART,
  95. .name = "rereadpt",
  96. .flags = ARG_NONE + FL_NORESULT,
  97. .argval = 0,
  98. }
  99. };
  100. static const struct bdc *find_cmd(const char *s)
  101. {
  102. const struct bdc *bdcmd = bdcommands;
  103. if (s[0] == '-' && s[1] == '-') {
  104. s += 2;
  105. do {
  106. if (strcmp(s, bdcmd->name) == 0)
  107. return bdcmd;
  108. bdcmd++;
  109. } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands));
  110. }
  111. bb_show_usage();
  112. }
  113. int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  114. int blockdev_main(int argc, char **argv)
  115. {
  116. const struct bdc *bdcmd;
  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. if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */
  125. bb_show_usage();
  126. bdcmd = find_cmd(*++argv);
  127. u64 = (int)bdcmd->argval;
  128. if (bdcmd->flags & FL_USRARG)
  129. u64 = xatoi_positive(*++argv);
  130. if (!*++argv || argv[1])
  131. bb_show_usage();
  132. fd = xopen(*argv, O_RDONLY);
  133. ioctl_val_on_stack.u64 = u64;
  134. #if BB_BIG_ENDIAN
  135. /* Store data properly wrt data size.
  136. * (1) It's no-op for little-endian.
  137. * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1,
  138. * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT.
  139. * Thus, we don't need to handle ARG_ULONG.
  140. */
  141. switch (bdcmd->flags & ARG_MASK) {
  142. case ARG_INT:
  143. ioctl_val_on_stack.i = (int)u64;
  144. break;
  145. # if 0 /* unused */
  146. case ARG_ULONG:
  147. ioctl_val_on_stack.lu = (unsigned long)u64;
  148. break;
  149. # endif
  150. }
  151. #endif
  152. if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1)
  153. bb_simple_perror_msg_and_die(*argv);
  154. /* Fetch it into register(s) */
  155. u64 = ioctl_val_on_stack.u64;
  156. /* Zero- or one-extend the value if needed, then print */
  157. switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) {
  158. case ARG_INT:
  159. /* Smaller code when we use long long
  160. * (gcc tail-merges printf call)
  161. */
  162. printf("%lld\n", (long long)(int)u64);
  163. break;
  164. case ARG_ULONG:
  165. u64 = (unsigned long)u64;
  166. /* FALLTHROUGH */
  167. case ARG_U64:
  168. printf("%llu\n", (unsigned long long)u64);
  169. break;
  170. }
  171. if (ENABLE_FEATURE_CLEAN_UP)
  172. close(fd);
  173. return EXIT_SUCCESS;
  174. }