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