chiark / gitweb /
move syslog wrapper to libudev
[elogind.git] / udev / udev-node.c
index 73075ee0aa874491722466d6bd289c0226f2b936..89b674e4c481a30b13a87e680310efe182271415 100644 (file)
 #include <sys/types.h>
 
 #include "udev.h"
-#include "udev-rules.h"
 
 #define TMP_FILE_EXT           ".udev-tmp"
 
 /* reverse mapping from the device file name to the devpath */
-static int name_index(struct udev *udev, const char *devpath, const char *name, int add, int test)
+static int name_index(struct udev *udev, const char *devpath, const char *name, int add)
 {
-       char device[UTIL_PATH_SIZE];
+       char devpath_enc[UTIL_PATH_SIZE];
+       char name_enc[UTIL_PATH_SIZE];
        char filename[UTIL_PATH_SIZE * 2];
-       size_t devlen = strlen(udev_get_dev_path(udev))+1;
-       size_t start;
        int fd;
 
-       /* directory with device name */
-       util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
-       start = util_strlcat(filename, "/.udev/names/", sizeof(filename));
-       util_strlcat(filename, &name[devlen], sizeof(filename));
-       util_path_encode(&filename[start], sizeof(filename) - start);
-       /* entry with the devpath */
-       util_strlcpy(device, devpath, sizeof(device));
-       util_path_encode(device, sizeof(device));
-       util_strlcat(filename, "/", sizeof(filename));
-       util_strlcat(filename, device, sizeof(filename));
+       util_path_encode(&name[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
+       util_path_encode(devpath, devpath_enc, sizeof(devpath_enc));
+       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev),
+                     "/.udev/names/", name_enc, "/", devpath_enc, NULL);
 
        if (add) {
-               info(udev, "creating index: '%s'\n", filename);
-               create_path(udev, filename);
+               dbg(udev, "creating index: '%s'\n", filename);
+               util_create_path(udev, filename);
                fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
                if (fd > 0)
                        close(fd);
        } else {
-               info(udev, "removing index: '%s'\n", filename);
+               dbg(udev, "removing index: '%s'\n", filename);
                unlink(filename);
-               delete_path(udev, filename);
+               util_delete_path(udev, filename);
        }
        return 0;
 }
