From 61b785184199f79f08d9ee023ce67ae56719499c Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 11 Mar 2020 14:35:22 +0100
Upstream: merged
Subject: [PATCH] udev: use correct udev rule (write) lock directory


diff --git a/src/futils.c b/src/futils.c
index b330f0a..9e9abd6 100644
--- a/src/futils.c
+++ b/src/futils.c
@@ -41,10 +41,35 @@
 #include <limits.h>
 #include <errno.h>
 #include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <futils.h>
 #include <logging.h>
 
+int /* bool */
+nc_isdir(const char *path)
+{
+	struct stat stb;
+
+	if (stat(path, &stb) < 0)
+		return 0;
+
+	return S_ISDIR(stb.st_mode);
+}
+
+int /* bool */
+nc_isreg(const char *path)
+{
+	struct stat stb;
+
+	if (stat(path, &stb) < 0)
+		return 0;
+
+	return S_ISREG(stb.st_mode);
+}
+
 int /* bool */
 nc_file_exists(const char *filename)
 {
@@ -64,6 +89,17 @@ nc_file_exists_fmt(const char *fmt, ...)
 	return nc_file_exists(filename);
 }
 
+const char *
+nc_basename(const char *pathname)
+{
+	const char *basename;
+
+	if (!pathname || !(basename = strrchr(pathname, '/')))
+		return pathname;
+	else
+		return basename + 1;
+}
+
 int
 nc_readlink(const char *link, char **path)
 {
diff --git a/src/futils.h b/src/futils.h
index 55355e4..822ced4 100644
--- a/src/futils.h
+++ b/src/futils.h
@@ -47,6 +47,11 @@ int		nc_scandir(const char *path, const char *filter, nc_string_array_t *result)
 
 int		nc_readlink(const char *link, char **path);
 
+const char *	nc_basename(const char *path);
+
+int /* bool */	nc_isdir(const char *path);
+int /* bool */	nc_isreg(const char *path);
+
 int /* bool */	nc_file_exists(const char *filename);
 int /* bool */	nc_file_exists_fmt(const char *fmt, ...) __fmtattr(1,2);
 
diff --git a/src/sutils.c b/src/sutils.c
index fd67fc0..3f54c78 100644
--- a/src/sutils.c
+++ b/src/sutils.c
@@ -107,6 +107,12 @@ nc_string_len(const char *str)
 	return str ? strlen(str) : 0;
 }
 
+int /* bool */
+nc_string_empty(const char *str)
+{
+	return !str || !*str;
+}
+
 int /* bool */
 nc_string_eq(const char *a, const char *b)
 {
diff --git a/src/sutils.h b/src/sutils.h
index b7734e0..51354ad 100644
--- a/src/sutils.h
+++ b/src/sutils.h
@@ -76,6 +76,7 @@ void		nc_string_free(char **);
 char *		nc_string_strip_spaces(char *str);
 
 size_t		nc_string_len(const char *);
+int /* bool */	nc_string_empty(const char *);
 int /* bool */	nc_string_eq(const char *a, const char *b);
 int		nc_string_prefix_eq(const char *prefix, const char *str);
 int		nc_string_suffix_eq(const char *suffix, const char *str);
diff --git a/src/udev_utils.c b/src/udev_utils.c
index 7ed4c86..3de2093 100644
--- a/src/udev_utils.c
+++ b/src/udev_utils.c
@@ -42,9 +42,10 @@
 #include <assert.h>
 
 #include <sutils.h>
+#include <futils.h>
 #include <logging.h>
 
-#define UDEV_NET_NAME_LOCK	"/dev/.udev/.lock-70-persistent-net.rules"
+#define UDEV_NET_LOCK_MODE	S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH
 #define UDEV_NET_NAME_RULE	"/etc/udev/rules.d/70-persistent-net.rules"
 #define UDEV_NET_NAME_TEMP	UDEV_NET_NAME_RULE".XXXXXX\0\0"
 #define UDEV_NET_NAME_SECS	5  /* running system shouldn't need more */
@@ -101,8 +102,8 @@ static void			nc_udev_rule_init(nc_udev_rule_t *rule);
 static void			nc_udev_rule_destroy(nc_udev_rule_t *rule);
 static int			nc_udev_rule_append(nc_udev_rule_t *rule, nc_udev_rule_cmd_t *cmd);
 
-static int			nc_udev_rule_file_lock(const char *rule_lock, unsigned int retry_sec);
-static int			nc_udev_rule_file_unlock(const char *rule_lock);
+static int			nc_udev_rule_file_lock(const char *rule_file, unsigned int retry_sec);
+static int			nc_udev_rule_file_unlock(const char *rule_file);
 
 /* internal helpers */
 static int			__nc_udev_rule_realloc(nc_udev_rule_t *rule, unsigned int newsize);
@@ -225,29 +226,82 @@ nc_udev_rule_append(nc_udev_rule_t *rule, nc_udev_rule_cmd_t *cmd)
 	return 0;
 }
 
