Annotation of qemu/roms/ipxe/src/image/script.c, revision 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.