summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/Makefile.am41
-rw-r--r--test/test-libudev.c520
-rw-r--r--test/test-udev.c180
3 files changed, 740 insertions, 1 deletions
diff --git a/test/Makefile.am b/test/Makefile.am
index ab3b68e4a6..954b93bcfb 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,5 +1,44 @@
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+
+AM_CPPFLAGS = \
+ -DVERSION=\"@VERSION@\" \
+ -I $(top_srcdir)/src/libudev \
+ -I $(top_srcdir)/src/udev
+
+noinst_PROGRAMS = \
+ test-libudev \
+ test-udev
+
+test_libudev_SOURCES = \
+ test-libudev.c
+
+test_libudev_LDADD = \
+ $(top_builddir)/src/libudev/libudev-private.la \
+ $(top_builddir)/src/udev/libudev-core.la
+
+test_libudev_CPPFLAGS = \
+ -I $(top_srcdir)/src/libudev \
+ $(AM_CPPFLAGS)
+
+test_udev_SOURCES = \
+ test-udev.c
+
+test_udev_LDADD = \
+ $(top_builddir)/src/libudev/libudev-private.la \
+ $(top_builddir)/src/udev/libudev-core.la \
+ $(BLKID_LIBS) \
+ $(SELINUX_LIBS)
+
+if HAVE_LIBKMOD
+test_udev_LDADD += $(KMOD_LIBS)
+endif
+
+test_udev_CPPFLAGS = \
+ -I $(top_srcdir)/src/udev \
+ $(AM_CPPFLAGS)
+
+
TESTS = \
udev-test.pl \
rules-test.sh
@@ -9,7 +48,7 @@ check_DATA = \
test/sys:
$(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)tar -C $(top_builddir)/test/ -xJf $(top_srcdir)/test/sys.tar.xz
+ $(AM_V_GEN)tar -C $(top_builddir)/test/test -xJf $(top_srcdir)/test/sys.tar.xz
test-sys-distclean:
-rm -rf $(top_builddir)/test/sys
diff --git a/test/test-libudev.c b/test/test-libudev.c
new file mode 100644
index 0000000000..caa3b4d14c
--- /dev/null
+++ b/test/test-libudev.c
@@ -0,0 +1,520 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+
+ systemd 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.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#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/epoll.h>
+
+#include "libudev.h"
+#include "util.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+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 = NULL;
+ int fd_ep;
+ int fd_udev = -1;
+ struct epoll_event ep_udev, ep_stdin;
+
+ fd_ep = epoll_create1(EPOLL_CLOEXEC);
+ if (fd_ep < 0) {
+ printf("error creating epoll fd: %m\n");
+ goto out;
+ }
+
+ udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (udev_monitor == NULL) {
+ printf("no socket\n");
+ goto out;
+ }
+ fd_udev = udev_monitor_get_fd(udev_monitor);
+
+ 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");
+ goto out;
+ }
+
+ if (udev_monitor_enable_receiving(udev_monitor) < 0) {
+ printf("bind failed\n");
+ goto out;
+ }
+
+ memset(&ep_udev, 0, sizeof(struct epoll_event));
+ ep_udev.events = EPOLLIN;
+ ep_udev.data.fd = fd_udev;
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
+ printf("fail to add fd to epoll: %m\n");
+ goto out;
+ }
+
+ memset(&ep_stdin, 0, sizeof(struct epoll_event));
+ ep_stdin.events = EPOLLIN;
+ ep_stdin.data.fd = STDIN_FILENO;
+ if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) {
+ printf("fail to add fd to epoll: %m\n");
+ goto out;
+ }
+
+ for (;;) {
+ int fdcount;
+ struct epoll_event ev[4];
+ struct udev_device *device;
+ int i;
+
+ printf("waiting for events from udev, press ENTER to exit\n");
+ fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
+ printf("epoll fd count: %i\n", fdcount);
+
+ for (i = 0; i < fdcount; i++) {
+ if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
+ device = udev_monitor_receive_device(udev_monitor);
+ if (device == NULL) {
+ printf("no device from socket\n");
+ continue;
+ }
+ print_device(device);
+ udev_device_unref(device);
+ } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) {
+ printf("exiting loop\n");
+ goto out;
+ }
+ }
+ }
+out:
+ if (fd_ep >= 0)
+ close(fd_ep);
+ 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");
+
+ 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 'net' + duplicated scan + null + zero\n");
+ udev_enumerate = udev_enumerate_new(udev);
+ if (udev_enumerate == NULL)
+ return -1;
+ udev_enumerate_add_match_subsystem(udev_enumerate, "net");
+ udev_enumerate_scan_devices(udev_enumerate);
+ udev_enumerate_scan_devices(udev_enumerate);
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
+ 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_add_match_is_initialized(udev_enumerate);
+ 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;
+}
+
+static int test_hwdb(struct udev *udev, const char *modalias) {
+ struct udev_hwdb * hwdb;
+ struct udev_list_entry *entry;
+
+ hwdb = udev_hwdb_new(udev);
+
+ udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
+ printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
+ printf("\n");
+
+ hwdb = udev_hwdb_unref(hwdb);
+ 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];
+
+ 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);
+
+ for (;;) {
+ int option;
+
+ option = getopt_long(argc, argv, "+p:s: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;
+ }
+ }
+
+ /* add sys path if needed */
+ if (!startswith(syspath, "/sys")) {
+ snprintf(path, sizeof(path), "/sys/%s", 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_hwdb(udev, "usb:v0D50p0011*");
+
+ test_monitor(udev);
+out:
+ udev_unref(udev);
+ return 0;
+}
diff --git a/test/test-udev.c b/test/test-udev.c
new file mode 100644
index 0000000000..26e173de63
--- /dev/null
+++ b/test/test-udev.c
@@ -0,0 +1,180 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ Copyright 2004-2012 Kay Sievers <kay@vrfy.org>
+
+ systemd 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.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <grp.h>
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/signalfd.h>
+
+#include "udev.h"
+
+#ifndef HAVE_UNSHARE
+#include <sys/syscall.h>
+/* Provide our own replacement with local reach*/
+static inline int unshare (int x) { return syscall(SYS_unshare, x); }
+#endif
+
+#ifndef _USE_GNU
+/* Make sure CLONE_NEWNS macro is available */
+#include <linux/sched.h>
+#endif
+
+void udev_main_log(struct udev *udev, int priority,
+ const char *file, int line, const char *fn,
+ const char *format, va_list args) {}
+
+static int fake_filesystems(void) {
+ static const struct fakefs {
+ const char *src;
+ const char *target;
+ const char *error;
+ } fakefss[] = {
+ { "test/sys", "/sys", "failed to mount test /sys" },
+ { "test/dev", "/dev", "failed to mount test /dev" },
+ { "test/run", "/run", "failed to mount test /run" },
+ { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" },
+ };
+ unsigned int i;
+ int err;
+
+ err = unshare(CLONE_NEWNS);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to call unshare(): %m\n");
+ goto out;
+ }
+
+ if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
+ err = -errno;
+ fprintf(stderr, "failed to mount / as private: %m\n");
+ goto out;
+ }
+
+ for (i = 0; i < ELEMENTSOF(fakefss); i++) {
+ err = mount(fakefss[i].src, fakefss[i].target, "tmpfs", MS_BIND, NULL);
+ if (err < 0) {
+ err = -errno;
+ fprintf(stderr, "%s %m", fakefss[i].error);
+ return err;
+ }
+ }
+out:
+ return err;
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct udev *udev;
+ struct udev_event *event = NULL;
+ struct udev_device *dev = NULL;
+ struct udev_rules *rules = NULL;
+ char syspath[UTIL_PATH_SIZE];
+ const char *devpath;
+ const char *action;
+ sigset_t mask, sigmask_orig;
+ int err;
+
+ err = fake_filesystems();
+ if (err < 0)
+ return EXIT_FAILURE;
+
+ udev = udev_new();
+ if (udev == NULL)
+ exit(EXIT_FAILURE);
+ log_debug("version %s\n", VERSION);
+ label_init("/dev");
+
+ sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
+
+ action = argv[1];
+ if (action == NULL) {
+ log_error("action missing\n");
+ goto out;
+ }
+
+ devpath = argv[2];
+ if (devpath == NULL) {
+ log_error("devpath missing\n");
+ goto out;
+ }
+
+ rules = udev_rules_new(udev, 1);
+
+ util_strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL);
+ dev = udev_device_new_from_syspath(udev, syspath);
+ if (dev == NULL) {
+ log_debug("unknown device '%s'\n", devpath);
+ goto out;
+ }
+
+ udev_device_set_action(dev, action);
+ event = udev_event_new(dev);
+
+ sigfillset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
+ event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
+ if (event->fd_signal < 0) {
+ fprintf(stderr, "error creating signalfd\n");
+ goto out;
+ }
+
+ /* do what devtmpfs usually provides us */
+ if (udev_device_get_devnode(dev) != NULL) {
+ mode_t mode = 0600;
+
+ if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
+ mode |= S_IFBLK;
+ else
+ mode |= S_IFCHR;
+
+ if (strcmp(action, "remove") != 0) {
+ mkdir_parents_label(udev_device_get_devnode(dev), 0755);
+ mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev));
+ } else {
+ unlink(udev_device_get_devnode(dev));
+ util_delete_path(udev, udev_device_get_devnode(dev));
+ }
+ }
+
+ err = udev_event_execute_rules(event, rules, &sigmask_orig);
+ if (err == 0)
+ udev_event_execute_run(event, NULL);
+out:
+ if (event != NULL && event->fd_signal >= 0)
+ close(event->fd_signal);
+ udev_event_unref(event);
+ udev_device_unref(dev);
+ udev_rules_unref(rules);
+ label_finish();
+ udev_unref(udev);
+ if (err != 0)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}