Add the "initrd" command
[gpxe.git] / src / hci / commands / image_cmd.c
index e38ecc9..900886f 100644 (file)
 
 #include <stdint.h>
 #include <stdlib.h>
+#include <errno.h>
+#include <libgen.h>
 #include <getopt.h>
 #include <vsprintf.h>
 #include <gpxe/image.h>
 #include <gpxe/command.h>
-#include <usr/fetch.h>
+#include <gpxe/initrd.h>
 #include <usr/imgmgmt.h>
 
 /** @file
  */
 
 /**
- * "fetch"/"module"/"kernel" command syntax message
+ * Fill in image command line
+ *
+ * @v image            Image
+ * @v nargs            Argument count
+ * @v args             Argument list
+ */
+void imgfill_cmdline ( struct image *image, unsigned int nargs, char **args ) {
+       size_t used = 0;
+
+       image->cmdline[0] = '\0';
+       while ( ( used < sizeof ( image->cmdline ) ) && nargs-- ) {
+               used += snprintf ( &image->cmdline[used],
+                                  ( sizeof ( image->cmdline ) - used ),
+                                  "%s%s", ( used ? " " : "" ), *(args++) );
+       }
+}
+
+/**
+ * "imgfetch"/"module"/"kernel" command syntax message
  *
  * @v argv             Argument list
  */
-static void fetch_syntax ( char **argv ) {
+static void imgfetch_core_syntax ( char **argv, int load ) {
        printf ( "Usage:\n"
                 "  %s [-n|--name <name>] filename [arguments...]\n"
                 "\n"
-                "Fetch executable/loadable image\n",
-                argv[0] );
+                "%s executable/loadable image\n",
+                argv[0], ( load ? "Fetch and load" : "Fetch" ) );
 }
 
 /**
- * The "fetch"/"module"/"kernel" command body
+ * The "imgfetch"/"module"/"kernel" command body
  *
  * @v argc             Argument count
  * @v argv             Argument list
- * @v name             Default name for image, or NULL
- * @ret rc             Exit code
+ * @v load             Image will be automatically loaded after fetching
+ * @ret image          Fetched image
+ * @ret rc             Return status code
  */
