mail archive of the rauc mailing list
 help / color / mirror / Atom feed
From: Ladislav Michl <ladis@linux-mips.org>
To: rauc@pengutronix.de
Cc: Trent Piepho <tpiepho@impinj.com>
Subject: [RAUC] [PATCH 2/3] Try harder to determine slot state (preview)
Date: Fri, 10 May 2019 11:49:14 +0200	[thread overview]
Message-ID: <20190510094914.GC29451@lenoch> (raw)
In-Reply-To: <20190510094803.GA29451@lenoch>

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

  parent reply	other threads:[~2019-05-10  9:49 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2019-05-10  9:49 ` [RAUC] [PATCH 3/3] Bind mount seed slot Ladislav Michl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190510094914.GC29451@lenoch \
    --to=ladis@linux-mips.org \
    --cc=rauc@pengutronix.de \
    --cc=tpiepho@impinj.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox