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