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