grub-mkstandalone.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
  3. *
  4. * GRUB is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * GRUB is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <config.h>
  18. #include <grub/util/install.h>
  19. #include <grub/util/misc.h>
  20. #include <grub/emu/config.h>
  21. #include <string.h>
  22. #pragma GCC diagnostic ignored "-Wmissing-prototypes"
  23. #pragma GCC diagnostic ignored "-Wmissing-declarations"
  24. #include <argp.h>
  25. #pragma GCC diagnostic error "-Wmissing-prototypes"
  26. #pragma GCC diagnostic error "-Wmissing-declarations"
  27. static char *output_image;
  28. static char **files;
  29. static int nfiles;
  30. const struct grub_install_image_target_desc *format;
  31. static FILE *memdisk;
  32. enum
  33. {
  34. OPTION_OUTPUT = 'o',
  35. OPTION_FORMAT = 'O'
  36. };
  37. static struct argp_option options[] = {
  38. GRUB_INSTALL_OPTIONS,
  39. {"output", 'o', N_("FILE"),
  40. 0, N_("save output in FILE [required]"), 2},
  41. {"format", 'O', N_("FILE"), 0, 0, 2},
  42. {"compression", 'C', "xz|none|auto", OPTION_HIDDEN, 0, 2},
  43. {0, 0, 0, 0, 0, 0}
  44. };
  45. static char *
  46. help_filter (int key, const char *text, void *input __attribute__ ((unused)))
  47. {
  48. switch (key)
  49. {
  50. case 'O':
  51. {
  52. char *formats = grub_install_get_image_targets_string (), *ret;
  53. ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
  54. _("available formats:"), formats);
  55. free (formats);
  56. return ret;
  57. }
  58. default:
  59. return grub_install_help_filter (key, text, input);
  60. }
  61. }
  62. static error_t
  63. argp_parser (int key, char *arg, struct argp_state *state)
  64. {
  65. if (key == 'C')
  66. key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS;
  67. if (grub_install_parse (key, arg))
  68. return 0;
  69. switch (key)
  70. {
  71. case 'o':
  72. if (output_image)
  73. free (output_image);
  74. output_image = xstrdup (arg);
  75. break;
  76. case 'O':
  77. {
  78. format = grub_install_get_image_target (arg);
  79. if (!format)
  80. {
  81. printf (_("unknown target format %s\n"), arg);
  82. argp_usage (state);
  83. exit (1);
  84. }
  85. break;
  86. }
  87. case ARGP_KEY_ARG:
  88. files[nfiles++] = xstrdup (arg);
  89. break;
  90. default:
  91. return ARGP_ERR_UNKNOWN;
  92. }
  93. return 0;
  94. }
  95. struct argp argp = {
  96. options, argp_parser, N_("[OPTION] SOURCE..."),
  97. N_("Generate a standalone image (containing all modules) in the selected format")"\v"N_("Graft point syntax (E.g. /boot/grub/grub.cfg=./grub.cfg) is accepted"),
  98. NULL, help_filter, NULL
  99. };
  100. /* tar support */
  101. #define MAGIC "ustar"
  102. struct head
  103. {
  104. char name[100];
  105. char mode[8];
  106. char uid[8];
  107. char gid[8];
  108. char size[12];
  109. char mtime[12];
  110. char chksum[8];
  111. char typeflag;
  112. char linkname[100];
  113. char magic[6];
  114. char version[2];
  115. char uname[32];
  116. char gname[32];
  117. char devmajor[8];
  118. char devminor[8];
  119. char prefix[155];
  120. char pad[12];
  121. } GRUB_PACKED;
  122. static void
  123. write_zeros (unsigned rsz)
  124. {
  125. char buf[512];
  126. memset (buf, 0, 512);
  127. fwrite (buf, 1, rsz, memdisk);
  128. }
  129. static void
  130. write_pad (unsigned sz)
  131. {
  132. write_zeros ((~sz + 1) & 511);
  133. }
  134. static void
  135. set_tar_value (char *field, grub_uint32_t val,
  136. unsigned len)
  137. {
  138. unsigned i;
  139. for (i = 0; i < len - 1; i++)
  140. field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7);
  141. }
  142. static void
  143. compute_checksum (struct head *hd)
  144. {
  145. unsigned int chk = 0;
  146. unsigned char *ptr;
  147. memset (hd->chksum, ' ', 8);
  148. for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++)
  149. chk += *ptr;
  150. set_tar_value (hd->chksum, chk, 8);
  151. }
  152. static void
  153. add_tar_file (const char *from,
  154. const char *to)
  155. {
  156. char *tcn;
  157. const char *iptr;
  158. char *optr;
  159. struct head hd;
  160. grub_util_fd_t in;
  161. ssize_t r;
  162. grub_uint32_t mtime = 0;
  163. grub_uint32_t size;
  164. COMPILE_TIME_ASSERT (sizeof (hd) == 512);
  165. if (grub_util_is_special_file (from))
  166. return;
  167. mtime = grub_util_get_mtime (from);
  168. optr = tcn = xmalloc (strlen (to) + 1);
  169. for (iptr = to; *iptr == '/'; iptr++);
  170. for (; *iptr; iptr++)
  171. if (!(iptr[0] == '/' && iptr[1] == '/'))
  172. *optr++ = *iptr;
  173. *optr = '\0';
  174. if (grub_util_is_directory (from))
  175. {
  176. grub_util_fd_dir_t d;
  177. grub_util_fd_dirent_t de;
  178. d = grub_util_fd_opendir (from);
  179. while ((de = grub_util_fd_readdir (d)))
  180. {
  181. char *fp, *tfp;
  182. if (strcmp (de->d_name, ".") == 0)
  183. continue;
  184. if (strcmp (de->d_name, "..") == 0)
  185. continue;
  186. fp = grub_util_path_concat (2, from, de->d_name);
  187. tfp = xasprintf ("%s/%s", to, de->d_name);
  188. add_tar_file (fp, tfp);
  189. free (fp);
  190. }
  191. grub_util_fd_closedir (d);
  192. free (tcn);
  193. return;
  194. }
  195. if (optr - tcn > 99)
  196. {
  197. memset (&hd, 0, sizeof (hd));
  198. memcpy (hd.name, tcn, 99);
  199. memcpy (hd.mode, "0000600", 7);
  200. memcpy (hd.uid, "0001750", 7);
  201. memcpy (hd.gid, "0001750", 7);
  202. set_tar_value (hd.size, optr - tcn, 12);
  203. set_tar_value (hd.mtime, mtime, 12);
  204. hd.typeflag = 'L';
  205. memcpy (hd.magic, MAGIC, sizeof (hd.magic));
  206. memcpy (hd.uname, "grub", 4);
  207. memcpy (hd.gname, "grub", 4);
  208. compute_checksum (&hd);
  209. fwrite (&hd, 1, sizeof (hd), memdisk);
  210. fwrite (tcn, 1, optr - tcn, memdisk);
  211. write_pad (optr - tcn);
  212. }
  213. in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY);
  214. if (!GRUB_UTIL_FD_IS_VALID (in))
  215. grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ());
  216. if (!grub_install_copy_buffer)
  217. grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
  218. size = grub_util_get_fd_size (in, from, NULL);
  219. memset (&hd, 0, sizeof (hd));
  220. memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99);
  221. memcpy (hd.mode, "0000600", 7);
  222. memcpy (hd.uid, "0001750", 7);
  223. memcpy (hd.gid, "0001750", 7);
  224. set_tar_value (hd.size, size, 12);
  225. set_tar_value (hd.mtime, mtime, 12);
  226. hd.typeflag = '0';
  227. memcpy (hd.magic, MAGIC, sizeof (hd.magic));
  228. memcpy (hd.uname, "grub", 4);
  229. memcpy (hd.gname, "grub", 4);
  230. compute_checksum (&hd);
  231. fwrite (&hd, 1, sizeof (hd), memdisk);
  232. while (1)
  233. {
  234. r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
  235. if (r <= 0)
  236. break;
  237. fwrite (grub_install_copy_buffer, 1, r, memdisk);
  238. }
  239. grub_util_fd_close (in);
  240. write_pad (size);
  241. free (tcn);
  242. }
  243. int
  244. main (int argc, char *argv[])
  245. {
  246. const char *pkglibdir;
  247. int i;
  248. grub_util_host_init (&argc, &argv);
  249. grub_util_disable_fd_syncs ();
  250. files = xmalloc ((argc + 1) * sizeof (files[0]));
  251. argp_parse (&argp, argc, argv, 0, 0, 0);
  252. pkglibdir = grub_util_get_pkglibdir ();
  253. if (!output_image)
  254. grub_util_error ("%s", _("output file must be specified"));
  255. if (!format)
  256. grub_util_error ("%s", _("Target format not specified (use the -O option)."));
  257. if (!grub_install_source_directory)
  258. grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format));
  259. enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory);
  260. char *memdisk_dir = grub_util_make_temporary_dir ();
  261. char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub");
  262. grub_install_copy_files (grub_install_source_directory,
  263. boot_grub, plat);
  264. char *memdisk_img = grub_util_make_temporary_file ();
  265. memdisk = grub_util_fopen (memdisk_img, "wb");
  266. add_tar_file (memdisk_dir, "");
  267. for (i = 0; i < nfiles; i++)
  268. {
  269. char *eq = grub_strchr (files[i], '=');
  270. char *from, *to;
  271. if (!eq)
  272. {
  273. from = files[i];
  274. to = files[i];
  275. }
  276. else
  277. {
  278. *eq = '\0';
  279. to = files[i];
  280. from = eq + 1;
  281. }
  282. while (*to == '/')
  283. to++;
  284. add_tar_file (from, to);
  285. }
  286. write_zeros (512);
  287. fclose (memdisk);
  288. grub_util_unlink_recursive (memdisk_dir);
  289. grub_install_push_module ("memdisk");
  290. grub_install_push_module ("tar");
  291. grub_install_make_image_wrap (grub_install_source_directory,
  292. "(memdisk)/boot/grub", output_image,
  293. memdisk_img, NULL,
  294. grub_util_get_target_name (format), 0);
  295. grub_util_unlink (memdisk_img);
  296. return 0;
  297. }