* [RAUC] [PATCH 1/3] Normalize device names to find mounted slots (2)
2019-05-10 9:48 [RAUC] [RFC 0/3] Fix slots with nodev mounts Ladislav Michl
@ 2019-05-10 9:48 ` Ladislav Michl
2019-05-10 9:49 ` [RAUC] [PATCH 2/3] Try harder to determine slot state (preview) Ladislav Michl
2019-05-10 9:49 ` [RAUC] [PATCH 3/3] Bind mount seed slot Ladislav Michl
2 siblings, 0 replies; 4+ messages in thread
From: Ladislav Michl @ 2019-05-10 9:48 UTC (permalink / raw)
To: rauc; +Cc: Trent Piepho
This one is meant to be squashed into this one:
https://github.com/rauc/rauc/pull/406
---
src/config_file.c | 60 ++++++++++++++++++++++++++---------------------
1 file changed, 33 insertions(+), 27 deletions(-)
diff --git a/src/config_file.c b/src/config_file.c
index 875e0ee..d966533 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -494,38 +494,44 @@ free:
return res;
}
-// Something that is, or can be, mounted onto a mount point
+/* Something that is, or can be, mounted onto a mount point */
typedef struct {
- gboolean is_device; // vs being a loop mounted file
- dev_t dev; // the device, or for a file, the device the file is on
- ino_t inode; // inode of file for a non-device
+ dev_t dev; /* the device, or for a file, the device the file is on */
+ ino_t inode; /* inode of file for a non-device */
+ gchar is_device; /* vs being a loop mounted file */
} MountableObj;
-// Take a device (or file) path and normalize it
-static MountableObj *normalize_mountable_object(const gchar *devicepath)
+/* Take a device (or file) path or name and normalize it */
+static gboolean normalize_mountable_object(const gchar *name, MountableObj *obj)
{
- MountableObj *obj;
GStatBuf st;
- if (g_stat(devicepath, &st) == -1) {
+ if (g_stat(name, &st) == -1) {
/* Virtual filesystems like devpts trigger case */
- g_debug("Can't stat '%s', assuming unmountable: %s", devicepath, g_strerror(errno));
- return NULL;
+ g_debug("Can't stat '%s', assuming unmountable: %s", name, g_strerror(errno));
+ return FALSE;
}
- obj = g_new0(MountableObj, 1);
- if (S_ISBLK(st.st_mode)) {
- obj->is_device = TRUE;
+ switch (st.st_mode & S_IFMT) {
+ case S_IFCHR:
+ obj->is_device = 1;
obj->dev = st.st_rdev;
- } else if (S_ISREG(st.st_mode)) {
- obj->is_device = FALSE;
+ break;
+ case S_IFBLK:
+ obj->is_device = 2;
+ obj->dev = st.st_rdev;
+ break;
+ case S_IFDIR:
+ case S_IFREG:
+ obj->is_device = 0;
obj->dev = st.st_dev;
obj->inode = st.st_ino;
- } else {
- g_debug("Device '%s' is not something which is mountable", devicepath);
- g_clear_pointer(&obj, g_free);
+ break;
+ default:
+ g_debug("Device '%s' is unmountable", name);
+ return FALSE;
}
- return obj;
+ return TRUE;
}
/* Compare two MountableObj for equality */
@@ -546,24 +552,24 @@ RaucSlot *find_slot_by_device(GHashTable *slots, const gchar *device)
{
GHashTableIter iter;
RaucSlot *slot;
- g_autofree MountableObj *obj = NULL;
+ MountableObj obj;
+ gboolean normalized;
g_return_val_if_fail(slots, NULL);
g_return_val_if_fail(device, NULL);
- obj = normalize_mountable_object(device);
+ normalized = normalize_mountable_object(device, &obj);
g_hash_table_iter_init(&iter, slots);
while (g_hash_table_iter_next(&iter, NULL, (gpointer*) &slot)) {
if (g_strcmp0(slot->device, device) == 0)
goto out;
- // Path doesn't match, but maybe device is same?
- if (obj) {
- g_autofree MountableObj *slot_obj =
- normalize_mountable_object(slot->device);
-
- if (slot_obj && is_same_mountable_object(obj, slot_obj))
+ /* Path doesn't match, but maybe device is the same? */
+ if (normalized) {
+ MountableObj slot_obj;
+ if (normalize_mountable_object(slot->device, &slot_obj) &&
+ is_same_mountable_object(&obj, &slot_obj))
goto out;
}
}
--
2.20.1
_______________________________________________
RAUC mailing list
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RAUC] [PATCH 2/3] Try harder to determine slot state (preview)
2019-05-10 9:48 [RAUC] [RFC 0/3] Fix slots with nodev mounts Ladislav Michl
2019-05-10 9:48 ` [RAUC] [PATCH 1/3] Normalize device names to find mounted slots (2) Ladislav Michl
@ 2019-05-10 9:49 ` Ladislav Michl
2019-05-10 9:49 ` [RAUC] [PATCH 3/3] Bind mount seed slot Ladislav Michl
2 siblings, 0 replies; 4+ messages in thread
From: Ladislav Michl @ 2019-05-10 9:49 UTC (permalink / raw)
To: rauc; +Cc: Trent Piepho
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
^ permalink raw reply [flat|nested] 4+ messages in thread
* [RAUC] [PATCH 3/3] Bind mount seed slot
2019-05-10 9:48 [RAUC] [RFC 0/3] Fix slots with nodev mounts Ladislav Michl
2019-05-10 9:48 ` [RAUC] [PATCH 1/3] Normalize device names to find mounted slots (2) Ladislav Michl
2019-05-10 9:49 ` [RAUC] [PATCH 2/3] Try harder to determine slot state (preview) Ladislav Michl
@ 2019-05-10 9:49 ` Ladislav Michl
2 siblings, 0 replies; 4+ messages in thread
From: Ladislav Michl @ 2019-05-10 9:49 UTC (permalink / raw)
To: rauc; +Cc: Trent Piepho
See that FIXME...
---
src/update_handler.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/src/update_handler.c b/src/update_handler.c
index b8d044f..6f490d0 100644
--- a/src/update_handler.c
+++ b/src/update_handler.c
@@ -1,6 +1,7 @@
#include <errno.h>
#include <fcntl.h>
#include <gio/gunixoutputstream.h>
+#include <glib/gstdio.h>
#include <mtd/ubi-user.h>
#include <string.h>
#include <sys/ioctl.h>
@@ -251,13 +252,33 @@ static gboolean casync_extract_image(RaucImage *image, gchar *dest, GError **err
* path to allow seeding. E.g. using mount path '/' for the
* rootfs slot seed is inaproppriate as it contains virtual
* file systems, additional mounts, etc. */
+ /* FIXME: r_mount_slot should be fixed instead to handle bind mounts
+ * as well as "nodev" mounts */
if (!seedslot->mount_point) {
g_debug("Mounting %s to use as seed", seedslot->device);
- res = r_mount_slot(seedslot, &ierror);
- if (!res) {
- g_warning("Failed mounting for seeding: %s", ierror->message);
- g_clear_error(&ierror);
- goto extract;
+ if (seedslot->ext_mount_point) {
+ gchar *mount_point = r_create_mount_point(seedslot->name, &ierror);
+ if (!mount_point) {
+ g_warning("Failed creating bind mount point for seeding: %s", ierror->message);
+ g_clear_error(&ierror);
+ goto extract;
+ }
+ res = r_mount_full(seedslot->ext_mount_point, mount_point, NULL, 0, "bind", &ierror);
+ if (!res) {
+ g_warning("Failed bind mounting for seeding: %s", ierror->message);
+ g_clear_error(&ierror);
+ g_rmdir(mount_point);
+ g_free(mount_point);
+ goto extract;
+ }
+ seedslot->mount_point = mount_point;
+ } else {
+ res = r_mount_slot(seedslot, &ierror);
+ if (!res) {
+ g_warning("Failed mounting for seeding: %s", ierror->message);
+ g_clear_error(&ierror);
+ goto extract;
+ }
}
seed_mounted = TRUE;
}
--
2.20.1
_______________________________________________
RAUC mailing list
^ permalink raw reply [flat|nested] 4+ messages in thread