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