@@ -69,7 +61,6 @@ static int name_index(struct udev *udev, const char *devpath, const char *name,
 int udev_node_mknod(struct udev_device *dev, const char *file, dev_t devnum, mode_t mode, uid_t uid, gid_t gid)
 {
        struct udev *udev = udev_device_get_udev(dev);
-       char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
        struct stat stats;
        int preserve = 0;
        int err = 0;
@@ -91,9 +82,10 @@ int udev_node_mknod(struct udev_device *dev, const char *file, dev_t devnum, mod
                        preserve = 1;
                        udev_selinux_lsetfilecon(udev, file, mode);
                } else {
+                       char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
+
                        info(udev, "atomically replace existing file '%s'\n", file);
-                       util_strlcpy(file_tmp, file, sizeof(file_tmp));
-                       util_strlcat(file_tmp, TMP_FILE_EXT, sizeof(file_tmp));
+                       util_strscpyl(file_tmp, sizeof(file_tmp), file, TMP_FILE_EXT, NULL);
                        unlink(file_tmp);
                        udev_selinux_setfscreatecon(udev, file_tmp, mode);
                        err = mknod(file_tmp, mode, devnum);
@@ -144,25 +136,33 @@ exit:
 static int node_symlink(struct udev *udev, const char *node, const char *slink)
 {
        struct stat stats;
-       char target[UTIL_PATH_SIZE] = "";
+       char target[UTIL_PATH_SIZE];
+       char *s;
+       size_t l;
        char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
        int i = 0;
        int tail = 0;
-       int len;
        int err = 0;
 
        /* use relative link */
+       target[0] = '\0';
        while (node[i] && (node[i] == slink[i])) {
                if (node[i] == '/')
                        tail = i+1;
                i++;
        }
+       s = target;
+       l = sizeof(target);
        while (slink[i] != '\0') {
                if (slink[i] == '/')
-                       util_strlcat(target, "../", sizeof(target));
+                       l = util_strpcpy(&s, l, "../");
                i++;
        }
-       util_strlcat(target, &node[tail], sizeof(target));
+       l = util_strscpy(s, l, &node[tail]);
+       if (l == 0) {
+               err = -EINVAL;
+               goto exit;
+       }
 
        /* preserve link with correct target, do not replace node of other device */
        if (lstat(slink, &stats) == 0) {
@@ -184,8 +184,9 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink)
                        }
                } else if (S_ISLNK(stats.st_mode)) {
                        char buf[UTIL_PATH_SIZE];
+                       int len;
 
-                       info(udev, "found existing symlink '%s'\n", slink);
+                       dbg(udev, "found existing symlink '%s'\n", slink);
                        len = readlink(slink, buf, sizeof(buf));
                        if (len > 0) {
                                buf[len] = '\0';
@@ -207,8 +208,7 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink)
        }
 
        info(udev, "atomically replace '%s'\n", slink);
-       util_strlcpy(slink_tmp, slink, sizeof(slink_tmp));
-       util_strlcat(slink_tmp, TMP_FILE_EXT, sizeof(slink_tmp));
+       util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
        unlink(slink_tmp);
        udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
        err = symlink(target, slink_tmp);
@@ -221,7 +221,6 @@ static int node_symlink(struct udev *udev, const char *node, const char *slink)
        if (err != 0) {
                err(udev, "rename(%s, %s) failed: %m\n", slink_tmp, slink);
                unlink(slink_tmp);
-               goto exit;
        }
 exit:
        return err;
@@ -229,23 +228,23 @@ exit:
 
 static int name_index_get_devices(struct udev *udev, const char *name, struct udev_list_node *dev_list)
 {
-       char dirname[PATH_MAX];
-       size_t devlen = strlen(udev_get_dev_path(udev))+1;
-       size_t start;
+       char dirname[UTIL_PATH_SIZE];
+       char *s;
+       size_t l;
        DIR *dir;
        int count = 0;
 
-       util_strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname));
-       start = util_strlcat(dirname, "/.udev/names/", sizeof(dirname));
-       util_strlcat(dirname, &name[devlen], sizeof(dirname));
-       util_path_encode(&dirname[start], sizeof(dirname) - start);
+       s = dirname;
+       l = util_strpcpyl(&s, sizeof(dirname), udev_get_dev_path(udev),
+                     "/.udev/names/", NULL);
+       util_path_encode(&name[strlen(udev_get_dev_path(udev))+1], s, l);
        dir = opendir(dirname);
        if (dir == NULL) {
-               info(udev, "no index directory '%s': %m\n", dirname);
+               dbg(udev, "no index directory '%s': %m\n", dirname);
                count = -1;
                goto out;
        }
-       info(udev, "found index directory '%s'\n", dirname);
+       dbg(udev, "found index directory '%s'\n", dirname);
 
        while (1) {
                struct dirent *ent;
@@ -257,8 +256,7 @@ static int name_index_get_devices(struct udev *udev, const char *name, struct ud
                if (ent->d_name[0] == '.')
                        continue;
 
-               util_strlcpy(device, udev_get_sys_path(udev), sizeof(device));
-               util_strlcat(device, ent->d_name, sizeof(device));
+               util_strscpyl(device, sizeof(device), udev_get_sys_path(udev), ent->d_name, NULL);
                util_path_decode(device);
                udev_list_entry_add(udev, dev_list, device, NULL, 1, 0);
                count++;
@@ -268,51 +266,51 @@ out:
        return count;
 }
 
-static int update_link(struct udev_device *dev, const char *slink, int test)
+static int update_link(struct udev_device *dev, const char *slink)
 {
        struct udev *udev = udev_device_get_udev(dev);
        struct udev_list_node dev_list;
        struct udev_list_entry *dev_entry;
-       char target[UTIL_PATH_SIZE] = "";
+       char target[UTIL_PATH_SIZE];
        int count;
        int priority = 0;
        int rc = 0;
 
-       info(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
+       dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
 
        udev_list_init(&dev_list);
        count = name_index_get_devices(udev, slink, &dev_list);
-       info(udev, "found %i devices with name '%s'\n", count, slink);
+       if (count > 1)
+               info(udev, "found %i devices with name '%s'\n", count, slink);
 
        /* if we don't have a reference, delete it */
        if (count <= 0) {
                info(udev, "no reference left, remove '%s'\n", slink);
-               if (!test) {
-                       unlink(slink);
-                       delete_path(udev, slink);
-               }
+               unlink(slink);
+               util_delete_path(udev, slink);
                goto out;
        }
 
        /* find the device with the highest priority */
+       target[0] = '\0';
        udev_list_entry_foreach(dev_entry, udev_list_get_entry(&dev_list)) {
                const char *syspath;
                struct udev_device *dev_db;
                const char *devnode;
 
                syspath = udev_list_entry_get_name(dev_entry);
-               info(udev, "found '%s' for '%s'\n", syspath, slink);
+               dbg(udev, "found '%s' for '%s'\n", syspath, slink);
 
                /* did we find ourself? we win, if we have the same priority */
                if (strcmp(udev_device_get_syspath(dev), syspath) == 0) {
-                       info(udev, "compare (our own) priority of '%s' %i >= %i\n",
-                            udev_device_get_devpath(dev), udev_device_get_devlink_priority(dev), priority);
+                       dbg(udev, "compare (our own) priority of '%s' %i >= %i\n",
+                           udev_device_get_devpath(dev), udev_device_get_devlink_priority(dev), priority);
                        if (strcmp(udev_device_get_devnode(dev), slink) == 0) {
                                info(udev, "'%s' is our device node, database inconsistent, skip link update\n",
                                     udev_device_get_devnode(dev));
                        } else if (target[0] == '\0' || udev_device_get_devlink_priority(dev) >= priority) {
                                priority = udev_device_get_devlink_priority(dev);
-                               util_strlcpy(target, udev_device_get_devnode(dev), sizeof(target));
+                               util_strscpy(target, sizeof(target), udev_device_get_devnode(dev));
                        }
                        continue;
                }
@@ -327,19 +325,19 @@ static int update_link(struct udev_device *dev, const char *slink, int test)
                                info(udev, "'%s' is a device node of '%s', skip link update\n",
                                     devnode, syspath);
                        } else {
-                               info(udev, "compare priority of '%s' %i > %i\n",
-                                    udev_device_get_devpath(dev_db),
-                                    udev_device_get_devlink_priority(dev_db),
-                                    priority);
+                               dbg(udev, "compare priority of '%s' %i > %i\n",
+                                   udev_device_get_devpath(dev_db),
+                                   udev_device_get_devlink_priority(dev_db),
+                                   priority);
                                if (target[0] == '\0' || udev_device_get_devlink_priority(dev_db) > priority) {
                                        priority = udev_device_get_devlink_priority(dev_db);
-                                       util_strlcpy(target, devnode, sizeof(target));
+                                       util_strscpy(target, sizeof(target), devnode);
                                }
                        }
                }
                udev_device_unref(dev_db);
        }
-       udev_list_cleanup(udev, &dev_list);
+       udev_list_cleanup_entries(udev, &dev_list);
 
        if (target[0] == '\0') {
                info(udev, "no current target for '%s' found\n", slink);
@@ -349,15 +347,13 @@ static int update_link(struct udev_device *dev, const char *slink, int test)
 
        /* create symlink to the target with the highest priority */
        info(udev, "'%s' with target '%s' has the highest priority %i, create it\n", slink, target, priority);
-       if (!test) {
-               create_path(udev, slink);
-               node_symlink(udev, target, slink);
-       }
+       util_create_path(udev, slink);
+       node_symlink(udev, target, slink);
 out:
        return rc;
 }
 
-void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old, int test)
+void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old)
 {
        struct udev *udev = udev_device_get_udev(dev);
        struct udev_list_entry *list_entry;
@@ -365,113 +361,98 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev
 
        /* update possible left-over symlinks */
        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) {
+               const char *name = udev_list_entry_get_name(list_entry);
                struct udev_list_entry *list_entry_current;
+               int found;
+
+               /* check if old link name is now our node name */
+               if (strcmp(name, udev_device_get_devnode(dev)) == 0)
+                       continue;
 
+               /* check if old link name still belongs to this device */
+               found = 0;
                udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) {
-                       if (strcmp(udev_list_entry_get_name(list_entry_current),
-                                  udev_list_entry_get_name(list_entry)) == 0)
-                               continue;
+                       const char *name_current = udev_list_entry_get_name(list_entry_current);
+
+                       if (strcmp(name, name_current) == 0) {
+                               found = 1;
+                               break;
+                       }
                }
