123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- #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];
- } GRUB_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_dprintf ("linux", "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];
- initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
- 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 += initrd_ctx->components[i].size;
- }
- if (newc)
- {
- initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
- 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;
- grub_ssize_t cursize = 0;
- for (i = 0; i < initrd_ctx->nfiles; i++)
- {
- grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
- ptr += ALIGN_UP_OVERHEAD (cursize, 4);
- 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;
- }
- if (newc)
- {
- grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
- ptr += ALIGN_UP_OVERHEAD (cursize, 4);
- ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
- }
- free_dir (root);
- root = 0;
- return GRUB_ERR_NONE;
- }
|