dd.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * BURG - Brand-new Universal loadeR from GRUB
  3. * Copyright 2009 Bean Lee - All Rights Reserved
  4. *
  5. * BURG is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * BURG is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with BURG. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <grub/dl.h>
  19. #include <grub/mm.h>
  20. #include <grub/file.h>
  21. #include <grub/extcmd.h>
  22. #include <grub/i18n.h>
  23. static const struct grub_arg_option options[] =
  24. {
  25. {"if", 'i', 0, N_("Specify input file."), "FILE", ARG_TYPE_STRING},
  26. {"str", 's', 0, N_("Specify input string."), "STRING", ARG_TYPE_STRING},
  27. {"hex", 'x', 0, N_("Specify input hex string."), "HEX", ARG_TYPE_STRING},
  28. {"of", 'o', 0, N_("Specify output file."), "FILE", ARG_TYPE_STRING},
  29. {"bs", 'b', 0, N_("Specify block size."), "BYTES", ARG_TYPE_INT},
  30. {"count", 'c', 0, N_("Number of blocks to copy."), "BLOCKS", ARG_TYPE_INT},
  31. {"skip", 0x100, 0, N_("Skip N blocks at input."), "BLOCKS", ARG_TYPE_INT},
  32. {"seek", 0x101, 0, N_("Skip N blocks at output."), "BLOCKS", ARG_TYPE_INT},
  33. {"verify", 'v', 0, N_("Skip N blocks at output."), 0, 0},
  34. {0, 0, 0, 0, 0, 0}
  35. };
  36. enum options
  37. {
  38. DD_IF,
  39. DD_STR,
  40. DD_HEX,
  41. DD_OF,
  42. DD_BS,
  43. DD_COUNT,
  44. DD_SKIP,
  45. DD_SEEK,
  46. DD_VERIFY,
  47. };
  48. static grub_err_t
  49. grub_cmd_dd (grub_extcmd_t cmd, int argc __attribute__ ((unused)),
  50. char **args __attribute__ ((unused)))
  51. {
  52. struct grub_arg_list *state = cmd->state;
  53. char *input = 0;
  54. char *output = 0;
  55. char *str = 0;
  56. char *hexstr = 0;
  57. grub_size_t bs = 1;
  58. int copy_bs = 512;
  59. grub_off_t skip = 0;
  60. grub_off_t seek = 0;
  61. grub_off_t in_size = 0;
  62. int count = -1;
  63. grub_file_t in;
  64. grub_file_t out;
  65. char *buf = 0;
  66. char *buf2 = 0;
  67. int verify = (state[DD_VERIFY].set);
  68. if (state[DD_IF].set)
  69. input = state[DD_IF].arg;
  70. if (state[DD_STR].set)
  71. {
  72. str = state[DD_STR].arg;
  73. in_size = grub_strlen (str);
  74. }
  75. if (state[DD_HEX].set)
  76. {
  77. int i, size;
  78. str = state[DD_HEX].arg;
  79. size = grub_strlen (str) / 2;
  80. if (size == 0)
  81. return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid hex string");
  82. hexstr = grub_zalloc (size);
  83. if (! hexstr)
  84. return grub_errno;
  85. for (i = 0; i < size * 2; i++)
  86. {
  87. int c;
  88. if ((str[i] >= '0') && (str[i] <= '9'))
  89. c = str[i] - '0';
  90. else if ((str[i] >= 'A') && (str[i] <= 'F'))
  91. c = str[i] - 'A' + 10;
  92. else if ((str[i] >= 'a') && (str[i] <= 'f'))
  93. c = str[i] - 'a' + 10;
  94. else
  95. {
  96. grub_free (hexstr);
  97. return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid hex string");
  98. }
  99. if ((i & 1) == 0)
  100. c <<= 4;
  101. hexstr[i >> 1] |= c;
  102. }
  103. str = hexstr;
  104. in_size = size;
  105. }
  106. if (state[DD_OF].set)
  107. output = state[DD_OF].arg;
  108. if (((! input) && (! str)) || (! output))
  109. return grub_error (GRUB_ERR_BAD_ARGUMENT, "no input or output file");
  110. if (state[DD_BS].set)
  111. {
  112. bs = grub_strtoul (state[DD_BS].arg, 0, 0);
  113. if (bs == 0)
  114. return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid block size");
  115. }
  116. if (state[DD_COUNT].set)
  117. {
  118. count = grub_strtoul (state[DD_COUNT].arg, 0, 0);
  119. if (count == 0)
  120. return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid count");
  121. }
  122. if (state[DD_SKIP].set)
  123. skip = grub_strtoull (state[DD_SKIP].arg, 0, 0);
  124. if (state[DD_SEEK].set)
  125. seek = grub_strtoull (state[DD_SEEK].arg, 0, 0);
  126. count *= bs;
  127. skip *= bs;
  128. seek *= bs;
  129. if (input)
  130. {
  131. in = grub_file_open (input);
  132. if (! in)
  133. return grub_errno;
  134. in_size = in->size;
  135. in->flags = 1;
  136. }
  137. else
  138. {
  139. in = 0;
  140. }
  141. out = grub_file_open (output);
  142. if (! out)
  143. goto quit;
  144. if (! verify)
  145. grub_blocklist_convert (out);
  146. if ((skip >= in->size) || (seek >= out->size))
  147. {
  148. if (verify)
  149. goto verify_fail;
  150. }
  151. if (in)
  152. in->offset = skip;
  153. else
  154. str += skip;
  155. out->offset = seek;
  156. if (count < 0)
  157. count = in_size - skip;
  158. if (skip + count > in_size)
  159. {
  160. if (verify)
  161. goto verify_fail;
  162. count = in_size - skip;
  163. }
  164. if (copy_bs < (int) bs)
  165. copy_bs = bs;
  166. buf = grub_malloc (copy_bs);
  167. if (! buf)
  168. goto quit;
  169. if (verify)
  170. {
  171. buf2 = grub_malloc (copy_bs);
  172. if (! buf2)
  173. goto quit;
  174. }
  175. while (count > 0)
  176. {
  177. int s1, s2;
  178. s1 = (copy_bs > count) ? count : copy_bs;
  179. if (in)
  180. {
  181. s1 = grub_file_read (in, buf, s1);
  182. if (grub_errno)
  183. break;
  184. if (s1 == -1)
  185. {
  186. grub_error (GRUB_ERR_BAD_ARGUMENT, "read fails");
  187. break;
  188. }
  189. }
  190. else
  191. {
  192. grub_memcpy (buf, str, s1);
  193. str += s1;
  194. }
  195. if (verify)
  196. {
  197. s2 = grub_file_read (out, buf2, s1);
  198. if ((s2 != s1) || (grub_memcmp (buf, buf2, s1)))
  199. goto verify_fail;
  200. }
  201. else
  202. {
  203. s2 = grub_blocklist_write (out, buf, s1);
  204. out->offset += s2;
  205. }
  206. if (grub_errno)
  207. break;
  208. if (s2 == -1)
  209. {
  210. grub_error (GRUB_ERR_BAD_ARGUMENT, "write fails");
  211. break;
  212. }
  213. if (s1 != s2)
  214. break;
  215. count -= s1;
  216. }
  217. quit:
  218. grub_free (buf);
  219. grub_free (buf2);
  220. grub_free (hexstr);
  221. if (out)
  222. grub_file_close (out);
  223. if (in)
  224. grub_file_close (in);
  225. return grub_errno;
  226. verify_fail:
  227. grub_error (GRUB_ERR_BAD_ARGUMENT, "verify fails");
  228. goto quit;
  229. }
  230. static grub_extcmd_t cmd;
  231. GRUB_MOD_INIT(dd)
  232. {
  233. cmd =
  234. grub_register_extcmd ("dd", grub_cmd_dd,
  235. GRUB_COMMAND_FLAG_BOTH,
  236. N_("[OPTIONS]"),
  237. N_("Copy data."),
  238. options);
  239. }
  240. GRUB_MOD_FINI(dd)
  241. {
  242. grub_unregister_extcmd (cmd);
  243. }