-               /* link does no longer belong to this device */
-               info(udev, "update old symlink '%s' no longer belonging to '%s'\n",
-                    udev_list_entry_get_name(list_entry), udev_device_get_devpath(dev));
-               update_link(dev, udev_list_entry_get_name(list_entry), test);
+               if (found)
+                       continue;
+
+               info(udev, "update old name, '%s' no longer belonging to '%s'\n",
+                    name, udev_device_get_devpath(dev));
+               name_index(udev, udev_device_get_devpath(dev), name, 0);
+               update_link(dev, name);
        }
 
        /*
         * if the node name has changed, delete the node,
-        * and possibly restore a symlink of another device
+        * and possibly restore a symlink of a different device
         */
        devnode_old = udev_device_get_devnode(dev_old);
        if (devnode_old != NULL) {
                const char *devnode = udev_device_get_devnode(dev);
 
-               if (devnode != NULL && strcmp(devnode_old, devnode) != 0)
-                       update_link(dev, devnode_old, test);
+               if (devnode != NULL && strcmp(devnode_old, devnode) != 0) {
+                       info(udev, "node has changed from '%s' to '%s'\n", devnode_old, devnode);
+                       name_index(udev, udev_device_get_devpath(dev), devnode_old, 0);
+                       update_link(dev, devnode_old);
+               }
        }
 }
 
