diff options
author | Matt Fleming <matt.fleming@intel.com> | 2012-11-05 15:35:35 +0000 |
---|---|---|
committer | Matt Fleming <matt.fleming@intel.com> | 2012-11-05 15:35:35 +0000 |
commit | c44fe85310a4efb1334b4e807b999870ab90e3f6 (patch) | |
tree | 2ca413b43932e71a072eb4b533a97df6776d6c94 | |
parent | dd59314c304ec83bee927af7395af5ceb4942f66 (diff) | |
parent | 28b3a9d4d7eb932b827122f3e641ce14fb2cbd03 (diff) | |
download | syslinux-c44fe85310a4efb1334b4e807b999870ab90e3f6.tar.gz |
Merge branch 'multi_initrd2-5.00-pre9' of git://git.zytor.com/users/sha0/syslinux into elflink
Pull multi-initrd patches from Shao Miller,
These patches provide two new options for the linux.c32 module.
The "initrd+=" option allows you to append initramfs-style blobs
(files which can be produced with 'cpio -o -H newc') to whatever
"initrd" was specified via the "initrd=" option (or was specified
indirectly via the INITRD directive).
The "initrdfile=" option allows you to load a file and encapsulate it
as though you had used 'cpio -o -H newc', and pass the resulting blob
alongside the other items that might have been specified with
"initrd=" or "initrd+=".
* 'multi_initrd2-5.00-pre9' of git://git.zytor.com/users/sha0/syslinux:
initramfs chain handling: Accounting fixes for padding, etc.
linux.c32: Introduce initrdfile= option
linux.c32: Add new initrd+= option for multiple initrds
linux.c32: Move some initrd=x,y,z code out of main
linux.c32: Add find_arguments function
-rw-r--r-- | com32/lib/syslinux/initramfs_file.c | 15 | ||||
-rw-r--r-- | com32/modules/linux.c | 200 |
2 files changed, 172 insertions, 43 deletions
diff --git a/com32/lib/syslinux/initramfs_file.c b/com32/lib/syslinux/initramfs_file.c index 763eff28..7eb55b5e 100644 --- a/com32/lib/syslinux/initramfs_file.c +++ b/com32/lib/syslinux/initramfs_file.c @@ -65,7 +65,7 @@ static size_t initramfs_mkdirs(const char *filename, void *buffer, const char *p = filename; char *bp = buffer; int len; - size_t bytes = 0; + size_t bytes = 0, hdr_sz; int pad; while ((p = strchr(p, '/'))) { @@ -81,15 +81,17 @@ static size_t initramfs_mkdirs(const char *filename, void *buffer, while ((p = strchr(p, '/'))) { if (p != filename && p[-1] != '/') { len = p - filename; + hdr_sz = ((sizeof(struct cpio_header) + len + 1) + 3) & ~3; bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x" "%08x%08x%08x%08x", next_ino++, S_IFDIR | 0755, 0, 0, 1, 0, 0, 0, 1, 0, 1, len + 1, 0); memcpy(bp, filename, len); bp += len; - pad = (-(sizeof(struct cpio_header) + len) & 3) + 1; + pad = hdr_sz - (sizeof(struct cpio_header) + len); memset(bp, 0, pad); bp += pad; } + p++; } } @@ -104,7 +106,7 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename, int do_mkdir, uint16_t mode, size_t len, uint32_t major, uint32_t minor) { - size_t bytes; + size_t bytes, hdr_sz; int namelen = strlen(filename); int pad; char *buffer, *bp; @@ -114,7 +116,8 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename, else bytes = 0; - bytes += ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3; + hdr_sz = ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3; + bytes += hdr_sz; bp = buffer = malloc(bytes); if (!buffer) @@ -127,8 +130,8 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename, "%08x%08x%08x%08x", next_ino++, mode, 0, 0, 1, 0, len, 0, 1, major, minor, namelen + 1, 0); memcpy(bp, filename, namelen); - bp += len; - pad = (-(sizeof(struct cpio_header) + namelen) & 3) + 1; + bp += namelen; + pad = hdr_sz - (sizeof(struct cpio_header) + namelen); memset(bp, 0, pad); if (initramfs_add_data(ihead, buffer, bytes, bytes, 4)) { diff --git a/com32/modules/linux.c b/com32/modules/linux.c index e4c067ff..f657eab4 100644 --- a/com32/modules/linux.c +++ b/com32/modules/linux.c @@ -48,6 +48,14 @@ #include <syslinux/linux.h> #include <syslinux/pxe.h> +enum ldmode { + ldmode_raw, + ldmode_cpio, + ldmodes +}; + +typedef int f_ldinitramfs(struct initramfs *, char *); + const char *progname = "linux.c32"; /* Find the last instance of a particular command line argument @@ -59,13 +67,34 @@ static char *find_argument(char **argv, const char *argument) char *ptr = NULL; for (arg = argv; *arg; arg++) { - if (!memcmp(*arg, argument, la)) + if (!strncmp(*arg, argument, la)) ptr = *arg + la; } return ptr; } +/* Find the next instance of a particular command line argument */ +static char **find_arguments(char **argv, char **ptr, + const char *argument) +{ + int la = strlen(argument); + char **arg; + + for (arg = argv; *arg; arg++) { + if (!strncmp(*arg, argument, la)) { + *ptr = *arg + la; + break; + } + } + + /* Exhausted all arguments */ + if (!*arg) + return NULL; + + return arg; +} + /* Search for a boolean argument; return its position, or 0 if not present */ static int find_boolean(char **argv, const char *argument) { @@ -109,6 +138,99 @@ static char *make_cmdline(char **argv) return cmdline; } +static f_ldinitramfs ldinitramfs_raw; +static int ldinitramfs_raw(struct initramfs *initramfs, char *fname) +{ + return initramfs_load_archive(initramfs, fname); +} + +static f_ldinitramfs ldinitramfs_cpio; +static int ldinitramfs_cpio(struct initramfs *initramfs, char *fname) +{ + char *target_fname, *p; + int do_mkdir, unmangle, rc; + + /* Choose target_fname based on presence of "@" syntax */ + target_fname = strchr(fname, '@'); + if (target_fname) { + /* Temporarily mangle */ + unmangle = 1; + *target_fname++ = '\0'; + + /* Make parent directories? */ + do_mkdir = !!strchr(target_fname, '/'); + } else { + unmangle = 0; + + /* Forget the source path */ + target_fname = fname; + while ((p = strchr(target_fname, '/'))) + target_fname = p + 1; + + /* The user didn't specify a desired path */ + do_mkdir = 0; + } + + /* + * Load the file, encapsulate it with the desired path, make the + * parent directories if the desired path contains them, add to initramfs + */ + rc = initramfs_load_file(initramfs, fname, target_fname, do_mkdir, 0755); + + /* Unmangle, if needed*/ + if (unmangle) + *--target_fname = '@'; + + return rc; +} + +/* It only makes sense to call this function from main */ +static int process_initramfs_args(char *arg, struct initramfs *initramfs, + const char *kernel_name, enum ldmode mode, + bool opt_quiet) +{ + const char *mode_msg; + f_ldinitramfs *ldinitramfs; + char *p; + + switch (mode) { + case ldmode_raw: + mode_msg = "Loading"; + ldinitramfs = ldinitramfs_raw; + break; + case ldmode_cpio: + mode_msg = "Encapsulating"; + ldinitramfs = ldinitramfs_cpio; + break; + case ldmodes: + default: + return 1; + } + + do { + p = strchr(arg, ','); + if (p) + *p = '\0'; + + if (!opt_quiet) + printf("%s %s... ", mode_msg, arg); + errno = 0; + if (ldinitramfs(initramfs, arg)) { + if (opt_quiet) + printf("Loading %s ", kernel_name); + printf("failed: "); + return 1; + } + if (!opt_quiet) + printf("ok\n"); + + if (p) + *p++ = ','; + } while ((arg = p)); + + return 0; +} + static int setup_data_file(struct setup_data *setup_data, uint32_t type, const char *filename, bool opt_quiet) @@ -142,7 +264,7 @@ int main(int argc, char *argv[]) bool opt_quiet = false; void *dhcpdata; size_t dhcplen; - char **argp, **argl, *arg, *p; + char **argp, **argl, *arg; (void)argc; argp = argv + 1; @@ -207,27 +329,27 @@ int main(int argc, char *argv[]) goto bail; } + /* Process initramfs arguments */ if ((arg = find_argument(argp, "initrd="))) { - do { - p = strchr(arg, ','); - if (p) - *p = '\0'; - - if (!opt_quiet) - printf("Loading %s... ", arg); - errno = 0; - if (initramfs_load_archive(initramfs, arg)) { - if (opt_quiet) - printf("Loading %s ", kernel_name); - printf("failed: "); - goto bail; - } - if (!opt_quiet) - printf("ok\n"); - - if (p) - *p++ = ','; - } while ((arg = p)); + if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw, + opt_quiet)) + goto bail; + } + + argl = argv; + while ((argl = find_arguments(argl, &arg, "initrd+="))) { + argl++; + if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw, + opt_quiet)) + goto bail; + } + + argl = argv; + while ((argl = find_arguments(argl, &arg, "initrdfile="))) { + argl++; + if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_cpio, + opt_quiet)) + goto bail; } /* Append the DHCP info */ @@ -246,24 +368,28 @@ int main(int argc, char *argv[]) if (!setup_data) goto bail; - for (argl = argv; (arg = *argl); argl++) { - if (!memcmp(arg, "dtb=", 4)) { - if (setup_data_file(setup_data, SETUP_DTB, arg+4, opt_quiet)) - goto bail; - } else if (!memcmp(arg, "blob.", 5)) { - uint32_t type; - char *ep; + argl = argv; + while ((argl = find_arguments(argl, &arg, "dtb="))) { + argl++; + if (setup_data_file(setup_data, SETUP_DTB, arg, opt_quiet)) + goto bail; + } + + argl = argv; + while ((argl = find_arguments(argl, &arg, "blob."))) { + uint32_t type; + char *ep; - type = strtoul(arg + 5, &ep, 10); - if (ep[0] != '=' || !ep[1]) - continue; + argl++; + type = strtoul(arg, &ep, 10); + if (ep[0] != '=' || !ep[1]) + continue; - if (!type) - continue; + if (!type) + continue; - if (setup_data_file(setup_data, type, ep+1, opt_quiet)) - goto bail; - } + if (setup_data_file(setup_data, type, ep+1, opt_quiet)) + goto bail; } /* This should not return... */ |