]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Add ability to generate newc additions on runtime.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Mar 2013 20:01:28 +0000 (21:01 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Fri, 22 Mar 2013 20:01:28 +0000 (21:01 +0100)
ChangeLog
grub-core/Makefile.core.def
grub-core/loader/i386/linux.c
grub-core/loader/i386/pc/linux.c
grub-core/loader/ia64/efi/linux.c
grub-core/loader/linux.c [new file with mode: 0644]
grub-core/loader/mips/linux.c
grub-core/loader/powerpc/ieee1275/linux.c
grub-core/loader/sparc64/ieee1275/linux.c
include/grub/linux.h [new file with mode: 0644]

index 4a5b683d3b67cbd4c8f262400d31d3c26e4de7db..5582e131efdb19ace48c66fcb18cc21fdcfa8d3c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-03-22  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Add ability to generate newc additions on runtime.
+
 2013-03-22  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/commands/i386/coreboot/cbls.c: Fix typos and wrong
index d851bc3c66e62663bf45456108783f4b108ea136..a614b221316519e464e03ae377a1b15b5f8728de 100644 (file)
@@ -1406,6 +1406,7 @@ module = {
 module = {
   name = linux16;
   common = loader/i386/pc/linux.c;
+  common = loader/linux.c;
   common = lib/cmdline.c;
   enable = x86;
 };
@@ -1454,6 +1455,7 @@ module = {
   powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
   sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
   ia64_efi = loader/ia64/efi/linux.c;
+  common = loader/linux.c;
   common = lib/cmdline.c;
   enable = noemu;
 };
index 92cabfb57fb974396ad4930858a5e652aa6234c7..bdfe19acd2dbc977b6e4eff1ab46ca5787b00954 100644 (file)
@@ -34,6 +34,7 @@
 #include <grub/i386/relocator.h>
 #include <grub/i18n.h>
 #include <grub/lib/cmdline.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -1055,14 +1056,11 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
   grub_size_t size = 0;
   grub_addr_t addr_min, addr_max;
   grub_addr_t addr;
   grub_err_t err;
-  int i;
-  int nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     {
@@ -1076,19 +1074,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      size += ALIGN_UP (grub_file_size (files[i]), 4);
-    }
+  size = grub_get_initrd_size (&initrd_ctx);
 
   initrd_pages = (page_align (size) >> 12);
 
@@ -1138,21 +1127,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
     initrd_mem_target = get_physical_target_address (ch);
   }
 
-  ptr = initrd_mem;
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+    goto fail;
 
   grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
                (unsigned) addr, (unsigned) size);
@@ -1162,9 +1138,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   linux_params.root_dev = 0x0100; /* XXX */
 
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
 
   return grub_errno;
 }
index 3ce21bc2b4ffcc314c120eb8943cf64f7afae653..672c013e74d26520f7f8abc84a413019e5d0b4aa 100644 (file)
@@ -34,6 +34,7 @@
 #include <grub/video.h>
 #include <grub/i386/floppy.h>
 #include <grub/lib/cmdline.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -381,15 +382,13 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
   grub_size_t size = 0;
   grub_addr_t addr_max, addr_min;
   struct linux_kernel_header *lh;
   grub_uint8_t *initrd_chunk;
   grub_addr_t initrd_addr;
   grub_err_t err;
-  int i, nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     {
@@ -437,19 +436,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
 
   addr_min = GRUB_LINUX_BZIMAGE_ADDR + grub_linux16_prot_size;
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      size += ALIGN_UP (grub_file_size (files[i]), 4);
-    }
+  size = grub_get_initrd_size (&initrd_ctx);
 
   {
     grub_relocator_chunk_t ch;
@@ -463,30 +453,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
     initrd_addr = get_physical_target_address (ch);
   }
 
-  ptr = initrd_chunk;
-  
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, initrd_chunk))
+    goto fail;
 
   lh->ramdisk_image = initrd_addr;
   lh->ramdisk_size = size;
 
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
 
   return grub_errno;
 }
index 17843fdbf912b8d627310dccf97c5211521b95f7..87ac49f8c3b5137ea24234fe99382ed883478bd2 100644 (file)
@@ -32,6 +32,7 @@
 #include <grub/elf.h>
 #include <grub/i18n.h>
 #include <grub/env.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -567,10 +568,7 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
-  int i;
-  int nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     {
@@ -584,22 +582,11 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  initrd_size = 0;
+  initrd_size = grub_get_initrd_size (&initrd_ctx);
   grub_dprintf ("linux", "Loading initrd\n");
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      initrd_size += ALIGN_UP (grub_file_size (files[i]), 4);
-      grub_dprintf ("linux", "File %d: %s\n", i, argv[i]);
-    }
 
   initrd_pages = (page_align (initrd_size) >> 12);
   initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
