summaryrefslogtreecommitdiffstats
path: root/util/grub-mkstandalone.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/grub-mkstandalone.c')
-rw-r--r--util/grub-mkstandalone.c363
1 files changed, 363 insertions, 0 deletions
diff --git a/util/grub-mkstandalone.c b/util/grub-mkstandalone.c
new file mode 100644
index 0000000..5f50a3b
--- /dev/null
+++ b/util/grub-mkstandalone.c
@@ -0,0 +1,363 @@
+
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+#include <grub/emu/config.h>
+
+#include <string.h>
+
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#pragma GCC diagnostic ignored "-Wmissing-declarations"
+#include <argp.h>
+#pragma GCC diagnostic error "-Wmissing-prototypes"
+#pragma GCC diagnostic error "-Wmissing-declarations"
+
+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', "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, MAGIC, sizeof (hd.magic));
+ 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, MAGIC, sizeof (hd.magic));
+ 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);
+ free (tcn);
+}
+
+int
+main (int argc, char *argv[])
+{
+ const char *pkglibdir;
+ int i;
+
+ grub_util_host_init (&argc, &argv);
+ grub_util_disable_fd_syncs ();
+
+ files = xcalloc (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);
+
+ grub_set_install_backup_ponr ();
+
+ 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;
+}