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