+static const char *
+nc_udev_rule_lock_dir(void)
+{
+	static const char *lock_dirs[] = {
+		"/run/udev",	/* systemd systems (>=SLE12) */
+		"/dev/.udev",	/* sysvinit systems (SLES11) */
+		NULL
+	}, **dir;
+
+	for (dir = lock_dirs; *dir; ++dir) {
+		if (nc_isdir(*dir))
+			return *dir;
+	}
+	return NULL;
+}
+
+static int
+nc_udev_rule_lock_file(nc_stringbuf_t *rule_lock, const char *rule_file)
+{
+	const char *rule_name;
+	const char *lock_dir;
+
+	if (!rule_lock || !rule_file)
+		return -1;
+
+	rule_name = nc_basename(rule_file);
+	if (nc_string_empty(rule_name))
+		return -1;
+
+	lock_dir = nc_udev_rule_lock_dir();
+	if (nc_string_empty(lock_dir))
+		return -1;
+
+	nc_stringbuf_clear(rule_lock);
+	nc_stringbuf_puts(rule_lock, lock_dir);
+	nc_stringbuf_puts(rule_lock, "/.lock-");
+	nc_stringbuf_puts(rule_lock, rule_name);
+	if (rule_lock->len && rule_lock->string)
+		return 0;
+
+	nc_stringbuf_clear(rule_lock);
+	return -1;
+}
+
 static int
-nc_udev_rule_file_lock(const char *rule_lock, unsigned int retry_sec)
+nc_udev_rule_file_lock(const char *rule_file, unsigned int retry_sec)
 {
-	assert(rule_lock);
-	if(!rule_lock)
+	nc_stringbuf_t rule_lock = NC_STRINGBUF_INIT;
+
+	if(nc_udev_rule_lock_file(&rule_lock, rule_file) != 0)
 		return -1;
 
-	while(mkdir(rule_lock, 755) != 0) {
+	while(mkdir(rule_lock.string, UDEV_NET_LOCK_MODE) != 0) {
 		if(retry_sec > 0) {
 			retry_sec--;
 			sleep(1);
 		} else {
+			nc_stringbuf_destroy(&rule_lock);
 			return 1;
 		}
 	}
+	nc_stringbuf_destroy(&rule_lock);
 	return 0;
 }
 
 static int
-nc_udev_rule_file_unlock(const char *rule_lock)
+nc_udev_rule_file_unlock(const char *rule_file)
 {
-	assert(rule_lock);
-	return rule_lock ? rmdir(rule_lock) : -1;
+	nc_stringbuf_t rule_lock = NC_STRINGBUF_INIT;
+
+	if(nc_udev_rule_lock_file(&rule_lock, rule_file) != 0)
+		return -1;
+
+	rmdir(rule_lock.string);
+	nc_stringbuf_destroy(&rule_lock);
+	return 0;
 }
 
 static char *
@@ -549,7 +603,6 @@ nc_udev_net_rule_hwaddr_for_name(const char *ifname, char **hwaddr)
 int
 nc_udev_net_rule_hwaddr_to_bus_id(nc_var_array_t *bus_id_map)
 {
-	const char * rule_lock   = UDEV_NET_NAME_LOCK;
 	const char * rule_file   = UDEV_NET_NAME_RULE;
 	char         rule_temp[] = UDEV_NET_NAME_TEMP;
 	int          ret;
@@ -559,14 +612,14 @@ nc_udev_net_rule_hwaddr_to_bus_id(nc_var_array_t *bus_id_map)
 	if(!bus_id_map->count)
 		return 0;
 
-	if(nc_udev_rule_file_lock(rule_lock, UDEV_NET_NAME_SECS) != 0) {
+	if(nc_udev_rule_file_lock(rule_file, UDEV_NET_NAME_SECS) != 0) {
 		nc_error("Unable to acquire lock for %s: %m", rule_file);
 		return 0; /* error, but we just report "not found" */
 	}
 
 	ret = __nc_udev_net_rule_hwaddr_to_bus_id(bus_id_map, rule_file, rule_temp);
 
-	if(nc_udev_rule_file_unlock(rule_lock) != 0) {
+	if(nc_udev_rule_file_unlock(rule_file) != 0) {
 		nc_error("Unable to release lock for %s: %m", rule_file);
 		/* Hmm... and now? */
 	}
-- 
2.16.4

