Home | History | Annotate | Download | only in commands
      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 #include <stdint.h>
     22 #include <stdlib.h>
     23 #include <stdio.h>
     24 #include <errno.h>
     25 #include <libgen.h>
     26 #include <getopt.h>
     27 #include <gpxe/image.h>
     28 #include <gpxe/command.h>
     29 #include <usr/imgmgmt.h>
     30 
     31 /** @file
     32  *
     33  * Image management commands
     34  *
     35  */
     36 
     37 enum image_action {
     38 	IMG_FETCH = 0,
     39 	IMG_LOAD,
     40 	IMG_EXEC,
     41 };
     42 
     43 /**
     44  * Fill in image command line
     45  *
     46  * @v image		Image
     47  * @v nargs		Argument count
     48  * @v args		Argument list
     49  * @ret rc		Return status code
     50  */
     51 static int imgfill_cmdline ( struct image *image, unsigned int nargs,
     52 			     char **args ) {
     53 	size_t len;
     54 	unsigned int i;
     55 
     56 	/* Determine total length of command line */
     57 	len = 1; /* NUL */
     58 	for ( i = 0 ; i < nargs ; i++ )
     59 		len += ( 1 /* possible space */ + strlen ( args[i] ) );
     60 
     61 	{
     62 		char buf[len];
     63 		char *ptr = buf;
     64 
     65 		/* Assemble command line */
     66 		buf[0] = '\0';
     67 		for ( i = 0 ; i < nargs ; i++ ) {
     68 			ptr += sprintf ( ptr, "%s%s", ( i ? " " : "" ),
     69 					 args[i] );
     70 		}
     71 		assert ( ptr < ( buf + len ) );
     72 
     73 		return image_set_cmdline ( image, buf );
     74 	}
     75 }
     76 
     77 /**
     78  * "imgfetch"/"module"/"kernel" command syntax message
     79  *
     80  * @v argv		Argument list
     81  */
     82 static void imgfetch_core_syntax ( char **argv, enum image_action action ) {
     83 	static const char *actions[] = {
     84 		[IMG_FETCH]	= "Fetch",
     85 		[IMG_LOAD]	= "Fetch and load",
     86 		[IMG_EXEC]	= "Fetch and execute",
     87 	};
     88 
     89 	printf ( "Usage:\n"
     90 		 "  %s [-n|--name <name>] filename [arguments...]\n"
     91 		 "\n"
     92 		 "%s executable/loadable image\n",
     93 		 argv[0], actions[action] );
     94 }
     95 
     96 /**
     97  * The "imgfetch"/"module"/"kernel" command body
     98  *
     99  * @v image_type	Image type to assign (or NULL)
    100  * @v load		Image will be automatically loaded after fetching
    101  * @v argc		Argument count
    102  * @v argv		Argument list
    103  * @ret rc		Return status code
    104  */
    105 static int imgfetch_core_exec ( struct image_type *image_type,
    106 				enum image_action action,
    107 				int argc, char **argv ) {
    108 	static struct option longopts[] = {
    109 		{ "help", 0, NULL, 'h' },
    110 		{ "name", required_argument, NULL, 'n' },
    111 		{ NULL, 0, NULL, 0 },
    112 	};
    113 	struct image *image;
    114 	const char *name = NULL;
    115 	char *filename;
    116 	int ( * image_register ) ( struct image *image );
    117 	int c;
    118 	int rc;
    119 
    120 	/* Parse options */
    121 	while ( ( c = getopt_long ( argc, argv, "hn:",
    122 				    longopts, NULL ) ) >= 0 ) {
    123 		switch ( c ) {
    124 		case 'n':
    125 			/* Set image name */
    126 			name = optarg;
    127 			break;
    128 		case 'h':
    129 			/* Display help text */
    130 		default:
    131 			/* Unrecognised/invalid option */
    132 			imgfetch_core_syntax ( argv, action );
    133 			return -EINVAL;
    134 		}
    135 	}
    136 
    137 	/* Need at least a filename remaining after the options */
    138 	if ( optind == argc ) {
    139 		imgfetch_core_syntax ( argv, action );
    140 		return -EINVAL;
    141 	}
    142 	filename = argv[optind++];
    143 	if ( ! name )
    144 		name = basename ( filename );
    145 
    146 	/* Allocate image */
    147 	image = alloc_image();
    148 	if ( ! image ) {
    149 		printf ( "%s\n", strerror ( -ENOMEM ) );
    150 		return -ENOMEM;
    151 	}
    152 
    153 	/* Fill in image name */
    154 	if ( name ) {
    155 		if ( ( rc = image_set_name ( image, name ) ) != 0 )
    156 			return rc;
    157 	}
    158 
    159 	/* Set image type (if specified) */
    160 	image->type = image_type;
    161 
    162 	/* Fill in command line */
    163 	if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
    164 				      &argv[optind] ) ) != 0 )
    165 		return rc;
    166 
    167 	/* Fetch the image */
    168 	switch ( action ) {
    169 	case IMG_FETCH:
    170 		image_register = register_image;
    171 		break;
    172 	case IMG_LOAD:
    173 		image_register = register_and_autoload_image;
    174 		break;
    175 	case IMG_EXEC:
    176 		image_register = register_and_autoexec_image;
    177 		break;
    178 	default:
    179 		assert ( 0 );
    180 		return -EINVAL;
    181 	}
    182 	if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) {
    183 		printf ( "Could not fetch %s: %s\n",
    184 			 filename, strerror ( rc ) );
    185 		image_put ( image );
    186 		return rc;
    187 	}
    188 
    189 	image_put ( image );
    190 	return 0;
    191 }
    192 
    193 /**
    194  * The "imgfetch"/"module" command
    195  *
    196  * @v argc		Argument count
    197  * @v argv		Argument list
    198  * @ret rc		Exit code
    199  */
    200 static int imgfetch_exec ( int argc, char **argv ) {
    201 	int rc;
    202 
    203 	if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH,
    204 					 argc, argv ) ) != 0 )
    205 		return rc;
    206 
    207 	return 0;
    208 }
    209 
    210 /**
    211  * The "kernel" command
    212  *
    213  * @v argc		Argument count
    214  * @v argv		Argument list
    215  * @ret rc		Exit code
    216  */
    217 static int kernel_exec ( int argc, char **argv ) {
    218 	int rc;
    219 
    220 	if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 )
    221 		return rc;
    222 
    223 	return 0;
    224 }
    225 
    226 /**
    227  * The "chain" command
    228  *
    229  * @v argc		Argument count
    230  * @v argv		Argument list
    231  * @ret rc		Exit code
    232  */
    233 static int chain_exec ( int argc, char **argv) {
    234 	int rc;
    235 
    236 	if ( ( rc = imgfetch_core_exec ( NULL, IMG_EXEC, argc, argv ) ) != 0 )
    237 		return rc;
    238 
    239 	return 0;
    240 }
    241 
    242 /**
    243  * "imgload" command syntax message
    244  *
    245  * @v argv		Argument list
    246  */
    247 static void imgload_syntax ( char **argv ) {
    248 	printf ( "Usage:\n"
    249 		 "  %s <image name>\n"
    250 		 "\n"
    251 		 "Load executable/loadable image\n",
    252 		 argv[0] );
    253 }
    254 
    255 /**
    256  * The "imgload" command
    257  *
    258  * @v argc		Argument count
    259  * @v argv		Argument list
    260  * @ret rc		Exit code
    261  */
    262 static int imgload_exec ( int argc, char **argv ) {
    263 	static struct option longopts[] = {
    264 		{ "help", 0, NULL, 'h' },
    265 		{ NULL, 0, NULL, 0 },
    266 	};
    267 	struct image *image;
    268 	const char *name;
    269 	int c;
    270 	int rc;
    271 
    272 	/* Parse options */
    273 	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
    274 		switch ( c ) {
    275 		case 'h':
    276 			/* Display help text */
    277 		default:
    278 			/* Unrecognised/invalid option */
    279 			imgload_syntax ( argv );
    280 			return 1;
    281 		}
    282 	}
    283 
    284 	/* Need exactly one image name remaining after the options */
    285 	if ( optind != ( argc - 1 ) ) {
    286 		imgload_syntax ( argv );
    287 		return 1;
    288 	}
    289 	name = argv[optind];
    290 
    291 	/* Load all specified images */
    292 	image = find_image ( name );
    293 	if ( ! image ) {
    294 		printf ( "No such image: %s\n", name );
    295 		return 1;
    296 	}
    297 	if ( ( rc = imgload ( image ) ) != 0 ) {
    298 		printf ( "Could not load %s: %s\n", name, strerror ( rc ) );
    299 		return rc;
    300 	}
    301 
    302 	return 0;
    303 }
    304 
    305 /**
    306  * "imgargs" command syntax message
    307  *
    308  * @v argv		Argument list
    309  */
    310 static void imgargs_syntax ( char **argv ) {
    311 	printf ( "Usage:\n"
    312 		 "  %s <image name> [<arguments>...]\n"
    313 		 "\n"
    314 		 "Set arguments for executable/loadable image\n",
    315 		 argv[0] );
    316 }
    317 
    318 /**
    319  * The "imgargs" command body
    320  *
    321  * @v argc		Argument count
    322  * @v argv		Argument list
    323  * @ret rc		Exit code
    324  */
    325 static int imgargs_exec ( int argc, char **argv ) {
    326 	static struct option longopts[] = {
    327 		{ "help", 0, NULL, 'h' },
    328 		{ NULL, 0, NULL, 0 },
    329 	};
    330 	struct image *image;
    331 	const char *name;
    332 	int c;
    333 	int rc;
    334 
    335 	/* Parse options */
    336 	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
    337 		switch ( c ) {
    338 		case 'h':
    339 			/* Display help text */
    340 		default:
    341 			/* Unrecognised/invalid option */
    342 			imgargs_syntax ( argv );
    343 			return 1;
    344 		}
    345 	}
    346 
    347 	/* Need at least an image name remaining after the options */
    348 	if ( optind == argc ) {
    349 		imgargs_syntax ( argv );
    350 		return 1;
    351 	}
    352 	name = argv[optind++];
    353 
    354 	/* Fill in command line */
    355 	image = find_image ( name );
    356 	if ( ! image ) {
    357 		printf ( "No such image: %s\n", name );
    358 		return 1;
    359 	}
    360 	if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
    361 				      &argv[optind] ) ) != 0 )
    362 		return rc;
    363 
    364 
    365 	return 0;
    366 }
    367 
    368 /**
    369  * "imgexec" command syntax message
    370  *
    371  * @v argv		Argument list
    372  */
    373 static void imgexec_syntax ( char **argv ) {
    374 	printf ( "Usage:\n"
    375 		 "  %s <image name>\n"
    376 		 "\n"
    377 		 "Execute executable/loadable image\n",
    378 		 argv[0] );
    379 }
    380 
    381 /**
    382  * The "imgexec" command
    383  *
    384  * @v argc		Argument count
    385  * @v argv		Argument list
    386  * @ret rc		Exit code
    387  */
    388 static int imgexec_exec ( int argc, char **argv ) {
    389 	static struct option longopts[] = {
    390 		{ "help", 0, NULL, 'h' },
    391 		{ NULL, 0, NULL, 0 },
    392 	};
    393 	struct image *image;
    394 	const char *name = NULL;
    395 	int c;
    396 	int rc;
    397 
    398 	/* Parse options */
    399 	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
    400 		switch ( c ) {
    401 		case 'h':
    402 			/* Display help text */
    403 		default:
    404 			/* Unrecognised/invalid option */
    405 			imgexec_syntax ( argv );
    406 			return 1;
    407 		}
    408 	}
    409 
    410 	/* Need no more than one image name */
    411 	if ( optind != argc )
    412 		name = argv[optind++];
    413 	if ( optind != argc ) {
    414 		imgexec_syntax ( argv );
    415 		return 1;
    416 	}
    417 
    418 	/* Execute specified image */
    419 	if ( name ) {
    420 		image = find_image ( name );
    421 		if ( ! image ) {
    422 			printf ( "No such image: %s\n", name );
    423 			return 1;
    424 		}
    425 	} else {
    426 		image = imgautoselect();
    427 		if ( ! image ) {
    428 			printf ( "No (unique) loaded image\n" );
    429 			return 1;
    430 		}
    431 	}
    432 
    433 	if ( ( rc = imgexec ( image ) ) != 0 ) {
    434 		printf ( "Could not execute %s: %s\n",
    435 			 image->name, strerror ( rc ) );
    436 		return 1;
    437 	}
    438 
    439 	return 0;
    440 }
    441 
    442 /**
    443  * "imgstat" command syntax message
    444  *
    445  * @v argv		Argument list
    446  */
    447 static void imgstat_syntax ( char **argv ) {
    448 	printf ( "Usage:\n"
    449 		 "  %s\n"
    450 		 "\n"
    451 		 "List executable/loadable images\n",
    452 		 argv[0] );
    453 }
    454 
    455 /**
    456  * The "imgstat" command
    457  *
    458  * @v argc		Argument count
    459  * @v argv		Argument list
    460  * @ret rc		Exit code
    461  */
    462 static int imgstat_exec ( int argc, char **argv ) {
    463 	static struct option longopts[] = {
    464 		{ "help", 0, NULL, 'h' },
    465 		{ NULL, 0, NULL, 0 },
    466 	};
    467 	struct image *image;
    468 	int c;
    469 
    470 	/* Parse options */
    471 	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
    472 		switch ( c ) {
    473 		case 'h':
    474 			/* Display help text */
    475 		default:
    476 			/* Unrecognised/invalid option */
    477 			imgstat_syntax ( argv );
    478 			return 1;
    479 		}
    480 	}
    481 
    482 	/* No arguments */
    483 	if ( optind != argc ) {
    484 		imgstat_syntax ( argv );
    485 		return 1;
    486 	}
    487 
    488 	/* Show status of all images */
    489 	for_each_image ( image ) {
    490 		imgstat ( image );
    491 	}
    492 	return 0;
    493 }
    494 
    495 /**
    496  * "imgstat" command syntax message
    497  *
    498  * @v argv		Argument list
    499  */
    500 static void imgfree_syntax ( char **argv ) {
    501 	printf ( "Usage:\n"
    502 		 "  %s [<image name>]\n"
    503 		 "\n"
    504 		 "Free one or all executable/loadable images\n",
    505 		 argv[0] );
    506 }
    507 
    508 /**
    509  * The "imgfree" command
    510  *
    511  * @v argc		Argument count
    512  * @v argv		Argument list
    513  * @ret rc		Exit code
    514  */
    515 static int imgfree_exec ( int argc, char **argv ) {
    516 	static struct option longopts[] = {
    517 		{ "help", 0, NULL, 'h' },
    518 		{ NULL, 0, NULL, 0 },
    519 	};
    520 	struct image *image;
    521 	struct image *tmp;
    522 	const char *name = NULL;
    523 	int c;
    524 
    525 	/* Parse options */
    526 	while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
    527 		switch ( c ) {
    528 		case 'h':
    529 			/* Display help text */
    530 		default:
    531 			/* Unrecognised/invalid option */
    532 			imgfree_syntax ( argv );
    533 			return 1;
    534 		}
    535 	}
    536 
    537 	/* Need no more than one image name */
    538 	if ( optind != argc )
    539 		name = argv[optind++];
    540 	if ( optind != argc ) {
    541 		imgfree_syntax ( argv );
    542 		return 1;
    543 	}
    544 
    545 	if ( name ) {
    546 		/* Free specified image (may leak) */
    547 		image = find_image ( name );
    548 		if ( ! image ) {
    549 			printf ( "No such image: %s\n", name );
    550 			return 1;
    551 		}
    552 		imgfree ( image );
    553 	} else {
    554 		/* Free all images */
    555 		list_for_each_entry_safe ( image, tmp, &images, list ) {
    556 			imgfree ( image );
    557 		}
    558 	}
    559 	return 0;
    560 }
    561 
    562 /** Image management commands */
    563 struct command image_commands[] __command = {
    564 	{
    565 		.name = "imgfetch",
    566 		.exec = imgfetch_exec,
    567 	},
    568 	{
    569 		.name = "module",
    570 		.exec = imgfetch_exec, /* synonym for "imgfetch" */
    571 	},
    572 	{
    573 		.name = "initrd",
    574 		.exec = imgfetch_exec, /* synonym for "imgfetch" */
    575 	},
    576 	{
    577 		.name = "kernel",
    578 		.exec = kernel_exec,
    579 	},
    580 	{
    581 		.name = "chain",
    582 		.exec = chain_exec,
    583 	},
    584 	{
    585 		.name = "imgload",
    586 		.exec = imgload_exec,
    587 	},
    588 	{
    589 		.name = "imgargs",
    590 		.exec = imgargs_exec,
    591 	},
    592 	{
    593 		.name = "imgexec",
    594 		.exec = imgexec_exec,
    595 	},
    596 	{
    597 		.name = "boot", /* synonym for "imgexec" */
    598 		.exec = imgexec_exec,
    599 	},
    600 	{
    601 		.name = "imgstat",
    602 		.exec = imgstat_exec,
    603 	},
    604 	{
    605 		.name = "imgfree",
    606 		.exec = imgfree_exec,
    607 	},
    608 };
    609