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

Reply via email to