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