david/ipxe
Archived
1
0
This repository has been archived on 2020-12-06. You can view files and clone it, but cannot push or open issues or pull requests.
ipxe/src/hci/commands/image_cmd.c
Michael Brown 3f43c1354e [image] Add "--timeout" parameter to image downloading commands
iPXE will detect timeout failures in several situations: network
link-up, DHCP, TCP connection attempts, unacknowledged TCP data, etc.
This does not cover all possible circumstances.  For example, if a
connection to a web server is successfully established and the web
server acknowledges the HTTP request but never sends any data in
response, then no timeout will be triggered.  There is no timeout
defined within the HTTP specifications, and the underlying TCP
connection will not generate a timeout since it has no way to know
that the HTTP layer is expecting to receive data from the server.

Add a "--timeout" parameter to "imgfetch", "chain", etc.  If no
progress is made (i.e. no data is downloaded) within the timeout
period, then the download will be aborted.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
2014-03-10 13:32:39 +00:00

442 lines
10 KiB
C

/*
* Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
FILE_LICENCE ( GPL2_OR_LATER );
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <getopt.h>
#include <ipxe/image.h>
#include <ipxe/command.h>
#include <ipxe/parseopt.h>
#include <ipxe/shell.h>
#include <usr/imgmgmt.h>
/** @file
*
* Image management commands
*
*/
/** "img{single}" options */
struct imgsingle_options {
/** Image name */
char *name;
/** Download timeout */
unsigned long timeout;
/** Replace image */
int replace;
/** Free image after execution */
int autofree;
};
/** "img{single}" option list */
static union {
/* "imgexec" takes all three options */
struct option_descriptor imgexec[4];
/* Other "img{single}" commands take only --name, --timeout,
* and --autofree
*/
struct option_descriptor imgsingle[3];
} opts = {
.imgexec = {
OPTION_DESC ( "name", 'n', required_argument,
struct imgsingle_options, name, parse_string ),
OPTION_DESC ( "timeout", 't', required_argument,
struct imgsingle_options, timeout, parse_timeout),
OPTION_DESC ( "autofree", 'a', no_argument,
struct imgsingle_options, autofree, parse_flag ),
OPTION_DESC ( "replace", 'r', no_argument,
struct imgsingle_options, replace, parse_flag ),
},
};
/** An "img{single}" family command descriptor */
struct imgsingle_descriptor {
/** Command descriptor */
struct command_descriptor *cmd;
/** Function to use to acquire the image */
int ( * acquire ) ( const char *name, unsigned long timeout,
struct image **image );
/** Pre-action to take upon image, or NULL */
void ( * preaction ) ( struct image *image );
/** Action to take upon image, or NULL */
int ( * action ) ( struct image *image,
struct imgsingle_options *opts );
/** Verb to describe action */
const char *verb;
};
/**
* The "img{single}" family of commands
*
* @v argc Argument count
* @v argv Argument list
* @v desc "img{single}" command descriptor
* @v action_name Action name (for error messages)
* @v action Action to take upon image
* @ret rc Return status code
*/
static int imgsingle_exec ( int argc, char **argv,
struct imgsingle_descriptor *desc ) {
struct imgsingle_options opts;
char *name_uri = NULL;
char *cmdline = NULL;
struct image *image;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, desc->cmd, &opts ) ) != 0 )
goto err_parse_options;
/* Parse name/URI string and command line, if present */
if ( optind < argc ) {
name_uri = argv[optind];
if ( argv[ optind + 1 ] != NULL ) {
cmdline = concat_args ( &argv[ optind + 1 ] );
if ( ! cmdline ) {
rc = -ENOMEM;
goto err_parse_cmdline;
}
}
}
/* Acquire the image */
if ( name_uri ) {
if ( ( rc = desc->acquire ( name_uri, opts.timeout,
&image ) ) != 0 )
goto err_acquire;
} else {
image = image_find_selected();
if ( ! image ) {
printf ( "No image selected\n" );
goto err_acquire;
}
}
/* Carry out command pre-action, if applicable */
if ( desc->preaction )
desc->preaction ( image );
/* Set the image name, if applicable */
if ( opts.name ) {
if ( ( rc = image_set_name ( image, opts.name ) ) != 0 ) {
printf ( "Could not name image: %s\n",
strerror ( rc ) );
goto err_set_name;
}
}
/* Set the command-line arguments, if applicable */
if ( cmdline ) {
if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 ) {
printf ( "Could not set arguments: %s\n",
strerror ( rc ) );
goto err_set_cmdline;
}
}
/* Set the auto-unregister flag, if applicable */
if ( opts.autofree )
image->flags |= IMAGE_AUTO_UNREGISTER;
/* Carry out command action, if applicable */
if ( desc->action ) {
if ( ( rc = desc->action ( image, &opts ) ) != 0 ) {
printf ( "Could not %s: %s\n",
desc->verb, strerror ( rc ) );
goto err_action;
}
}
/* Success */
rc = 0;
err_action:
err_set_cmdline:
err_set_name:
err_acquire:
free ( cmdline );
err_parse_cmdline:
err_parse_options:
return rc;
}
/** "imgfetch" command descriptor */
static struct command_descriptor imgfetch_cmd =
COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
1, MAX_ARGUMENTS, "<uri> [<arguments>...]" );
/** "imgfetch" family command descriptor */
struct imgsingle_descriptor imgfetch_desc = {
.cmd = &imgfetch_cmd,
.acquire = imgdownload_string,
};
/**
* The "imgfetch" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgfetch_exec ( int argc, char **argv ) {
return imgsingle_exec ( argc, argv, &imgfetch_desc );
}
/**
* "imgselect" command action
*
* @v image Image
* @v opts Options
* @ret rc Return status code
*/
static int imgselect ( struct image *image,
struct imgsingle_options *opts __unused ) {
return image_select ( image );
}
/** "imgselect" command descriptor */
static struct command_descriptor imgselect_cmd =
COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" );
/** "imgselect" family command descriptor */
struct imgsingle_descriptor imgselect_desc = {
.cmd = &imgselect_cmd,
.acquire = imgacquire,
.action = imgselect,
.verb = "select",
};
/**
* The "imgselect" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgselect_exec ( int argc, char **argv ) {
return imgsingle_exec ( argc, argv, &imgselect_desc );
}
/** "imgexec" command descriptor */
static struct command_descriptor imgexec_cmd =
COMMAND_DESC ( struct imgsingle_options, opts.imgexec,
0, MAX_ARGUMENTS, "[<uri|image> [<arguments>...]]" );
/**
* "imgexec" command action
*
* @v image Image
* @v opts Options
* @ret rc Return status code
*/
static int imgexec ( struct image *image, struct imgsingle_options *opts ) {
int rc;
/* Perform replacement or execution as applicable */
if ( opts->replace ) {
/* Try to replace image */
if ( ( rc = image_replace ( image ) ) != 0 )
return rc;
/* Stop script and tail-recurse into replacement image */
shell_stop ( SHELL_STOP_COMMAND_SEQUENCE );
} else {
/* Try to execute image */
if ( ( rc = image_exec ( image ) ) != 0 )
return rc;
}
return 0;
}
/** "imgexec" family command descriptor */
struct imgsingle_descriptor imgexec_desc = {
.cmd = &imgexec_cmd,
.acquire = imgacquire,
.action = imgexec,
.verb = "boot",
};
/**
* The "imgexec" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgexec_exec ( int argc, char **argv) {
return imgsingle_exec ( argc, argv, &imgexec_desc );
}
/** "imgargs" command descriptor */
static struct command_descriptor imgargs_cmd =
COMMAND_DESC ( struct imgsingle_options, opts.imgsingle,
1, MAX_ARGUMENTS, "<uri|image> [<arguments>...]" );
/** "imgargs" family command descriptor */
struct imgsingle_descriptor imgargs_desc = {
.cmd = &imgargs_cmd,
.acquire = imgacquire,
.preaction = image_clear_cmdline,
};
/**
* The "imgargs" command body
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgargs_exec ( int argc, char **argv ) {
return imgsingle_exec ( argc, argv, &imgargs_desc );
}
/** "img{multi}" options */
struct imgmulti_options {};
/** "img{multi}" option list */
static struct option_descriptor imgmulti_opts[] = {};
/** "img{multi}" command descriptor */
static struct command_descriptor imgmulti_cmd =
COMMAND_DESC ( struct imgmulti_options, imgmulti_opts, 0, MAX_ARGUMENTS,
"[<image>...]" );
/**
* The "img{multi}" family of commands
*
* @v argc Argument count
* @v argv Argument list
* @v payload Function to execute on each image
* @ret rc Return status code
*/
static int imgmulti_exec ( int argc, char **argv,
void ( * payload ) ( struct image *image ) ) {
struct imgmulti_options opts;
struct image *image;
struct image *tmp;
int i;
int rc;
/* Parse options */
if ( ( rc = parse_options ( argc, argv, &imgmulti_cmd, &opts ) ) != 0 )
return rc;
/* If no images are explicitly specified, process all images */
if ( optind == argc ) {
for_each_image_safe ( image, tmp )
payload ( image );
return 0;
}
/* Otherwise, process specified images */
for ( i = optind ; i < argc ; i++ ) {
image = find_image ( argv[i] );
if ( ! image ) {
printf ( "\"%s\": no such image\n", argv[i] );
return -ENOENT;
}
payload ( image );
}
return 0;
}
/**
* The "imgstat" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgstat_exec ( int argc, char **argv ) {
return imgmulti_exec ( argc, argv, imgstat );
}
/**
* The "imgfree" command
*
* @v argc Argument count
* @v argv Argument list
* @ret rc Return status code
*/
static int imgfree_exec ( int argc, char **argv ) {
return imgmulti_exec ( argc, argv, unregister_image );
}
/** 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 = imgselect_exec, /* synonym for "imgselect" */
},
{
.name = "chain",
.exec = imgexec_exec, /* synonym for "imgexec" */
},
{
.name = "imgselect",
.exec = imgselect_exec,
},
{
.name = "imgload",
.exec = imgselect_exec, /* synonym for "imgselect" */
},
{
.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,
},
};