/* * Copyright (C) 2007 Michael Brown . * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include #include #include #include #include #include #include /** @file * * Image management commands * */ enum image_action { IMG_FETCH = 0, IMG_LOAD, IMG_EXEC, }; /** * Fill in image command line * * @v image Image * @v nargs Argument count * @v args Argument list * @ret rc Return status code */ static int imgfill_cmdline ( struct image *image, unsigned int nargs, char **args ) { size_t len; unsigned int i; /* Determine total length of command line */ len = 1; /* NUL */ for ( i = 0 ; i < nargs ; i++ ) len += ( 1 /* possible space */ + strlen ( args[i] ) ); { char buf[len]; char *ptr = buf; /* Assemble command line */ buf[0] = '\0'; for ( i = 0 ; i < nargs ; i++ ) { ptr += sprintf ( ptr, "%s%s", ( i ? " " : "" ), args[i] ); } assert ( ptr < ( buf + len ) ); return image_set_cmdline ( image, buf ); } } /** * "imgfetch"/"module"/"kernel" command syntax message * * @v argv Argument list */ static void imgfetch_core_syntax ( char **argv, enum image_action action ) { static const char *actions[] = { [IMG_FETCH] = "Fetch", [IMG_LOAD] = "Fetch and load", [IMG_EXEC] = "Fetch and execute", }; printf ( "Usage:\n" " %s [-n|--name ] filename [arguments...]\n" "\n" "%s executable/loadable image\n", argv[0], actions[action] ); } /** * The "imgfetch"/"module"/"kernel" command body * * @v image_type Image type to assign (or NULL) * @v load Image will be automatically loaded after fetching * @v argc Argument count * @v argv Argument list * @ret rc Return status code */ static int imgfetch_core_exec ( struct image_type *image_type, enum image_action action, int argc, char **argv ) { static struct option longopts[] = { { "help", 0, NULL, 'h' }, { "name", required_argument, NULL, 'n' }, { NULL, 0, NULL, 0 }, }; struct image *image; const char *name = NULL; char *filename; int ( * image_register ) ( struct image *image ); int c; int rc; /* Parse options */ while ( ( c = getopt_long ( argc, argv, "hn:", longopts, NULL ) ) >= 0 ) { switch ( c ) { case 'n': /* Set image name */ name = optarg; break; case 'h': /* Display help text */ default: /* Unrecognised/invalid option */ imgfetch_core_syntax ( argv, action ); return -EINVAL; } } /* Need at least a filename remaining after the options */ if ( optind == argc ) { imgfetch_core_syntax ( argv, action ); return -EINVAL; } filename = argv[optind++]; if ( ! name ) name = basename ( filename ); /* Allocate image */ image = alloc_image(); if ( ! image ) { printf ( "%s\n", strerror ( -ENOMEM ) ); return -ENOMEM; } /* Fill in image name */ if ( name ) { if ( ( rc = image_set_name ( image, name ) ) != 0 ) return rc; } /* Set image type (if specified) */ image->type = image_type; /* Fill in command line */ if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), &argv[optind] ) ) != 0 ) return rc; /* Fetch the image */ switch ( action ) { case IMG_FETCH: image_register = register_image; break; case IMG_LOAD: image_register = register_and_autoload_image; break; case IMG_EXEC: image_register = register_and_autoexec_image; break; default: assert ( 0 ); return -EINVAL; } if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) { printf ( "Could not fetch %s: %s\n", filename, strerror ( rc ) ); image_put ( image ); return rc; } image_put ( image ); 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 ) { int rc; if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH, argc, argv ) ) != 0 ) return rc; 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 ) { int rc; if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 ) return rc; return 0; } /** * The "chain" command * * @v argc Argument count * @v argv Argument list * @ret rc Exit code */ static int chain_exec ( int argc, char **argv) { int rc; if ( ( rc = imgfetch_core_exec ( NULL, IMG_EXEC, argc, argv ) ) != 0 ) return rc; return 0; } /** * "imgload" command syntax message * * @v argv Argument list */ static void imgload_syntax ( char **argv ) { printf ( "Usage:\n" " %s \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 rc; } return 0; } /** * "imgargs" command syntax message * * @v argv Argument list */ static void imgargs_syntax ( char **argv ) { printf ( "Usage:\n" " %s [...]\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 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; 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 */ 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; } if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), &argv[optind] ) ) != 0 ) return rc; return 0; } /** * "imgexec" command syntax message * * @v argv Argument list */ static void imgexec_syntax ( char **argv ) { printf ( "Usage:\n" " %s \n" "\n" "Execute executable/loadable image\n", argv[0] ); } /** * The "imgexec" command * * @v argc Argument count * @v argv Argument list * @ret rc Exit code */ 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 (unique) loaded image\n" ); return 1; } } if ( ( rc = imgexec ( image ) ) != 0 ) { printf ( "Could not execute %s: %s\n", image->name, strerror ( rc ) ); return 1; } return 0; } /** * "imgstat" command syntax message * * @v argv Argument list */ static void imgstat_syntax ( char **argv ) { printf ( "Usage:\n" " %s\n" "\n" "List executable/loadable images\n", argv[0] ); } /** * The "imgstat" command * * @v argc Argument count * @v argv Argument list * @ret rc Exit code */ static int imgstat_exec ( int argc, char **argv ) { static struct option longopts[] = { { "help", 0, NULL, 'h' }, { NULL, 0, NULL, 0 }, }; struct image *image; 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 */ imgstat_syntax ( argv ); return 1; } } /* No arguments */ if ( optind != argc ) { imgstat_syntax ( argv ); return 1; } /* Show status of all images */ for_each_image ( image ) { imgstat ( image ); } return 0; } /** * "imgstat" command syntax message * * @v argv Argument list */ static void imgfree_syntax ( char **argv ) { printf ( "Usage:\n" " %s []\n" "\n" "Free one or 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; const char *name = NULL; 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; } } /* Need no more than one image name */ if ( optind != argc ) name = argv[optind++]; if ( optind != argc ) { imgfree_syntax ( argv ); return 1; } if ( name ) { /* Free specified image (may leak) */ image = find_image ( name ); if ( ! image ) { printf ( "No such image: %s\n", name ); return 1; } imgfree ( image ); } else { /* 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 = "imgfetch", .exec = imgfetch_exec, }, { .name = "module", .exec = imgfetch_exec, /* synonym for "imgfetch" */ }, { .name = "initrd", .exec = imgfetch_exec, /* synonym for "imgfetch" */ }, { .name = "kernel", .exec = kernel_exec, }, { .name = "chain", .exec = chain_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, }, };