From: Jeremy Kerr Date: Mon, 7 Jan 2008 08:15:03 +0000 (+1100) Subject: Rework device-path handling X-Git-Tag: v1.0.0~971 X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=aab818c10b1fa68b968cabc852680f8ec0fe1360 Rework device-path handling Pass full device paths around, rather than shortened device names and mountpoints. The parse() function has been updated to only take a device path; the mountpoint can be derived with mountpoint_for_device. Also, add initial handling for uuid= and label= syntaxes. This allows us to remap ps3 devices where necessary. Signed-off-by: Jeremy Kerr --- diff --git a/devices/kboot-parser.c b/devices/kboot-parser.c index b70d5fc..9388981 100644 --- a/devices/kboot-parser.c +++ b/devices/kboot-parser.c @@ -15,7 +15,7 @@ #define buf_size 1024 -static const char *mountpoint; +static const char *devpath; static int param_is_ignored(const char *param) { @@ -138,13 +138,13 @@ static int parse_option(struct boot_option *opt, char *config) /* if there's no space, it's only a kernel image with no params */ if (!pos) { - opt->boot_image_file = resolve_path(config, mountpoint); + opt->boot_image_file = resolve_path(config, devpath); opt->description = strdup(config); return 1; } *pos = 0; - opt->boot_image_file = resolve_path(config, mountpoint); + opt->boot_image_file = resolve_path(config, devpath); cmdline = malloc(buf_size); *cmdline = 0; @@ -179,7 +179,7 @@ static int parse_option(struct boot_option *opt, char *config) free(cmdline); cmdline = tmp; - opt->initrd_file = resolve_path(initrd, mountpoint); + opt->initrd_file = resolve_path(initrd, devpath); } if (root) { @@ -236,16 +236,16 @@ static void parse_buf(struct device *dev, char *buf) } } -static int parse(const char *devicepath, const char *_mountpoint) +static int parse(const char *device) { char *filepath, *buf; int fd, len, rc = 0; struct stat stat; struct device *dev; - mountpoint = _mountpoint; + devpath = device; - filepath = join_paths(mountpoint, "/etc/kboot.conf"); + filepath = resolve_path("/etc/kboot.conf", devpath); fd = open(filepath, O_RDONLY); if (fd < 0) @@ -265,7 +265,7 @@ static int parse(const char *devicepath, const char *_mountpoint) dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); - dev->id = strdup(devicepath); + dev->id = strdup(device); dev->icon_file = strdup(generic_icon_file(guess_device_type())); parse_buf(dev, buf); diff --git a/devices/native-parser.c b/devices/native-parser.c index 5f79451..24713b1 100644 --- a/devices/native-parser.c +++ b/devices/native-parser.c @@ -1,6 +1,7 @@ #include "parser.h" #include "params.h" +#include "paths.h" #include #include @@ -10,7 +11,7 @@ const char *conf_filename = "/boot/petitboot.conf"; static struct boot_option *cur_opt; static struct device *dev; -static const char *mountpoint; +static const char *devpath; int device_added; int check_and_add_device(struct device *dev) @@ -47,13 +48,13 @@ static void set_boot_option_parameter(struct boot_option *opt, opt->description = strdup(value); else if (streq(name, "image")) - opt->boot_image_file = join_paths(mountpoint, value); + opt->boot_image_file = resolve_path(value, devpath); else if (streq(name, "icon")) - opt->icon_file = join_paths(mountpoint, value); + opt->icon_file = resolve_path(value, devpath); else if (streq(name, "initrd")) - opt->initrd_file = join_paths(mountpoint, value); + opt->initrd_file =resolve_path(value, devpath); else if (streq(name, "args")) opt->boot_args = strdup(value); @@ -72,7 +73,7 @@ static void set_device_parameter(struct device *dev, dev->description = strdup(value); else if (streq(name, "icon")) - dev->icon_file = join_paths(mountpoint, value); + dev->icon_file = resolve_path(value, devpath); } static int parameter(char *param_name, char *param_value) @@ -85,19 +86,17 @@ static int parameter(char *param_name, char *param_value) } -int parse(const char *devicepath, const char *_mountpoint) +int parse(const char *device) { char *filepath; int rc; - mountpoint = _mountpoint; - - filepath = join_paths(mountpoint, conf_filename); + filepath = resolve_path(conf_filename, device); cur_opt = NULL; dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); - dev->id = strdup(devicepath); + dev->id = strdup(device); rc = pm_process(filepath, section, parameter); if (!rc) diff --git a/devices/parser-test.sh b/devices/parser-test.sh index cdd814b..140601e 100755 --- a/devices/parser-test.sh +++ b/devices/parser-test.sh @@ -11,7 +11,7 @@ function test_dir() then rootdev=$(cat "$dir/rootdev") fi - ./parser-test "$dir" $rootdev 2>/dev/null | + ./parser-test "$dir" /dev/$rootdev 2>/dev/null | diff -u "$dir/expected-output" - } diff --git a/devices/parser-tests/001/expected-output b/devices/parser-tests/001/expected-output index 9d2d0ec..bace9f7 100644 --- a/devices/parser-tests/001/expected-output +++ b/devices/parser-tests/001/expected-output @@ -1,24 +1,24 @@ -[dev 0] id: ps3da1 +[dev 0] id: /dev/ps3da1 [dev 0] name: (null) [dev 0] description: (null) [dev 0] boot_image: /usr/share/petitboot/artwork/hdd.png [opt 0] name: live [opt 0] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash -- -[opt 0] boot_image: devices/parser-tests/001/ps3da1//casper/vmlinux -[opt 0] initrd: devices/parser-tests/001/ps3da1//casper/initrd.gz +[opt 0] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux +[opt 0] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz [opt 0] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash -- [opt 1] name: live_nosplash [opt 1] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper quiet -- -[opt 1] boot_image: devices/parser-tests/001/ps3da1//casper/vmlinux -[opt 1] initrd: devices/parser-tests/001/ps3da1//casper/initrd.gz +[opt 1] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux +[opt 1] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz [opt 1] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper quiet -- [opt 2] name: driverupdates [opt 2] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash -- -[opt 2] boot_image: devices/parser-tests/001/ps3da1//casper/vmlinux -[opt 2] initrd: devices/parser-tests/001/ps3da1//casper/initrd.gz +[opt 2] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux +[opt 2] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz [opt 2] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz file=/cdrom/preseed/ubuntu.seed boot=casper debian-installer/driver-update=true quiet splash -- [opt 3] name: check [opt 3] description: /casper/vmlinux root=/dev/ram0 initrd=/casper/initrd.gz boot=casper integrity-check quiet splash -- -[opt 3] boot_image: devices/parser-tests/001/ps3da1//casper/vmlinux -[opt 3] initrd: devices/parser-tests/001/ps3da1//casper/initrd.gz +[opt 3] boot_image: devices/parser-tests/001/ps3da1/casper/vmlinux +[opt 3] initrd: devices/parser-tests/001/ps3da1/casper/initrd.gz [opt 3] boot_args: root=/dev/ram0 initrd=/casper/initrd.gz boot=casper integrity-check quiet splash -- diff --git a/devices/parser-tests/002/expected-output b/devices/parser-tests/002/expected-output index 9d2a146..304f15c 100644 --- a/devices/parser-tests/002/expected-output +++ b/devices/parser-tests/002/expected-output @@ -1,9 +1,9 @@ -[dev 0] id: ps3da1 +[dev 0] id: /dev/ps3da1 [dev 0] name: (null) [dev 0] description: [dev 0] boot_image: /usr/share/petitboot/artwork/hdd.png [opt 0] name: linux [opt 0] description: (null) -[opt 0] boot_image: devices/parser-tests/002/ps3da1//ppc/ppc64/vmlinux -[opt 0] initrd: devices/parser-tests/002/ps3da1//ppc/ppc64/ramdisk.image.gz +[opt 0] boot_image: devices/parser-tests/002/ps3da1/ppc/ppc64/vmlinux +[opt 0] initrd: devices/parser-tests/002/ps3da1/ppc/ppc64/ramdisk.image.gz [opt 0] boot_args: ro diff --git a/devices/parser-tests/003/expected-output b/devices/parser-tests/003/expected-output new file mode 100644 index 0000000..4f60310 --- /dev/null +++ b/devices/parser-tests/003/expected-output @@ -0,0 +1,9 @@ +[dev 0] id: /dev/ps3da1 +[dev 0] name: (null) +[dev 0] description: (null) +[dev 0] boot_image: /usr/share/petitboot/artwork/hdd.png +[opt 0] name: test +[opt 0] description: /dev/sda1:/vmlinux +[opt 0] boot_image: devices/parser-tests/003/ps3da1/vmlinux +[opt 0] initrd: (null) +[opt 0] boot_args: (null) diff --git a/devices/parser-tests/003/ps3da1/etc/kboot.conf b/devices/parser-tests/003/ps3da1/etc/kboot.conf new file mode 100644 index 0000000..a7bb199 --- /dev/null +++ b/devices/parser-tests/003/ps3da1/etc/kboot.conf @@ -0,0 +1,4 @@ +# test remapping sda to ps3da, when mounted from a ps3da device + +test='/dev/sda1:/vmlinux' + diff --git a/devices/parser-tests/004/expected-output b/devices/parser-tests/004/expected-output new file mode 100644 index 0000000..76a90a2 --- /dev/null +++ b/devices/parser-tests/004/expected-output @@ -0,0 +1,9 @@ +[dev 0] id: /dev/sda1 +[dev 0] name: (null) +[dev 0] description: (null) +[dev 0] boot_image: /usr/share/petitboot/artwork/hdd.png +[opt 0] name: test +[opt 0] description: /dev/sda1:/vmlinux +[opt 0] boot_image: devices/parser-tests/004/sda1/vmlinux +[opt 0] initrd: (null) +[opt 0] boot_args: (null) diff --git a/devices/parser-tests/004/rootdev b/devices/parser-tests/004/rootdev new file mode 100644 index 0000000..36cfa0d --- /dev/null +++ b/devices/parser-tests/004/rootdev @@ -0,0 +1 @@ +sda1 diff --git a/devices/parser-tests/004/sda1/etc/kboot.conf b/devices/parser-tests/004/sda1/etc/kboot.conf new file mode 100644 index 0000000..9755f77 --- /dev/null +++ b/devices/parser-tests/004/sda1/etc/kboot.conf @@ -0,0 +1,4 @@ +# test remapping sda to ps3da, when mounted from a plain sd device + +test='/dev/sda1:/vmlinux' + diff --git a/devices/parser.c b/devices/parser.c index 00f3659..5e50dcb 100644 --- a/devices/parser.c +++ b/devices/parser.c @@ -26,7 +26,7 @@ void iterate_parsers(const char *devpath, const char *mountpoint) for (i = 0; parsers[i]; i++) { pb_log("\ttrying parser '%s'\n", parsers[i]->name); /* just use a dummy device path for now */ - if (parsers[i]->parse(devpath, mountpoint_for_device(devpath))) + if (parsers[i]->parse(devpath)) return; } pb_log("\tno boot_options found\n"); @@ -67,20 +67,6 @@ void free_boot_option(struct boot_option *opt) free(opt); } -char *join_paths(const char *a, const char *b) -{ - char *full_path; - - full_path = malloc(strlen(a) + strlen(b) + 2); - - strcpy(full_path, a); - if (b[0] != '/') - strcat(full_path, "/"); - strcat(full_path, b); - - return full_path; -} - const char *generic_icon_file(enum generic_icon_type type) { switch (type) { diff --git a/devices/parser.h b/devices/parser.h index 840ca1b..9c6fb35 100644 --- a/devices/parser.h +++ b/devices/parser.h @@ -8,7 +8,7 @@ struct parser { char *name; int priority; - int (*parse)(const char *devicepath, const char *mountpoint); + int (*parse)(const char *device); struct parser *next; }; @@ -28,8 +28,6 @@ void iterate_parsers(const char *devpath, const char *mountpoint); void free_device(struct device *dev); void free_boot_option(struct boot_option *opt); -char *join_paths(const char *a, const char *b); - const char *generic_icon_file(enum generic_icon_type type); /* functions provided by udev-helper or the test wrapper */ @@ -37,7 +35,7 @@ void pb_log(const char *fmt, ...); int mount_device(const char *dev_path); -char *resolve_path(const char *path, const char *default_mountpoint); +char *resolve_path(const char *path, const char *current_dev); const char *mountpoint_for_device(const char *dev_path); enum generic_icon_type guess_device_type(void); diff --git a/devices/paths.c b/devices/paths.c index a1df5d2..e9bf6cb 100644 --- a/devices/paths.c +++ b/devices/paths.c @@ -15,46 +15,104 @@ struct device_map { #define DEVICE_MAP_SIZE 32 static struct device_map device_map[DEVICE_MAP_SIZE]; -const char *mountpoint_for_device(const char *dev_path) +static char *encode_label(const char *label) { + char *str, *c; int i; - const char *basename; - /* shorten '/dev/foo' to 'foo' */ - basename = strrchr(dev_path, '/'); - if (basename) - basename++; - else - basename = dev_path; + /* the label can be expanded by up to four times */ + str = malloc(strlen(label) * 4 + 1); + c = str; + + for (i = 0; i < strlen(label); i++) { + + if (label[i] == '/' || label[i] == '\\') { + sprintf(c, "\\x%02x", label[i]); + c += 4; + continue; + } + + *(c++) = label[i]; + } + + *c = '\0'; + + return str; +} + +char *parse_device_path(const char *dev_str, const char *cur_dev) +{ + char *dev, tmp[256], *enc; + + if (!strncasecmp(dev_str, "uuid=", 5)) { + asprintf(&dev, "/dev/disk/by-uuid/%s", dev_str + 5); + return dev; + } + + if (!strncasecmp(dev_str, "label=", 6)) { + enc = encode_label(dev_str + 6); + asprintf(&dev, "/dev/disk/by-label/%s", enc); + free(enc); + return dev; + } + + /* normalise '/dev/foo' to 'foo' for easy comparisons, we'll expand + * back before returning. + */ + if (!strncmp(dev_str, "/dev/", 5)) + dev_str += 5; + + /* PS3 hack: if we're reading from a ps3dx device, and we refer to + * a sdx device, remap to ps3dx */ + if (cur_dev && !strncmp(cur_dev, "/dev/ps3d", 9) + && !strncmp(dev_str, "sd", 2)) { + snprintf(tmp, 255, "ps3d%s", dev_str + 2); + dev_str = tmp; + } + + return join_paths("/dev", dev_str); +} + +const char *mountpoint_for_device(const char *dev) +{ + int i; + + if (!strncmp(dev, "/dev/", 5)) + dev += 5; /* check existing entries in the map */ for (i = 0; (i < DEVICE_MAP_SIZE) && device_map[i].dev; i++) - if (!strcmp(device_map[i].dev, basename)) + if (!strcmp(device_map[i].dev, dev)) return device_map[i].mnt; if (i == DEVICE_MAP_SIZE) return NULL; - device_map[i].dev = strdup(dev_path); - asprintf(&device_map[i].mnt, "%s/%s", mount_base, basename); + device_map[i].dev = strdup(dev); + device_map[i].mnt = join_paths(mount_base, dev); return device_map[i].mnt; } -char *resolve_path(const char *path, const char *current_mountpoint) +char *resolve_path(const char *path, const char *current_dev) { char *ret; const char *devpath, *sep; sep = strchr(path, ':'); if (!sep) { - devpath = current_mountpoint; - asprintf(&ret, "%s/%s", devpath, path); + devpath = mountpoint_for_device(current_dev); + ret = join_paths(devpath, path); } else { - /* copy just the device name into tmp */ - char *dev = strndup(path, sep - path); + /* parse just the device name into dev */ + char *tmp, *dev; + tmp = strndup(path, sep - path); + dev = parse_device_path(tmp, current_dev); + devpath = mountpoint_for_device(dev); - asprintf(&ret, "%s/%s", devpath, sep + 1); + ret = join_paths(devpath, sep + 1); + free(dev); + free(tmp); } return ret; @@ -67,3 +125,17 @@ void set_mount_base(const char *path) mount_base = strdup(path); } +char *join_paths(const char *a, const char *b) +{ + char *full_path; + + full_path = malloc(strlen(a) + strlen(b) + 2); + + strcpy(full_path, a); + if (b[0] != '/' && a[strlen(a) - 1] != '/') + strcat(full_path, "/"); + strcat(full_path, b); + + return full_path; +} + diff --git a/devices/paths.h b/devices/paths.h index eca6689..a6f01c4 100644 --- a/devices/paths.h +++ b/devices/paths.h @@ -2,9 +2,21 @@ #define PATHS_H /** - * Get the mountpoint for a device + * Given a string (eg /dev/sda1, sda1 or UUID=B8E53381CA9EA0E3), parse the + * device path (eg /dev/sda1). Any device descriptions read from config files + * should be parsed into the path first. + * + * The cur_dev is provided for some remapping situations. If NULL is provided, + * no remapping will be done. + * + * Returns a newly-allocated string. + */ +char *parse_device_path(const char *dev_str, const char *current_device); + +/** + * Get the mountpoint for a device. */ -const char *mountpoint_for_device(const char *dev_path); +const char *mountpoint_for_device(const char *dev); /** * Resolve a path given in a config file, to a path in the local filesystem. @@ -17,11 +29,21 @@ const char *mountpoint_for_device(const char *dev_path); * * Returns a newly-allocated string containing a full path to the file in path */ -char *resolve_path(const char *path, const char *current_mountpoint); +char *resolve_path(const char *path, const char *current_device); + /** * Set the base directory for newly-created mountpoints */ void set_mount_base(const char *path); +/** + * Utility function for joining two paths. Adds a / between a and b if + * required. + * + * Returns a newly-allocated string. + */ +char *join_paths(const char *a, const char *b); + + #endif /* PATHS_H */ diff --git a/devices/yaboot-parser.c b/devices/yaboot-parser.c index 8d65ce2..27b4b78 100644 --- a/devices/yaboot-parser.c +++ b/devices/yaboot-parser.c @@ -1,6 +1,7 @@ #include "parser.h" #include "params.h" +#include "paths.h" #include "yaboot-cfg.h" #include @@ -14,7 +15,7 @@ #include static struct device *dev; -static const char *mountpoint; +static char *devpath; static char *defimage; char * @@ -102,13 +103,13 @@ void process_image(char *label) opt.name = label; cfgopt = cfg_get_strg(label, "image"); - opt.boot_image_file = resolve_path(cfgopt, mountpoint); + opt.boot_image_file = resolve_path(cfgopt, devpath); if (cfgopt == defimage) pb_log("This one is default. What do we do about it?\n"); cfgopt = cfg_get_strg(label, "initrd"); if (cfgopt) - opt.initrd_file = resolve_path(cfgopt, mountpoint); + opt.initrd_file = resolve_path(cfgopt, devpath); opt.boot_args = make_params(label, NULL); @@ -118,7 +119,7 @@ void process_image(char *label) free(opt.initrd_file); } -static int yaboot_parse(const char *devicepath, const char *_mountpoint) +static int yaboot_parse(const char *device) { char *filepath; char *conf_file; @@ -128,14 +129,14 @@ static int yaboot_parse(const char *devicepath, const char *_mountpoint) struct stat st; char *label; - mountpoint = _mountpoint; + devpath = strdup(device); - filepath = join_paths(mountpoint, "/etc/yaboot.conf"); + filepath = resolve_path("/etc/yaboot.conf", devpath); fd = open(filepath, O_RDONLY); if (fd < 0) { free(filepath); - filepath = join_paths(mountpoint, "/yaboot.conf"); + filepath = resolve_path("/yaboot.conf", devpath); fd = open(filepath, O_RDONLY); if (fd < 0) @@ -171,7 +172,7 @@ static int yaboot_parse(const char *devicepath, const char *_mountpoint) dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); - dev->id = strdup(devicepath); + dev->id = strdup(devpath); if (cfg_get_strg(0, "init-message")) { char *newline; dev->description = strdup(cfg_get_strg(0, "init-message")); @@ -181,28 +182,32 @@ static int yaboot_parse(const char *devicepath, const char *_mountpoint) } dev->icon_file = strdup(generic_icon_file(guess_device_type())); - /* If we have a 'partiton=' directive, update the default mountpoint - * to use that instead of the current mountpoint */ + /* If we have a 'partiton=' directive, update the default devpath + * to use that instead of the current device */ tmpstr = cfg_get_strg(0, "partition"); if (tmpstr) { char *endp; int partnr = strtol(tmpstr, &endp, 10); if (endp != tmpstr && !*endp) { - char *new_dev = malloc(strlen(devicepath) + strlen(tmpstr) + 1); + char *new_dev, *tmp; + + new_dev = malloc(strlen(devpath) + strlen(tmpstr) + 1); if (!new_dev) return 0; - strcpy(new_dev, devicepath); + strcpy(new_dev, devpath); /* Strip digits (partition number) from string */ - endp = &new_dev[strlen(devicepath) - 1]; + endp = new_dev + strlen(devpath) - 1; while (isdigit(*endp)) *(endp--) = 0; /* and add our own... */ - sprintf(endp+1, "%d", partnr); + sprintf(endp + 1, "%d", partnr); - mountpoint = mountpoint_for_device(new_dev); + tmp = devpath; + devpath = parse_device_path(new_dev, devpath); + free(tmp); free(new_dev); } }