1 /* 2 * Copyright (C) 2007 Michael Brown <mbrown (at) 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 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <stdint.h> 22 #include <stdlib.h> 23 #include <stdio.h> 24 #include <errno.h> 25 #include <libgen.h> 26 #include <getopt.h> 27 #include <gpxe/image.h> 28 #include <gpxe/command.h> 29 #include <usr/imgmgmt.h> 30 31 /** @file 32 * 33 * Image management commands 34 * 35 */ 36 37 enum image_action { 38 IMG_FETCH = 0, 39 IMG_LOAD, 40 IMG_EXEC, 41 }; 42 43 /** 44 * Fill in image command line 45 * 46 * @v image Image 47 * @v nargs Argument count 48 * @v args Argument list 49 * @ret rc Return status code 50 */ 51 static int imgfill_cmdline ( struct image *image, unsigned int nargs, 52 char **args ) { 53 size_t len; 54 unsigned int i; 55 56 /* Determine total length of command line */ 57 len = 1; /* NUL */ 58 for ( i = 0 ; i < nargs ; i++ ) 59 len += ( 1 /* possible space */ + strlen ( args[i] ) ); 60 61 { 62 char buf[len]; 63 char *ptr = buf; 64 65 /* Assemble command line */ 66 buf[0] = '\0'; 67 for ( i = 0 ; i < nargs ; i++ ) { 68 ptr += sprintf ( ptr, "%s%s", ( i ? " " : "" ), 69 args[i] ); 70 } 71 assert ( ptr < ( buf + len ) ); 72 73 return image_set_cmdline ( image, buf ); 74 } 75 } 76 77 /** 78 * "imgfetch"/"module"/"kernel" command syntax message 79 * 80 * @v argv Argument list 81 */ 82 static void imgfetch_core_syntax ( char **argv, enum image_action action ) { 83 static const char *actions[] = { 84 [IMG_FETCH] = "Fetch", 85 [IMG_LOAD] = "Fetch and load", 86 [IMG_EXEC] = "Fetch and execute", 87 }; 88 89 printf ( "Usage:\n" 90 " %s [-n|--name <name>] filename [arguments...]\n" 91 "\n" 92 "%s executable/loadable image\n", 93 argv[0], actions[action] ); 94 } 95 96 /** 97 * The "imgfetch"/"module"/"kernel" command body 98 * 99 * @v image_type Image type to assign (or NULL) 100 * @v load Image will be automatically loaded after fetching 101 * @v argc Argument count 102 * @v argv Argument list 103 * @ret rc Return status code 104 */ 105 static int imgfetch_core_exec ( struct image_type *image_type, 106 enum image_action action, 107 int argc, char **argv ) { 108 static struct option longopts[] = { 109 { "help", 0, NULL, 'h' }, 110 { "name", required_argument, NULL, 'n' }, 111 { NULL, 0, NULL, 0 }, 112 }; 113 struct image *image; 114 const char *name = NULL; 115 char *filename; 116 int ( * image_register ) ( struct image *image ); 117 int c; 118 int rc; 119 120 /* Parse options */ 121 while ( ( c = getopt_long ( argc, argv, "hn:", 122 longopts, NULL ) ) >= 0 ) { 123 switch ( c ) { 124 case 'n': 125 /* Set image name */ 126 name = optarg; 127 break; 128 case 'h': 129 /* Display help text */ 130 default: 131 /* Unrecognised/invalid option */ 132 imgfetch_core_syntax ( argv, action ); 133 return -EINVAL; 134 } 135 } 136 137 /* Need at least a filename remaining after the options */ 138 if ( optind == argc ) { 139 imgfetch_core_syntax ( argv, action ); 140 return -EINVAL; 141 } 142 filename = argv[optind++]; 143 if ( ! name ) 144 name = basename ( filename ); 145 146 /* Allocate image */ 147 image = alloc_image(); 148 if ( ! image ) { 149 printf ( "%s\n", strerror ( -ENOMEM ) ); 150 return -ENOMEM; 151 } 152 153 /* Fill in image name */ 154 if ( name ) { 155 if ( ( rc = image_set_name ( image, name ) ) != 0 ) 156 return rc; 157 } 158 159 /* Set image type (if specified) */ 160 image->type = image_type; 161 162 /* Fill in command line */ 163 if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), 164 &argv[optind] ) ) != 0 ) 165 return rc; 166 167 /* Fetch the image */ 168 switch ( action ) { 169 case IMG_FETCH: 170 image_register = register_image; 171 break; 172 case IMG_LOAD: 173 image_register = register_and_autoload_image; 174 break; 175 case IMG_EXEC: 176 image_register = register_and_autoexec_image; 177 break; 178 default: 179 assert ( 0 ); 180 return -EINVAL; 181 } 182 if ( ( rc = imgfetch ( image, filename, image_register ) ) != 0 ) { 183 printf ( "Could not fetch %s: %s\n", 184 filename, strerror ( rc ) ); 185 image_put ( image ); 186 return rc; 187 } 188 189 image_put ( image ); 190 return 0; 191 } 192 193 /** 194 * The "imgfetch"/"module" command 195 * 196 * @v argc Argument count 197 * @v argv Argument list 198 * @ret rc Exit code 199 */ 200 static int imgfetch_exec ( int argc, char **argv ) { 201 int rc; 202 203 if ( ( rc = imgfetch_core_exec ( NULL, IMG_FETCH, 204 argc, argv ) ) != 0 ) 205 return rc; 206 207 return 0; 208 } 209 210 /** 211 * The "kernel" command 212 * 213 * @v argc Argument count 214 * @v argv Argument list 215 * @ret rc Exit code 216 */ 217 static int kernel_exec ( int argc, char **argv ) { 218 int rc; 219 220 if ( ( rc = imgfetch_core_exec ( NULL, IMG_LOAD, argc, argv ) ) != 0 ) 221 return rc; 222 223 return 0; 224 } 225 226 /** 227 * The "chain" command 228 * 229 * @v argc Argument count 230 * @v argv Argument list 231 * @ret rc Exit code 232 */ 233 static int chain_exec ( int argc, char **argv) { 234 int rc; 235 236 if ( ( rc = imgfetch_core_exec ( NULL, IMG_EXEC, argc, argv ) ) != 0 ) 237 return rc; 238 239 return 0; 240 } 241 242 /** 243 * "imgload" command syntax message 244 * 245 * @v argv Argument list 246 */ 247 static void imgload_syntax ( char **argv ) { 248 printf ( "Usage:\n" 249 " %s <image name>\n" 250 "\n" 251 "Load executable/loadable image\n", 252 argv[0] ); 253 } 254 255 /** 256 * The "imgload" command 257 * 258 * @v argc Argument count 259 * @v argv Argument list 260 * @ret rc Exit code 261 */ 262 static int imgload_exec ( int argc, char **argv ) { 263 static struct option longopts[] = { 264 { "help", 0, NULL, 'h' }, 265 { NULL, 0, NULL, 0 }, 266 }; 267 struct image *image; 268 const char *name; 269 int c; 270 int rc; 271 272 /* Parse options */ 273 while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ 274 switch ( c ) { 275 case 'h': 276 /* Display help text */ 277 default: 278 /* Unrecognised/invalid option */ 279 imgload_syntax ( argv ); 280 return 1; 281 } 282 } 283 284 /* Need exactly one image name remaining after the options */ 285 if ( optind != ( argc - 1 ) ) { 286 imgload_syntax ( argv ); 287 return 1; 288 } 289 name = argv[optind]; 290 291 /* Load all specified images */ 292 image = find_image ( name ); 293 if ( ! image ) { 294 printf ( "No such image: %s\n", name ); 295 return 1; 296 } 297 if ( ( rc = imgload ( image ) ) != 0 ) { 298 printf ( "Could not load %s: %s\n", name, strerror ( rc ) ); 299 return rc; 300 } 301 302 return 0; 303 } 304 305 /** 306 * "imgargs" command syntax message 307 * 308 * @v argv Argument list 309 */ 310 static void imgargs_syntax ( char **argv ) { 311 printf ( "Usage:\n" 312 " %s <image name> [<arguments>...]\n" 313 "\n" 314 "Set arguments for executable/loadable image\n", 315 argv[0] ); 316 } 317 318 /** 319 * The "imgargs" command body 320 * 321 * @v argc Argument count 322 * @v argv Argument list 323 * @ret rc Exit code 324 */ 325 static int imgargs_exec ( int argc, char **argv ) { 326 static struct option longopts[] = { 327 { "help", 0, NULL, 'h' }, 328 { NULL, 0, NULL, 0 }, 329 }; 330 struct image *image; 331 const char *name; 332 int c; 333 int rc; 334 335 /* Parse options */ 336 while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ 337 switch ( c ) { 338 case 'h': 339 /* Display help text */ 340 default: 341 /* Unrecognised/invalid option */ 342 imgargs_syntax ( argv ); 343 return 1; 344 } 345 } 346 347 /* Need at least an image name remaining after the options */ 348 if ( optind == argc ) { 349 imgargs_syntax ( argv ); 350 return 1; 351 } 352 name = argv[optind++]; 353 354 /* Fill in command line */ 355 image = find_image ( name ); 356 if ( ! image ) { 357 printf ( "No such image: %s\n", name ); 358 return 1; 359 } 360 if ( ( rc = imgfill_cmdline ( image, ( argc - optind ), 361 &argv[optind] ) ) != 0 ) 362 return rc; 363 364 365 return 0; 366 } 367 368 /** 369 * "imgexec" command syntax message 370 * 371 * @v argv Argument list 372 */ 373 static void imgexec_syntax ( char **argv ) { 374 printf ( "Usage:\n" 375 " %s <image name>\n" 376 "\n" 377 "Execute executable/loadable image\n", 378 argv[0] ); 379 } 380 381 /** 382 * The "imgexec" command 383 * 384 * @v argc Argument count 385 * @v argv Argument list 386 * @ret rc Exit code 387 */ 388 static int imgexec_exec ( int argc, char **argv ) { 389 static struct option longopts[] = { 390 { "help", 0, NULL, 'h' }, 391 { NULL, 0, NULL, 0 }, 392 }; 393 struct image *image; 394 const char *name = NULL; 395 int c; 396 int rc; 397 398 /* Parse options */ 399 while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ 400 switch ( c ) { 401 case 'h': 402 /* Display help text */ 403 default: 404 /* Unrecognised/invalid option */ 405 imgexec_syntax ( argv ); 406 return 1; 407 } 408 } 409 410 /* Need no more than one image name */ 411 if ( optind != argc ) 412 name = argv[optind++]; 413 if ( optind != argc ) { 414 imgexec_syntax ( argv ); 415 return 1; 416 } 417 418 /* Execute specified image */ 419 if ( name ) { 420 image = find_image ( name ); 421 if ( ! image ) { 422 printf ( "No such image: %s\n", name ); 423 return 1; 424 } 425 } else { 426 image = imgautoselect(); 427 if ( ! image ) { 428 printf ( "No (unique) loaded image\n" ); 429 return 1; 430 } 431 } 432 433 if ( ( rc = imgexec ( image ) ) != 0 ) { 434 printf ( "Could not execute %s: %s\n", 435 image->name, strerror ( rc ) ); 436 return 1; 437 } 438 439 return 0; 440 } 441 442 /** 443 * "imgstat" command syntax message 444 * 445 * @v argv Argument list 446 */ 447 static void imgstat_syntax ( char **argv ) { 448 printf ( "Usage:\n" 449 " %s\n" 450 "\n" 451 "List executable/loadable images\n", 452 argv[0] ); 453 } 454 455 /** 456 * The "imgstat" command 457 * 458 * @v argc Argument count 459 * @v argv Argument list 460 * @ret rc Exit code 461 */ 462 static int imgstat_exec ( int argc, char **argv ) { 463 static struct option longopts[] = { 464 { "help", 0, NULL, 'h' }, 465 { NULL, 0, NULL, 0 }, 466 }; 467 struct image *image; 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 imgstat_syntax ( argv ); 478 return 1; 479 } 480 } 481 482 /* No arguments */ 483 if ( optind != argc ) { 484 imgstat_syntax ( argv ); 485 return 1; 486 } 487 488 /* Show status of all images */ 489 for_each_image ( image ) { 490 imgstat ( image ); 491 } 492 return 0; 493 } 494 495 /** 496 * "imgstat" command syntax message 497 * 498 * @v argv Argument list 499 */ 500 static void imgfree_syntax ( char **argv ) { 501 printf ( "Usage:\n" 502 " %s [<image name>]\n" 503 "\n" 504 "Free one or all executable/loadable images\n", 505 argv[0] ); 506 } 507 508 /** 509 * The "imgfree" command 510 * 511 * @v argc Argument count 512 * @v argv Argument list 513 * @ret rc Exit code 514 */ 515 static int imgfree_exec ( int argc, char **argv ) { 516 static struct option longopts[] = { 517 { "help", 0, NULL, 'h' }, 518 { NULL, 0, NULL, 0 }, 519 }; 520 struct image *image; 521 struct image *tmp; 522 const char *name = NULL; 523 int c; 524 525 /* Parse options */ 526 while ( ( c = getopt_long ( argc, argv, "h", longopts, NULL ) ) >= 0 ){ 527 switch ( c ) { 528 case 'h': 529 /* Display help text */ 530 default: 531 /* Unrecognised/invalid option */ 532 imgfree_syntax ( argv ); 533 return 1; 534 } 535 } 536 537 /* Need no more than one image name */ 538 if ( optind != argc ) 539 name = argv[optind++]; 540 if ( optind != argc ) { 541 imgfree_syntax ( argv ); 542 return 1; 543 } 544 545 if ( name ) { 546 /* Free specified image (may leak) */ 547 image = find_image ( name ); 548 if ( ! image ) { 549 printf ( "No such image: %s\n", name ); 550 return 1; 551 } 552 imgfree ( image ); 553 } else { 554 /* Free all images */ 555 list_for_each_entry_safe ( image, tmp, &images, list ) { 556 imgfree ( image ); 557 } 558 } 559 return 0; 560 } 561 562 /** Image management commands */ 563 struct command image_commands[] __command = { 564 { 565 .name = "imgfetch", 566 .exec = imgfetch_exec, 567 }, 568 { 569 .name = "module", 570 .exec = imgfetch_exec, /* synonym for "imgfetch" */ 571 }, 572 { 573 .name = "initrd", 574 .exec = imgfetch_exec, /* synonym for "imgfetch" */ 575 }, 576 { 577 .name = "kernel", 578 .exec = kernel_exec, 579 }, 580 { 581 .name = "chain", 582 .exec = chain_exec, 583 }, 584 { 585 .name = "imgload", 586 .exec = imgload_exec, 587 }, 588 { 589 .name = "imgargs", 590 .exec = imgargs_exec, 591 }, 592 { 593 .name = "imgexec", 594 .exec = imgexec_exec, 595 }, 596 { 597 .name = "boot", /* synonym for "imgexec" */ 598 .exec = imgexec_exec, 599 }, 600 { 601 .name = "imgstat", 602 .exec = imgstat_exec, 603 }, 604 { 605 .name = "imgfree", 606 .exec = imgfree_exec, 607 }, 608 }; 609