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