aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-11-05 15:35:35 +0000
committerMatt Fleming <matt.fleming@intel.com>2012-11-05 15:35:35 +0000
commitc44fe85310a4efb1334b4e807b999870ab90e3f6 (patch)
tree2ca413b43932e71a072eb4b533a97df6776d6c94
parentdd59314c304ec83bee927af7395af5ceb4942f66 (diff)
parent28b3a9d4d7eb932b827122f3e641ce14fb2cbd03 (diff)
downloadsyslinux-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.c15
-rw-r--r--com32/modules/linux.c200
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... */