-int udev_node_add(struct udev_device *dev, mode_t mode, const char *owner, const char *group, int test)
+int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
 {
        struct udev *udev = udev_device_get_udev(dev);
-       uid_t uid;
-       gid_t gid;
        int i;
        int num;
        struct udev_list_entry *list_entry;
        int err = 0;
 
-       create_path(udev, udev_device_get_devnode(dev));
-
-       if (strcmp(owner, "root") == 0)
-               uid = 0;
-       else {
-               char *endptr;
-               unsigned long id;
-
-               id = strtoul(owner, &endptr, 10);
-               if (endptr[0] == '\0')
-                       uid = (uid_t) id;
-               else
-                       uid = lookup_user(udev, owner);
-       }
-
-       if (strcmp(group, "root") == 0)
-               gid = 0;
-       else {
-               char *endptr;
-               unsigned long id;
-
-               id = strtoul(group, &endptr, 10);
-               if (endptr[0] == '\0')
-                       gid = (gid_t) id;
-               else
-                       gid = lookup_group(udev, group);
-       }
-
        info(udev, "creating device node '%s', devnum=%d:%d, mode=%#o, uid=%d, gid=%d\n",
             udev_device_get_devnode(dev),
             major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)),
             mode, uid, gid);
 
-       if (!test)
-               if (udev_node_mknod(dev, NULL, makedev(0,0), mode, uid, gid) != 0) {
-                       err = -1;
-                       goto exit;
-               }
+       util_create_path(udev, udev_device_get_devnode(dev));
+       if (udev_node_mknod(dev, NULL, makedev(0,0), mode, uid, gid) != 0) {
+               err = -1;
+               goto exit;
+       }
 
        /* create all_partitions if requested */
        num = udev_device_get_num_fake_partitions(dev);
        if (num > 0) {
                info(udev, "creating device partition nodes '%s[1-%i]'\n", udev_device_get_devnode(dev), num);
-               if (!test) {
-                       for (i = 1; i <= num; i++) {
-                               char partitionname[UTIL_PATH_SIZE];
-                               dev_t part_devnum;
-
-                               snprintf(partitionname, sizeof(partitionname), "%s%d",
-                                        udev_device_get_devnode(dev), i);
-                               partitionname[sizeof(partitionname)-1] = '\0';
-                               part_devnum = makedev(major(udev_device_get_devnum(dev)),
-                                                   minor(udev_device_get_devnum(dev)) + i);
-                               udev_node_mknod(dev, partitionname, part_devnum, mode, uid, gid);
-                       }
+               for (i = 1; i <= num; i++) {
+                       char partitionname[UTIL_PATH_SIZE];
+                       dev_t part_devnum;
+
+                       snprintf(partitionname, sizeof(partitionname), "%s%d",
+                                udev_device_get_devnode(dev), i);
+                       partitionname[sizeof(partitionname)-1] = '\0';
+                       part_devnum = makedev(major(udev_device_get_devnum(dev)),
+                                           minor(udev_device_get_devnum(dev)) + i);
+                       udev_node_mknod(dev, partitionname, part_devnum, mode, uid, gid);
                }
        }
 
-       /* add node and to name index */
-       name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 1, test);
+       /* add node to name index */
+       name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 1);
 
        /* create/update symlinks, add symlinks to name index */
        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
