iPXE
image_cmd.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <stdint.h>
00027 #include <stdlib.h>
00028 #include <stdio.h>
00029 #include <errno.h>
00030 #include <getopt.h>
00031 #include <ipxe/image.h>
00032 #include <ipxe/command.h>
00033 #include <ipxe/parseopt.h>
00034 #include <ipxe/shell.h>
00035 #include <usr/imgmgmt.h>
00036 
00037 /** @file
00038  *
00039  * Image management commands
00040  *
00041  */
00042 
00043 /** "img{single}" options */
00044 struct imgsingle_options {
00045         /** Image name */
00046         char *name;
00047         /** Download timeout */
00048         unsigned long timeout;
00049         /** Replace image */
00050         int replace;
00051         /** Free image after execution */
00052         int autofree;
00053 };
00054 
00055 /** "img{single}" option list */
00056 static union {
00057         /* "imgexec" takes all three options */
00058         struct option_descriptor imgexec[4];
00059         /* Other "img{single}" commands take only --name, --timeout,
00060          * and --autofree
00061          */
00062         struct option_descriptor imgsingle[3];
00063 } opts = {
00064         .imgexec = {
00065                 OPTION_DESC ( "name", 'n', required_argument,
00066                               struct imgsingle_options, name, parse_string ),
00067                 OPTION_DESC ( "timeout", 't', required_argument,
00068                               struct imgsingle_options, timeout, parse_timeout),
00069                 OPTION_DESC ( "autofree", 'a', no_argument,
00070                               struct imgsingle_options, autofree, parse_flag ),
00071                 OPTION_DESC ( "replace", 'r', no_argument,
00072                               struct imgsingle_options, replace, parse_flag ),
00073         },
00074 };
00075 
00076 /** An "img{single}" family command descriptor */
00077 struct imgsingle_descriptor {
00078         /** Command descriptor */
00079         struct command_descriptor *cmd;
00080         /** Function to use to acquire the image */
00081         int ( * acquire ) ( const char *name, unsigned long timeout,
00082                             struct image **image );
00083         /** Pre-action to take upon image, or NULL */
00084         void ( * preaction ) ( struct image *image );
00085         /** Action to take upon image, or NULL */
00086         int ( * action ) ( struct image *image,
00087                            struct imgsingle_options *opts );
00088         /** Verb to describe action */
00089         const char *verb;
00090 };
00091 
00092 /**
00093  * The "img{single}" family of commands
00094  *
00095  * @v argc              Argument count
00096  * @v argv              Argument list
00097  * @v desc              "img{single}" command descriptor
00098  * @v action_name       Action name (for error messages)
00099  * @v action            Action to take upon image
00100  * @ret rc              Return status code
00101  */
00102 static int imgsingle_exec ( int argc, char **argv,
00103                             struct imgsingle_descriptor *desc ) {
00104         struct imgsingle_options opts;
00105         char *name_uri = NULL;
00106         char *cmdline = NULL;
00107         struct image *image;
00108         int rc;
00109 
00110         /* Parse options */
00111         if ( ( rc = parse_options ( argc, argv, desc->cmd, &opts ) ) != 0 )
00112                 goto err_parse_options;
00113 
00114         /* Parse name/URI string and command line, if present */
00115         if ( optind < argc ) {
00116                 name_uri = argv[optind];
00117                 if ( argv[ optind + 1 ] != NULL ) {
00118                         cmdline = concat_args ( &argv[ optind + 1 ] );
00119                         if ( ! cmdline ) {
00120                                 rc = -ENOMEM;
00121                                 goto err_parse_cmdline;
00122                         }
00123                 }
00124         }
00125 
00126         /* Acquire the image */
00127         if ( name_uri ) {
00128                 if ( ( rc = desc->acquire ( name_uri, opts.timeout,
00129                                             &image ) ) != 0 )
00130                         goto err_acquire;
00131         } else {
00132                 image = image_find_selected();
00133                 if ( ! image ) {
00134                         printf ( "No image selected\n" );
00135                         goto err_acquire;
00136                 }
00137         }
00138 
00139         /* Carry out command pre-action, if applicable */
00140         if ( desc->preaction )
00141                 desc->preaction ( image );
00142 
00143         /* Set the image name, if applicable */
00144         if ( opts.name ) {
00145                 if ( ( rc = image_set_name ( image, opts.name ) ) != 0 ) {
00146                         printf ( "Could not name image: %s\n",
00147                                  strerror ( rc ) );
00148                         goto err_set_name;
00149                 }
00150         }
00151 
00152         /* Set the command-line arguments, if applicable */
00153         if ( cmdline ) {
00154                 if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 ) {
00155                         printf ( "Could not set arguments: %s\n",
00156                                  strerror ( rc ) );
00157                         goto err_set_cmdline;
00158                 }
00159         }
00160 
00161         /* Set the auto-unregister flag, if applicable */
00162         if ( opts.autofree )
00163                 image->flags |= IMAGE_AUTO_UNREGISTER;
00164 
00165         /* Carry out command action, if applicable */
00166         if ( desc->action ) {
00167                 if ( ( rc = desc->action ( image, &opts ) ) != 0 ) {
00168                         printf ( "Could not %s: %s\n",
00169                                  desc->verb, strerror ( rc ) );
00170                         goto err_action;
00171                 }
00172         }
00173 
00174         /* Success */
00175         rc = 0;
00176 
00177  err_action:
00178  err_set_cmdline:
00179  err_set_name:
00180  err_acquire:
00181         free ( cmdline );
00182  err_parse_cmdline:
00183  err_parse_options:
00184         return rc;
00185 }
00186 
00187 /** "imgfetch" command descriptor */
00188 static struct command_descriptor imgfetch_cmd =
00189         COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
00190                        1, MAX_ARGUMENTS, "<uri> [<arguments>...]" );
00191 
00192 /** "imgfetch" family command descriptor */
00193 struct imgsingle_descriptor imgfetch_desc = {
00194         .cmd = &imgfetch_cmd,
00195         .acquire = imgdownload_string,
00196 };
00197 
00198 /**
00199  * The "imgfetch" command
00200  *
00201  * @v argc              Argument count
00202  * @v argv              Argument list
00203  * @ret rc              Return status code
00204  */
00205 static int imgfetch_exec ( int argc, char **argv ) {
00206         return imgsingle_exec ( argc, argv, &imgfetch_desc );
00207 }
00208 
00209 /**
00210  * "imgselect" command action
00211  *
00212  * @v image             Image
00213  * @v opts              Options
00214  * @ret rc              Return status code
00215  */
00216 static int imgselect ( struct image *image,
00217                        struct imgsingle_options *opts __unused ) {
00218         return image_select ( image );
00219 }
00220 
00221 /** "imgselect" command descriptor */
00222 static struct command_descriptor imgselect_cmd =
00223         COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
00224                        1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" );
00225 
00226 /** "imgselect" family command descriptor */
00227 struct imgsingle_descriptor imgselect_desc = {
00228         .cmd = &imgselect_cmd,
00229         .acquire = imgacquire,
00230         .action = imgselect,
00231         .verb = "select",
00232 };
00233 
00234 /**
00235  * The "imgselect" command
00236  *
00237  * @v argc              Argument count
00238  * @v argv              Argument list
00239  * @ret rc              Return status code
00240  */
00241 static int imgselect_exec ( int argc, char **argv ) {
00242         return imgsingle_exec ( argc, argv, &imgselect_desc );
00243 }
00244 
00245 /** "imgexec" command descriptor */
00246 static struct command_descriptor imgexec_cmd =
00247         COMMAND_DESC ( struct imgsingle_options, opts.imgexec,
00248                        0, MAX_ARGUMENTS, "[<uri|image> [<arguments>...]]" );
00249 
00250 /**
00251  * "imgexec" command action
00252  *
00253  * @v image             Image
00254  * @v opts              Options
00255  * @ret rc              Return status code
00256  */
00257 static int imgexec ( struct image *image, struct imgsingle_options *opts ) {
00258         int rc;
00259 
00260         /* Perform replacement or execution as applicable */
00261         if ( opts->replace ) {
00262 
00263                 /* Try to replace image */
00264                 if ( ( rc = image_replace ( image ) ) != 0 )
00265                         return rc;
00266 
00267                 /* Stop script and tail-recurse into replacement image */
00268                 shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
00269 
00270         } else {
00271 
00272                 /* Try to execute image */
00273                 if ( ( rc = image_exec ( image ) ) != 0 )
00274                         return rc;
00275         }
00276 
00277         return 0;
00278 }
00279 
00280 /** "imgexec" family command descriptor */
00281 struct imgsingle_descriptor imgexec_desc = {
00282         .cmd = &imgexec_cmd,
00283         .acquire = imgacquire,
00284         .action = imgexec,
00285         .verb = "boot",
00286 };
00287 
00288 /**
00289  * The "imgexec" command
00290  *
00291  * @v argc              Argument count
00292  * @v argv              Argument list
00293  * @ret rc              Return status code
00294  */
00295 static int imgexec_exec ( int argc, char **argv) {
00296         return imgsingle_exec ( argc, argv, &imgexec_desc );
00297 }
00298 
00299 /** "imgargs" command descriptor */
00300 static struct command_descriptor imgargs_cmd =
00301         COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
00302                        1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" );
00303 
00304 /** "imgargs" family command descriptor */
00305 struct imgsingle_descriptor imgargs_desc = {
00306         .cmd = &imgargs_cmd,
00307         .acquire = imgacquire,
00308         .preaction = image_clear_cmdline,
00309 };
00310 
00311 /**
00312  * The "imgargs" command body
00313  *
00314  * @v argc              Argument count
00315  * @v argv              Argument list
00316  * @ret rc              Return status code
00317  */
00318 static int imgargs_exec ( int argc, char **argv ) {
00319         return imgsingle_exec ( argc, argv, &imgargs_desc );
00320 }
00321 
00322 /** "img{multi}" options */
00323 struct imgmulti_options {};
00324 
00325 /** "img{multi}" option list */
00326 static struct option_descriptor imgmulti_opts[] = {};
00327 
00328 /** "img{multi}" command descriptor */
00329 static struct command_descriptor imgmulti_cmd =
00330         COMMAND_DESC ( struct imgmulti_options, imgmulti_opts, 0, MAX_ARGUMENTS,
00331                        "[<image>...]" );
00332 
00333 /**
00334  * The "img{multi}" family of commands
00335  *
00336  * @v argc              Argument count
00337  * @v argv              Argument list
00338  * @v payload           Function to execute on each image
00339  * @ret rc              Return status code
00340  */
00341 static int imgmulti_exec ( int argc, char **argv,
00342                            void ( * payload ) ( struct image *image ) ) {
00343         struct imgmulti_options opts;
00344         struct image *image;
00345         struct image *tmp;
00346         int i;
00347         int rc;
00348 
00349         /* Parse options */
00350         if ( ( rc = parse_options ( argc, argv, &imgmulti_cmd, &opts ) ) != 0 )
00351                 return rc;
00352 
00353         /* If no images are explicitly specified, process all images */
00354         if ( optind == argc ) {
00355                 for_each_image_safe ( image, tmp )
00356                         payload ( image );
00357                 return 0;
00358         }
00359 
00360         /* Otherwise, process specified images */
00361         for ( i = optind ; i < argc ; i++ ) {
00362                 image = find_image ( argv[i] );
00363                 if ( ! image ) {
00364                         printf ( "\"%s\": no such image\n", argv[i] );
00365                         return -ENOENT;
00366                 }
00367                 payload ( image );
00368         }
00369 
00370         return 0;
00371 }
00372 
00373 /**
00374  * The "imgstat" command
00375  *
00376  * @v argc              Argument count
00377  * @v argv              Argument list
00378  * @ret rc              Return status code
00379  */
00380 static int imgstat_exec ( int argc, char **argv ) {
00381         return imgmulti_exec ( argc, argv, imgstat );
00382 }
00383 
00384 /**
00385  * The "imgfree" command
00386  *
00387  * @v argc              Argument count
00388  * @v argv              Argument list
00389  * @ret rc              Return status code
00390  */
00391 static int imgfree_exec ( int argc, char **argv ) {
00392         return imgmulti_exec ( argc, argv, unregister_image );
00393 }
00394 
00395 /** Image management commands */
00396 struct command image_commands[] __command = {
00397         {
00398                 .name = "imgfetch",
00399                 .exec = imgfetch_exec,
00400         },
00401         {
00402                 .name = "module",
00403                 .exec = imgfetch_exec, /* synonym for "imgfetch" */
00404         },
00405         {
00406                 .name = "initrd",
00407                 .exec = imgfetch_exec, /* synonym for "imgfetch" */
00408         },
00409         {
00410                 .name = "kernel",
00411                 .exec = imgselect_exec, /* synonym for "imgselect" */
00412         },
00413         {
00414                 .name = "chain",
00415                 .exec = imgexec_exec, /* synonym for "imgexec" */
00416         },
00417         {
00418                 .name = "imgselect",
00419                 .exec = imgselect_exec,
00420         },
00421         {
00422                 .name = "imgload",
00423                 .exec = imgselect_exec, /* synonym for "imgselect" */
00424         },
00425         {
00426                 .name = "imgargs",
00427                 .exec = imgargs_exec,
00428         },
00429         {
00430                 .name = "imgexec",
00431                 .exec = imgexec_exec,
00432         },
00433         {
00434                 .name = "boot", /* synonym for "imgexec" */
00435                 .exec = imgexec_exec,
00436         },
00437         {
00438                 .name = "imgstat",
00439                 .exec = imgstat_exec,
00440         },
00441         {
00442                 .name = "imgfree",
00443                 .exec = imgfree_exec,
00444         },
00445 };