Annotation of qemu/roms/ipxe/src/image/script.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (C) 2007 Michael Brown <[email protected]>.
                      3:  *
                      4:  * This program is free software; you can redistribute it and/or
                      5:  * modify it under the terms of the GNU General Public License as
                      6:  * published by the Free Software Foundation; either version 2 of the
                      7:  * License, or any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful, but
                     10:  * WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
                     12:  * General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program; if not, write to the Free Software
                     16:  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     17:  */
                     18: 
                     19: FILE_LICENCE ( GPL2_OR_LATER );
                     20: 
                     21: /**
                     22:  * @file
                     23:  *
                     24:  * iPXE scripts
                     25:  *
                     26:  */
                     27: 
                     28: #include <string.h>
                     29: #include <stdlib.h>
                     30: #include <stdio.h>
                     31: #include <ctype.h>
                     32: #include <errno.h>
                     33: #include <getopt.h>
                     34: #include <ipxe/command.h>
                     35: #include <ipxe/parseopt.h>
                     36: #include <ipxe/image.h>
                     37: #include <ipxe/shell.h>
                     38: #include <usr/prompt.h>
                     39: #include <ipxe/script.h>
                     40: 
                     41: /** Offset within current script
                     42:  *
                     43:  * This is a global in order to allow goto_exec() to update the
                     44:  * offset.
                     45:  */
                     46: static size_t script_offset;
                     47: 
                     48: /**
                     49:  * Process script lines
                     50:  *
                     51:  * @v image            Script
                     52:  * @v process_line     Line processor
                     53:  * @v terminate                Termination check
                     54:  * @ret rc             Return status code
                     55:  */
                     56: static int process_script ( struct image *image,
                     57:                            int ( * process_line ) ( const char *line ),
                     58:                            int ( * terminate ) ( int rc ) ) {
                     59:        off_t eol;
                     60:        size_t len;
                     61:        int rc;
                     62: 
                     63:        script_offset = 0;
                     64: 
                     65:        do {
                     66:        
                     67:                /* Find length of next line, excluding any terminating '\n' */
                     68:                eol = memchr_user ( image->data, script_offset, '\n',
                     69:                                    ( image->len - script_offset ) );
                     70:                if ( eol < 0 )
                     71:                        eol = image->len;
                     72:                len = ( eol - script_offset );
                     73: 
                     74:                /* Copy line, terminate with NUL, and execute command */
                     75:                {
                     76:                        char cmdbuf[ len + 1 ];
                     77: 
                     78:                        copy_from_user ( cmdbuf, image->data,
                     79:                                         script_offset, len );
                     80:                        cmdbuf[len] = '\0';
                     81:                        DBG ( "$ %s\n", cmdbuf );
                     82: 
                     83:                        /* Move to next line */
                     84:                        script_offset += ( len + 1 );
                     85: 
                     86:                        /* Process line */
                     87:                        rc = process_line ( cmdbuf );
                     88:                        if ( terminate ( rc ) )
                     89:                                return rc;
                     90:                }
                     91: 
                     92:        } while ( script_offset < image->len );
                     93: 
                     94:        return rc;
                     95: }
                     96: 
                     97: /**
                     98:  * Terminate script processing on shell exit or command failure
                     99:  *
                    100:  * @v rc               Line processing status
                    101:  * @ret terminate      Terminate script processing
                    102:  */
                    103: static int terminate_on_exit_or_failure ( int rc ) {
                    104: 
                    105:        return ( shell_stopped ( SHELL_STOP_COMMAND_SEQUENCE ) ||
                    106:                 ( rc != 0 ) );
                    107: }
                    108: 
                    109: /**
                    110:  * Execute script line
                    111:  *
                    112:  * @v line             Line of script
                    113:  * @ret rc             Return status code
                    114:  */
                    115: static int script_exec_line ( const char *line ) {
                    116:        int rc;
                    117: 
                    118:        /* Skip label lines */
                    119:        if ( line[0] == ':' )
                    120:                return 0;
                    121: 
                    122:        /* Execute command */
                    123:        if ( ( rc = system ( line ) ) != 0 )
                    124:                return rc;
                    125: 
                    126:        return 0;
                    127: }
                    128: 
                    129: /**
                    130:  * Execute script
                    131:  *
                    132:  * @v image            Script
                    133:  * @ret rc             Return status code
                    134:  */
                    135: static int script_exec ( struct image *image ) {
                    136:        size_t saved_offset;
                    137:        int rc;
                    138: 
                    139:        /* Temporarily de-register image, so that a "boot" command
                    140:         * doesn't throw us into an execution loop.
                    141:         */
                    142:        unregister_image ( image );
                    143: 
                    144:        /* Preserve state of any currently-running script */
                    145:        saved_offset = script_offset;
                    146: 
                    147:        /* Process script */
                    148:        rc = process_script ( image, script_exec_line,
                    149:                              terminate_on_exit_or_failure );
                    150: 
                    151:        /* Restore saved state */
                    152:        script_offset = saved_offset;
                    153: 
                    154:        /* Re-register image (unless we have been replaced) */
                    155:        if ( ! image->replacement )
                    156:                register_image ( image );
                    157: 
                    158:        return rc;
                    159: }
                    160: 
                    161: /**
                    162:  * Probe script image
                    163:  *
                    164:  * @v image            Script
                    165:  * @ret rc             Return status code
                    166:  */
                    167: static int script_probe ( struct image *image ) {
                    168:        static const char ipxe_magic[] = "#!ipxe";
                    169:        static const char gpxe_magic[] = "#!gpxe";
                    170:        linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ),
                    171:                        magic_size_mismatch );
                    172:        char test[ sizeof ( ipxe_magic ) - 1 /* NUL */
                    173:                   + 1 /* terminating space */];
                    174: 
                    175:        /* Sanity check */
                    176:        if ( image->len < sizeof ( test ) ) {
                    177:                DBG ( "Too short to be a script\n" );
                    178:                return -ENOEXEC;
                    179:        }
                    180: 
                    181:        /* Check for magic signature */
                    182:        copy_from_user ( test, image->data, 0, sizeof ( test ) );
                    183:        if ( ! ( ( ( memcmp ( test, ipxe_magic, sizeof ( test ) - 1 ) == 0 ) ||
                    184:                   ( memcmp ( test, gpxe_magic, sizeof ( test ) - 1 ) == 0 )) &&
                    185:                 isspace ( test[ sizeof ( test ) - 1 ] ) ) ) {
                    186:                DBG ( "Invalid magic signature\n" );
                    187:                return -ENOEXEC;
                    188:        }
                    189: 
                    190:        return 0;
                    191: }
                    192: 
                    193: /** Script image type */
                    194: struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
                    195:        .name = "script",
                    196:        .probe = script_probe,
                    197:        .exec = script_exec,
                    198: };
                    199: 
                    200: /** "goto" options */
                    201: struct goto_options {};
                    202: 
                    203: /** "goto" option list */
                    204: static struct option_descriptor goto_opts[] = {};
                    205: 
                    206: /** "goto" command descriptor */
                    207: static struct command_descriptor goto_cmd =
                    208:        COMMAND_DESC ( struct goto_options, goto_opts, 1, 1, "<label>" );
                    209: 
                    210: /**
                    211:  * Current "goto" label
                    212:  *
                    213:  * Valid only during goto_exec().  Consider this part of a closure.
                    214:  */
                    215: static const char *goto_label;
                    216: 
                    217: /**
                    218:  * Check for presence of label
                    219:  *
                    220:  * @v line             Script line
                    221:  * @ret rc             Return status code
                    222:  */
                    223: static int goto_find_label ( const char *line ) {
                    224: 
                    225:        if ( line[0] != ':' )
                    226:                return -ENOENT;
                    227:        if ( strcmp ( goto_label, &line[1] ) != 0 )
                    228:                return -ENOENT;
                    229:        return 0;
                    230: }
                    231: 
                    232: /**
                    233:  * Terminate script processing when label is found
                    234:  *
                    235:  * @v rc               Line processing status
                    236:  * @ret terminate      Terminate script processing
                    237:  */
                    238: static int terminate_on_label_found ( int rc ) {
                    239:        return ( rc == 0 );
                    240: }
                    241: 
                    242: /**
                    243:  * "goto" command
                    244:  *
                    245:  * @v argc             Argument count
                    246:  * @v argv             Argument list
                    247:  * @ret rc             Return status code
                    248:  */
                    249: static int goto_exec ( int argc, char **argv ) {
                    250:        struct goto_options opts;
                    251:        size_t saved_offset;
                    252:        int rc;
                    253: 
                    254:        /* Parse options */
                    255:        if ( ( rc = parse_options ( argc, argv, &goto_cmd, &opts ) ) != 0 )
                    256:                return rc;
                    257: 
                    258:        /* Sanity check */
                    259:        if ( ! current_image ) {
                    260:                rc = -ENOTTY;
                    261:                printf ( "Not in a script: %s\n", strerror ( rc ) );
                    262:                return rc;
                    263:        }
                    264: 
                    265:        /* Parse label */
                    266:        goto_label = argv[optind];
                    267: 
                    268:        /* Find label */
                    269:        saved_offset = script_offset;
                    270:        if ( ( rc = process_script ( current_image, goto_find_label,
                    271:                                     terminate_on_label_found ) ) != 0 ) {
                    272:                script_offset = saved_offset;
                    273:                return rc;
                    274:        }
                    275: 
                    276:        /* Terminate processing of current command */
                    277:        shell_stop ( SHELL_STOP_COMMAND );
                    278: 
                    279:        return 0;
                    280: }
                    281: 
                    282: /** "goto" command */
                    283: struct command goto_command __command = {
                    284:        .name = "goto",
                    285:        .exec = goto_exec,
                    286: };
                    287: 
                    288: /** "prompt" options */
                    289: struct prompt_options {
                    290:        /** Key to wait for */
                    291:        unsigned int key;
                    292:        /** Timeout */
                    293:        unsigned int timeout;
                    294: };
                    295: 
                    296: /** "prompt" option list */
                    297: static struct option_descriptor prompt_opts[] = {
                    298:        OPTION_DESC ( "key", 'k', required_argument,
                    299:                      struct prompt_options, key, parse_integer ),
                    300:        OPTION_DESC ( "timeout", 't', required_argument,
                    301:                      struct prompt_options, timeout, parse_integer ),
                    302: };
                    303: 
                    304: /** "prompt" command descriptor */
                    305: static struct command_descriptor prompt_cmd =
                    306:        COMMAND_DESC ( struct prompt_options, prompt_opts, 0, MAX_ARGUMENTS,
                    307:                       "[--key <key>] [--timeout <timeout>] [<text>]" );
                    308: 
                    309: /**
                    310:  * "prompt" command
                    311:  *
                    312:  * @v argc             Argument count
                    313:  * @v argv             Argument list
                    314:  * @ret rc             Return status code
                    315:  */
                    316: static int prompt_exec ( int argc, char **argv ) {
                    317:        struct prompt_options opts;
                    318:        char *text;
                    319:        int rc;
                    320: 
                    321:        /* Parse options */
                    322:        if ( ( rc = parse_options ( argc, argv, &prompt_cmd, &opts ) ) != 0 )
                    323:                goto err_parse;
                    324: 
                    325:        /* Parse prompt text */
                    326:        text = concat_args ( &argv[optind] );
                    327:        if ( ! text ) {
                    328:                rc = -ENOMEM;
                    329:                goto err_concat;
                    330:        }
                    331: 
                    332:        /* Display prompt and wait for key */
                    333:        if ( ( rc = prompt ( text, opts.timeout, opts.key ) ) != 0 )
                    334:                goto err_prompt;
                    335: 
                    336:        /* Free prompt text */
                    337:        free ( text );
                    338: 
                    339:        return 0;
                    340: 
                    341:  err_prompt:
                    342:        free ( text );
                    343:  err_concat:
                    344:  err_parse:
                    345:        return rc;
                    346: }
                    347: 
                    348: /** "prompt" command */
                    349: struct command prompt_command __command = {
                    350:        .name = "prompt",
                    351:        .exec = prompt_exec,
                    352: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.