chiark / gitweb /
[PATCH] - unlink bugfix
[elogind.git] / udev-add.c
index 2f64b4375ab8019409f289f48b4cb2cd22f14171..c13cce53d4f413960465d1f53d29b410ab15acba 100644 (file)
@@ -32,6 +32,7 @@
 #include <grp.h>
 #ifndef __KLIBC__
 #include <pwd.h>
+#include <utmp.h>
 #endif
 
 #include "libsysfs/sysfs/libsysfs.h"
@@ -44,6 +45,8 @@
 #include "udevdb.h"
 #include "klibc_fixups.h"
 
+#define LOCAL_USER "$local"
+
 /* 
  * Right now the major/minor of a device is stored in a file called
  * "dev" in sysfs.
@@ -132,9 +135,57 @@ static int make_node(char *filename, int major, int minor, unsigned int mode, ui
        return 0;
 }
 
-static int create_node(struct udevice *dev, int fake)
+/* get the local logged in user */
+static void set_to_local_user(char *user)
+{
+       struct utmp *u;
+       time_t recent = 0;
+
+       strnfieldcpy(user, default_owner_str, OWNER_SIZE);
+       setutent();
+       while (1) {
+               u = getutent();
+               if (u == NULL)
+                       break;
+
+               /* is this a user login ? */
+               if (u->ut_type != USER_PROCESS)
+                       continue;
+
+               /* is this a local login ? */
+               if (strcmp(u->ut_host, ""))
+                       continue;
+
+               if (u->ut_time > recent) {
+                       recent = u->ut_time;
+                       strfieldcpy(user, u->ut_user);
+                       dbg("local user is '%s'", user);
+                       break;
+               }
+       }
+       endutent();
+}
+
+/* Used to unlink existing files to ensure that our new file/symlink is created */
+static int unlink_entry(char *filename)
 {
        struct stat stats;
+       int retval = 0;
+       
+       if (lstat(filename, &stats) == 0) {
+               if ((stats.st_mode & S_IFMT) != S_IFDIR) {
+                       retval = unlink(filename);
+                       if (retval) {
+                               dbg("unlink(%s) failed with error '%s'",
+                                   filename, strerror(errno));
+                       }
+               }
+       }
+       return retval;
+}
+
+static int create_node(struct udevice *dev, int fake)
+{
        char filename[255];
        char linktarget[255];
        char partitionname[255];
@@ -175,6 +226,9 @@ static int create_node(struct udevice *dev, int fake)
                if (endptr[0] == '\0')
                        uid = (uid_t) id;
                else {
+                       if (strncmp(dev->owner, LOCAL_USER, sizeof(LOCAL_USER)) == 0)
+                               set_to_local_user(dev->owner);
+
                        struct passwd *pw = getpwnam(dev->owner);
                        if (pw == NULL)
                                dbg("specified user unknown '%s'", dev->owner);
@@ -198,6 +252,7 @@ static int create_node(struct udevice *dev, int fake)
        }
 
        if (!fake) {
+               unlink_entry(filename);
                info("creating device node '%s'", filename);
                make_node(filename, dev->major, dev->minor, dev->mode, uid, gid);
        } else {
@@ -211,7 +266,9 @@ static int create_node(struct udevice *dev, int fake)
                info("creating device partition nodes '%s[1-%i]'", filename, dev->partitions);
                if (!fake) {
                        for (i = 1; i <= dev->partitions; i++) {
-                               sprintf(partitionname, "%s%i", filename, i);
+                               strfieldcpy(partitionname, filename);
+                               strintcat(partitionname, i);
+                               unlink_entry(partitionname);
                                make_node(partitionname, dev->major,
                                          dev->minor + i, dev->mode, uid, gid);
                        }
@@ -251,18 +308,10 @@ static int create_node(struct udevice *dev, int fake)
                                i++;
                        }
 
-                       if (linktarget[0] == '\0')
-                               strfieldcpy(linktarget, "./");
                        strfieldcat(linktarget, &dev->name[tail]);
 
-                       /* unlink existing files to ensure that our symlink is created */
-                       if (!fake && (lstat(filename, &stats) == 0)) {
-                               if ((stats.st_mode & S_IFMT) != S_IFDIR) {
-                                       if (unlink(filename))
-                                               dbg("unlink(%s) failed with error '%s'",
-                                                   filename, strerror(errno));
-                               }
-                       }
+                       if (!fake)
+                               unlink_entry(filename);
 
                        dbg("symlink(%s, %s)", linktarget, filename);
                        if (!fake) {