-               name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 1, test);
-               update_link(dev, udev_list_entry_get_name(list_entry), test);
+               name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 1);
+               update_link(dev, udev_list_entry_get_name(list_entry));
        }
 exit:
        return err;
 }
 
-extern int udev_node_remove(struct udev_device *dev, int test)
+int udev_node_remove(struct udev_device *dev)
 {
        struct udev *udev = udev_device_get_udev(dev);
        struct udev_list_entry *list_entry;
@@ -482,12 +463,12 @@ extern int udev_node_remove(struct udev_device *dev, int test)
        int num;
 
        /* remove node from name index */
-       name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 0, test);
+       name_index(udev, udev_device_get_devpath(dev), udev_device_get_devnode(dev), 0);
 
        /* remove,update symlinks, remove symlinks from name index */
        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
-               name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 0, test);
-               update_link(dev, udev_list_entry_get_name(list_entry), test);
+               name_index(udev, udev_device_get_devpath(dev), udev_list_entry_get_name(list_entry), 0);
+               update_link(dev, udev_list_entry_get_name(list_entry));
        }
 
        devnode = udev_device_get_devnode(dev);
@@ -503,8 +484,7 @@ extern int udev_node_remove(struct udev_device *dev, int test)
        }
 
        info(udev, "removing device node '%s'\n", devnode);
-       if (!test)
-               err = unlink_secure(udev, devnode);
+       err = util_unlink_secure(udev, devnode);
        if (err)
                return err;
 
@@ -518,10 +498,9 @@ extern int udev_node_remove(struct udev_device *dev, int test)
                for (i = 1; i <= num; i++) {
                        snprintf(partitionname, sizeof(partitionname), "%s%d", devnode, i);
                        partitionname[sizeof(partitionname)-1] = '\0';
-                       if (!test)
-                               unlink_secure(udev, partitionname);
+                       util_unlink_secure(udev, partitionname);
                }
        }
-       delete_path(udev, devnode);
+       util_delete_path(udev, devnode);
        return err;
 }