grub-mkstandalone.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. /* use 2015-01-01T00:00:00+0000 as a stock timestamp */
  28. #define STABLE_EMBEDDING_TIMESTAMP 1420070400
  29. static char *output_image;
  30. static char **files;
  31. static int nfiles;
  32. const struct grub_install_image_target_desc *format;
  33. static FILE *memdisk;
  34. enum
  35. {
  36. OPTION_OUTPUT = 'o',
  37. OPTION_FORMAT = 'O'
  38. };
  39. static struct argp_option options[] = {
  40. GRUB_INSTALL_OPTIONS,
  41. {"output", 'o', N_("FILE"),
  42. 0, N_("save output in FILE [required]"), 2},
  43. {"format", 'O', N_("FILE"), 0, 0, 2},
  44. {"compression", 'C', "xz|none|auto", OPTION_HIDDEN, 0, 2},
  45. {0, 0, 0, 0, 0, 0}
  46. };
  47. static char *
  48. help_filter (int key, const char *text, void *input __attribute__ ((unused)))
  49. {
  50. switch (key)
  51. {
  52. case 'O':
  53. {
  54. char *formats = grub_install_get_image_targets_string (), *ret;
  55. ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
  56. _("available formats:"), formats);
  57. free (formats);
  58. return ret;
  59. }
  60. default:
  61. return grub_install_help_filter (key, text, input);
  62. }
  63. }
  64. static error_t
  65. argp_parser (int key, char *arg, struct argp_state *state)
  66. {
  67. if (key == 'C')
  68. key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS;
  69. if (grub_install_parse (key, arg))
  70. return 0;
  71. switch (key)
  72. {
  73. case 'o':
  74. if (output_image)
  75. free (output_image);
  76. output_image = xstrdup (arg);
  77. break;
  78. case 'O':
  79. {
  80. format = grub_install_get_image_target (arg);
  81. if (!format)
  82. {
  83. printf (_("unknown target format %s\n"), arg);
  84. argp_usage (state);
  85. exit (1);
  86. }
  87. break;
  88. }
  89. case ARGP_KEY_ARG:
  90. files[nfiles++] = xstrdup (arg);
  91. break;
  92. default:
  93. return ARGP_ERR_UNKNOWN;
  94. }
  95. return 0;
  96. }
  97. struct argp argp = {
  98. options, argp_parser, N_("[OPTION] SOURCE..."),
  99. 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"),
  100. NULL, help_filter, NULL
  101. };
  102. /* tar support */
  103. #define MAGIC "ustar"
  104. struct head
  105. {
  106. char name[100];
  107. char mode[8];
  108. char uid[8];
  109. char gid[8];
  110. char size[12];
  111. char mtime[12];
  112. char chksum[8];
  113. char typeflag;
  114. char linkname[100];
  115. char magic[6];
  116. char version[2];
  117. char uname[32];
  118. char gname[32];
  119. char devmajor[8];
  120. char devminor[8];
  121. char prefix[155];
  122. char pad[12];
  123. } GRUB_PACKED;
  124. static void
  125. write_zeros (unsigned rsz)
  126. {
  127. char buf[512];
  128. memset (buf, 0, 512);
  129. fwrite (buf, 1, rsz, memdisk);
  130. }
  131. static void
  132. write_pad (unsigned sz)
  133. {
  134. write_zeros ((~sz + 1) & 511);
  135. }
  136. static void
  137. set_tar_value (char *field, grub_uint32_t val,
  138. unsigned len)
  139. {
  140. unsigned i;
  141. for (i = 0; i < len - 1; i++)
  142. field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7);
  143. }
  144. static void
  145. compute_checksum (struct head *hd)
  146. {
  147. unsigned int chk = 0;
  148. unsigned char *ptr;
  149. memset (hd->chksum, ' ', 8);
  150. for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++)
  151. chk += *ptr;
  152. set_tar_value (hd->chksum, chk, 8);
  153. }
  154. static void
  155. add_tar_file (const char *from,
  156. const char *to)
  157. {
  158. char *tcn;
  159. const char *iptr;
  160. char *optr;
  161. struct head hd;
  162. grub_util_fd_t in;
  163. ssize_t r;
  164. grub_uint32_t size;
  165. COMPILE_TIME_ASSERT (sizeof (hd) == 512);
  166. if (grub_util_is_special_file (from))
  167. return;
  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. char **from_files;
  179. grub_size_t alloc = 8, used = 0;
  180. grub_size_t i;
  181. d = grub_util_fd_opendir (from);
  182. from_files = xmalloc (alloc * sizeof (*from_files));
  183. while ((de = grub_util_fd_readdir (d)))
  184. {
  185. if (strcmp (de->d_name, ".") == 0)
  186. continue;
  187. if (strcmp (de->d_name, "..") == 0)
  188. continue;
  189. if (alloc <= used)
  190. {
  191. alloc <<= 1;
  192. from_files = xrealloc (from_files, alloc * sizeof (*from_files));
  193. }
  194. from_files[used++] = xstrdup (de->d_name);
  195. }
  196. qsort (from_files, used, sizeof (*from_files), grub_qsort_strcmp);
  197. for (i = 0; i < used; i++)
  198. {
  199. char *fp, *tfp;
  200. fp = grub_util_path_concat (2, from, from_files[i]);
  201. tfp = xasprintf ("%s/%s", to, from_files[i]);
  202. add_tar_file (fp, tfp);
  203. free (tfp);
  204. free (fp);
  205. free (from_files[i]);
  206. }
  207. grub_util_fd_closedir (d);
  208. free (from_files);
  209. free (tcn);
  210. return;
  211. }
  212. if (optr - tcn > 99)
  213. {
  214. memset (&hd, 0, sizeof (hd));
  215. memcpy (hd.name, tcn, 99);
  216. memcpy (hd.mode, "0000600", 7);
  217. memcpy (hd.uid, "0001750", 7);
  218. memcpy (hd.gid, "0001750", 7);
  219. set_tar_value (hd.size, optr - tcn, 12);
  220. set_tar_value (hd.mtime, STABLE_EMBEDDING_TIMESTAMP, 12);
  221. hd.typeflag = 'L';
  222. memcpy (hd.magic, MAGIC, sizeof (hd.magic));
  223. memcpy (hd.uname, "grub", 4);
  224. memcpy (hd.gname, "grub", 4);
  225. compute_checksum (&hd);
  226. fwrite (&hd, 1, sizeof (hd), memdisk);
  227. fwrite (tcn, 1, optr - tcn, memdisk);
  228. write_pad (optr - tcn);
  229. }
  230. in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY);
  231. if (!GRUB_UTIL_FD_IS_VALID (in))
  232. grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ());
  233. if (!grub_install_copy_buffer)
  234. grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
  235. size = grub_util_get_fd_size (in, from, NULL);
  236. memset (&hd, 0, sizeof (hd));
  237. memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99);
  238. memcpy (hd.mode, "0000600", 7);
  239. memcpy (hd.uid, "0001750", 7);
  240. memcpy (hd.gid, "0001750", 7);
  241. set_tar_value (hd.size, size, 12);
  242. set_tar_value (hd.mtime, STABLE_EMBEDDING_TIMESTAMP, 12);
  243. hd.typeflag = '0';
  244. memcpy (hd.magic, MAGIC, sizeof (hd.magic));
  245. memcpy (hd.uname, "grub", 4);
  246. memcpy (hd.gname, "grub", 4);
  247. compute_checksum (&hd);
  248. fwrite (&hd, 1, sizeof (hd), memdisk);
  249. while (1)
  250. {
  251. r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
  252. if (r <= 0)
  253. break;
  254. fwrite (grub_install_copy_buffer, 1, r, memdisk);
  255. }
  256. grub_util_fd_close (in);
  257. write_pad (size);
  258. free (tcn);
  259. }
  260. int
  261. main (int argc, char *argv[])
  262. {
  263. const char *pkglibdir;
  264. int i;
  265. grub_util_host_init (&argc, &argv);
  266. grub_util_disable_fd_syncs ();
  267. files = xcalloc (argc + 1, sizeof (files[0]));
  268. argp_parse (&argp, argc, argv, 0, 0, 0);
  269. pkglibdir = grub_util_get_pkglibdir ();
  270. if (!output_image)
  271. grub_util_error ("%s", _("output file must be specified"));
  272. if (!format)
  273. grub_util_error ("%s", _("Target format not specified (use the -O option)."));
  274. if (!grub_install_source_directory)
  275. grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format));
  276. enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory);
  277. char *memdisk_dir = grub_util_make_temporary_dir ();
  278. char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub");
  279. grub_install_copy_files (grub_install_source_directory,
  280. boot_grub, plat);
  281. grub_set_install_backup_ponr ();
  282. char *memdisk_img = grub_util_make_temporary_file ();
  283. memdisk = grub_util_fopen (memdisk_img, "wb");
  284. add_tar_file (memdisk_dir, "");
  285. for (i = 0; i < nfiles; i++)
  286. {
  287. char *eq = grub_strchr (files[i], '=');
  288. char *from, *to;
  289. if (!eq)
  290. {
  291. from = files[i];
  292. to = files[i];
  293. }
  294. else
  295. {
  296. *eq = '\0';
  297. to = files[i];
  298. from = eq + 1;
  299. }
  300. while (*to == '/')
  301. to++;
  302. add_tar_file (from, to);
  303. }
  304. write_zeros (512);
  305. fclose (memdisk);
  306. grub_util_unlink_recursive (memdisk_dir);
  307. grub_install_push_module ("memdisk");
  308. grub_install_push_module ("tar");
  309. grub_install_make_image_wrap (grub_install_source_directory,
  310. "(memdisk)/boot/grub", output_image,
  311. memdisk_img, NULL,
  312. grub_util_get_target_name (format), 0);
  313. grub_util_unlink (memdisk_img);
  314. return 0;
  315. }