@@ -612,25 +599,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   grub_dprintf ("linux", "[addr=0x%lx, size=0x%lx]\n",
                (grub_uint64_t) initrd_mem, initrd_size);
 
-  ptr = initrd_mem;
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+    goto fail;
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
   return grub_errno;
 }
 
diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
new file mode 100644 (file)
index 0000000..cbe3c53
--- /dev/null
@@ -0,0 +1,294 @@
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/linux.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+
+struct newc_head
+{
+  char magic[6];
+  char ino[8];
+  char mode[8];
+  char uid[8];
+  char gid[8];
+  char nlink[8];
+  char mtime[8];
+  char filesize[8];
+  char devmajor[8];
+  char devminor[8];
+  char rdevmajor[8];
+  char rdevminor[8];
+  char namesize[8];
+  char check[8];
+} __attribute__ ((packed));
+
+struct grub_linux_initrd_component
+{
+  grub_file_t file;
+  char *newc_name;
+  grub_off_t size;
+};
+
+struct dir
+{
+  char *name;
+  struct dir *next;
+  struct dir *child;
+};
+
+static char
+hex (grub_uint8_t val)
+{
+  if (val < 10)
+    return '0' + val;
+  return 'a' + val - 10;
+}
+
+static void
+set_field (char *var, grub_uint32_t val)
+{
+  int i;
+  char *ptr = var;
+  for (i = 28; i >= 0; i -= 4)
+    *ptr++ = hex((val >> i) & 0xf);
+}
+
+static grub_uint8_t *
+make_header (grub_uint8_t *ptr,
+            const char *name, grub_size_t len,
+            grub_uint32_t mode,
+            grub_off_t fsize)
+{
+  struct newc_head *head = (struct newc_head *) ptr;
+  grub_uint8_t *optr;
+  grub_size_t oh = 0;
+  grub_memcpy (head->magic, "070701", 6);
+  set_field (head->ino, 0);
+  set_field (head->mode, mode);
+  set_field (head->uid, 0);
+  set_field (head->gid, 0);
+  set_field (head->nlink, 1);
+  set_field (head->mtime, 0);
+  set_field (head->filesize, fsize);
+  set_field (head->devmajor, 0);
+  set_field (head->devminor, 0);
+  set_field (head->rdevmajor, 0);
+  set_field (head->rdevminor, 0);
+  set_field (head->namesize, len);
+  set_field (head->check, 0);
+  optr = ptr;
+  ptr += sizeof (struct newc_head);
+  grub_memcpy (ptr, name, len);
+  ptr += len;
+  oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
+  grub_memset (ptr, 0, oh);
+  ptr += oh;
+  return ptr;
+}
+
+static void
+free_dir (struct dir *root)
+{
+  if (!root)
+    return;
+  free_dir (root->next);
+  free_dir (root->child);
+  grub_free (root->name);
+  grub_free (root);
+}
+
+static grub_size_t
+insert_dir (const char *name, struct dir **root,
+           grub_uint8_t *ptr)
+{
+  struct dir *cur, **head = root;
+  const char *cb, *ce = name;
+  grub_size_t size = 0;
+  while (1)
+    {
+      for (cb = ce; *cb == '/'; cb++);
+      for (ce = cb; *ce && *ce != '/'; ce++);
+      if (!*ce)
+       break;
+
+      for (cur = *root; cur; cur = cur->next)
+       if (grub_memcmp (cur->name, cb, ce - cb)
+           && cur->name[ce - cb] == 0)
+         break;
+      if (!cur)
+       {
+         struct dir *n;
+         n = grub_zalloc (sizeof (*n));
+         if (!n)
+           return 0;
+         n->next = *head;
+         n->name = grub_strndup (cb, ce - cb);
+         if (ptr)
+           {
+             grub_printf ("Creating directory %s, %s\n", name, ce);
+             ptr = make_header (ptr, name, ce - name,
+                                040777, 0);
+           }
+         size += ALIGN_UP ((ce - (char *) name)
+                           + sizeof (struct newc_head), 4);
+         *head = n;
+         cur = n;
+       }
+      root = &cur->next;
+    }
+  return size;
+}
+
+grub_err_t
+grub_initrd_init (int argc, char *argv[],
+                 struct grub_linux_initrd_context *initrd_ctx)
+{
+  int i;
+  int newc = 0;
+  struct dir *root = 0;
+
+  initrd_ctx->nfiles = 0;
+  initrd_ctx->components = 0;
+
+  initrd_ctx->components = grub_zalloc (argc
+                                       * sizeof (initrd_ctx->components[0]));
+  if (!initrd_ctx->components)
+    return grub_errno;
+
+  initrd_ctx->size = 0;
+
+  for (i = 0; i < argc; i++)
+    {
+      const char *fname = argv[i];
+      if (grub_memcmp (argv[i], "newc:", 5) == 0)
+       {
+         const char *ptr, *eptr;
+         ptr = argv[i] + 5;
+         while (*ptr == '/')
+           ptr++;
+         eptr = grub_strchr (ptr, ':');
+         if (eptr)
+           {
+             grub_file_filter_disable_compression ();
+             initrd_ctx->components[i].newc_name = grub_strndup (ptr, eptr - ptr);
+             if (!initrd_ctx->components[i].newc_name)
+               {
+                 grub_initrd_close (initrd_ctx);
+                 return grub_errno;
+               }
+             initrd_ctx->size
+               += ALIGN_UP (sizeof (struct newc_head)
+                           + grub_strlen (initrd_ctx->components[i].newc_name),
+                            4);
+             initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
+                                             &root, 0);
+             newc = 1;
+             fname = eptr + 1;
+           }
+       }
+      else if (newc)
+       {
+         initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+                                       + sizeof ("TRAILER!!!") - 1, 4);
+         free_dir (root);
+         root = 0;
+         newc = 0;
+       }
+      grub_file_filter_disable_compression ();
+      initrd_ctx->components[i].file = grub_file_open (fname);
+      if (!initrd_ctx->components[i].file)
+       {
+         grub_initrd_close (initrd_ctx);
+         return grub_errno;
+       }
+      initrd_ctx->nfiles++;
+      initrd_ctx->components[i].size
+       = grub_file_size (initrd_ctx->components[i].file);
+      initrd_ctx->size += ALIGN_UP (initrd_ctx->components[i].size, 4);
+    }
+
+  if (newc)
+    {
+      initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
+                                   + sizeof ("TRAILER!!!") - 1, 4);
+      free_dir (root);
+      root = 0;
+    }
+  
+  return GRUB_ERR_NONE;
+}
+
+grub_size_t
+grub_get_initrd_size (struct grub_linux_initrd_context *initrd_ctx)
+{
+  return initrd_ctx->size;
+}
+
+void
+grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx)
+{
+  int i;
+  if (!initrd_ctx->components)
+    return;
+  for (i = 0; i < initrd_ctx->nfiles; i++)
+    {
+      grub_free (initrd_ctx->components[i].newc_name);
+      grub_file_close (initrd_ctx->components[i].file);
+    }
+  grub_free (initrd_ctx->components);
+  initrd_ctx->components = 0;
+}
+
+grub_err_t
+grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+                 char *argv[], void *target)
+{
+  grub_uint8_t *ptr = target;
+  int i;
+  int newc = 0;
+  struct dir *root = 0;
+
+  for (i = 0; i < initrd_ctx->nfiles; i++)
+    {
+      grub_ssize_t cursize;
+
+      if (initrd_ctx->components[i].newc_name)
+       {
+         ptr += insert_dir (initrd_ctx->components[i].newc_name,
+                            &root, ptr);
+         ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
+                            grub_strlen (initrd_ctx->components[i].newc_name),
+                            0100777,
+                            initrd_ctx->components[i].size);
+         newc = 1;
+       }
+      else if (newc)
+       {
+         ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
+                            0, 0);
+         free_dir (root);
+         root = 0;
+         newc = 0;
+       }
+
+      cursize = initrd_ctx->components[i].size;
+      if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
+         != cursize)
+       {
+         if (!grub_errno)
+           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
+                       argv[i]);
+         grub_initrd_close (initrd_ctx);
+         return grub_errno;
+       }
+      ptr += cursize;
+      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
+      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
+    }
+  if (newc)
+    ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
+  free_dir (root);
+  root = 0;
+  return GRUB_ERR_NONE;
+}
index 653f8a26c5b1766c26d2f37db1be67502428e467..ef64a5b1d362c53d1b6300f23bbe928aa8b487c2 100644 (file)
@@ -28,6 +28,7 @@
 #include <grub/memory.h>
 #include <grub/i18n.h>
 #include <grub/lib/cmdline.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -410,14 +411,11 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
   grub_size_t size = 0;
   void *initrd_src;
   grub_addr_t initrd_dest;
   grub_err_t err;
