chiark / gitweb /
don't remove symlinks if they are already there
authorKay Sievers <kay.sievers@suse.de>
Wed, 14 Jun 2006 14:32:52 +0000 (16:32 +0200)
committerKay Sievers <kay.sievers@suse.de>
Wed, 14 Jun 2006 14:32:52 +0000 (16:32 +0200)
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.

test/udev-test.pl
udev_device.c
udev_node.c

index 33da68a..fafaa96 100755 (executable)
@@ -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
index 6dc843e..a7a8b13 100644 (file)
@@ -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;
        }
 
index 2a30fe3..ee59d4a 100644 (file)
@@ -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));