Patrick Georgi (patrick@georgi-clan.de) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/198
-gerrit
commit 876ac941e9209166c83667a7eaffe7eab98e33d2 Author: Patrick Georgi patrick.georgi@secunet.com Date: Thu Mar 24 09:13:54 2011 +0100
Allow switching between partitions on the current device
root (,1) or configfile 2:/filo.lst work now and change the active partition on the current device (as defined by "root").
Change-Id: I271f5f407297c072f35ac8410c278b1c9442d654 Signed-off-by: Patrick Georgi patrick.georgi@secunet.com --- include/grub/shared.h | 2 +- main/grub/builtins.c | 184 +++++++++++++++++++++++++++---------------------- main/grub/grub.c | 5 +- 3 files changed, 104 insertions(+), 87 deletions(-)
diff --git a/include/grub/shared.h b/include/grub/shared.h index 127b74f..9e74d7c 100644 --- a/include/grub/shared.h +++ b/include/grub/shared.h @@ -304,6 +304,6 @@ int print_completions (int is_filename, int is_completion); int check_password(char *entered, char* expected, password_t type);
/* FILO specific stuff */ -void copy_path_to_filo_bootline(char *arg, char *path, int use_rootdev); +void copy_path_to_filo_bootline(char *arg, char *path, int use_rootdev, int append);
#endif /* ! GRUB_SHARED_HEADER */ diff --git a/main/grub/builtins.c b/main/grub/builtins.c index c926b7d..e2f4612 100644 --- a/main/grub/builtins.c +++ b/main/grub/builtins.c @@ -303,8 +303,7 @@ static int configfile_func(char *arg, int flags) extern int is_opened, keep_cmdline_running;
/* Check if the file ARG is present. */ - temp_space[0]=0; - copy_path_to_filo_bootline(arg, temp_space, 1); + copy_path_to_filo_bootline(arg, temp_space, 1, 0); if (temp_space[0]==0) { return help_func("configfile",0); } @@ -316,8 +315,7 @@ static int configfile_func(char *arg, int flags) file_close();
/* Copy ARG to CONFIG_FILE. */ - memset(config_file, 0, 128); - copy_path_to_filo_bootline(arg, config_file, 1); + copy_path_to_filo_bootline(arg, config_file, 1, 0);
/* Force to load the configuration file. */ is_opened = 0; @@ -632,114 +630,140 @@ static struct builtin builtin_hiddenmenu = { };
/** + * @param arg linux style driver specifier + * @param drivername driver name (out) + * @param disk disk number (out) + * @return length of parsed string + */ +static +int parse_linux_style_driver(char *arg, char *drivername, int *disk) +{ + int i = 0; + + *disk = -1; + drivername[0] = '\0'; + while ((i < 16) && (isalpha(arg[i]))) { + drivername[i] = arg[i]; + i++; + } + + if (i > 0) { + drivername[--i] = '\0'; + *disk = arg[i]-'a'; + i++; + } + return i; +} + +/** * @param arg source pointer with grub device names * @param path destination pointer (will be filled with filo device names) * @param use_rootdev values other than zero mean the root device set by the "root" * command is taken into regard here. This has to be zero when calling from root_func. */
-void copy_path_to_filo_bootline(char *arg, char *path, int use_rootdev) +void copy_path_to_filo_bootline(char *arg, char *path, int use_rootdev, int append) { char devicename[16]; char drivername[16]; int disk, part; + unsigned long addr; int i, len;
- - /* Clean up */ memset(devicename, 0, 16); memset(drivername, 0, 16); + disk = -1; + part = -1; + addr = -1;
- /* Copy over the driver name: "hd", "ud", "sd" ... */ if (arg[0] == '(') { + // grub style device specifier i = 1; /* Read until we encounter a number, a comma or a closing * bracket */ - while ((i <= 16) && (arg[i]) && (!isdigit(arg[i])) && (arg[i] != ',') - && (arg[i] != ')')) { + while ((i <= 16) && (isalpha(arg[i]))) { drivername[i - 1] = arg[i]; i++; } - }
- disk = -1; - part = -1; - - len = strlen(drivername); - if (len) { /* We have a driver. No idea if it exists though */ - // The driver should decide this: - len++; // skip driver name + opening bracket - - // XXX put @ handling in here, too for flash@addr and mem@addr - - if (isdigit(arg[len])) { - disk = arg[len] - '0'; - len++; - if (isdigit(arg[len])) { /* More than 9 drives? */ - /* ok, get one more number. No more than 99 drives */ - disk *= 10; - disk += arg[len] - '0'; - len++; - } + if (isdigit(arg[i])) { + char *postnum; + disk = strtoul(arg+i, &postnum, 10); + i = postnum - arg; } - if (arg[len] == ',') { - len++; - part = arg[len] - '0'; - len++; - if (isdigit(arg[len])) { /* More than 9 partitions? */ - /* ok, get one more number. No more than 99 - * partitions */ - part *= 10; - part += arg[len] - '0'; - len++; - } + + if (arg[i] == ',') { + char *postnum; + part = strtoul(arg+i+1, &postnum, 10) + 1; + i = postnum - arg; } - if (arg[len] != ')') { - grub_printf("Drive Error.\n"); - // set len = 0 --> just copy the drive name - len = 0; - } else { - len++; // skip closing bracket + + if (arg[i] == '@') { + char *postnum; + addr = strtoul(arg+i+1, &postnum, 0); + i = postnum - arg; } - }
- if (disk == -1) { - int cnt = 0; - len = 0; - while ((arg[cnt] != 0) && (arg[cnt+1] != 0)) { - if (arg[cnt] == ':' && arg[cnt+1] == '/') { - /* The user did specify a FILO name already */ - len = cnt; - break; - } - cnt++; + if (arg[i] == ')') i++; + + arg += i; + } else if ((use_rootdev == 0) || (strchr(arg, ':') != NULL)) { + // linux-style device specifier or + // leading device name required (assume it's linux-style then) + i = parse_linux_style_driver(arg, drivername, &disk); + + if (isdigit(arg[i])) { + char *postnum; + part = strtoul(arg+i, &postnum, 10); + i = postnum - arg; } - } else { - if (part == -1) { // No partition - sprintf(devicename, "%s%c:", drivername, disk + 'a'); - } else { // both disk and partition - sprintf(devicename, "%s%c%d:", drivername, disk + 'a', part + 1); + + if (arg[i] == '@') { + char *postnum; + addr = strtoul(arg+i+1, &postnum, 0); + i = postnum - arg; } - strncat(path, devicename, BOOT_LINE_LENGTH); - arg += len; // skip original drive name + + if (arg[i] == ':') i++; + arg += i; }
- if (use_rootdev && !len) { // No drive was explicitly specified - if (strlen(root_device)) { // But someone set a root device - strncat(path, root_device, BOOT_LINE_LENGTH); - } + if ((disk == -1) && (part != -1) && (strlen(drivername) == 0)) { + // special case for partition-only identifiers: + // take driver and disk number from root_device + i = parse_linux_style_driver(root_device, drivername, &disk); }
- /* Copy the rest over */ - strncat(path, arg, BOOT_LINE_LENGTH); + if (!append) path[0] = 0; + if ((use_rootdev == 1) && (strlen(drivername) == 0)) { + strlcat(path, root_device, BOOT_LINE_LENGTH); + } else { + char buffer[32]; + strlcat(path, drivername, BOOT_LINE_LENGTH); + if (disk != -1) { + snprintf(buffer, 31, "%c", 'a'+disk); + strlcat(path, buffer, BOOT_LINE_LENGTH); + } + if (part != -1) { + snprintf(buffer, 31, "%d", part); + strlcat(path, buffer, BOOT_LINE_LENGTH); + } + if (addr != -1) { + snprintf(buffer, 31, "@0x%x", addr); + strlcat(path, buffer, BOOT_LINE_LENGTH); + } + buffer[0]=':'; + buffer[1]='\0'; + strlcat(path, buffer, BOOT_LINE_LENGTH); + } + strlcat(path, arg, BOOT_LINE_LENGTH); }
/* initrd */ static int initrd_func(char *arg, int flags) { - initrd_space[0]=0; // Erase string - copy_path_to_filo_bootline(arg, initrd_space, 1); + copy_path_to_filo_bootline(arg, initrd_space, 1, 0); if (!file_open(initrd_space)) { initrd_space[0]=0; // Erase string errnum = ERR_FILE_NOT_FOUND; @@ -877,12 +901,8 @@ static int kernel_func(char *arg, int flags)
kernel_type = KERNEL_TYPE_NONE;
- /* clear out boot_line. Kernel is the first thing */ - boot_line[0] = 0; // Erase string - /* Get the real boot line and extract the kernel name */ - temp_space[0] = 0; // Erase string - copy_path_to_filo_bootline(arg, temp_space, 1); + copy_path_to_filo_bootline(arg, temp_space, 1, 0); i=0; while ((temp_space[i] != 0) && (temp_space[i]!=' ')) i++; temp_space[i] = 0;
@@ -897,7 +917,7 @@ static int kernel_func(char *arg, int flags) /* Needed to pass grub checks */ kernel_type = KERNEL_TYPE_LINUX;
- copy_path_to_filo_bootline(arg, boot_line, 1); + copy_path_to_filo_bootline(arg, boot_line, 1, 0);
return 0; } @@ -1319,8 +1339,7 @@ static int root_func(char *arg, int flags) { int len;
- root_device[0] = 0; /* Clear root device */ - copy_path_to_filo_bootline(arg, root_device, 0); + copy_path_to_filo_bootline(arg, root_device, 0, 0);
/* The following code handles an extra case * where the user specifies "root hde1" without @@ -1790,8 +1809,7 @@ static int cat_func(char *arg, int flags) char buf[4096]; int len;
- temp_space[0]=0; - copy_path_to_filo_bootline(arg, temp_space, 1); + copy_path_to_filo_bootline(arg, temp_space, 1, 0); if (temp_space[0]==0) { return help_func("cat",0); } diff --git a/main/grub/grub.c b/main/grub/grub.c index 7881a98..f4deedf 100644 --- a/main/grub/grub.c +++ b/main/grub/grub.c @@ -127,7 +127,7 @@ void manual_grub_menulst(void) break;
if (line[0]) { - copy_path_to_filo_bootline(line, config_file, 0); + copy_path_to_filo_bootline(line, config_file, 0, 1); break; } } @@ -143,8 +143,7 @@ int probe_menulst(char *bootdevice, char *filename) strcpy(menulst, bootdevice); strncat(menulst, filename, 256); /* Set string to zero: */ - config_file[0] = 0; - copy_path_to_filo_bootline(menulst, config_file, 0); + copy_path_to_filo_bootline(menulst, config_file, 0, 0); if (file_open(config_file)) { /* We found a config file. Bail out */ /* The valid config file name stays in config_file[] */