]> git.proxmox.com Git - systemd.git/commitdiff
libudev: move to top-level directory
authorKay Sievers <kay.sievers@vrfy.org>
Mon, 8 Jun 2009 19:36:06 +0000 (21:36 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Mon, 8 Jun 2009 19:36:06 +0000 (21:36 +0200)
50 files changed:
Makefile.am
Makefile.am.inc
configure.ac
extras/ata_id/Makefile.am
extras/cdrom_id/Makefile.am
extras/collect/Makefile.am
extras/collect/collect.c
extras/edd_id/Makefile.am
extras/floppy/Makefile.am
extras/fstab_import/Makefile.am
extras/path_id/Makefile.am
extras/path_id/path_id.c
extras/scsi_id/Makefile.am
extras/usb_id/Makefile.am
libudev/.gitignore [new file with mode: 0644]
libudev/Makefile.am [new file with mode: 0644]
libudev/exported_symbols [new file with mode: 0644]
libudev/libudev-ctrl.c [new file with mode: 0644]
libudev/libudev-device-db-write.c [new file with mode: 0644]
libudev/libudev-device.c [new file with mode: 0644]
libudev/libudev-enumerate.c [new file with mode: 0644]
libudev/libudev-list.c [new file with mode: 0644]
libudev/libudev-monitor.c [new file with mode: 0644]
libudev/libudev-private.h [new file with mode: 0644]
libudev/libudev-queue-export.c [new file with mode: 0644]
libudev/libudev-queue.c [new file with mode: 0644]
libudev/libudev-util.c [new file with mode: 0644]
libudev/libudev.c [new file with mode: 0644]
libudev/libudev.h [new file with mode: 0644]
libudev/libudev.pc.in [new file with mode: 0644]
libudev/test-libudev.c [new file with mode: 0644]
udev/Makefile.am
udev/lib/.gitignore [deleted file]
udev/lib/Makefile.am [deleted file]
udev/lib/exported_symbols [deleted file]
udev/lib/libudev-ctrl.c [deleted file]
udev/lib/libudev-device-db-write.c [deleted file]
udev/lib/libudev-device.c [deleted file]
udev/lib/libudev-enumerate.c [deleted file]
udev/lib/libudev-list.c [deleted file]
udev/lib/libudev-monitor.c [deleted file]
udev/lib/libudev-private.h [deleted file]
udev/lib/libudev-queue-export.c [deleted file]
udev/lib/libudev-queue.c [deleted file]
udev/lib/libudev-util.c [deleted file]
udev/lib/libudev.c [deleted file]
udev/lib/libudev.h [deleted file]
udev/lib/libudev.pc.in [deleted file]
udev/lib/test-libudev.c [deleted file]
udev/udev.h

index 1bb2d7773b5ffd53f0290629a3191e734d09f87e..678a3e426acd156a24fe4defe03fe449649909e2 100644 (file)
@@ -1,6 +1,7 @@
 include $(top_srcdir)/Makefile.am.inc
 
 SUBDIRS = \
+       libudev \
        udev \
        rules \
        extras
index 7ecd55de78fe06e861ca570aadaf7dd8ce6afb69..802143bb6b14a3f734791185872a41d95753ddda 100644 (file)
@@ -1,8 +1,8 @@
 AM_CPPFLAGS = \
        -include $(top_builddir)/config.h \
+       -I$(top_builddir)/libudev \
        -DSYSCONFDIR=\""$(sysconfdir)"\" \
-       -DUDEV_PREFIX=\""$(udev_prefix)"\" \
-       -D_LIBUDEV_COMPILATION
+       -DUDEV_PREFIX=\""$(udev_prefix)"\"
 
 AM_CFLAGS =
 
index 9857d52e4efa3aa538ba0214c73500490b261506..e9c949647abdc2a40673e9829e0b1a4cbaa4360d 100644 (file)
@@ -70,9 +70,9 @@ fi
 AC_CONFIG_HEADERS(config.h)
 AC_CONFIG_FILES([
        Makefile
+       libudev/Makefile
+       libudev/libudev.pc
        udev/Makefile
-       udev/lib/Makefile
-       udev/lib/libudev.pc
        rules/Makefile
        extras/Makefile
        extras/ata_id/Makefile
index d31fd2c93c06a3c1acb277e43740edc0d97b98bf..ffbdba32f28e7c4a22634009d4d0c0fd9f174e61 100644 (file)
@@ -6,10 +6,10 @@ udevhome_PROGRAMS = \
 
 ata_id_SOURCES = \
        ata_id.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../udev/udev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
 dist_man_MANS = \
        ata_id.8
index 51b6a20ee238bc14e54b761f94ab4b009dd8b7de..8e1968e6e13e67e755bdaada16e8fc238e8b8b95 100644 (file)
@@ -10,10 +10,10 @@ dist_udevrules_DATA = \
 
 cdrom_id_SOURCES = \
        cdrom_id.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
 dist_man_MANS = \
        cdrom_id.8
index d9792b89ebf726c3bc73035213cc189871903868..7ad2937f5d6a8999f05839f65e4b6f9819d2d375 100644 (file)
@@ -6,7 +6,7 @@ udevhome_PROGRAMS = \
 
 collect_SOURCES = \
        collect.c \
-       ../../udev/lib/libudev-private.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-util.c \
-       ../../udev/lib/libudev-list.c
+       ../../libudev/libudev-private.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-util.c \
+       ../../libudev/libudev-list.c
index 3a7e826e4dfd0ce80b914cdfd0196d1cb66ce529..3284c3df40209a11cbe052fb188757f2f69d5391 100644 (file)
@@ -31,8 +31,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "../../udev/lib/libudev.h"
-#include "../../udev/lib/libudev-private.h"
+#include "libudev.h"
+#include "libudev-private.h"
 
 #define TMPFILE                        UDEV_PREFIX "/dev/.udev/collect"
 #define BUFSIZE                        16
index 9bfe43231f926d36d5265388c8924cec3c5ef498..7c562d3c31314a3dac5ee699a725f49f32e7fa94 100644 (file)
@@ -10,10 +10,10 @@ dist_udevrules_DATA = \
 
 edd_id_SOURCES = \
        edd_id.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
 dist_man_MANS = \
        edd_id.8
index 8cb9cbd47d75f29209d6203f3fe8e22a2bd9d9b0..2baaa10f022f8ecf474a62892873a7ee0661e918 100644 (file)
@@ -6,12 +6,12 @@ udevhome_PROGRAMS = \
 
 create_floppy_devices_SOURCES = \
        create_floppy_devices.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c \
-       ../../udev/lib/libudev-device.c \
-       ../../udev/lib/libudev-enumerate.c \
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c \
+       ../../libudev/libudev-device.c \
+       ../../libudev/libudev-enumerate.c \
        ../../udev/udev-util.c
 
 if USE_SELINUX
index c63dc7cf178c8c557c96769869ffac5a22bd559c..42acfd15cfc3d2cfe9ecabf40f7b6afa766b1d78 100644 (file)
@@ -10,8 +10,8 @@ dist_udevrules_DATA = \
 
 fstab_import_SOURCES = \
        fstab_import.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
index 5d4bf6283d4fc6b52a51de0088e02cd3e3082c2c..867ad5ef8ed13d1cc7b81cff0a7825a76322af15 100644 (file)
@@ -6,12 +6,12 @@ udevhome_PROGRAMS = \
 
 path_id_SOURCES = \
        path_id.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-device.c \
-       ../../udev/lib/libudev-enumerate.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-device.c \
+       ../../libudev/libudev-enumerate.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
 dist_man_MANS = \
        path_id.8
index 08b7e150c9dacfd37ad17111a7ec7b0e58c90dd2..dbb52bad2141ffc06308bbd45f5e5fe6ee980f8c 100644 (file)
@@ -28,8 +28,8 @@
 #include <dirent.h>
 #include <getopt.h>
 
-#include <../../udev/lib/libudev.h>
-#include <../../udev/udev.h>
+#include "libudev.h"
+#include "../../udev/udev.h"
 
 int debug;
 
@@ -366,7 +366,7 @@ int main(int argc, char **argv)
        if (udev == NULL)
                goto exit;
 
-       logging_init("usb_id");
+       logging_init("path_id");
        udev_set_log_fn(udev, log_fn);
 
        while (1) {
index 29d5fe7344174e62e2ca5d72e39c989f42f810f3..ffebc38e20a6690227a9b7f9651f3752e9450877 100644 (file)
@@ -10,10 +10,10 @@ scsi_id_SOURCES = \
        scsi.h \
        scsi_id.h \
        bsg.h \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c
 
 dist_sysconf_DATA = \
        scsi_id.config
index 07b286d61f3882e8b7a9052d6a0b64258366c15d..a9bd407031cfa7bc9caf25e491a035338e8b6eb2 100644 (file)
@@ -6,12 +6,12 @@ udevhome_PROGRAMS = \
 
 usb_id_SOURCES = \
        usb_id.c \
-       ../../udev/lib/libudev.h \
-       ../../udev/lib/libudev.c \
-       ../../udev/lib/libudev-list.c \
-       ../../udev/lib/libudev-util.c \
-       ../../udev/lib/libudev-device.c \
-       ../../udev/lib/libudev-enumerate.c
+       ../../libudev/libudev.h \
+       ../../libudev/libudev.c \
+       ../../libudev/libudev-list.c \
+       ../../libudev/libudev-util.c \
+       ../../libudev/libudev-device.c \
+       ../../libudev/libudev-enumerate.c
 
 dist_man_MANS = \
        usb_id.8
diff --git a/libudev/.gitignore b/libudev/.gitignore
new file mode 100644 (file)
index 0000000..74a5f1d
--- /dev/null
@@ -0,0 +1,4 @@
+test-libudev
+libudev.pc
+libudev.so*
+
diff --git a/libudev/Makefile.am b/libudev/Makefile.am
new file mode 100644 (file)
index 0000000..1f0bf2f
--- /dev/null
@@ -0,0 +1,54 @@
+include $(top_srcdir)/Makefile.am.inc
+
+noinst_PROGRAMS = \
+       test-libudev
+
+test_libudev_SOURCES = \
+       test-libudev.c
+
+test_libudev_LDADD = \
+       libudev.la
+
+rootlibdir = $(exec_prefix)/$(libdir_name)
+rootlib_LTLIBRARIES = \
+       libudev.la
+
+include_HEADERS =\
+       libudev.h
+
+libudev_la_SOURCES =\
+       libudev-private.h \
+       libudev.c \
+       libudev-list.c \
+       libudev-util.c \
+       libudev-device.c \
+       libudev-enumerate.c \
+       libudev-monitor.c \
+       libudev-queue.c
+
+libudev_la_LDFLAGS = \
+       -version-info $(LIBUDEV_LT_CURRENT):$(LIBUDEV_LT_REVISION):$(LIBUDEV_LT_AGE) \
+       -export-symbols $(top_srcdir)/libudev/exported_symbols
+
+pkgconfigdir = $(prefix)/$(libdir_name)/pkgconfig
+pkgconfig_DATA = libudev.pc
+
+EXTRA_DIST = \
+       exported_symbols
+
+# move devel files to $(prefix)$(libdir_name) if needed
+install-data-hook:
+       rm  $(DESTDIR)$(rootlibdir)/libudev.la
+       if test "$(prefix)" != "$(exec_prefix)"; then \
+               mkdir -p $(DESTDIR)$(prefix)/$(libdir_name); \
+               mv $(DESTDIR)$(rootlibdir)/libudev.a $(DESTDIR)$(prefix)/$(libdir_name)/; \
+               so_img_name=$$(readlink $(DESTDIR)$(rootlibdir)/libudev.so); \
+               rm $(DESTDIR)$(rootlibdir)/libudev.so; \
+               so_img_rel_target_prefix=$$(echo $(prefix)/$(libdir_name) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
+               ln -sf  $$so_img_rel_target_prefix$(exec_prefix)/$(libdir_name)/$$so_img_name \
+                       $(DESTDIR)$(prefix)/$(libdir_name)/libudev.so; \
+       fi
+
+uninstall-hook:
+       rm -f $(DESTDIR)$(prefix)/$(libdir_name)/libudev.a
+       rm -f $(DESTDIR)$(prefix)/$(libdir_name)/libudev.so*
diff --git a/libudev/exported_symbols b/libudev/exported_symbols
new file mode 100644 (file)
index 0000000..8e7749e
--- /dev/null
@@ -0,0 +1,73 @@
+udev_new
+udev_ref
+udev_unref
+udev_set_log_fn
+udev_get_log_priority
+udev_set_log_priority
+udev_get_userdata
+udev_set_userdata
+udev_get_sys_path
+udev_get_dev_path
+udev_list_entry_get_next
+udev_list_entry_get_by_name
+udev_list_entry_get_name
+udev_list_entry_get_value
+udev_device_new_from_syspath
+udev_device_new_from_devnum
+udev_device_new_from_subsystem_sysname
+udev_device_get_parent
+udev_device_get_parent_with_subsystem_devtype
+udev_device_ref
+udev_device_unref
+udev_device_get_udev
+udev_device_get_syspath
+udev_device_get_devpath
+udev_device_get_devnode
+udev_device_get_sysname
+udev_device_get_sysnum
+udev_device_get_subsystem
+udev_device_get_devtype
+udev_device_get_devlinks_list_entry
+udev_device_get_properties_list_entry
+udev_device_get_property_value
+udev_device_get_action
+udev_device_get_driver
+udev_device_get_devnum
+udev_device_get_seqnum
+udev_device_get_sysattr_value
+udev_enumerate_new
+udev_enumerate_ref
+udev_enumerate_unref
+udev_enumerate_get_udev
+udev_enumerate_get_list_entry
+udev_enumerate_add_match_subsystem
+udev_enumerate_add_nomatch_subsystem
+udev_enumerate_add_match_sysattr
+udev_enumerate_add_nomatch_sysattr
+udev_enumerate_add_match_property
+udev_enumerate_scan_devices
+udev_enumerate_scan_subsystems
+udev_enumerate_add_syspath
+udev_monitor_new_from_socket
+udev_monitor_new_from_netlink
+udev_monitor_enable_receiving
+udev_monitor_ref
+udev_monitor_unref
+udev_monitor_get_udev
+udev_monitor_get_fd
+udev_monitor_receive_device
+udev_monitor_filter_add_match_subsystem_devtype
+udev_monitor_filter_update
+udev_monitor_filter_remove
+udev_queue_new
+udev_queue_ref
+udev_queue_unref
+udev_queue_get_udev
+udev_queue_get_kernel_seqnum
+udev_queue_get_udev_seqnum
+udev_queue_get_udev_is_active
+udev_queue_get_queue_is_empty
+udev_queue_get_seqnum_is_finished
+udev_queue_get_seqnum_sequence_is_finished
+udev_queue_get_queued_list_entry
+udev_queue_get_failed_list_entry
diff --git a/libudev/libudev-ctrl.c b/libudev/libudev-ctrl.c
new file mode 100644 (file)
index 0000000..e47b2b6
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+/* wire protocol magic must match */
+#define UDEV_CTRL_MAGIC                                0xdead1dea
+
+enum udev_ctrl_msg_type {
+       UDEV_CTRL_UNKNOWN,
+       UDEV_CTRL_SET_LOG_LEVEL,
+       UDEV_CTRL_STOP_EXEC_QUEUE,
+       UDEV_CTRL_START_EXEC_QUEUE,
+       UDEV_CTRL_RELOAD_RULES,
+       UDEV_CTRL_SET_ENV,
+       UDEV_CTRL_SET_MAX_CHILDS,
+       UDEV_CTRL_SET_MAX_CHILDS_RUNNING,
+       UDEV_CTRL_SETTLE,
+};
+
+struct udev_ctrl_msg_wire {
+       char version[16];
+       unsigned int magic;
+       enum udev_ctrl_msg_type type;
+       union {
+               int intval;
+               char buf[256];
+       };
+};
+
+struct udev_ctrl_msg {
+       int refcount;
+       struct udev_ctrl *uctrl;
+       struct udev_ctrl_msg_wire ctrl_msg_wire;
+       pid_t pid;
+};
+
+struct udev_ctrl {
+       int refcount;
+       struct udev *udev;
+       int sock;
+       struct sockaddr_un saddr;
+       socklen_t addrlen;
+};
+
+struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path)
+{
+       struct udev_ctrl *uctrl;
+
+       uctrl = calloc(1, sizeof(struct udev_ctrl));
+       if (uctrl == NULL)
+               return NULL;
+       uctrl->refcount = 1;
+       uctrl->udev = udev;
+
+       uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+       if (uctrl->sock < 0) {
+               err(udev, "error getting socket: %m\n");
+               udev_ctrl_unref(uctrl);
+               return NULL;
+       }
+
+       uctrl->saddr.sun_family = AF_LOCAL;
+       strcpy(uctrl->saddr.sun_path, socket_path);
+       uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
+       /* translate leading '@' to abstract namespace */
+       if (uctrl->saddr.sun_path[0] == '@')
+               uctrl->saddr.sun_path[0] = '\0';
+
+       return uctrl;
+}
+
+int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
+{
+       int err;
+       const int feature_on = 1;
+
+       err= bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
+       if (err < 0) {
+               err(uctrl->udev, "bind failed: %m\n");
+               return err;
+       }
+
+       /* enable receiving of the sender credentials */
+       setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
+       return 0;
+}
+
+struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
+{
+       return uctrl->udev;
+}
+
+struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
+{
+       if (uctrl == NULL)
+               return NULL;
+       uctrl->refcount++;
+       return uctrl;
+}
+
+void udev_ctrl_unref(struct udev_ctrl *uctrl)
+{
+       if (uctrl == NULL)
+               return;
+       uctrl->refcount--;
+       if (uctrl->refcount > 0)
+               return;
+       if (uctrl->sock >= 0)
+               close(uctrl->sock);
+       free(uctrl);
+}
+
+int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
+{
+       if (uctrl == NULL)
+               return -1;
+       return uctrl->sock;
+}
+
+static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf)
+{
+       struct udev_ctrl_msg_wire ctrl_msg_wire;
+       int err;
+
+       memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
+       strcpy(ctrl_msg_wire.version, "udev-" VERSION);
+       ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
+       ctrl_msg_wire.type = type;
+
+       if (buf != NULL)
+               util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
+       else
+               ctrl_msg_wire.intval = intval;
+
+       err = sendto(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0,
+                    (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
+       if (err == -1) {
+               err(uctrl->udev, "error sending message: %m\n");
+       }
+       return err;
+}
+
+int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
+}
+
+int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
+}
+
+int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
+}
+
+int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL);
+}
+
+int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
+}
+
+int udev_ctrl_send_set_max_childs(struct udev_ctrl *uctrl, int count)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_SET_MAX_CHILDS, count, NULL);
+}
+
+int udev_ctrl_send_settle(struct udev_ctrl *uctrl)
+{
+       return ctrl_send(uctrl, UDEV_CTRL_SETTLE, 0, NULL);
+}
+
+struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl)
+{
+       struct udev_ctrl_msg *uctrl_msg;
+       ssize_t size;
+       struct msghdr smsg;
+       struct cmsghdr *cmsg;
+       struct iovec iov;
+       struct ucred *cred;
+       char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+
+       uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
+       if (uctrl_msg == NULL)
+               return NULL;
+       uctrl_msg->refcount = 1;
+       uctrl_msg->uctrl = uctrl;
+
+       iov.iov_base = &uctrl_msg->ctrl_msg_wire;
+       iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
+
+       memset(&smsg, 0x00, sizeof(struct msghdr));
+       smsg.msg_iov = &iov;
+       smsg.msg_iovlen = 1;
+       smsg.msg_control = cred_msg;
+       smsg.msg_controllen = sizeof(cred_msg);
+
+       size = recvmsg(uctrl->sock, &smsg, 0);
+       if (size <  0) {
+               err(uctrl->udev, "unable to receive user udevd message: %m\n");
+               goto err;
+       }
+       cmsg = CMSG_FIRSTHDR(&smsg);
+       cred = (struct ucred *) CMSG_DATA(cmsg);
+
+       if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+               err(uctrl->udev, "no sender credentials received, message ignored\n");
+               goto err;
+       }
+
+       if (cred->uid != 0) {
+               err(uctrl->udev, "sender uid=%i, message ignored\n", cred->uid);
+               goto err;
+       }
+
+       uctrl_msg->pid = cred->pid;
+
+       if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
+               err(uctrl->udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
+               goto err;
+       }
+
+       dbg(uctrl->udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
+       return uctrl_msg;
+err:
+       udev_ctrl_msg_unref(uctrl_msg);
+       return NULL;
+}
+
+struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg == NULL)
+               return NULL;
+       ctrl_msg->refcount++;
+       return ctrl_msg;
+}
+
+void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg == NULL)
+               return;
+       ctrl_msg->refcount--;
+       if (ctrl_msg->refcount > 0)
+               return;
+       dbg(ctrl_msg->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
+       free(ctrl_msg);
+}
+
+int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
+               return ctrl_msg->ctrl_msg_wire.intval;
+       return -1;
+}
+
+int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
+               return 1;
+       return -1;
+}
+
+int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
+               return 1;
+       return -1;
+}
+
+int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD_RULES)
+               return 1;
+       return -1;
+}
+
+const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
+               return ctrl_msg->ctrl_msg_wire.buf;
+       return NULL;
+}
+
+int udev_ctrl_get_set_max_childs(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_MAX_CHILDS)
+               return ctrl_msg->ctrl_msg_wire.intval;
+       return -1;
+}
+
+pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg)
+{
+       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SETTLE)
+               return ctrl_msg->pid;
+       return -1;
+}
diff --git a/libudev/libudev-device-db-write.c b/libudev/libudev-device-db-write.c
new file mode 100644 (file)
index 0000000..a8e66f7
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "udev.h"
+
+static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
+{
+       char *s;
+       size_t l;
+
+       s = filename;
+       l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
+       return util_path_encode(devpath, s, l);
+}
+
+int udev_device_update_db(struct udev_device *udev_device)
+{
+       struct udev *udev = udev_device_get_udev(udev_device);
+       char filename[UTIL_PATH_SIZE];
+       FILE *f;
+       char target[232]; /* on 64bit, tmpfs inlines up to 239 bytes */
+       size_t devlen = strlen(udev_get_dev_path(udev))+1;
+       char *s;
+       size_t l;
+       struct udev_list_entry *list_entry;
+       int ret;
+
+       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
+       util_create_path(udev, filename);
+       unlink(filename);
+
+       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
+               if (udev_list_entry_get_flag(list_entry))
+                       goto file;
+       if (udev_device_get_num_fake_partitions(udev_device) != 0)
+               goto file;
+       if (udev_device_get_ignore_remove(udev_device))
+               goto file;
+       if (udev_device_get_devlink_priority(udev_device) != 0)
+               goto file;
+       if (udev_device_get_event_timeout(udev_device) >= 0)
+               goto file;
+       if (udev_device_get_watch_handle(udev_device) >= 0)
+               goto file;
+       if (udev_device_get_devnode(udev_device) == NULL)
+               goto out;
+
+       /*
+        * if we have only the node and symlinks to store, try not to waste
+        * tmpfs memory -- store values, if they fit, in a symlink target
+        */
+       s = target;
+       l = util_strpcpy(&s, sizeof(target), &udev_device_get_devnode(udev_device)[devlen]);
+       udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) {
+               l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
+               if (l == 0) {
+                       info(udev, "size of links too large, create file\n");
+                       goto file;
+               }
+       }
+       info(udev, "create db link (%s)\n", target);
+       udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
+       ret = symlink(target, filename);
+       udev_selinux_resetfscreatecon(udev);
+       if (ret == 0)
+               goto out;
+file:
+       f = fopen(filename, "w");
+       if (f == NULL) {
+               err(udev, "unable to create db file '%s': %m\n", filename);
+               return -1;
+               }
+       info(udev, "created db file for '%s' in '%s'\n", udev_device_get_devpath(udev_device), filename);
+
+       if (udev_device_get_devnode(udev_device) != NULL) {
+               fprintf(f, "N:%s\n", &udev_device_get_devnode(udev_device)[devlen]);
+               udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device))
+                       fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]);
+       }
+       if (udev_device_get_devlink_priority(udev_device) != 0)
+               fprintf(f, "L:%u\n", udev_device_get_devlink_priority(udev_device));
+       if (udev_device_get_event_timeout(udev_device) >= 0)
+               fprintf(f, "T:%u\n", udev_device_get_event_timeout(udev_device));
+       if (udev_device_get_num_fake_partitions(udev_device) != 0)
+               fprintf(f, "A:%u\n", udev_device_get_num_fake_partitions(udev_device));
+       if (udev_device_get_ignore_remove(udev_device))
+               fprintf(f, "R:%u\n", udev_device_get_ignore_remove(udev_device));
+       if (udev_device_get_watch_handle(udev_device) >= 0)
+               fprintf(f, "W:%u\n", udev_device_get_watch_handle(udev_device));
+       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
+               if (!udev_list_entry_get_flag(list_entry))
+                       continue;
+               fprintf(f, "E:%s=%s\n",
+                       udev_list_entry_get_name(list_entry),
+                       udev_list_entry_get_value(list_entry));
+       }
+       fclose(f);
+out:
+       return 0;
+}
+
+int udev_device_delete_db(struct udev_device *udev_device)
+{
+       struct udev *udev = udev_device_get_udev(udev_device);
+       char filename[UTIL_PATH_SIZE];
+
+       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
+       unlink(filename);
+       return 0;
+}
+
+int udev_device_rename_db(struct udev_device *udev_device, const char *devpath_old)
+{
+       struct udev *udev = udev_device_get_udev(udev_device);
+       char filename_old[UTIL_PATH_SIZE];
+       char filename[UTIL_PATH_SIZE];
+
+       devpath_to_db_path(udev, devpath_old, filename_old, sizeof(filename_old));
+       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
+       return rename(filename_old, filename);
+}
diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c
new file mode 100644 (file)
index 0000000..ea54bad
--- /dev/null
@@ -0,0 +1,1249 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+struct udev_device {
+       struct udev *udev;
+       struct udev_device *parent_device;
+       char *syspath;
+       const char *devpath;
+       char *sysname;
+       const char *sysnum;
+       char *devnode;
+       char *subsystem;
+       char *devtype;
+       char *driver;
+       char *action;
+       char *devpath_old;
+       char *knodename;
+       char **envp;
+       char *monitor_buf;
+       size_t monitor_buf_len;
+       struct udev_list_node devlinks_list;
+       struct udev_list_node properties_list;
+       struct udev_list_node sysattr_list;
+       unsigned long long int seqnum;
+       int event_timeout;
+       int timeout;
+       int num_fake_partitions;
+       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;
+       unsigned int info_loaded:1;
+       unsigned int ignore_remove:1;
+};
+
+static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
+{
+       char *s;
+       size_t l;
+
+       s = filename;
+       l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
+       return util_path_encode(devpath, s, l);
+}
+
+int udev_device_read_db(struct udev_device *udev_device)
+{
+       struct stat stats;
+       char filename[UTIL_PATH_SIZE];
+       char line[UTIL_LINE_SIZE];
+       FILE *f;
+
+       devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
+
+       if (lstat(filename, &stats) != 0) {
+               dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
+               return -1;
+       }
+       if ((stats.st_mode & S_IFMT) == S_IFLNK) {
+               char target[UTIL_PATH_SIZE];
+               char devnode[UTIL_PATH_SIZE];
+               int target_len;
+               char *next;
+
+               target_len = readlink(filename, target, sizeof(target));
+               if (target_len > 0)
+                       target[target_len] = '\0';
+               else {
+                       dbg(udev_device->udev, "error reading db link %s: %m\n", filename);
+                       return -1;
+               }
+
+               next = strchr(target, ' ');
+               if (next != NULL) {
+                       next[0] = '\0';
+                       next = &next[1];
+               }
+               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];
+                       const char *lnk;
+
+                       lnk = next;
+                       next = strchr(next, ' ');
+                       if (next != NULL) {
+                               next[0] = '\0';
+                               next = &next[1];
+                       }
+                       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);
+               return 0;
+       }
+
+       f = fopen(filename, "r");
+       if (f == NULL) {
+               dbg(udev_device->udev, "error reading db file %s: %m\n", filename);
+               return -1;
+       }
+       while (fgets(line, sizeof(line), f)) {
+               ssize_t len;
+               const char *val;
+
+               len = strlen(line);
+               if (len < 4)
+                       break;
+               line[len-1] = '\0';
+               val = &line[2];
+               switch(line[0]) {
+               case 'N':
+                       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_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
+                       udev_device_add_devlink(udev_device, filename);
+                       break;
+               case 'L':
+                       udev_device_set_devlink_priority(udev_device, atoi(val));
+                       break;
+               case 'T':
+                       udev_device_set_event_timeout(udev_device, atoi(val));
+                       break;
+               case 'A':
+                       udev_device_set_num_fake_partitions(udev_device, atoi(val));
+                       break;
+               case 'R':
+                       udev_device_set_ignore_remove(udev_device, atoi(val));
+                       break;
+               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);
+
+       info(udev_device->udev, "device %p filled with db file data\n", udev_device);
+       return 0;
+}
+
+int udev_device_read_uevent_file(struct udev_device *udev_device)
+{
+       char filename[UTIL_PATH_SIZE];
+       FILE *f;
+       char line[UTIL_LINE_SIZE];
+       int maj = 0;
+       int min = 0;
+
+       util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
+       f = fopen(filename, "r");
+       if (f == NULL)
+               return -1;
+
+       while (fgets(line, sizeof(line), f)) {
+               char *pos;
+
+               pos = strchr(line, '\n');
+               if (pos == NULL)
+                       continue;
+               pos[0] = '\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);
+       }
+
+       udev_device->devnum = makedev(maj, min);
+
+       fclose(f);
+       return 0;
+}
+
+static void device_load_info(struct udev_device *device)
+{
+       device->info_loaded = 1;
+       udev_device_read_uevent_file(device);
+       udev_device_read_db(device);
+}
+
+void udev_device_set_info_loaded(struct udev_device *device)
+{
+       device->info_loaded = 1;
+}
+
+struct udev_device *device_new(struct udev *udev)
+{
+       struct udev_device *udev_device;
+       struct udev_list_entry *list_entry;
+
+       if (udev == NULL)
+               return NULL;
+
+       udev_device = calloc(1, sizeof(struct udev_device));
+       if (udev_device == NULL)
+               return NULL;
+       udev_device->refcount = 1;
+       udev_device->udev = udev;
+       udev_list_init(&udev_device->devlinks_list);
+       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,
+                                        udev_list_entry_get_name(list_entry),
+                                        udev_list_entry_get_value(list_entry));
+       dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
+       return udev_device;
+}
+
+/**
+ * udev_device_new_from_syspath:
+ * @udev: udev library context
+ * @syspath: sys device path including sys directory
+ *
+ * Create new udev device, and fill in information from the sys
+ * device and the udev database entry. The sypath is the absolute
+ * path to the device, including the sys mount point.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev device.
+ *
+ * Returns: a new udev device, or #NULL, if it does not exist
+ **/
+struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
+{
+       size_t len;
+       const char *subdir;
+       char path[UTIL_PATH_SIZE];
+       char *pos;
+       struct stat statbuf;
+       struct udev_device *udev_device;
+
+       if (udev == NULL)
+               return NULL;
+       if (syspath == NULL)
+               return NULL;
+
+       /* path starts in sys */
+       len = strlen(udev_get_sys_path(udev));
+       if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
+               info(udev, "not in sys :%s\n", syspath);
+               return NULL;
+       }
+
+       /* path is not a root directory */
+       subdir = &syspath[len+1];
+       pos = strrchr(subdir, '/');
+       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_strscpy(path, sizeof(path), syspath);
+       util_resolve_sys_link(udev, path, sizeof(path));
+
+       /* try to resolve the silly block layout if needed */
+       if (strncmp(&path[len], "/block/", 7) == 0) {
+               char block[UTIL_PATH_SIZE];
+               char part[UTIL_PATH_SIZE];
+
+               util_strscpy(block, sizeof(block), path);
+               pos = strrchr(block, '/');
+               if (pos == NULL)
+                       return NULL;
+               util_strscpy(part, sizeof(part), pos);
+               pos[0] = '\0';
+               if (util_resolve_sys_link(udev, block, sizeof(block)) == 0)
+                       util_strscpyl(path, sizeof(path), block, part, NULL);
+       }
+
+       /* path exists in sys */
+       if (strncmp(&syspath[len], "/devices/", 9) == 0 ||
+           strncmp(&syspath[len], "/class/", 7) == 0 ||
+           strncmp(&syspath[len], "/block/", 7) == 0) {
+               char file[UTIL_PATH_SIZE];
+
+               /* all "devices" require a "uevent" file */
+               util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
+               if (stat(file, &statbuf) != 0) {
+                       dbg(udev, "not a device: %s\n", syspath);
+                       return NULL;
+               }
+       } else {
+               /* everything else just needs to be a directory */
+               if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+                       dbg(udev, "directory not found: %s\n", syspath);
+                       return NULL;
+               }
+       }
+
+       udev_device = device_new(udev);
+       if (udev_device == NULL)
+               return NULL;
+
+       udev_device_set_syspath(udev_device, path);
+       info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
+
+       return udev_device;
+}
+
+struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
+{
+       char path[UTIL_PATH_SIZE];
+       const char *type_str;
+       struct udev_enumerate *udev_enumerate;
+       struct udev_list_entry *list_entry;
+       struct udev_device *device = NULL;
+
+       if (type == 'b')
+               type_str = "block";
+       else if (type == 'c')
+               type_str = "char";
+       else
+               return NULL;
+
+       /* /sys/dev/{block,char}/<maj>:<min> link */
+       snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", udev_get_sys_path(udev),
+                type_str, major(devnum), minor(devnum));
+       if (util_resolve_sys_link(udev, path, sizeof(path)) == 0)
+               return udev_device_new_from_syspath(udev, path);
+
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return NULL;
+
+       /* fallback to search sys devices for the major/minor */
+       if (type == 'b')
+               udev_enumerate_add_match_subsystem(udev_enumerate, "block");
+       else if (type == 'c')
+               udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
+       udev_enumerate_scan_devices(udev_enumerate);
+       udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
+               struct udev_device *device_loop;
+
+               device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
+               if (device_loop != NULL) {
+                       if (udev_device_get_devnum(device_loop) == devnum) {
+                               if (type == 'b' && strcmp(udev_device_get_subsystem(device_loop), "block") != 0)
+                                       continue;
+                               if (type == 'c' && strcmp(udev_device_get_subsystem(device_loop), "block") == 0)
+                                       continue;
+                               device = device_loop;
+                               break;
+                       }
+                       udev_device_unref(device_loop);
+               }
+       }
+       udev_enumerate_unref(udev_enumerate);
+       return device;
+}
+
+struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
+{
+       char path_full[UTIL_PATH_SIZE];
+       char *path;
+       size_t l;
+       struct stat statbuf;
+
+       path = path_full;
+       l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
+
+       if (strcmp(subsystem, "subsystem") == 0) {
+               util_strscpyl(path, l, "/subsystem/", sysname, NULL);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+
+               util_strscpyl(path, l, "/bus/", sysname, NULL);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+
+               util_strscpyl(path, l, "/class/", sysname, NULL);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+               goto out;
+       }
+
+       if (strcmp(subsystem, "module") == 0) {
+               util_strscpyl(path, l, "/module/", sysname, NULL);
+               if (stat(path_full, &statbuf) == 0)
+                       goto found;
+               goto out;
+       }
+
+       if (strcmp(subsystem, "drivers") == 0) {
+               char subsys[UTIL_NAME_SIZE];
+               char *driver;
+
+               util_strscpy(subsys, sizeof(subsys), sysname);
+               driver = strchr(subsys, ':');
+               if (driver != NULL) {
+                       driver[0] = '\0';
+                       driver = &driver[1];
+
+                       util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
+                       if (stat(path_full, &statbuf) == 0)
+                               goto found;
+
+                       util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
+                       if (stat(path_full, &statbuf) == 0)
+                               goto found;
+               }
+               goto out;
+       }
+
+       util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+       util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+
+       util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
+       if (stat(path_full, &statbuf) == 0)
+               goto found;
+out:
+       return NULL;
+found:
+       return udev_device_new_from_syspath(udev, path_full);
+}
+
+static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
+{
+       struct udev_device *udev_device_parent = NULL;
+       char path[UTIL_PATH_SIZE];
+       const char *subdir;
+
+       /* follow "device" link in deprecated sys layout */
+       if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
+           strncmp(udev_device->devpath, "/block/", 7) == 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);
+                       if (udev_device_parent != NULL)
+                               return udev_device_parent;
+               }
+       }
+
+       util_strscpy(path, sizeof(path), udev_device->syspath);
+       subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
+       while (1) {
+               char *pos;
+
+               pos = strrchr(subdir, '/');
+               if (pos == NULL || pos < &subdir[2])
+                       break;
+               pos[0] = '\0';
+               udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
+               if (udev_device_parent != NULL)
+                       return udev_device_parent;
+       }
+       return NULL;
+}
+
+struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->parent_set) {
+               udev_device->parent_set = 1;
+               udev_device->parent_device = device_new_from_parent(udev_device);
+       }
+       if (udev_device->parent_device != NULL)
+               dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
+       return udev_device->parent_device;
+}
+
+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) {
+                       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;
+}
+
+/**
+ * udev_device_get_udev:
+ * @udev_device: udev device
+ *
+ * Retrieve the udev library context the device was created with.
+ *
+ * Returns: the udev library context
+ **/
+struct udev *udev_device_get_udev(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->udev;
+}
+
+/**
+ * udev_device_ref:
+ * @udev_device: udev device
+ *
+ * Take a reference of a udev device.
+ *
+ * Returns: the passed udev device
+ **/
+struct udev_device *udev_device_ref(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       udev_device->refcount++;
+       return udev_device;
+}
+
+/**
+ * udev_device_unref:
+ * @udev_device: udev device
+ *
+ * Drop a reference of a udev device. If the refcount reaches zero,
+ * the resources of the device will be released.
+ *
+ **/
+void udev_device_unref(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return;
+       udev_device->refcount--;
+       if (udev_device->refcount > 0)
+               return;
+       if (udev_device->parent_device != NULL)
+               udev_device_unref(udev_device->parent_device);
+       free(udev_device->syspath);
+       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->knodename);
+       udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
+       free(udev_device->envp);
+       free(udev_device->monitor_buf);
+       dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
+       free(udev_device);
+}
+
+/**
+ * udev_device_get_devpath:
+ * @udev_device: udev device
+ *
+ * Retrieve the kernel devpath value of the udev device. The path
+ * does not contain the sys mount point, and starts with a '/'.
+ *
+ * Returns: the devpath of the udev device
+ **/
+const char *udev_device_get_devpath(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->devpath;
+}
+
+/**
+ * udev_device_get_syspath:
+ * @udev_device: udev device
+ *
+ * Retrieve the sys path of the udev device. The path is an
+ * absolute path and starts with the sys mount point.
+ *
+ * Returns: the sys path of the udev device
+ **/
+const char *udev_device_get_syspath(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->syspath;
+}
+
+const char *udev_device_get_sysname(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->sysname;
+}
+
+const char *udev_device_get_sysnum(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->sysnum;
+}
+
+/**
+ * udev_device_get_devnode:
+ * @udev_device: udev device
+ *
+ * Retrieve the device node file name belonging to the udev device.
+ * The path is an absolute path, and starts with the device directory.
+ *
+ * Returns: the device node file name of the udev device, or #NULL if no device node exists
+ **/
+const char *udev_device_get_devnode(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->devnode;
+}
+
+/**
+ * udev_device_get_subsystem:
+ * @udev_device: udev device
+ *
+ * Retrieve the subsystem string of the udev device. The string does not
+ * contain any "/".
+ *
+ * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
+ **/
+const char *udev_device_get_subsystem(struct udev_device *udev_device)
+{
+       char subsystem[UTIL_NAME_SIZE];
+
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->subsystem_set) {
+               udev_device->subsystem_set = 1;
+               /* read "subsytem" link */
+               if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
+                       udev_device_set_subsystem(udev_device, subsystem);
+                       return udev_device->subsystem;
+               }
+               /* implicit names */
+               if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
+                       udev_device_set_subsystem(udev_device, "module");
+                       return udev_device->subsystem;
+               }
+               if (strstr(udev_device->devpath, "/drivers/") != NULL) {
+                       udev_device_set_subsystem(udev_device, "drivers");
+                       return udev_device->subsystem;
+               }
+               if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
+                   strncmp(udev_device->devpath, "/class/", 7) == 0 ||
+                   strncmp(udev_device->devpath, "/bus/", 5) == 0) {
+                       udev_device_set_subsystem(udev_device, "subsystem");
+                       return udev_device->subsystem;
+               }
+       }
+       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
+ *
+ * Retrieve the list of device links pointing to the device file of
+ * the udev device. The next list entry can be retrieved with
+ * udev_list_entry_next(), which returns #NULL if no more entries exist.
+ * The devlink path can be retrieved from the list entry by
+ * udev_list_entry_get_name(). The path is an absolute path, and starts with
+ * the device directory.
+ *
+ * Returns: the first entry of the device node link list
+ **/
+struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_list_get_entry(&udev_device->devlinks_list);
+}
+
+void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
+{
+       udev_device->devlinks_uptodate = 0;
+       udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
+}
+
+/**
+ * udev_device_get_properties_list_entry:
+ * @udev_device: udev device
+ *
+ * Retrieve the list of key/value device properties of the udev
+ * device. The next list entry can be retrieved with udev_list_entry_next(),
+ * which returns #NULL if no more entries exist. The property name
+ * can be retrieved from the list entry by udev_list_get_name(),
+ * the property value by udev_list_get_value().
+ *
+ * Returns: the first entry of the property list
+ **/
+struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       if (!udev_device->devlinks_uptodate) {
+               char symlinks[UTIL_PATH_SIZE];
+               struct udev_list_entry *list_entry;
+
+               udev_device->devlinks_uptodate = 1;
+               list_entry = udev_device_get_devlinks_list_entry(udev_device);
+               if (list_entry != NULL) {
+                       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);
+               }
+       }
+       return udev_list_get_entry(&udev_device->properties_list);
+}
+
+const char *udev_device_get_driver(struct udev_device *udev_device)
+{
+       char driver[UTIL_NAME_SIZE];
+
+       if (udev_device == NULL)
+               return NULL;
+       if (!udev_device->driver_set) {
+               udev_device->driver_set = 1;
+               if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0)
+                       udev_device->driver = strdup(driver);
+       }
+       return udev_device->driver;
+}
+
+dev_t udev_device_get_devnum(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return makedev(0, 0);
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->devnum;
+}
+
+const char *udev_device_get_action(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return NULL;
+       return udev_device->action;
+}
+
+unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
+{
+       if (udev_device == NULL)
+               return 0;
+       return udev_device->seqnum;
+}
+
+const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
+{
+       struct udev_list_entry *list_entry;
+       char path[UTIL_PATH_SIZE];
+       char value[4096];
+       struct stat statbuf;
+       int fd;
+       ssize_t size;
+       const char *val = NULL;
+
+       if (udev_device == NULL)
+               return NULL;
+       if (sysattr == NULL)
+               return NULL;
+
+       /* look for possibly already cached result */
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_device->sysattr_list)) {
+               if (strcmp(udev_list_entry_get_name(list_entry), sysattr) == 0) {
+                       dbg(udev_device->udev, "got '%s' (%s) from cache\n",
+                           sysattr, udev_list_entry_get_value(list_entry));
+                       return udev_list_entry_get_value(list_entry);
+               }
+       }
+
+       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);
+               goto out;
+       }
+
+       if (S_ISLNK(statbuf.st_mode)) {
+               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';
+                       pos = strrchr(target, '/');
+                       if (pos != NULL) {
+                               pos = &pos[1];
+                               dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
+                               list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0);
+                               val = udev_list_entry_get_value(list_entry);
+                       }
+               }
+               goto out;
+       }
+
+       /* skip directories */
+       if (S_ISDIR(statbuf.st_mode))
+               goto out;
+
+       /* skip non-readable files */
+       if ((statbuf.st_mode & S_IRUSR) == 0)
+               goto out;
+
+       /* read attribute value */
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
+               goto out;
+       }
+       size = read(fd, value, sizeof(value));
+       close(fd);
+       if (size < 0)
+               goto out;
+       if (size == sizeof(value))
+               goto out;
+
+       /* got a valid value, store it in cache and return it */
+       value[size] = '\0';
+       util_remove_trailing_chars(value, '\n');
+       dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
+       list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, value, 0, 0);
+       val = udev_list_entry_get_value(list_entry);
+out:
+       return val;
+}
+
+int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath)
+{
+       const char *pos;
+       size_t len;
+
+       free(udev_device->syspath);
+       udev_device->syspath = strdup(syspath);
+       if (udev_device->syspath ==  NULL)
+               return -ENOMEM;
+       udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
+       udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath);
+
+       pos = strrchr(udev_device->syspath, '/');
+       if (pos == NULL)
+               return -EINVAL;
+       udev_device->sysname = strdup(&pos[1]);
+       if (udev_device->sysname == NULL)
+               return -ENOMEM;
+
+       /* some devices have '!' in their name, change that to '/' */
+       len = 0;
+       while (udev_device->sysname[len] != '\0') {
+               if (udev_device->sysname[len] == '!')
+                       udev_device->sysname[len] = '/';
+               len++;
+       }
+
+       /* trailing number */
+       while (len > 0 && isdigit(udev_device->sysname[--len]))
+               udev_device->sysnum = &udev_device->sysname[len];
+
+       /* sysname is completely numeric */
+       if (len == 0)
+               udev_device->sysnum = NULL;
+
+       return 0;
+}
+
+int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
+{
+       free(udev_device->subsystem);
+       udev_device->subsystem = strdup(subsystem);
+       if (udev_device->subsystem == NULL)
+               return -ENOMEM;
+       udev_device->subsystem_set = 1;
+       udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
+       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);
+       udev_device->devnode = strdup(devnode);
+       if (devnode == NULL)
+               return 0;
+       if (udev_device->devnode == NULL)
+               return -ENOMEM;
+       udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode);
+       return 0;
+}
+
+int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink)
+{
+       udev_device->devlinks_uptodate = 0;
+       if (udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
+{
+       udev_device->envp_uptodate = 0;
+       if (value == NULL) {
+               struct udev_list_entry *list_entry;
+
+               list_entry = udev_device_get_properties_list_entry(udev_device);
+               list_entry = udev_list_entry_get_by_name(list_entry, key);
+               if (list_entry != NULL)
+                       udev_list_entry_delete(list_entry);
+               return NULL;
+       }
+       return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0);
+}
+
+struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property)
+{
+       char name[UTIL_PATH_SIZE];
+       char *val;
+
+       util_strscpy(name, sizeof(name), property);
+       val = strchr(name, '=');
+       if (val == NULL)
+               return NULL;
+       val[0] = '\0';
+       val = &val[1];
+       if (val[0] == '\0')
+               val = NULL;
+       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)
+{
+       struct udev_list_entry *list_entry;
+       char *s;
+       size_t l;
+       unsigned int i;
+
+       /* monitor buffer of property strings */
+       free(udev_device->monitor_buf);
+       udev_device->monitor_buf_len = 0;
+       udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE);
+       if (udev_device->monitor_buf == NULL)
+               return -ENOMEM;
+
+       /* envp array, strings will point into monitor buffer */
+       if (udev_device->envp == NULL)
+               udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE);
+       if (udev_device->envp == NULL)
+               return -ENOMEM;
+
+       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++] = s;
+               if (i+1 >= ENVP_SIZE)
+                       return -EINVAL;
+
+               /* add property string to monitor buffer */
+               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;
+               s++;
+       }
+       udev_device->envp[i] = NULL;
+       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, udev_device->monitor_buf_len);
+       return 0;
+}
+
+char **udev_device_get_properties_envp(struct udev_device *udev_device)
+{
+       if (!udev_device->envp_uptodate)
+               if (update_envp_monitor_buf(udev_device) != 0)
+                       return NULL;
+       return udev_device->envp;
+}
+
+ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf)
+{
+       if (!udev_device->envp_uptodate)
+               if (update_envp_monitor_buf(udev_device) != 0)
+                       return -EINVAL;
+       *buf = udev_device->monitor_buf;
+       return udev_device->monitor_buf_len;
+}
+
+int udev_device_set_action(struct udev_device *udev_device, const char *action)
+{
+       free(udev_device->action);
+       udev_device->action = strdup(action);
+       if (udev_device->action == NULL)
+               return -ENOMEM;
+       udev_device_add_property(udev_device, "ACTION", udev_device->action);
+       return 0;
+}
+
+int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
+{
+       free(udev_device->driver);
+       udev_device->driver = strdup(driver);
+       if (udev_device->driver == NULL)
+               return -ENOMEM;
+       udev_device->driver_set = 1;
+       udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
+       return 0;
+}
+
+const char *udev_device_get_devpath_old(struct udev_device *udev_device)
+{
+       return udev_device->devpath_old;
+}
+
+int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
+{
+       udev_device->devpath_old = strdup(devpath_old);
+       if (udev_device->devpath_old == NULL)
+               return -ENOMEM;
+       udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
+       return 0;
+}
+
+const char *udev_device_get_knodename(struct udev_device *udev_device)
+{
+       return udev_device->knodename;
+}
+
+int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename)
+{
+       udev_device->knodename = strdup(knodename);
+       if (udev_device->knodename == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+int udev_device_get_timeout(struct udev_device *udev_device)
+{
+       return udev_device->timeout;
+}
+
+int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
+{
+       udev_device->timeout = timeout;
+       return 0;
+}
+int udev_device_get_event_timeout(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->event_timeout;
+}
+
+int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
+{
+       udev_device->event_timeout = event_timeout;
+       return 0;
+}
+
+int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
+{
+       char num[32];
+
+       udev_device->seqnum = seqnum;
+       snprintf(num, sizeof(num), "%llu", seqnum);
+       udev_device_add_property(udev_device, "SEQNUM", num);
+       return 0;
+}
+
+int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
+{
+       char num[32];
+
+       udev_device->devnum = devnum;
+
+       snprintf(num, sizeof(num), "%u", major(devnum));
+       udev_device_add_property(udev_device, "MAJOR", num);
+       snprintf(num, sizeof(num), "%u", minor(devnum));
+       udev_device_add_property(udev_device, "MINOR", num);
+       return 0;
+}
+
+int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->num_fake_partitions;
+}
+
+int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num)
+{
+       udev_device->num_fake_partitions = num;
+       return 0;
+}
+
+int udev_device_get_devlink_priority(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->devlink_priority;
+}
+
+int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
+{
+        udev_device->devlink_priority = prio;
+       return 0;
+}
+
+int udev_device_get_ignore_remove(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               device_load_info(udev_device);
+       return udev_device->ignore_remove;
+}
+
+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;
+}
diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c
new file mode 100644 (file)
index 0000000..63f8406
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static int devices_sort(struct udev_enumerate *udev_enumerate);
+
+struct udev_enumerate {
+       struct udev *udev;
+       int refcount;
+       struct udev_list_node sysattr_match_list;
+       struct udev_list_node sysattr_nomatch_list;
+       struct udev_list_node subsystem_match_list;
+       struct udev_list_node subsystem_nomatch_list;
+       struct udev_list_node properties_match_list;
+       struct udev_list_node devices_list;
+       int devices_sorted;
+};
+
+/**
+ * udev_enumerate_new:
+ * @udev: udev library context
+ *
+ * Returns: an enumeration context
+ **/
+struct udev_enumerate *udev_enumerate_new(struct udev *udev)
+{
+       struct udev_enumerate *udev_enumerate;
+
+       udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
+       if (udev_enumerate == NULL)
+               return NULL;
+       udev_enumerate->refcount = 1;
+       udev_enumerate->udev = udev;
+       udev_list_init(&udev_enumerate->devices_list);
+       udev_list_init(&udev_enumerate->sysattr_match_list);
+       udev_list_init(&udev_enumerate->sysattr_nomatch_list);
+       udev_list_init(&udev_enumerate->subsystem_match_list);
+       udev_list_init(&udev_enumerate->subsystem_nomatch_list);
+       udev_list_init(&udev_enumerate->properties_match_list);
+       return udev_enumerate;
+}
+
+struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
+{
+       if (udev_enumerate == NULL)
+               return NULL;
+       udev_enumerate->refcount++;
+       return udev_enumerate;
+}
+
+void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
+{
+       if (udev_enumerate == NULL)
+               return;
+       udev_enumerate->refcount--;
+       if (udev_enumerate->refcount > 0)
+               return;
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_match_list);
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_nomatch_list);
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_match_list);
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_nomatch_list);
+       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->properties_match_list);
+       free(udev_enumerate);
+}
+
+struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
+{
+       if (udev_enumerate == NULL)
+               return NULL;
+       return udev_enumerate->udev;
+}
+
+struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
+{
+       if (udev_enumerate == NULL)
+               return NULL;
+       if (!udev_enumerate->devices_sorted)
+               devices_sort(udev_enumerate);
+       return udev_list_get_entry(&udev_enumerate->devices_list);
+}
+
+int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (subsystem == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
+                               &udev_enumerate->subsystem_match_list, subsystem, NULL, 1, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (subsystem == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
+                               &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, 1, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (sysattr == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
+                          &udev_enumerate->sysattr_match_list, sysattr, value, 0, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (sysattr == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
+                          &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static int match_sysattr_value(struct udev *udev, const char *syspath, const char *sysattr, const char *match_val)
+{
+       struct udev_device *device;
+       const char *val = NULL;
+       int match = 0;
+
+       device = udev_device_new_from_syspath(udev, syspath);
+       if (device == NULL)
+               return -EINVAL;
+       val = udev_device_get_sysattr_value(device, sysattr);
+       if (val == NULL)
+               goto exit;
+       if (match_val == NULL) {
+               match = 1;
+               goto exit;
+       }
+       if (fnmatch(match_val, val, 0) == 0) {
+               match = 1;
+               goto exit;
+       }
+exit:
+       udev_device_unref(device);
+       return match;
+}
+
+int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (property == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
+                               &udev_enumerate->properties_match_list, property, value, 0, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static int match_sysattr(struct udev_enumerate *udev_enumerate, const char *syspath)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+       struct udev_list_entry *list_entry;
+
+       /* skip list */
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
+               if (match_sysattr_value(udev, syspath,
+                                    udev_list_entry_get_name(list_entry),
+                                    udev_list_entry_get_value(list_entry)))
+                       return 0;
+       }
+       /* include list */
+       if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
+               udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
+                       /* anything that does not match, will make it FALSE */
+                       if (!match_sysattr_value(udev, syspath,
+                                             udev_list_entry_get_name(list_entry),
+                                             udev_list_entry_get_value(list_entry)))
+                               return 0;
+               }
+               return 1;
+       }
+       return 1;
+}
+
+static int match_property(struct udev_enumerate *udev_enumerate, const char *syspath)
+{
+       struct udev_device *dev;
+       struct udev_list_entry *list_entry;
+       int match = 0;
+
+       /* no match always matches */
+       if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
+               return 1;
+
+       /* no device does not match */
+       dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
+       if (dev == NULL)
+               return 0;
+
+       /* loop over matches */
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
+               const char *match_key = udev_list_entry_get_name(list_entry);
+               const char *match_value = udev_list_entry_get_value(list_entry);
+               struct udev_list_entry *property_entry;
+
+               /* loop over device properties */
+               udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
+                       const char *dev_key = udev_list_entry_get_name(property_entry);
+                       const char *dev_value = udev_list_entry_get_value(property_entry);
+
+                       if (fnmatch(match_key, dev_key, 0) != 0)
+                               continue;
+                       if (match_value == NULL && dev_value == NULL) {
+                               match = 1;
+                               goto out;
+                       }
+                       if (match_value == NULL || dev_value == NULL)
+                               continue;
+                       if (fnmatch(match_value, dev_value, 0) == 0) {
+                               match = 1;
+                               goto out;
+                       }
+               }
+       }
+out:
+       udev_device_unref(dev);
+       return match;
+}
+
+static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
+                                   const char *basedir, const char *subdir1, const char *subdir2)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+       char path[UTIL_PATH_SIZE];
+       size_t l;
+       char *s;
+       DIR *dir;
+       struct dirent *dent;
+
+       s = path;
+       l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
+       if (subdir1 != NULL)
+               l = util_strpcpyl(&s, l, "/", subdir1, NULL);
+       if (subdir2 != NULL)
+               l = util_strpcpyl(&s, l, "/", subdir2, NULL);
+       dir = opendir(path);
+       if (dir == NULL)
+               return -1;
+       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+               char syspath[UTIL_PATH_SIZE];
+               char filename[UTIL_PATH_SIZE];
+               struct stat statbuf;
+
+               if (dent->d_name[0] == '.')
+                       continue;
+               util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
+               if (lstat(syspath, &statbuf) != 0)
+                       continue;
+               if (S_ISREG(statbuf.st_mode))
+                       continue;
+               if (S_ISLNK(statbuf.st_mode))
+                       util_resolve_sys_link(udev, syspath, sizeof(syspath));
+
+               util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
+               if (stat(filename, &statbuf) != 0)
+                       continue;
+               if (!match_sysattr(udev_enumerate, syspath))
+                       continue;
+               if (!match_property(udev_enumerate, syspath))
+                       continue;
+               udev_list_entry_add(udev, &udev_enumerate->devices_list, syspath, NULL, 1, 1);
+       }
+       closedir(dir);
+       return 0;
+}
+
+static int match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
+{
+       struct udev_list_entry *list_entry;
+
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
+               if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
+                       return 0;
+       }
+       if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
+               udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
+                       if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
+                               return 1;
+               }
+               return 0;
+       }
+       return 1;
+}
+
+static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+
+       char path[UTIL_PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
+       dir = opendir(path);
+       if (dir == NULL)
+               return -1;
+       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+               if (dent->d_name[0] == '.')
+                       continue;
+               if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
+                       continue;
+               scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
+       }
+       closedir(dir);
+       return 0;
+}
+
+static int devices_delay(struct udev *udev, const char *syspath)
+{
+       static const char *delay_device_list[] = {
+               "/block/md",
+               "/block/dm-",
+               NULL
+       };
+       size_t len;
+       int i;
+
+       len = strlen(udev_get_sys_path(udev));
+       for (i = 0; delay_device_list[i] != NULL; i++) {
+               if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
+                       dbg(udev, "delaying: %s\n", syspath);
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+/* sort delayed devices to the end of the list */
+static int devices_sort(struct udev_enumerate *udev_enumerate)
+{
+       struct udev_list_entry *entry_loop;
+       struct udev_list_entry *entry_tmp;
+       struct udev_list_node devices_list;
+
+       udev_list_init(&devices_list);
+       /* move delayed to delay list */
+       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(&udev_enumerate->devices_list)) {
+               if (devices_delay(udev_enumerate->udev, udev_list_entry_get_name(entry_loop))) {
+                       udev_list_entry_remove(entry_loop);
+                       udev_list_entry_append(entry_loop, &devices_list);
+               }
+       }
+       /* move delayed back to end of list */
+       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(&devices_list)) {
+               udev_list_entry_remove(entry_loop);
+               udev_list_entry_append(entry_loop, &udev_enumerate->devices_list);
+       }
+       udev_enumerate->devices_sorted = 1;
+       return 0;
+}
+
+int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+       struct udev_device *udev_device;
+
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       if (syspath == NULL)
+               return 0;
+       /* resolve to real syspath */
+       udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
+       if (udev_device == NULL)
+               return -EINVAL;
+       udev_list_entry_add(udev, &udev_enumerate->devices_list,
+                           udev_device_get_syspath(udev_device), NULL, 1, 1);
+       udev_device_unref(udev_device);
+       return 0;
+}
+
+/**
+ * udev_enumerate_scan_devices:
+ * @udev_enumerate: udev enumeration context
+ *
+ * Returns: a negative value on error.
+ **/
+int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+       char base[UTIL_PATH_SIZE];
+       struct stat statbuf;
+
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
+       if (stat(base, &statbuf) == 0) {
+               /* we have /subsystem/, forget all the old stuff */
+               dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
+               scan_dir(udev_enumerate, "subsystem", "devices", NULL);
+       } else {
+               dbg(udev, "searching '/bus/*/devices/*' dir\n");
+               scan_dir(udev_enumerate, "bus", "devices", NULL);
+               dbg(udev, "searching '/class/*' dir\n");
+               scan_dir(udev_enumerate, "class", NULL, NULL);
+               /* if block isn't a class, scan /block/ */
+               util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/class/block", NULL);
+               if (stat(base, &statbuf) != 0) {
+                       if (match_subsystem(udev_enumerate, "block")) {
+                               dbg(udev, "searching '/block/*' dir\n");
+                               /* scan disks */
+                               scan_dir_and_add_devices(udev_enumerate, "block", NULL, NULL);
+                               /* scan partitions */
+                               dbg(udev, "searching '/block/*/*' dir\n");
+                               scan_dir(udev_enumerate, "block", NULL, "block");
+                       }
+               }
+       }
+       return 0;
+}
+
+/**
+ * udev_enumerate_scan_subsystems:
+ * @udev_enumerate: udev enumeration context
+ *
+ * Returns: a negative value on error.
+ **/
+int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
+{
+       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
+       char base[UTIL_PATH_SIZE];
+       struct stat statbuf;
+       const char *subsysdir;
+
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
+       if (stat(base, &statbuf) == 0)
+               subsysdir = "subsystem";
+       else
+               subsysdir = "bus";
+       if (match_subsystem(udev_enumerate, "subsystem")) {
+               dbg(udev, "searching '%s/*' dir\n", subsysdir);
+               scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
+       }
+       if (match_subsystem(udev_enumerate, "drivers")) {
+               dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
+               scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
+       }
+       return 0;
+}
diff --git a/libudev/libudev-list.c b/libudev/libudev-list.c
new file mode 100644 (file)
index 0000000..182d75a
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+struct udev_list_entry {
+       struct udev_list_node node;
+       struct udev *udev;
+       struct udev_list_node *list;
+       char *name;
+       char *value;
+       int flag;
+};
+
+/* list head point to itself if empty */
+void udev_list_init(struct udev_list_node *list)
+{
+       list->next = list;
+       list->prev = list;
+}
+
+int udev_list_is_empty(struct udev_list_node *list)
+{
+       return list->next == list;
+}
+
+static void udev_list_node_insert_between(struct udev_list_node *new,
+                                         struct udev_list_node *prev,
+                                         struct udev_list_node *next)
+{
+       next->prev = new;
+       new->next = next;
+       new->prev = prev;
+       prev->next = new;
+}
+
+void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
+{
+       udev_list_node_insert_between(new, list->prev, list);
+}
+
+void udev_list_node_remove(struct udev_list_node *entry)
+{
+       struct udev_list_node *prev = entry->prev;
+       struct udev_list_node *next = entry->next;
+
+       next->prev = prev;
+       prev->next = next;
+
+       entry->prev = NULL;
+       entry->next = NULL;
+}
+
+/* return list entry which embeds this node */
+static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
+{
+       char *list;
+
+       list = (char *)node;
+       list -= offsetof(struct udev_list_entry, node);
+       return (struct udev_list_entry *)list;
+}
+
+/* insert entry into a list as the last element  */
+void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list)
+{
+       /* inserting before the list head make the node the last node in the list */
+       udev_list_node_insert_between(&new->node, list->prev, list);
+       new->list = list;
+}
+
+/* remove entry from a list */
+void udev_list_entry_remove(struct udev_list_entry *entry)
+{
+       udev_list_node_remove(&entry->node);
+       entry->list = NULL;
+}
+
+/* insert entry into a list, before a given existing entry */
+void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
+{
+       udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
+       new->list = entry->list;
+}
+
+struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list,
+                                           const char *name, const char *value,
+                                           int unique, int sort)
+{
+       struct udev_list_entry *entry_loop = NULL;
+       struct udev_list_entry *entry_new;
+
+       if (unique)
+               udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
+                       if (strcmp(entry_loop->name, name) == 0) {
+                               dbg(udev, "'%s' is already in the list\n", name);
+                               free(entry_loop->value);
+                               if (value == NULL) {
+                                       entry_loop->value = NULL;
+                                       dbg(udev, "'%s' value unset\n", name);
+                                       return entry_loop;
+                               }
+                               entry_loop->value = strdup(value);
+                               if (entry_loop->value == NULL)
+                                       return NULL;
+                               dbg(udev, "'%s' value replaced with '%s'\n", name, value);
+                               return entry_loop;
+                       }
+               }
+
+       if (sort)
+               udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
+                       if (strcmp(entry_loop->name, name) > 0)
+                               break;
+               }
+
+       entry_new = malloc(sizeof(struct udev_list_entry));
+       if (entry_new == NULL)
+               return NULL;
+       memset(entry_new, 0x00, sizeof(struct udev_list_entry));
+       entry_new->udev = udev;
+       entry_new->name = strdup(name);
+       if (entry_new->name == NULL) {
+               free(entry_new);
+               return NULL;
+       }
+       if (value != NULL) {
+               entry_new->value = strdup(value);
+               if (entry_new->value == NULL) {
+                       free(entry_new->name);
+                       free(entry_new);
+                       return NULL;
+               }
+       }
+       if (entry_loop != NULL)
+               udev_list_entry_insert_before(entry_new, entry_loop);
+       else
+               udev_list_entry_append(entry_new, list);
+       dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value);
+       return entry_new;
+}
+
+void udev_list_entry_delete(struct udev_list_entry *entry)
+{
+       udev_list_node_remove(&entry->node);
+       free(entry->name);
+       free(entry->value);
+       free(entry);
+}
+
+void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list)
+{
+       struct udev_list_entry *entry_loop;
+       struct udev_list_entry *entry_tmp;
+
+       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
+               udev_list_entry_delete(entry_loop);
+}
+
+struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list)
+{
+       if (udev_list_is_empty(list))
+               return NULL;
+       return list_node_to_entry(list->next);
+}
+
+struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
+{
+       struct udev_list_node *next;
+
+       if (list_entry == NULL)
+               return NULL;
+       next = list_entry->node.next;
+       /* empty list or no more entries */
+       if (next == list_entry->list)
+               return NULL;
+       return list_node_to_entry(next);
+}
+
+struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
+{
+       struct udev_list_entry *entry;
+
+       udev_list_entry_foreach(entry, list_entry) {
+               if (strcmp(udev_list_entry_get_name(entry), name) == 0) {
+                       dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value);
+                       return entry;
+               }
+       }
+       return NULL;
+}
+
+const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
+{
+       if (list_entry == NULL)
+               return NULL;
+       return list_entry->name;
+}
+
+const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
+{
+       if (list_entry == NULL)
+               return NULL;
+       return list_entry->value;
+}
+
+int udev_list_entry_get_flag(struct udev_list_entry *list_entry)
+{
+       if (list_entry == NULL)
+               return -EINVAL;
+       return list_entry->flag;
+}
+
+void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag)
+{
+       if (list_entry == NULL)
+               return;
+       list_entry->flag = flag;
+}
diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c
new file mode 100644 (file)
index 0000000..7a0cb47
--- /dev/null
@@ -0,0 +1,760 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <linux/netlink.h>
+#include <linux/filter.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+struct udev_monitor {
+       struct udev *udev;
+       int refcount;
+       int sock;
+       struct sockaddr_nl snl;
+       struct sockaddr_nl snl_trusted_sender;
+       struct sockaddr_nl snl_destination;
+       struct sockaddr_un sun;
+       socklen_t addrlen;
+       struct udev_list_node filter_subsystem_list;
+};
+
+enum udev_monitor_netlink_group {
+       UDEV_MONITOR_NONE,
+       UDEV_MONITOR_KERNEL,
+       UDEV_MONITOR_UDEV,
+};
+
+#define UDEV_MONITOR_MAGIC             0xcafe1dea
+struct udev_monitor_netlink_header {
+       /* udev version text */
+       char version[16];
+       /*
+        * magic to protect against daemon <-> library message format mismatch
+        * used in the kernel from socket filter rules; needs to be stored in network order
+        */
+       unsigned int magic;
+       /* properties buffer */
+       unsigned short properties_off;
+       unsigned short properties_len;
+       /*
+        * hashes of some common device properties strings to filter with socket filters in
+        * the client used in the kernel from socket filter rules; needs to be stored in
+        * network order
+        */
+       unsigned int filter_subsystem;
+       unsigned int filter_devtype;
+};
+
+static struct udev_monitor *udev_monitor_new(struct udev *udev)
+{
+       struct udev_monitor *udev_monitor;
+
+       udev_monitor = calloc(1, sizeof(struct udev_monitor));
+       if (udev_monitor == NULL)
+               return NULL;
+       udev_monitor->refcount = 1;
+       udev_monitor->udev = udev;
+       udev_list_init(&udev_monitor->filter_subsystem_list);
+       return udev_monitor;
+}
+
+/**
+ * udev_monitor_new_from_socket:
+ * @udev: udev library context
+ * @socket_path: unix socket path
+ *
+ * Create new udev monitor and connect to a specified socket. The
+ * path to a socket either points to an existing socket file, or if
+ * the socket path starts with a '@' character, an abstract namespace
+ * socket will be used.
+ *
+ * A socket file will not be created. If it does not already exist,
+ * it will fall-back and connect to an abstract namespace socket with
+ * the given path. The permissions adjustment of a socket file, as
+ * well as the later cleanup, needs to be done by the caller.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev monitor.
+ *
+ * Returns: a new udev monitor, or #NULL, in case of an error
+ **/
+struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
+{
+       struct udev_monitor *udev_monitor;
+       struct stat statbuf;
+
+       if (udev == NULL)
+               return NULL;
+       if (socket_path == NULL)
+               return NULL;
+       udev_monitor = udev_monitor_new(udev);
+       if (udev_monitor == NULL)
+               return NULL;
+
+       udev_monitor->sun.sun_family = AF_LOCAL;
+       if (socket_path[0] == '@') {
+               /* translate leading '@' to abstract namespace */
+               util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
+               udev_monitor->sun.sun_path[0] = '\0';
+               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
+       } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
+               /* existing socket file */
+               util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
+               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
+       } else {
+               /* no socket file, assume abstract namespace socket */
+               util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
+               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
+       }
+       udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+       if (udev_monitor->sock == -1) {
+               err(udev, "error getting socket: %m\n");
+               free(udev_monitor);
+               return NULL;
+       }
+       util_set_fd_cloexec(udev_monitor->sock);
+
+       dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
+       return udev_monitor;
+}
+
+/**
+ * udev_monitor_new_from_netlink:
+ * @udev: udev library context
+ * @name: name of event source
+ *
+ * Create new udev monitor and connect to a specified event
+ * source. Valid sources identifiers are "udev" and "kernel".
+ *
+ * Applications should usually not connect directly to the
+ * "kernel" events, because the devices might not be useable
+ * at that time, before udev has configured them, and created
+ * device nodes.
+ *
+ * Accessing devices at the same time as udev, might result
+ * in unpredictable behavior.
+ *
+ * The "udev" events are sent out after udev has finished its
+ * event processing, all rules have been processed, and needed
+ * device nodes are created.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev monitor.
+ *
+ * Returns: a new udev monitor, or #NULL, in case of an error
+ **/
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
+{
+       struct udev_monitor *udev_monitor;
+       unsigned int group;
+
+       if (udev == NULL)
+               return NULL;
+
+       if (name == NULL)
+               group = UDEV_MONITOR_NONE;
+       else if (strcmp(name, "udev") == 0)
+               group = UDEV_MONITOR_UDEV;
+       else if (strcmp(name, "kernel") == 0)
+               group = UDEV_MONITOR_KERNEL;
+       else
+               return NULL;
+
+       udev_monitor = udev_monitor_new(udev);
+       if (udev_monitor == NULL)
+               return NULL;
+
+       udev_monitor->sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+       if (udev_monitor->sock == -1) {
+               err(udev, "error getting socket: %m\n");
+               free(udev_monitor);
+               return NULL;
+       }
+       util_set_fd_cloexec(udev_monitor->sock);
+
+       udev_monitor->snl.nl_family = AF_NETLINK;
+       udev_monitor->snl.nl_groups = group;
+
+       /* default destination for sending */
+       udev_monitor->snl_destination.nl_family = AF_NETLINK;
+       udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
+
+       dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
+       return udev_monitor;
+}
+
+static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
+                           unsigned short code, unsigned int data)
+{
+       struct sock_filter *ins = &inss[*i];
+
+       ins->code = code;
+       ins->k = data;
+       (*i)++;
+}
+
+static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
+                          unsigned short code, unsigned int data,
+                          unsigned short jt, unsigned short jf)
+{
+       struct sock_filter *ins = &inss[*i];
+
+       ins->code = code;
+       ins->jt = jt;
+       ins->jf = jf;
+       ins->k = data;
+       (*i)++;
+}
+
+int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
+{
+       static struct sock_filter ins[256];
+       static struct sock_fprog filter;
+       unsigned int i;
+       struct udev_list_entry *list_entry;
+       int err;
+
+       if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
+               return 0;
+
+       memset(ins, 0x00, sizeof(ins));
+       i = 0;
+
+       /* load magic in A */
+       bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
+       /* jump if magic matches */
+       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
+       /* wrong magic, pass packet */
+       bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
+
+       /* add all subsystem match values */
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
+               unsigned int hash;
+
+               /* load filter_subsystem value in A */
+               bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem));
+               hash = util_string_hash32(udev_list_entry_get_name(list_entry));
+               if (udev_list_entry_get_value(list_entry) == NULL) {
+                       /* jump if subsystem does not match */
+                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
+               } else {
+                       /* jump if subsystem does not match */
+                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
+
+                       /* load filter_devtype value in A */
+                       bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype));
+                       /* jump if value does not match */
+                       hash = util_string_hash32(udev_list_entry_get_value(list_entry));
+                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
+               }
+
+               /* matched, pass packet */
+               bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
+
+               if (i+1 >= ARRAY_SIZE(ins))
+                       return -1;
+       }
+       /* nothing matched, drop packet */
+       bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
+
+       /* install filter */
+       filter.len = i;
+       filter.filter = ins;
+       err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
+       return err;
+}
+
+int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
+{
+       udev_monitor->snl_trusted_sender.nl_pid = sender->snl.nl_pid;
+       return 0;
+}
+
+int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
+{
+       int err;
+       const int on = 1;
+
+       if (udev_monitor->sun.sun_family != 0) {
+               err = bind(udev_monitor->sock,
+                          (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
+       } else if (udev_monitor->snl.nl_family != 0) {
+               udev_monitor_filter_update(udev_monitor);
+               err = bind(udev_monitor->sock,
+                          (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
+               if (err == 0) {
+                       struct sockaddr_nl snl;
+                       socklen_t addrlen;
+
+                       /*
+                        * get the address the kernel has assigned us
+                        * it is usually, but not neccessarily the pid
+                        */
+                       addrlen = sizeof(struct sockaddr_nl);
+                       err = getsockname(udev_monitor->sock, (struct sockaddr *)&snl, &addrlen);
+                       if (err == 0)
+                               udev_monitor->snl.nl_pid = snl.nl_pid;
+               }
+       } else {
+               return -EINVAL;
+       }
+
+       if (err < 0) {
+               err(udev_monitor->udev, "bind failed: %m\n");
+               return err;
+       }
+
+       /* enable receiving of sender credentials */
+       setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
+       return 0;
+}
+
+int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
+{
+       if (udev_monitor == NULL)
+               return -1;
+       return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
+}
+
+int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
+{
+       int err;
+
+       err = close(udev_monitor->sock);
+       udev_monitor->sock = -1;
+       return err;
+}
+
+/**
+ * udev_monitor_ref:
+ * @udev_monitor: udev monitor
+ *
+ * Take a reference of a udev monitor.
+ *
+ * Returns: the passed udev monitor
+ **/
+struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
+{
+       if (udev_monitor == NULL)
+               return NULL;
+       udev_monitor->refcount++;
+       return udev_monitor;
+}
+
+/**
+ * udev_monitor_unref:
+ * @udev_monitor: udev monitor
+ *
+ * Drop a reference of a udev monitor. If the refcount reaches zero,
+ * the bound socket will be closed, and the resources of the monitor
+ * will be released.
+ *
+ **/
+void udev_monitor_unref(struct udev_monitor *udev_monitor)
+{
+       if (udev_monitor == NULL)
+               return;
+       udev_monitor->refcount--;
+       if (udev_monitor->refcount > 0)
+               return;
+       if (udev_monitor->sock >= 0)
+               close(udev_monitor->sock);
+       udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list);
+       dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
+       free(udev_monitor);
+}
+
+/**
+ * udev_monitor_get_udev:
+ * @udev_monitor: udev monitor
+ *
+ * Retrieve the udev library context the monitor was created with.
+ *
+ * Returns: the udev library context
+ **/
+struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
+{
+       if (udev_monitor == NULL)
+               return NULL;
+       return udev_monitor->udev;
+}
+
+/**
+ * udev_monitor_get_fd:
+ * @udev_monitor: udev monitor
+ *
+ * Retrieve the socket file descriptor associated with the monitor.
+ *
+ * Returns: the socket file descriptor
+ **/
+int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
+{
+       if (udev_monitor == NULL)
+               return -1;
+       return udev_monitor->sock;
+}
+
+static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
+{
+       struct udev_list_entry *list_entry;
+
+       if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
+               return 1;
+
+       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
+               const char *subsys = udev_list_entry_get_name(list_entry);
+               const char *dsubsys = udev_device_get_subsystem(udev_device);
+               const char *devtype;
+               const char *ddevtype;
+
+               if (strcmp(dsubsys, subsys) != 0)
+                       continue;
+
+               devtype = udev_list_entry_get_value(list_entry);
+               if (devtype == NULL)
+                       return 1;
+               ddevtype = udev_device_get_devtype(udev_device);
+               if (ddevtype == NULL)
+                       continue;
+               if (strcmp(ddevtype, devtype) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * udev_monitor_receive_device:
+ * @udev_monitor: udev monitor
+ *
+ * Receive data from the udev monitor socket, allocate a new udev
+ * device, fill in the received data, and return the device.
+ *
+ * Only socket connections with uid=0 are accepted. The caller
+ * needs to make sure that there is data to read from the socket.
+ * The call will block until the socket becomes readable.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev device.
+ *
+ * Returns: a new udev device, or #NULL, in case of an error
+ **/
+struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
+{
+       struct udev_device *udev_device;
+       struct msghdr smsg;
+       struct iovec iov;
+       char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
+       struct cmsghdr *cmsg;
+       struct sockaddr_nl snl;
+       struct ucred *cred;
+       char buf[8192];
+       ssize_t buflen;
+       ssize_t bufpos;
+       struct udev_monitor_netlink_header *nlh;
+       int devpath_set = 0;
+       int subsystem_set = 0;
+       int action_set = 0;
+       int maj = 0;
+       int min = 0;
+       int is_kernel = 0;
+
+retry:
+       if (udev_monitor == NULL)
+               return NULL;
+       memset(buf, 0x00, sizeof(buf));
+       iov.iov_base = &buf;
+       iov.iov_len = sizeof(buf);
+       memset (&smsg, 0x00, sizeof(struct msghdr));
+       smsg.msg_iov = &iov;
+       smsg.msg_iovlen = 1;
+       smsg.msg_control = cred_msg;
+       smsg.msg_controllen = sizeof(cred_msg);
+
+       if (udev_monitor->snl.nl_family != 0) {
+               smsg.msg_name = &snl;
+               smsg.msg_namelen = sizeof(snl);
+       }
+
+       buflen = recvmsg(udev_monitor->sock, &smsg, 0);
+       if (buflen < 0) {
+               if (errno != EINTR)
+                       info(udev_monitor->udev, "unable to receive message\n");
+               return NULL;
+       }
+
+       if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
+               info(udev_monitor->udev, "invalid message length\n");
+               return NULL;
+       }
+
+       if (udev_monitor->snl.nl_family != 0) {
+               if (snl.nl_groups == 0) {
+                       /* unicast message, check if we trust the sender */
+                       if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
+                           snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
+                               info(udev_monitor->udev, "unicast netlink message ignored\n");
+                               return NULL;
+                       }
+               } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
+                       if (snl.nl_pid > 0) {
+                               info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n", snl.nl_pid);
+                               return NULL;
+                       }
+                       is_kernel = 1;
+               }
+       }
+
+       cmsg = CMSG_FIRSTHDR(&smsg);
+       if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
+               info(udev_monitor->udev, "no sender credentials received, message ignored\n");
+               return NULL;
+       }
+
+       cred = (struct ucred *)CMSG_DATA(cmsg);
+       if (cred->uid != 0) {
+               info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
+               return NULL;
+       }
+
+       if (strncmp(buf, "udev-", 5) == 0) {
+               /* udev message needs proper version magic */
+               nlh = (struct udev_monitor_netlink_header *) buf;
+               if (nlh->magic != htonl(UDEV_MONITOR_MAGIC))
+                       return NULL;
+               if (nlh->properties_off < sizeof(struct udev_monitor_netlink_header))
+                       return NULL;
+               if (nlh->properties_off+32 > buflen)
+                       return NULL;
+               bufpos = nlh->properties_off;
+       } else {
+               /* kernel message with header */
+               bufpos = strlen(buf) + 1;
+               if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
+                       info(udev_monitor->udev, "invalid message length\n");
+                       return NULL;
+               }
+
+               /* check message header */
+               if (strstr(buf, "@/") == NULL) {
+                       info(udev_monitor->udev, "unrecognized message header\n");
+                       return NULL;
+               }
+       }
+
+       udev_device = device_new(udev_monitor->udev);
+       if (udev_device == NULL) {
+               return NULL;
+       }
+
+       while (bufpos < buflen) {
+               char *key;
+               size_t keylen;
+
+               key = &buf[bufpos];
+               keylen = strlen(key);
+               if (keylen == 0)
+                       break;
+               bufpos += keylen + 1;
+
+               if (strncmp(key, "DEVPATH=", 8) == 0) {
+                       char path[UTIL_PATH_SIZE];
+
+                       util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_monitor->udev), &key[8], NULL);
+                       udev_device_set_syspath(udev_device, path);
+                       devpath_set = 1;
+               } else if (strncmp(key, "SUBSYSTEM=", 10) == 0) {
+                       udev_device_set_subsystem(udev_device, &key[10]);
+                       subsystem_set = 1;
+               } else if (strncmp(key, "DEVTYPE=", 8) == 0) {
+                       udev_device_set_devtype(udev_device, &key[8]);
+               } else if (strncmp(key, "DEVNAME=", 8) == 0) {
+                       if (is_kernel)
+                               udev_device_set_knodename(udev_device, &key[8]);
+                       else
+                               udev_device_set_devnode(udev_device, &key[8]);
+               } else if (strncmp(key, "DEVLINKS=", 9) == 0) {
+                       char devlinks[UTIL_PATH_SIZE];
+                       char *slink;
+                       char *next;
+
+                       util_strscpy(devlinks, sizeof(devlinks), &key[9]);
+                       slink = devlinks;
+                       next = strchr(slink, ' ');
+                       while (next != NULL) {
+                               next[0] = '\0';
+                               udev_device_add_devlink(udev_device, slink);
+                               slink = &next[1];
+                               next = strchr(slink, ' ');
+                       }
+                       if (slink[0] != '\0')
+                               udev_device_add_devlink(udev_device, slink);
+               } else if (strncmp(key, "DRIVER=", 7) == 0) {
+                       udev_device_set_driver(udev_device, &key[7]);
+               } else if (strncmp(key, "ACTION=", 7) == 0) {
+                       udev_device_set_action(udev_device, &key[7]);
+                       action_set = 1;
+               } else if (strncmp(key, "MAJOR=", 6) == 0) {
+                       maj = strtoull(&key[6], NULL, 10);
+               } else if (strncmp(key, "MINOR=", 6) == 0) {
+                       min = strtoull(&key[6], NULL, 10);
+               } else if (strncmp(key, "DEVPATH_OLD=", 12) == 0) {
+                       udev_device_set_devpath_old(udev_device, &key[12]);
+               } else if (strncmp(key, "SEQNUM=", 7) == 0) {
+                       udev_device_set_seqnum(udev_device, strtoull(&key[7], NULL, 10));
+               } else if (strncmp(key, "TIMEOUT=", 8) == 0) {
+                       udev_device_set_timeout(udev_device, strtoull(&key[8], NULL, 10));
+               } else {
+                       udev_device_add_property_from_string(udev_device, key);
+               }
+       }
+       if (!devpath_set || !subsystem_set || !action_set) {
+               info(udev_monitor->udev, "missing values, skip\n");
+               udev_device_unref(udev_device);
+               return NULL;
+       }
+
+       /* skip device, if it does not pass the current filter */
+       if (!passes_filter(udev_monitor, udev_device)) {
+               struct pollfd pfd[1];
+               int rc;
+
+               udev_device_unref(udev_device);
+
+               /* if something is queued, get next device */
+               pfd[0].fd = udev_monitor->sock;
+               pfd[0].events = POLLIN;
+               rc = poll(pfd, 1, 0);
+               if (rc > 0)
+                       goto retry;
+               return NULL;
+       }
+
+       if (maj > 0)
+               udev_device_set_devnum(udev_device, makedev(maj, min));
+       udev_device_set_info_loaded(udev_device);
+       return udev_device;
+}
+
+int udev_monitor_send_device(struct udev_monitor *udev_monitor,
+                            struct udev_monitor *destination, struct udev_device *udev_device)
+{
+       struct msghdr smsg;
+       struct iovec iov[2];
+       const char *buf;
+       ssize_t blen;
+       ssize_t count;
+
+       blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
+       if (blen < 32)
+               return -1;
+
+       if (udev_monitor->sun.sun_family != 0) {
+               const char *action;
+               char header[2048];
+               char *s;
+
+               /* header <action>@<devpath> */
+               action = udev_device_get_action(udev_device);
+               if (action == NULL)
+                       return -EINVAL;
+               s = header;
+               if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
+                       return -EINVAL;
+               iov[0].iov_base = header;
+               iov[0].iov_len = (s - header)+1;
+
+               /* add properties list */
+               iov[1].iov_base = (char *)buf;
+               iov[1].iov_len = blen;
+
+               memset(&smsg, 0x00, sizeof(struct msghdr));
+               smsg.msg_iov = iov;
+               smsg.msg_iovlen = 2;
+               smsg.msg_name = &udev_monitor->sun;
+               smsg.msg_namelen = udev_monitor->addrlen;
+       } else if (udev_monitor->snl.nl_family != 0) {
+               const char *val;
+               struct udev_monitor_netlink_header nlh;
+
+
+               /* add versioned header */
+               memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header));
+               util_strscpy(nlh.version, sizeof(nlh.version), "udev-" VERSION);
+               nlh.magic = htonl(UDEV_MONITOR_MAGIC);
+               val = udev_device_get_subsystem(udev_device);
+               nlh.filter_subsystem = htonl(util_string_hash32(val));
+               val = udev_device_get_devtype(udev_device);
+               if (val != NULL)
+                       nlh.filter_devtype = htonl(util_string_hash32(val));
+               iov[0].iov_base = &nlh;
+               iov[0].iov_len = sizeof(struct udev_monitor_netlink_header);
+
+               /* add properties list */
+               nlh.properties_off = iov[0].iov_len;
+               nlh.properties_len = blen;
+               iov[1].iov_base = (char *)buf;
+               iov[1].iov_len = blen;
+
+               memset(&smsg, 0x00, sizeof(struct msghdr));
+               smsg.msg_iov = iov;
+               smsg.msg_iovlen = 2;
+               /*
+                * Use custom address for target, or the default one.
+                *
+                * If we send to a muticast group, we will get
+                * ECONNREFUSED, which is expected.
+                */
+               if (destination != NULL)
+                       smsg.msg_name = &destination->snl;
+               else
+                       smsg.msg_name = &udev_monitor->snl_destination;
+               smsg.msg_namelen = sizeof(struct sockaddr_nl);
+       } else {
+               return -1;
+       }
+
+       count = sendmsg(udev_monitor->sock, &smsg, 0);
+       info(udev_monitor->udev, "passed %zi bytes to monitor %p\n", count, udev_monitor);
+       return count;
+}
+
+int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
+{
+       if (udev_monitor == NULL)
+               return -EINVAL;
+       if (subsystem == NULL)
+               return 0;
+       if (udev_list_entry_add(udev_monitor->udev,
+                               &udev_monitor->filter_subsystem_list, subsystem, devtype, 0, 0) == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
+{
+       static struct sock_fprog filter = { 0, NULL };
+
+       udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list);
+       return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
+}
diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h
new file mode 100644 (file)
index 0000000..5512341
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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.
+ */
+
+#ifndef _LIBUDEV_PRIVATE_H_
+#define _LIBUDEV_PRIVATE_H_
+
+#include <syslog.h>
+#include "libudev.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static inline void __attribute__ ((format(printf, 2, 3)))
+udev_log_null(struct udev *udev, const char *format, ...) {}
+
+#ifdef USE_LOG
+#  ifdef DEBUG
+#    define dbg(udev, arg...) udev_log(udev, LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#  else
+#    define dbg(udev, arg...) udev_log_null(udev, ## arg)
+#  endif
+#  define info(udev, arg...) udev_log(udev, LOG_INFO, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#  define err(udev, arg...) udev_log(udev, LOG_ERR, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#else
+#  define dbg(udev, arg...) udev_log_null(udev, ## arg)
+#  define info(udev, arg...) udev_log_null(udev, ## arg)
+#  define err(udev, arg...) udev_log_null(udev, ## arg)
+#endif
+
+/* libudev */
+void udev_log(struct udev *udev,
+             int priority, const char *file, int line, const char *fn,
+             const char *format, ...)
+             __attribute__ ((format(printf, 6, 7)));
+struct udev_device *device_new(struct udev *udev);
+const char *udev_get_rules_path(struct udev *udev);
+int udev_get_run(struct udev *udev);
+struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
+struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
+
+/* libudev-device */
+int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
+int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem);
+int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype);
+int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
+int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink);
+void udev_device_cleanup_devlinks_list(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
+struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property);
+char **udev_device_get_properties_envp(struct udev_device *udev_device);
+ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf);
+int udev_device_read_db(struct udev_device *udev_device);
+int udev_device_read_uevent_file(struct udev_device *udev_device);
+int udev_device_set_action(struct udev_device *udev_device, const char *action);
+int udev_device_set_driver(struct udev_device *udev_device, const char *driver);
+const char *udev_device_get_devpath_old(struct udev_device *udev_device);
+int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
+const char *udev_device_get_knodename(struct udev_device *udev_device);
+int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename);
+int udev_device_get_timeout(struct udev_device *udev_device);
+int udev_device_set_timeout(struct udev_device *udev_device, int timeout);
+int udev_device_get_event_timeout(struct udev_device *udev_device);
+int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout);
+int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum);
+int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum);
+int udev_device_get_num_fake_partitions(struct udev_device *udev_device);
+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);
+int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
+int udev_device_get_ignore_remove(struct udev_device *udev_device);
+int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore);
+int udev_device_get_watch_handle(struct udev_device *udev_device);
+int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
+void udev_device_set_info_loaded(struct udev_device *device);
+
+/* libudev-device-db-write.c */
+int udev_device_update_db(struct udev_device *udev_device);
+int udev_device_delete_db(struct udev_device *udev_device);
+int udev_device_rename_db(struct udev_device *udev_device, const char *devpath);
+
+/* libudev-monitor - netlink/unix socket communication  */
+int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
+int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender);
+int udev_monitor_send_device(struct udev_monitor *udev_monitor,
+                            struct udev_monitor *destination, struct udev_device *udev_device);
+int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
+
+/* libudev-ctrl - daemon runtime setup */
+struct udev_ctrl;
+struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path);
+int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
+struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
+void udev_ctrl_unref(struct udev_ctrl *uctrl);
+struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
+int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
+int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority);
+int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl);
+int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl);
+int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl);
+int udev_ctrl_send_settle(struct udev_ctrl *uctrl);
+int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key);
+int udev_ctrl_send_set_max_childs(struct udev_ctrl *uctrl, int count);
+struct udev_ctrl_msg;
+struct udev_ctrl_msg *udev_ctrl_msg(struct udev_ctrl *uctrl);
+struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl);
+struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg);
+void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg);
+pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg);
+const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_get_set_max_childs(struct udev_ctrl_msg *ctrl_msg);
+
+/* libudev-list */
+struct udev_list_node {
+       struct udev_list_node *next, *prev;
+};
+void udev_list_init(struct udev_list_node *list);
+int udev_list_is_empty(struct udev_list_node *list);
+void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);
+void udev_list_node_remove(struct udev_list_node *entry);
+#define udev_list_node_foreach(node, list) \
+       for (node = (list)->next; \
+            node != list; \
+            node = (node)->next)
+#define udev_list_node_foreach_safe(node, tmp, list) \
+       for (node = (list)->next, tmp = (node)->next; \
+            node != list; \
+            node = tmp, tmp = (tmp)->next)
+struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list,
+                                                  const char *name, const char *value,
+                                                  int unique, int sort);
+void udev_list_entry_delete(struct udev_list_entry *entry);
+void udev_list_entry_remove(struct udev_list_entry *entry);
+void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
+void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list);
+void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *name_list);
+struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list);
+int udev_list_entry_get_flag(struct udev_list_entry *list_entry);
+void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag);
+#define udev_list_entry_foreach_safe(entry, tmp, first) \
+       for (entry = first, tmp = udev_list_entry_get_next(entry); \
+            entry != NULL; \
+            entry = tmp, tmp = udev_list_entry_get_next(tmp))
+
+/* libudev-queue */
+unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
+int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
+ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
+ssize_t udev_queue_skip_devpath(FILE *queue_file);
+
+/* libudev-queue-export */
+struct udev_queue_export *udev_queue_export_new(struct udev *udev);
+void udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
+void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
+int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
+int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
+int udev_queue_export_device_failed(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
+
+/* libudev-utils */
+#define UTIL_PATH_SIZE                         1024
+#define UTIL_LINE_SIZE                         2048
+#define UTIL_NAME_SIZE                         512
+#define UDEV_ALLOWED_CHARS_INPUT               "/ $%?,"
+ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size);
+ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size);
+int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
+int util_log_priority(const char *priority);
+size_t util_path_encode(const char *src, char *dest, size_t size);
+size_t util_path_decode(char *s);
+void util_remove_trailing_chars(char *path, char c);
+size_t util_strpcpy(char **dest, size_t size, const char *src);
+size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__ ((sentinel));
+size_t util_strscpy(char *dest, size_t size, const char *src);
+size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__ ((sentinel));
+int udev_util_replace_whitespace(const char *str, char *to, size_t len);
+int udev_util_replace_chars(char *str, const char *white);
+int udev_util_encode_string(const char *str, char *str_enc, size_t len);
+void util_set_fd_cloexec(int fd);
+unsigned int util_string_hash32(const char *str);
+#endif
diff --git a/libudev/libudev-queue-export.c b/libudev/libudev-queue-export.c
new file mode 100644 (file)
index 0000000..a36ff51
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+ *
+ * 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.
+ */
+
+/*
+ * DISCLAIMER - The file format mentioned here is private to udev/libudev,
+ *              and may be changed without notice.
+ *
+ *
+ * The udev event queue is exported as a binary log file.
+ * Each log record consists of a sequence number followed by the device path.
+ *
+ * When a new event is queued, its details are appended to the log.
+ * When the event finishes, a second record is appended to the log
+ * with the same sequence number but a null devpath.
+ *
+ * Example:
+ *     {1, "/devices/virtual/mem/null" },
+ *     {2, "/devices/virtual/mem/zero" },
+ *     {1, "" },
+ * Event 2 is still queued, but event 1 has been finished
+ *
+ * The queue does not grow indefinitely.  It is periodically re-created
+ * to remove finished events.  Atomic rename() makes this transparent to readers.
+ *
+ *
+ * The queue file starts with a single sequence number which specifies the
+ * minimum sequence number in the log that follows.  Any events prior to this
+ * sequence number have already finished.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include "udev.h"
+
+static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
+
+struct udev_queue_export {
+       struct udev *udev;
+       int failed_count;       /* number of failed events exported */
+       int queued_count;       /* number of unfinished events exported in queue file */
+       FILE *queue_file;
+       unsigned long long int seqnum_max;      /* earliest sequence number in queue file */
+       unsigned long long int seqnum_min;      /* latest sequence number in queue file */
+       int waste_bytes;                        /* queue file bytes wasted on finished events */
+};
+
+struct udev_queue_export *udev_queue_export_new(struct udev *udev)
+{
+       struct udev_queue_export *udev_queue_export;
+       unsigned long long int initial_seqnum;
+
+       if (udev == NULL)
+               return NULL;
+
+       udev_queue_export = calloc(1, sizeof(struct udev_queue_export));
+       if (udev_queue_export == NULL)
+               return NULL;
+       udev_queue_export->udev = udev;
+
+       initial_seqnum = udev_get_kernel_seqnum(udev);
+       udev_queue_export->seqnum_min = initial_seqnum;
+       udev_queue_export->seqnum_max = initial_seqnum;
+
+       udev_queue_export_cleanup(udev_queue_export);
+       if (rebuild_queue_file(udev_queue_export) != 0) {
+               free(udev_queue_export);
+               return NULL;
+       }
+
+       return udev_queue_export;
+}
+
+void udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
+{
+       if (udev_queue_export == NULL)
+               return;
+       if (udev_queue_export->queue_file != NULL)
+               fclose(udev_queue_export->queue_file);
+       free(udev_queue_export);
+}
+
+void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
+{
+       char filename[UTIL_PATH_SIZE];
+
+       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.tmp", NULL);
+       unlink(filename);
+
+       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.bin", NULL);
+       unlink(filename);
+}
+
+
+static int skip_to(FILE *file, long offset)
+{
+       long old_offset;
+
+       /* fseek may drop buffered data, avoid it for small seeks */
+       old_offset = ftell(file);
+       if (offset > old_offset && offset - old_offset <= BUFSIZ) {
+               size_t skip_bytes = offset - old_offset;
+               char buf[skip_bytes];
+
+               if (fread(buf, skip_bytes, 1, file) != skip_bytes)
+                       return -1;
+       }
+
+       return fseek(file, offset, SEEK_SET);
+}
+
+struct queue_devpaths {
+       unsigned int devpaths_first;    /* index of first queued event */
+       unsigned int devpaths_size;
+       long devpaths[];                /* seqnum -> offset of devpath in queue file (or 0) */
+};
+
+/*
+ * Returns a table mapping seqnum to devpath file offset for currently queued events.
+ * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
+ */
+static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
+{
+       struct queue_devpaths *devpaths;
+       unsigned long long int range;
+       long devpath_offset;
+       ssize_t devpath_len;
+       unsigned long long int seqnum;
+       unsigned long long int n;
+       unsigned int i;
+
+       /* seek to the first event in the file */
+       rewind(udev_queue_export->queue_file);
+       udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
+
+       /* allocate the table */
+       range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
+       if (range - 1 > INT_MAX) {
+               err(udev_queue_export->udev, "queue file overflow\n");
+               return NULL;
+       }
+       devpaths = calloc(1, sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
+       if (index == NULL)
+               return NULL;
+       devpaths->devpaths_size = range + 1;
+
+       /* read all records and populate the table */
+       while(1) {
+               if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
+                       break;
+               n = seqnum - udev_queue_export->seqnum_max;
+               if (n >= devpaths->devpaths_size)
+                       goto read_error;
+
+               devpath_offset = ftell(udev_queue_export->queue_file);
+               devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
+               if (devpath_len < 0)
+                       goto read_error;
+
+               if (devpath_len > 0)
+                       devpaths->devpaths[n] = devpath_offset;
+               else
+                       devpaths->devpaths[n] = 0;
+       }
+
+       /* find first queued event */
+       for (i = 0; i < devpaths->devpaths_size; i++) {
+               if (devpaths->devpaths[i] != 0)
+                       break;
+       }
+       devpaths->devpaths_first = i;
+
+       return devpaths;
+
+read_error:
+       err(udev_queue_export->udev, "queue file corrupted\n");
+       free(devpaths);
+       return NULL;
+}
+
+static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
+{
+       unsigned long long int seqnum;
+       struct queue_devpaths *devpaths = NULL;
+       char filename[UTIL_PATH_SIZE];
+       char filename_tmp[UTIL_PATH_SIZE];
+       FILE *new_queue_file = NULL;
+       unsigned int i;
+
+       /* read old queue file */
+       if (udev_queue_export->queue_file != NULL) {
+               dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n",
+                                               udev_queue_export->waste_bytes);
+
+               devpaths = build_index(udev_queue_export);
+               if (devpaths != NULL)
+                       udev_queue_export->seqnum_max += devpaths->devpaths_first;
+       }
+       if (devpaths == NULL) {
+               dbg(udev_queue_export->udev, "creating empty queue file\n");
+               udev_queue_export->queued_count = 0;
+               udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
+       }
+
+       /* create new queue file */
+       util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.tmp", NULL);
+       new_queue_file = fopen(filename_tmp, "w+");
+       if (new_queue_file == NULL)
+               goto error;
+       seqnum = udev_queue_export->seqnum_max;
+       fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
+
+       /* copy unfinished events only to the new file */
+       if (devpaths != NULL) {
+               for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
+                       char devpath[UTIL_PATH_SIZE];
+                       int err;
+                       unsigned short devpath_len;
+
+                       if (devpaths->devpaths[i] != 0)
+                       {
+                               skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
+                               err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
+                               devpath_len = err;
+
+                               fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
+                               fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
+                               fwrite(devpath, 1, devpath_len, new_queue_file);
+                       }
+                       seqnum++;
+               }
+               free(devpaths);
+               devpaths = NULL;
+       }
+       fflush(new_queue_file);
+       if (ferror(new_queue_file))
+               goto error;
+
+       /* rename the new file on top of the old one */
+       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.bin", NULL);
+       if (rename(filename_tmp, filename) != 0)
+               goto error;
+
+       if (udev_queue_export->queue_file != NULL)
+               fclose(udev_queue_export->queue_file);
+       udev_queue_export->queue_file = new_queue_file;
+       udev_queue_export->waste_bytes = 0;
+
+       return 0;
+
+error:
+       err(udev_queue_export->udev, "failed to create queue file: %m\n");
+       udev_queue_export_cleanup(udev_queue_export);
+
+       if (udev_queue_export->queue_file != NULL) {
+               fclose(udev_queue_export->queue_file);
+               udev_queue_export->queue_file = NULL;
+       }
+       if (new_queue_file != NULL)
+               fclose(new_queue_file);
+
+       if (devpaths != NULL)
+               free(devpaths);
+       udev_queue_export->queued_count = 0;
+       udev_queue_export->waste_bytes = 0;
+       udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
+
+       return -1;
+}
+
+static int write_queue_record(struct udev_queue_export *udev_queue_export,
+                             unsigned long long int seqnum, const char *devpath, size_t devpath_len)
+{
+       unsigned short len;
+
+       if (udev_queue_export->queue_file == NULL) {
+               dbg(udev_queue_export->udev, "can't record event: queue file not available\n");
+               return -1;
+       }
+
+       if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
+               goto write_error;
+
+       len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
+       if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
+               goto write_error;
+       if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
+               goto write_error;
+
+       /* *must* flush output; caller may fork */
+       if (fflush(udev_queue_export->queue_file) != 0)
+               goto write_error;
+
+       return 0;
+
+write_error:
+       /* if we failed half way through writing a record to a file,
+          we should not try to write any further records to it. */
+       err(udev_queue_export->udev, "error writing to queue file: %m\n");
+       fclose(udev_queue_export->queue_file);
+       udev_queue_export->queue_file = NULL;
+
+       return -1;
+}
+
+
+enum device_state {
+       DEVICE_QUEUED,
+       DEVICE_FINISHED,
+       DEVICE_FAILED,
+};
+
+static inline size_t queue_record_size(size_t devpath_len)
+{
+       return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
+}
+
+static int update_queue(struct udev_queue_export *udev_queue_export,
+                        struct udev_device *udev_device, enum device_state state)
+{
+       unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
+       const char *devpath = NULL;
+       size_t devpath_len = 0;
+       int bytes;
+       int err;
+
+       if (state == DEVICE_QUEUED) {
+               devpath = udev_device_get_devpath(udev_device);
+               devpath_len = strlen(devpath);
+       }
+
+       /* recover from an earlier failed rebuild */
+       if (udev_queue_export->queue_file == NULL) {
+               if (rebuild_queue_file(udev_queue_export) != 0)
+                       return -1;
+       }
+
+       /* when the queue files grow too large, they must be garbage collected and rebuilt */
+       bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
+
+       /* if we're removing the last event from the queue, that's the best time to rebuild it */
+       if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1 && bytes > 2048) {
+               /* because we don't need to read the old queue file */
+               fclose(udev_queue_export->queue_file);
+               udev_queue_export->queue_file = NULL;
+               rebuild_queue_file(udev_queue_export);
+               return 0;
+       }
+
+       /* try to rebuild the queue files before they grow larger than one page. */
+       if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
+               rebuild_queue_file(udev_queue_export);
+
+       /* don't record a finished event, if we already dropped the event in a failed rebuild */
+       if (seqnum < udev_queue_export->seqnum_max)
+               return 0;
+
+       /* now write to the queue */
+       if (state == DEVICE_QUEUED) {
+               udev_queue_export->queued_count++;
+               udev_queue_export->seqnum_min = seqnum;
+       } else {
+               udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
+               udev_queue_export->queued_count--;
+       }
+       err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
+
+       /* try to handle ENOSPC */
+       if (err != 0 && udev_queue_export->queued_count == 0) {
+               udev_queue_export_cleanup(udev_queue_export);
+               err = rebuild_queue_file(udev_queue_export);
+       }
+
+       return err;
+}
+
+static void update_failed(struct udev_queue_export *udev_queue_export,
+                         struct udev_device *udev_device, enum device_state state)
+{
+       struct udev *udev = udev_device_get_udev(udev_device);
+       char filename[UTIL_PATH_SIZE];
+       char *s;
+       size_t l;
+
+       if (state != DEVICE_FAILED && udev_queue_export->failed_count == 0)
+               return;
+
+       /* location of failed file */
+       s = filename;
+       l = util_strpcpyl(&s, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
+       util_path_encode(udev_device_get_devpath(udev_device), s, l);
+
+       switch (state) {
+       case DEVICE_FAILED:
+               /* record event in the failed directory */
+               if (udev_queue_export->failed_count == 0)
+                       util_create_path(udev, filename);
+               udev_queue_export->failed_count++;
+
+               udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
+               symlink(udev_device_get_devpath(udev_device), filename);
+               udev_selinux_resetfscreatecon(udev);
+               break;
+
+       case DEVICE_QUEUED:
+               /* delete failed file */
+               if (unlink(filename) == 0) {
+                       util_delete_path(udev, filename);
+                       udev_queue_export->failed_count--;
+               }
+               break;
+
+       case DEVICE_FINISHED:
+               if (udev_device_get_devpath_old(udev_device) != NULL) {
+                       /* "move" event - rename failed file to current name, do not delete failed */
+                       char filename_old[UTIL_PATH_SIZE];
+
+                       s = filename_old;
+                       l = util_strpcpyl(&s, sizeof(filename_old), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
+                       util_path_encode(udev_device_get_devpath_old(udev_device), s, l);
+
+                       if (rename(filename_old, filename) == 0)
+                               info(udev, "renamed devpath, moved failed state of '%s' to %s'\n",
+                                    udev_device_get_devpath_old(udev_device), udev_device_get_devpath(udev_device));
+               }
+               break;
+       }
+
+       return;
+}
+
+static int update(struct udev_queue_export *udev_queue_export,
+                 struct udev_device *udev_device, enum device_state state)
+{
+       update_failed(udev_queue_export, udev_device, state);
+
+       if (update_queue(udev_queue_export, udev_device, state) != 0)
+               return -1;
+
+       return 0;
+}
+
+int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
+{
+       return update(udev_queue_export, udev_device, DEVICE_QUEUED);
+}
+
+int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
+{
+       return update(udev_queue_export, udev_device, DEVICE_FINISHED);
+}
+
+int udev_queue_export_device_failed(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
+{
+       return update(udev_queue_export, udev_device, DEVICE_FAILED);
+}
diff --git a/libudev/libudev-queue.c b/libudev/libudev-queue.c
new file mode 100644 (file)
index 0000000..cf1ddf3
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+struct udev_queue {
+       struct udev *udev;
+       int refcount;
+       struct udev_list_node queue_list;
+       struct udev_list_node failed_list;
+};
+
+struct udev_queue *udev_queue_new(struct udev *udev)
+{
+       struct udev_queue *udev_queue;
+
+       if (udev == NULL)
+               return NULL;
+
+       udev_queue = calloc(1, sizeof(struct udev_queue));
+       if (udev_queue == NULL)
+               return NULL;
+       udev_queue->refcount = 1;
+       udev_queue->udev = udev;
+       udev_list_init(&udev_queue->queue_list);
+       udev_list_init(&udev_queue->failed_list);
+       return udev_queue;
+}
+
+struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
+{
+       if (udev_queue == NULL)
+               return NULL;
+       udev_queue->refcount++;
+       return udev_queue;
+}
+
+void udev_queue_unref(struct udev_queue *udev_queue)
+{
+       if (udev_queue == NULL)
+               return;
+       udev_queue->refcount--;
+       if (udev_queue->refcount > 0)
+               return;
+       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
+       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
+       free(udev_queue);
+}
+
+struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
+{
+       if (udev_queue == NULL)
+               return NULL;
+       return udev_queue->udev;
+}
+
+unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
+{
+       char filename[UTIL_PATH_SIZE];
+       unsigned long long int seqnum;
+       int fd;
+       char buf[32];
+       ssize_t len;
+
+       util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
+       fd = open(filename, O_RDONLY);
+       if (fd < 0)
+               return 0;
+       len = read(fd, buf, sizeof(buf));
+       close(fd);
+       if (len <= 2)
+               return 0;
+       buf[len-1] = '\0';
+       seqnum = strtoull(buf, NULL, 10);
+       return seqnum;
+}
+
+unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
+{
+       unsigned long long int seqnum;
+
+       if (udev_queue == NULL)
+               return -EINVAL;
+
+       seqnum = udev_get_kernel_seqnum(udev_queue->udev);
+       dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
+       return seqnum;
+}
+
+int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
+{
+       if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
+               return -1;
+
+       return 0;
+}
+
+ssize_t udev_queue_skip_devpath(FILE *queue_file)
+{
+       unsigned short int len;
+
+       if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
+               char devpath[len];
+
+               /* use fread to skip, fseek might drop buffered data */
+               if (fread(devpath, 1, len, queue_file) == len)
+                       return len;
+       }
+
+       return -1;
+}
+
+ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
+{
+       unsigned short int read_bytes = 0;
+       unsigned short int len;
+
+       if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
+               return -1;
+
+       read_bytes = (len < size - 1) ? len : size - 1;
+       if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
+               return -1;
+       devpath[read_bytes] = '\0';
+
+       /* if devpath was too long, skip unread characters */
+       if (read_bytes != len) {
+               unsigned short int skip_bytes = len - read_bytes;
+               char buf[skip_bytes];
+
+               if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
+                       return -1;
+       }
+
+       return read_bytes;
+}
+
+static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
+{
+       char filename[UTIL_PATH_SIZE];
+       FILE *queue_file;
+
+       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL);
+       queue_file = fopen(filename, "r");
+       if (queue_file == NULL)
+               return NULL;
+
+       if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
+               err(udev_queue->udev, "corrupt queue file\n");
+               fclose(queue_file);
+               return NULL;
+       }
+
+       return queue_file;
+}
+
+
+unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
+{
+       unsigned long long int seqnum_udev;
+       FILE *queue_file;
+
+       queue_file = open_queue_file(udev_queue, &seqnum_udev);
+       if (queue_file == NULL)
+               return 0;
+
+       while (1) {
+               unsigned long long int seqnum;
+               ssize_t devpath_len;
+
+               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
+                       break;
+               devpath_len = udev_queue_skip_devpath(queue_file);
+               if (devpath_len < 0)
+                       break;
+               if (devpath_len > 0)
+                       seqnum_udev = seqnum;
+       }
+
+       fclose(queue_file);
+       return seqnum_udev;
+}
+
+int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
+{
+       unsigned long long int seqnum_start;
+       FILE *queue_file;
+
+       queue_file = open_queue_file(udev_queue, &seqnum_start);
+       if (queue_file == NULL)
+               return 0;
+
+       fclose(queue_file);
+       return 1;
+}
+
+int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
+{
+       unsigned long long int seqnum_kernel;
+       unsigned long long int seqnum_udev = 0;
+       int queued = 0;
+       int is_empty = 0;
+       FILE *queue_file;
+
+       if (udev_queue == NULL)
+               return -EINVAL;
+       queue_file = open_queue_file(udev_queue, &seqnum_udev);
+       if (queue_file == NULL)
+               return 1;
+
+       while (1) {
+               unsigned long long int seqnum;
+               ssize_t devpath_len;
+
+               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
+                       break;
+               devpath_len = udev_queue_skip_devpath(queue_file);
+               if (devpath_len < 0)
+                       break;
+
+               if (devpath_len > 0) {
+                       queued++;
+                       seqnum_udev = seqnum;
+               } else {
+                       queued--;
+               }
+       }
+
+       if (queued > 0) {
+               dbg(udev_queue->udev, "queue is not empty\n");
+               goto out;
+       }
+
+       seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
+       if (seqnum_udev < seqnum_kernel) {
+               dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
+                                       seqnum_kernel, seqnum_udev);
+               goto out;
+       }
+
+       dbg(udev_queue->udev, "queue is empty\n");
+       is_empty = 1;
+
+out:
+       fclose(queue_file);
+       return is_empty;
+}
+
+int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
+                                              unsigned long long int start, unsigned long long int end)
+{
+       unsigned long long int seqnum = 0;
+       ssize_t devpath_len;
+       int unfinished;
+       FILE *queue_file;
+
+       if (udev_queue == NULL)
+               return -EINVAL;
+       queue_file = open_queue_file(udev_queue, &seqnum);
+       if (queue_file == NULL)
+               return 1;
+       if (start < seqnum)
+               start = seqnum;
+       if (start > end)
+               return 1;
+       if (end - start > INT_MAX - 1)
+               return -EOVERFLOW;
+       unfinished = (end - start) + 1;
+
+       while (unfinished > 0) {
+               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
+                       break;
+               devpath_len = udev_queue_skip_devpath(queue_file);
+               if (devpath_len < 0)
+                       break;
+
+               if (devpath_len == 0) {
+                       if (seqnum >= start && seqnum <= end)
+                               unfinished--;
+               }
+       }
+       fclose(queue_file);
+
+       return (unfinished == 0);
+}
+
+int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
+{
+       if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
+               return 0;
+
+       dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
+       return 1;
+}
+
+struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
+{
+       unsigned long long int seqnum;
+       FILE *queue_file;
+
+       if (udev_queue == NULL)
+               return NULL;
+       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
+
+       queue_file = open_queue_file(udev_queue, &seqnum);
+       if (queue_file == NULL)
+               return NULL;
+
+       while (1) {
+               char syspath[UTIL_PATH_SIZE];
+               char *s;
+               size_t l;
+               ssize_t len;
+               char seqnum_str[32];
+               struct udev_list_entry *list_entry;
+
+               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
+                       break;
+               snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
+
+               s = syspath;
+               l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
+               len = udev_queue_read_devpath(queue_file, s, l);
+               if (len < 0)
+                       break;
+
+               if (len > 0) {
+                       udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0, 0);
+               } else {
+                       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
+                               if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
+                                       udev_list_entry_delete(list_entry);
+                                       break;
+                               }
+                       }
+               }
+       }
+       fclose(queue_file);
+
+       return udev_list_get_entry(&udev_queue->queue_list);
+}
+
+struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
+{
+       char path[UTIL_PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       if (udev_queue == NULL)
+               return NULL;
+       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
+       util_strscpyl(path, sizeof(path), udev_get_dev_path(udev_queue->udev), "/.udev/failed", NULL);
+       dir = opendir(path);
+       if (dir == NULL)
+               return NULL;
+       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+               char filename[UTIL_PATH_SIZE];
+               char syspath[UTIL_PATH_SIZE];
+               char *s;
+               size_t l;
+               ssize_t len;
+               struct stat statbuf;
+
+               if (dent->d_name[0] == '.')
+                       continue;
+               s = syspath;
+               l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
+               len = readlinkat(dirfd(dir), dent->d_name, s, l);
+               if (len < 0 || (size_t)len >= l)
+                       continue;
+               s[len] = '\0';
+               dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name);
+               util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
+               if (stat(filename, &statbuf) != 0)
+                       continue;
+               udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0);
+       }
+       closedir(dir);
+       return udev_list_get_entry(&udev_queue->failed_list);
+}
diff --git a/libudev/libudev-util.c b/libudev/libudev-util.c
new file mode 100644 (file)
index 0000000..dcc4a0f
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
+{
+       char path[UTIL_PATH_SIZE];
+       ssize_t len;
+       const char *pos;
+
+       util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
+       len = readlink(path, path, sizeof(path));
+       if (len < 0 || len >= (ssize_t) sizeof(path))
+               return -1;
+       path[len] = '\0';
+       pos = strrchr(path, '/');
+       if (pos == NULL)
+               return -1;
+       pos = &pos[1];
+       dbg(udev, "resolved link to: '%s'\n", pos);
+       return util_strscpy(value, size, pos);
+}
+
+ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
+{
+       return get_sys_link(udev, "subsystem", syspath, subsystem, size);
+}
+
+ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
+{
+       return get_sys_link(udev, "driver", syspath, driver, size);
+}
+
+int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
+{
+       char link_target[UTIL_PATH_SIZE];
+
+       int len;
+       int i;
+       int back;
+       char *base;
+
+       len = readlink(syspath, link_target, sizeof(link_target));
+       if (len <= 0)
+               return -1;
+       link_target[len] = '\0';
+       dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
+
+       for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
+               ;
+       dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
+       for (i = 0; i <= back; i++) {
+               base = strrchr(syspath, '/');
+               if (base == NULL)
+                       return -1;
+               base[0] = '\0';
+       }
+       dbg(udev, "after moving back '%s'\n", syspath);
+       util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
+       return 0;
+}
+
+int util_log_priority(const char *priority)
+{
+       char *endptr;
+       int prio;
+
+       prio = strtol(priority, &endptr, 10);
+       if (endptr[0] == '\0')
+               return prio;
+       if (strncmp(priority, "err", 3) == 0)
+               return LOG_ERR;
+       if (strcmp(priority, "info") == 0)
+               return LOG_INFO;
+       if (strcmp(priority, "debug") == 0)
+               return LOG_DEBUG;
+       return 0;
+}
+
+size_t util_path_encode(const char *src, char *dest, size_t size)
+{
+       size_t i, j;
+
+       for (i = 0, j = 0; src[i] != '\0'; i++) {
+               if (src[i] == '/') {
+                       if (j+4 >= size) {
+                               j = 0;
+                               break;
+                       }
+                       memcpy(&dest[j], "\\x2f", 4);
+                       j += 4;
+               } else if (src[i] == '\\') {
+                       if (j+4 >= size) {
+                               j = 0;
+                               break;
+                       }
+                       memcpy(&dest[j], "\\x5c", 4);
+                       j += 4;
+               } else {
+                       if (j+1 >= size) {
+                               j = 0;
+                               break;
+                       }
+                       dest[j] = src[i];
+                       j++;
+               }
+       }
+       dest[j] = '\0';
+       return j;
+}
+
+size_t util_path_decode(char *s)
+{
+       size_t i, j;
+
+       for (i = 0, j = 0; s[i] != '\0'; j++) {
+               if (memcmp(&s[i], "\\x2f", 4) == 0) {
+                       s[j] = '/';
+                       i += 4;
+               } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
+                       s[j] = '\\';
+                       i += 4;
+               } else {
+                       s[j] = s[i];
+                       i++;
+               }
+       }
+       s[j] = '\0';
+       return j;
+}
+
+void util_remove_trailing_chars(char *path, char c)
+{
+       size_t len;
+
+       if (path == NULL)
+               return;
+       len = strlen(path);
+       while (len > 0 && path[len-1] == c)
+               path[--len] = '\0';
+}
+
+/*
+ * Concatenates strings. In any case, terminates in _all_ cases with '\0'
+ * and moves the @dest pointer forward to the added '\0'. Returns the
+ * remaining size, and 0 if the string was truncated.
+ */
+size_t util_strpcpy(char **dest, size_t size, const char *src)
+{
+       size_t len;
+
+       len = strlen(src);
+       if (len >= size) {
+               if (size > 1)
+                       *dest = mempcpy(*dest, src, size-1);
+               size = 0;
+               *dest[0] = '\0';
+       } else {
+               if (len > 0) {
+                       *dest = mempcpy(*dest, src, len);
+                       size -= len;
+               }
+               *dest[0] = '\0';
+       }
+       return size;
+}
+
+/* concatenates list of strings, moves dest forward */
+size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
+{
+       va_list va;
+
+       va_start(va, src);
+       do {
+               size = util_strpcpy(dest, size, src);
+               src = va_arg(va, char *);
+       } while (src != NULL);
+       va_end(va);
+
+       return size;
+}
+
+/* copies string */
+size_t util_strscpy(char *dest, size_t size, const char *src)
+{
+       char *s;
+
+       s = dest;
+       return util_strpcpy(&s, size, src);
+}
+
+/* concatenates list of strings */
+size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
+{
+       va_list va;
+       char *s;
+
+       va_start(va, src);
+       s = dest;
+       do {
+               size = util_strpcpy(&s, size, src);
+               src = va_arg(va, char *);
+       } while (src != NULL);
+       va_end(va);
+
+       return size;
+}
+
+/* count of characters used to encode one unicode char */
+static int utf8_encoded_expected_len(const char *str)
+{
+       unsigned char c = (unsigned char)str[0];
+
+       if (c < 0x80)
+               return 1;
+       if ((c & 0xe0) == 0xc0)
+               return 2;
+       if ((c & 0xf0) == 0xe0)
+               return 3;
+       if ((c & 0xf8) == 0xf0)
+               return 4;
+       if ((c & 0xfc) == 0xf8)
+               return 5;
+       if ((c & 0xfe) == 0xfc)
+               return 6;
+       return 0;
+}
+
+/* decode one unicode char */
+static int utf8_encoded_to_unichar(const char *str)
+{
+       int unichar;
+       int len;
+       int i;
+
+       len = utf8_encoded_expected_len(str);
+       switch (len) {
+       case 1:
+               return (int)str[0];
+       case 2:
+               unichar = str[0] & 0x1f;
+               break;
+       case 3:
+               unichar = (int)str[0] & 0x0f;
+               break;
+       case 4:
+               unichar = (int)str[0] & 0x07;
+               break;
+       case 5:
+               unichar = (int)str[0] & 0x03;
+               break;
+       case 6:
+               unichar = (int)str[0] & 0x01;
+               break;
+       default:
+               return -1;
+       }
+
+       for (i = 1; i < len; i++) {
+               if (((int)str[i] & 0xc0) != 0x80)
+                       return -1;
+               unichar <<= 6;
+               unichar |= (int)str[i] & 0x3f;
+       }
+
+       return unichar;
+}
+
+/* expected size used to encode one unicode char */
+static int utf8_unichar_to_encoded_len(int unichar)
+{
+       if (unichar < 0x80)
+               return 1;
+       if (unichar < 0x800)
+               return 2;
+       if (unichar < 0x10000)
+               return 3;
+       if (unichar < 0x200000)
+               return 4;
+       if (unichar < 0x4000000)
+               return 5;
+       return 6;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+       if (unichar > 0x10ffff)
+               return 0;
+       if ((unichar & 0xfffff800) == 0xd800)
+               return 0;
+       if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+               return 0;
+       if ((unichar & 0xffff) == 0xffff)
+               return 0;
+       return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+static int utf8_encoded_valid_unichar(const char *str)
+{
+       int len;
+       int unichar;
+       int i;
+
+       len = utf8_encoded_expected_len(str);
+       if (len == 0)
+               return -1;
+
+       /* ascii is valid */
+       if (len == 1)
+               return 1;
+
+       /* check if expected encoded chars are available */
+       for (i = 0; i < len; i++)
+               if ((str[i] & 0x80) != 0x80)
+                       return -1;
+
+       unichar = utf8_encoded_to_unichar(str);
+
+       /* check if encoded length matches encoded value */
+       if (utf8_unichar_to_encoded_len(unichar) != len)
+               return -1;
+
+       /* check if value has valid range */
+       if (!utf8_unichar_valid_range(unichar))
+               return -1;
+
+       return len;
+}
+
+int udev_util_replace_whitespace(const char *str, char *to, size_t len)
+{
+       size_t i, j;
+
+       /* strip trailing whitespace */
+       len = strnlen(str, len);
+       while (len && isspace(str[len-1]))
+               len--;
+
+       /* strip leading whitespace */
+       i = 0;
+       while (isspace(str[i]) && (i < len))
+               i++;
+
+       j = 0;
+       while (i < len) {
+               /* substitute multiple whitespace with a single '_' */
+               if (isspace(str[i])) {
+                       while (isspace(str[i]))
+                               i++;
+                       to[j++] = '_';
+               }
+               to[j++] = str[i++];
+       }
+       to[j] = '\0';
+       return 0;
+}
+
+static int is_whitelisted(char c, const char *white)
+{
+       if ((c >= '0' && c <= '9') ||
+           (c >= 'A' && c <= 'Z') ||
+           (c >= 'a' && c <= 'z') ||
+           strchr("#+-.:=@_", c) != NULL ||
+           (white != NULL && strchr(white, c) != NULL))
+               return 1;
+       return 0;
+}
+
+/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
+int udev_util_replace_chars(char *str, const char *white)
+{
+       size_t i = 0;
+       int replaced = 0;
+
+       while (str[i] != '\0') {
+               int len;
+
+               if (is_whitelisted(str[i], white)) {
+                       i++;
+                       continue;
+               }
+
+               /* accept hex encoding */
+               if (str[i] == '\\' && str[i+1] == 'x') {
+                       i += 2;
+                       continue;
+               }
+
+               /* accept valid utf8 */
+               len = utf8_encoded_valid_unichar(&str[i]);
+               if (len > 1) {
+                       i += len;
+                       continue;
+               }
+
+               /* if space is allowed, replace whitespace with ordinary space */
+               if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
+                       str[i] = ' ';
+                       i++;
+                       replaced++;
+                       continue;
+               }
+
+               /* everything else is replaced with '_' */
+               str[i] = '_';
+               i++;
+               replaced++;
+       }
+       return replaced;
+}
+
+/**
+ * util_encode_string:
+ * @str: input string to be encoded
+ * @str_enc: output string to store the encoded input string
+ * @len: maximum size of the output string, which may be
+ *       four times as long as the input string
+ *
+ * Encode all potentially unsafe characters of a string to the
+ * corresponding hex value prefixed by '\x'.
+ *
+ * Returns: 0 if the entire string was copied, non-zero otherwise.
+ **/
+int udev_util_encode_string(const char *str, char *str_enc, size_t len)
+{
+       size_t i, j;
+
+       if (str == NULL || str_enc == NULL || len == 0)
+               return -1;
+
+       str_enc[0] = '\0';
+       for (i = 0, j = 0; str[i] != '\0'; i++) {
+               int seqlen;
+
+               seqlen = utf8_encoded_valid_unichar(&str[i]);
+               if (seqlen > 1) {
+                       memcpy(&str_enc[j], &str[i], seqlen);
+                       j += seqlen;
+                       i += (seqlen-1);
+               } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
+                       sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
+                       j += 4;
+               } else {
+                       str_enc[j] = str[i];
+                       j++;
+               }
+               if (j+3 >= len)
+                       goto err;
+       }
+       str_enc[j] = '\0';
+       return 0;
+err:
+       return -1;
+}
+
+void util_set_fd_cloexec(int fd)
+{
+       int flags;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags < 0)
+               flags = FD_CLOEXEC;
+       else
+               flags |= FD_CLOEXEC;
+       fcntl(fd, F_SETFD, flags);
+}
+
+unsigned int util_string_hash32(const char *str)
+{
+       unsigned int hash = 0;
+
+       while (str[0] != '\0') {
+               hash += str[0] << 4;
+               hash += str[0] >> 4;
+               hash *= 11;
+               str++;
+       }
+       return hash;
+}
diff --git a/libudev/libudev.c b/libudev/libudev.c
new file mode 100644 (file)
index 0000000..a9baa70
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "libudev.h"
+#include "libudev-private.h"
+
+struct udev {
+       int refcount;
+       void (*log_fn)(struct udev *udev,
+                      int priority, const char *file, int line, const char *fn,
+                      const char *format, va_list args);
+       void *userdata;
+       char *sys_path;
+       char *dev_path;
+       char *rules_path;
+       struct udev_list_node properties_list;
+       int log_priority;
+       int run;
+};
+
+void udev_log(struct udev *udev,
+             int priority, const char *file, int line, const char *fn,
+             const char *format, ...)
+{
+       va_list args;
+
+       if (priority > udev->log_priority)
+               return;
+
+       va_start(args, format);
+       udev->log_fn(udev, priority, file, line, fn, format, args);
+       va_end(args);
+}
+
+static void log_stderr(struct udev *udev,
+                      int priority, const char *file, int line, const char *fn,
+                      const char *format, va_list args)
+{
+       fprintf(stderr, "libudev: %s: ", fn);
+       vfprintf(stderr, format, args);
+}
+
+void *udev_get_userdata(struct udev *udev)
+{
+       if (udev == NULL)
+               return NULL;
+       return udev->userdata;
+}
+
+void udev_set_userdata(struct udev *udev, void *userdata)
+{
+       if (udev == NULL)
+               return;
+       udev->userdata = userdata;
+}
+
+/**
+ * udev_new:
+ *
+ * Create udev library context.
+ *
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the udev library context.
+ *
+ * Returns: a new udev library context
+ **/
+struct udev *udev_new(void)
+{
+       struct udev *udev;
+       const char *env;
+       char *config_file;
+       FILE *f;
+
+       udev = calloc(1, sizeof(struct udev));
+       if (udev == NULL)
+               return NULL;
+       udev->refcount = 1;
+       udev->log_fn = log_stderr;
+       udev->log_priority = LOG_ERR;
+       udev_list_init(&udev->properties_list);
+       udev->run = 1;
+       udev->dev_path = strdup(UDEV_PREFIX "/dev");
+       udev->sys_path = strdup("/sys");
+       config_file = strdup(SYSCONFDIR "/udev/udev.conf");
+       if (udev->dev_path == NULL ||
+           udev->sys_path == NULL ||
+           config_file == NULL)
+               goto err;
+
+       /* settings by environment and config file */
+       env = getenv("SYSFS_PATH");
+       if (env != NULL) {
+               free(udev->sys_path);
+               udev->sys_path = strdup(env);
+               util_remove_trailing_chars(udev->sys_path, '/');
+               udev_add_property(udev, "SYSFS_PATH", udev->sys_path);
+       }
+
+       env = getenv("UDEV_RUN");
+       if (env != NULL && strcmp(env, "0") == 0)
+               udev->run = 0;
+
+       env = getenv("UDEV_CONFIG_FILE");
+       if (env != NULL) {
+               free(config_file);
+               config_file = strdup(env);
+               util_remove_trailing_chars(config_file, '/');
+       }
+       if (config_file == NULL)
+               goto err;
+       f = fopen(config_file, "r");
+       if (f != NULL) {
+               char line[UTIL_LINE_SIZE];
+               int line_nr = 0;
+
+               while (fgets(line, sizeof(line), f)) {
+                       size_t len;
+                       char *key;
+                       char *val;
+
+                       line_nr++;
+
+                       /* find key */
+                       key = line;
+                       while (isspace(key[0]))
+                               key++;
+
+                       /* comment or empty line */
+                       if (key[0] == '#' || key[0] == '\0')
+                               continue;
+
+                       /* split key/value */
+                       val = strchr(key, '=');
+                       if (val == NULL) {
+                               err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, line_nr);
+                               continue;
+                       }
+                       val[0] = '\0';
+                       val++;
+
+                       /* find value */
+                       while (isspace(val[0]))
+                               val++;
+
+                       /* terminate key */
+                       len = strlen(key);
+                       if (len == 0)
+                               continue;
+                       while (isspace(key[len-1]))
+                               len--;
+                       key[len] = '\0';
+
+                       /* terminate value */
+                       len = strlen(val);
+                       if (len == 0)
+                               continue;
+                       while (isspace(val[len-1]))
+                               len--;
+                       val[len] = '\0';
+
+                       if (len == 0)
+                               continue;
+
+                       /* unquote */
+                       if (val[0] == '"' || val[0] == '\'') {
+                               if (val[len-1] != val[0]) {
+                                       err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
+                                       continue;
+                               }
+                               val[len-1] = '\0';
+                               val++;
+                       }
+
+                       if (strcmp(key, "udev_log") == 0) {
+                               udev_set_log_priority(udev, util_log_priority(val));
+                               continue;
+                       }
+                       if (strcmp(key, "udev_root") == 0) {
+                               free(udev->dev_path);
+                               udev->dev_path = strdup(val);
+                               util_remove_trailing_chars(udev->dev_path, '/');
+                               continue;
+                       }
+                       if (strcmp(key, "udev_rules") == 0) {
+                               free(udev->rules_path);
+                               udev->rules_path = strdup(val);
+                               util_remove_trailing_chars(udev->rules_path, '/');
+                               continue;
+                       }
+               }
+               fclose(f);
+       }
+
+       env = getenv("UDEV_ROOT");
+       if (env != NULL) {
+               free(udev->dev_path);
+               udev->dev_path = strdup(env);
+               util_remove_trailing_chars(udev->dev_path, '/');
+               udev_add_property(udev, "UDEV_ROOT", udev->dev_path);
+       }
+
+       env = getenv("UDEV_LOG");
+       if (env != NULL)
+               udev_set_log_priority(udev, util_log_priority(env));
+
+       if (udev->dev_path == NULL || udev->sys_path == NULL)
+               goto err;
+       dbg(udev, "context %p created\n", udev);
+       dbg(udev, "log_priority=%d\n", udev->log_priority);
+       dbg(udev, "config_file='%s'\n", config_file);
+       dbg(udev, "dev_path='%s'\n", udev->dev_path);
+       dbg(udev, "sys_path='%s'\n", udev->sys_path);
+       if (udev->rules_path != NULL)
+               dbg(udev, "rules_path='%s'\n", udev->rules_path);
+       free(config_file);
+       return udev;
+err:
+       free(config_file);
+       err(udev, "context creation failed\n");
+       udev_unref(udev);
+       return NULL;
+}
+
+/**
+ * udev_ref:
+ * @udev: udev library context
+ *
+ * Take a reference of the udev library context.
+ *
+ * Returns: the passed udev library context
+ **/
+struct udev *udev_ref(struct udev *udev)
+{
+       if (udev == NULL)
+               return NULL;
+       udev->refcount++;
+       return udev;
+}
+
+/**
+ * udev_unref:
+ * @udev: udev library context
+ *
+ * Drop a reference of the udev library context. If the refcount
+ * reaches zero, the resources of the context will be released.
+ *
+ **/
+void udev_unref(struct udev *udev)
+{
+       if (udev == NULL)
+               return;
+       udev->refcount--;
+       if (udev->refcount > 0)
+               return;
+       udev_list_cleanup_entries(udev, &udev->properties_list);
+       free(udev->dev_path);
+       free(udev->sys_path);
+       free(udev->rules_path);
+       dbg(udev, "context %p released\n", udev);
+       free(udev);
+}
+
+/**
+ * udev_set_log_fn:
+ * @udev: udev library context
+ * @log_fn: function to be called for logging messages
+ *
+ * The built-in logging writes to stderr. It can be
+ * overridden by a custom function, to plug log messages
+ * into the users' logging functionality.
+ *
+ **/
+void udev_set_log_fn(struct udev *udev,
+                    void (*log_fn)(struct udev *udev,
+                                   int priority, const char *file, int line, const char *fn,
+                                   const char *format, va_list args))
+{
+       udev->log_fn = log_fn;
+       info(udev, "custom logging function %p registered\n", udev);
+}
+
+int udev_get_log_priority(struct udev *udev)
+{
+       return udev->log_priority;
+}
+
+void udev_set_log_priority(struct udev *udev, int priority)
+{
+       char num[32];
+
+       udev->log_priority = priority;
+       snprintf(num, sizeof(num), "%u", udev->log_priority);
+       udev_add_property(udev, "UDEV_LOG", num);
+}
+
+const char *udev_get_rules_path(struct udev *udev)
+{
+       return udev->rules_path;
+}
+
+int udev_get_run(struct udev *udev)
+{
+       return udev->run;
+}
+
+/**
+ * udev_get_sys_path:
+ * @udev: udev library context
+ *
+ * Retrieve the sysfs mount point. The default is "/sys". For
+ * testing purposes, it can be overridden with the environment
+ * variable SYSFS_PATH.
+ *
+ * Returns: the sys mount point
+ **/
+const char *udev_get_sys_path(struct udev *udev)
+{
+       if (udev == NULL)
+               return NULL;
+       return udev->sys_path;
+}
+
+/**
+ * udev_get_dev_path:
+ * @udev: udev library context
+ *
+ * Retrieve the device directory path. The default value is "/dev",
+ * the actual value may be overridden in the udev configuration
+ * file.
+ *
+ * Returns: the device directory path
+ **/
+const char *udev_get_dev_path(struct udev *udev)
+{
+       if (udev == NULL)
+               return NULL;
+       return udev->dev_path;
+}
+
+struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
+{
+       if (value == NULL) {
+               struct udev_list_entry *list_entry;
+
+               list_entry = udev_get_properties_list_entry(udev);
+               list_entry = udev_list_entry_get_by_name(list_entry, key);
+               if (list_entry != NULL)
+                       udev_list_entry_delete(list_entry);
+               return NULL;
+       }
+       return udev_list_entry_add(udev, &udev->properties_list, key, value, 1, 0);
+}
+
+struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
+{
+       return udev_list_get_entry(&udev->properties_list);
+}
diff --git a/libudev/libudev.h b/libudev/libudev.h
new file mode 100644 (file)
index 0000000..ffeb80f
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * libudev - interface to udev device information
+ *
+ * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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.
+ */
+
+#ifndef _LIBUDEV_H_
+#define _LIBUDEV_H_
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*
+ * udev - library context
+ * 
+ * reads the udev config and system environment
+ * allows custom logging
+ */
+struct udev;
+struct udev *udev_ref(struct udev *udev);
+void udev_unref(struct udev *udev);
+struct udev *udev_new(void);
+void udev_set_log_fn(struct udev *udev,
+                           void (*log_fn)(struct udev *udev,
+                                          int priority, const char *file, int line, const char *fn,
+                                          const char *format, va_list args));
+int udev_get_log_priority(struct udev *udev);
+void udev_set_log_priority(struct udev *udev, int priority);
+const char *udev_get_sys_path(struct udev *udev);
+const char *udev_get_dev_path(struct udev *udev);
+void *udev_get_userdata(struct udev *udev);
+void udev_set_userdata(struct udev *udev, void *userdata);
+
+/*
+ * udev_list
+ *
+ * access to libudev generated lists
+ */
+struct udev_list_entry;
+struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
+struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
+const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
+const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
+#define udev_list_entry_foreach(entry, first) \
+       for (entry = first; \
+            entry != NULL; \
+            entry = udev_list_entry_get_next(entry))
+
+/*
+ * udev_device
+ *
+ * access to sysfs/kernel devices
+ */
+struct udev_device;
+struct udev_device *udev_device_ref(struct udev_device *udev_device);
+void udev_device_unref(struct udev_device *udev_device);
+struct udev *udev_device_get_udev(struct udev_device *udev_device);
+struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
+struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
+struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
+/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
+struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
+struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
+                                                                 const char *subsystem, const char *devtype);
+/* retrieve device properties */
+const char *udev_device_get_devpath(struct udev_device *udev_device);
+const char *udev_device_get_subsystem(struct udev_device *udev_device);
+const char *udev_device_get_devtype(struct udev_device *udev_device);
+const char *udev_device_get_syspath(struct udev_device *udev_device);
+const char *udev_device_get_sysname(struct udev_device *udev_device);
+const char *udev_device_get_sysnum(struct udev_device *udev_device);
+const char *udev_device_get_devnode(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
+struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
+const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
+const char *udev_device_get_driver(struct udev_device *udev_device);
+dev_t udev_device_get_devnum(struct udev_device *udev_device);
+const char *udev_device_get_action(struct udev_device *udev_device);
+unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
+const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
+
+/*
+ * udev_monitor
+ *
+ * access to kernel uevents and udev events
+ */
+struct udev_monitor;
+struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
+void udev_monitor_unref(struct udev_monitor *udev_monitor);
+struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
+/* kernel and udev generated events over netlink */
+struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
+/* custom socket (use netlink and filters instead) */
+struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
+/* bind socket */
+int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
+int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
+struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
+/* in-kernel socket filters to select messages that get delivered to a listener */
+int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
+                                                   const char *subsystem, const char *devtype);
+int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
+int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
+
+/*
+ * udev_enumerate
+ *
+ * search sysfs for specific devices and provide a sorted list
+ */
+struct udev_enumerate;
+struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
+void udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
+struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
+struct udev_enumerate *udev_enumerate_new(struct udev *udev);
+/* device properties filter */
+int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
+int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
+int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
+int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
+/* run enumeration with active filters */
+int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
+int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
+/* return device list */
+struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
+
+/*
+ * udev_queue
+ *
+ * access to the currently running udev events
+ */
+struct udev_queue;
+struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
+void udev_queue_unref(struct udev_queue *udev_queue);
+struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
+struct udev_queue *udev_queue_new(struct udev *udev);
+unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
+unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
+int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
+int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
+int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
+int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
+                                              unsigned long long int start, unsigned long long int end);
+struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
+struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
+#endif
diff --git a/libudev/libudev.pc.in b/libudev/libudev.pc.in
new file mode 100644 (file)
index 0000000..38fc052
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@prefix@
+libdir=@prefix@/@libdir_name@
+includedir=@prefix@/include
+
+Name: libudev
+Description: Library to access udev device information
+Version: @VERSION@
+Libs: -L${libdir} -ludev
+Libs.private: 
+Cflags: -I${includedir}
diff --git a/libudev/test-libudev.c b/libudev/test-libudev.c
new file mode 100644 (file)
index 0000000..db08d48
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * test-libudev
+ *
+ * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * 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>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/select.h>
+
+#include "libudev.h"
+
+static void log_fn(struct udev *udev,
+                  int priority, const char *file, int line, const char *fn,
+                  const char *format, va_list args)
+{
+       printf("test-libudev: %s %s:%d ", fn, file, line);
+       vprintf(format, args);
+}
+
+static void print_device(struct udev_device *device)
+{
+       const char *str;
+       dev_t devnum;
+       int count;
+       struct udev_list_entry *list_entry;
+
+       printf("*** device: %p ***\n", device);
+       str = udev_device_get_action(device);
+       if (str != NULL)
+               printf("action:    '%s'\n", str);
+
+       str = udev_device_get_syspath(device);
+       printf("syspath:   '%s'\n", str);
+
+       str = udev_device_get_sysname(device);
+       printf("sysname:   '%s'\n", str);
+
+       str = udev_device_get_sysnum(device);
+       if (str != NULL)
+               printf("sysnum:    '%s'\n", str);
+
+       str = udev_device_get_devpath(device);
+       printf("devpath:   '%s'\n", str);
+
+       str = udev_device_get_subsystem(device);
+       if (str != NULL)
+               printf("subsystem: '%s'\n", str);
+
+       str = udev_device_get_devtype(device);
+       if (str != NULL)
+               printf("devtype:   '%s'\n", str);
+
+       str = udev_device_get_driver(device);
+       if (str != NULL)
+               printf("driver:    '%s'\n", str);
+
+       str = udev_device_get_devnode(device);
+       if (str != NULL)
+               printf("devname:   '%s'\n", str);
+
+       devnum = udev_device_get_devnum(device);
+       if (major(devnum) > 0)
+               printf("devnum:    %u:%u\n", major(devnum), minor(devnum));
+
+       count = 0;
+       udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
+               printf("link:      '%s'\n", udev_list_entry_get_name(list_entry));
+               count++;
+       }
+       if (count > 0)
+               printf("found %i links\n", count);
+
+       count = 0;
+       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
+               printf("property:  '%s=%s'\n",
+                      udev_list_entry_get_name(list_entry),
+                      udev_list_entry_get_value(list_entry));
+               count++;
+       }
+       if (count > 0)
+               printf("found %i properties\n", count);
+
+       str = udev_device_get_property_value(device, "MAJOR");
+       if (str != NULL)
+               printf("MAJOR: '%s'\n", str);
+
+       str = udev_device_get_sysattr_value(device, "dev");
+       if (str != NULL)
+               printf("attr{dev}: '%s'\n", str);
+
+       printf("\n");
+}
+
+static int test_device(struct udev *udev, const char *syspath)
+{
+       struct udev_device *device;
+
+       printf("looking at device: %s\n", syspath);
+       device = udev_device_new_from_syspath(udev, syspath);
+       if (device == NULL) {
+               printf("no device found\n");
+               return -1;
+       }
+       print_device(device);
+       udev_device_unref(device);
+       return 0;
+}
+
+static int test_device_parents(struct udev *udev, const char *syspath)
+{
+       struct udev_device *device;
+       struct udev_device *device_parent;
+
+       printf("looking at device: %s\n", syspath);
+       device = udev_device_new_from_syspath(udev, syspath);
+       if (device == NULL)
+               return -1;
+
+       printf("looking at parents\n");
+       device_parent = device;
+       do {
+               print_device(device_parent);
+               device_parent = udev_device_get_parent(device_parent);
+       } while (device_parent != NULL);
+
+       printf("looking at parents again\n");
+       device_parent = device;
+       do {
+               print_device(device_parent);
+               device_parent = udev_device_get_parent(device_parent);
+       } while (device_parent != NULL);
+       udev_device_unref(device);
+
+       return 0;
+}
+
+static int test_device_devnum(struct udev *udev)
+{
+       dev_t devnum = makedev(1, 3);
+       struct udev_device *device;
+
+       printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
+       device = udev_device_new_from_devnum(udev, 'c', devnum);
+       if (device == NULL)
+               return -1;
+       print_device(device);
+       udev_device_unref(device);
+       return 0;
+}
+
+static int test_device_subsys_name(struct udev *udev)
+{
+       struct udev_device *device;
+
+       printf("looking up device: 'block':'sda'\n");
+       device = udev_device_new_from_subsystem_sysname(udev, "block", "sda");
+       if (device == NULL)
+               return -1;
+       print_device(device);
+       udev_device_unref(device);
+
+       printf("looking up device: 'subsystem':'pci'\n");
+       device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
+       if (device == NULL)
+               return -1;
+       print_device(device);
+       udev_device_unref(device);
+
+       printf("looking up device: 'drivers':'scsi:sd'\n");
+       device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd");
+       if (device == NULL)
+               return -1;
+       print_device(device);
+       udev_device_unref(device);
+
+       printf("looking up device: 'module':'printk'\n");
+       device = udev_device_new_from_subsystem_sysname(udev, "module", "printk");
+       if (device == NULL)
+               return -1;
+       print_device(device);
+       udev_device_unref(device);
+       return 0;
+}
+
+static int test_enumerate_print_list(struct udev_enumerate *enumerate)
+{
+       struct udev_list_entry *list_entry;
+       int count = 0;
+
+       udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
+               struct udev_device *device;
+
+               device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
+                                                     udev_list_entry_get_name(list_entry));
+               if (device != NULL) {
+                       printf("device: '%s' (%s)\n",
+                              udev_device_get_syspath(device),
+                              udev_device_get_subsystem(device));
+                       udev_device_unref(device);
+                       count++;
+               }
+       }
+       printf("found %i devices\n\n", count);
+       return count;
+}
+
+static int test_monitor(struct udev *udev)
+{
+       struct udev_monitor *udev_monitor;
+       fd_set readfds;
+       int fd;
+
+       udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+       if (udev_monitor == NULL) {
+               printf("no socket\n");
+               return -1;
+       }
+       if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 ||
+           udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 ||
+           udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) {
+               printf("filter failed\n");
+               return -1;
+       }
+       if (udev_monitor_enable_receiving(udev_monitor) < 0) {
+               printf("bind failed\n");
+               return -1;
+       }
+
+       fd = udev_monitor_get_fd(udev_monitor);
+       FD_ZERO(&readfds);
+
+       while (1) {
+               struct udev_device *device;
+               int fdcount;
+
+               FD_SET(STDIN_FILENO, &readfds);
+               FD_SET(fd, &readfds);
+
+               printf("waiting for events from udev, press ENTER to exit\n");
+               fdcount = select(fd+1, &readfds, NULL, NULL, NULL);
+               printf("select fd count: %i\n", fdcount);
+
+               if (FD_ISSET(fd, &readfds)) {
+                       device = udev_monitor_receive_device(udev_monitor);
+                       if (device == NULL) {
+                               printf("no device from socket\n");
+                               continue;
+                       }
+                       print_device(device);
+                       udev_device_unref(device);
+               }
+
+               if (FD_ISSET(STDIN_FILENO, &readfds)) {
+                       printf("exiting loop\n");
+                       break;
+               }
+       }
+
+       udev_monitor_unref(udev_monitor);
+       return 0;
+}
+
+static int test_queue(struct udev *udev)
+{
+       struct udev_queue *udev_queue;
+       unsigned long long int seqnum;
+       struct udev_list_entry *list_entry;
+
+       udev_queue = udev_queue_new(udev);
+       if (udev_queue == NULL)
+               return -1;
+       seqnum = udev_queue_get_kernel_seqnum(udev_queue);
+       printf("seqnum kernel: %llu\n", seqnum);
+       seqnum = udev_queue_get_udev_seqnum(udev_queue);
+       printf("seqnum udev  : %llu\n", seqnum);
+
+       if (udev_queue_get_queue_is_empty(udev_queue))
+               printf("queue is empty\n");
+       printf("get queue list\n");
+       udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
+               printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+       printf("\n");
+       printf("get queue list again\n");
+       udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
+               printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+       printf("\n");
+       printf("get failed list\n");
+       udev_list_entry_foreach(list_entry, udev_queue_get_failed_list_entry(udev_queue))
+               printf("failed: '%s'\n", udev_list_entry_get_name(list_entry));
+       printf("\n");
+
+       list_entry = udev_queue_get_queued_list_entry(udev_queue);
+       if (list_entry != NULL) {
+               printf("event [%llu] is queued\n", seqnum);
+               seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10);
+               if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum))
+                       printf("event [%llu] is not finished\n", seqnum);
+               else
+                       printf("event [%llu] is finished\n", seqnum);
+       }
+       printf("\n");
+       udev_queue_unref(udev_queue);
+       return 0;
+}
+
+static int test_enumerate(struct udev *udev, const char *subsystem)
+{
+       struct udev_enumerate *udev_enumerate;
+
+       printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem);
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
+       udev_enumerate_scan_devices(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+
+       printf("enumerate 'block'\n");
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_add_match_subsystem(udev_enumerate,"block");
+       udev_enumerate_scan_devices(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+
+       printf("enumerate 'not block'\n");
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
+       udev_enumerate_scan_devices(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+
+       printf("enumerate 'pci, mem, vc'\n");
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_add_match_subsystem(udev_enumerate, "pci");
+       udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
+       udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
+       udev_enumerate_scan_devices(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+
+       printf("enumerate 'subsystem'\n");
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_scan_subsystems(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+
+       printf("enumerate 'property IF_FS_*=filesystem'\n");
+       udev_enumerate = udev_enumerate_new(udev);
+       if (udev_enumerate == NULL)
+               return -1;
+       udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
+       udev_enumerate_scan_devices(udev_enumerate);
+       test_enumerate_print_list(udev_enumerate);
+       udev_enumerate_unref(udev_enumerate);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       struct udev *udev = NULL;
+       static const struct option options[] = {
+               { "syspath", required_argument, NULL, 'p' },
+               { "subsystem", required_argument, NULL, 's' },
+               { "debug", no_argument, NULL, 'd' },
+               { "help", no_argument, NULL, 'h' },
+               { "version", no_argument, NULL, 'V' },
+               {}
+       };
+       const char *syspath = "/devices/virtual/mem/null";
+       const char *subsystem = NULL;
+       char path[1024];
+       const char *str;
+
+       udev = udev_new();
+       printf("context: %p\n", udev);
+       if (udev == NULL) {
+               printf("no context\n");
+               return 1;
+       }
+       udev_set_log_fn(udev, log_fn);
+       printf("set log: %p\n", log_fn);
+
+       while (1) {
+               int option;
+
+               option = getopt_long(argc, argv, "+dhV", options, NULL);
+               if (option == -1)
+                       break;
+
+               switch (option) {
+               case 'p':
+                       syspath = optarg;
+                       break;
+               case 's':
+                       subsystem = optarg;
+                       break;
+               case 'd':
+                       if (udev_get_log_priority(udev) < LOG_INFO)
+                               udev_set_log_priority(udev, LOG_INFO);
+                       break;
+               case 'h':
+                       printf("--debug --syspath= --subsystem= --help\n");
+                       goto out;
+               case 'V':
+                       printf("%s\n", VERSION);
+                       goto out;
+               default:
+                       goto out;
+               }
+       }
+
+       str = udev_get_sys_path(udev);
+       printf("sys_path: '%s'\n", str);
+       str = udev_get_dev_path(udev);
+       printf("dev_path: '%s'\n", str);
+
+       /* add sys path if needed */
+       if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
+               snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), syspath);
+               syspath = path;
+       }
+
+       test_device(udev, syspath);
+       test_device_devnum(udev);
+       test_device_subsys_name(udev);
+       test_device_parents(udev, syspath);
+
+       test_enumerate(udev, subsystem);
+
+       test_queue(udev);
+
+       test_monitor(udev);
+out:
+       udev_unref(udev);
+       return 0;
+}
index 94989e64bf57eac7ee7edb45a471641aa894c4ee..ca5b4fae593fc5c0cf16be478c2b225d133b356d 100644 (file)
@@ -1,8 +1,5 @@
 include $(top_srcdir)/Makefile.am.inc
 
-SUBDIRS = \
-       lib
-
 sbin_PROGRAMS = \
        udevd \
        udevadm
@@ -19,18 +16,18 @@ common_files = \
        udev-node.c \
        udev-rules.c \
        udev-util.c \
-       lib/libudev.h \
-       lib/libudev-private.h \
-       lib/libudev.c \
-       lib/libudev-list.c \
-       lib/libudev-util.c \
-       lib/libudev-device.c \
-       lib/libudev-device-db-write.c \
-       lib/libudev-monitor.c \
-       lib/libudev-enumerate.c \
-       lib/libudev-queue.c \
-       lib/libudev-queue-export.c \
-       lib/libudev-ctrl.c
+       ../libudev/libudev.h \
+       ../libudev/libudev-private.h \
+       ../libudev/libudev.c \
+       ../libudev/libudev-list.c \
+       ../libudev/libudev-util.c \
+       ../libudev/libudev-device.c \
+       ../libudev/libudev-device-db-write.c \
+       ../libudev/libudev-monitor.c \
+       ../libudev/libudev-enumerate.c \
+       ../libudev/libudev-queue.c \
+       ../libudev/libudev-queue-export.c \
+       ../libudev/libudev-ctrl.c
 
 if USE_SELINUX
 common_files += \
diff --git a/udev/lib/.gitignore b/udev/lib/.gitignore
deleted file mode 100644 (file)
index 74a5f1d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-test-libudev
-libudev.pc
-libudev.so*
-
diff --git a/udev/lib/Makefile.am b/udev/lib/Makefile.am
deleted file mode 100644 (file)
index 7cd8833..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-include $(top_srcdir)/Makefile.am.inc
-
-noinst_PROGRAMS = \
-       test-libudev
-
-test_libudev_SOURCES = \
-       test-libudev.c
-
-test_libudev_LDADD = \
-       libudev.la
-
-rootlibdir = $(exec_prefix)/$(libdir_name)
-rootlib_LTLIBRARIES = \
-       libudev.la
-
-include_HEADERS =\
-       libudev.h
-
-libudev_la_SOURCES =\
-       libudev-private.h \
-       libudev.c \
-       libudev-list.c \
-       libudev-util.c \
-       libudev-device.c \
-       libudev-enumerate.c \
-       libudev-monitor.c \
-       libudev-queue.c
-
-libudev_la_LDFLAGS = \
-       -version-info $(LIBUDEV_LT_CURRENT):$(LIBUDEV_LT_REVISION):$(LIBUDEV_LT_AGE) \
-       -export-symbols $(top_srcdir)/udev/lib/exported_symbols
-
-pkgconfigdir = $(prefix)/$(libdir_name)/pkgconfig
-pkgconfig_DATA = libudev.pc
-
-EXTRA_DIST = \
-       exported_symbols
-
-# move devel files to $(prefix)$(libdir_name) if needed
-install-data-hook:
-       rm  $(DESTDIR)$(rootlibdir)/libudev.la
-       if test "$(prefix)" != "$(exec_prefix)"; then \
-               mkdir -p $(DESTDIR)$(prefix)/$(libdir_name); \
-               mv $(DESTDIR)$(rootlibdir)/libudev.a $(DESTDIR)$(prefix)/$(libdir_name)/; \
-               so_img_name=$$(readlink $(DESTDIR)$(rootlibdir)/libudev.so); \
-               rm $(DESTDIR)$(rootlibdir)/libudev.so; \
-               so_img_rel_target_prefix=$$(echo $(prefix)/$(libdir_name) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \
-               ln -sf  $$so_img_rel_target_prefix$(exec_prefix)/$(libdir_name)/$$so_img_name \
-                       $(DESTDIR)$(prefix)/$(libdir_name)/libudev.so; \
-       fi
-
-uninstall-hook:
-       rm -f $(DESTDIR)$(prefix)/$(libdir_name)/libudev.a
-       rm -f $(DESTDIR)$(prefix)/$(libdir_name)/libudev.so*
diff --git a/udev/lib/exported_symbols b/udev/lib/exported_symbols
deleted file mode 100644 (file)
index 8e7749e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-udev_new
-udev_ref
-udev_unref
-udev_set_log_fn
-udev_get_log_priority
-udev_set_log_priority
-udev_get_userdata
-udev_set_userdata
-udev_get_sys_path
-udev_get_dev_path
-udev_list_entry_get_next
-udev_list_entry_get_by_name
-udev_list_entry_get_name
-udev_list_entry_get_value
-udev_device_new_from_syspath
-udev_device_new_from_devnum
-udev_device_new_from_subsystem_sysname
-udev_device_get_parent
-udev_device_get_parent_with_subsystem_devtype
-udev_device_ref
-udev_device_unref
-udev_device_get_udev
-udev_device_get_syspath
-udev_device_get_devpath
-udev_device_get_devnode
-udev_device_get_sysname
-udev_device_get_sysnum
-udev_device_get_subsystem
-udev_device_get_devtype
-udev_device_get_devlinks_list_entry
-udev_device_get_properties_list_entry
-udev_device_get_property_value
-udev_device_get_action
-udev_device_get_driver
-udev_device_get_devnum
-udev_device_get_seqnum
-udev_device_get_sysattr_value
-udev_enumerate_new
-udev_enumerate_ref
-udev_enumerate_unref
-udev_enumerate_get_udev
-udev_enumerate_get_list_entry
-udev_enumerate_add_match_subsystem
-udev_enumerate_add_nomatch_subsystem
-udev_enumerate_add_match_sysattr
-udev_enumerate_add_nomatch_sysattr
-udev_enumerate_add_match_property
-udev_enumerate_scan_devices
-udev_enumerate_scan_subsystems
-udev_enumerate_add_syspath
-udev_monitor_new_from_socket
-udev_monitor_new_from_netlink
-udev_monitor_enable_receiving
-udev_monitor_ref
-udev_monitor_unref
-udev_monitor_get_udev
-udev_monitor_get_fd
-udev_monitor_receive_device
-udev_monitor_filter_add_match_subsystem_devtype
-udev_monitor_filter_update
-udev_monitor_filter_remove
-udev_queue_new
-udev_queue_ref
-udev_queue_unref
-udev_queue_get_udev
-udev_queue_get_kernel_seqnum
-udev_queue_get_udev_seqnum
-udev_queue_get_udev_is_active
-udev_queue_get_queue_is_empty
-udev_queue_get_seqnum_is_finished
-udev_queue_get_seqnum_sequence_is_finished
-udev_queue_get_queued_list_entry
-udev_queue_get_failed_list_entry
diff --git a/udev/lib/libudev-ctrl.c b/udev/lib/libudev-ctrl.c
deleted file mode 100644 (file)
index e47b2b6..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-/* wire protocol magic must match */
-#define UDEV_CTRL_MAGIC                                0xdead1dea
-
-enum udev_ctrl_msg_type {
-       UDEV_CTRL_UNKNOWN,
-       UDEV_CTRL_SET_LOG_LEVEL,
-       UDEV_CTRL_STOP_EXEC_QUEUE,
-       UDEV_CTRL_START_EXEC_QUEUE,
-       UDEV_CTRL_RELOAD_RULES,
-       UDEV_CTRL_SET_ENV,
-       UDEV_CTRL_SET_MAX_CHILDS,
-       UDEV_CTRL_SET_MAX_CHILDS_RUNNING,
-       UDEV_CTRL_SETTLE,
-};
-
-struct udev_ctrl_msg_wire {
-       char version[16];
-       unsigned int magic;
-       enum udev_ctrl_msg_type type;
-       union {
-               int intval;
-               char buf[256];
-       };
-};
-
-struct udev_ctrl_msg {
-       int refcount;
-       struct udev_ctrl *uctrl;
-       struct udev_ctrl_msg_wire ctrl_msg_wire;
-       pid_t pid;
-};
-
-struct udev_ctrl {
-       int refcount;
-       struct udev *udev;
-       int sock;
-       struct sockaddr_un saddr;
-       socklen_t addrlen;
-};
-
-struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path)
-{
-       struct udev_ctrl *uctrl;
-
-       uctrl = calloc(1, sizeof(struct udev_ctrl));
-       if (uctrl == NULL)
-               return NULL;
-       uctrl->refcount = 1;
-       uctrl->udev = udev;
-
-       uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-       if (uctrl->sock < 0) {
-               err(udev, "error getting socket: %m\n");
-               udev_ctrl_unref(uctrl);
-               return NULL;
-       }
-
-       uctrl->saddr.sun_family = AF_LOCAL;
-       strcpy(uctrl->saddr.sun_path, socket_path);
-       uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
-       /* translate leading '@' to abstract namespace */
-       if (uctrl->saddr.sun_path[0] == '@')
-               uctrl->saddr.sun_path[0] = '\0';
-
-       return uctrl;
-}
-
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
-{
-       int err;
-       const int feature_on = 1;
-
-       err= bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
-       if (err < 0) {
-               err(uctrl->udev, "bind failed: %m\n");
-               return err;
-       }
-
-       /* enable receiving of the sender credentials */
-       setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on));
-       return 0;
-}
-
-struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
-{
-       return uctrl->udev;
-}
-
-struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
-{
-       if (uctrl == NULL)
-               return NULL;
-       uctrl->refcount++;
-       return uctrl;
-}
-
-void udev_ctrl_unref(struct udev_ctrl *uctrl)
-{
-       if (uctrl == NULL)
-               return;
-       uctrl->refcount--;
-       if (uctrl->refcount > 0)
-               return;
-       if (uctrl->sock >= 0)
-               close(uctrl->sock);
-       free(uctrl);
-}
-
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
-{
-       if (uctrl == NULL)
-               return -1;
-       return uctrl->sock;
-}
-
-static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf)
-{
-       struct udev_ctrl_msg_wire ctrl_msg_wire;
-       int err;
-
-       memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
-       strcpy(ctrl_msg_wire.version, "udev-" VERSION);
-       ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
-       ctrl_msg_wire.type = type;
-
-       if (buf != NULL)
-               util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
-       else
-               ctrl_msg_wire.intval = intval;
-
-       err = sendto(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0,
-                    (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
-       if (err == -1) {
-               err(uctrl->udev, "error sending message: %m\n");
-       }
-       return err;
-}
-
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
-}
-
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
-}
-
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
-}
-
-int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL);
-}
-
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
-}
-
-int udev_ctrl_send_set_max_childs(struct udev_ctrl *uctrl, int count)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_SET_MAX_CHILDS, count, NULL);
-}
-
-int udev_ctrl_send_settle(struct udev_ctrl *uctrl)
-{
-       return ctrl_send(uctrl, UDEV_CTRL_SETTLE, 0, NULL);
-}
-
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl)
-{
-       struct udev_ctrl_msg *uctrl_msg;
-       ssize_t size;
-       struct msghdr smsg;
-       struct cmsghdr *cmsg;
-       struct iovec iov;
-       struct ucred *cred;
-       char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
-
-       uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
-       if (uctrl_msg == NULL)
-               return NULL;
-       uctrl_msg->refcount = 1;
-       uctrl_msg->uctrl = uctrl;
-
-       iov.iov_base = &uctrl_msg->ctrl_msg_wire;
-       iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
-
-       memset(&smsg, 0x00, sizeof(struct msghdr));
-       smsg.msg_iov = &iov;
-       smsg.msg_iovlen = 1;
-       smsg.msg_control = cred_msg;
-       smsg.msg_controllen = sizeof(cred_msg);
-
-       size = recvmsg(uctrl->sock, &smsg, 0);
-       if (size <  0) {
-               err(uctrl->udev, "unable to receive user udevd message: %m\n");
-               goto err;
-       }
-       cmsg = CMSG_FIRSTHDR(&smsg);
-       cred = (struct ucred *) CMSG_DATA(cmsg);
-
-       if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-               err(uctrl->udev, "no sender credentials received, message ignored\n");
-               goto err;
-       }
-
-       if (cred->uid != 0) {
-               err(uctrl->udev, "sender uid=%i, message ignored\n", cred->uid);
-               goto err;
-       }
-
-       uctrl_msg->pid = cred->pid;
-
-       if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
-               err(uctrl->udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
-               goto err;
-       }
-
-       dbg(uctrl->udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
-       return uctrl_msg;
-err:
-       udev_ctrl_msg_unref(uctrl_msg);
-       return NULL;
-}
-
-struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg == NULL)
-               return NULL;
-       ctrl_msg->refcount++;
-       return ctrl_msg;
-}
-
-void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg == NULL)
-               return;
-       ctrl_msg->refcount--;
-       if (ctrl_msg->refcount > 0)
-               return;
-       dbg(ctrl_msg->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
-       free(ctrl_msg);
-}
-
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
-               return ctrl_msg->ctrl_msg_wire.intval;
-       return -1;
-}
-
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
-               return 1;
-       return -1;
-}
-
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
-               return 1;
-       return -1;
-}
-
-int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD_RULES)
-               return 1;
-       return -1;
-}
-
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
-               return ctrl_msg->ctrl_msg_wire.buf;
-       return NULL;
-}
-
-int udev_ctrl_get_set_max_childs(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_MAX_CHILDS)
-               return ctrl_msg->ctrl_msg_wire.intval;
-       return -1;
-}
-
-pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg)
-{
-       if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SETTLE)
-               return ctrl_msg->pid;
-       return -1;
-}
diff --git a/udev/lib/libudev-device-db-write.c b/udev/lib/libudev-device-db-write.c
deleted file mode 100644 (file)
index a8e66f7..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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 <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "udev.h"
-
-static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
-{
-       char *s;
-       size_t l;
-
-       s = filename;
-       l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
-       return util_path_encode(devpath, s, l);
-}
-
-int udev_device_update_db(struct udev_device *udev_device)
-{
-       struct udev *udev = udev_device_get_udev(udev_device);
-       char filename[UTIL_PATH_SIZE];
-       FILE *f;
-       char target[232]; /* on 64bit, tmpfs inlines up to 239 bytes */
-       size_t devlen = strlen(udev_get_dev_path(udev))+1;
-       char *s;
-       size_t l;
-       struct udev_list_entry *list_entry;
-       int ret;
-
-       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
-       util_create_path(udev, filename);
-       unlink(filename);
-
-       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
-               if (udev_list_entry_get_flag(list_entry))
-                       goto file;
-       if (udev_device_get_num_fake_partitions(udev_device) != 0)
-               goto file;
-       if (udev_device_get_ignore_remove(udev_device))
-               goto file;
-       if (udev_device_get_devlink_priority(udev_device) != 0)
-               goto file;
-       if (udev_device_get_event_timeout(udev_device) >= 0)
-               goto file;
-       if (udev_device_get_watch_handle(udev_device) >= 0)
-               goto file;
-       if (udev_device_get_devnode(udev_device) == NULL)
-               goto out;
-
-       /*
-        * if we have only the node and symlinks to store, try not to waste
-        * tmpfs memory -- store values, if they fit, in a symlink target
-        */
-       s = target;
-       l = util_strpcpy(&s, sizeof(target), &udev_device_get_devnode(udev_device)[devlen]);
-       udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) {
-               l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
-               if (l == 0) {
-                       info(udev, "size of links too large, create file\n");
-                       goto file;
-               }
-       }
-       info(udev, "create db link (%s)\n", target);
-       udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
-       ret = symlink(target, filename);
-       udev_selinux_resetfscreatecon(udev);
-       if (ret == 0)
-               goto out;
-file:
-       f = fopen(filename, "w");
-       if (f == NULL) {
-               err(udev, "unable to create db file '%s': %m\n", filename);
-               return -1;
-               }
-       info(udev, "created db file for '%s' in '%s'\n", udev_device_get_devpath(udev_device), filename);
-
-       if (udev_device_get_devnode(udev_device) != NULL) {
-               fprintf(f, "N:%s\n", &udev_device_get_devnode(udev_device)[devlen]);
-               udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device))
-                       fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]);
-       }
-       if (udev_device_get_devlink_priority(udev_device) != 0)
-               fprintf(f, "L:%u\n", udev_device_get_devlink_priority(udev_device));
-       if (udev_device_get_event_timeout(udev_device) >= 0)
-               fprintf(f, "T:%u\n", udev_device_get_event_timeout(udev_device));
-       if (udev_device_get_num_fake_partitions(udev_device) != 0)
-               fprintf(f, "A:%u\n", udev_device_get_num_fake_partitions(udev_device));
-       if (udev_device_get_ignore_remove(udev_device))
-               fprintf(f, "R:%u\n", udev_device_get_ignore_remove(udev_device));
-       if (udev_device_get_watch_handle(udev_device) >= 0)
-               fprintf(f, "W:%u\n", udev_device_get_watch_handle(udev_device));
-       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
-               if (!udev_list_entry_get_flag(list_entry))
-                       continue;
-               fprintf(f, "E:%s=%s\n",
-                       udev_list_entry_get_name(list_entry),
-                       udev_list_entry_get_value(list_entry));
-       }
-       fclose(f);
-out:
-       return 0;
-}
-
-int udev_device_delete_db(struct udev_device *udev_device)
-{
-       struct udev *udev = udev_device_get_udev(udev_device);
-       char filename[UTIL_PATH_SIZE];
-
-       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
-       unlink(filename);
-       return 0;
-}
-
-int udev_device_rename_db(struct udev_device *udev_device, const char *devpath_old)
-{
-       struct udev *udev = udev_device_get_udev(udev_device);
-       char filename_old[UTIL_PATH_SIZE];
-       char filename[UTIL_PATH_SIZE];
-
-       devpath_to_db_path(udev, devpath_old, filename_old, sizeof(filename_old));
-       devpath_to_db_path(udev, udev_device_get_devpath(udev_device), filename, sizeof(filename));
-       return rename(filename_old, filename);
-}
diff --git a/udev/lib/libudev-device.c b/udev/lib/libudev-device.c
deleted file mode 100644 (file)
index ea54bad..0000000
+++ /dev/null
@@ -1,1249 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <ctype.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-struct udev_device {
-       struct udev *udev;
-       struct udev_device *parent_device;
-       char *syspath;
-       const char *devpath;
-       char *sysname;
-       const char *sysnum;
-       char *devnode;
-       char *subsystem;
-       char *devtype;
-       char *driver;
-       char *action;
-       char *devpath_old;
-       char *knodename;
-       char **envp;
-       char *monitor_buf;
-       size_t monitor_buf_len;
-       struct udev_list_node devlinks_list;
-       struct udev_list_node properties_list;
-       struct udev_list_node sysattr_list;
-       unsigned long long int seqnum;
-       int event_timeout;
-       int timeout;
-       int num_fake_partitions;
-       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;
-       unsigned int info_loaded:1;
-       unsigned int ignore_remove:1;
-};
-
-static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
-{
-       char *s;
-       size_t l;
-
-       s = filename;
-       l = util_strpcpyl(&s, len, udev_get_dev_path(udev), "/.udev/db/", NULL);
-       return util_path_encode(devpath, s, l);
-}
-
-int udev_device_read_db(struct udev_device *udev_device)
-{
-       struct stat stats;
-       char filename[UTIL_PATH_SIZE];
-       char line[UTIL_LINE_SIZE];
-       FILE *f;
-
-       devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
-
-       if (lstat(filename, &stats) != 0) {
-               dbg(udev_device->udev, "no db file to read %s: %m\n", filename);
-               return -1;
-       }
-       if ((stats.st_mode & S_IFMT) == S_IFLNK) {
-               char target[UTIL_PATH_SIZE];
-               char devnode[UTIL_PATH_SIZE];
-               int target_len;
-               char *next;
-
-               target_len = readlink(filename, target, sizeof(target));
-               if (target_len > 0)
-                       target[target_len] = '\0';
-               else {
-                       dbg(udev_device->udev, "error reading db link %s: %m\n", filename);
-                       return -1;
-               }
-
-               next = strchr(target, ' ');
-               if (next != NULL) {
-                       next[0] = '\0';
-                       next = &next[1];
-               }
-               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];
-                       const char *lnk;
-
-                       lnk = next;
-                       next = strchr(next, ' ');
-                       if (next != NULL) {
-                               next[0] = '\0';
-                               next = &next[1];
-                       }
-                       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);
-               return 0;
-       }
-
-       f = fopen(filename, "r");
-       if (f == NULL) {
-               dbg(udev_device->udev, "error reading db file %s: %m\n", filename);
-               return -1;
-       }
-       while (fgets(line, sizeof(line), f)) {
-               ssize_t len;
-               const char *val;
-
-               len = strlen(line);
-               if (len < 4)
-                       break;
-               line[len-1] = '\0';
-               val = &line[2];
-               switch(line[0]) {
-               case 'N':
-                       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_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
-                       udev_device_add_devlink(udev_device, filename);
-                       break;
-               case 'L':
-                       udev_device_set_devlink_priority(udev_device, atoi(val));
-                       break;
-               case 'T':
-                       udev_device_set_event_timeout(udev_device, atoi(val));
-                       break;
-               case 'A':
-                       udev_device_set_num_fake_partitions(udev_device, atoi(val));
-                       break;
-               case 'R':
-                       udev_device_set_ignore_remove(udev_device, atoi(val));
-                       break;
-               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);
-
-       info(udev_device->udev, "device %p filled with db file data\n", udev_device);
-       return 0;
-}
-
-int udev_device_read_uevent_file(struct udev_device *udev_device)
-{
-       char filename[UTIL_PATH_SIZE];
-       FILE *f;
-       char line[UTIL_LINE_SIZE];
-       int maj = 0;
-       int min = 0;
-
-       util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
-       f = fopen(filename, "r");
-       if (f == NULL)
-               return -1;
-
-       while (fgets(line, sizeof(line), f)) {
-               char *pos;
-
-               pos = strchr(line, '\n');
-               if (pos == NULL)
-                       continue;
-               pos[0] = '\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);
-       }
-
-       udev_device->devnum = makedev(maj, min);
-
-       fclose(f);
-       return 0;
-}
-
-static void device_load_info(struct udev_device *device)
-{
-       device->info_loaded = 1;
-       udev_device_read_uevent_file(device);
-       udev_device_read_db(device);
-}
-
-void udev_device_set_info_loaded(struct udev_device *device)
-{
-       device->info_loaded = 1;
-}
-
-struct udev_device *device_new(struct udev *udev)
-{
-       struct udev_device *udev_device;
-       struct udev_list_entry *list_entry;
-
-       if (udev == NULL)
-               return NULL;
-
-       udev_device = calloc(1, sizeof(struct udev_device));
-       if (udev_device == NULL)
-               return NULL;
-       udev_device->refcount = 1;
-       udev_device->udev = udev;
-       udev_list_init(&udev_device->devlinks_list);
-       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,
-                                        udev_list_entry_get_name(list_entry),
-                                        udev_list_entry_get_value(list_entry));
-       dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
-       return udev_device;
-}
-
-/**
- * udev_device_new_from_syspath:
- * @udev: udev library context
- * @syspath: sys device path including sys directory
- *
- * Create new udev device, and fill in information from the sys
- * device and the udev database entry. The sypath is the absolute
- * path to the device, including the sys mount point.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev device.
- *
- * Returns: a new udev device, or #NULL, if it does not exist
- **/
-struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
-{
-       size_t len;
-       const char *subdir;
-       char path[UTIL_PATH_SIZE];
-       char *pos;
-       struct stat statbuf;
-       struct udev_device *udev_device;
-
-       if (udev == NULL)
-               return NULL;
-       if (syspath == NULL)
-               return NULL;
-
-       /* path starts in sys */
-       len = strlen(udev_get_sys_path(udev));
-       if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
-               info(udev, "not in sys :%s\n", syspath);
-               return NULL;
-       }
-
-       /* path is not a root directory */
-       subdir = &syspath[len+1];
-       pos = strrchr(subdir, '/');
-       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_strscpy(path, sizeof(path), syspath);
-       util_resolve_sys_link(udev, path, sizeof(path));
-
-       /* try to resolve the silly block layout if needed */
-       if (strncmp(&path[len], "/block/", 7) == 0) {
-               char block[UTIL_PATH_SIZE];
-               char part[UTIL_PATH_SIZE];
-
-               util_strscpy(block, sizeof(block), path);
-               pos = strrchr(block, '/');
-               if (pos == NULL)
-                       return NULL;
-               util_strscpy(part, sizeof(part), pos);
-               pos[0] = '\0';
-               if (util_resolve_sys_link(udev, block, sizeof(block)) == 0)
-                       util_strscpyl(path, sizeof(path), block, part, NULL);
-       }
-
-       /* path exists in sys */
-       if (strncmp(&syspath[len], "/devices/", 9) == 0 ||
-           strncmp(&syspath[len], "/class/", 7) == 0 ||
-           strncmp(&syspath[len], "/block/", 7) == 0) {
-               char file[UTIL_PATH_SIZE];
-
-               /* all "devices" require a "uevent" file */
-               util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
-               if (stat(file, &statbuf) != 0) {
-                       dbg(udev, "not a device: %s\n", syspath);
-                       return NULL;
-               }
-       } else {
-               /* everything else just needs to be a directory */
-               if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
-                       dbg(udev, "directory not found: %s\n", syspath);
-                       return NULL;
-               }
-       }
-
-       udev_device = device_new(udev);
-       if (udev_device == NULL)
-               return NULL;
-
-       udev_device_set_syspath(udev_device, path);
-       info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
-
-       return udev_device;
-}
-
-struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
-{
-       char path[UTIL_PATH_SIZE];
-       const char *type_str;
-       struct udev_enumerate *udev_enumerate;
-       struct udev_list_entry *list_entry;
-       struct udev_device *device = NULL;
-
-       if (type == 'b')
-               type_str = "block";
-       else if (type == 'c')
-               type_str = "char";
-       else
-               return NULL;
-
-       /* /sys/dev/{block,char}/<maj>:<min> link */
-       snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", udev_get_sys_path(udev),
-                type_str, major(devnum), minor(devnum));
-       if (util_resolve_sys_link(udev, path, sizeof(path)) == 0)
-               return udev_device_new_from_syspath(udev, path);
-
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return NULL;
-
-       /* fallback to search sys devices for the major/minor */
-       if (type == 'b')
-               udev_enumerate_add_match_subsystem(udev_enumerate, "block");
-       else if (type == 'c')
-               udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
-       udev_enumerate_scan_devices(udev_enumerate);
-       udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
-               struct udev_device *device_loop;
-
-               device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
-               if (device_loop != NULL) {
-                       if (udev_device_get_devnum(device_loop) == devnum) {
-                               if (type == 'b' && strcmp(udev_device_get_subsystem(device_loop), "block") != 0)
-                                       continue;
-                               if (type == 'c' && strcmp(udev_device_get_subsystem(device_loop), "block") == 0)
-                                       continue;
-                               device = device_loop;
-                               break;
-                       }
-                       udev_device_unref(device_loop);
-               }
-       }
-       udev_enumerate_unref(udev_enumerate);
-       return device;
-}
-
-struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
-{
-       char path_full[UTIL_PATH_SIZE];
-       char *path;
-       size_t l;
-       struct stat statbuf;
-
-       path = path_full;
-       l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
-
-       if (strcmp(subsystem, "subsystem") == 0) {
-               util_strscpyl(path, l, "/subsystem/", sysname, NULL);
-               if (stat(path_full, &statbuf) == 0)
-                       goto found;
-
-               util_strscpyl(path, l, "/bus/", sysname, NULL);
-               if (stat(path_full, &statbuf) == 0)
-                       goto found;
-
-               util_strscpyl(path, l, "/class/", sysname, NULL);
-               if (stat(path_full, &statbuf) == 0)
-                       goto found;
-               goto out;
-       }
-
-       if (strcmp(subsystem, "module") == 0) {
-               util_strscpyl(path, l, "/module/", sysname, NULL);
-               if (stat(path_full, &statbuf) == 0)
-                       goto found;
-               goto out;
-       }
-
-       if (strcmp(subsystem, "drivers") == 0) {
-               char subsys[UTIL_NAME_SIZE];
-               char *driver;
-
-               util_strscpy(subsys, sizeof(subsys), sysname);
-               driver = strchr(subsys, ':');
-               if (driver != NULL) {
-                       driver[0] = '\0';
-                       driver = &driver[1];
-
-                       util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
-                       if (stat(path_full, &statbuf) == 0)
-                               goto found;
-
-                       util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
-                       if (stat(path_full, &statbuf) == 0)
-                               goto found;
-               }
-               goto out;
-       }
-
-       util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
-       if (stat(path_full, &statbuf) == 0)
-               goto found;
-
-       util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
-       if (stat(path_full, &statbuf) == 0)
-               goto found;
-
-       util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
-       if (stat(path_full, &statbuf) == 0)
-               goto found;
-out:
-       return NULL;
-found:
-       return udev_device_new_from_syspath(udev, path_full);
-}
-
-static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
-{
-       struct udev_device *udev_device_parent = NULL;
-       char path[UTIL_PATH_SIZE];
-       const char *subdir;
-
-       /* follow "device" link in deprecated sys layout */
-       if (strncmp(udev_device->devpath, "/class/", 7) == 0 ||
-           strncmp(udev_device->devpath, "/block/", 7) == 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);
-                       if (udev_device_parent != NULL)
-                               return udev_device_parent;
-               }
-       }
-
-       util_strscpy(path, sizeof(path), udev_device->syspath);
-       subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
-       while (1) {
-               char *pos;
-
-               pos = strrchr(subdir, '/');
-               if (pos == NULL || pos < &subdir[2])
-                       break;
-               pos[0] = '\0';
-               udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
-               if (udev_device_parent != NULL)
-                       return udev_device_parent;
-       }
-       return NULL;
-}
-
-struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->parent_set) {
-               udev_device->parent_set = 1;
-               udev_device->parent_device = device_new_from_parent(udev_device);
-       }
-       if (udev_device->parent_device != NULL)
-               dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
-       return udev_device->parent_device;
-}
-
-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) {
-                       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;
-}
-
-/**
- * udev_device_get_udev:
- * @udev_device: udev device
- *
- * Retrieve the udev library context the device was created with.
- *
- * Returns: the udev library context
- **/
-struct udev *udev_device_get_udev(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->udev;
-}
-
-/**
- * udev_device_ref:
- * @udev_device: udev device
- *
- * Take a reference of a udev device.
- *
- * Returns: the passed udev device
- **/
-struct udev_device *udev_device_ref(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       udev_device->refcount++;
-       return udev_device;
-}
-
-/**
- * udev_device_unref:
- * @udev_device: udev device
- *
- * Drop a reference of a udev device. If the refcount reaches zero,
- * the resources of the device will be released.
- *
- **/
-void udev_device_unref(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return;
-       udev_device->refcount--;
-       if (udev_device->refcount > 0)
-               return;
-       if (udev_device->parent_device != NULL)
-               udev_device_unref(udev_device->parent_device);
-       free(udev_device->syspath);
-       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->knodename);
-       udev_list_cleanup_entries(udev_device->udev, &udev_device->sysattr_list);
-       free(udev_device->envp);
-       free(udev_device->monitor_buf);
-       dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
-       free(udev_device);
-}
-
-/**
- * udev_device_get_devpath:
- * @udev_device: udev device
- *
- * Retrieve the kernel devpath value of the udev device. The path
- * does not contain the sys mount point, and starts with a '/'.
- *
- * Returns: the devpath of the udev device
- **/
-const char *udev_device_get_devpath(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->devpath;
-}
-
-/**
- * udev_device_get_syspath:
- * @udev_device: udev device
- *
- * Retrieve the sys path of the udev device. The path is an
- * absolute path and starts with the sys mount point.
- *
- * Returns: the sys path of the udev device
- **/
-const char *udev_device_get_syspath(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->syspath;
-}
-
-const char *udev_device_get_sysname(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->sysname;
-}
-
-const char *udev_device_get_sysnum(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->sysnum;
-}
-
-/**
- * udev_device_get_devnode:
- * @udev_device: udev device
- *
- * Retrieve the device node file name belonging to the udev device.
- * The path is an absolute path, and starts with the device directory.
- *
- * Returns: the device node file name of the udev device, or #NULL if no device node exists
- **/
-const char *udev_device_get_devnode(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->devnode;
-}
-
-/**
- * udev_device_get_subsystem:
- * @udev_device: udev device
- *
- * Retrieve the subsystem string of the udev device. The string does not
- * contain any "/".
- *
- * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
- **/
-const char *udev_device_get_subsystem(struct udev_device *udev_device)
-{
-       char subsystem[UTIL_NAME_SIZE];
-
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->subsystem_set) {
-               udev_device->subsystem_set = 1;
-               /* read "subsytem" link */
-               if (util_get_sys_subsystem(udev_device->udev, udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
-                       udev_device_set_subsystem(udev_device, subsystem);
-                       return udev_device->subsystem;
-               }
-               /* implicit names */
-               if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
-                       udev_device_set_subsystem(udev_device, "module");
-                       return udev_device->subsystem;
-               }
-               if (strstr(udev_device->devpath, "/drivers/") != NULL) {
-                       udev_device_set_subsystem(udev_device, "drivers");
-                       return udev_device->subsystem;
-               }
-               if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
-                   strncmp(udev_device->devpath, "/class/", 7) == 0 ||
-                   strncmp(udev_device->devpath, "/bus/", 5) == 0) {
-                       udev_device_set_subsystem(udev_device, "subsystem");
-                       return udev_device->subsystem;
-               }
-       }
-       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
- *
- * Retrieve the list of device links pointing to the device file of
- * the udev device. The next list entry can be retrieved with
- * udev_list_entry_next(), which returns #NULL if no more entries exist.
- * The devlink path can be retrieved from the list entry by
- * udev_list_entry_get_name(). The path is an absolute path, and starts with
- * the device directory.
- *
- * Returns: the first entry of the device node link list
- **/
-struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_list_get_entry(&udev_device->devlinks_list);
-}
-
-void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
-{
-       udev_device->devlinks_uptodate = 0;
-       udev_list_cleanup_entries(udev_device->udev, &udev_device->devlinks_list);
-}
-
-/**
- * udev_device_get_properties_list_entry:
- * @udev_device: udev device
- *
- * Retrieve the list of key/value device properties of the udev
- * device. The next list entry can be retrieved with udev_list_entry_next(),
- * which returns #NULL if no more entries exist. The property name
- * can be retrieved from the list entry by udev_list_get_name(),
- * the property value by udev_list_get_value().
- *
- * Returns: the first entry of the property list
- **/
-struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       if (!udev_device->devlinks_uptodate) {
-               char symlinks[UTIL_PATH_SIZE];
-               struct udev_list_entry *list_entry;
-
-               udev_device->devlinks_uptodate = 1;
-               list_entry = udev_device_get_devlinks_list_entry(udev_device);
-               if (list_entry != NULL) {
-                       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);
-               }
-       }
-       return udev_list_get_entry(&udev_device->properties_list);
-}
-
-const char *udev_device_get_driver(struct udev_device *udev_device)
-{
-       char driver[UTIL_NAME_SIZE];
-
-       if (udev_device == NULL)
-               return NULL;
-       if (!udev_device->driver_set) {
-               udev_device->driver_set = 1;
-               if (util_get_sys_driver(udev_device->udev, udev_device->syspath, driver, sizeof(driver)) > 0)
-                       udev_device->driver = strdup(driver);
-       }
-       return udev_device->driver;
-}
-
-dev_t udev_device_get_devnum(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return makedev(0, 0);
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->devnum;
-}
-
-const char *udev_device_get_action(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return NULL;
-       return udev_device->action;
-}
-
-unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
-{
-       if (udev_device == NULL)
-               return 0;
-       return udev_device->seqnum;
-}
-
-const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
-{
-       struct udev_list_entry *list_entry;
-       char path[UTIL_PATH_SIZE];
-       char value[4096];
-       struct stat statbuf;
-       int fd;
-       ssize_t size;
-       const char *val = NULL;
-
-       if (udev_device == NULL)
-               return NULL;
-       if (sysattr == NULL)
-               return NULL;
-
-       /* look for possibly already cached result */
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_device->sysattr_list)) {
-               if (strcmp(udev_list_entry_get_name(list_entry), sysattr) == 0) {
-                       dbg(udev_device->udev, "got '%s' (%s) from cache\n",
-                           sysattr, udev_list_entry_get_value(list_entry));
-                       return udev_list_entry_get_value(list_entry);
-               }
-       }
-
-       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);
-               goto out;
-       }
-
-       if (S_ISLNK(statbuf.st_mode)) {
-               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';
-                       pos = strrchr(target, '/');
-                       if (pos != NULL) {
-                               pos = &pos[1];
-                               dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, pos);
-                               list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, pos, 0, 0);
-                               val = udev_list_entry_get_value(list_entry);
-                       }
-               }
-               goto out;
-       }
-
-       /* skip directories */
-       if (S_ISDIR(statbuf.st_mode))
-               goto out;
-
-       /* skip non-readable files */
-       if ((statbuf.st_mode & S_IRUSR) == 0)
-               goto out;
-
-       /* read attribute value */
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
-               goto out;
-       }
-       size = read(fd, value, sizeof(value));
-       close(fd);
-       if (size < 0)
-               goto out;
-       if (size == sizeof(value))
-               goto out;
-
-       /* got a valid value, store it in cache and return it */
-       value[size] = '\0';
-       util_remove_trailing_chars(value, '\n');
-       dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
-       list_entry = udev_list_entry_add(udev_device->udev, &udev_device->sysattr_list, sysattr, value, 0, 0);
-       val = udev_list_entry_get_value(list_entry);
-out:
-       return val;
-}
-
-int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath)
-{
-       const char *pos;
-       size_t len;
-
-       free(udev_device->syspath);
-       udev_device->syspath = strdup(syspath);
-       if (udev_device->syspath ==  NULL)
-               return -ENOMEM;
-       udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
-       udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath);
-
-       pos = strrchr(udev_device->syspath, '/');
-       if (pos == NULL)
-               return -EINVAL;
-       udev_device->sysname = strdup(&pos[1]);
-       if (udev_device->sysname == NULL)
-               return -ENOMEM;
-
-       /* some devices have '!' in their name, change that to '/' */
-       len = 0;
-       while (udev_device->sysname[len] != '\0') {
-               if (udev_device->sysname[len] == '!')
-                       udev_device->sysname[len] = '/';
-               len++;
-       }
-
-       /* trailing number */
-       while (len > 0 && isdigit(udev_device->sysname[--len]))
-               udev_device->sysnum = &udev_device->sysname[len];
-
-       /* sysname is completely numeric */
-       if (len == 0)
-               udev_device->sysnum = NULL;
-
-       return 0;
-}
-
-int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
-{
-       free(udev_device->subsystem);
-       udev_device->subsystem = strdup(subsystem);
-       if (udev_device->subsystem == NULL)
-               return -ENOMEM;
-       udev_device->subsystem_set = 1;
-       udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
-       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);
-       udev_device->devnode = strdup(devnode);
-       if (devnode == NULL)
-               return 0;
-       if (udev_device->devnode == NULL)
-               return -ENOMEM;
-       udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode);
-       return 0;
-}
-
-int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink)
-{
-       udev_device->devlinks_uptodate = 0;
-       if (udev_list_entry_add(udev_device->udev, &udev_device->devlinks_list, devlink, NULL, 1, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
-{
-       udev_device->envp_uptodate = 0;
-       if (value == NULL) {
-               struct udev_list_entry *list_entry;
-
-               list_entry = udev_device_get_properties_list_entry(udev_device);
-               list_entry = udev_list_entry_get_by_name(list_entry, key);
-               if (list_entry != NULL)
-                       udev_list_entry_delete(list_entry);
-               return NULL;
-       }
-       return udev_list_entry_add(udev_device->udev, &udev_device->properties_list, key, value, 1, 0);
-}
-
-struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property)
-{
-       char name[UTIL_PATH_SIZE];
-       char *val;
-
-       util_strscpy(name, sizeof(name), property);
-       val = strchr(name, '=');
-       if (val == NULL)
-               return NULL;
-       val[0] = '\0';
-       val = &val[1];
-       if (val[0] == '\0')
-               val = NULL;
-       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)
-{
-       struct udev_list_entry *list_entry;
-       char *s;
-       size_t l;
-       unsigned int i;
-
-       /* monitor buffer of property strings */
-       free(udev_device->monitor_buf);
-       udev_device->monitor_buf_len = 0;
-       udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE);
-       if (udev_device->monitor_buf == NULL)
-               return -ENOMEM;
-
-       /* envp array, strings will point into monitor buffer */
-       if (udev_device->envp == NULL)
-               udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE);
-       if (udev_device->envp == NULL)
-               return -ENOMEM;
-
-       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++] = s;
-               if (i+1 >= ENVP_SIZE)
-                       return -EINVAL;
-
-               /* add property string to monitor buffer */
-               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;
-               s++;
-       }
-       udev_device->envp[i] = NULL;
-       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, udev_device->monitor_buf_len);
-       return 0;
-}
-
-char **udev_device_get_properties_envp(struct udev_device *udev_device)
-{
-       if (!udev_device->envp_uptodate)
-               if (update_envp_monitor_buf(udev_device) != 0)
-                       return NULL;
-       return udev_device->envp;
-}
-
-ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf)
-{
-       if (!udev_device->envp_uptodate)
-               if (update_envp_monitor_buf(udev_device) != 0)
-                       return -EINVAL;
-       *buf = udev_device->monitor_buf;
-       return udev_device->monitor_buf_len;
-}
-
-int udev_device_set_action(struct udev_device *udev_device, const char *action)
-{
-       free(udev_device->action);
-       udev_device->action = strdup(action);
-       if (udev_device->action == NULL)
-               return -ENOMEM;
-       udev_device_add_property(udev_device, "ACTION", udev_device->action);
-       return 0;
-}
-
-int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
-{
-       free(udev_device->driver);
-       udev_device->driver = strdup(driver);
-       if (udev_device->driver == NULL)
-               return -ENOMEM;
-       udev_device->driver_set = 1;
-       udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
-       return 0;
-}
-
-const char *udev_device_get_devpath_old(struct udev_device *udev_device)
-{
-       return udev_device->devpath_old;
-}
-
-int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
-{
-       udev_device->devpath_old = strdup(devpath_old);
-       if (udev_device->devpath_old == NULL)
-               return -ENOMEM;
-       udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
-       return 0;
-}
-
-const char *udev_device_get_knodename(struct udev_device *udev_device)
-{
-       return udev_device->knodename;
-}
-
-int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename)
-{
-       udev_device->knodename = strdup(knodename);
-       if (udev_device->knodename == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-int udev_device_get_timeout(struct udev_device *udev_device)
-{
-       return udev_device->timeout;
-}
-
-int udev_device_set_timeout(struct udev_device *udev_device, int timeout)
-{
-       udev_device->timeout = timeout;
-       return 0;
-}
-int udev_device_get_event_timeout(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->event_timeout;
-}
-
-int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout)
-{
-       udev_device->event_timeout = event_timeout;
-       return 0;
-}
-
-int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
-{
-       char num[32];
-
-       udev_device->seqnum = seqnum;
-       snprintf(num, sizeof(num), "%llu", seqnum);
-       udev_device_add_property(udev_device, "SEQNUM", num);
-       return 0;
-}
-
-int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
-{
-       char num[32];
-
-       udev_device->devnum = devnum;
-
-       snprintf(num, sizeof(num), "%u", major(devnum));
-       udev_device_add_property(udev_device, "MAJOR", num);
-       snprintf(num, sizeof(num), "%u", minor(devnum));
-       udev_device_add_property(udev_device, "MINOR", num);
-       return 0;
-}
-
-int udev_device_get_num_fake_partitions(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->num_fake_partitions;
-}
-
-int udev_device_set_num_fake_partitions(struct udev_device *udev_device, int num)
-{
-       udev_device->num_fake_partitions = num;
-       return 0;
-}
-
-int udev_device_get_devlink_priority(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->devlink_priority;
-}
-
-int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
-{
-        udev_device->devlink_priority = prio;
-       return 0;
-}
-
-int udev_device_get_ignore_remove(struct udev_device *udev_device)
-{
-       if (!udev_device->info_loaded)
-               device_load_info(udev_device);
-       return udev_device->ignore_remove;
-}
-
-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;
-}
diff --git a/udev/lib/libudev-enumerate.c b/udev/lib/libudev-enumerate.c
deleted file mode 100644 (file)
index 63f8406..0000000
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static int devices_sort(struct udev_enumerate *udev_enumerate);
-
-struct udev_enumerate {
-       struct udev *udev;
-       int refcount;
-       struct udev_list_node sysattr_match_list;
-       struct udev_list_node sysattr_nomatch_list;
-       struct udev_list_node subsystem_match_list;
-       struct udev_list_node subsystem_nomatch_list;
-       struct udev_list_node properties_match_list;
-       struct udev_list_node devices_list;
-       int devices_sorted;
-};
-
-/**
- * udev_enumerate_new:
- * @udev: udev library context
- *
- * Returns: an enumeration context
- **/
-struct udev_enumerate *udev_enumerate_new(struct udev *udev)
-{
-       struct udev_enumerate *udev_enumerate;
-
-       udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
-       if (udev_enumerate == NULL)
-               return NULL;
-       udev_enumerate->refcount = 1;
-       udev_enumerate->udev = udev;
-       udev_list_init(&udev_enumerate->devices_list);
-       udev_list_init(&udev_enumerate->sysattr_match_list);
-       udev_list_init(&udev_enumerate->sysattr_nomatch_list);
-       udev_list_init(&udev_enumerate->subsystem_match_list);
-       udev_list_init(&udev_enumerate->subsystem_nomatch_list);
-       udev_list_init(&udev_enumerate->properties_match_list);
-       return udev_enumerate;
-}
-
-struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
-{
-       if (udev_enumerate == NULL)
-               return NULL;
-       udev_enumerate->refcount++;
-       return udev_enumerate;
-}
-
-void udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
-{
-       if (udev_enumerate == NULL)
-               return;
-       udev_enumerate->refcount--;
-       if (udev_enumerate->refcount > 0)
-               return;
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->devices_list);
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_match_list);
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->sysattr_nomatch_list);
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_match_list);
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->subsystem_nomatch_list);
-       udev_list_cleanup_entries(udev_enumerate->udev, &udev_enumerate->properties_match_list);
-       free(udev_enumerate);
-}
-
-struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
-{
-       if (udev_enumerate == NULL)
-               return NULL;
-       return udev_enumerate->udev;
-}
-
-struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
-{
-       if (udev_enumerate == NULL)
-               return NULL;
-       if (!udev_enumerate->devices_sorted)
-               devices_sort(udev_enumerate);
-       return udev_list_get_entry(&udev_enumerate->devices_list);
-}
-
-int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (subsystem == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
-                               &udev_enumerate->subsystem_match_list, subsystem, NULL, 1, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (subsystem == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
-                               &udev_enumerate->subsystem_nomatch_list, subsystem, NULL, 1, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (sysattr == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
-                          &udev_enumerate->sysattr_match_list, sysattr, value, 0, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
-{
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (sysattr == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
-                          &udev_enumerate->sysattr_nomatch_list, sysattr, value, 0, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-static int match_sysattr_value(struct udev *udev, const char *syspath, const char *sysattr, const char *match_val)
-{
-       struct udev_device *device;
-       const char *val = NULL;
-       int match = 0;
-
-       device = udev_device_new_from_syspath(udev, syspath);
-       if (device == NULL)
-               return -EINVAL;
-       val = udev_device_get_sysattr_value(device, sysattr);
-       if (val == NULL)
-               goto exit;
-       if (match_val == NULL) {
-               match = 1;
-               goto exit;
-       }
-       if (fnmatch(match_val, val, 0) == 0) {
-               match = 1;
-               goto exit;
-       }
-exit:
-       udev_device_unref(device);
-       return match;
-}
-
-int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
-{
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (property == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_enumerate_get_udev(udev_enumerate),
-                               &udev_enumerate->properties_match_list, property, value, 0, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-static int match_sysattr(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-       struct udev_list_entry *list_entry;
-
-       /* skip list */
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
-               if (match_sysattr_value(udev, syspath,
-                                    udev_list_entry_get_name(list_entry),
-                                    udev_list_entry_get_value(list_entry)))
-                       return 0;
-       }
-       /* include list */
-       if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
-               udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
-                       /* anything that does not match, will make it FALSE */
-                       if (!match_sysattr_value(udev, syspath,
-                                             udev_list_entry_get_name(list_entry),
-                                             udev_list_entry_get_value(list_entry)))
-                               return 0;
-               }
-               return 1;
-       }
-       return 1;
-}
-
-static int match_property(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
-       struct udev_device *dev;
-       struct udev_list_entry *list_entry;
-       int match = 0;
-
-       /* no match always matches */
-       if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
-               return 1;
-
-       /* no device does not match */
-       dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
-       if (dev == NULL)
-               return 0;
-
-       /* loop over matches */
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
-               const char *match_key = udev_list_entry_get_name(list_entry);
-               const char *match_value = udev_list_entry_get_value(list_entry);
-               struct udev_list_entry *property_entry;
-
-               /* loop over device properties */
-               udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
-                       const char *dev_key = udev_list_entry_get_name(property_entry);
-                       const char *dev_value = udev_list_entry_get_value(property_entry);
-
-                       if (fnmatch(match_key, dev_key, 0) != 0)
-                               continue;
-                       if (match_value == NULL && dev_value == NULL) {
-                               match = 1;
-                               goto out;
-                       }
-                       if (match_value == NULL || dev_value == NULL)
-                               continue;
-                       if (fnmatch(match_value, dev_value, 0) == 0) {
-                               match = 1;
-                               goto out;
-                       }
-               }
-       }
-out:
-       udev_device_unref(dev);
-       return match;
-}
-
-static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
-                                   const char *basedir, const char *subdir1, const char *subdir2)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-       char path[UTIL_PATH_SIZE];
-       size_t l;
-       char *s;
-       DIR *dir;
-       struct dirent *dent;
-
-       s = path;
-       l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
-       if (subdir1 != NULL)
-               l = util_strpcpyl(&s, l, "/", subdir1, NULL);
-       if (subdir2 != NULL)
-               l = util_strpcpyl(&s, l, "/", subdir2, NULL);
-       dir = opendir(path);
-       if (dir == NULL)
-               return -1;
-       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-               char syspath[UTIL_PATH_SIZE];
-               char filename[UTIL_PATH_SIZE];
-               struct stat statbuf;
-
-               if (dent->d_name[0] == '.')
-                       continue;
-               util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
-               if (lstat(syspath, &statbuf) != 0)
-                       continue;
-               if (S_ISREG(statbuf.st_mode))
-                       continue;
-               if (S_ISLNK(statbuf.st_mode))
-                       util_resolve_sys_link(udev, syspath, sizeof(syspath));
-
-               util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
-               if (stat(filename, &statbuf) != 0)
-                       continue;
-               if (!match_sysattr(udev_enumerate, syspath))
-                       continue;
-               if (!match_property(udev_enumerate, syspath))
-                       continue;
-               udev_list_entry_add(udev, &udev_enumerate->devices_list, syspath, NULL, 1, 1);
-       }
-       closedir(dir);
-       return 0;
-}
-
-static int match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
-{
-       struct udev_list_entry *list_entry;
-
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
-               if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
-                       return 0;
-       }
-       if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
-               udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
-                       if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
-                               return 1;
-               }
-               return 0;
-       }
-       return 1;
-}
-
-static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-
-       char path[UTIL_PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
-       dir = opendir(path);
-       if (dir == NULL)
-               return -1;
-       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-               if (dent->d_name[0] == '.')
-                       continue;
-               if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
-                       continue;
-               scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
-       }
-       closedir(dir);
-       return 0;
-}
-
-static int devices_delay(struct udev *udev, const char *syspath)
-{
-       static const char *delay_device_list[] = {
-               "/block/md",
-               "/block/dm-",
-               NULL
-       };
-       size_t len;
-       int i;
-
-       len = strlen(udev_get_sys_path(udev));
-       for (i = 0; delay_device_list[i] != NULL; i++) {
-               if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
-                       dbg(udev, "delaying: %s\n", syspath);
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/* sort delayed devices to the end of the list */
-static int devices_sort(struct udev_enumerate *udev_enumerate)
-{
-       struct udev_list_entry *entry_loop;
-       struct udev_list_entry *entry_tmp;
-       struct udev_list_node devices_list;
-
-       udev_list_init(&devices_list);
-       /* move delayed to delay list */
-       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(&udev_enumerate->devices_list)) {
-               if (devices_delay(udev_enumerate->udev, udev_list_entry_get_name(entry_loop))) {
-                       udev_list_entry_remove(entry_loop);
-                       udev_list_entry_append(entry_loop, &devices_list);
-               }
-       }
-       /* move delayed back to end of list */
-       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(&devices_list)) {
-               udev_list_entry_remove(entry_loop);
-               udev_list_entry_append(entry_loop, &udev_enumerate->devices_list);
-       }
-       udev_enumerate->devices_sorted = 1;
-       return 0;
-}
-
-int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-       struct udev_device *udev_device;
-
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       if (syspath == NULL)
-               return 0;
-       /* resolve to real syspath */
-       udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
-       if (udev_device == NULL)
-               return -EINVAL;
-       udev_list_entry_add(udev, &udev_enumerate->devices_list,
-                           udev_device_get_syspath(udev_device), NULL, 1, 1);
-       udev_device_unref(udev_device);
-       return 0;
-}
-
-/**
- * udev_enumerate_scan_devices:
- * @udev_enumerate: udev enumeration context
- *
- * Returns: a negative value on error.
- **/
-int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-       char base[UTIL_PATH_SIZE];
-       struct stat statbuf;
-
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
-       if (stat(base, &statbuf) == 0) {
-               /* we have /subsystem/, forget all the old stuff */
-               dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
-               scan_dir(udev_enumerate, "subsystem", "devices", NULL);
-       } else {
-               dbg(udev, "searching '/bus/*/devices/*' dir\n");
-               scan_dir(udev_enumerate, "bus", "devices", NULL);
-               dbg(udev, "searching '/class/*' dir\n");
-               scan_dir(udev_enumerate, "class", NULL, NULL);
-               /* if block isn't a class, scan /block/ */
-               util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/class/block", NULL);
-               if (stat(base, &statbuf) != 0) {
-                       if (match_subsystem(udev_enumerate, "block")) {
-                               dbg(udev, "searching '/block/*' dir\n");
-                               /* scan disks */
-                               scan_dir_and_add_devices(udev_enumerate, "block", NULL, NULL);
-                               /* scan partitions */
-                               dbg(udev, "searching '/block/*/*' dir\n");
-                               scan_dir(udev_enumerate, "block", NULL, "block");
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
- * udev_enumerate_scan_subsystems:
- * @udev_enumerate: udev enumeration context
- *
- * Returns: a negative value on error.
- **/
-int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
-{
-       struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
-       char base[UTIL_PATH_SIZE];
-       struct stat statbuf;
-       const char *subsysdir;
-
-       if (udev_enumerate == NULL)
-               return -EINVAL;
-       util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
-       if (stat(base, &statbuf) == 0)
-               subsysdir = "subsystem";
-       else
-               subsysdir = "bus";
-       if (match_subsystem(udev_enumerate, "subsystem")) {
-               dbg(udev, "searching '%s/*' dir\n", subsysdir);
-               scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
-       }
-       if (match_subsystem(udev_enumerate, "drivers")) {
-               dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
-               scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
-       }
-       return 0;
-}
diff --git a/udev/lib/libudev-list.c b/udev/lib/libudev-list.c
deleted file mode 100644 (file)
index 182d75a..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-struct udev_list_entry {
-       struct udev_list_node node;
-       struct udev *udev;
-       struct udev_list_node *list;
-       char *name;
-       char *value;
-       int flag;
-};
-
-/* list head point to itself if empty */
-void udev_list_init(struct udev_list_node *list)
-{
-       list->next = list;
-       list->prev = list;
-}
-
-int udev_list_is_empty(struct udev_list_node *list)
-{
-       return list->next == list;
-}
-
-static void udev_list_node_insert_between(struct udev_list_node *new,
-                                         struct udev_list_node *prev,
-                                         struct udev_list_node *next)
-{
-       next->prev = new;
-       new->next = next;
-       new->prev = prev;
-       prev->next = new;
-}
-
-void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
-{
-       udev_list_node_insert_between(new, list->prev, list);
-}
-
-void udev_list_node_remove(struct udev_list_node *entry)
-{
-       struct udev_list_node *prev = entry->prev;
-       struct udev_list_node *next = entry->next;
-
-       next->prev = prev;
-       prev->next = next;
-
-       entry->prev = NULL;
-       entry->next = NULL;
-}
-
-/* return list entry which embeds this node */
-static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
-{
-       char *list;
-
-       list = (char *)node;
-       list -= offsetof(struct udev_list_entry, node);
-       return (struct udev_list_entry *)list;
-}
-
-/* insert entry into a list as the last element  */
-void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list)
-{
-       /* inserting before the list head make the node the last node in the list */
-       udev_list_node_insert_between(&new->node, list->prev, list);
-       new->list = list;
-}
-
-/* remove entry from a list */
-void udev_list_entry_remove(struct udev_list_entry *entry)
-{
-       udev_list_node_remove(&entry->node);
-       entry->list = NULL;
-}
-
-/* insert entry into a list, before a given existing entry */
-void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
-{
-       udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
-       new->list = entry->list;
-}
-
-struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list,
-                                           const char *name, const char *value,
-                                           int unique, int sort)
-{
-       struct udev_list_entry *entry_loop = NULL;
-       struct udev_list_entry *entry_new;
-
-       if (unique)
-               udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
-                       if (strcmp(entry_loop->name, name) == 0) {
-                               dbg(udev, "'%s' is already in the list\n", name);
-                               free(entry_loop->value);
-                               if (value == NULL) {
-                                       entry_loop->value = NULL;
-                                       dbg(udev, "'%s' value unset\n", name);
-                                       return entry_loop;
-                               }
-                               entry_loop->value = strdup(value);
-                               if (entry_loop->value == NULL)
-                                       return NULL;
-                               dbg(udev, "'%s' value replaced with '%s'\n", name, value);
-                               return entry_loop;
-                       }
-               }
-
-       if (sort)
-               udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) {
-                       if (strcmp(entry_loop->name, name) > 0)
-                               break;
-               }
-
-       entry_new = malloc(sizeof(struct udev_list_entry));
-       if (entry_new == NULL)
-               return NULL;
-       memset(entry_new, 0x00, sizeof(struct udev_list_entry));
-       entry_new->udev = udev;
-       entry_new->name = strdup(name);
-       if (entry_new->name == NULL) {
-               free(entry_new);
-               return NULL;
-       }
-       if (value != NULL) {
-               entry_new->value = strdup(value);
-               if (entry_new->value == NULL) {
-                       free(entry_new->name);
-                       free(entry_new);
-                       return NULL;
-               }
-       }
-       if (entry_loop != NULL)
-               udev_list_entry_insert_before(entry_new, entry_loop);
-       else
-               udev_list_entry_append(entry_new, list);
-       dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value);
-       return entry_new;
-}
-
-void udev_list_entry_delete(struct udev_list_entry *entry)
-{
-       udev_list_node_remove(&entry->node);
-       free(entry->name);
-       free(entry->value);
-       free(entry);
-}
-
-void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list)
-{
-       struct udev_list_entry *entry_loop;
-       struct udev_list_entry *entry_tmp;
-
-       udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
-               udev_list_entry_delete(entry_loop);
-}
-
-struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list)
-{
-       if (udev_list_is_empty(list))
-               return NULL;
-       return list_node_to_entry(list->next);
-}
-
-struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
-{
-       struct udev_list_node *next;
-
-       if (list_entry == NULL)
-               return NULL;
-       next = list_entry->node.next;
-       /* empty list or no more entries */
-       if (next == list_entry->list)
-               return NULL;
-       return list_node_to_entry(next);
-}
-
-struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
-{
-       struct udev_list_entry *entry;
-
-       udev_list_entry_foreach(entry, list_entry) {
-               if (strcmp(udev_list_entry_get_name(entry), name) == 0) {
-                       dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value);
-                       return entry;
-               }
-       }
-       return NULL;
-}
-
-const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
-{
-       if (list_entry == NULL)
-               return NULL;
-       return list_entry->name;
-}
-
-const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
-{
-       if (list_entry == NULL)
-               return NULL;
-       return list_entry->value;
-}
-
-int udev_list_entry_get_flag(struct udev_list_entry *list_entry)
-{
-       if (list_entry == NULL)
-               return -EINVAL;
-       return list_entry->flag;
-}
-
-void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag)
-{
-       if (list_entry == NULL)
-               return;
-       list_entry->flag = flag;
-}
diff --git a/udev/lib/libudev-monitor.c b/udev/lib/libudev-monitor.c
deleted file mode 100644 (file)
index 7a0cb47..0000000
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
-#include <linux/netlink.h>
-#include <linux/filter.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-struct udev_monitor {
-       struct udev *udev;
-       int refcount;
-       int sock;
-       struct sockaddr_nl snl;
-       struct sockaddr_nl snl_trusted_sender;
-       struct sockaddr_nl snl_destination;
-       struct sockaddr_un sun;
-       socklen_t addrlen;
-       struct udev_list_node filter_subsystem_list;
-};
-
-enum udev_monitor_netlink_group {
-       UDEV_MONITOR_NONE,
-       UDEV_MONITOR_KERNEL,
-       UDEV_MONITOR_UDEV,
-};
-
-#define UDEV_MONITOR_MAGIC             0xcafe1dea
-struct udev_monitor_netlink_header {
-       /* udev version text */
-       char version[16];
-       /*
-        * magic to protect against daemon <-> library message format mismatch
-        * used in the kernel from socket filter rules; needs to be stored in network order
-        */
-       unsigned int magic;
-       /* properties buffer */
-       unsigned short properties_off;
-       unsigned short properties_len;
-       /*
-        * hashes of some common device properties strings to filter with socket filters in
-        * the client used in the kernel from socket filter rules; needs to be stored in
-        * network order
-        */
-       unsigned int filter_subsystem;
-       unsigned int filter_devtype;
-};
-
-static struct udev_monitor *udev_monitor_new(struct udev *udev)
-{
-       struct udev_monitor *udev_monitor;
-
-       udev_monitor = calloc(1, sizeof(struct udev_monitor));
-       if (udev_monitor == NULL)
-               return NULL;
-       udev_monitor->refcount = 1;
-       udev_monitor->udev = udev;
-       udev_list_init(&udev_monitor->filter_subsystem_list);
-       return udev_monitor;
-}
-
-/**
- * udev_monitor_new_from_socket:
- * @udev: udev library context
- * @socket_path: unix socket path
- *
- * Create new udev monitor and connect to a specified socket. The
- * path to a socket either points to an existing socket file, or if
- * the socket path starts with a '@' character, an abstract namespace
- * socket will be used.
- *
- * A socket file will not be created. If it does not already exist,
- * it will fall-back and connect to an abstract namespace socket with
- * the given path. The permissions adjustment of a socket file, as
- * well as the later cleanup, needs to be done by the caller.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev monitor.
- *
- * Returns: a new udev monitor, or #NULL, in case of an error
- **/
-struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
-{
-       struct udev_monitor *udev_monitor;
-       struct stat statbuf;
-
-       if (udev == NULL)
-               return NULL;
-       if (socket_path == NULL)
-               return NULL;
-       udev_monitor = udev_monitor_new(udev);
-       if (udev_monitor == NULL)
-               return NULL;
-
-       udev_monitor->sun.sun_family = AF_LOCAL;
-       if (socket_path[0] == '@') {
-               /* translate leading '@' to abstract namespace */
-               util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-               udev_monitor->sun.sun_path[0] = '\0';
-               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-       } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
-               /* existing socket file */
-               util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
-               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
-       } else {
-               /* no socket file, assume abstract namespace socket */
-               util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
-               udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
-       }
-       udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-       if (udev_monitor->sock == -1) {
-               err(udev, "error getting socket: %m\n");
-               free(udev_monitor);
-               return NULL;
-       }
-       util_set_fd_cloexec(udev_monitor->sock);
-
-       dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
-       return udev_monitor;
-}
-
-/**
- * udev_monitor_new_from_netlink:
- * @udev: udev library context
- * @name: name of event source
- *
- * Create new udev monitor and connect to a specified event
- * source. Valid sources identifiers are "udev" and "kernel".
- *
- * Applications should usually not connect directly to the
- * "kernel" events, because the devices might not be useable
- * at that time, before udev has configured them, and created
- * device nodes.
- *
- * Accessing devices at the same time as udev, might result
- * in unpredictable behavior.
- *
- * The "udev" events are sent out after udev has finished its
- * event processing, all rules have been processed, and needed
- * device nodes are created.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev monitor.
- *
- * Returns: a new udev monitor, or #NULL, in case of an error
- **/
-struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
-{
-       struct udev_monitor *udev_monitor;
-       unsigned int group;
-
-       if (udev == NULL)
-               return NULL;
-
-       if (name == NULL)
-               group = UDEV_MONITOR_NONE;
-       else if (strcmp(name, "udev") == 0)
-               group = UDEV_MONITOR_UDEV;
-       else if (strcmp(name, "kernel") == 0)
-               group = UDEV_MONITOR_KERNEL;
-       else
-               return NULL;
-
-       udev_monitor = udev_monitor_new(udev);
-       if (udev_monitor == NULL)
-               return NULL;
-
-       udev_monitor->sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-       if (udev_monitor->sock == -1) {
-               err(udev, "error getting socket: %m\n");
-               free(udev_monitor);
-               return NULL;
-       }
-       util_set_fd_cloexec(udev_monitor->sock);
-
-       udev_monitor->snl.nl_family = AF_NETLINK;
-       udev_monitor->snl.nl_groups = group;
-
-       /* default destination for sending */
-       udev_monitor->snl_destination.nl_family = AF_NETLINK;
-       udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
-
-       dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
-       return udev_monitor;
-}
-
-static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
-                           unsigned short code, unsigned int data)
-{
-       struct sock_filter *ins = &inss[*i];
-
-       ins->code = code;
-       ins->k = data;
-       (*i)++;
-}
-
-static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
-                          unsigned short code, unsigned int data,
-                          unsigned short jt, unsigned short jf)
-{
-       struct sock_filter *ins = &inss[*i];
-
-       ins->code = code;
-       ins->jt = jt;
-       ins->jf = jf;
-       ins->k = data;
-       (*i)++;
-}
-
-int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
-{
-       static struct sock_filter ins[256];
-       static struct sock_fprog filter;
-       unsigned int i;
-       struct udev_list_entry *list_entry;
-       int err;
-
-       if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
-               return 0;
-
-       memset(ins, 0x00, sizeof(ins));
-       i = 0;
-
-       /* load magic in A */
-       bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
-       /* jump if magic matches */
-       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
-       /* wrong magic, pass packet */
-       bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
-
-       /* add all subsystem match values */
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
-               unsigned int hash;
-
-               /* load filter_subsystem value in A */
-               bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem));
-               hash = util_string_hash32(udev_list_entry_get_name(list_entry));
-               if (udev_list_entry_get_value(list_entry) == NULL) {
-                       /* jump if subsystem does not match */
-                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
-               } else {
-                       /* jump if subsystem does not match */
-                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
-
-                       /* load filter_devtype value in A */
-                       bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype));
-                       /* jump if value does not match */
-                       hash = util_string_hash32(udev_list_entry_get_value(list_entry));
-                       bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
-               }
-
-               /* matched, pass packet */
-               bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
-
-               if (i+1 >= ARRAY_SIZE(ins))
-                       return -1;
-       }
-       /* nothing matched, drop packet */
-       bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
-
-       /* install filter */
-       filter.len = i;
-       filter.filter = ins;
-       err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
-       return err;
-}
-
-int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
-{
-       udev_monitor->snl_trusted_sender.nl_pid = sender->snl.nl_pid;
-       return 0;
-}
-
-int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
-{
-       int err;
-       const int on = 1;
-
-       if (udev_monitor->sun.sun_family != 0) {
-               err = bind(udev_monitor->sock,
-                          (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
-       } else if (udev_monitor->snl.nl_family != 0) {
-               udev_monitor_filter_update(udev_monitor);
-               err = bind(udev_monitor->sock,
-                          (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
-               if (err == 0) {
-                       struct sockaddr_nl snl;
-                       socklen_t addrlen;
-
-                       /*
-                        * get the address the kernel has assigned us
-                        * it is usually, but not neccessarily the pid
-                        */
-                       addrlen = sizeof(struct sockaddr_nl);
-                       err = getsockname(udev_monitor->sock, (struct sockaddr *)&snl, &addrlen);
-                       if (err == 0)
-                               udev_monitor->snl.nl_pid = snl.nl_pid;
-               }
-       } else {
-               return -EINVAL;
-       }
-
-       if (err < 0) {
-               err(udev_monitor->udev, "bind failed: %m\n");
-               return err;
-       }
-
-       /* enable receiving of sender credentials */
-       setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-       return 0;
-}
-
-int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
-{
-       if (udev_monitor == NULL)
-               return -1;
-       return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
-}
-
-int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
-{
-       int err;
-
-       err = close(udev_monitor->sock);
-       udev_monitor->sock = -1;
-       return err;
-}
-
-/**
- * udev_monitor_ref:
- * @udev_monitor: udev monitor
- *
- * Take a reference of a udev monitor.
- *
- * Returns: the passed udev monitor
- **/
-struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
-{
-       if (udev_monitor == NULL)
-               return NULL;
-       udev_monitor->refcount++;
-       return udev_monitor;
-}
-
-/**
- * udev_monitor_unref:
- * @udev_monitor: udev monitor
- *
- * Drop a reference of a udev monitor. If the refcount reaches zero,
- * the bound socket will be closed, and the resources of the monitor
- * will be released.
- *
- **/
-void udev_monitor_unref(struct udev_monitor *udev_monitor)
-{
-       if (udev_monitor == NULL)
-               return;
-       udev_monitor->refcount--;
-       if (udev_monitor->refcount > 0)
-               return;
-       if (udev_monitor->sock >= 0)
-               close(udev_monitor->sock);
-       udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list);
-       dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
-       free(udev_monitor);
-}
-
-/**
- * udev_monitor_get_udev:
- * @udev_monitor: udev monitor
- *
- * Retrieve the udev library context the monitor was created with.
- *
- * Returns: the udev library context
- **/
-struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
-{
-       if (udev_monitor == NULL)
-               return NULL;
-       return udev_monitor->udev;
-}
-
-/**
- * udev_monitor_get_fd:
- * @udev_monitor: udev monitor
- *
- * Retrieve the socket file descriptor associated with the monitor.
- *
- * Returns: the socket file descriptor
- **/
-int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
-{
-       if (udev_monitor == NULL)
-               return -1;
-       return udev_monitor->sock;
-}
-
-static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
-{
-       struct udev_list_entry *list_entry;
-
-       if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
-               return 1;
-
-       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
-               const char *subsys = udev_list_entry_get_name(list_entry);
-               const char *dsubsys = udev_device_get_subsystem(udev_device);
-               const char *devtype;
-               const char *ddevtype;
-
-               if (strcmp(dsubsys, subsys) != 0)
-                       continue;
-
-               devtype = udev_list_entry_get_value(list_entry);
-               if (devtype == NULL)
-                       return 1;
-               ddevtype = udev_device_get_devtype(udev_device);
-               if (ddevtype == NULL)
-                       continue;
-               if (strcmp(ddevtype, devtype) == 0)
-                       return 1;
-       }
-       return 0;
-}
-
-/**
- * udev_monitor_receive_device:
- * @udev_monitor: udev monitor
- *
- * Receive data from the udev monitor socket, allocate a new udev
- * device, fill in the received data, and return the device.
- *
- * Only socket connections with uid=0 are accepted. The caller
- * needs to make sure that there is data to read from the socket.
- * The call will block until the socket becomes readable.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev device.
- *
- * Returns: a new udev device, or #NULL, in case of an error
- **/
-struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
-{
-       struct udev_device *udev_device;
-       struct msghdr smsg;
-       struct iovec iov;
-       char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
-       struct cmsghdr *cmsg;
-       struct sockaddr_nl snl;
-       struct ucred *cred;
-       char buf[8192];
-       ssize_t buflen;
-       ssize_t bufpos;
-       struct udev_monitor_netlink_header *nlh;
-       int devpath_set = 0;
-       int subsystem_set = 0;
-       int action_set = 0;
-       int maj = 0;
-       int min = 0;
-       int is_kernel = 0;
-
-retry:
-       if (udev_monitor == NULL)
-               return NULL;
-       memset(buf, 0x00, sizeof(buf));
-       iov.iov_base = &buf;
-       iov.iov_len = sizeof(buf);
-       memset (&smsg, 0x00, sizeof(struct msghdr));
-       smsg.msg_iov = &iov;
-       smsg.msg_iovlen = 1;
-       smsg.msg_control = cred_msg;
-       smsg.msg_controllen = sizeof(cred_msg);
-
-       if (udev_monitor->snl.nl_family != 0) {
-               smsg.msg_name = &snl;
-               smsg.msg_namelen = sizeof(snl);
-       }
-
-       buflen = recvmsg(udev_monitor->sock, &smsg, 0);
-       if (buflen < 0) {
-               if (errno != EINTR)
-                       info(udev_monitor->udev, "unable to receive message\n");
-               return NULL;
-       }
-
-       if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
-               info(udev_monitor->udev, "invalid message length\n");
-               return NULL;
-       }
-
-       if (udev_monitor->snl.nl_family != 0) {
-               if (snl.nl_groups == 0) {
-                       /* unicast message, check if we trust the sender */
-                       if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
-                           snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
-                               info(udev_monitor->udev, "unicast netlink message ignored\n");
-                               return NULL;
-                       }
-               } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
-                       if (snl.nl_pid > 0) {
-                               info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n", snl.nl_pid);
-                               return NULL;
-                       }
-                       is_kernel = 1;
-               }
-       }
-
-       cmsg = CMSG_FIRSTHDR(&smsg);
-       if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
-               info(udev_monitor->udev, "no sender credentials received, message ignored\n");
-               return NULL;
-       }
-
-       cred = (struct ucred *)CMSG_DATA(cmsg);
-       if (cred->uid != 0) {
-               info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
-               return NULL;
-       }
-
-       if (strncmp(buf, "udev-", 5) == 0) {
-               /* udev message needs proper version magic */
-               nlh = (struct udev_monitor_netlink_header *) buf;
-               if (nlh->magic != htonl(UDEV_MONITOR_MAGIC))
-                       return NULL;
-               if (nlh->properties_off < sizeof(struct udev_monitor_netlink_header))
-                       return NULL;
-               if (nlh->properties_off+32 > buflen)
-                       return NULL;
-               bufpos = nlh->properties_off;
-       } else {
-               /* kernel message with header */
-               bufpos = strlen(buf) + 1;
-               if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
-                       info(udev_monitor->udev, "invalid message length\n");
-                       return NULL;
-               }
-
-               /* check message header */
-               if (strstr(buf, "@/") == NULL) {
-                       info(udev_monitor->udev, "unrecognized message header\n");
-                       return NULL;
-               }
-       }
-
-       udev_device = device_new(udev_monitor->udev);
-       if (udev_device == NULL) {
-               return NULL;
-       }
-
-       while (bufpos < buflen) {
-               char *key;
-               size_t keylen;
-
-               key = &buf[bufpos];
-               keylen = strlen(key);
-               if (keylen == 0)
-                       break;
-               bufpos += keylen + 1;
-
-               if (strncmp(key, "DEVPATH=", 8) == 0) {
-                       char path[UTIL_PATH_SIZE];
-
-                       util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_monitor->udev), &key[8], NULL);
-                       udev_device_set_syspath(udev_device, path);
-                       devpath_set = 1;
-               } else if (strncmp(key, "SUBSYSTEM=", 10) == 0) {
-                       udev_device_set_subsystem(udev_device, &key[10]);
-                       subsystem_set = 1;
-               } else if (strncmp(key, "DEVTYPE=", 8) == 0) {
-                       udev_device_set_devtype(udev_device, &key[8]);
-               } else if (strncmp(key, "DEVNAME=", 8) == 0) {
-                       if (is_kernel)
-                               udev_device_set_knodename(udev_device, &key[8]);
-                       else
-                               udev_device_set_devnode(udev_device, &key[8]);
-               } else if (strncmp(key, "DEVLINKS=", 9) == 0) {
-                       char devlinks[UTIL_PATH_SIZE];
-                       char *slink;
-                       char *next;
-
-                       util_strscpy(devlinks, sizeof(devlinks), &key[9]);
-                       slink = devlinks;
-                       next = strchr(slink, ' ');
-                       while (next != NULL) {
-                               next[0] = '\0';
-                               udev_device_add_devlink(udev_device, slink);
-                               slink = &next[1];
-                               next = strchr(slink, ' ');
-                       }
-                       if (slink[0] != '\0')
-                               udev_device_add_devlink(udev_device, slink);
-               } else if (strncmp(key, "DRIVER=", 7) == 0) {
-                       udev_device_set_driver(udev_device, &key[7]);
-               } else if (strncmp(key, "ACTION=", 7) == 0) {
-                       udev_device_set_action(udev_device, &key[7]);
-                       action_set = 1;
-               } else if (strncmp(key, "MAJOR=", 6) == 0) {
-                       maj = strtoull(&key[6], NULL, 10);
-               } else if (strncmp(key, "MINOR=", 6) == 0) {
-                       min = strtoull(&key[6], NULL, 10);
-               } else if (strncmp(key, "DEVPATH_OLD=", 12) == 0) {
-                       udev_device_set_devpath_old(udev_device, &key[12]);
-               } else if (strncmp(key, "SEQNUM=", 7) == 0) {
-                       udev_device_set_seqnum(udev_device, strtoull(&key[7], NULL, 10));
-               } else if (strncmp(key, "TIMEOUT=", 8) == 0) {
-                       udev_device_set_timeout(udev_device, strtoull(&key[8], NULL, 10));
-               } else {
-                       udev_device_add_property_from_string(udev_device, key);
-               }
-       }
-       if (!devpath_set || !subsystem_set || !action_set) {
-               info(udev_monitor->udev, "missing values, skip\n");
-               udev_device_unref(udev_device);
-               return NULL;
-       }
-
-       /* skip device, if it does not pass the current filter */
-       if (!passes_filter(udev_monitor, udev_device)) {
-               struct pollfd pfd[1];
-               int rc;
-
-               udev_device_unref(udev_device);
-
-               /* if something is queued, get next device */
-               pfd[0].fd = udev_monitor->sock;
-               pfd[0].events = POLLIN;
-               rc = poll(pfd, 1, 0);
-               if (rc > 0)
-                       goto retry;
-               return NULL;
-       }
-
-       if (maj > 0)
-               udev_device_set_devnum(udev_device, makedev(maj, min));
-       udev_device_set_info_loaded(udev_device);
-       return udev_device;
-}
-
-int udev_monitor_send_device(struct udev_monitor *udev_monitor,
-                            struct udev_monitor *destination, struct udev_device *udev_device)
-{
-       struct msghdr smsg;
-       struct iovec iov[2];
-       const char *buf;
-       ssize_t blen;
-       ssize_t count;
-
-       blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
-       if (blen < 32)
-               return -1;
-
-       if (udev_monitor->sun.sun_family != 0) {
-               const char *action;
-               char header[2048];
-               char *s;
-
-               /* header <action>@<devpath> */
-               action = udev_device_get_action(udev_device);
-               if (action == NULL)
-                       return -EINVAL;
-               s = header;
-               if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
-                       return -EINVAL;
-               iov[0].iov_base = header;
-               iov[0].iov_len = (s - header)+1;
-
-               /* add properties list */
-               iov[1].iov_base = (char *)buf;
-               iov[1].iov_len = blen;
-
-               memset(&smsg, 0x00, sizeof(struct msghdr));
-               smsg.msg_iov = iov;
-               smsg.msg_iovlen = 2;
-               smsg.msg_name = &udev_monitor->sun;
-               smsg.msg_namelen = udev_monitor->addrlen;
-       } else if (udev_monitor->snl.nl_family != 0) {
-               const char *val;
-               struct udev_monitor_netlink_header nlh;
-
-
-               /* add versioned header */
-               memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header));
-               util_strscpy(nlh.version, sizeof(nlh.version), "udev-" VERSION);
-               nlh.magic = htonl(UDEV_MONITOR_MAGIC);
-               val = udev_device_get_subsystem(udev_device);
-               nlh.filter_subsystem = htonl(util_string_hash32(val));
-               val = udev_device_get_devtype(udev_device);
-               if (val != NULL)
-                       nlh.filter_devtype = htonl(util_string_hash32(val));
-               iov[0].iov_base = &nlh;
-               iov[0].iov_len = sizeof(struct udev_monitor_netlink_header);
-
-               /* add properties list */
-               nlh.properties_off = iov[0].iov_len;
-               nlh.properties_len = blen;
-               iov[1].iov_base = (char *)buf;
-               iov[1].iov_len = blen;
-
-               memset(&smsg, 0x00, sizeof(struct msghdr));
-               smsg.msg_iov = iov;
-               smsg.msg_iovlen = 2;
-               /*
-                * Use custom address for target, or the default one.
-                *
-                * If we send to a muticast group, we will get
-                * ECONNREFUSED, which is expected.
-                */
-               if (destination != NULL)
-                       smsg.msg_name = &destination->snl;
-               else
-                       smsg.msg_name = &udev_monitor->snl_destination;
-               smsg.msg_namelen = sizeof(struct sockaddr_nl);
-       } else {
-               return -1;
-       }
-
-       count = sendmsg(udev_monitor->sock, &smsg, 0);
-       info(udev_monitor->udev, "passed %zi bytes to monitor %p\n", count, udev_monitor);
-       return count;
-}
-
-int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
-{
-       if (udev_monitor == NULL)
-               return -EINVAL;
-       if (subsystem == NULL)
-               return 0;
-       if (udev_list_entry_add(udev_monitor->udev,
-                               &udev_monitor->filter_subsystem_list, subsystem, devtype, 0, 0) == NULL)
-               return -ENOMEM;
-       return 0;
-}
-
-int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
-{
-       static struct sock_fprog filter = { 0, NULL };
-
-       udev_list_cleanup_entries(udev_monitor->udev, &udev_monitor->filter_subsystem_list);
-       return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
-}
diff --git a/udev/lib/libudev-private.h b/udev/lib/libudev-private.h
deleted file mode 100644 (file)
index 5512341..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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.
- */
-
-#ifndef _LIBUDEV_PRIVATE_H_
-#define _LIBUDEV_PRIVATE_H_
-
-#include <syslog.h>
-#include "libudev.h"
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-static inline void __attribute__ ((format(printf, 2, 3)))
-udev_log_null(struct udev *udev, const char *format, ...) {}
-
-#ifdef USE_LOG
-#  ifdef DEBUG
-#    define dbg(udev, arg...) udev_log(udev, LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, ## arg)
-#  else
-#    define dbg(udev, arg...) udev_log_null(udev, ## arg)
-#  endif
-#  define info(udev, arg...) udev_log(udev, LOG_INFO, __FILE__, __LINE__, __FUNCTION__, ## arg)
-#  define err(udev, arg...) udev_log(udev, LOG_ERR, __FILE__, __LINE__, __FUNCTION__, ## arg)
-#else
-#  define dbg(udev, arg...) udev_log_null(udev, ## arg)
-#  define info(udev, arg...) udev_log_null(udev, ## arg)
-#  define err(udev, arg...) udev_log_null(udev, ## arg)
-#endif
-
-/* libudev */
-void udev_log(struct udev *udev,
-             int priority, const char *file, int line, const char *fn,
-             const char *format, ...)
-             __attribute__ ((format(printf, 6, 7)));
-struct udev_device *device_new(struct udev *udev);
-const char *udev_get_rules_path(struct udev *udev);
-int udev_get_run(struct udev *udev);
-struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
-struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
-
-/* libudev-device */
-int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
-int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem);
-int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype);
-int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
-int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink);
-void udev_device_cleanup_devlinks_list(struct udev_device *udev_device);
-struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
-struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property);
-char **udev_device_get_properties_envp(struct udev_device *udev_device);
-ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf);
-int udev_device_read_db(struct udev_device *udev_device);
-int udev_device_read_uevent_file(struct udev_device *udev_device);
-int udev_device_set_action(struct udev_device *udev_device, const char *action);
-int udev_device_set_driver(struct udev_device *udev_device, const char *driver);
-const char *udev_device_get_devpath_old(struct udev_device *udev_device);
-int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
-const char *udev_device_get_knodename(struct udev_device *udev_device);
-int udev_device_set_knodename(struct udev_device *udev_device, const char *knodename);
-int udev_device_get_timeout(struct udev_device *udev_device);
-int udev_device_set_timeout(struct udev_device *udev_device, int timeout);
-int udev_device_get_event_timeout(struct udev_device *udev_device);
-int udev_device_set_event_timeout(struct udev_device *udev_device, int event_timeout);
-int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum);
-int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum);
-int udev_device_get_num_fake_partitions(struct udev_device *udev_device);
-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);
-int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
-int udev_device_get_ignore_remove(struct udev_device *udev_device);
-int udev_device_set_ignore_remove(struct udev_device *udev_device, int ignore);
-int udev_device_get_watch_handle(struct udev_device *udev_device);
-int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
-void udev_device_set_info_loaded(struct udev_device *device);
-
-/* libudev-device-db-write.c */
-int udev_device_update_db(struct udev_device *udev_device);
-int udev_device_delete_db(struct udev_device *udev_device);
-int udev_device_rename_db(struct udev_device *udev_device, const char *devpath);
-
-/* libudev-monitor - netlink/unix socket communication  */
-int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
-int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender);
-int udev_monitor_send_device(struct udev_monitor *udev_monitor,
-                            struct udev_monitor *destination, struct udev_device *udev_device);
-int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
-
-/* libudev-ctrl - daemon runtime setup */
-struct udev_ctrl;
-struct udev_ctrl *udev_ctrl_new_from_socket(struct udev *udev, const char *socket_path);
-int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
-struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
-void udev_ctrl_unref(struct udev_ctrl *uctrl);
-struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority);
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl);
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl);
-int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl);
-int udev_ctrl_send_settle(struct udev_ctrl *uctrl);
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key);
-int udev_ctrl_send_set_max_childs(struct udev_ctrl *uctrl, int count);
-struct udev_ctrl_msg;
-struct udev_ctrl_msg *udev_ctrl_msg(struct udev_ctrl *uctrl);
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl *uctrl);
-struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg);
-void udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg);
-pid_t udev_ctrl_get_settle(struct udev_ctrl_msg *ctrl_msg);
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_max_childs(struct udev_ctrl_msg *ctrl_msg);
-
-/* libudev-list */
-struct udev_list_node {
-       struct udev_list_node *next, *prev;
-};
-void udev_list_init(struct udev_list_node *list);
-int udev_list_is_empty(struct udev_list_node *list);
-void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);
-void udev_list_node_remove(struct udev_list_node *entry);
-#define udev_list_node_foreach(node, list) \
-       for (node = (list)->next; \
-            node != list; \
-            node = (node)->next)
-#define udev_list_node_foreach_safe(node, tmp, list) \
-       for (node = (list)->next, tmp = (node)->next; \
-            node != list; \
-            node = tmp, tmp = (tmp)->next)
-struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list,
-                                                  const char *name, const char *value,
-                                                  int unique, int sort);
-void udev_list_entry_delete(struct udev_list_entry *entry);
-void udev_list_entry_remove(struct udev_list_entry *entry);
-void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
-void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list);
-void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *name_list);
-struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list);
-int udev_list_entry_get_flag(struct udev_list_entry *list_entry);
-void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag);
-#define udev_list_entry_foreach_safe(entry, tmp, first) \
-       for (entry = first, tmp = udev_list_entry_get_next(entry); \
-            entry != NULL; \
-            entry = tmp, tmp = udev_list_entry_get_next(tmp))
-
-/* libudev-queue */
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
-ssize_t udev_queue_skip_devpath(FILE *queue_file);
-
-/* libudev-queue-export */
-struct udev_queue_export *udev_queue_export_new(struct udev *udev);
-void udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
-void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
-int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-int udev_queue_export_device_failed(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
-
-/* libudev-utils */
-#define UTIL_PATH_SIZE                         1024
-#define UTIL_LINE_SIZE                         2048
-#define UTIL_NAME_SIZE                         512
-#define UDEV_ALLOWED_CHARS_INPUT               "/ $%?,"
-ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size);
-ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size);
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
-int util_log_priority(const char *priority);
-size_t util_path_encode(const char *src, char *dest, size_t size);
-size_t util_path_decode(char *s);
-void util_remove_trailing_chars(char *path, char c);
-size_t util_strpcpy(char **dest, size_t size, const char *src);
-size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__ ((sentinel));
-size_t util_strscpy(char *dest, size_t size, const char *src);
-size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__ ((sentinel));
-int udev_util_replace_whitespace(const char *str, char *to, size_t len);
-int udev_util_replace_chars(char *str, const char *white);
-int udev_util_encode_string(const char *str, char *str_enc, size_t len);
-void util_set_fd_cloexec(int fd);
-unsigned int util_string_hash32(const char *str);
-#endif
diff --git a/udev/lib/libudev-queue-export.c b/udev/lib/libudev-queue-export.c
deleted file mode 100644 (file)
index a36ff51..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * 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.
- */
-
-/*
- * DISCLAIMER - The file format mentioned here is private to udev/libudev,
- *              and may be changed without notice.
- *
- *
- * The udev event queue is exported as a binary log file.
- * Each log record consists of a sequence number followed by the device path.
- *
- * When a new event is queued, its details are appended to the log.
- * When the event finishes, a second record is appended to the log
- * with the same sequence number but a null devpath.
- *
- * Example:
- *     {1, "/devices/virtual/mem/null" },
- *     {2, "/devices/virtual/mem/zero" },
- *     {1, "" },
- * Event 2 is still queued, but event 1 has been finished
- *
- * The queue does not grow indefinitely.  It is periodically re-created
- * to remove finished events.  Atomic rename() makes this transparent to readers.
- *
- *
- * The queue file starts with a single sequence number which specifies the
- * minimum sequence number in the log that follows.  Any events prior to this
- * sequence number have already finished.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <assert.h>
-
-#include "udev.h"
-
-static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
-
-struct udev_queue_export {
-       struct udev *udev;
-       int failed_count;       /* number of failed events exported */
-       int queued_count;       /* number of unfinished events exported in queue file */
-       FILE *queue_file;
-       unsigned long long int seqnum_max;      /* earliest sequence number in queue file */
-       unsigned long long int seqnum_min;      /* latest sequence number in queue file */
-       int waste_bytes;                        /* queue file bytes wasted on finished events */
-};
-
-struct udev_queue_export *udev_queue_export_new(struct udev *udev)
-{
-       struct udev_queue_export *udev_queue_export;
-       unsigned long long int initial_seqnum;
-
-       if (udev == NULL)
-               return NULL;
-
-       udev_queue_export = calloc(1, sizeof(struct udev_queue_export));
-       if (udev_queue_export == NULL)
-               return NULL;
-       udev_queue_export->udev = udev;
-
-       initial_seqnum = udev_get_kernel_seqnum(udev);
-       udev_queue_export->seqnum_min = initial_seqnum;
-       udev_queue_export->seqnum_max = initial_seqnum;
-
-       udev_queue_export_cleanup(udev_queue_export);
-       if (rebuild_queue_file(udev_queue_export) != 0) {
-               free(udev_queue_export);
-               return NULL;
-       }
-
-       return udev_queue_export;
-}
-
-void udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
-{
-       if (udev_queue_export == NULL)
-               return;
-       if (udev_queue_export->queue_file != NULL)
-               fclose(udev_queue_export->queue_file);
-       free(udev_queue_export);
-}
-
-void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
-{
-       char filename[UTIL_PATH_SIZE];
-
-       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.tmp", NULL);
-       unlink(filename);
-
-       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.bin", NULL);
-       unlink(filename);
-}
-
-
-static int skip_to(FILE *file, long offset)
-{
-       long old_offset;
-
-       /* fseek may drop buffered data, avoid it for small seeks */
-       old_offset = ftell(file);
-       if (offset > old_offset && offset - old_offset <= BUFSIZ) {
-               size_t skip_bytes = offset - old_offset;
-               char buf[skip_bytes];
-
-               if (fread(buf, skip_bytes, 1, file) != skip_bytes)
-                       return -1;
-       }
-
-       return fseek(file, offset, SEEK_SET);
-}
-
-struct queue_devpaths {
-       unsigned int devpaths_first;    /* index of first queued event */
-       unsigned int devpaths_size;
-       long devpaths[];                /* seqnum -> offset of devpath in queue file (or 0) */
-};
-
-/*
- * Returns a table mapping seqnum to devpath file offset for currently queued events.
- * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
- */
-static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
-{
-       struct queue_devpaths *devpaths;
-       unsigned long long int range;
-       long devpath_offset;
-       ssize_t devpath_len;
-       unsigned long long int seqnum;
-       unsigned long long int n;
-       unsigned int i;
-
-       /* seek to the first event in the file */
-       rewind(udev_queue_export->queue_file);
-       udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
-
-       /* allocate the table */
-       range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
-       if (range - 1 > INT_MAX) {
-               err(udev_queue_export->udev, "queue file overflow\n");
-               return NULL;
-       }
-       devpaths = calloc(1, sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
-       if (index == NULL)
-               return NULL;
-       devpaths->devpaths_size = range + 1;
-
-       /* read all records and populate the table */
-       while(1) {
-               if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
-                       break;
-               n = seqnum - udev_queue_export->seqnum_max;
-               if (n >= devpaths->devpaths_size)
-                       goto read_error;
-
-               devpath_offset = ftell(udev_queue_export->queue_file);
-               devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
-               if (devpath_len < 0)
-                       goto read_error;
-
-               if (devpath_len > 0)
-                       devpaths->devpaths[n] = devpath_offset;
-               else
-                       devpaths->devpaths[n] = 0;
-       }
-
-       /* find first queued event */
-       for (i = 0; i < devpaths->devpaths_size; i++) {
-               if (devpaths->devpaths[i] != 0)
-                       break;
-       }
-       devpaths->devpaths_first = i;
-
-       return devpaths;
-
-read_error:
-       err(udev_queue_export->udev, "queue file corrupted\n");
-       free(devpaths);
-       return NULL;
-}
-
-static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
-{
-       unsigned long long int seqnum;
-       struct queue_devpaths *devpaths = NULL;
-       char filename[UTIL_PATH_SIZE];
-       char filename_tmp[UTIL_PATH_SIZE];
-       FILE *new_queue_file = NULL;
-       unsigned int i;
-
-       /* read old queue file */
-       if (udev_queue_export->queue_file != NULL) {
-               dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n",
-                                               udev_queue_export->waste_bytes);
-
-               devpaths = build_index(udev_queue_export);
-               if (devpaths != NULL)
-                       udev_queue_export->seqnum_max += devpaths->devpaths_first;
-       }
-       if (devpaths == NULL) {
-               dbg(udev_queue_export->udev, "creating empty queue file\n");
-               udev_queue_export->queued_count = 0;
-               udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
-       }
-
-       /* create new queue file */
-       util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.tmp", NULL);
-       new_queue_file = fopen(filename_tmp, "w+");
-       if (new_queue_file == NULL)
-               goto error;
-       seqnum = udev_queue_export->seqnum_max;
-       fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
-
-       /* copy unfinished events only to the new file */
-       if (devpaths != NULL) {
-               for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
-                       char devpath[UTIL_PATH_SIZE];
-                       int err;
-                       unsigned short devpath_len;
-
-                       if (devpaths->devpaths[i] != 0)
-                       {
-                               skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
-                               err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
-                               devpath_len = err;
-
-                               fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
-                               fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
-                               fwrite(devpath, 1, devpath_len, new_queue_file);
-                       }
-                       seqnum++;
-               }
-               free(devpaths);
-               devpaths = NULL;
-       }
-       fflush(new_queue_file);
-       if (ferror(new_queue_file))
-               goto error;
-
-       /* rename the new file on top of the old one */
-       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/queue.bin", NULL);
-       if (rename(filename_tmp, filename) != 0)
-               goto error;
-
-       if (udev_queue_export->queue_file != NULL)
-               fclose(udev_queue_export->queue_file);
-       udev_queue_export->queue_file = new_queue_file;
-       udev_queue_export->waste_bytes = 0;
-
-       return 0;
-
-error:
-       err(udev_queue_export->udev, "failed to create queue file: %m\n");
-       udev_queue_export_cleanup(udev_queue_export);
-
-       if (udev_queue_export->queue_file != NULL) {
-               fclose(udev_queue_export->queue_file);
-               udev_queue_export->queue_file = NULL;
-       }
-       if (new_queue_file != NULL)
-               fclose(new_queue_file);
-
-       if (devpaths != NULL)
-               free(devpaths);
-       udev_queue_export->queued_count = 0;
-       udev_queue_export->waste_bytes = 0;
-       udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
-
-       return -1;
-}
-
-static int write_queue_record(struct udev_queue_export *udev_queue_export,
-                             unsigned long long int seqnum, const char *devpath, size_t devpath_len)
-{
-       unsigned short len;
-
-       if (udev_queue_export->queue_file == NULL) {
-               dbg(udev_queue_export->udev, "can't record event: queue file not available\n");
-               return -1;
-       }
-
-       if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
-               goto write_error;
-
-       len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
-       if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
-               goto write_error;
-       if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
-               goto write_error;
-
-       /* *must* flush output; caller may fork */
-       if (fflush(udev_queue_export->queue_file) != 0)
-               goto write_error;
-
-       return 0;
-
-write_error:
-       /* if we failed half way through writing a record to a file,
-          we should not try to write any further records to it. */
-       err(udev_queue_export->udev, "error writing to queue file: %m\n");
-       fclose(udev_queue_export->queue_file);
-       udev_queue_export->queue_file = NULL;
-
-       return -1;
-}
-
-
-enum device_state {
-       DEVICE_QUEUED,
-       DEVICE_FINISHED,
-       DEVICE_FAILED,
-};
-
-static inline size_t queue_record_size(size_t devpath_len)
-{
-       return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
-}
-
-static int update_queue(struct udev_queue_export *udev_queue_export,
-                        struct udev_device *udev_device, enum device_state state)
-{
-       unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
-       const char *devpath = NULL;
-       size_t devpath_len = 0;
-       int bytes;
-       int err;
-
-       if (state == DEVICE_QUEUED) {
-               devpath = udev_device_get_devpath(udev_device);
-               devpath_len = strlen(devpath);
-       }
-
-       /* recover from an earlier failed rebuild */
-       if (udev_queue_export->queue_file == NULL) {
-               if (rebuild_queue_file(udev_queue_export) != 0)
-                       return -1;
-       }
-
-       /* when the queue files grow too large, they must be garbage collected and rebuilt */
-       bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
-
-       /* if we're removing the last event from the queue, that's the best time to rebuild it */
-       if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1 && bytes > 2048) {
-               /* because we don't need to read the old queue file */
-               fclose(udev_queue_export->queue_file);
-               udev_queue_export->queue_file = NULL;
-               rebuild_queue_file(udev_queue_export);
-               return 0;
-       }
-
-       /* try to rebuild the queue files before they grow larger than one page. */
-       if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
-               rebuild_queue_file(udev_queue_export);
-
-       /* don't record a finished event, if we already dropped the event in a failed rebuild */
-       if (seqnum < udev_queue_export->seqnum_max)
-               return 0;
-
-       /* now write to the queue */
-       if (state == DEVICE_QUEUED) {
-               udev_queue_export->queued_count++;
-               udev_queue_export->seqnum_min = seqnum;
-       } else {
-               udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
-               udev_queue_export->queued_count--;
-       }
-       err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
-
-       /* try to handle ENOSPC */
-       if (err != 0 && udev_queue_export->queued_count == 0) {
-               udev_queue_export_cleanup(udev_queue_export);
-               err = rebuild_queue_file(udev_queue_export);
-       }
-
-       return err;
-}
-
-static void update_failed(struct udev_queue_export *udev_queue_export,
-                         struct udev_device *udev_device, enum device_state state)
-{
-       struct udev *udev = udev_device_get_udev(udev_device);
-       char filename[UTIL_PATH_SIZE];
-       char *s;
-       size_t l;
-
-       if (state != DEVICE_FAILED && udev_queue_export->failed_count == 0)
-               return;
-
-       /* location of failed file */
-       s = filename;
-       l = util_strpcpyl(&s, sizeof(filename), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
-       util_path_encode(udev_device_get_devpath(udev_device), s, l);
-
-       switch (state) {
-       case DEVICE_FAILED:
-               /* record event in the failed directory */
-               if (udev_queue_export->failed_count == 0)
-                       util_create_path(udev, filename);
-               udev_queue_export->failed_count++;
-
-               udev_selinux_setfscreatecon(udev, filename, S_IFLNK);
-               symlink(udev_device_get_devpath(udev_device), filename);
-               udev_selinux_resetfscreatecon(udev);
-               break;
-
-       case DEVICE_QUEUED:
-               /* delete failed file */
-               if (unlink(filename) == 0) {
-                       util_delete_path(udev, filename);
-                       udev_queue_export->failed_count--;
-               }
-               break;
-
-       case DEVICE_FINISHED:
-               if (udev_device_get_devpath_old(udev_device) != NULL) {
-                       /* "move" event - rename failed file to current name, do not delete failed */
-                       char filename_old[UTIL_PATH_SIZE];
-
-                       s = filename_old;
-                       l = util_strpcpyl(&s, sizeof(filename_old), udev_get_dev_path(udev_queue_export->udev), "/.udev/failed/", NULL);
-                       util_path_encode(udev_device_get_devpath_old(udev_device), s, l);
-
-                       if (rename(filename_old, filename) == 0)
-                               info(udev, "renamed devpath, moved failed state of '%s' to %s'\n",
-                                    udev_device_get_devpath_old(udev_device), udev_device_get_devpath(udev_device));
-               }
-               break;
-       }
-
-       return;
-}
-
-static int update(struct udev_queue_export *udev_queue_export,
-                 struct udev_device *udev_device, enum device_state state)
-{
-       update_failed(udev_queue_export, udev_device, state);
-
-       if (update_queue(udev_queue_export, udev_device, state) != 0)
-               return -1;
-
-       return 0;
-}
-
-int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
-{
-       return update(udev_queue_export, udev_device, DEVICE_QUEUED);
-}
-
-int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
-{
-       return update(udev_queue_export, udev_device, DEVICE_FINISHED);
-}
-
-int udev_queue_export_device_failed(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
-{
-       return update(udev_queue_export, udev_device, DEVICE_FAILED);
-}
diff --git a/udev/lib/libudev-queue.c b/udev/lib/libudev-queue.c
deleted file mode 100644 (file)
index cf1ddf3..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-struct udev_queue {
-       struct udev *udev;
-       int refcount;
-       struct udev_list_node queue_list;
-       struct udev_list_node failed_list;
-};
-
-struct udev_queue *udev_queue_new(struct udev *udev)
-{
-       struct udev_queue *udev_queue;
-
-       if (udev == NULL)
-               return NULL;
-
-       udev_queue = calloc(1, sizeof(struct udev_queue));
-       if (udev_queue == NULL)
-               return NULL;
-       udev_queue->refcount = 1;
-       udev_queue->udev = udev;
-       udev_list_init(&udev_queue->queue_list);
-       udev_list_init(&udev_queue->failed_list);
-       return udev_queue;
-}
-
-struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
-{
-       if (udev_queue == NULL)
-               return NULL;
-       udev_queue->refcount++;
-       return udev_queue;
-}
-
-void udev_queue_unref(struct udev_queue *udev_queue)
-{
-       if (udev_queue == NULL)
-               return;
-       udev_queue->refcount--;
-       if (udev_queue->refcount > 0)
-               return;
-       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
-       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
-       free(udev_queue);
-}
-
-struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
-{
-       if (udev_queue == NULL)
-               return NULL;
-       return udev_queue->udev;
-}
-
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
-{
-       char filename[UTIL_PATH_SIZE];
-       unsigned long long int seqnum;
-       int fd;
-       char buf[32];
-       ssize_t len;
-
-       util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
-       fd = open(filename, O_RDONLY);
-       if (fd < 0)
-               return 0;
-       len = read(fd, buf, sizeof(buf));
-       close(fd);
-       if (len <= 2)
-               return 0;
-       buf[len-1] = '\0';
-       seqnum = strtoull(buf, NULL, 10);
-       return seqnum;
-}
-
-unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
-{
-       unsigned long long int seqnum;
-
-       if (udev_queue == NULL)
-               return -EINVAL;
-
-       seqnum = udev_get_kernel_seqnum(udev_queue->udev);
-       dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
-       return seqnum;
-}
-
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
-{
-       if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
-               return -1;
-
-       return 0;
-}
-
-ssize_t udev_queue_skip_devpath(FILE *queue_file)
-{
-       unsigned short int len;
-
-       if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
-               char devpath[len];
-
-               /* use fread to skip, fseek might drop buffered data */
-               if (fread(devpath, 1, len, queue_file) == len)
-                       return len;
-       }
-
-       return -1;
-}
-
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
-{
-       unsigned short int read_bytes = 0;
-       unsigned short int len;
-
-       if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
-               return -1;
-
-       read_bytes = (len < size - 1) ? len : size - 1;
-       if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
-               return -1;
-       devpath[read_bytes] = '\0';
-
-       /* if devpath was too long, skip unread characters */
-       if (read_bytes != len) {
-               unsigned short int skip_bytes = len - read_bytes;
-               char buf[skip_bytes];
-
-               if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
-                       return -1;
-       }
-
-       return read_bytes;
-}
-
-static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
-{
-       char filename[UTIL_PATH_SIZE];
-       FILE *queue_file;
-
-       util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL);
-       queue_file = fopen(filename, "r");
-       if (queue_file == NULL)
-               return NULL;
-
-       if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
-               err(udev_queue->udev, "corrupt queue file\n");
-               fclose(queue_file);
-               return NULL;
-       }
-
-       return queue_file;
-}
-
-
-unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
-{
-       unsigned long long int seqnum_udev;
-       FILE *queue_file;
-
-       queue_file = open_queue_file(udev_queue, &seqnum_udev);
-       if (queue_file == NULL)
-               return 0;
-
-       while (1) {
-               unsigned long long int seqnum;
-               ssize_t devpath_len;
-
-               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                       break;
-               devpath_len = udev_queue_skip_devpath(queue_file);
-               if (devpath_len < 0)
-                       break;
-               if (devpath_len > 0)
-                       seqnum_udev = seqnum;
-       }
-
-       fclose(queue_file);
-       return seqnum_udev;
-}
-
-int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
-{
-       unsigned long long int seqnum_start;
-       FILE *queue_file;
-
-       queue_file = open_queue_file(udev_queue, &seqnum_start);
-       if (queue_file == NULL)
-               return 0;
-
-       fclose(queue_file);
-       return 1;
-}
-
-int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
-{
-       unsigned long long int seqnum_kernel;
-       unsigned long long int seqnum_udev = 0;
-       int queued = 0;
-       int is_empty = 0;
-       FILE *queue_file;
-
-       if (udev_queue == NULL)
-               return -EINVAL;
-       queue_file = open_queue_file(udev_queue, &seqnum_udev);
-       if (queue_file == NULL)
-               return 1;
-
-       while (1) {
-               unsigned long long int seqnum;
-               ssize_t devpath_len;
-
-               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                       break;
-               devpath_len = udev_queue_skip_devpath(queue_file);
-               if (devpath_len < 0)
-                       break;
-
-               if (devpath_len > 0) {
-                       queued++;
-                       seqnum_udev = seqnum;
-               } else {
-                       queued--;
-               }
-       }
-
-       if (queued > 0) {
-               dbg(udev_queue->udev, "queue is not empty\n");
-               goto out;
-       }
-
-       seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
-       if (seqnum_udev < seqnum_kernel) {
-               dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
-                                       seqnum_kernel, seqnum_udev);
-               goto out;
-       }
-
-       dbg(udev_queue->udev, "queue is empty\n");
-       is_empty = 1;
-
-out:
-       fclose(queue_file);
-       return is_empty;
-}
-
-int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
-                                              unsigned long long int start, unsigned long long int end)
-{
-       unsigned long long int seqnum = 0;
-       ssize_t devpath_len;
-       int unfinished;
-       FILE *queue_file;
-
-       if (udev_queue == NULL)
-               return -EINVAL;
-       queue_file = open_queue_file(udev_queue, &seqnum);
-       if (queue_file == NULL)
-               return 1;
-       if (start < seqnum)
-               start = seqnum;
-       if (start > end)
-               return 1;
-       if (end - start > INT_MAX - 1)
-               return -EOVERFLOW;
-       unfinished = (end - start) + 1;
-
-       while (unfinished > 0) {
-               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                       break;
-               devpath_len = udev_queue_skip_devpath(queue_file);
-               if (devpath_len < 0)
-                       break;
-
-               if (devpath_len == 0) {
-                       if (seqnum >= start && seqnum <= end)
-                               unfinished--;
-               }
-       }
-       fclose(queue_file);
-
-       return (unfinished == 0);
-}
-
-int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
-{
-       if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
-               return 0;
-
-       dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
-       return 1;
-}
-
-struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
-{
-       unsigned long long int seqnum;
-       FILE *queue_file;
-
-       if (udev_queue == NULL)
-               return NULL;
-       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
-
-       queue_file = open_queue_file(udev_queue, &seqnum);
-       if (queue_file == NULL)
-               return NULL;
-
-       while (1) {
-               char syspath[UTIL_PATH_SIZE];
-               char *s;
-               size_t l;
-               ssize_t len;
-               char seqnum_str[32];
-               struct udev_list_entry *list_entry;
-
-               if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                       break;
-               snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
-
-               s = syspath;
-               l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
-               len = udev_queue_read_devpath(queue_file, s, l);
-               if (len < 0)
-                       break;
-
-               if (len > 0) {
-                       udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0, 0);
-               } else {
-                       udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
-                               if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
-                                       udev_list_entry_delete(list_entry);
-                                       break;
-                               }
-                       }
-               }
-       }
-       fclose(queue_file);
-
-       return udev_list_get_entry(&udev_queue->queue_list);
-}
-
-struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
-{
-       char path[UTIL_PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       if (udev_queue == NULL)
-               return NULL;
-       udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
-       util_strscpyl(path, sizeof(path), udev_get_dev_path(udev_queue->udev), "/.udev/failed", NULL);
-       dir = opendir(path);
-       if (dir == NULL)
-               return NULL;
-       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-               char filename[UTIL_PATH_SIZE];
-               char syspath[UTIL_PATH_SIZE];
-               char *s;
-               size_t l;
-               ssize_t len;
-               struct stat statbuf;
-
-               if (dent->d_name[0] == '.')
-                       continue;
-               s = syspath;
-               l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
-               len = readlinkat(dirfd(dir), dent->d_name, s, l);
-               if (len < 0 || (size_t)len >= l)
-                       continue;
-               s[len] = '\0';
-               dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name);
-               util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
-               if (stat(filename, &statbuf) != 0)
-                       continue;
-               udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0);
-       }
-       closedir(dir);
-       return udev_list_get_entry(&udev_queue->failed_list);
-}
diff --git a/udev/lib/libudev-util.c b/udev/lib/libudev-util.c
deleted file mode 100644 (file)
index dcc4a0f..0000000
+++ /dev/null
@@ -1,502 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-static ssize_t get_sys_link(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
-{
-       char path[UTIL_PATH_SIZE];
-       ssize_t len;
-       const char *pos;
-
-       util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
-       len = readlink(path, path, sizeof(path));
-       if (len < 0 || len >= (ssize_t) sizeof(path))
-               return -1;
-       path[len] = '\0';
-       pos = strrchr(path, '/');
-       if (pos == NULL)
-               return -1;
-       pos = &pos[1];
-       dbg(udev, "resolved link to: '%s'\n", pos);
-       return util_strscpy(value, size, pos);
-}
-
-ssize_t util_get_sys_subsystem(struct udev *udev, const char *syspath, char *subsystem, size_t size)
-{
-       return get_sys_link(udev, "subsystem", syspath, subsystem, size);
-}
-
-ssize_t util_get_sys_driver(struct udev *udev, const char *syspath, char *driver, size_t size)
-{
-       return get_sys_link(udev, "driver", syspath, driver, size);
-}
-
-int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
-{
-       char link_target[UTIL_PATH_SIZE];
-
-       int len;
-       int i;
-       int back;
-       char *base;
-
-       len = readlink(syspath, link_target, sizeof(link_target));
-       if (len <= 0)
-               return -1;
-       link_target[len] = '\0';
-       dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
-
-       for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
-               ;
-       dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
-       for (i = 0; i <= back; i++) {
-               base = strrchr(syspath, '/');
-               if (base == NULL)
-                       return -1;
-               base[0] = '\0';
-       }
-       dbg(udev, "after moving back '%s'\n", syspath);
-       util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
-       return 0;
-}
-
-int util_log_priority(const char *priority)
-{
-       char *endptr;
-       int prio;
-
-       prio = strtol(priority, &endptr, 10);
-       if (endptr[0] == '\0')
-               return prio;
-       if (strncmp(priority, "err", 3) == 0)
-               return LOG_ERR;
-       if (strcmp(priority, "info") == 0)
-               return LOG_INFO;
-       if (strcmp(priority, "debug") == 0)
-               return LOG_DEBUG;
-       return 0;
-}
-
-size_t util_path_encode(const char *src, char *dest, size_t size)
-{
-       size_t i, j;
-
-       for (i = 0, j = 0; src[i] != '\0'; i++) {
-               if (src[i] == '/') {
-                       if (j+4 >= size) {
-                               j = 0;
-                               break;
-                       }
-                       memcpy(&dest[j], "\\x2f", 4);
-                       j += 4;
-               } else if (src[i] == '\\') {
-                       if (j+4 >= size) {
-                               j = 0;
-                               break;
-                       }
-                       memcpy(&dest[j], "\\x5c", 4);
-                       j += 4;
-               } else {
-                       if (j+1 >= size) {
-                               j = 0;
-                               break;
-                       }
-                       dest[j] = src[i];
-                       j++;
-               }
-       }
-       dest[j] = '\0';
-       return j;
-}
-
-size_t util_path_decode(char *s)
-{
-       size_t i, j;
-
-       for (i = 0, j = 0; s[i] != '\0'; j++) {
-               if (memcmp(&s[i], "\\x2f", 4) == 0) {
-                       s[j] = '/';
-                       i += 4;
-               } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
-                       s[j] = '\\';
-                       i += 4;
-               } else {
-                       s[j] = s[i];
-                       i++;
-               }
-       }
-       s[j] = '\0';
-       return j;
-}
-
-void util_remove_trailing_chars(char *path, char c)
-{
-       size_t len;
-
-       if (path == NULL)
-               return;
-       len = strlen(path);
-       while (len > 0 && path[len-1] == c)
-               path[--len] = '\0';
-}
-
-/*
- * Concatenates strings. In any case, terminates in _all_ cases with '\0'
- * and moves the @dest pointer forward to the added '\0'. Returns the
- * remaining size, and 0 if the string was truncated.
- */
-size_t util_strpcpy(char **dest, size_t size, const char *src)
-{
-       size_t len;
-
-       len = strlen(src);
-       if (len >= size) {
-               if (size > 1)
-                       *dest = mempcpy(*dest, src, size-1);
-               size = 0;
-               *dest[0] = '\0';
-       } else {
-               if (len > 0) {
-                       *dest = mempcpy(*dest, src, len);
-                       size -= len;
-               }
-               *dest[0] = '\0';
-       }
-       return size;
-}
-
-/* concatenates list of strings, moves dest forward */
-size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
-{
-       va_list va;
-
-       va_start(va, src);
-       do {
-               size = util_strpcpy(dest, size, src);
-               src = va_arg(va, char *);
-       } while (src != NULL);
-       va_end(va);
-
-       return size;
-}
-
-/* copies string */
-size_t util_strscpy(char *dest, size_t size, const char *src)
-{
-       char *s;
-
-       s = dest;
-       return util_strpcpy(&s, size, src);
-}
-
-/* concatenates list of strings */
-size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
-{
-       va_list va;
-       char *s;
-
-       va_start(va, src);
-       s = dest;
-       do {
-               size = util_strpcpy(&s, size, src);
-               src = va_arg(va, char *);
-       } while (src != NULL);
-       va_end(va);
-
-       return size;
-}
-
-/* count of characters used to encode one unicode char */
-static int utf8_encoded_expected_len(const char *str)
-{
-       unsigned char c = (unsigned char)str[0];
-
-       if (c < 0x80)
-               return 1;
-       if ((c & 0xe0) == 0xc0)
-               return 2;
-       if ((c & 0xf0) == 0xe0)
-               return 3;
-       if ((c & 0xf8) == 0xf0)
-               return 4;
-       if ((c & 0xfc) == 0xf8)
-               return 5;
-       if ((c & 0xfe) == 0xfc)
-               return 6;
-       return 0;
-}
-
-/* decode one unicode char */
-static int utf8_encoded_to_unichar(const char *str)
-{
-       int unichar;
-       int len;
-       int i;
-
-       len = utf8_encoded_expected_len(str);
-       switch (len) {
-       case 1:
-               return (int)str[0];
-       case 2:
-               unichar = str[0] & 0x1f;
-               break;
-       case 3:
-               unichar = (int)str[0] & 0x0f;
-               break;
-       case 4:
-               unichar = (int)str[0] & 0x07;
-               break;
-       case 5:
-               unichar = (int)str[0] & 0x03;
-               break;
-       case 6:
-               unichar = (int)str[0] & 0x01;
-               break;
-       default:
-               return -1;
-       }
-
-       for (i = 1; i < len; i++) {
-               if (((int)str[i] & 0xc0) != 0x80)
-                       return -1;
-               unichar <<= 6;
-               unichar |= (int)str[i] & 0x3f;
-       }
-
-       return unichar;
-}
-
-/* expected size used to encode one unicode char */
-static int utf8_unichar_to_encoded_len(int unichar)
-{
-       if (unichar < 0x80)
-               return 1;
-       if (unichar < 0x800)
-               return 2;
-       if (unichar < 0x10000)
-               return 3;
-       if (unichar < 0x200000)
-               return 4;
-       if (unichar < 0x4000000)
-               return 5;
-       return 6;
-}
-
-/* check if unicode char has a valid numeric range */
-static int utf8_unichar_valid_range(int unichar)
-{
-       if (unichar > 0x10ffff)
-               return 0;
-       if ((unichar & 0xfffff800) == 0xd800)
-               return 0;
-       if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
-               return 0;
-       if ((unichar & 0xffff) == 0xffff)
-               return 0;
-       return 1;
-}
-
-/* validate one encoded unicode char and return its length */
-static int utf8_encoded_valid_unichar(const char *str)
-{
-       int len;
-       int unichar;
-       int i;
-
-       len = utf8_encoded_expected_len(str);
-       if (len == 0)
-               return -1;
-
-       /* ascii is valid */
-       if (len == 1)
-               return 1;
-
-       /* check if expected encoded chars are available */
-       for (i = 0; i < len; i++)
-               if ((str[i] & 0x80) != 0x80)
-                       return -1;
-
-       unichar = utf8_encoded_to_unichar(str);
-
-       /* check if encoded length matches encoded value */
-       if (utf8_unichar_to_encoded_len(unichar) != len)
-               return -1;
-
-       /* check if value has valid range */
-       if (!utf8_unichar_valid_range(unichar))
-               return -1;
-
-       return len;
-}
-
-int udev_util_replace_whitespace(const char *str, char *to, size_t len)
-{
-       size_t i, j;
-
-       /* strip trailing whitespace */
-       len = strnlen(str, len);
-       while (len && isspace(str[len-1]))
-               len--;
-
-       /* strip leading whitespace */
-       i = 0;
-       while (isspace(str[i]) && (i < len))
-               i++;
-
-       j = 0;
-       while (i < len) {
-               /* substitute multiple whitespace with a single '_' */
-               if (isspace(str[i])) {
-                       while (isspace(str[i]))
-                               i++;
-                       to[j++] = '_';
-               }
-               to[j++] = str[i++];
-       }
-       to[j] = '\0';
-       return 0;
-}
-
-static int is_whitelisted(char c, const char *white)
-{
-       if ((c >= '0' && c <= '9') ||
-           (c >= 'A' && c <= 'Z') ||
-           (c >= 'a' && c <= 'z') ||
-           strchr("#+-.:=@_", c) != NULL ||
-           (white != NULL && strchr(white, c) != NULL))
-               return 1;
-       return 0;
-}
-
-/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
-int udev_util_replace_chars(char *str, const char *white)
-{
-       size_t i = 0;
-       int replaced = 0;
-
-       while (str[i] != '\0') {
-               int len;
-
-               if (is_whitelisted(str[i], white)) {
-                       i++;
-                       continue;
-               }
-
-               /* accept hex encoding */
-               if (str[i] == '\\' && str[i+1] == 'x') {
-                       i += 2;
-                       continue;
-               }
-
-               /* accept valid utf8 */
-               len = utf8_encoded_valid_unichar(&str[i]);
-               if (len > 1) {
-                       i += len;
-                       continue;
-               }
-
-               /* if space is allowed, replace whitespace with ordinary space */
-               if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
-                       str[i] = ' ';
-                       i++;
-                       replaced++;
-                       continue;
-               }
-
-               /* everything else is replaced with '_' */
-               str[i] = '_';
-               i++;
-               replaced++;
-       }
-       return replaced;
-}
-
-/**
- * util_encode_string:
- * @str: input string to be encoded
- * @str_enc: output string to store the encoded input string
- * @len: maximum size of the output string, which may be
- *       four times as long as the input string
- *
- * Encode all potentially unsafe characters of a string to the
- * corresponding hex value prefixed by '\x'.
- *
- * Returns: 0 if the entire string was copied, non-zero otherwise.
- **/
-int udev_util_encode_string(const char *str, char *str_enc, size_t len)
-{
-       size_t i, j;
-
-       if (str == NULL || str_enc == NULL || len == 0)
-               return -1;
-
-       str_enc[0] = '\0';
-       for (i = 0, j = 0; str[i] != '\0'; i++) {
-               int seqlen;
-
-               seqlen = utf8_encoded_valid_unichar(&str[i]);
-               if (seqlen > 1) {
-                       memcpy(&str_enc[j], &str[i], seqlen);
-                       j += seqlen;
-                       i += (seqlen-1);
-               } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
-                       sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
-                       j += 4;
-               } else {
-                       str_enc[j] = str[i];
-                       j++;
-               }
-               if (j+3 >= len)
-                       goto err;
-       }
-       str_enc[j] = '\0';
-       return 0;
-err:
-       return -1;
-}
-
-void util_set_fd_cloexec(int fd)
-{
-       int flags;
-
-       flags = fcntl(fd, F_GETFD);
-       if (flags < 0)
-               flags = FD_CLOEXEC;
-       else
-               flags |= FD_CLOEXEC;
-       fcntl(fd, F_SETFD, flags);
-}
-
-unsigned int util_string_hash32(const char *str)
-{
-       unsigned int hash = 0;
-
-       while (str[0] != '\0') {
-               hash += str[0] << 4;
-               hash += str[0] >> 4;
-               hash *= 11;
-               str++;
-       }
-       return hash;
-}
diff --git a/udev/lib/libudev.c b/udev/lib/libudev.c
deleted file mode 100644 (file)
index a9baa70..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <ctype.h>
-
-#include "libudev.h"
-#include "libudev-private.h"
-
-struct udev {
-       int refcount;
-       void (*log_fn)(struct udev *udev,
-                      int priority, const char *file, int line, const char *fn,
-                      const char *format, va_list args);
-       void *userdata;
-       char *sys_path;
-       char *dev_path;
-       char *rules_path;
-       struct udev_list_node properties_list;
-       int log_priority;
-       int run;
-};
-
-void udev_log(struct udev *udev,
-             int priority, const char *file, int line, const char *fn,
-             const char *format, ...)
-{
-       va_list args;
-
-       if (priority > udev->log_priority)
-               return;
-
-       va_start(args, format);
-       udev->log_fn(udev, priority, file, line, fn, format, args);
-       va_end(args);
-}
-
-static void log_stderr(struct udev *udev,
-                      int priority, const char *file, int line, const char *fn,
-                      const char *format, va_list args)
-{
-       fprintf(stderr, "libudev: %s: ", fn);
-       vfprintf(stderr, format, args);
-}
-
-void *udev_get_userdata(struct udev *udev)
-{
-       if (udev == NULL)
-               return NULL;
-       return udev->userdata;
-}
-
-void udev_set_userdata(struct udev *udev, void *userdata)
-{
-       if (udev == NULL)
-               return;
-       udev->userdata = userdata;
-}
-
-/**
- * udev_new:
- *
- * Create udev library context.
- *
- * The initial refcount is 1, and needs to be decremented to
- * release the resources of the udev library context.
- *
- * Returns: a new udev library context
- **/
-struct udev *udev_new(void)
-{
-       struct udev *udev;
-       const char *env;
-       char *config_file;
-       FILE *f;
-
-       udev = calloc(1, sizeof(struct udev));
-       if (udev == NULL)
-               return NULL;
-       udev->refcount = 1;
-       udev->log_fn = log_stderr;
-       udev->log_priority = LOG_ERR;
-       udev_list_init(&udev->properties_list);
-       udev->run = 1;
-       udev->dev_path = strdup(UDEV_PREFIX "/dev");
-       udev->sys_path = strdup("/sys");
-       config_file = strdup(SYSCONFDIR "/udev/udev.conf");
-       if (udev->dev_path == NULL ||
-           udev->sys_path == NULL ||
-           config_file == NULL)
-               goto err;
-
-       /* settings by environment and config file */
-       env = getenv("SYSFS_PATH");
-       if (env != NULL) {
-               free(udev->sys_path);
-               udev->sys_path = strdup(env);
-               util_remove_trailing_chars(udev->sys_path, '/');
-               udev_add_property(udev, "SYSFS_PATH", udev->sys_path);
-       }
-
-       env = getenv("UDEV_RUN");
-       if (env != NULL && strcmp(env, "0") == 0)
-               udev->run = 0;
-
-       env = getenv("UDEV_CONFIG_FILE");
-       if (env != NULL) {
-               free(config_file);
-               config_file = strdup(env);
-               util_remove_trailing_chars(config_file, '/');
-       }
-       if (config_file == NULL)
-               goto err;
-       f = fopen(config_file, "r");
-       if (f != NULL) {
-               char line[UTIL_LINE_SIZE];
-               int line_nr = 0;
-
-               while (fgets(line, sizeof(line), f)) {
-                       size_t len;
-                       char *key;
-                       char *val;
-
-                       line_nr++;
-
-                       /* find key */
-                       key = line;
-                       while (isspace(key[0]))
-                               key++;
-
-                       /* comment or empty line */
-                       if (key[0] == '#' || key[0] == '\0')
-                               continue;
-
-                       /* split key/value */
-                       val = strchr(key, '=');
-                       if (val == NULL) {
-                               err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, line_nr);
-                               continue;
-                       }
-                       val[0] = '\0';
-                       val++;
-
-                       /* find value */
-                       while (isspace(val[0]))
-                               val++;
-
-                       /* terminate key */
-                       len = strlen(key);
-                       if (len == 0)
-                               continue;
-                       while (isspace(key[len-1]))
-                               len--;
-                       key[len] = '\0';
-
-                       /* terminate value */
-                       len = strlen(val);
-                       if (len == 0)
-                               continue;
-                       while (isspace(val[len-1]))
-                               len--;
-                       val[len] = '\0';
-
-                       if (len == 0)
-                               continue;
-
-                       /* unquote */
-                       if (val[0] == '"' || val[0] == '\'') {
-                               if (val[len-1] != val[0]) {
-                                       err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
-                                       continue;
-                               }
-                               val[len-1] = '\0';
-                               val++;
-                       }
-
-                       if (strcmp(key, "udev_log") == 0) {
-                               udev_set_log_priority(udev, util_log_priority(val));
-                               continue;
-                       }
-                       if (strcmp(key, "udev_root") == 0) {
-                               free(udev->dev_path);
-                               udev->dev_path = strdup(val);
-                               util_remove_trailing_chars(udev->dev_path, '/');
-                               continue;
-                       }
-                       if (strcmp(key, "udev_rules") == 0) {
-                               free(udev->rules_path);
-                               udev->rules_path = strdup(val);
-                               util_remove_trailing_chars(udev->rules_path, '/');
-                               continue;
-                       }
-               }
-               fclose(f);
-       }
-
-       env = getenv("UDEV_ROOT");
-       if (env != NULL) {
-               free(udev->dev_path);
-               udev->dev_path = strdup(env);
-               util_remove_trailing_chars(udev->dev_path, '/');
-               udev_add_property(udev, "UDEV_ROOT", udev->dev_path);
-       }
-
-       env = getenv("UDEV_LOG");
-       if (env != NULL)
-               udev_set_log_priority(udev, util_log_priority(env));
-
-       if (udev->dev_path == NULL || udev->sys_path == NULL)
-               goto err;
-       dbg(udev, "context %p created\n", udev);
-       dbg(udev, "log_priority=%d\n", udev->log_priority);
-       dbg(udev, "config_file='%s'\n", config_file);
-       dbg(udev, "dev_path='%s'\n", udev->dev_path);
-       dbg(udev, "sys_path='%s'\n", udev->sys_path);
-       if (udev->rules_path != NULL)
-               dbg(udev, "rules_path='%s'\n", udev->rules_path);
-       free(config_file);
-       return udev;
-err:
-       free(config_file);
-       err(udev, "context creation failed\n");
-       udev_unref(udev);
-       return NULL;
-}
-
-/**
- * udev_ref:
- * @udev: udev library context
- *
- * Take a reference of the udev library context.
- *
- * Returns: the passed udev library context
- **/
-struct udev *udev_ref(struct udev *udev)
-{
-       if (udev == NULL)
-               return NULL;
-       udev->refcount++;
-       return udev;
-}
-
-/**
- * udev_unref:
- * @udev: udev library context
- *
- * Drop a reference of the udev library context. If the refcount
- * reaches zero, the resources of the context will be released.
- *
- **/
-void udev_unref(struct udev *udev)
-{
-       if (udev == NULL)
-               return;
-       udev->refcount--;
-       if (udev->refcount > 0)
-               return;
-       udev_list_cleanup_entries(udev, &udev->properties_list);
-       free(udev->dev_path);
-       free(udev->sys_path);
-       free(udev->rules_path);
-       dbg(udev, "context %p released\n", udev);
-       free(udev);
-}
-
-/**
- * udev_set_log_fn:
- * @udev: udev library context
- * @log_fn: function to be called for logging messages
- *
- * The built-in logging writes to stderr. It can be
- * overridden by a custom function, to plug log messages
- * into the users' logging functionality.
- *
- **/
-void udev_set_log_fn(struct udev *udev,
-                    void (*log_fn)(struct udev *udev,
-                                   int priority, const char *file, int line, const char *fn,
-                                   const char *format, va_list args))
-{
-       udev->log_fn = log_fn;
-       info(udev, "custom logging function %p registered\n", udev);
-}
-
-int udev_get_log_priority(struct udev *udev)
-{
-       return udev->log_priority;
-}
-
-void udev_set_log_priority(struct udev *udev, int priority)
-{
-       char num[32];
-
-       udev->log_priority = priority;
-       snprintf(num, sizeof(num), "%u", udev->log_priority);
-       udev_add_property(udev, "UDEV_LOG", num);
-}
-
-const char *udev_get_rules_path(struct udev *udev)
-{
-       return udev->rules_path;
-}
-
-int udev_get_run(struct udev *udev)
-{
-       return udev->run;
-}
-
-/**
- * udev_get_sys_path:
- * @udev: udev library context
- *
- * Retrieve the sysfs mount point. The default is "/sys". For
- * testing purposes, it can be overridden with the environment
- * variable SYSFS_PATH.
- *
- * Returns: the sys mount point
- **/
-const char *udev_get_sys_path(struct udev *udev)
-{
-       if (udev == NULL)
-               return NULL;
-       return udev->sys_path;
-}
-
-/**
- * udev_get_dev_path:
- * @udev: udev library context
- *
- * Retrieve the device directory path. The default value is "/dev",
- * the actual value may be overridden in the udev configuration
- * file.
- *
- * Returns: the device directory path
- **/
-const char *udev_get_dev_path(struct udev *udev)
-{
-       if (udev == NULL)
-               return NULL;
-       return udev->dev_path;
-}
-
-struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
-{
-       if (value == NULL) {
-               struct udev_list_entry *list_entry;
-
-               list_entry = udev_get_properties_list_entry(udev);
-               list_entry = udev_list_entry_get_by_name(list_entry, key);
-               if (list_entry != NULL)
-                       udev_list_entry_delete(list_entry);
-               return NULL;
-       }
-       return udev_list_entry_add(udev, &udev->properties_list, key, value, 1, 0);
-}
-
-struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
-{
-       return udev_list_get_entry(&udev->properties_list);
-}
diff --git a/udev/lib/libudev.h b/udev/lib/libudev.h
deleted file mode 100644 (file)
index 241091c..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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.
- */
-
-#ifndef _LIBUDEV_H_
-#define _LIBUDEV_H_
-
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-/* this will stay as long as the DeviceKit integration of udev is work in progress */
-#if !defined _LIBUDEV_COMPILATION && !defined LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
-#error "#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE is needed to use this experimental library version"
-#endif
-
-/*
- * udev - library context
- * 
- * reads the udev config and system environment
- * allows custom logging
- */
-struct udev;
-struct udev *udev_ref(struct udev *udev);
-void udev_unref(struct udev *udev);
-struct udev *udev_new(void);
-void udev_set_log_fn(struct udev *udev,
-                           void (*log_fn)(struct udev *udev,
-                                          int priority, const char *file, int line, const char *fn,
-                                          const char *format, va_list args));
-int udev_get_log_priority(struct udev *udev);
-void udev_set_log_priority(struct udev *udev, int priority);
-const char *udev_get_sys_path(struct udev *udev);
-const char *udev_get_dev_path(struct udev *udev);
-void *udev_get_userdata(struct udev *udev);
-void udev_set_userdata(struct udev *udev, void *userdata);
-
-/*
- * udev_list
- *
- * access to libudev generated lists
- */
-struct udev_list_entry;
-struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
-struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
-const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
-const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
-#define udev_list_entry_foreach(entry, first) \
-       for (entry = first; \
-            entry != NULL; \
-            entry = udev_list_entry_get_next(entry))
-
-/*
- * udev_device
- *
- * access to sysfs/kernel devices
- */
-struct udev_device;
-struct udev_device *udev_device_ref(struct udev_device *udev_device);
-void udev_device_unref(struct udev_device *udev_device);
-struct udev *udev_device_get_udev(struct udev_device *udev_device);
-struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
-struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
-struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
-/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
-struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
-struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
-                                                                 const char *subsystem, const char *devtype);
-/* retrieve device properties */
-const char *udev_device_get_devpath(struct udev_device *udev_device);
-const char *udev_device_get_subsystem(struct udev_device *udev_device);
-const char *udev_device_get_devtype(struct udev_device *udev_device);
-const char *udev_device_get_syspath(struct udev_device *udev_device);
-const char *udev_device_get_sysname(struct udev_device *udev_device);
-const char *udev_device_get_sysnum(struct udev_device *udev_device);
-const char *udev_device_get_devnode(struct udev_device *udev_device);
-struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
-struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
-const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
-const char *udev_device_get_driver(struct udev_device *udev_device);
-dev_t udev_device_get_devnum(struct udev_device *udev_device);
-const char *udev_device_get_action(struct udev_device *udev_device);
-unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
-const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
-
-/*
- * udev_monitor
- *
- * access to kernel uevents and udev events
- */
-struct udev_monitor;
-struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
-void udev_monitor_unref(struct udev_monitor *udev_monitor);
-struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
-/* kernel and udev generated events over netlink */
-struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
-/* custom socket (use netlink and filters instead) */
-struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
-/* bind socket */
-int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
-int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
-struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
-/* in-kernel socket filters to select messages that get delivered to a listener */
-int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
-                                                   const char *subsystem, const char *devtype);
-int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
-int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
-
-/*
- * udev_enumerate
- *
- * search sysfs for specific devices and provide a sorted list
- */
-struct udev_enumerate;
-struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
-void udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
-struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
-struct udev_enumerate *udev_enumerate_new(struct udev *udev);
-/* device properties filter */
-int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
-int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
-int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
-int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
-int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
-int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
-/* run enumeration with active filters */
-int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
-int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
-/* return device list */
-struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
-
-/*
- * udev_queue
- *
- * access to the currently running udev events
- */
-struct udev_queue;
-struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
-void udev_queue_unref(struct udev_queue *udev_queue);
-struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
-struct udev_queue *udev_queue_new(struct udev *udev);
-unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
-unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
-int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
-int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
-int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
-int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
-                                              unsigned long long int start, unsigned long long int end);
-struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
-struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
-#endif
diff --git a/udev/lib/libudev.pc.in b/udev/lib/libudev.pc.in
deleted file mode 100644 (file)
index 38fc052..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-prefix=@prefix@
-exec_prefix=@prefix@
-libdir=@prefix@/@libdir_name@
-includedir=@prefix@/include
-
-Name: libudev
-Description: Library to access udev device information
-Version: @VERSION@
-Libs: -L${libdir} -ludev
-Libs.private: 
-Cflags: -I${includedir}
diff --git a/udev/lib/test-libudev.c b/udev/lib/test-libudev.c
deleted file mode 100644 (file)
index db08d48..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * test-libudev
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- *
- * 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>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <syslog.h>
-#include <fcntl.h>
-#include <sys/select.h>
-
-#include "libudev.h"
-
-static void log_fn(struct udev *udev,
-                  int priority, const char *file, int line, const char *fn,
-                  const char *format, va_list args)
-{
-       printf("test-libudev: %s %s:%d ", fn, file, line);
-       vprintf(format, args);
-}
-
-static void print_device(struct udev_device *device)
-{
-       const char *str;
-       dev_t devnum;
-       int count;
-       struct udev_list_entry *list_entry;
-
-       printf("*** device: %p ***\n", device);
-       str = udev_device_get_action(device);
-       if (str != NULL)
-               printf("action:    '%s'\n", str);
-
-       str = udev_device_get_syspath(device);
-       printf("syspath:   '%s'\n", str);
-
-       str = udev_device_get_sysname(device);
-       printf("sysname:   '%s'\n", str);
-
-       str = udev_device_get_sysnum(device);
-       if (str != NULL)
-               printf("sysnum:    '%s'\n", str);
-
-       str = udev_device_get_devpath(device);
-       printf("devpath:   '%s'\n", str);
-
-       str = udev_device_get_subsystem(device);
-       if (str != NULL)
-               printf("subsystem: '%s'\n", str);
-
-       str = udev_device_get_devtype(device);
-       if (str != NULL)
-               printf("devtype:   '%s'\n", str);
-
-       str = udev_device_get_driver(device);
-       if (str != NULL)
-               printf("driver:    '%s'\n", str);
-
-       str = udev_device_get_devnode(device);
-       if (str != NULL)
-               printf("devname:   '%s'\n", str);
-
-       devnum = udev_device_get_devnum(device);
-       if (major(devnum) > 0)
-               printf("devnum:    %u:%u\n", major(devnum), minor(devnum));
-
-       count = 0;
-       udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
-               printf("link:      '%s'\n", udev_list_entry_get_name(list_entry));
-               count++;
-       }
-       if (count > 0)
-               printf("found %i links\n", count);
-
-       count = 0;
-       udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
-               printf("property:  '%s=%s'\n",
-                      udev_list_entry_get_name(list_entry),
-                      udev_list_entry_get_value(list_entry));
-               count++;
-       }
-       if (count > 0)
-               printf("found %i properties\n", count);
-
-       str = udev_device_get_property_value(device, "MAJOR");
-       if (str != NULL)
-               printf("MAJOR: '%s'\n", str);
-
-       str = udev_device_get_sysattr_value(device, "dev");
-       if (str != NULL)
-               printf("attr{dev}: '%s'\n", str);
-
-       printf("\n");
-}
-
-static int test_device(struct udev *udev, const char *syspath)
-{
-       struct udev_device *device;
-
-       printf("looking at device: %s\n", syspath);
-       device = udev_device_new_from_syspath(udev, syspath);
-       if (device == NULL) {
-               printf("no device found\n");
-               return -1;
-       }
-       print_device(device);
-       udev_device_unref(device);
-       return 0;
-}
-
-static int test_device_parents(struct udev *udev, const char *syspath)
-{
-       struct udev_device *device;
-       struct udev_device *device_parent;
-
-       printf("looking at device: %s\n", syspath);
-       device = udev_device_new_from_syspath(udev, syspath);
-       if (device == NULL)
-               return -1;
-
-       printf("looking at parents\n");
-       device_parent = device;
-       do {
-               print_device(device_parent);
-               device_parent = udev_device_get_parent(device_parent);
-       } while (device_parent != NULL);
-
-       printf("looking at parents again\n");
-       device_parent = device;
-       do {
-               print_device(device_parent);
-               device_parent = udev_device_get_parent(device_parent);
-       } while (device_parent != NULL);
-       udev_device_unref(device);
-
-       return 0;
-}
-
-static int test_device_devnum(struct udev *udev)
-{
-       dev_t devnum = makedev(1, 3);
-       struct udev_device *device;
-
-       printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
-       device = udev_device_new_from_devnum(udev, 'c', devnum);
-       if (device == NULL)
-               return -1;
-       print_device(device);
-       udev_device_unref(device);
-       return 0;
-}
-
-static int test_device_subsys_name(struct udev *udev)
-{
-       struct udev_device *device;
-
-       printf("looking up device: 'block':'sda'\n");
-       device = udev_device_new_from_subsystem_sysname(udev, "block", "sda");
-       if (device == NULL)
-               return -1;
-       print_device(device);
-       udev_device_unref(device);
-
-       printf("looking up device: 'subsystem':'pci'\n");
-       device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
-       if (device == NULL)
-               return -1;
-       print_device(device);
-       udev_device_unref(device);
-
-       printf("looking up device: 'drivers':'scsi:sd'\n");
-       device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd");
-       if (device == NULL)
-               return -1;
-       print_device(device);
-       udev_device_unref(device);
-
-       printf("looking up device: 'module':'printk'\n");
-       device = udev_device_new_from_subsystem_sysname(udev, "module", "printk");
-       if (device == NULL)
-               return -1;
-       print_device(device);
-       udev_device_unref(device);
-       return 0;
-}
-
-static int test_enumerate_print_list(struct udev_enumerate *enumerate)
-{
-       struct udev_list_entry *list_entry;
-       int count = 0;
-
-       udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
-               struct udev_device *device;
-
-               device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
-                                                     udev_list_entry_get_name(list_entry));
-               if (device != NULL) {
-                       printf("device: '%s' (%s)\n",
-                              udev_device_get_syspath(device),
-                              udev_device_get_subsystem(device));
-                       udev_device_unref(device);
-                       count++;
-               }
-       }
-       printf("found %i devices\n\n", count);
-       return count;
-}
-
-static int test_monitor(struct udev *udev)
-{
-       struct udev_monitor *udev_monitor;
-       fd_set readfds;
-       int fd;
-
-       udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
-       if (udev_monitor == NULL) {
-               printf("no socket\n");
-               return -1;
-       }
-       if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 ||
-           udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 ||
-           udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) {
-               printf("filter failed\n");
-               return -1;
-       }
-       if (udev_monitor_enable_receiving(udev_monitor) < 0) {
-               printf("bind failed\n");
-               return -1;
-       }
-
-       fd = udev_monitor_get_fd(udev_monitor);
-       FD_ZERO(&readfds);
-
-       while (1) {
-               struct udev_device *device;
-               int fdcount;
-
-               FD_SET(STDIN_FILENO, &readfds);
-               FD_SET(fd, &readfds);
-
-               printf("waiting for events from udev, press ENTER to exit\n");
-               fdcount = select(fd+1, &readfds, NULL, NULL, NULL);
-               printf("select fd count: %i\n", fdcount);
-
-               if (FD_ISSET(fd, &readfds)) {
-                       device = udev_monitor_receive_device(udev_monitor);
-                       if (device == NULL) {
-                               printf("no device from socket\n");
-                               continue;
-                       }
-                       print_device(device);
-                       udev_device_unref(device);
-               }
-
-               if (FD_ISSET(STDIN_FILENO, &readfds)) {
-                       printf("exiting loop\n");
-                       break;
-               }
-       }
-
-       udev_monitor_unref(udev_monitor);
-       return 0;
-}
-
-static int test_queue(struct udev *udev)
-{
-       struct udev_queue *udev_queue;
-       unsigned long long int seqnum;
-       struct udev_list_entry *list_entry;
-
-       udev_queue = udev_queue_new(udev);
-       if (udev_queue == NULL)
-               return -1;
-       seqnum = udev_queue_get_kernel_seqnum(udev_queue);
-       printf("seqnum kernel: %llu\n", seqnum);
-       seqnum = udev_queue_get_udev_seqnum(udev_queue);
-       printf("seqnum udev  : %llu\n", seqnum);
-
-       if (udev_queue_get_queue_is_empty(udev_queue))
-               printf("queue is empty\n");
-       printf("get queue list\n");
-       udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
-               printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
-       printf("\n");
-       printf("get queue list again\n");
-       udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
-               printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
-       printf("\n");
-       printf("get failed list\n");
-       udev_list_entry_foreach(list_entry, udev_queue_get_failed_list_entry(udev_queue))
-               printf("failed: '%s'\n", udev_list_entry_get_name(list_entry));
-       printf("\n");
-
-       list_entry = udev_queue_get_queued_list_entry(udev_queue);
-       if (list_entry != NULL) {
-               printf("event [%llu] is queued\n", seqnum);
-               seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10);
-               if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum))
-                       printf("event [%llu] is not finished\n", seqnum);
-               else
-                       printf("event [%llu] is finished\n", seqnum);
-       }
-       printf("\n");
-       udev_queue_unref(udev_queue);
-       return 0;
-}
-
-static int test_enumerate(struct udev *udev, const char *subsystem)
-{
-       struct udev_enumerate *udev_enumerate;
-
-       printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem);
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
-       udev_enumerate_scan_devices(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-
-       printf("enumerate 'block'\n");
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_add_match_subsystem(udev_enumerate,"block");
-       udev_enumerate_scan_devices(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-
-       printf("enumerate 'not block'\n");
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
-       udev_enumerate_scan_devices(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-
-       printf("enumerate 'pci, mem, vc'\n");
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_add_match_subsystem(udev_enumerate, "pci");
-       udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
-       udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
-       udev_enumerate_scan_devices(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-
-       printf("enumerate 'subsystem'\n");
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_scan_subsystems(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-
-       printf("enumerate 'property IF_FS_*=filesystem'\n");
-       udev_enumerate = udev_enumerate_new(udev);
-       if (udev_enumerate == NULL)
-               return -1;
-       udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
-       udev_enumerate_scan_devices(udev_enumerate);
-       test_enumerate_print_list(udev_enumerate);
-       udev_enumerate_unref(udev_enumerate);
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       struct udev *udev = NULL;
-       static const struct option options[] = {
-               { "syspath", required_argument, NULL, 'p' },
-               { "subsystem", required_argument, NULL, 's' },
-               { "debug", no_argument, NULL, 'd' },
-               { "help", no_argument, NULL, 'h' },
-               { "version", no_argument, NULL, 'V' },
-               {}
-       };
-       const char *syspath = "/devices/virtual/mem/null";
-       const char *subsystem = NULL;
-       char path[1024];
-       const char *str;
-
-       udev = udev_new();
-       printf("context: %p\n", udev);
-       if (udev == NULL) {
-               printf("no context\n");
-               return 1;
-       }
-       udev_set_log_fn(udev, log_fn);
-       printf("set log: %p\n", log_fn);
-
-       while (1) {
-               int option;
-
-               option = getopt_long(argc, argv, "+dhV", options, NULL);
-               if (option == -1)
-                       break;
-
-               switch (option) {
-               case 'p':
-                       syspath = optarg;
-                       break;
-               case 's':
-                       subsystem = optarg;
-                       break;
-               case 'd':
-                       if (udev_get_log_priority(udev) < LOG_INFO)
-                               udev_set_log_priority(udev, LOG_INFO);
-                       break;
-               case 'h':
-                       printf("--debug --syspath= --subsystem= --help\n");
-                       goto out;
-               case 'V':
-                       printf("%s\n", VERSION);
-                       goto out;
-               default:
-                       goto out;
-               }
-       }
-
-       str = udev_get_sys_path(udev);
-       printf("sys_path: '%s'\n", str);
-       str = udev_get_dev_path(udev);
-       printf("dev_path: '%s'\n", str);
-
-       /* add sys path if needed */
-       if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
-               snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), syspath);
-               syspath = path;
-       }
-
-       test_device(udev, syspath);
-       test_device_devnum(udev);
-       test_device_subsys_name(udev);
-       test_device_parents(udev, syspath);
-
-       test_enumerate(udev, subsystem);
-
-       test_queue(udev);
-
-       test_monitor(udev);
-out:
-       udev_unref(udev);
-       return 0;
-}
index 718797539030dae45f0505241c1c6fbe5ea2e3f7..8926dee9326ed02af990de107da1cde6e964ef95 100644 (file)
@@ -22,8 +22,8 @@
 #include <sys/types.h>
 #include <sys/param.h>
 
-#include "lib/libudev.h"
-#include "lib/libudev-private.h"
+#include "libudev.h"
+#include "libudev-private.h"
 
 #define DEFAULT_FAKE_PARTITIONS_COUNT          15
 #define UDEV_EVENT_TIMEOUT                     180