-  int i;
-  int nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
@@ -428,19 +426,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   if (initrd_loaded)
     return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued.");
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      size += ALIGN_UP (grub_file_size (files[i]), 4);
-    }
+  size = grub_get_initrd_size (&initrd_ctx);
 
   {
     grub_relocator_chunk_t ch;
@@ -458,21 +447,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
     initrd_dest = get_physical_target_address (ch) | 0x80000000;
   }
 
-  ptr = initrd_src;
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, initrd_src))
+    goto fail;
 
 #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
   {
@@ -504,9 +480,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   initrd_loaded = 1;
 
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
 
   return grub_errno;
 }
index 9055399e707ef0a30734158f2bcd229371c19f43..cff4fd1842d64b8e85166936b72c21804d052184 100644 (file)
@@ -29,6 +29,7 @@
 #include <grub/memory.h>
 #include <grub/lib/cmdline.h>
 #include <grub/cache.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -315,13 +316,10 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
   grub_size_t size = 0;
   grub_addr_t first_addr;
   grub_addr_t addr;
-  int i;
-  int nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     {
@@ -335,19 +333,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      size += ALIGN_UP (grub_file_size (files[i]), 4);
-    }
+  size = grub_get_initrd_size (&initrd_ctx);
 
   first_addr = linux_addr + linux_size;
 
