/* * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ #include #include #include #include #include #include static char *output_image; static char **files; static int nfiles; const struct grub_install_image_target_desc *format; static FILE *memdisk; enum { OPTION_OUTPUT = 'o', OPTION_FORMAT = 'O' }; static struct argp_option options[] = { GRUB_INSTALL_OPTIONS, {"output", 'o', N_("FILE"), 0, N_("save output in FILE [required]"), 2}, {"format", 'O', N_("FILE"), 0, 0, 2}, {"compression", 'C', N_("xz|none|auto"), OPTION_HIDDEN, 0, 2}, {0, 0, 0, 0, 0, 0} }; static char * help_filter (int key, const char *text, void *input __attribute__ ((unused))) { switch (key) { case 'O': { char *formats = grub_install_get_image_targets_string (), *ret; ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"), _("available formats:"), formats); free (formats); return ret; } default: return grub_install_help_filter (key, text, input); } } static error_t argp_parser (int key, char *arg, struct argp_state *state) { if (key == 'C') key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS; if (grub_install_parse (key, arg)) return 0; switch (key) { case 'o': if (output_image) free (output_image); output_image = xstrdup (arg); break; case 'O': { format = grub_install_get_image_target (arg); if (!format) { printf (_("unknown target format %s\n"), arg); argp_usage (state); exit (1); } break; } case ARGP_KEY_ARG: files[nfiles++] = xstrdup (arg); break; default: return ARGP_ERR_UNKNOWN; } return 0; } struct argp argp = { options, argp_parser, N_("[OPTION] SOURCE..."), 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"), NULL, help_filter, NULL }; /* tar support */ #define MAGIC "ustar" struct head { char name[100]; char mode[8]; char uid[8]; char gid[8]; char size[12]; char mtime[12]; char chksum[8]; char typeflag; char linkname[100]; char magic[6]; char version[2]; char uname[32]; char gname[32]; char devmajor[8]; char devminor[8]; char prefix[155]; char pad[12]; } GRUB_PACKED; static void write_zeros (unsigned rsz) { char buf[512]; memset (buf, 0, 512); fwrite (buf, 1, rsz, memdisk); } static void write_pad (unsigned sz) { write_zeros ((~sz + 1) & 511); } static void set_tar_value (char *field, grub_uint32_t val, unsigned len) { unsigned i; for (i = 0; i < len - 1; i++) field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7); } static void compute_checksum (struct head *hd) { unsigned int chk = 0; unsigned char *ptr; memset (hd->chksum, ' ', 8); for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++) chk += *ptr; set_tar_value (hd->chksum, chk, 8); } static void add_tar_file (const char *from, const char *to) { char *tcn; const char *iptr; char *optr; struct head hd; grub_util_fd_t in; ssize_t r; grub_uint32_t mtime = 0; grub_uint32_t size; COMPILE_TIME_ASSERT (sizeof (hd) == 512); if (grub_util_is_special_file (from)) return; mtime = grub_util_get_mtime (from); optr = tcn = xmalloc (strlen (to) + 1); for (iptr = to; *iptr == '/'; iptr++); for (; *iptr; iptr++) if (!(iptr[0] == '/' && iptr[1] == '/')) *optr++ = *iptr; *optr = '\0'; if (grub_util_is_directory (from)) { grub_util_fd_dir_t d; grub_util_fd_dirent_t de; d = grub_util_fd_opendir (from); while ((de = grub_util_fd_readdir (d))) { char *fp, *tfp; if (strcmp (de->d_name, ".") == 0) continue; if (strcmp (de->d_name, "..") == 0) continue; fp = grub_util_path_concat (2, from, de->d_name); tfp = xasprintf ("%s/%s", to, de->d_name); add_tar_file (fp, tfp); free (fp); } grub_util_fd_closedir (d); free (tcn); return; } if (optr - tcn > 99) { memset (&hd, 0, sizeof (hd)); memcpy (hd.name, tcn, 99); memcpy (hd.mode, "0000600", 7); memcpy (hd.uid, "0001750", 7); memcpy (hd.gid, "0001750", 7); set_tar_value (hd.size, optr - tcn, 12); set_tar_value (hd.mtime, mtime, 12); hd.typeflag = 'L'; memcpy (hd.magic, "ustar ", 7); memcpy (hd.uname, "grub", 4); memcpy (hd.gname, "grub", 4); compute_checksum (&hd); fwrite (&hd, 1, sizeof (hd), memdisk); fwrite (tcn, 1, optr - tcn, memdisk); write_pad (optr - tcn); } in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY); if (!GRUB_UTIL_FD_IS_VALID (in)) grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ()); if (!grub_install_copy_buffer) grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE); size = grub_util_get_fd_size (in, from, NULL); memset (&hd, 0, sizeof (hd)); memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99); memcpy (hd.mode, "0000600", 7); memcpy (hd.uid, "0001750", 7); memcpy (hd.gid, "0001750", 7); set_tar_value (hd.size, size, 12); set_tar_value (hd.mtime, mtime, 12); hd.typeflag = '0'; memcpy (hd.magic, "ustar ", 7); memcpy (hd.uname, "grub", 4); memcpy (hd.gname, "grub", 4); compute_checksum (&hd); fwrite (&hd, 1, sizeof (hd), memdisk); while (1) { r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE); if (r <= 0) break; fwrite (grub_install_copy_buffer, 1, r, memdisk); } grub_util_fd_close (in); write_pad (size); } int main (int argc, char *argv[]) { const char *pkglibdir; int i; grub_util_host_init (&argc, &argv); grub_util_disable_fd_syncs (); files = xmalloc ((argc + 1) * sizeof (files[0])); argp_parse (&argp, argc, argv, 0, 0, 0); pkglibdir = grub_util_get_pkglibdir (); if (!output_image) grub_util_error ("%s", _("output file must be specified")); if (!format) grub_util_error ("%s", _("Target format not specified (use the -O option).")); if (!grub_install_source_directory) grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format)); enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory); char *memdisk_dir = grub_util_make_temporary_dir (); char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub"); grub_install_copy_files (grub_install_source_directory, boot_grub, plat); char *memdisk_img = grub_util_make_temporary_file (); memdisk = grub_util_fopen (memdisk_img, "wb"); add_tar_file (memdisk_dir, ""); for (i = 0; i < nfiles; i++) { char *eq = grub_strchr (files[i], '='); char *from, *to; if (!eq) { from = files[i]; to = files[i]; } else { *eq = '\0'; to = files[i]; from = eq + 1; } while (*to == '/') to++; add_tar_file (from, to); } write_zeros (512); fclose (memdisk); grub_util_unlink_recursive (memdisk_dir); grub_install_push_module ("memdisk"); grub_install_push_module ("tar"); grub_install_make_image_wrap (grub_install_source_directory, "(memdisk)/boot/grub", output_image, memdisk_img, NULL, grub_util_get_target_name (format), 0); grub_util_unlink (memdisk_img); return 0; }