diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2008-01-07 21:25:22 +1100 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2008-01-07 21:25:22 +1100 |
commit | d56c4f5febce598f7ddc1fd5e78ec6ee621a0d9b (patch) | |
tree | 5ee8e974ce8067606090d1a6b7e9c7a4d1977f14 | |
parent | aab818c10b1fa68b968cabc852680f8ec0fe1360 (diff) | |
download | petitboot-d56c4f5febce598f7ddc1fd5e78ec6ee621a0d9b.zip petitboot-d56c4f5febce598f7ddc1fd5e78ec6ee621a0d9b.tar.gz |
Create uuid and label symlinks when mounting devices
When we discover a device with ID_FS_UUID or ID_FS_LABEL properties,
create a symlink in the mount tree. This will end up with a mount
tree structure mirroring /dev, and allow devices to be referenced
by uuid when booting is attempted.
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r-- | devices/paths.c | 2 | ||||
-rw-r--r-- | devices/paths.h | 4 | ||||
-rw-r--r-- | devices/udev-helper.c | 95 |
3 files changed, 99 insertions, 2 deletions
diff --git a/devices/paths.c b/devices/paths.c index e9bf6cb..2373c28 100644 --- a/devices/paths.c +++ b/devices/paths.c @@ -15,7 +15,7 @@ struct device_map { #define DEVICE_MAP_SIZE 32 static struct device_map device_map[DEVICE_MAP_SIZE]; -static char *encode_label(const char *label) +char *encode_label(const char *label) { char *str, *c; int i; diff --git a/devices/paths.h b/devices/paths.h index a6f01c4..26d4ce4 100644 --- a/devices/paths.h +++ b/devices/paths.h @@ -45,5 +45,9 @@ void set_mount_base(const char *path); */ char *join_paths(const char *a, const char *b); +/** + * encode a disk label (or uuid) for use in a symlink. + */ +char *encode_label(const char *label); #endif /* PATHS_H */ diff --git a/devices/udev-helper.c b/devices/udev-helper.c index a55d378..f77777a 100644 --- a/devices/udev-helper.c +++ b/devices/udev-helper.c @@ -184,6 +184,97 @@ int connect_to_socket() #endif } +static int mkdir_recursive(const char *dir) +{ + char *str, *sep; + int mode = 0755; + struct stat statbuf; + + pb_log("mkdir_recursive(%s)\n", dir); + + if (!*dir) + return 0; + + if (!stat(dir, &statbuf)) { + if (!S_ISDIR(statbuf.st_mode)) { + pb_log("%s: %s exists, but isn't a directory\n", + __func__, dir); + return -1; + } + return 0; + } + + str = strdup(dir); + sep = strchr(*str == '/' ? str + 1 : str, '/'); + + while (1) { + + /* terminate the path at sep */ + if (sep) + *sep = '\0'; + pb_log("mkdir(%s)\n", str); + + if (mkdir(str, mode) && errno != EEXIST) { + pb_log("mkdir(%s): %s\n", str, strerror(errno)); + return -1; + } + + if (!sep) + break; + + /* reset dir to the full path */ + strcpy(str, dir); + sep = strchr(sep + 1, '/'); + } + + free(str); + + return 0; +} + +static void setup_device_links(const char *device) +{ + struct link { + char *env, *dir; + } *link, links[] = { + { + .env = "ID_FS_UUID", + .dir = "disk/by-uuid" + }, + { + .env = "ID_FS_LABEL", + .dir = "disk/by-label" + }, + { + .env = NULL + } + }; + + for (link = links; link->env; link++) { + char *value, *dir, *path; + + value = getenv(link->env); + if (!value) + continue; + + value = encode_label(value); + dir = join_paths(TMP_DIR, link->dir); + path = join_paths(dir, value); + + if (!mkdir_recursive(dir)) { + unlink(path); + if (symlink(mountpoint_for_device(device), path)) { + pb_log("symlink(%s): %s\n", + path, strerror(errno)); + } + } + + free(path); + free(dir); + free(value); + } +} + int mount_device(const char *dev_path) { const char *dir; @@ -224,8 +315,10 @@ int mount_device(const char *dev_path) goto out; } - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + setup_device_links(dev_path); rc = 0; + } out: return rc; |