Only ubi volume by name is supported for now... --- Makefile.am | 2 ++ include/mtd.h | 3 ++ src/config_file.c | 79 ++++++++++++++++++++++++++++++++++++++++++ src/install.c | 37 ++------------------ src/mtd.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 174 insertions(+), 35 deletions(-) create mode 100644 include/mtd.h create mode 100644 src/mtd.c
diff --git a/Makefile.am b/Makefile.am index 3bf4936..7e0efa4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -43,6 +43,7 @@ librauc_la_SOURCES = \ src/manifest.c \ src/mark.c \ src/mount.c \ + src/mtd.c \ src/service.c \ src/signature.c \ src/utils.c \ @@ -57,6 +58,7 @@ librauc_la_SOURCES = \ include/manifest.h \ include/mark.h \ include/mount.h \ + include/mtd.h \ include/service.h \ include/signature.h \ include/update_handler.h \ diff --git a/include/mtd.h b/include/mtd.h new file mode 100644 index 0000000..e01a203 --- /dev/null +++ b/include/mtd.h @@ -0,0 +1,3 @@ +#pragma once + +int ubi_volume_device_id(int device, const char *volname, unsigned *major, unsigned *minor); diff --git a/src/config_file.c b/src/config_file.c index d966533..453d6a1 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -2,11 +2,13 @@ #include <glib.h> #include <glib/gstdio.h> #include <string.h> +#include <sys/sysmacros.h> #include "config_file.h" #include "context.h" #include "manifest.h" #include "mount.h" +#include "mtd.h" #include "utils.h" G_DEFINE_QUARK(r-config-error-quark, r_config_error) @@ -501,10 +503,87 @@ typedef struct { gchar is_device; /* vs being a loop mounted file */ } MountableObj; +static gboolean mtd_by_name(const gchar *name, MountableObj *obj) +{ + return FALSE; /* TODO */ +} + +static gboolean mtd_by_index(guint index, MountableObj *obj) +{ + return FALSE; /* TODO */ +} + +static gboolean ubi_volume_by_name(guint index, const gchar *name, MountableObj *obj) +{ + unsigned major, minor; + + if (ubi_volume_device_id(index, name, &major, &minor) < 0) + return FALSE; + + obj->is_device = 1; + obj->dev = makedev(major, minor); + + return TRUE; +} + +static gboolean ubi_volume_by_index(guint index, guint vol, MountableObj *obj) +{ + return FALSE; /* TODO */ +} + /* Take a device (or file) path or name and normalize it */ static gboolean normalize_mountable_object(const gchar *name, MountableObj *obj) { GStatBuf st; + gchar *endptr; + guint index; + + if (g_str_has_prefix(name, "mtd")) { + /* MTD can be also mounted as mtdX or mtd:NAME */ + if (name[3] == ':' && name[4] != '\0') { + if (mtd_by_name(name, obj)) + return TRUE; + } else if (g_ascii_isdigit(name[3])) { + index = g_ascii_strtoull(name + 3, &endptr, 0); + if (*endptr == '\0' && mtd_by_index(index, obj)) + return TRUE; + } + } else if (g_str_has_prefix(name, "ubi")) { + /* fs/ubifs/super.c of kernel source says: + * + * The primary method of mounting UBIFS is by specifying the UBI volume + * character device node path. However, UBIFS may also be mounted withoug any + * character device node using one of the following methods: + * + * o ubiX_Y - mount UBI device number X, volume Y; + * o ubiY - mount UBI device number 0, volume Y; + * o ubiX:NAME - mount UBI device X, volume with name NAME; + * o ubi:NAME - mount UBI device 0, volume with name NAME. + * + * Alternative '!' separator may be used instead of ':' */ + if ((name[3] == ':' || name[3] == '!') && name[4] != '\0') { + if (ubi_volume_by_name(0, name + 4, obj)) + return TRUE; + } else if (g_ascii_isdigit(name[3])) { + index = g_ascii_strtoull(name + 3, &endptr, 0); + if (*endptr == '\0') { + if (ubi_volume_by_index(0, index, obj)) + return TRUE; + } else if (*endptr == '_' && g_ascii_isdigit(endptr[1])) { + guint vol = g_ascii_strtoull(endptr + 1, &endptr, 0); + if (*endptr == '\0' && ubi_volume_by_index(index, vol, obj)) + return TRUE; + } else if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0') { + if (ubi_volume_by_name(index, ++endptr, obj)) + return TRUE; + } + } + } else if (!g_str_has_prefix(name, "/")) { + /* Relative paths will be from something like tmpfs, cgroups, + * etc. which we want to ignore rather than try to follow some + * random symlink named "tmpfs" in the CWD. */ + return FALSE; + } if (g_stat(name, &st) == -1) { /* Virtual filesystems like devpts trigger case */ diff --git a/src/install.c b/src/install.c index 2cda3be..6d8e8e9 100644 --- a/src/install.c +++ b/src/install.c @@ -43,30 +43,6 @@ static void install_args_update(RaucInstallArgs *args, const gchar *msg) g_main_context_invoke(NULL, args->notify, args); } -static gchar *resolve_loop_device(const gchar *devicepath) -{ - g_autofree gchar *devicename = NULL; - g_autofree gchar *syspath = NULL; - gchar *content = NULL; - GError *ierror = NULL; - - if (!g_str_has_prefix(devicepath, "/dev/loop")) - return g_strdup(devicepath); - - devicename = g_path_get_basename(devicepath); - syspath = g_build_filename("/sys/block", devicename, "loop/backing_file", NULL); - - content = read_file_str(syspath, &ierror); - if (!content) { - g_message("%s", ierror->message); - g_clear_error(&ierror); - return NULL; - } - - /* g_strchomp modifies the string and returns it */ - return g_strchomp(content); -} - gboolean determine_slot_states(GError **error) { GList *slotlist = NULL; @@ -90,17 +66,8 @@ gboolean determine_slot_states(GError **error) mountlist = g_unix_mounts_get(NULL); for (GList *l = mountlist; l != NULL; l = l->next) { GUnixMountEntry *m = (GUnixMountEntry*)l->data; - g_autofree gchar *devicepath = NULL; - RaucSlot *s = NULL; - /* Relative paths will be from something like tmpfs, cgroups, - * etc. which we want to ignore rather than try to follow some - * random symlink named "tmpfs" in the CWD. */ - if (g_unix_mount_get_device_path(m)[0] != '/') - continue; - - devicepath = resolve_loop_device(g_unix_mount_get_device_path(m)); - s = find_config_slot_by_device(r_context()->config, devicepath); - if (!s) + RaucSlot *s = find_config_slot_by_device(r_context()->config, g_unix_mount_get_device_path(m)); + if (!s || s->ext_mount_point) continue; s->ext_mount_point = g_strdup(g_unix_mount_get_mount_path(m)); diff --git a/src/mtd.c b/src/mtd.c new file mode 100644 index 0000000..95a8c41 --- /dev/null +++ b/src/mtd.c @@ -0,0 +1,88 @@ +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/sysmacros.h> +#include <unistd.h> + +#include "mtd.h" + +int ubi_volume_device_id(int device, const char *volname, unsigned *major, unsigned *minor) +{ + ssize_t len; + char buf[256], prefix[16], *endptr; + struct dirent *dp; + DIR *ubi_dir; + int prefix_len; + unsigned maj, min; + int fd, vol_fd, ubi_fd; + + snprintf(buf, sizeof(buf), "/sys/class/ubi/ubi%d", device); + ubi_dir = opendir(buf); + if (!ubi_dir) + return -1; + + ubi_fd = dirfd(ubi_dir); + if (ubi_fd < 0) { + closedir(ubi_dir); + return -1; + } + + endptr = NULL; + prefix_len = snprintf(prefix, sizeof(prefix), "ubi%d_", device); + + while ((dp = readdir(ubi_dir)) != NULL) { + if (dp->d_type != DT_DIR || strncmp(dp->d_name, prefix, prefix_len)) + continue; + + vol_fd = openat(ubi_fd, dp->d_name, O_CLOEXEC | O_DIRECTORY | O_PATH); + if (vol_fd < 0) + continue; + + /* read volume name */ + fd = openat(vol_fd, "name", O_RDONLY | O_CLOEXEC); + if (fd != -1) { + len = read(fd, buf, sizeof(buf)); + close(fd); + /* Do not compare trailing newline */ + if (--len > 0) + buf[len] = '\0'; + if (len > 0 && strcmp(volname, buf) == 0) { + /* volume found, get device ID */ + fd = openat(vol_fd, "dev", O_RDONLY | O_CLOEXEC); + if (fd != -1) { + len = read(fd, buf, sizeof(buf) - 1); + close(fd); + /* at least colon and two digits */ + if (len > 2) { + buf[len] = '\0'; + maj = strtoul(buf, &endptr, 0); + if (*endptr == ':') { + min = strtoul(endptr + 1, &endptr, 0); + if (*endptr == '\0' || *endptr == '\n') { + close(vol_fd); + break; + } + } + endptr = NULL; + } + } + } + } + close(vol_fd); + } + closedir(ubi_dir); + + if (endptr == NULL) + return -1; + + *major = maj; + *minor = min; + + return 0; +} + + -- 2.20.1 _______________________________________________ RAUC mailing list