From 4281da1fa6fda10c15bee984825fc607a8385004 Mon Sep 17 00:00:00 2001
From: Kay Sievers <kay.sievers@vrfy.org>
Date: Fri, 10 Dec 2010 01:13:35 +0100
Subject: [PATCH] udevd: use dev_t or netif ifindex as database key

We need to preserve the database of network interfaces while we
rename them. Use the kernel's numbers wherever possible, instead
of the device names.

Fix wrong database filenames which contain a '/', translated
from '!' in the kernel name.

Fix segfault for kobject pathes where the subsystem can not be
determined from sysfs.

Signed-off-by: Robert Milasan <rmilasan@suse.com>
---

Index: udev-147/libudev/libudev-device-private.c
===================================================================
--- udev-147.orig/libudev/libudev-device-private.c
+++ udev-147/libudev/libudev-device-private.c
@@ -23,6 +23,7 @@
 
 int udev_device_update_db(struct udev_device *udev_device)
 {
+	const char *id;
 	struct udev *udev = udev_device_get_udev(udev_device);
 	char filename[UTIL_PATH_SIZE];
 	FILE *f;
@@ -33,8 +34,11 @@ int udev_device_update_db(struct udev_de
 	struct udev_list_entry *list_entry;
 	int ret;
 
-	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
-		      udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
+	id = udev_device_get_id_filename(udev_device);
+	if (id == NULL)
+	        return -1;
+	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
+
 	unlink(filename);
 
 	udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
@@ -111,11 +115,14 @@ out:
 
 int udev_device_delete_db(struct udev_device *udev_device)
 {
+	const char *id;
 	struct udev *udev = udev_device_get_udev(udev_device);
 	char filename[UTIL_PATH_SIZE];
 
-	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/",
-		      udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
+	id = udev_device_get_id_filename(udev_device);
+	if (id == NULL)
+		return -1;
+	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
 	unlink(filename);
 	return 0;
 }
Index: udev-147/libudev/libudev-device.c
===================================================================
--- udev-147.orig/libudev/libudev-device.c
+++ udev-147/libudev/libudev-device.c
@@ -54,6 +54,7 @@ struct udev_device {
 	char *devpath_old;
 	char *sysname_old;
 	char *knodename;
+	char *id_filename;
 	char **envp;
 	char *monitor_buf;
 	size_t monitor_buf_len;
@@ -67,6 +68,7 @@ struct udev_device {
 	int devlink_priority;
 	int refcount;
 	dev_t devnum;
+	int ifindex;
 	int watch_handle;
 	unsigned int parent_set:1;
 	unsigned int subsystem_set:1;
@@ -80,13 +82,16 @@ struct udev_device {
 
 int udev_device_read_db(struct udev_device *udev_device)
 {
+	const char *id;
 	struct stat stats;
 	char filename[UTIL_PATH_SIZE];
 	char line[UTIL_LINE_SIZE];
 	FILE *f;
 
-	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/",
-		      udev_device_get_subsystem(udev_device), ":", udev_device_get_sysname(udev_device), NULL);
+	id = udev_device_get_id_filename(udev_device);
+	if (id == NULL)
+		return -1;
+	util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/.udev/db/", id, NULL);
 
 	if (lstat(filename, &stats) != 0) {
 		dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
@@ -672,6 +677,7 @@ void udev_device_unref(struct udev_devic
 	free(udev_device->devpath_old);
 	free(udev_device->sysname_old);
 	free(udev_device->knodename);
+	free(udev_device->id_filename);
 	udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
 	free(udev_device->envp);
 	free(udev_device->monitor_buf);
@@ -1139,6 +1145,40 @@ int udev_device_add_devlink(struct udev_
 	return 0;
 }
 
+const char *udev_device_get_id_filename(struct udev_device *udev_device)
+{
+       if (udev_device->id_filename == NULL) {
+               if (udev_device_get_subsystem(udev_device) == NULL)
+                       return NULL;
+
+               if (major(udev_device_get_devnum(udev_device)) > 0) {
+                       /* use dev_t -- b259:131072, c254:0 */
+                       if (asprintf(&udev_device->id_filename, "%c%u:%u",
+                                    strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c',
+                                    major(udev_device_get_devnum(udev_device)),
+                                    minor(udev_device_get_devnum(udev_device))) < 0)
+                               udev_device->id_filename = NULL;
+               } else if (strcmp(udev_device_get_subsystem(udev_device), "net") == 0) {
+                       /* use netdev ifindex -- n3 */
+                       if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0)
+                               udev_device->id_filename = NULL;
+               } else {
+                       /*
+                        * use $subsys:$syname -- pci:0000:00:1f.2
+                        * sysname() has '!' translated, get it from devpath
+                        */
+                       const char *sysname;
+                       sysname = strrchr(udev_device->devpath, '/');
+                       if (sysname == NULL)
+                               return NULL;
+                       sysname = &sysname[1];
+                       if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0)
+                               udev_device->id_filename = NULL;
+               }
+       }
+       return udev_device->id_filename;
+}
+
 struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
 {
 	udev_device->envp_uptodate = 0;
@@ -1357,7 +1397,11 @@ int udev_device_get_event_timeout(struct
 
 int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
 {
+	char num[32];
+
 	udev_device->event_timeout = event_timeout;
+	snprintf(num, sizeof(num), "%u", event_timeout);
+	udev_device_add_property(udev_device, "TIMEOUT", num);
 	return 0;
 }
 
@@ -1435,3 +1479,14 @@ int udev_device_set_watch_handle(struct
 	udev_device->watch_handle = handle;
 	return 0;
 }
+
+int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex)
+{
+	char num[32];
+
+	udev_device->ifindex = ifindex;
+	snprintf(num, sizeof(num), "%u", ifindex);
+	udev_device_add_property(udev_device, "IFINDEX", num);
+	return 0;
+}
+
Index: udev-147/libudev/libudev-private.h
===================================================================
--- udev-147.orig/libudev/libudev-private.h
+++ udev-147/libudev/libudev-private.h
@@ -83,6 +83,7 @@ const char *udev_device_get_devpath_old(
 const char *udev_device_get_sysname_old(struct udev_device *udev_device);
 int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
 const char *udev_device_get_knodename(struct udev_device *udev_device);
+const char *udev_device_get_id_filename(struct udev_device *udev_device);
 int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename);
 int udev_device_get_timeout(struct udev_device *udev_device);
 int udev_device_set_timeout(struct udev_device *udev_device, int timeout);
Index: udev-147/udev/udev-node.c
===================================================================
--- udev-147.orig/udev/udev-node.c
+++ udev-147/udev/udev-node.c
@@ -297,10 +297,8 @@ static void link_update(struct udev_devi
 	dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
 
 	util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
-	snprintf(dirname, sizeof(dirname), "%s/.udev/links/%s", udev_get_dev_path(udev), name_enc);
-	snprintf(filename, sizeof(filename), "%s/%c%u:%u", dirname,
-		 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? 'b' : 'c',
-		 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
+	util_strscpyl(dirname, sizeof(dirname), udev_get_dev_path(udev), "/.udev/links/", name_enc, NULL);
+	util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
 
 	if (!add) {
 		dbg(udev, "removing index: '%s'\n", filename);
Index: udev-147/udev/udev-watch.c
===================================================================
--- udev-147.orig/udev/udev-watch.c
+++ udev-147/udev/udev-watch.c
@@ -125,7 +125,7 @@ void udev_watch_begin(struct udev *udev,
 	snprintf(filename, sizeof(filename), "%s/.udev/watch/%d", udev_get_dev_path(udev), wd);
 	util_create_path(udev, filename);
 	unlink(filename);
-	symlink(udev_device_get_devpath(dev), filename);
+	symlink(udev_device_get_id_filename(dev), filename);
 
 	udev_device_set_watch_handle(dev, wd);
 }