@@ -359,30 +348,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
 
   grub_dprintf ("loader", "Loading initrd at 0x%x, size 0x%x\n", addr, size);
 
-  ptr = (void *) addr;
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         grub_ieee1275_release (addr, size);
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, (void *) addr))
+    goto fail;
 
   initrd_addr = addr;
   initrd_size = size;
 
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
 
   return grub_errno;
 }
index d20337744362fb26ce5359dfa475e76cc80c215a..577ecff83bc37e32b5669f439d9850032868fba4 100644 (file)
@@ -28,6 +28,7 @@
 #include <grub/i18n.h>
 #include <grub/memory.h>
 #include <grub/lib/cmdline.h>
+#include <grub/linux.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -368,14 +369,11 @@ static grub_err_t
 grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char *argv[])
 {
-  grub_file_t *files = 0;
   grub_size_t size = 0;
   grub_addr_t paddr;
   grub_addr_t addr;
   int ret;
-  int i;
-  int nfiles = 0;
-  grub_uint8_t *ptr;
+  struct grub_linux_initrd_context initrd_ctx;
 
   if (argc == 0)
     {
@@ -389,19 +387,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  files = grub_zalloc (argc * sizeof (files[0]));
-  if (!files)
+  if (grub_initrd_init (argc, argv, &initrd_ctx))
     goto fail;
 
-  for (i = 0; i < argc; i++)
-    {
-      grub_file_filter_disable_compression ();
-      files[i] = grub_file_open (argv[i]);
-      if (! files[i])
-       goto fail;
-      nfiles++;
-      size += ALIGN_UP(grub_file_size (files[i]), 4);
-    }
+  size = grub_get_initrd_size (&initrd_ctx);
 
   addr = 0x60000000;
 
@@ -423,30 +412,15 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   grub_dprintf ("loader", "Loading initrd at vaddr 0x%lx, paddr 0x%lx, size 0x%lx\n",
                addr, paddr, size);
 
-  ptr = (void *) addr;
-  for (i = 0; i < nfiles; i++)
-    {
-      grub_ssize_t cursize = grub_file_size (files[i]);
-      if (grub_file_read (files[i], ptr, cursize) != cursize)
-       {
-         if (!grub_errno)
-           grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
-                       argv[i]);
-         goto fail;
-       }
-      ptr += cursize;
-      grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
-      ptr += ALIGN_UP_OVERHEAD (cursize, 4);
-    }
+  if (grub_initrd_load (&initrd_ctx, argv, (void *) addr))
+    goto fail;
 
   initrd_addr = addr;
   initrd_paddr = paddr;
   initrd_size = size;
 
  fail:
-  for (i = 0; i < nfiles; i++)
-    grub_file_close (files[i]);
-  grub_free (files);
+  grub_initrd_close (&initrd_ctx);
 
   return grub_errno;
 }
diff --git a/include/grub/linux.h b/include/grub/linux.h
new file mode 100644 (file)
index 0000000..594a3f3
--- /dev/null
@@ -0,0 +1,24 @@
+#include <grub/file.h>
+
+struct grub_linux_initrd_component;
+
+struct grub_linux_initrd_context
+{
+  int nfiles;
+  struct grub_linux_initrd_component *components;
+  grub_size_t size;
+};
+
+grub_err_t
+grub_initrd_init (int argc, char *argv[],
+                 struct grub_linux_initrd_context *ctx);
+
+grub_size_t
+grub_get_initrd_size (struct grub_linux_initrd_context *ctx);
+
+void
+grub_initrd_close (struct grub_linux_initrd_context *initrd_ctx);
+
+grub_err_t
+grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
+                 char *argv[], void *target);