summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
authorSimon Rettberg2021-07-22 14:36:35 +0200
committerSimon Rettberg2021-07-22 14:36:35 +0200
commitfc21afb08c7b827b3cd4a77618f36a7abdc13494 (patch)
treef7909726a1d49cb834bfa9647621b29cb15caea4 /src/core
parentMerge branch 'master' into openslx (diff)
parent[cloud] Retry DHCP aggressively in AWS EC2 (diff)
downloadipxe-fc21afb08c7b827b3cd4a77618f36a7abdc13494.tar.gz
ipxe-fc21afb08c7b827b3cd4a77618f36a7abdc13494.tar.xz
ipxe-fc21afb08c7b827b3cd4a77618f36a7abdc13494.zip
Merge branch 'master' into openslx
Diffstat (limited to 'src/core')
-rw-r--r--src/core/archive.c138
-rw-r--r--src/core/base64.c2
-rw-r--r--src/core/console.c5
-rw-r--r--src/core/cpio.c85
-rw-r--r--src/core/image.c25
-rw-r--r--src/core/open.c3
-rw-r--r--src/core/string.c17
7 files changed, 267 insertions, 8 deletions
diff --git a/src/core/archive.c b/src/core/archive.c
new file mode 100644
index 000000000..bb62c7e47
--- /dev/null
+++ b/src/core/archive.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <string.h>
+#include <errno.h>
+#include <ipxe/image.h>
+
+/** @file
+ *
+ * Archive images
+ *
+ */
+
+/**
+ * Extract archive image
+ *
+ * @v image Image
+ * @v name Extracted image name
+ * @v extracted Extracted image to fill in
+ * @ret rc Return status code
+ */
+int image_extract ( struct image *image, const char *name,
+ struct image **extracted ) {
+ char *dot;
+ int rc;
+
+ /* Check that this image can be used to extract an archive image */
+ if ( ! ( image->type && image->type->extract ) ) {
+ rc = -ENOTSUP;
+ goto err_unsupported;
+ }
+
+ /* Allocate new image */
+ *extracted = alloc_image ( image->uri );
+ if ( ! *extracted ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Set image name */
+ if ( ( rc = image_set_name ( *extracted,
+ ( name ? name : image->name ) ) ) != 0 ) {
+ goto err_set_name;
+ }
+
+ /* Strip any archive or compression suffix from implicit name */
+ if ( ( ! name ) && ( (*extracted)->name ) &&
+ ( ( dot = strrchr ( (*extracted)->name, '.' ) ) != NULL ) ) {
+ *dot = '\0';
+ }
+
+ /* Try extracting archive image */
+ if ( ( rc = image->type->extract ( image, *extracted ) ) != 0 ) {
+ DBGC ( image, "IMAGE %s could not extract image: %s\n",
+ image->name, strerror ( rc ) );
+ goto err_extract;
+ }
+
+ /* Register image */
+ if ( ( rc = register_image ( *extracted ) ) != 0 )
+ goto err_register;
+
+ /* Propagate trust flag */
+ if ( image->flags & IMAGE_TRUSTED )
+ image_trust ( *extracted );
+
+ /* Drop local reference to image */
+ image_put ( *extracted );
+
+ return 0;
+
+ unregister_image ( *extracted );
+ err_register:
+ err_extract:
+ err_set_name:
+ image_put ( *extracted );
+ err_alloc:
+ err_unsupported:
+ return rc;
+}
+
+/**
+ * Extract and execute image
+ *
+ * @v image Image
+ * @ret rc Return status code
+ */
+int image_extract_exec ( struct image *image ) {
+ struct image *extracted;
+ int rc;
+
+ /* Extract image */
+ if ( ( rc = image_extract ( image, NULL, &extracted ) ) != 0 )
+ goto err_extract;
+
+ /* Set image command line */
+ if ( ( rc = image_set_cmdline ( extracted, image->cmdline ) ) != 0 )
+ goto err_set_cmdline;
+
+ /* Set auto-unregister flag */
+ extracted->flags |= IMAGE_AUTO_UNREGISTER;
+
+ /* Tail-recurse into extracted image */
+ return image_exec ( extracted );
+
+ err_set_cmdline:
+ unregister_image ( extracted );
+ err_extract:
+ return rc;
+}
+
+/* Drag in objects via image_extract() */
+REQUIRING_SYMBOL ( image_extract );
+
+/* Drag in archive image formats */
+REQUIRE_OBJECT ( config_archive );
diff --git a/src/core/base64.c b/src/core/base64.c
index e452f7d41..ec11be261 100644
--- a/src/core/base64.c
+++ b/src/core/base64.c
@@ -36,7 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-static const char base64[64] =
+static const char base64[ 64 + 1 /* NUL */ ] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
diff --git a/src/core/console.c b/src/core/console.c
index 7fd00036f..2b90809bf 100644
--- a/src/core/console.c
+++ b/src/core/console.c
@@ -20,11 +20,12 @@ unsigned int console_height = CONSOLE_DEFAULT_HEIGHT;
* Write a single character to each console device
*
* @v character Character to be written
+ * @ret character Character written
*
* The character is written out to all enabled console devices, using
* each device's console_driver::putchar() method.
*/
-void putchar ( int character ) {
+int putchar ( int character ) {
struct console_driver *console;
/* Automatic LF -> CR,LF translation */
@@ -37,6 +38,8 @@ void putchar ( int character ) {
console->putchar )
console->putchar ( character );
}
+
+ return character;
}
/**
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;
+}
diff --git a/src/core/image.c b/src/core/image.c
index 9fe77c54c..ce8cf868b 100644
--- a/src/core/image.c
+++ b/src/core/image.c
@@ -176,14 +176,13 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
}
/**
- * Set image data
+ * Set image length
*
* @v image Image
- * @v data Image data
* @v len Length of image data
* @ret rc Return status code
*/
-int image_set_data ( struct image *image, userptr_t data, size_t len ) {
+int image_set_len ( struct image *image, size_t len ) {
userptr_t new;
/* (Re)allocate image data */
@@ -191,10 +190,28 @@ int image_set_data ( struct image *image, userptr_t data, size_t len ) {
if ( ! new )
return -ENOMEM;
image->data = new;
+ image->len = len;
+
+ return 0;
+}
+
+/**
+ * Set image data
+ *
+ * @v image Image
+ * @v data Image data
+ * @v len Length of image data
+ * @ret rc Return status code
+ */
+int image_set_data ( struct image *image, userptr_t data, size_t len ) {
+ int rc;
+
+ /* Set image length */
+ if ( ( rc = image_set_len ( image, len ) ) != 0 )
+ return rc;
/* Copy in new image data */
memcpy_user ( image->data, 0, data, 0, len );
- image->len = len;
return 0;
}
diff --git a/src/core/open.c b/src/core/open.c
index c27d8a021..f9198c9d9 100644
--- a/src/core/open.c
+++ b/src/core/open.c
@@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdarg.h>
#include <string.h>
+#include <strings.h>
#include <errno.h>
#include <ipxe/xfer.h>
#include <ipxe/uri.h>
@@ -47,7 +48,7 @@ struct uri_opener * xfer_uri_opener ( const char *scheme ) {
struct uri_opener *opener;
for_each_table_entry ( opener, URI_OPENERS ) {
- if ( strcmp ( scheme, opener->scheme ) == 0 )
+ if ( strcasecmp ( scheme, opener->scheme ) == 0 )
return opener;
}
return NULL;
diff --git a/src/core/string.c b/src/core/string.c
index 188fe0864..9a1b9b72a 100644
--- a/src/core/string.c
+++ b/src/core/string.c
@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <strings.h>
#include <ctype.h>
/** @file
@@ -205,11 +206,24 @@ int strncmp ( const char *first, const char *second, size_t max ) {
* @ret diff Difference
*/
int strcasecmp ( const char *first, const char *second ) {
+
+ return strncasecmp ( first, second, ~( ( size_t ) 0 ) );
+}
+
+/**
+ * Compare case-insensitive strings
+ *
+ * @v first First string
+ * @v second Second string
+ * @v max Maximum length to compare
+ * @ret diff Difference
+ */
+int strncasecmp ( const char *first, const char *second, size_t max ) {
const uint8_t *first_bytes = ( ( const uint8_t * ) first );
const uint8_t *second_bytes = ( ( const uint8_t * ) second );
int diff;
- for ( ; ; first_bytes++, second_bytes++ ) {
+ for ( ; max-- ; first_bytes++, second_bytes++ ) {
diff = ( toupper ( *first_bytes ) -
toupper ( *second_bytes ) );
if ( diff )
@@ -217,6 +231,7 @@ int strcasecmp ( const char *first, const char *second ) {
if ( ! *first_bytes )
return 0;
}
+ return 0;
}
/**