summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@suse.de>2006-06-14 16:32:52 +0200
committerKay Sievers <kay.sievers@suse.de>2006-06-14 16:32:52 +0200
commitfa33d857e2cdd65d3de2f88021ecacf167fc21f0 (patch)
tree0267347e95dcf04ae57df4baa0054d7502f7cb5b
parentafb66e32335d7bea55b015855089df4779916829 (diff)
don't remove symlinks if they are already there
Consecutive "add" events will not remove and recreate the same symlinks anymore. No longer valid links, like after changing a filesystem label, will still be removed.
-rwxr-xr-xtest/udev-test.pl1
-rw-r--r--udev_device.c35
-rw-r--r--udev_node.c39
3 files changed, 61 insertions, 14 deletions
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 33da68a386..fafaa96ab6 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -862,6 +862,7 @@ EOF
devpath => "/class/tty/tty0",
exp_name => "link",
exp_target => "link",
+ exp_add_error => "yes",
exp_rem_error => "yes",
option => "clean",
rules => <<EOF
diff --git a/udev_device.c b/udev_device.c
index 6dc843ed22..a7a8b13c96 100644
--- a/udev_device.c
+++ b/udev_device.c
@@ -132,17 +132,38 @@ int udev_device_event(struct udev_rules *rules, struct udevice *udev)
/* read current database entry, we may want to cleanup symlinks */
udev_old = udev_device_init();
if (udev_old != NULL) {
- if (udev_db_get_device(udev_old, udev->dev->devpath) == 0) {
- info("device '%s' already known, remove possible symlinks", udev->dev->devpath);
- udev_node_remove_symlinks(udev_old);
- }
- udev_device_cleanup(udev_old);
+ if (udev_db_get_device(udev_old, udev->dev->devpath) != 0) {
+ udev_device_cleanup(udev_old);
+ udev_old = NULL;
+ } else
+ info("device '%s' already in database, validate currently present symlinks",
+ udev->dev->devpath);
}
- /* create node and symlinks, store record in database */
+ /* create node and symlinks */
retval = udev_node_add(udev, udev_old);
- if (retval == 0)
+ if (retval == 0) {
+ /* store record in database */
udev_db_add_device(udev);
+
+ /* remove possibly left-over symlinks */
+ if (udev_old != NULL) {
+ struct name_entry *link_loop;
+ struct name_entry *link_old_loop;
+ struct name_entry *link_old_tmp_loop;
+
+ /* remove still valid symlinks from old list */
+ list_for_each_entry_safe(link_old_loop, link_old_tmp_loop, &udev_old->symlink_list, node)
+ list_for_each_entry(link_loop, &udev->symlink_list, node)
+ if (strcmp(link_old_loop->name, link_loop->name) == 0) {
+ dbg("symlink '%s' still valid, keep it", link_old_loop->name);
+ list_del(&link_old_loop->node);
+ free(link_old_loop);
+ }
+ udev_node_remove_symlinks(udev_old);
+ udev_device_cleanup(udev_old);
+ }
+ }
goto exit;
}
diff --git a/udev_node.c b/udev_node.c
index 2a30fe3222..ee59d4ae7c 100644
--- a/udev_node.c
+++ b/udev_node.c
@@ -90,6 +90,36 @@ exit:
return retval;
}
+static int udev_node_symlink(struct udevice *udev, const char *linktarget, const char *filename)
+{
+ char target[PATH_SIZE];
+ int len;
+
+ /* look if symlink already exists */
+ len = readlink(filename, target, sizeof(target));
+ if (len > 0) {
+ target[len] = '\0';
+ if (strcmp(linktarget, target) == 0) {
+ info("preserving symlink '%s' to '%s'", filename, linktarget);
+ selinux_setfilecon(filename, NULL, S_IFLNK);
+ goto exit;
+ } else {
+ info("link '%s' points to different target '%s', delete it", filename, target);
+ unlink(filename);
+ }
+ }
+
+ /* create link */
+ info("creating symlink '%s' to '%s'", filename, linktarget);
+ selinux_setfscreatecon(filename, NULL, S_IFLNK);
+ if (symlink(linktarget, filename) != 0)
+ err("symlink(%s, %s) failed: %s", linktarget, filename, strerror(errno));
+ selinux_resetfscreatecon();
+
+exit:
+ return 0;
+}
+
int udev_node_add(struct udevice *udev, struct udevice *udev_old)
{
char filename[PATH_SIZE];
@@ -205,13 +235,8 @@ int udev_node_add(struct udevice *udev, struct udevice *udev_old)
strlcat(linktarget, &udev->name[tail], sizeof(linktarget));
info("creating symlink '%s' to '%s'", filename, linktarget);
- if (!udev->test_run) {
- unlink(filename);
- selinux_setfscreatecon(filename, NULL, S_IFLNK);
- if (symlink(linktarget, filename) != 0)
- err("symlink(%s, %s) failed: %s", linktarget, filename, strerror(errno));
- selinux_resetfscreatecon();
- }
+ if (!udev->test_run)
+ udev_node_symlink(udev, linktarget, filename);
strlcat(symlinks, filename, sizeof(symlinks));
strlcat(symlinks, " ", sizeof(symlinks));