Allow images to hold references to the originating URI.
[people/pcmattman/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", name, strerror ( rc ) );
171                 image_put ( image );
172                 return rc;
173         }
174
175         image_put ( image );
176         return 0;
177 }
178
179 /**
180  * The "imgfetch"/"module" command
181  *
182  * @v argc              Argument count
183  * @v argv              Argument list
184  * @ret rc              Exit code
185  */
186 static int imgfetch_exec ( int argc, char **argv ) {
187         int rc;
188
189         if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH,
190                                          argc, argv ) ) != 0 )
191                 return rc;
192
193         return 0;
194 }
195
196 /**
197  * The "kernel" command
198  *
199  * @v argc              Argument count
200  * @v argv              Argument list
201  * @ret rc              Exit code
202  */
203 static int kernel_exec ( int argc, char **argv ) {
204         int rc;
205
206         if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 )
207                 return rc;
208
209         return 0;
210 }
211
212 /**
213  * The "initrd" command
214  *
215  * @v argc              Argument count
216  * @v argv              Argument list
217  * @ret rc              Exit code
218  */
219 static int initrd_exec ( int argc, char **argv ) {
220         int rc;
221
222         if ( ( rc = imgfetch_core_exec ( &initrd_image_type, IMG_FETCH,
223                                          argc, argv ) ) != 0 )
224                 return rc;
225
226         return 0;
227 }
228
229 /**
230  * "imgload" command syntax message
231  *
232  * @v argv              Argument list
233  */
234 static void imgload_syntax ( char **argv ) {
235         printf ( "Usage:\n"
236                  "  %s <image name>\n"
237                  "\n"
238                  "Load executable/loadable image\n",
239                  argv[0] );
240 }
241
242 /**
243  * The "imgload" command
244  *
245  * @v argc              Argument count
246  * @v argv              Argument list
247  * @ret rc              Exit code
248  */
249 static int imgload_exec ( int argc, char **argv ) {
250         static struct option longopts[] = {
251                 { "help", 0, NULL, 'h' },
252                 { NULL, 0, NULL, 0 },
253         };
254         struct image *image;
255         const char *name;
256         int c;
257         int rc;
258
259         /* Parse options */
260         while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
261                 switch ( c ) {
262                 case 'h':
263                         /* Display help text */
264                 default:
265                         /* Unrecognised/invalid option */
266                         imgload_syntax ( argv );
267                         return 1;
268                 }
269         }
270
271         /* Need exactly one image name remaining after the options */
272         if ( optind != ( argc - 1 ) ) {
273                 imgload_syntax ( argv );
274                 return 1;
275         }
276         name = argv[optind];
277
278         /* Load all specified images */
279         image = find_image ( name );
280         if ( ! image ) {
281                 printf ( "No such image: %s\n", name );
282                 return 1;
283         }
284         if ( ( rc = imgload ( image ) ) != 0 ) {
285                 printf ( "Could not load %s: %s\n", name, strerror ( rc ) );
286                 return rc;
287         }
288
289         return 0;
290 }
291
292 /**
293  * "imgargs" command syntax message
294  *
295  * @v argv              Argument list
296  */
297 static void imgargs_syntax ( char **argv ) {
298         printf ( "Usage:\n"
299                  "  %s <image name> [<arguments>...]\n"
300                  "\n"
301                  "Set arguments for executable/loadable image\n",
302                  argv[0] );
303 }
304
305 /**
306  * The "imgargs" command body
307  *
308  * @v argc              Argument count
309  * @v argv              Argument list
310  * @ret rc              Exit code
311  */
312 static int imgargs_exec ( int argc, char **argv ) {
313         static struct option longopts[] = {
314                 { "help", 0, NULL, 'h' },
315                 { NULL, 0, NULL, 0 },
316         };
317         struct image *image;
318         const char *name;
319         int c;
320         int rc;
321
322         /* Parse options */
323         while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
324                 switch ( c ) {
325                 case 'h':
326                         /* Display help text */
327                 default:
328                         /* Unrecognised/invalid option */
329                         imgargs_syntax ( argv );
330                         return 1;
331                 }
332         }
333
334         /* Need at least an image name remaining after the options */
335         if ( optind == argc ) {
336                 imgargs_syntax ( argv );
337                 return 1;
338         }
339         name = argv[optind++];
340
341         /* Fill in command line */
342         image = find_image ( name );
343         if ( ! image ) {
344                 printf ( "No such image: %s\n", name );
345                 return 1;
346         }
347         if ( ( rc = imgfill_cmdline ( image, ( argc - optind ),
348                                       &argv[optind] ) ) != 0 )
349                 return rc;
350
351
352         return 0;
353 }
354
355 /**
356  * "imgexec" command syntax message
357  *
358  * @v argv              Argument list
359  */
360 static void imgexec_syntax ( char **argv ) {
361         printf ( "Usage:\n"
362                  "  %s <image name>\n"
363                  "\n"
364                  "Execute executable/loadable image\n",
365                  argv[0] );
366 }
367
368 /**
369  * The "imgexec" command
370  *
371  * @v argc              Argument count
372  * @v argv              Argument list
373  * @ret rc              Exit code
374  */
375 static int imgexec_exec ( int argc, char **argv ) {
376         static struct option longopts[] = {
377                 { "help", 0, NULL, 'h' },
378                 { NULL, 0, NULL, 0 },
379         };
380         struct image *image;
381         const char *name = NULL;
382         int c;
383         int rc;
384
385         /* Parse options */
386         while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
387                 switch ( c ) {
388                 case 'h':
389                         /* Display help text */
390                 default:
391                         /* Unrecognised/invalid option */
392                         imgexec_syntax ( argv );
393                         return 1;
394                 }
395         }
396
397         /* Need no more than one image name */
398         if ( optind != argc )
399                 name = argv[optind++];
400         if ( optind != argc ) {
401                 imgexec_syntax ( argv );
402                 return 1;
403         }
404         
405         /* Execute specified image */
406         if ( name ) {
407                 image = find_image ( name );
408                 if ( ! image ) {
409                         printf ( "No such image: %s\n", name );
410                         return 1;
411                 }
412         } else {
413                 image = imgautoselect();
414                 if ( ! image ) {
415                         printf ( "No loaded images\n" );
416                         return 1;
417                 }
418         }
419
420         if ( ( rc = imgexec ( image ) ) != 0 ) {
421                 printf ( "Could not execute %s: %s\n",
422                          image->name, strerror ( rc ) );
423                 return 1;
424         }
425
426         return 0;
427 }
428
429 /**
430  * "imgstat" command syntax message
431  *
432  * @v argv              Argument list
433  */
434 static void imgstat_syntax ( char **argv ) {
435         printf ( "Usage:\n"
436                  "  %s\n"
437                  "\n"
438                  "List executable/loadable images\n",
439                  argv[0] );
440 }
441
442 /**
443  * The "imgstat" command
444  *
445  * @v argc              Argument count
446  * @v argv              Argument list
447  * @ret rc              Exit code
448  */
449 static int imgstat_exec ( int argc, char **argv ) {
450         static struct option longopts[] = {
451                 { "help", 0, NULL, 'h' },
452                 { NULL, 0, NULL, 0 },
453         };
454         struct image *image;
455         int c;
456
457         /* Parse options */
458         while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
459                 switch ( c ) {
460                 case 'h':
461                         /* Display help text */
462                 default:
463                         /* Unrecognised/invalid option */
464                         imgstat_syntax ( argv );
465                         return 1;
466                 }
467         }
468
469         /* No arguments */
470         if ( optind != argc ) {
471                 imgstat_syntax ( argv );
472                 return 1;
473         }
474
475         /* Show status of all images */
476         for_each_image ( image ) {
477                 imgstat ( image );
478         }
479         return 0;
480 }
481
482 /**
483  * "imgstat" command syntax message
484  *
485  * @v argv              Argument list
486  */
487 static void imgfree_syntax ( char **argv ) {
488         printf ( "Usage:\n"
489                  "  %s\n"
490                  "\n"
491                  "Free all executable/loadable images\n",
492                  argv[0] );
493 }
494
495 /**
496  * The "imgfree" command
497  *
498  * @v argc              Argument count
499  * @v argv              Argument list
500  * @ret rc              Exit code
501  */
502 static int imgfree_exec ( int argc, char **argv ) {
503         static struct option longopts[] = {
504                 { "help", 0, NULL, 'h' },
505                 { NULL, 0, NULL, 0 },
506         };
507         struct image *image;
508         struct image *tmp;
509         int c;
510
511         /* Parse options */
512         while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
513                 switch ( c ) {
514                 case 'h':
515                         /* Display help text */
516                 default:
517                         /* Unrecognised/invalid option */
518                         imgfree_syntax ( argv );
519                         return 1;
520                 }
521         }
522
523         /* No arguments */
524         if ( optind != argc ) {
525                 imgfree_syntax ( argv );
526                 return 1;
527         }
528
529         /* Free all images */
530         list_for_each_entry_safe ( image, tmp, &images, list ) {
531                 imgfree ( image );
532         }
533         return 0;
534 }
535
536 /** Image management commands */
537 struct command image_commands[] __command = {
538         {
539                 .name = "imgfetch",
540                 .exec = imgfetch_exec,
541         },
542         {
543                 .name = "module",
544                 .exec = imgfetch_exec, /* synonym for "imgfetch" */
545         },
546         {
547                 .name = "kernel",
548                 .exec = kernel_exec,
549         },
550         {
551                 .name = "initrd",
552                 .exec = initrd_exec,
553         },
554         {
555                 .name = "imgload",
556                 .exec = imgload_exec,
557         },
558         {
559                 .name = "imgargs",
560                 .exec = imgargs_exec,
561         },
562         {
563                 .name = "imgexec",
564                 .exec = imgexec_exec,
565         },
566         {
567                 .name = "boot", /* synonym for "imgexec" */
568                 .exec = imgexec_exec,
569         },
570         {
571                 .name = "imgstat",
572                 .exec = imgstat_exec,
573         },
574         {
575                 .name = "imgfree",
576                 .exec = imgfree_exec,
577         },
578 };