Initial code release
[external/syslinux.git] / gpxe / src / hci / commands / image_cmd.c
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  */
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 };