diff options
author | Michael Brown <mcb30@ipxe.org> | 2021-05-17 14:57:48 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2021-05-21 15:19:38 +0100 |
commit | bfca3db41e9af78e56e7a9b7f30121df83b6af0a (patch) | |
tree | 4f75eef31776bcc8d2918b9b2e92e90560859794 /src/core | |
parent | fc8bd4ba1a65db9d9091705f30fec19ded75530c (diff) | |
download | ipxe-bfca3db41e9af78e56e7a9b7f30121df83b6af0a.tar.gz |
[cpio] Split out bzImage initrd CPIO header construction
iPXE will construct CPIO headers for images that have a non-empty
command line, thereby allowing raw images (without CPIO headers) to be
injected into a dynamically constructed initrd. This feature is
currently implemented within the BIOS-only bzImage format support.
Split out the CPIO header construction logic to allow for reuse in
other contexts such as in a UEFI build.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/cpio.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/src/core/cpio.c b/src/core/cpio.c index 080c72daf..27aee7581 100644 --- a/src/core/cpio.c +++ b/src/core/cpio.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <ipxe/cpio.h> @@ -45,3 +46,87 @@ void cpio_set_field ( char *field, unsigned long value ) { snprintf ( buf, sizeof ( buf ), "%08lx", value ); memcpy ( field, buf, 8 ); } + +/** + * Get CPIO image filename + * + * @v image Image + * @ret len CPIO filename length (0 for no filename) + */ +size_t cpio_name_len ( struct image *image ) { + const char *name = cpio_name ( image ); + char *sep; + size_t len; + + /* Check for existence of CPIO filename */ + if ( ! name ) + return 0; + + /* Locate separator (if any) */ + sep = strchr ( name, ' ' ); + len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) ); + + return len; +} + +/** + * Parse CPIO image parameters + * + * @v image Image + * @v cpio CPIO header to fill in + */ +static void cpio_parse_cmdline ( struct image *image, + struct cpio_header *cpio ) { + const char *cmdline; + char *arg; + char *end; + unsigned int mode; + + /* Skip image filename */ + cmdline = ( cpio_name ( image ) + cpio_name_len ( image ) ); + + /* Look for "mode=" */ + if ( ( arg = strstr ( cmdline, "mode=" ) ) ) { + arg += 5; + mode = strtoul ( arg, &end, 8 /* Octal for file mode */ ); + if ( *end && ( *end != ' ' ) ) { + DBGC ( image, "CPIO %p strange \"mode=\" " + "terminator '%c'\n", image, *end ); + } + cpio_set_field ( cpio->c_mode, ( 0100000 | mode ) ); + } +} + +/** + * Construct CPIO header for image, if applicable + * + * @v image Image + * @v cpio CPIO header to fill in + * @ret len Length of magic CPIO header (including filename) + */ +size_t cpio_header ( struct image *image, struct cpio_header *cpio ) { + size_t name_len; + size_t len; + + /* Get filename length */ + name_len = cpio_name_len ( image ); + + /* Images with no filename are assumed to already be CPIO archives */ + if ( ! name_len ) + return 0; + + /* Construct CPIO header */ + memset ( cpio, '0', sizeof ( *cpio ) ); + memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) ); + cpio_set_field ( cpio->c_mode, 0100644 ); + cpio_set_field ( cpio->c_nlink, 1 ); + cpio_set_field ( cpio->c_filesize, image->len ); + cpio_set_field ( cpio->c_namesize, ( name_len + 1 /* NUL */ ) ); + cpio_parse_cmdline ( image, cpio ); + + /* Calculate total length */ + len = ( ( sizeof ( *cpio ) + name_len + 1 /* NUL */ + CPIO_ALIGN - 1 ) + & ~( CPIO_ALIGN - 1 ) ); + + return len; +} |