• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@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  */
imgfill_cmdline(struct image * image,unsigned int nargs,char ** args)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  */
imgfetch_core_syntax(char ** argv,enum image_action action)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  */
imgfetch_core_exec(struct image_type * image_type,enum image_action action,int argc,char ** argv)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  */
imgfetch_exec(int argc,char ** argv)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  */
kernel_exec(int argc,char ** argv)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  */
chain_exec(int argc,char ** argv)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  */
imgload_syntax(char ** argv)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  */
imgload_exec(int argc,char ** argv)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  */
imgargs_syntax(char ** argv)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  */
imgargs_exec(int argc,char ** argv)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  */
imgexec_syntax(char ** argv)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  */
imgexec_exec(int argc,char ** argv)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  */
imgstat_syntax(char ** argv)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  */
imgstat_exec(int argc,char ** argv)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  */
imgfree_syntax(char ** argv)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  */
imgfree_exec(int argc,char ** argv)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