Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>.
      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  * gPXE scripts
     25  *
     26  */
     27 
     28 #include <string.h>
     29 #include <stdlib.h>
     30 #include <ctype.h>
     31 #include <errno.h>
     32 #include <gpxe/image.h>
     33 
     34 struct image_type script_image_type __image_type ( PROBE_NORMAL );
     35 
     36 /**
     37  * Execute script
     38  *
     39  * @v image		Script
     40  * @ret rc		Return status code
     41  */
     42 static int script_exec ( struct image *image ) {
     43 	size_t offset = 0;
     44 	off_t eol;
     45 	size_t len;
     46 	int rc;
     47 
     48 	/* Temporarily de-register image, so that a "boot" command
     49 	 * doesn't throw us into an execution loop.
     50 	 */
     51 	unregister_image ( image );
     52 
     53 	while ( offset < image->len ) {
     54 
     55 		/* Find length of next line, excluding any terminating '\n' */
     56 		eol = memchr_user ( image->data, offset, '\n',
     57 				    ( image->len - offset ) );
     58 		if ( eol < 0 )
     59 			eol = image->len;
     60 		len = ( eol - offset );
     61 
     62 		/* Copy line, terminate with NUL, and execute command */
     63 		{
     64 			char cmdbuf[ len + 1 ];
     65 
     66 			copy_from_user ( cmdbuf, image->data, offset, len );
     67 			cmdbuf[len] = '\0';
     68 			DBG ( "$ %s\n", cmdbuf );
     69 			if ( ( rc = system ( cmdbuf ) ) != 0 ) {
     70 				DBG ( "Command \"%s\" failed: %s\n",
     71 				      cmdbuf, strerror ( rc ) );
     72 				goto done;
     73 			}
     74 		}
     75 
     76 		/* Move to next line */
     77 		offset += ( len + 1 );
     78 	}
     79 
     80 	rc = 0;
     81  done:
     82 	/* Re-register image and return */
     83 	register_image ( image );
     84 	return rc;
     85 }
     86 
     87 /**
     88  * Load script into memory
     89  *
     90  * @v image		Script
     91  * @ret rc		Return status code
     92  */
     93 static int script_load ( struct image *image ) {
     94 	static const char magic[] = "#!gpxe";
     95 	char test[ sizeof ( magic ) - 1 /* NUL */ + 1 /* terminating space */];
     96 
     97 	/* Sanity check */
     98 	if ( image->len < sizeof ( test ) ) {
     99 		DBG ( "Too short to be a script\n" );
    100 		return -ENOEXEC;
    101 	}
    102 
    103 	/* Check for magic signature */
    104 	copy_from_user ( test, image->data, 0, sizeof ( test ) );
    105 	if ( ( memcmp ( test, magic, ( sizeof ( test ) - 1 ) ) != 0 ) ||
    106 	     ! isspace ( test[ sizeof ( test ) - 1 ] ) ) {
    107 		DBG ( "Invalid magic signature\n" );
    108 		return -ENOEXEC;
    109 	}
    110 
    111 	/* This is a script */
    112 	image->type = &script_image_type;
    113 
    114 	/* We don't actually load it anywhere; we will pick the lines
    115 	 * out of the image as we need them.
    116 	 */
    117 
    118 	return 0;
    119 }
    120 
    121 /** Script image type */
    122 struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
    123 	.name = "script",
    124 	.load = script_load,
    125 	.exec = script_exec,
    126 };
    127