* in. If bootfile isn't defined in the environment, return NULL, which should
* be interpreted as "don't prepend anything to paths".
*/
-static int get_bootfile_path(char *bootfile_path, size_t bootfile_path_size)
+static int get_bootfile_path(const char *file_path, char *bootfile_path,
+ size_t bootfile_path_size)
{
char *bootfile, *last_slash;
- size_t path_len;
+ size_t path_len = 0;
+
+ if (file_path[0] == '/')
+ goto ret;
bootfile = from_env("bootfile");
- if (!bootfile) {
- bootfile_path[0] = '\0';
- return 1;
- }
+ if (!bootfile)
+ goto ret;
last_slash = strrchr(bootfile, '/');
- if (last_slash == NULL) {
- bootfile_path[0] = '\0';
- return 1;
- }
+ if (last_slash == NULL)
+ goto ret;
path_len = (last_slash - bootfile) + 1;
strncpy(bootfile_path, bootfile, path_len);
+ ret:
bootfile_path[path_len] = '\0';
return 1;
}
+static int (*do_getfile)(char *file_path, char *file_addr);
+
+static int do_get_tftp(char *file_path, char *file_addr)
+{
+ char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
+
+ tftp_argv[1] = file_addr;
+ tftp_argv[2] = file_path;
+
+ if (do_tftpb(NULL, 0, 3, tftp_argv))
+ return -ENOENT;
+
+ return 1;
+}
+
+static char *fs_argv[5];
+
+static int do_get_ext2(char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_EXT2
+ fs_argv[0] = "ext2load";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = file_path;
+
+ if (!do_ext2load(NULL, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+static int do_get_fat(char *file_path, char *file_addr)
+{
+#ifdef CONFIG_CMD_FAT
+ fs_argv[0] = "fatload";
+ fs_argv[3] = file_addr;
+ fs_argv[4] = file_path;
+
+ if (!do_fat_fsload(NULL, 0, 5, fs_argv))
+ return 1;
+#endif
+ return -ENOENT;
+}
+
+
+
/*
* As in pxelinux, paths to files referenced from files we retrieve are
* relative to the location of bootfile. get_relfile takes such a path and
size_t path_len;
char relfile[MAX_TFTP_PATH_LEN+1];
char addr_buf[10];
- char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
int err;
- err = get_bootfile_path(relfile, sizeof(relfile));
+ err = get_bootfile_path(file_path, relfile, sizeof(relfile));
if (err < 0)
return err;
sprintf(addr_buf, "%p", file_addr);
- tftp_argv[1] = addr_buf;
- tftp_argv[2] = relfile;
-
- if (do_tftpb(NULL, 0, 3, tftp_argv))
- return -ENOENT;
-
- return 1;
+ return do_getfile(relfile, addr_buf);
}
/*
unsigned long pxefile_addr_r;
int err;
+ do_getfile = do_get_tftp;
+
if (argc != 1)
return CMD_RET_USAGE;
*/
struct pxe_label {
char *name;
+ char *menu;
char *kernel;
char *append;
char *initrd;
static void label_print(void *data)
{
struct pxe_label *label = data;
+ const char *c = label->menu ? label->menu : label->kernel;
- printf("Label: %s\n", label->name);
+ printf("%s:\t%s\n", label->name, c);
if (label->kernel)
- printf("\tkernel: %s\n", label->kernel);
+ printf("\t\tkernel: %s\n", label->kernel);
if (label->append)
- printf("\tappend: %s\n", label->append);
+ printf("\t\tappend: %s\n", label->append);
if (label->initrd)
- printf("\tinitrd: %s\n", label->initrd);
+ printf("\t\tinitrd: %s\n", label->initrd);
}
/*
T_TIMEOUT,
T_LABEL,
T_KERNEL,
+ T_LINUX,
T_APPEND,
T_INITRD,
T_LOCALBOOT,
{"prompt", T_PROMPT},
{"label", T_LABEL},
{"kernel", T_KERNEL},
+ {"linux", T_LINUX},
{"localboot", T_LOCALBOOT},
{"append", T_APPEND},
{"initrd", T_INITRD},
if (!cfg->default_label)
return -ENOMEM;
+ break;
+ case T_LABEL:
+ parse_sliteral(c, &label->menu);
break;
default:
printf("Ignoring malformed menu command: %.*s\n",
static int parse_label(char **c, struct pxe_menu *cfg)
{
struct token t;
+ int len;
char *s = *c;
struct pxe_label *label;
int err;
break;
case T_KERNEL:
+ case T_LINUX:
err = parse_sliteral(c, &label->kernel);
break;
case T_APPEND:
err = parse_sliteral(c, &label->append);
+ if (label->initrd)
+ break;
+ s = strstr(label->append, "initrd=");
+ if (!s)
+ break;
+ s += 7;
+ len = (int)(strchr(s, ' ') - s);
+ label->initrd = malloc(len + 1);
+ strncpy(label->initrd, s, len);
+ label->initrd[len] = '\0';
+
break;
case T_INITRD:
- err = parse_sliteral(c, &label->initrd);
+ if (!label->initrd)
+ err = parse_sliteral(c, &label->initrd);
break;
case T_LOCALBOOT:
struct pxe_menu *cfg;
char *pxefile_addr_str;
+ do_getfile = do_get_tftp;
+
if (argc == 1) {
pxefile_addr_str = from_env("pxefile_addr_r");
if (!pxefile_addr_str)
"get - try to retrieve a pxe file using tftp\npxe "
"boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
);
+
+/*
+ * Boots a system using a local disk syslinux/extlinux file
+ *
+ * Returns 0 on success, 1 on error.
+ */
+int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ unsigned long pxefile_addr_r;
+ struct pxe_menu *cfg;
+ char *pxefile_addr_str;
+ char *filename;
+ int prompt = 0;
+
+ if (strstr(argv[1], "-p")) {
+ prompt = 1;
+ argc--;
+ argv++;
+ }
+
+ if (argc < 4)
+ return cmd_usage(cmdtp);
+
+ if (argc < 5) {
+ pxefile_addr_str = from_env("pxefile_addr_r");
+ if (!pxefile_addr_str)
+ return 1;
+ } else {
+ pxefile_addr_str = argv[4];
+ }
+
+ if (argc < 6)
+ filename = getenv("bootfile");
+ else {
+ filename = argv[5];
+ setenv("bootfile", filename);
+ }
+
+ if (strstr(argv[3], "ext2"))
+ do_getfile = do_get_ext2;
+ else if (strstr(argv[3], "fat"))
+ do_getfile = do_get_fat;
+ else {
+ printf("Invalid filesystem: %s\n", argv[3]);
+ return 1;
+ }
+ fs_argv[1] = argv[1];
+ fs_argv[2] = argv[2];
+
+ if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
+ printf("Invalid pxefile address: %s\n", pxefile_addr_str);
+ return 1;
+ }
+
+ if (get_pxe_file(filename, (void *)pxefile_addr_r) < 0) {
+ printf("Error reading config file\n");
+ return 1;
+ }
+
+ cfg = parse_pxefile((char *)(pxefile_addr_r));
+
+ if (cfg == NULL) {
+ printf("Error parsing config file\n");
+ return 1;
+ }
+
+ if (prompt)
+ cfg->prompt = 1;
+
+ handle_pxe_menu(cfg);
+
+ destroy_pxe_menu(cfg);
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ sysboot, 7, 1, do_sysboot,
+ "command to get and boot from syslinux files",
+ "[-p] <interface> <dev[:part]> <ext2|fat> [addr] [filename]\n"
+ " - load and parse syslinux menu file 'filename' from ext2 or fat\n"
+ " filesystem on 'dev' on 'interface' to address 'addr'"
+);