mail archive of the rauc mailing list
 help / color / mirror / Atom feed
* [RAUC] [RFC 0/3] Fix slots with nodev mounts
@ 2019-05-10  9:48 Ladislav Michl
  2019-05-10  9:48 ` [RAUC] [PATCH 1/3] Normalize device names to find mounted slots (2) Ladislav Michl
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Ladislav Michl @ 2019-05-10  9:48 UTC (permalink / raw)
  To: rauc; +Cc: Trent Piepho

Hi there,

this is just an attempt to make rauc work with nodev mounted slots.
It is based on https://github.com/rauc/rauc/pull/406 where first
patch in the serie is meant to be squashed there.

Second patch then implements matching against ubi:<vol_name>
device naming scheme and can be easily extended. Now with
$ cat /proc/mounts 
ubi0:rootfs0 / ubifs ro,relatime,assert=read-only,ubi=0,vol=0 0 0
[strip]
It is able to correctly find slot and use it as seed slot for casync:
$ rauc status
Compatible:  Foomatic System
Variant:     
Booted from: rootfs.0 (system0)
Activated:   rootfs.0 (system0)
slot states:
  rootfs.1: class=rootfs, device=/dev/ubi0_1, type=ubifs, bootname=system1
      state=inactive, description=, parent=(none), mountpoint=(none)
      boot status=good
  rootfs.0: class=rootfs, device=/dev/ubi0_0, type=ubifs, bootname=system0
      state=booted, description=, parent=(none), mountpoint=/
      boot status=good

Third patch is again just a preview - r_mount_slot should be fixed
instead. I'm assuming anything having ext_mount_point set is already
mounted there, thus only bind mount makes sense here. Correct?

Please review, I'd like to have patch 1 and (rewritten) patch 3
merged for v1.1 milestone :)

Thank you,
	ladis

_______________________________________________
RAUC mailing list

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [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

end of thread, other threads:[~2019-05-10  9:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [RAUC] [PATCH 3/3] Bind mount seed slot Ladislav Michl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox