chiark / gitweb /
use more efficient string copying
[elogind.git] / udev / lib / libudev-device.c
index 38af0e7c9411bb573c20d4a240d710fc2629c47a..37b3a3b7a2e6524aca4ad3a016f4191897fa7164 100644 (file)
@@ -1,20 +1,12 @@
 /*
  * libudev - interface to udev device information
  *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
  *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
  */
 
 #include <stdio.h>
@@ -40,10 +32,11 @@ struct udev_device {
        const char *sysnum;
        char *devnode;
        char *subsystem;
+       char *devtype;
        char *driver;
        char *action;
        char *devpath_old;
-       char *physdevpath;
+       char *knodename;
        char **envp;
        char *monitor_buf;
        size_t monitor_buf_len;
@@ -57,8 +50,10 @@ struct udev_device {
        int devlink_priority;
        int refcount;
        dev_t devnum;
+       int watch_handle;
        unsigned int parent_set:1;
        unsigned int subsystem_set:1;
+       unsigned int devtype_set:1;
        unsigned int devlinks_uptodate:1;
        unsigned int envp_uptodate:1;
        unsigned int driver_set:1;
@@ -68,16 +63,15 @@ struct udev_device {
 
 static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
 {
-       size_t start;
+       char *s;
+       size_t l;
 
-       /* translate to location of db file */
-       util_strlcpy(filename, udev_get_dev_path(udev), len);
-       start = util_strlcat(filename, "/.udev/db/", len);
-       util_strlcat(filename, devpath, len);
-       return util_path_encode(&filename[start], len - start);
+       s = filename;
+       l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
+       return util_path_encode(devpath, filename, l);
 }
 
-static int device_read_db(struct udev_device *udev_device)
+int udev_device_read_db(struct udev_device *udev_device)
 {
        struct stat stats;
        char filename[UTIL_PATH_SIZE];
@@ -109,9 +103,7 @@ static int device_read_db(struct udev_device *udev_device)
                        next[0] = '\0';
                        next = &next[1];
                }
-               util_strlcpy(devnode, udev_get_dev_path(udev_device->udev), sizeof(devnode));
-               util_strlcat(devnode, "/", sizeof(devnode));
-               util_strlcat(devnode, target, sizeof(devnode));
+               util_strscpyl(devnode, sizeof(devnode), udev_get_dev_path(udev_device->udev), "/", target, NULL);
                udev_device_set_devnode(udev_device, devnode);
                while (next != NULL) {
                        char devlink[UTIL_PATH_SIZE];
@@ -123,9 +115,7 @@ static int device_read_db(struct udev_device *udev_device)
                                next[0] = '\0';
                                next = &next[1];
                        }
-                       util_strlcpy(devlink, udev_get_dev_path(udev_device->udev), sizeof(devlink));
-                       util_strlcat(devlink, "/", sizeof(devlink));
-                       util_strlcat(devlink, lnk, sizeof(devlink));
+                       util_strscpyl(devlink, sizeof(devlink), udev_get_dev_path(udev_device->udev), "/", lnk, NULL);
                        udev_device_add_devlink(udev_device, devlink);
                }
                info(udev_device->udev, "device %p filled with db symlink data '%s'\n", udev_device, udev_device->devnode);
@@ -148,15 +138,11 @@ static int device_read_db(struct udev_device *udev_device)
                val = &line[2];
                switch(line[0]) {
                case 'N':
-                       util_strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
-                       util_strlcat(filename, "/", sizeof(filename));
-                       util_strlcat(filename, val, sizeof(filename));
+                       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
                        udev_device_set_devnode(udev_device, filename);
                        break;
                case 'S':
-                       util_strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
-                       util_strlcat(filename, "/", sizeof(filename));
-                       util_strlcat(filename, val, sizeof(filename));
+                       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
                        udev_device_add_devlink(udev_device, filename);
                        break;
                case 'L':
@@ -174,6 +160,9 @@ static int device_read_db(struct udev_device *udev_device)
                case 'E':
                        udev_device_add_property_from_string(udev_device, val);
                        break;
+               case 'W':
+                       udev_device_set_watch_handle(udev_device, atoi(val));
+                       break;
                }
        }
        fclose(f);
@@ -190,8 +179,7 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
        int maj = 0;
        int min = 0;
 
-       util_strlcpy(filename, udev_device->syspath, sizeof(filename));
-       util_strlcat(filename, "/uevent", sizeof(filename));
+       util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
        f = fopen(filename, "r");
        if (f == NULL)
                return -1;
@@ -204,10 +192,14 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
                        continue;
                pos[0] = '\0';
 
-               if (strncmp(line, "MAJOR=", 6) == 0)
+               if (strncmp(line, "DEVTYPE=", 8) == 0)
+                       udev_device_set_devtype(udev_device, &line[8]);
+               else if (strncmp(line, "MAJOR=", 6) == 0)
                        maj = strtoull(&line[6], NULL, 10);
                else if (strncmp(line, "MINOR=", 6) == 0)
                        min = strtoull(&line[6], NULL, 10);
+               else if (strncmp(line, "DEVNAME=", 8) == 0)
+                       udev_device_set_knodename(udev_device, &line[8]);
 
                udev_device_add_property_from_string(udev_device, line);
        }
@@ -218,11 +210,11 @@ int udev_device_read_uevent_file(struct udev_device *udev_device)
        return 0;
 }
 
-void udev_device_load_info(struct udev_device *device)
+static void device_load_info(struct udev_device *device)
 {
        device->info_loaded = 1;
        udev_device_read_uevent_file(device);
-       device_read_db(device);
+       udev_device_read_db(device);
 }
 
 void udev_device_set_info_loaded(struct udev_device *device)
@@ -247,6 +239,7 @@ struct udev_device *device_new(struct udev *udev)
        udev_list_init(&udev_device->properties_list);
        udev_list_init(&udev_device->sysattr_list);
        udev_device->event_timeout = -1;
+       udev_device->watch_handle = -1;
        /* copy global properties */
        udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev))
                udev_device_add_property(udev_device,
@@ -294,13 +287,13 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
        /* path is not a root directory */
        subdir = &syspath[len+1];
        pos = strrchr(subdir, '/');
-       if (pos == NULL || pos < &subdir[2]) {
+       if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
                dbg(udev, "not a subdir :%s\n", syspath);
                return NULL;
        }
 
        /* resolve possible symlink to real path */
-       util_strlcpy(path, syspath, sizeof(path));
+       util_strscpy(path, sizeof(path), syspath);
        util_resolve_sys_link(udev, path, sizeof(path));
 
        /* try to resolve the silly block layout if needed */
@@ -308,16 +301,14 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
                char block[UTIL_PATH_SIZE];
                char part[UTIL_PATH_SIZE];
 
-               util_strlcpy(block, path, sizeof(block));
+               util_strscpy(block, sizeof(block), path);
                pos = strrchr(block, '/');
                if (pos == NULL)
                        return NULL;
-               util_strlcpy(part, pos, sizeof(part));
+               util_strscpy(part, sizeof(part), pos);
                pos[0] = '\0';
-               if (util_resolve_sys_link(udev, block, sizeof(block)) == 0) {
-                       util_strlcpy(path, block, sizeof(path));
-                       util_strlcat(path, part, sizeof(path));
-               }
+               if (util_resolve_sys_link(udev, block, sizeof(block)) == 0)
+                       util_strscpyl(path, sizeof(path), block, part, NULL);
        }
 
        /* path exists in sys */
@@ -327,8 +318,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *
                char file[UTIL_PATH_SIZE];
 
                /* all "devices" require a "uevent" file */
-               util_strlcpy(file, path, sizeof(file));
-               util_strlcat(file, "/uevent", sizeof(file));
+               util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
                if (stat(file, &statbuf) != 0) {
                        dbg(udev, "not a device: %s\n", syspath);
                        return NULL;
@@ -404,35 +394,31 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de
 
 struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
 {
-       size_t sys_path_len;
        char path_full[UTIL_PATH_SIZE];
        char *path;
+       size_t l;
        struct stat statbuf;
 
-       sys_path_len = util_strlcpy(path_full, udev_get_sys_path(udev), sizeof(path_full));
-       path = &path_full[sys_path_len];
+       path = path_full;
+       l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
 
        if (strcmp(subsystem, "subsystem") == 0) {
-               util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
-               util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+               util_strscpyl(path, l, "/subsystem/", sysname, NULL);
                if (stat(path_full, &statbuf) == 0)
                        goto found;
 
-               util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
-               util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+               util_strscpyl(path, l, "/bus/", sysname, NULL);
                if (stat(path_full, &statbuf) == 0)
                        goto found;
 
-               util_strlcpy(path, "/class/", sizeof(path_full) - sys_path_len);
-               util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+               util_strscpyl(path, l, "/class/", sysname, NULL);
                if (stat(path_full, &statbuf) == 0)
                        goto found;
                goto out;
        }
 
        if (strcmp(subsystem, "module") == 0) {
-               util_strlcpy(path, "/module/", sizeof(path_full) - sys_path_len);
-               util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+               util_strscpyl(path, l, "/module/", sysname, NULL);
                if (stat(path_full, &statbuf) == 0)
                        goto found;
                goto out;
@@ -442,46 +428,32 @@ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, co
                char subsys[UTIL_NAME_SIZE];
                char *driver;
 
-               util_strlcpy(subsys, sysname, sizeof(subsys));
+               util_strscpy(subsys, sizeof(subsys), sysname);
                driver = strchr(subsys, ':');
                if (driver != NULL) {
                        driver[0] = '\0';
                        driver = &driver[1];
-                       util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, subsys, sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, "/drivers/", sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, driver, sizeof(path_full) - sys_path_len);
+
+                       util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
                        if (stat(path_full, &statbuf) == 0)
                                goto found;
 
-                       util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, subsys, sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, "/drivers/", sizeof(path_full) - sys_path_len);
-                       util_strlcat(path, driver, sizeof(path_full) - sys_path_len);
+                       util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
                        if (stat(path_full, &statbuf) == 0)
                                goto found;
                }
                goto out;
        }
 
-       util_strlcpy(path, "/subsystem/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
-       util_strlcat(path, "/devices/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+       util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
        if (stat(path_full, &statbuf) == 0)
                goto found;
 
-       util_strlcpy(path, "/bus/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
-       util_strlcat(path, "/devices/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+       util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
        if (stat(path_full, &statbuf) == 0)
                goto found;
 
-       util_strlcpy(path, "/class/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, subsystem, sizeof(path_full) - sys_path_len);
-       util_strlcat(path, "/", sizeof(path_full) - sys_path_len);
-       util_strlcat(path, sysname, sizeof(path_full) - sys_path_len);
+       util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
        if (stat(path_full, &statbuf) == 0)
                goto found;
 out:
@@ -499,14 +471,15 @@ static struct udev_device *device_new_from_parent(struct udev_device *udev_devic
        /* follow "device" link in deprecated sys layout */
        if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
            strncmp(udev_device->devpath, "/block/", 7) == 0) {
-               util_strlcpy(path, udev_device->syspath, sizeof(path));
-               util_strlcat(path, "/device", sizeof(path));
-               if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0)
+               util_strscpyl(path, sizeof(path), udev_device->syspath, "/device", NULL);
+               if (util_resolve_sys_link(udev_device->udev, path, sizeof(path)) == 0) {
                        udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
-               return udev_device_parent;
+                       if (udev_device_parent != NULL)
+                               return udev_device_parent;
+               }
        }
 
-       util_strlcpy(path, udev_device->syspath, sizeof(path));
+       util_strscpy(path, sizeof(path), udev_device->syspath);
        subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
        while (1) {
                char *pos;
@@ -535,17 +508,26 @@ struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
        return udev_device->parent_device;
 }
 
-struct udev_device *udev_device_get_parent_with_subsystem(struct udev_device *udev_device, const char *subsystem)
+struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
 {
        struct udev_device *parent;
 
+       if (subsystem == NULL)
+               return NULL;
+
        parent = udev_device_get_parent(udev_device);
        while (parent != NULL) {
                const char *parent_subsystem;
+               const char *parent_devtype;
 
                parent_subsystem = udev_device_get_subsystem(parent);
-               if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0)
-                       break;
+               if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) {
+                       if (devtype == NULL)
+                               break;
+                       parent_devtype = udev_device_get_devtype(parent);
+                       if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
+                               break;
+               }
                parent = udev_device_get_parent(parent);
        }
        return parent;
@@ -603,12 +585,13 @@ void udev_device_unref(struct udev_device *udev_device)
        free(udev_device->sysname);
        free(udev_device->devnode);
        free(udev_device->subsystem);
+       free(udev_device->devtype);
        udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
        udev_list_cleanup_entries(udev_device->udev, &udev_device->properties_list);
        free(udev_device->action);
        free(udev_device->driver);
        free(udev_device->devpath_old);
-       free(udev_device->physdevpath);
+       free(udev_device->knodename);
        udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
        free(udev_device->envp);
        free(udev_device->monitor_buf);
@@ -676,7 +659,7 @@ const char *udev_device_get_devnode(struct udev_device *udev_device)
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devnode;
 }
 
@@ -721,6 +704,26 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device)
        return udev_device->subsystem;
 }
 
+/**
+ * udev_device_get_devtype:
+ * @udev_device: udev device
+ *
+ * Retrieve the devtype string of the udev device.
+ *
+ * Returns: the devtype name of the udev device, or #NULL if it can not be determined
+ **/
+const char *udev_device_get_devtype(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->devtype_set) {
+               udev_device->devtype_set = 1;
+               if (!udev_device->info_loaded)
+                       udev_device_read_uevent_file(udev_device);
+       }
+       return udev_device->devtype;
+}
+
 /**
  * udev_device_get_devlinks_list_entry:
  * @udev_device: udev device
@@ -739,7 +742,7 @@ struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_list_get_entry(&udev_device->devlinks_list);
 }
 
@@ -766,7 +769,7 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
        if (udev_device == NULL)
                return NULL;
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        if (!udev_device->devlinks_uptodate) {
                char symlinks[UTIL_PATH_SIZE];
                struct udev_list_entry *list_entry;
@@ -774,11 +777,13 @@ struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device
                udev_device->devlinks_uptodate = 1;
                list_entry = udev_device_get_devlinks_list_entry(udev_device);
                if (list_entry != NULL) {
-                       util_strlcpy(symlinks, udev_list_entry_get_name(list_entry), sizeof(symlinks));
-                       udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) {
-                               util_strlcat(symlinks, " ", sizeof(symlinks));
-                               util_strlcat(symlinks, udev_list_entry_get_name(list_entry), sizeof(symlinks));
-                       }
+                       char *s;
+                       size_t l;
+
+                       s = symlinks;
+                       l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
+                       udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
+                               l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
                        udev_device_add_property(udev_device, "DEVLINKS", symlinks);
                }
        }
@@ -804,7 +809,7 @@ dev_t udev_device_get_devnum(struct udev_device *udev_device)
        if (udev_device == NULL)
                return makedev(0, 0);
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devnum;
 }
 
@@ -826,7 +831,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
 {
        struct udev_list_entry *list_entry;
        char path[UTIL_PATH_SIZE];
-       char value[UTIL_NAME_SIZE];
+       char value[4096];
        struct stat statbuf;
        int fd;
        ssize_t size;
@@ -846,10 +851,7 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
                }
        }
 
-       util_strlcpy(path, udev_device_get_syspath(udev_device), sizeof(path));
-       util_strlcat(path, "/", sizeof(path));
-       util_strlcat(path, sysattr, sizeof(path));
-
+       util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
        if (lstat(path, &statbuf) != 0) {
                dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
                udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, NULL, 0, 0);
@@ -857,11 +859,16 @@ const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const
        }
 
        if (S_ISLNK(statbuf.st_mode)) {
-               /* links return the last element of the target path */
                char target[UTIL_NAME_SIZE];
                int len;
                char *pos;
 
+               /* some core links return the last element of the target path */
+               if (strcmp(sysattr, "driver") != 0 &&
+                   strcmp(sysattr, "subsystem") != 0 &&
+                   strcmp(sysattr, "module") != 0)
+                       goto out;
+
                len = readlink(path, target, sizeof(target));
                if (len > 0) {
                        target[len] = '\0';
@@ -956,6 +963,17 @@ int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsy
        return 0;
 }
 
+int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype)
+{
+       free(udev_device->devtype);
+       udev_device->devtype = strdup(devtype);
+       if (udev_device->devtype == NULL)
+               return -ENOMEM;
+       udev_device->devtype_set = 1;
+       udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
+       return 0;
+}
+
 int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode)
 {
        free(udev_device->devnode);
@@ -996,7 +1014,7 @@ struct udev_list_entry *udev_device_add_property_from_string(struct udev_device
        char name[UTIL_PATH_SIZE];
        char *val;
 
-       util_strlcpy(name, property, sizeof(name));
+       util_strscpy(name, sizeof(name), property);
        val = strchr(name, '=');
        if (val == NULL)
                return NULL;
@@ -1007,14 +1025,27 @@ struct udev_list_entry *udev_device_add_property_from_string(struct udev_device
        return udev_device_add_property(udev_device, name, val);
 }
 
+const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
+{
+       struct udev_list_entry *list_entry;
+
+       if (udev_device == NULL)
+               return NULL;
+       if (key == NULL)
+               return NULL;
+
+       list_entry = udev_device_get_properties_list_entry(udev_device);
+       list_entry =  udev_list_entry_get_by_name(list_entry, key);
+       return udev_list_entry_get_value(list_entry);
+}
+
 #define ENVP_SIZE                      128
 #define MONITOR_BUF_SIZE               4096
 static int update_envp_monitor_buf(struct udev_device *udev_device)
 {
-       const char *action;
        struct udev_list_entry *list_entry;
-       size_t bufpos;
-       size_t len;
+       char *s;
+       size_t l;
        unsigned int i;
 
        /* monitor buffer of property strings */
@@ -1030,49 +1061,27 @@ static int update_envp_monitor_buf(struct udev_device *udev_device)
        if (udev_device->envp == NULL)
                return -ENOMEM;
 
-       /* header <action>@<devpath> */
-       action = udev_device_get_action(udev_device);
-       if (action == NULL)
-               return -EINVAL;
-       bufpos = util_strlcpy(udev_device->monitor_buf, action, MONITOR_BUF_SIZE);
-       len = util_strlcpy(&udev_device->monitor_buf[bufpos], "@", MONITOR_BUF_SIZE-bufpos);
-       if (len >= MONITOR_BUF_SIZE-bufpos)
-               return -EINVAL;
-       bufpos += len;
-       len = util_strlcpy(&udev_device->monitor_buf[bufpos],
-                          udev_device_get_devpath(udev_device),
-                          MONITOR_BUF_SIZE-bufpos);
-       if (len+1 >= MONITOR_BUF_SIZE-bufpos)
-               return -EINVAL;
-       bufpos += len+1;
-
        i = 0;
+       s = udev_device->monitor_buf;
+       l = MONITOR_BUF_SIZE;
        udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
                /* add string to envp array */
-               udev_device->envp[i++] = &udev_device->monitor_buf[bufpos];
+               udev_device->envp[i++] = s;
                if (i+1 >= ENVP_SIZE)
                        return -EINVAL;
 
                /* add property string to monitor buffer */
-               len = util_strlcpy(&udev_device->monitor_buf[bufpos],
-                                  udev_list_entry_get_name(list_entry), MONITOR_BUF_SIZE-bufpos);
-               if (len >= MONITOR_BUF_SIZE-bufpos)
+               l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), "=",
+                                 udev_list_entry_get_value(list_entry), NULL);
+               if (l == 0)
                        return -EINVAL;
-               bufpos += len;
-               len = util_strlcpy(&udev_device->monitor_buf[bufpos], "=", MONITOR_BUF_SIZE-bufpos);
-               if (len >= MONITOR_BUF_SIZE-bufpos)
-                       return -EINVAL;
-               bufpos += len;
-               len = util_strlcpy(&udev_device->monitor_buf[bufpos], udev_list_entry_get_value(list_entry),
-                                  MONITOR_BUF_SIZE-bufpos);
-               if (len+1 >= MONITOR_BUF_SIZE-bufpos)
-                       return -EINVAL;
-               bufpos += len+1;
+               s++;
        }
        udev_device->envp[i] = NULL;
-       udev_device->monitor_buf_len = bufpos;
+       udev_device->monitor_buf_len = s - udev_device->monitor_buf;
        udev_device->envp_uptodate = 1;
-       dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n", i, bufpos);
+       dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
+           i, udev_device->monitor_buf_len);
        return 0;
 }
 
@@ -1128,15 +1137,15 @@ int udev_device_set_devpath_old(struct udev_device *udev_device, const char *dev
        return 0;
 }
 
-const char *udev_device_get_physdevpath(struct udev_device *udev_device)
+const char *udev_device_get_knodename(struct udev_device *udev_device)
 {
-       return udev_device->physdevpath;
+       return udev_device->knodename;
 }
 
-int udev_device_set_physdevpath(struct udev_device *udev_device, const char *physdevpath)
+int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename)
 {
-       udev_device->physdevpath = strdup(physdevpath);
-       if (udev_device->physdevpath == NULL)
+       udev_device->knodename = strdup(knodename);
+       if (udev_device->knodename == NULL)
                return -ENOMEM;
        return 0;
 }
@@ -1154,7 +1163,7 @@ int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
 int udev_device_get_event_timeout(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->event_timeout;
 }
 
@@ -1190,7 +1199,7 @@ int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
 int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->num_fake_partitions;
 }
 
@@ -1203,7 +1212,7 @@ int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num
 int udev_device_get_devlink_priority(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->devlink_priority;
 }
 
@@ -1216,7 +1225,7 @@ int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
 int udev_device_get_ignore_remove(struct udev_device *udev_device)
 {
        if (!udev_device->info_loaded)
-               udev_device_load_info(udev_device);
+               device_load_info(udev_device);
        return udev_device->ignore_remove;
 }
 
@@ -1225,3 +1234,16 @@ int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore)
        udev_device->ignore_remove = ignore;
        return 0;
 }
+
+int udev_device_get_watch_handle(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->watch_handle;
+}
+
+int udev_device_set_watch_handle(struct udev_device *udev_device, int handle)
+{
+       udev_device->watch_handle = handle;
+       return 0;
+}