-static int fetch_exec_name ( int argc, char **argv, const char *name ) {
+static int imgfetch_core_exec ( int argc, char **argv, int load,
+                               struct image **image ) {
        static struct option longopts[] = {
                { "help", 0, NULL, 'h' },
                { "name", required_argument, NULL, 'n' },
                { NULL, 0, NULL, 0 },
        };
-       struct image *image;
-       const char *filename;
-       char cmdline[ sizeof ( image->cmdline ) ];
-       size_t used = 0;
+       const char *name = NULL;
+       char *filename;
        int c;
        int rc;
 
@@ -82,76 +102,287 @@ static int fetch_exec_name ( int argc, char **argv, const char *name ) {
                        /* Display help text */
                default:
                        /* Unrecognised/invalid option */
-                       fetch_syntax ( argv );
-                       return 1;
+                       imgfetch_core_syntax ( argv, load );
+                       return -EINVAL;
                }
        }
 
        /* Need at least a filename remaining after the options */
-       if ( optind >= argc ) {
-               fetch_syntax ( argv );
-               return 1;
+       if ( optind == argc ) {
+               imgfetch_core_syntax ( argv, load );
+               return -EINVAL;
        }
        filename = argv[optind++];
+       if ( ! name )
+               name = basename ( filename );
 
-       /* Build command line */
-       while ( ( used < sizeof ( cmdline ) ) && ( optind < argc ) ) {
-               used += snprintf ( &cmdline[used], sizeof ( cmdline ) - used,
-                                  " %s",  argv[optind++] );
+       /* Fetch the image */
+       if ( ( rc = imgfetch ( filename, name, image ) ) != 0 ) {
+               printf ( "Could not fetch %s: %s\n", name, strerror ( rc ) );
+               return rc;
        }
 
-       /* Allocate and fill struct image */
-       image = malloc ( sizeof ( *image ) );
-       if ( ! image ) {
-               printf ( "Out of memory\n" );
+       /* Fill in command line */
+       imgfill_cmdline ( *image, ( argc - optind ), &argv[optind] );
+
+       return 0;
+}
+
+/**
+ * The "imgfetch"/"module" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int imgfetch_exec ( int argc, char **argv ) {
+       struct image *image;
+       int rc;
+
+       if ( ( rc = imgfetch_core_exec ( argc, argv, 0, &image ) ) != 0 )
+               return 1;
+
+       return 0;
+}
+
+/**
+ * The "kernel" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int kernel_exec ( int argc, char **argv ) {
+       struct image *image;
+       int rc;
+
+       if ( ( rc = imgfetch_core_exec ( argc, argv, 1, &image ) != 0 ) )
                return 1;
-       }
-       memset ( image, 0, sizeof ( *image ) );
-       if ( name )
-               strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) );
-       if ( used )
-               memcpy ( image->cmdline, cmdline, sizeof ( image->cmdline ) );
 
-       /* Fetch the file */
-       if ( ( rc = fetch ( image, filename ) ) != 0 ) {
-               printf ( "Could not fetch %s: %s\n", filename,
+       /* Load image */
+       if ( ( rc = imgload ( image ) ) != 0 ) {
+               printf ( "Could not load %s: %s\n", image->name,
                         strerror ( rc ) );
-               free ( image );
                return 1;
        }
 
-       /* Register the image */
-       if ( ( rc = register_image ( image ) ) != 0 ) {
-               printf ( "Could not register %s: %s\n", filename,
-                        strerror ( rc ) );
-               free ( image );
+       return 0;
+}
+
+/**
+ * The "initrd" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int initrd_exec ( int argc, char **argv ) {
+       struct image *image;
+       int rc;
+
+       if ( ( rc = imgfetch_core_exec ( argc, argv, 0, &image ) != 0 ) )
+               return 1;
+
+       /* Mark image as an intird */
+       image->type = &initrd_image_type;
+
+       return 0;
+}
+
+/**
+ * "imgload" command syntax message
+ *
+ * @v argv             Argument list
+ */
+static void imgload_syntax ( char **argv ) {
+       printf ( "Usage:\n"
+                "  %s <image name>\n"
+                "\n"
+                "Load executable/loadable image\n",
+                argv[0] );
+}
+
+/**
+ * The "imgload" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int imgload_exec ( int argc, char **argv ) {
+       static struct option longopts[] = {
+               { "help", 0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+       struct image *image;
+       const char *name;
+       int c;
+       int rc;
+
+       /* Parse options */
+       while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+               switch ( c ) {
+               case 'h':
+                       /* Display help text */
+               default:
+                       /* Unrecognised/invalid option */
+                       imgload_syntax ( argv );
+                       return 1;
+               }
+       }
+
+       /* Need exactly one image name remaining after the options */
+       if ( optind != ( argc - 1 ) ) {
+               imgload_syntax ( argv );
+               return 1;
+       }
+       name = argv[optind];
+
+       /* Load all specified images */
+       image = find_image ( name );
+       if ( ! image ) {
+               printf ( "No such image: %s\n", name );
+               return 1;
+       }
+       if ( ( rc = imgload ( image ) ) != 0 ) {
+               printf ( "Could not load %s: %s\n", name, strerror ( rc ) );
                return 1;
        }
 
-       imgstat ( image );
        return 0;
 }
 
 /**
- * The "fetch"/"module" command
+ * "imgargs" command syntax message
+ *
+ * @v argv             Argument list
+ */
+static void imgargs_syntax ( char **argv ) {
+       printf ( "Usage:\n"
+                "  %s <image name> [<arguments>...]\n"
+                "\n"
+                "Set arguments for executable/loadable image\n",
+                argv[0] );
+}
+
+/**
+ * The "imgargs" command body
  *
  * @v argc             Argument count
  * @v argv             Argument list
  * @ret rc             Exit code
  */
-static int fetch_exec ( int argc, char **argv ) {
-       return fetch_exec_name ( argc, argv, NULL );
+static int imgargs_exec ( int argc, char **argv ) {
+       static struct option longopts[] = {
+               { "help", 0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+       struct image *image;
+       const char *name;
+       int c;
+
+       /* Parse options */
+       while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+               switch ( c ) {
+               case 'h':
+                       /* Display help text */
+               default:
+                       /* Unrecognised/invalid option */
+                       imgargs_syntax ( argv );
+                       return 1;
+               }
+       }
+
+       /* Need at least an image name remaining after the options */
+       if ( optind == argc ) {
+               imgargs_syntax ( argv );
+               return 1;
+       }
+       name = argv[optind++];
+
+       /* Fill in command line */
+       image = find_image ( name );
+       if ( ! image ) {
+               printf ( "No such image: %s\n", name );
+               return 1;
+       }
+       imgfill_cmdline ( image, ( argc - optind ), &argv[optind] );
+
+       return 0;
+}
+
+/**
+ * "imgexec" command syntax message
+ *
+ * @v argv             Argument list
+ */
+static void imgexec_syntax ( char **argv ) {
+       printf ( "Usage:\n"
+                "  %s <image name>\n"
+                "\n"
+                "Execute executable/loadable image\n",
+                argv[0] );
 }
 
 /**
- * The "kernel" command
+ * The "imgexec" command
  *
  * @v argc             Argument count
  * @v argv             Argument list
  * @ret rc             Exit code
  */
-static int kernel_exec ( int argc, char **argv ) {
-       return fetch_exec_name ( argc, argv, "kernel" );
+static int imgexec_exec ( int argc, char **argv ) {
+       static struct option longopts[] = {
+               { "help", 0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+       struct image *image;
+       const char *name = NULL;
+       int c;
+       int rc;
+
+       /* Parse options */
+       while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+               switch ( c ) {
+               case 'h':
+                       /* Display help text */
+               default:
+                       /* Unrecognised/invalid option */
+                       imgexec_syntax ( argv );
+                       return 1;
+               }
+       }
+
+       /* Need no more than one image name */
+       if ( optind != argc )
+               name = argv[optind++];
+       if ( optind != argc ) {
+               imgexec_syntax ( argv );
+               return 1;
+       }
+       
+       /* Execute specified image */
+       if ( name ) {
+               image = find_image ( name );
+               if ( ! image ) {
+                       printf ( "No such image: %s\n", name );
+                       return 1;
+               }
+       } else {
+               image = imgautoselect();
+               if ( ! image ) {
+                       printf ( "No loaded images\n" );
+                       return 1;
+               }
+       }
+
+       if ( ( rc = imgexec ( image ) ) != 0 ) {
+               printf ( "Could not execute %s: %s\n",
+                        image->name, strerror ( rc ) );
+               return 1;
+       }
+
+       return 0;
 }
 
 /**
@@ -174,7 +405,7 @@ static void imgstat_syntax ( char **argv ) {
  * @v argv             Argument list
  * @ret rc             Exit code
  */
-static int imgstat_exec ( int argc __unused, char **argv __unused ) {
+static int imgstat_exec ( int argc, char **argv ) {
        static struct option longopts[] = {
                { "help", 0, NULL, 'h' },
                { NULL, 0, NULL, 0 },
@@ -194,7 +425,7 @@ static int imgstat_exec ( int argc __unused, char **argv __unused ) {
                }
        }
 
-       /* Need at least a filename remaining after the options */
+       /* No arguments */
        if ( optind != argc ) {
                imgstat_syntax ( argv );
                return 1;
@@ -207,22 +438,100 @@ static int imgstat_exec ( int argc __unused, char **argv __unused ) {
        return 0;
 }
 
+/**
+ * "imgstat" command syntax message
+ *
+ * @v argv             Argument list
+ */
+static void imgfree_syntax ( char **argv ) {
+       printf ( "Usage:\n"
+                "  %s\n"
+                "\n"
+                "Free all executable/loadable images\n",
+                argv[0] );
+}
+
+/**
+ * The "imgfree" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Exit code
+ */
+static int imgfree_exec ( int argc, char **argv ) {
+       static struct option longopts[] = {
+               { "help", 0, NULL, 'h' },
+               { NULL, 0, NULL, 0 },
+       };
+       struct image *image;
+       struct image *tmp;
+       int c;
+
+       /* Parse options */
+       while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){
+               switch ( c ) {
+               case 'h':
+                       /* Display help text */
+               default:
+                       /* Unrecognised/invalid option */
+                       imgfree_syntax ( argv );
+                       return 1;
+               }
+       }
+
+       /* No arguments */
+       if ( optind != argc ) {
+               imgfree_syntax ( argv );
+               return 1;
+       }
+
+       /* Free all images */
+       list_for_each_entry_safe ( image, tmp, &images, list ) {
+               imgfree ( image );
+       }
+       return 0;
+}
+
 /** Image management commands */
 struct command image_commands[] __command = {
        {
-               .name = "fetch",
-               .exec = fetch_exec,
+               .name = "imgfetch",
+               .exec = imgfetch_exec,
        },
        {
                .name = "module",
-               .exec = fetch_exec, /* synonym for "fetch" */
+               .exec = imgfetch_exec, /* synonym for "imgfetch" */
        },
        {
                .name = "kernel",
                .exec = kernel_exec,
        },
+       {
+               .name = "initrd",
+               .exec = initrd_exec,
+       },
+       {
+               .name = "imgload",
+               .exec = imgload_exec,
+       },
+       {
+               .name = "imgargs",
+               .exec = imgargs_exec,
+       },
+       {
+               .name = "imgexec",
+               .exec = imgexec_exec,
+       },
+       {
+               .name = "boot", /* synonym for "imgexec" */
+               .exec = imgexec_exec,
+       },
        {
                .name = "imgstat",
                .exec = imgstat_exec,
        },
+       {
+               .name = "imgfree",
+               .exec = imgfree_exec,
+       },
 };