X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fipxe%2Fsrc%2Fimage%2Fscript.c;fp=qemu%2Froms%2Fipxe%2Fsrc%2Fimage%2Fscript.c;h=5328da8b4fcebcb19c8cff48eba768ec1a4f524a;hb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;hp=0000000000000000000000000000000000000000;hpb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;p=kvmfornfv.git diff --git a/qemu/roms/ipxe/src/image/script.c b/qemu/roms/ipxe/src/image/script.c new file mode 100644 index 000000000..5328da8b4 --- /dev/null +++ b/qemu/roms/ipxe/src/image/script.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * 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. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * iPXE scripts + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** Offset within current script + * + * This is a global in order to allow goto_exec() to update the + * offset. + */ +static size_t script_offset; + +/** + * Process script lines + * + * @v image Script + * @v process_line Line processor + * @v terminate Termination check + * @ret rc Return status code + */ +static int process_script ( struct image *image, + int ( * process_line ) ( struct image *image, + size_t offset, + const char *label, + const char *command ), + int ( * terminate ) ( int rc ) ) { + size_t len = 0; + char *line = NULL; + size_t line_offset; + char *label; + char *command; + off_t eol; + size_t frag_len; + char *tmp; + int rc; + + /* Initialise script and line offsets */ + script_offset = 0; + line_offset = 0; + + do { + + /* Find length of next line, excluding any terminating '\n' */ + eol = memchr_user ( image->data, script_offset, '\n', + ( image->len - script_offset ) ); + if ( eol < 0 ) + eol = image->len; + frag_len = ( eol - script_offset ); + + /* Allocate buffer for line */ + tmp = realloc ( line, ( len + frag_len + 1 /* NUL */ ) ); + if ( ! tmp ) { + rc = -ENOMEM; + goto err_alloc; + } + line = tmp; + + /* Copy line */ + copy_from_user ( ( line + len ), image->data, script_offset, + frag_len ); + len += frag_len; + + /* Move to next line in script */ + script_offset += ( frag_len + 1 ); + + /* Strip trailing CR, if present */ + if ( len && ( line[ len - 1 ] == '\r' ) ) + len--; + + /* Handle backslash continuations */ + if ( len && ( line[ len - 1 ] == '\\' ) ) { + len--; + rc = -EINVAL; + continue; + } + + /* Terminate line */ + line[len] = '\0'; + + /* Split line into (optional) label and command */ + command = line; + while ( isspace ( *command ) ) + command++; + if ( *command == ':' ) { + label = ++command; + while ( *command && ! isspace ( *command ) ) + command++; + if ( *command ) + *(command++) = '\0'; + } else { + label = NULL; + } + + /* Process line */ + rc = process_line ( image, line_offset, label, command ); + if ( terminate ( rc ) ) + goto err_process; + + /* Free line */ + free ( line ); + line = NULL; + len = 0; + + /* Update line offset */ + line_offset = script_offset; + + } while ( script_offset < image->len ); + + err_process: + err_alloc: + free ( line ); + return rc; +} + +/** + * Terminate script processing on shell exit or command failure + * + * @v rc Line processing status + * @ret terminate Terminate script processing + */ +static int terminate_on_exit_or_failure ( int rc ) { + + return ( shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) || + ( rc != 0 ) ); +} + +/** + * Execute script line + * + * @v image Script + * @v offset Offset within script + * @v label Label, or NULL + * @v command Command + * @ret rc Return status code + */ +static int script_exec_line ( struct image *image, size_t offset, + const char *label __unused, + const char *command ) { + int rc; + + DBGC ( image, "[%04zx] $ %s\n", offset, command ); + + /* Execute command */ + if ( ( rc = system ( command ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Execute script + * + * @v image Script + * @ret rc Return status code + */ +static int script_exec ( struct image *image ) { + size_t saved_offset; + int rc; + + /* Temporarily de-register image, so that a "boot" command + * doesn't throw us into an execution loop. + */ + unregister_image ( image ); + + /* Preserve state of any currently-running script */ + saved_offset = script_offset; + + /* Process script */ + rc = process_script ( image, script_exec_line, + terminate_on_exit_or_failure ); + + /* Restore saved state */ + script_offset = saved_offset; + + /* Re-register image (unless we have been replaced) */ + if ( ! image->replacement ) + register_image ( image ); + + return rc; +} + +/** + * Probe script image + * + * @v image Script + * @ret rc Return status code + */ +static int script_probe ( struct image *image ) { + static const char ipxe_magic[] = "#!ipxe"; + static const char gpxe_magic[] = "#!gpxe"; + linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ), + magic_size_mismatch ); + char test[ sizeof ( ipxe_magic ) - 1 /* NUL */ + + 1 /* terminating space */]; + + /* Sanity check */ + if ( image->len < sizeof ( test ) ) { + DBGC ( image, "Too short to be a script\n" ); + return -ENOEXEC; + } + + /* Check for magic signature */ + copy_from_user ( test, image->data, 0, sizeof ( test ) ); + if ( ! ( ( ( memcmp ( test, ipxe_magic, sizeof ( test ) - 1 ) == 0 ) || + ( memcmp ( test, gpxe_magic, sizeof ( test ) - 1 ) == 0 )) && + isspace ( test[ sizeof ( test ) - 1 ] ) ) ) { + DBGC ( image, "Invalid magic signature\n" ); + return -ENOEXEC; + } + + return 0; +} + +/** Script image type */ +struct image_type script_image_type __image_type ( PROBE_NORMAL ) = { + .name = "script", + .probe = script_probe, + .exec = script_exec, +}; + +/** "goto" options */ +struct goto_options {}; + +/** "goto" option list */ +static struct option_descriptor goto_opts[] = {}; + +/** "goto" command descriptor */ +static struct command_descriptor goto_cmd = + COMMAND_DESC ( struct goto_options, goto_opts, 1, 1, "