udevadm: rename source files
authorKay Sievers <kay.sievers@vrfy.org>
Wed, 3 Sep 2008 21:33:06 +0000 (23:33 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Wed, 3 Sep 2008 21:33:06 +0000 (23:33 +0200)
15 files changed:
NEWS
udev/Makefile.am
udev/udevadm-control.c [new file with mode: 0644]
udev/udevadm-info.c [new file with mode: 0644]
udev/udevadm-monitor.c [new file with mode: 0644]
udev/udevadm-settle.c [new file with mode: 0644]
udev/udevadm-test.c [new file with mode: 0644]
udev/udevadm-trigger.c [new file with mode: 0644]
udev/udevcontrol.c [deleted file]
udev/udevd.h
udev/udevinfo.c [deleted file]
udev/udevmonitor.c [deleted file]
udev/udevsettle.c [deleted file]
udev/udevtest.c [deleted file]
udev/udevtrigger.c [deleted file]

diff --git a/NEWS b/NEWS
index 70cd0debbbe429fda2a4aec3c962d5b56c7ce7b9..8f7871d566c5f6be9a29219a5a4ebecd58569a60 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ The udevadm info --device-id-of-file= output has changed to use
 the obvious format. Possible current users should use the --export
 option which is not affected.
 
+The old udev commands symlinks to udevadm are not installed since
+a while, if these symlinks are used, a deprecation warning to stderr
+is printed.
+
 udev 127
 ========
 Bugfixes.
index 4a7c7855ce042536d54c73706140fbfd29f37fe8..d123c0b3fd23af9aa01df7f1f6d137d02a04fb57 100644 (file)
@@ -55,12 +55,12 @@ udevd_LDADD = \
 udevadm_SOURCES = \
        $(common_files) \
        udevadm.c \
-       udevinfo.c \
-       udevcontrol.c \
-       udevtest.c \
-       udevmonitor.c \
-       udevsettle.c \
-       udevtrigger.c
+       udevadm-info.c \
+       udevadm-control.c \
+       udevadm-test.c \
+       udevadm-monitor.c \
+       udevadm-settle.c \
+       udevadm-trigger.c
 
 udevadm_LDADD = \
        $(common_ldadd)
diff --git a/udev/udevadm-control.c b/udev/udevadm-control.c
new file mode 100644 (file)
index 0000000..5f19525
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <time.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+
+#include "udev.h"
+#include "udevd.h"
+
+static int udev_log = 0;
+
+struct udev_ctrl;
+extern struct udev_ctrl *udev_ctrl_new_from_socket(const char *socket_path);
+extern void udev_ctrl_unref(struct udev_ctrl *uctrl);
+extern int udev_ctrl_set_log_level(struct udev_ctrl *uctrl, int priority);
+extern int udev_ctrl_stop_exec_queue(struct udev_ctrl *uctrl);
+extern int udev_ctrl_start_exec_queue(struct udev_ctrl *uctrl);
+extern int udev_ctrl_reload_rules(struct udev_ctrl *uctrl);
+extern int udev_ctrl_set_env(struct udev_ctrl *uctrl, const char *key);
+extern int udev_ctrl_set_max_childs(struct udev_ctrl *uctrl, int count);
+extern int udev_ctrl_set_max_childs_running(struct udev_ctrl *uctrl, int count);
+
+struct udev_ctrl {
+       int sock;
+       struct sockaddr_un saddr;
+       socklen_t addrlen;
+};
+
+struct udev_ctrl *udev_ctrl_new_from_socket(const char *socket_path)
+{
+       struct udev_ctrl *uctrl;
+
+       uctrl = malloc(sizeof(struct udev_ctrl));
+       if (uctrl == NULL)
+               return NULL;
+       memset(uctrl, 0x00, sizeof(struct udev_ctrl));
+
+       uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+       if (uctrl->sock < 0) {
+               err("error getting socket: %s\n", strerror(errno));
+               free(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;
+}
+
+void udev_ctrl_unref(struct udev_ctrl *uctrl)
+{
+       if (uctrl == NULL)
+               return;
+       close(uctrl->sock);
+}
+
+static int ctrl_send(struct udev_ctrl *uctrl, enum udevd_ctrl_msg_type type, int intval, const char *buf)
+{
+       struct udevd_ctrl_msg ctrl_msg;
+       int err;
+
+       memset(&ctrl_msg, 0x00, sizeof(struct udevd_ctrl_msg));
+       strcpy(ctrl_msg.magic, UDEVD_CTRL_MAGIC);
+       ctrl_msg.type = type;
+
+       if (buf != NULL)
+               strlcpy(ctrl_msg.buf, buf, sizeof(ctrl_msg.buf));
+       else
+               ctrl_msg.intval = intval;
+
+       err = sendto(uctrl->sock, &ctrl_msg, sizeof(ctrl_msg), 0, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
+       if (err == -1) {
+               err("error sending message: %s\n", strerror(errno));
+       }
+       return err;
+}
+
+int udev_ctrl_set_log_level(struct udev_ctrl *uctrl, int priority)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_SET_LOG_LEVEL, priority, NULL);
+       return 0;
+}
+
+int udev_ctrl_stop_exec_queue(struct udev_ctrl *uctrl)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_STOP_EXEC_QUEUE, 0, NULL);
+       return 0;
+}
+
+int udev_ctrl_start_exec_queue(struct udev_ctrl *uctrl)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_START_EXEC_QUEUE, 0, NULL);
+       return 0;
+}
+
+int udev_ctrl_reload_rules(struct udev_ctrl *uctrl)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_RELOAD_RULES, 0, NULL);
+       return 0;
+}
+
+int udev_ctrl_set_env(struct udev_ctrl *uctrl, const char *key)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_ENV, 0, optarg);
+       return 0;
+}
+
+int udev_ctrl_set_max_childs(struct udev_ctrl *uctrl, int count)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_SET_MAX_CHILDS, count, NULL);
+       return 0;
+}
+
+int udev_ctrl_set_max_childs_running(struct udev_ctrl *uctrl, int count)
+{
+       ctrl_send(uctrl, UDEVD_CTRL_SET_MAX_CHILDS_RUNNING, count, NULL);
+       return 0;
+}
+
+int udevcontrol(int argc, char *argv[])
+{
+       struct udev_ctrl *uctrl;
+       const char *env;
+       int rc = 1;
+
+       /* compat values with '_' will be removed in a future release */
+       static const struct option options[] = {
+               { "log-priority", 1, NULL, 'l' },
+               { "log_priority", 1, NULL, 'l' + 256 },
+               { "stop-exec-queue", 0, NULL, 's' },
+               { "stop_exec_queue", 0, NULL, 's' + 256 },
+               { "start-exec-queue", 0, NULL, 'S' },
+               { "start_exec_queue", 0, NULL, 'S' + 256},
+               { "reload-rules", 0, NULL, 'R' },
+               { "reload_rules", 0, NULL, 'R' + 256},
+               { "env", 1, NULL, 'e' },
+               { "max-childs", 1, NULL, 'm' },
+               { "max_childs", 1, NULL, 'm' + 256},
+               { "max-childs-running", 1, NULL, 'M' },
+               { "max_childs_running", 1, NULL, 'M' + 256},
+               { "help", 0, NULL, 'h' },
+               {}
+       };
+
+       env = getenv("UDEV_LOG");
+       if (env)
+               udev_log = log_priority(env);
+
+       logging_init("udevcontrol");
+       dbg("version %s\n", VERSION);
+
+       if (getuid() != 0) {
+               fprintf(stderr, "root privileges required\n");
+               goto exit;
+       }
+
+       uctrl = udev_ctrl_new_from_socket(UDEVD_CTRL_SOCK_PATH);
+       if (uctrl == NULL)
+               goto exit;
+
+       while (1) {
+               int option;
+               int i;
+               char *endp;
+
+               option = getopt_long(argc, argv, "l:sSRe:m:M:h", options, NULL);
+               if (option == -1)
+                       break;
+
+               if (option > 255) {
+                       info("udevadm control expects commands without underscore, "
+                           "this will stop working in a future release\n");
+                       fprintf(stderr, "udevadm control expects commands without underscore, "
+                               "this will stop working in a future release\n");
+               }
+
+               switch (option) {
+               case 'l':
+               case 'l' + 256:
+                       i = log_priority(optarg);
+                       if (i < 0) {
+                               fprintf(stderr, "invalid number '%s'\n", optarg);
+                               goto exit;
+                       }
+                       udev_ctrl_set_log_level(uctrl, log_priority(optarg));
+                       break;
+               case 's':
+               case 's' + 256:
+                       udev_ctrl_stop_exec_queue(uctrl);
+                       break;
+               case 'S':
+               case 'S' + 256:
+                       udev_ctrl_start_exec_queue(uctrl);
+                       break;
+               case 'R':
+               case 'R' + 256:
+                       udev_ctrl_reload_rules(uctrl);
+                       break;
+               case 'e':
+                       if (strchr(optarg, '=') == NULL) {
+                               fprintf(stderr, "expect <KEY>=<valaue> instead of '%s'\n", optarg);
+                               goto exit;
+                       }
+                       udev_ctrl_set_env(uctrl, optarg);
+                       break;
+               case 'm':
+               case 'm' + 256:
+                       i = strtoul(optarg, &endp, 0);
+                       if (endp[0] != '\0' || i < 1) {
+                               fprintf(stderr, "invalid number '%s'\n", optarg);
+                               goto exit;
+                       }
+                       udev_ctrl_set_max_childs(uctrl, i);
+                       break;
+               case 'M':
+               case 'M' + 256:
+                       i = strtoul(optarg, &endp, 0);
+                       if (endp[0] != '\0' || i < 1) {
+                               fprintf(stderr, "invalid number '%s'\n", optarg);
+                               goto exit;
+                       }
+                       udev_ctrl_set_max_childs_running(uctrl, i);
+                       break;
+                       break;
+               case 'h':
+                       printf("Usage: udevadm control COMMAND\n"
+                               "  --log-priority=<level>   set the udev log level for the daemon\n"
+                               "  --stop-exec-queue        keep udevd from executing events, queue only\n"
+                               "  --start-exec-queue       execute events, flush queue\n"
+                               "  --reload-rules           reloads the rules files\n"
+                               "  --env=<KEY>=<value>      set a global environment variable\n"
+                               "  --max-childs=<N>         maximum number of childs\n"
+                               "  --max-childs-running=<N> maximum number of childs running at the same time\n"
+                               "  --help                   print this help text\n\n");
+                       goto exit;
+               default:
+                       goto exit;
+               }
+       }
+
+       /* compat stuff which will be removed in a future release */
+       if (argv[optind] != NULL) {
+               const char *arg = argv[optind];
+
+               fprintf(stderr, "udevadm control commands requires the --<command> format, "
+                       "this will stop working in a future release\n");
+               err("udevadm control commands requires the --<command> format, "
+                   "this will stop working in a future release\n");
+
+               if (!strncmp(arg, "log_priority=", strlen("log_priority="))) {
+                       udev_ctrl_set_log_level(uctrl, log_priority(&arg[strlen("log_priority=")]));
+               } else if (!strcmp(arg, "stop_exec_queue")) {
+                       udev_ctrl_stop_exec_queue(uctrl);
+               } else if (!strcmp(arg, "start_exec_queue")) {
+                       udev_ctrl_start_exec_queue(uctrl);
+               } else if (!strcmp(arg, "reload_rules")) {
+                       udev_ctrl_reload_rules(uctrl);
+               } else if (!strncmp(arg, "max_childs=", strlen("max_childs="))) {
+                       udev_ctrl_set_max_childs(uctrl, strtoul(&arg[strlen("max_childs=")], NULL, 0));
+               } else if (!strncmp(arg, "max_childs_running=", strlen("max_childs_running="))) {
+                       udev_ctrl_set_max_childs_running(uctrl, strtoul(&arg[strlen("max_childs_running=")], NULL, 0));
+               } else if (!strncmp(arg, "env", strlen("env"))) {
+                       udev_ctrl_set_env(uctrl, &arg[strlen("env=")]);
+               } else {
+                       fprintf(stderr, "unrecognized command '%s'\n", arg);
+                       err("unrecognized command '%s'\n", arg);
+               }
+       }
+exit:
+       udev_ctrl_unref(uctrl);
+       logging_close();
+       return rc;
+}
diff --git a/udev/udevadm-info.c b/udev/udevadm-info.c
new file mode 100644 (file)
index 0000000..6501b57
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev.h"
+
+static void print_all_attributes(const char *devpath, const char *key)
+{
+       char path[PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       strlcpy(path, sysfs_path, sizeof(path));
+       strlcat(path, devpath, sizeof(path));
+
+       dir = opendir(path);
+       if (dir != NULL) {
+               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                       struct stat statbuf;
+                       char filename[PATH_SIZE];
+                       char *attr_value;
+                       char value[NAME_SIZE];
+                       size_t len;
+
+                       if (dent->d_name[0] == '.')
+                               continue;
+
+                       if (strcmp(dent->d_name, "uevent") == 0)
+                               continue;
+                       if (strcmp(dent->d_name, "dev") == 0)
+                               continue;
+
+                       strlcpy(filename, path, sizeof(filename));
+                       strlcat(filename, "/", sizeof(filename));
+                       strlcat(filename, dent->d_name, sizeof(filename));
+                       if (lstat(filename, &statbuf) != 0)
+                               continue;
+                       if (S_ISLNK(statbuf.st_mode))
+                               continue;
+
+                       attr_value = sysfs_attr_get_value(devpath, dent->d_name);
+                       if (attr_value == NULL)
+                               continue;
+                       len = strlcpy(value, attr_value, sizeof(value));
+                       if(len >= sizeof(value))
+                               len = sizeof(value) - 1;
+                       dbg("attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
+
+                       /* remove trailing newlines */
+                       while (len && value[len-1] == '\n')
+                               value[--len] = '\0';
+
+                       /* skip nonprintable attributes */
+                       while (len && isprint(value[len-1]))
+                               len--;
+                       if (len) {
+                               dbg("attribute value of '%s' non-printable, skip\n", dent->d_name);
+                               continue;
+                       }
+
+                       printf("    %s{%s}==\"%s\"\n", key, dent->d_name, value);
+               }
+       }
+       printf("\n");
+}
+
+static int print_device_chain(const char *devpath)
+{
+       struct sysfs_device *dev;
+
+       dev = sysfs_device_get(devpath);
+       if (dev == NULL)
+               return -1;
+
+       printf("\n"
+              "Udevinfo starts with the device specified by the devpath and then\n"
+              "walks up the chain of parent devices. It prints for every device\n"
+              "found, all possible attributes in the udev rules key format.\n"
+              "A rule to match, can be composed by the attributes of the device\n"
+              "and the attributes from one single parent device.\n"
+              "\n");
+
+       printf("  looking at device '%s':\n", dev->devpath);
+       printf("    KERNEL==\"%s\"\n", dev->kernel);
+       printf("    SUBSYSTEM==\"%s\"\n", dev->subsystem);
+       printf("    DRIVER==\"%s\"\n", dev->driver);
+       print_all_attributes(dev->devpath, "ATTR");
+
+       /* walk up the chain of devices */
+       while (1) {
+               dev = sysfs_device_get_parent(dev);
+               if (dev == NULL)
+                       break;
+               printf("  looking at parent device '%s':\n", dev->devpath);
+               printf("    KERNELS==\"%s\"\n", dev->kernel);
+               printf("    SUBSYSTEMS==\"%s\"\n", dev->subsystem);
+               printf("    DRIVERS==\"%s\"\n", dev->driver);
+
+               print_all_attributes(dev->devpath, "ATTRS");
+       }
+
+       return 0;
+}
+
+static void print_record(struct udevice *udev)
+{
+       struct name_entry *name_loop;
+
+       printf("P: %s\n", udev->dev->devpath);
+       printf("N: %s\n", udev->name);
+       list_for_each_entry(name_loop, &udev->symlink_list, node)
+               printf("S: %s\n", name_loop->name);
+       if (udev->link_priority != 0)
+               printf("L: %i\n", udev->link_priority);
+       if (udev->partitions != 0)
+               printf("A:%u\n", udev->partitions);
+       if (udev->ignore_remove)
+               printf("R:%u\n", udev->ignore_remove);
+       list_for_each_entry(name_loop, &udev->env_list, node)
+               printf("E: %s\n", name_loop->name);
+}
+
+static void export_db(void) {
+       LIST_HEAD(name_list);
+       struct name_entry *name_loop;
+
+       udev_db_get_all_entries(&name_list);
+       list_for_each_entry(name_loop, &name_list, node) {
+               struct udevice *udev_db;
+
+               udev_db = udev_device_init();
+               if (udev_db == NULL)
+                       continue;
+               if (udev_db_get_device(udev_db, name_loop->name) == 0)
+                       print_record(udev_db);
+                       printf("\n");
+               udev_device_cleanup(udev_db);
+       }
+       name_list_cleanup(&name_list);
+}
+
+static int lookup_device_by_name(struct udevice **udev, const char *name)
+{
+       LIST_HEAD(name_list);
+       int count;
+       struct name_entry *device;
+       int rc  = -1;
+
+       count = udev_db_get_devices_by_name(name, &name_list);
+       if (count <= 0)
+               goto out;
+
+       info("found %i devices for '%s'\n", count, name);
+
+       /* select the device that seems to match */
+       list_for_each_entry(device, &name_list, node) {
+               struct udevice *udev_loop;
+               char filename[PATH_SIZE];
+               struct stat statbuf;
+
+               udev_loop = udev_device_init();
+               if (udev_loop == NULL)
+                       break;
+               if (udev_db_get_device(udev_loop, device->name) != 0)
+                       goto next;
+               info("found db entry '%s'\n", device->name);
+
+               /* make sure, we don't get a link of a different device */
+               strlcpy(filename, udev_root, sizeof(filename));
+               strlcat(filename, "/", sizeof(filename));
+               strlcat(filename, name, sizeof(filename));
+               if (stat(filename, &statbuf) != 0)
+                       goto next;
+               if (major(udev_loop->devt) > 0 && udev_loop->devt != statbuf.st_rdev) {
+                       info("skip '%s', dev_t doesn't match\n", udev_loop->name);
+                       goto next;
+               }
+               rc = 0;
+               *udev = udev_loop;
+               break;
+next:
+               udev_device_cleanup(udev_loop);
+       }
+out:
+       name_list_cleanup(&name_list);
+       return rc;
+}
+
+static int stat_device(const char *name, int export, const char *prefix)
+{
+       struct stat statbuf;
+
+       if (stat(name, &statbuf) != 0)
+               return -1;
+
+       if (export) {
+               if (prefix == NULL)
+                       prefix = "INFO_";
+               printf("%sMAJOR=%d\n"
+                      "%sMINOR=%d\n",
+                      prefix, major(statbuf.st_dev),
+                      prefix, minor(statbuf.st_dev));
+       } else
+               printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
+       return 0;
+}
+
+int udevinfo(int argc, char *argv[])
+{
+       int option;
+       struct udevice *udev = NULL;
+       int root = 0;
+       int export = 0;
+       const char *export_prefix = NULL;
+
+       static const struct option options[] = {
+               { "name", 1, NULL, 'n' },
+               { "path", 1, NULL, 'p' },
+               { "query", 1, NULL, 'q' },
+               { "attribute-walk", 0, NULL, 'a' },
+               { "export-db", 0, NULL, 'e' },
+               { "root", 0, NULL, 'r' },
+               { "device-id-of-file", 1, NULL, 'd' },
+               { "export", 0, NULL, 'x' },
+               { "export-prefix", 1, NULL, 'P' },
+               { "version", 0, NULL, 1 }, /* -V outputs braindead format */
+               { "help", 0, NULL, 'h' },
+               {}
+       };
+
+       enum action_type {
+               ACTION_NONE,
+               ACTION_QUERY,
+               ACTION_ATTRIBUTE_WALK,
+               ACTION_ROOT,
+               ACTION_DEVICE_ID_FILE,
+       } action = ACTION_NONE;
+
+       enum query_type {
+               QUERY_NONE,
+               QUERY_NAME,
+               QUERY_PATH,
+               QUERY_SYMLINK,
+               QUERY_ENV,
+               QUERY_ALL,
+       } query = QUERY_NONE;
+
+       char path[PATH_SIZE] = "";
+       char name[PATH_SIZE] = "";
+       struct name_entry *name_loop;
+       int rc = 0;
+
+       logging_init("udevinfo");
+       udev_config_init();
+       sysfs_init();
+
+       while (1) {
+               option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
+               if (option == -1)
+                       break;
+
+               dbg("option '%c'\n", option);
+               switch (option) {
+               case 'n':
+                       /* remove /dev if given */
+                       if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
+                               strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
+                       else
+                               strlcpy(name, optarg, sizeof(name));
+                       remove_trailing_chars(name, '/');
+                       dbg("name: %s\n", name);
+                       break;
+               case 'p':
+                       /* remove /sys if given */
+                       if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
+                               strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
+                       else
+                               strlcpy(path, optarg, sizeof(path));
+                       remove_trailing_chars(path, '/');
+
+                       /* possibly resolve to real devpath */
+                       if (sysfs_resolve_link(path, sizeof(path)) != 0) {
+                               char temp[PATH_SIZE];
+                               char *pos;
+
+                               /* also check if the parent is a link */
+                               strlcpy(temp, path, sizeof(temp));
+                               pos = strrchr(temp, '/');
+                               if (pos != 0) {
+                                       char tail[PATH_SIZE];
+
+                                       strlcpy(tail, pos, sizeof(tail));
+                                       pos[0] = '\0';
+                                       if (sysfs_resolve_link(temp, sizeof(temp)) == 0) {
+                                               strlcpy(path, temp, sizeof(path));
+                                               strlcat(path, tail, sizeof(path));
+                                       }
+                               }
+                       }
+                       dbg("path: %s\n", path);
+                       break;
+               case 'q':
+                       action = ACTION_QUERY;
+                       if (strcmp(optarg, "name") == 0) {
+                               query = QUERY_NAME;
+                               break;
+                       }
+                       if (strcmp(optarg, "symlink") == 0) {
+                               query = QUERY_SYMLINK;
+                               break;
+                       }
+                       if (strcmp(optarg, "path") == 0) {
+                               query = QUERY_PATH;
+                               break;
+                       }
+                       if (strcmp(optarg, "env") == 0) {
+                               query = QUERY_ENV;
+                               break;
+                       }
+                       if (strcmp(optarg, "all") == 0) {
+                               query = QUERY_ALL;
+                               break;
+                       }
+                       fprintf(stderr, "unknown query type\n");
+                       rc = 2;
+                       goto exit;
+               case 'r':
+                       if (action == ACTION_NONE)
+                               action = ACTION_ROOT;
+                       root = 1;
+                       break;
+               case 'd':
+                       action = ACTION_DEVICE_ID_FILE;
+                       strlcpy(name, optarg, sizeof(name));
+                       break;
+               case 'a':
+                       action = ACTION_ATTRIBUTE_WALK;
+                       break;
+               case 'e':
+                       export_db();
+                       goto exit;
+               case 'x':
+                       export = 1;
+                       break;
+               case 'P':
+                       export_prefix = optarg;
+                       break;
+               case 1:
+                       printf("%s\n", VERSION);
+                       goto exit;
+               case 'V':
+                       printf("udevinfo, version %s\n", VERSION);
+                       goto exit;
+               case 'h':
+                       printf("Usage: udevadm info OPTIONS\n"
+                              "  --query=<type>             query database for the specified value:\n"
+                              "      name                     name of device node\n"
+                              "      symlink                  pointing to node\n"
+                              "      path                     sysfs device path\n"
+                              "      env                      the device related imported environment\n"
+                              "      all                      all values\n"
+                              "  --path=<devpath>           sysfs device path used for query or chain\n"
+                              "  --name=<name>              node or symlink name used for query\n"
+                              "  --root                     prepend to query result or print udev_root\n"
+                              "  --attribute-walk           print all key matches while walking along chain\n"
+                              "                             of parent devices\n"
+                              "  --device-id-of-file=<file> print major/minor of underlying device\n"
+                              "  --export-db                export the content of the udev database\n"
+                              "  --help                     print this text\n"
+                              "\n");
+                       goto exit;
+               default:
+                       goto exit;
+               }
+       }
+
+       /* run action */
+       switch (action) {
+       case ACTION_QUERY:
+               /* needs devpath or node/symlink name for query */
+               if (path[0] != '\0') {
+                       udev = udev_device_init();
+                       if (udev == NULL) {
+                               rc = 1;
+                               goto exit;
+                       }
+                       if (udev_db_get_device(udev, path) != 0) {
+                               fprintf(stderr, "no record for '%s' in database\n", path);
+                               rc = 3;
+                               goto exit;
+                       }
+               } else if (name[0] != '\0') {
+                       if (lookup_device_by_name(&udev, name) != 0) {
+                               fprintf(stderr, "node name not found\n");
+                               rc = 4;
+                               goto exit;
+                       }
+               } else {
+                       fprintf(stderr, "query needs --path or node --name specified\n");
+                       rc = 4;
+                       goto exit;
+               }
+
+               switch(query) {
+               case QUERY_NAME:
+                       if (root)
+                               printf("%s/%s\n", udev_root, udev->name);
+                       else
+                               printf("%s\n", udev->name);
+                       break;
+               case QUERY_SYMLINK:
+                       list_for_each_entry(name_loop, &udev->symlink_list, node) {
+                               char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
+
+                               if (root)
+                                       printf("%s/%s%c", udev_root, name_loop->name, c);
+                               else
+                                       printf("%s%c", name_loop->name, c);
+                       }
+                       break;
+               case QUERY_PATH:
+                       printf("%s\n", udev->dev->devpath);
+                       goto exit;
+               case QUERY_ENV:
+                       list_for_each_entry(name_loop, &udev->env_list, node)
+                               printf("%s\n", name_loop->name);
+                       break;
+               case QUERY_ALL:
+                       print_record(udev);
+                       break;
+               default:
+                       fprintf(stderr, "unknown query type\n");
+                       break;
+               }
+               break;
+       case ACTION_ATTRIBUTE_WALK:
+               if (path[0] != '\0') {
+                       if (print_device_chain(path) != 0) {
+                               fprintf(stderr, "no valid sysfs device found\n");
+                               rc = 4;
+                               goto exit;
+                       }
+               } else if (name[0] != '\0') {
+                       if (lookup_device_by_name(&udev, name) != 0) {
+                               fprintf(stderr, "node name not found\n");
+                               rc = 4;
+                               goto exit;
+                       }
+                       if (print_device_chain(udev->dev->devpath) != 0) {
+                               fprintf(stderr, "no valid sysfs device found\n");
+                               rc = 4;
+                               goto exit;
+                       }
+               } else {
+                       fprintf(stderr, "attribute walk needs --path or node --name specified\n");
+                       rc = 5;
+                       goto exit;
+               }
+               break;
+       case ACTION_DEVICE_ID_FILE:
+               if (stat_device(name, export, export_prefix) != 0)
+                       rc = 6;
+               break;
+       case ACTION_ROOT:
+               printf("%s\n", udev_root);
+               break;
+       default:
+               fprintf(stderr, "missing option\n");
+               rc = 1;
+               break;
+       }
+
+exit:
+       udev_device_cleanup(udev);
+       sysfs_cleanup();
+       logging_close();
+       return rc;
+}
diff --git a/udev/udevadm-monitor.c b/udev/udevadm-monitor.c
new file mode 100644 (file)
index 0000000..3b65bca
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <getopt.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/select.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+#include "udev.h"
+#include "udevd.h"
+
+static int uevent_netlink_sock = -1;
+static int udev_monitor_sock = -1;
+static volatile int udev_exit;
+
+static int init_udev_monitor_socket(void)
+{
+       struct sockaddr_un saddr;
+       socklen_t addrlen;
+       int retval;
+
+       memset(&saddr, 0x00, sizeof(saddr));
+       saddr.sun_family = AF_LOCAL;
+       /* use abstract namespace for socket path */
+       strcpy(&saddr.sun_path[1], "/org/kernel/udev/monitor");
+       addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+
+       udev_monitor_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+       if (udev_monitor_sock == -1) {
+               fprintf(stderr, "error getting socket: %s\n", strerror(errno));
+               return -1;
+       }
+
+       /* the bind takes care of ensuring only one copy running */
+       retval = bind(udev_monitor_sock, (struct sockaddr *) &saddr, addrlen);
+       if (retval < 0) {
+               fprintf(stderr, "bind failed: %s\n", strerror(errno));
+               close(udev_monitor_sock);
+               udev_monitor_sock = -1;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int init_uevent_netlink_sock(void)
+{
+       struct sockaddr_nl snl;
+       int retval;
+
+       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+       snl.nl_family = AF_NETLINK;
+       snl.nl_pid = getpid();
+       snl.nl_groups = 1;
+
+       uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+       if (uevent_netlink_sock == -1) {
+               fprintf(stderr, "error getting socket: %s\n", strerror(errno));
+               return -1;
+       }
+
+       retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl,
+                     sizeof(struct sockaddr_nl));
+       if (retval < 0) {
+               fprintf(stderr, "bind failed: %s\n", strerror(errno));
+               close(uevent_netlink_sock);
+               uevent_netlink_sock = -1;
+               return -1;
+       }
+
+       return 0;
+}
+
+static void asmlinkage sig_handler(int signum)
+{
+       if (signum == SIGINT || signum == SIGTERM)
+               udev_exit = 1;
+}
+
+static const char *search_key(const char *searchkey, const char *buf, size_t buflen)
+{
+       size_t bufpos = 0;
+       size_t searchkeylen = strlen(searchkey);
+
+       while (bufpos < buflen) {
+               const char *key;
+               int keylen;
+
+               key = &buf[bufpos];
+               keylen = strlen(key);
+               if (keylen == 0)
+                       break;
+                if ((strncmp(searchkey, key, searchkeylen) == 0) && key[searchkeylen] == '=')
+                       return &key[searchkeylen + 1];
+               bufpos += keylen + 1;
+       }
+       return NULL;
+}
+
+int udevmonitor(int argc, char *argv[])
+{
+       struct sigaction act;
+       int option;
+       int env = 0;
+       int kernel = 0;
+       int udev = 0;
+       fd_set readfds;
+       int retval = 0;
+
+       static const struct option options[] = {
+               { "environment", 0, NULL, 'e' },
+               { "kernel", 0, NULL, 'k' },
+               { "udev", 0, NULL, 'u' },
+               { "help", 0, NULL, 'h' },
+               {}
+       };
+
+       while (1) {
+               option = getopt_long(argc, argv, "ekuh", options, NULL);
+               if (option == -1)
+                       break;
+
+               switch (option) {
+               case 'e':
+                       env = 1;
+                       break;
+               case 'k':
+                       kernel = 1;
+                       break;
+               case 'u':
+                       udev = 1;
+                       break;
+               case 'h':
+                       printf("Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help]\n"
+                              "  --env    print the whole event environment\n"
+                              "  --kernel print kernel uevents\n"
+                              "  --udev   print udev events\n"
+                              "  --help   print this help text\n\n");
+               default:
+                       goto out;
+               }
+       }
+
+       if (!kernel && !udev) {
+               kernel = 1;
+               udev =1;
+       }
+
+       if (getuid() != 0 && kernel) {
+               fprintf(stderr, "root privileges needed to subscribe to kernel events\n");
+               goto out;
+       }
+
+       /* set signal handlers */
+       memset(&act, 0x00, sizeof(struct sigaction));
+       act.sa_handler = (void (*)(int)) sig_handler;
+       sigemptyset(&act.sa_mask);
+       act.sa_flags = SA_RESTART;
+       sigaction(SIGINT, &act, NULL);
+       sigaction(SIGTERM, &act, NULL);
+
+       printf("udevmonitor will print the received events for:\n");
+       if (udev) {
+               retval = init_udev_monitor_socket();
+               if (retval)
+                       goto out;
+               printf("UDEV the event which udev sends out after rule processing\n");
+       }
+       if (kernel) {
+               retval = init_uevent_netlink_sock();
+               if (retval)
+                       goto out;
+               printf("UEVENT the kernel uevent\n");
+       }
+       printf("\n");
+
+       while (!udev_exit) {
+               char buf[UEVENT_BUFFER_SIZE*2];
+               ssize_t buflen;
+               ssize_t bufpos;
+               ssize_t keys;
+               int fdcount;
+               struct timeval tv;
+               struct timezone tz;
+               char timestr[64];
+               const char *source = NULL;
+               const char *devpath, *action, *subsys;
+
+               buflen = 0;
+               FD_ZERO(&readfds);
+               if (uevent_netlink_sock >= 0)
+                       FD_SET(uevent_netlink_sock, &readfds);
+               if (udev_monitor_sock >= 0)
+                       FD_SET(udev_monitor_sock, &readfds);
+
+               fdcount = select(UDEV_MAX(uevent_netlink_sock, udev_monitor_sock)+1, &readfds, NULL, NULL, NULL);
+               if (fdcount < 0) {
+                       if (errno != EINTR)
+                               fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno));
+                       continue;
+               }
+
+               if (gettimeofday(&tv, &tz) == 0) {
+                       snprintf(timestr, sizeof(timestr), "%llu.%06u",
+                                (unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec);
+               } else
+                       timestr[0] = '\0';
+
+               if ((uevent_netlink_sock >= 0) && FD_ISSET(uevent_netlink_sock, &readfds)) {
+                       buflen = recv(uevent_netlink_sock, &buf, sizeof(buf), 0);
+                       if (buflen <= 0) {
+                               fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno));
+                               continue;
+                       }
+                       source = "UEVENT";
+               }
+
+               if ((udev_monitor_sock >= 0) && FD_ISSET(udev_monitor_sock, &readfds)) {
+                       buflen = recv(udev_monitor_sock, &buf, sizeof(buf), 0);
+                       if (buflen <= 0) {
+                               fprintf(stderr, "error receiving udev message: %s\n", strerror(errno));
+                               continue;
+                       }
+                       source = "UDEV  ";
+               }
+
+               if (buflen == 0)
+                       continue;
+
+               keys = strlen(buf) + 1; /* start of payload */
+               devpath = search_key("DEVPATH", &buf[keys], buflen);
+               action = search_key("ACTION", &buf[keys], buflen);
+               subsys = search_key("SUBSYSTEM", &buf[keys], buflen);
+               printf("%s[%s] %-8s %s (%s)\n", source, timestr, action, devpath, subsys);
+
+               /* print environment */
+               bufpos = keys;
+               if (env) {
+                       while (bufpos < buflen) {
+                               int keylen;
+                               char *key;
+
+                               key = &buf[bufpos];
+                               keylen = strlen(key);
+                               if (keylen == 0)
+                                       break;
+                               printf("%s\n", key);
+                               bufpos += keylen + 1;
+                       }
+                       printf("\n");
+               }
+       }
+
+out:
+       if (uevent_netlink_sock >= 0)
+               close(uevent_netlink_sock);
+       if (udev_monitor_sock >= 0)
+               close(udev_monitor_sock);
+
+       if (retval)
+               return 1;
+       return 0;
+}
diff --git a/udev/udevadm-settle.c b/udev/udevadm-settle.c
new file mode 100644 (file)
index 0000000..11277f5
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2006 Kay Sievers <kay@vrfy.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "udev.h"
+#include "udevd.h"
+
+#define DEFAULT_TIMEOUT                        180
+#define LOOP_PER_SECOND                        20
+
+static void print_queue(const char *dir)
+{
+       LIST_HEAD(files);
+       struct name_entry *item;
+
+       if (add_matching_files(&files, dir, NULL) < 0)
+               return;
+
+       printf("\n\nAfter the udevadm settle timeout, the events queue contains:\n\n");
+
+       list_for_each_entry(item, &files, node) {
+               char target[NAME_SIZE];
+               size_t len;
+               const char *filename = strrchr(item->name, '/');
+
+               if (filename == NULL)
+                       continue;
+               filename++;
+               if (*filename == '\0')
+                       continue;
+
+               len = readlink(item->name, target, sizeof(target));
+               if (len < 0)
+                       continue;
+               target[len] = '\0';
+
+               printf("%s: %s\n", filename, target);
+       }
+
+       printf("\n\n");
+}
+
+int udevsettle(int argc, char *argv[])
+{
+       char queuename[PATH_SIZE];
+       char filename[PATH_SIZE];
+       unsigned long long seq_kernel;
+       unsigned long long seq_udev;
+       char seqnum[32];
+       int fd;
+       ssize_t len;
+       int timeout = DEFAULT_TIMEOUT;
+       int loop;
+       static const struct option options[] = {
+               { "timeout", 1, NULL, 't' },
+               { "help", 0, NULL, 'h' },
+               {}
+       };
+       int option;
+       int rc = 1;
+       int seconds;
+
+       logging_init("udevsettle");
+       udev_config_init();
+       dbg("version %s\n", VERSION);
+       sysfs_init();
+
+       while (1) {
+               option = getopt_long(argc, argv, "t:h", options, NULL);
+               if (option == -1)
+                       break;
+
+               switch (option) {
+               case 't':
+                       seconds = atoi(optarg);
+                       if (seconds > 0)
+                               timeout = seconds;
+                       else
+                               fprintf(stderr, "invalid timeout value\n");
+                       dbg("timeout=%i\n", timeout);
+                       break;
+               case 'h':
+                       printf("Usage: udevadm settle [--help] [--timeout=<seconds>]\n\n");
+                       goto exit;
+               }
+       }
+
+       strlcpy(queuename, udev_root, sizeof(queuename));
+       strlcat(queuename, "/.udev/queue", sizeof(queuename));
+
+       loop = timeout * LOOP_PER_SECOND;
+       while (loop--) {
+               /* wait for events in queue to finish */
+               while (loop--) {
+                       struct stat statbuf;
+
+                       if (stat(queuename, &statbuf) < 0) {
+                               info("queue is empty\n");
+                               break;
+                       }
+                       usleep(1000 * 1000 / LOOP_PER_SECOND);
+               }
+               if (loop <= 0) {
+                       info("timeout waiting for queue\n");
+                       print_queue(queuename);
+                       goto exit;
+               }
+
+               /* read current udev seqnum */
+               strlcpy(filename, udev_root, sizeof(filename));
+               strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename));
+               fd = open(filename, O_RDONLY);
+               if (fd < 0)
+                       goto exit;
+               len = read(fd, seqnum, sizeof(seqnum)-1);
+               close(fd);
+               if (len <= 0)
+                       goto exit;
+               seqnum[len] = '\0';
+               seq_udev = strtoull(seqnum, NULL, 10);
+               info("udev seqnum = %llu\n", seq_udev);
+
+               /* read current kernel seqnum */
+               strlcpy(filename, sysfs_path, sizeof(filename));
+               strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename));
+               fd = open(filename, O_RDONLY);
+               if (fd < 0)
+                       goto exit;
+               len = read(fd, seqnum, sizeof(seqnum)-1);
+               close(fd);
+               if (len <= 0)
+                       goto exit;
+               seqnum[len] = '\0';
+               seq_kernel = strtoull(seqnum, NULL, 10);
+               info("kernel seqnum = %llu\n", seq_kernel);
+
+               /* make sure all kernel events have arrived in the queue */
+               if (seq_udev >= seq_kernel) {
+                       info("queue is empty and no pending events left\n");
+                       rc = 0;
+                       goto exit;
+               }
+               usleep(1000 * 1000 / LOOP_PER_SECOND);
+               info("queue is empty, but events still pending\n");
+       }
+
+exit:
+       sysfs_cleanup();
+       logging_close();
+       return rc;
+}
diff --git a/udev/udevadm-test.c b/udev/udevadm-test.c
new file mode 100644 (file)
index 0000000..63603aa
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <syslog.h>
+#include <getopt.h>
+
+#include "udev.h"
+#include "udev_rules.h"
+
+static int import_uevent_var(const char *devpath)
+{
+       char path[PATH_SIZE];
+       static char value[4096]; /* must stay, used with putenv */
+       ssize_t size;
+       int fd;
+       char *key;
+       char *next;
+       int rc = -1;
+
+       /* read uevent file */
+       strlcpy(path, sysfs_path, sizeof(path));
+       strlcat(path, devpath, sizeof(path));
+       strlcat(path, "/uevent", sizeof(path));
+       fd = open(path, O_RDONLY);
+       if (fd < 0)
+               goto out;
+       size = read(fd, value, sizeof(value));
+       close(fd);
+       if (size < 0)
+               goto out;
+       value[size] = '\0';
+
+       /* import keys into environment */
+       key = value;
+       while (key[0] != '\0') {
+               next = strchr(key, '\n');
+               if (next == NULL)
+                       goto out;
+               next[0] = '\0';
+               info("import into environment: '%s'\n", key);
+               putenv(key);
+               key = &next[1];
+       }
+       rc = 0;
+out:
+       return rc;
+}
+
+int udevtest(int argc, char *argv[])
+{
+       int force = 0;
+       const char *action = "add";
+       const char *subsystem = NULL;
+       const char *devpath = NULL;
+       struct udevice *udev;
+       struct sysfs_device *dev;
+       struct udev_rules rules = {};
+       int retval;
+       int rc = 0;
+
+       static const struct option options[] = {
+               { "action", 1, NULL, 'a' },
+               { "subsystem", 1, NULL, 's' },
+               { "force", 0, NULL, 'f' },
+               { "help", 0, NULL, 'h' },
+               {}
+       };
+
+       info("version %s\n", VERSION);
+       udev_config_init();
+       if (udev_log_priority < LOG_INFO) {
+               char priority[32];
+
+               udev_log_priority = LOG_INFO;
+               sprintf(priority, "%i", udev_log_priority);
+               setenv("UDEV_LOG", priority, 1);
+       }
+
+       while (1) {
+               int option;
+
+               option = getopt_long(argc, argv, "a:s:fh", options, NULL);
+               if (option == -1)
+                       break;
+
+               dbg("option '%c'\n", option);
+               switch (option) {
+               case 'a':
+                       action = optarg;
+                       break;
+               case 's':
+                       subsystem = optarg;
+                       break;
+               case 'f':
+                       force = 1;
+                       break;
+               case 'h':
+                       printf("Usage: udevadm test OPTIONS <devpath>\n"
+                              "  --action=<string>     set action string\n"
+                              "  --subsystem=<string>  set subsystem string\n"
+                              "  --force               don't skip node/link creation\n"
+                              "  --help                print this help text\n\n");
+                       exit(0);
+               default:
+                       exit(1);
+               }
+       }
+       devpath = argv[optind];
+
+       if (devpath == NULL) {
+               fprintf(stderr, "devpath parameter missing\n");
+               rc = 1;
+               goto exit;
+       }
+
+       printf("This program is for debugging only, it does not run any program,\n"
+              "specified by a RUN key. It may show incorrect results, because\n"
+              "some values may be different, or not available at a simulation run.\n"
+              "\n");
+
+       sysfs_init();
+       udev_rules_init(&rules, 0);
+
+       /* remove /sys if given */
+       if (strncmp(devpath, sysfs_path, strlen(sysfs_path)) == 0)
+               devpath = &devpath[strlen(sysfs_path)];
+
+       dev = sysfs_device_get(devpath);
+       if (dev == NULL) {
+               fprintf(stderr, "unable to open device '%s'\n", devpath);
+               rc = 2;
+               goto exit;
+       }
+
+       udev = udev_device_init();
+       if (udev == NULL) {
+               fprintf(stderr, "error initializing device\n");
+               rc = 3;
+               goto exit;
+       }
+
+       if (subsystem != NULL)
+               strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
+
+       /* override built-in sysfs device */
+       udev->dev = dev;
+       strlcpy(udev->action, action, sizeof(udev->action));
+       udev->devt = udev_device_get_devt(udev);
+
+       /* simulate node creation with test flag */
+       if (!force)
+               udev->test_run = 1;
+
+       setenv("DEVPATH", udev->dev->devpath, 1);
+       setenv("SUBSYSTEM", udev->dev->subsystem, 1);
+       setenv("ACTION", udev->action, 1);
+       import_uevent_var(udev->dev->devpath);
+
+       info("looking at device '%s' from subsystem '%s'\n", udev->dev->devpath, udev->dev->subsystem);
+       retval = udev_device_event(&rules, udev);
+
+       if (udev->event_timeout >= 0)
+               info("custom event timeout: %i\n", udev->event_timeout);
+
+       if (retval == 0 && !udev->ignore_device && udev_run) {
+               struct name_entry *name_loop;
+
+               list_for_each_entry(name_loop, &udev->run_list, node) {
+                       char program[PATH_SIZE];
+
+                       strlcpy(program, name_loop->name, sizeof(program));
+                       udev_rules_apply_format(udev, program, sizeof(program));
+                       info("run: '%s'\n", program);
+               }
+       }
+       udev_device_cleanup(udev);
+
+exit:
+       udev_rules_cleanup(&rules);
+       sysfs_cleanup();
+       return rc;
+}
diff --git a/udev/udevadm-trigger.c b/udev/udevadm-trigger.c
new file mode 100644 (file)
index 0000000..4a8f62a
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
+ *
+ *     This program is free software; you can redistribute it and/or modify it
+ *     under the terms of the GNU General Public License as published by the
+ *     Free Software Foundation version 2 of the License.
+ * 
+ *     This program is distributed in the hope that it will be useful, but
+ *     WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *     General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License along
+ *     with this program; if not, write to the Free Software Foundation, Inc.,
+ *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <fnmatch.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "udev.h"
+#include "udevd.h"
+#include "udev_rules.h"
+
+static int verbose;
+static int dry_run;
+LIST_HEAD(device_list);
+LIST_HEAD(filter_subsystem_match_list);
+LIST_HEAD(filter_subsystem_nomatch_list);
+LIST_HEAD(filter_attr_match_list);
+LIST_HEAD(filter_attr_nomatch_list);
+static int sock = -1;
+static struct sockaddr_un saddr;
+static socklen_t saddrlen;
+
+/* devices that should run last cause of their dependencies */
+static int delay_device(const char *devpath)
+{
+       static const char *delay_device_list[] = {
+               "*/md*",
+               "*/dm-*",
+               NULL
+       };
+       int i;
+
+       for (i = 0; delay_device_list[i] != NULL; i++)
+               if (fnmatch(delay_device_list[i], devpath, 0) == 0)
+                       return 1;
+       return 0;
+}
+
+static int device_list_insert(const char *path)
+{
+       char filename[PATH_SIZE];
+       char devpath[PATH_SIZE];
+       struct stat statbuf;
+
+       dbg("add '%s'\n" , path);
+
+       /* we only have a device, if we have an uevent file */
+       strlcpy(filename, path, sizeof(filename));
+       strlcat(filename, "/uevent", sizeof(filename));
+       if (stat(filename, &statbuf) < 0)
+               return -1;
+       if (!(statbuf.st_mode & S_IWUSR))
+               return -1;
+
+       strlcpy(devpath, &path[strlen(sysfs_path)], sizeof(devpath));
+
+       /* resolve possible link to real target */
+       if (lstat(path, &statbuf) < 0)
+               return -1;
+       if (S_ISLNK(statbuf.st_mode))
+               if (sysfs_resolve_link(devpath, sizeof(devpath)) != 0)
+                       return -1;
+
+       name_list_add(&device_list, devpath, 1);
+       return 0;
+}
+
+static void trigger_uevent(const char *devpath, const char *action)
+{
+       char filename[PATH_SIZE];
+       int fd;
+
+       strlcpy(filename, sysfs_path, sizeof(filename));
+       strlcat(filename, devpath, sizeof(filename));
+       strlcat(filename, "/uevent", sizeof(filename));
+
+       if (verbose)
+               printf("%s\n", devpath);
+
+       if (dry_run)
+               return;
+
+       fd = open(filename, O_WRONLY);
+       if (fd < 0) {
+               dbg("error on opening %s: %s\n", filename, strerror(errno));
+               return;
+       }
+
+       if (write(fd, action, strlen(action)) < 0)
+               info("error writing '%s' to '%s': %s\n", action, filename, strerror(errno));
+
+       close(fd);
+}
+
+static int pass_to_socket(const char *devpath, const char *action, const char *env)
+{
+       struct udevice *udev;
+       struct name_entry *name_loop;
+       char buf[4096];
+       size_t bufpos = 0;
+       ssize_t count;
+       char path[PATH_SIZE];
+       int fd;
+       char link_target[PATH_SIZE];
+       int len;
+       int err = 0;
+
+       if (verbose)
+               printf("%s\n", devpath);
+
+       udev = udev_device_init();
+       if (udev == NULL)
+               return -1;
+       udev_db_get_device(udev, devpath);
+
+       /* add header */
+       bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
+       bufpos++;
+
+       /* add cookie */
+       if (env != NULL) {
+               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "%s", env);
+               bufpos++;
+       }
+
+       /* add standard keys */
+       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVPATH=%s", devpath);
+       bufpos++;
+       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "ACTION=%s", action);
+       bufpos++;
+
+       /* add subsystem */
+       strlcpy(path, sysfs_path, sizeof(path));
+       strlcat(path, devpath, sizeof(path));
+       strlcat(path, "/subsystem", sizeof(path));
+       len = readlink(path, link_target, sizeof(link_target));
+       if (len > 0) {
+               char *pos;
+
+               link_target[len] = '\0';
+               pos = strrchr(link_target, '/');
+               if (pos != NULL) {
+                       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "SUBSYSTEM=%s", &pos[1]);
+                       bufpos++;
+               }
+       }
+
+       /* add symlinks and node name */
+       path[0] = '\0';
+       list_for_each_entry(name_loop, &udev->symlink_list, node) {
+               strlcat(path, udev_root, sizeof(path));
+               strlcat(path, "/", sizeof(path));
+               strlcat(path, name_loop->name, sizeof(path));
+               strlcat(path, " ", sizeof(path));
+       }
+       remove_trailing_chars(path, ' ');
+       if (path[0] != '\0') {
+               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVLINKS=%s", path);
+               bufpos++;
+       }
+       if (udev->name[0] != '\0') {
+               strlcpy(path, udev_root, sizeof(path));
+               strlcat(path, "/", sizeof(path));
+               strlcat(path, udev->name, sizeof(path));
+               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVNAME=%s", path);
+               bufpos++;
+       }
+
+       /* add keys from device "uevent" file */
+       strlcpy(path, sysfs_path, sizeof(path));
+       strlcat(path, devpath, sizeof(path));
+       strlcat(path, "/uevent", sizeof(path));
+       fd = open(path, O_RDONLY);
+       if (fd >= 0) {
+               char value[4096];
+
+               count = read(fd, value, sizeof(value));
+               close(fd);
+               if (count > 0) {
+                       char *key;
+
+                       value[count] = '\0';
+                       key = value;
+                       while (key[0] != '\0') {
+                               char *next;
+
+                               next = strchr(key, '\n');
+                               if (next == NULL)
+                                       break;
+                               next[0] = '\0';
+                               bufpos += strlcpy(&buf[bufpos], key, sizeof(buf) - bufpos-1);
+                               bufpos++;
+                               key = &next[1];
+                       }
+               }
+       }
+
+       /* add keys from database */
+       list_for_each_entry(name_loop, &udev->env_list, node) {
+               bufpos += strlcpy(&buf[bufpos], name_loop->name, sizeof(buf) - bufpos-1);
+               bufpos++;
+       }
+       if (bufpos > sizeof(buf))
+               bufpos = sizeof(buf);
+
+       count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen);
+       if (count < 0)
+               err = -1;
+
+       return err;
+}
+
+static void exec_list(const char *action, const char *env)
+{
+       struct name_entry *loop_device;
+       struct name_entry *tmp_device;
+
+       list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
+               if (delay_device(loop_device->name))
+                       continue;
+               if (sock >= 0)
+                       pass_to_socket(loop_device->name, action, env);
+               else
+                       trigger_uevent(loop_device->name, action);
+               list_del(&loop_device->node);
+               free(loop_device);
+       }
+
+       /* trigger remaining delayed devices */
+       list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
+               if (sock >= 0)
+                       pass_to_socket(loop_device->name, action, env);
+               else
+                       trigger_uevent(loop_device->name, action);
+               list_del(&loop_device->node);
+               free(loop_device);
+       }
+}
+
+static int subsystem_filtered(const char *subsystem)
+{
+       struct name_entry *loop_name;
+
+       /* skip devices matching the listed subsystems */
+       list_for_each_entry(loop_name, &filter_subsystem_nomatch_list, node)
+               if (fnmatch(loop_name->name, subsystem, 0) == 0)
+                       return 1;
+
+       /* skip devices not matching the listed subsystems */
+       if (!list_empty(&filter_subsystem_match_list)) {
+               list_for_each_entry(loop_name, &filter_subsystem_match_list, node)
+                       if (fnmatch(loop_name->name, subsystem, 0) == 0)
+                               return 0;
+               return 1;
+       }
+
+       return 0;
+}
+
+static int attr_match(const char *path, const char *attr_value)
+{
+       char attr[NAME_SIZE];
+       char file[PATH_SIZE];
+       char *match_value;
+
+       strlcpy(attr, attr_value, sizeof(attr));
+
+       /* separate attr and match value */
+       match_value = strchr(attr, '=');
+       if (match_value != NULL) {
+               match_value[0] = '\0';
+               match_value = &match_value[1];
+       }
+
+       strlcpy(file, path, sizeof(file));
+       strlcat(file, "/", sizeof(file));
+       strlcat(file, attr, sizeof(file));
+
+       if (match_value != NULL) {
+               /* match file content */
+               char value[NAME_SIZE];
+               int fd;
+               ssize_t size;
+
+               fd = open(file, O_RDONLY);
+               if (fd < 0)
+                       return 0;
+               size = read(fd, value, sizeof(value));
+               close(fd);
+               if (size < 0)
+                       return 0;
+               value[size] = '\0';
+               remove_trailing_chars(value, '\n');
+
+               /* match if attribute value matches */
+               if (fnmatch(match_value, value, 0) == 0)
+                       return 1;
+       } else {
+               /* match if attribute exists */
+               struct stat statbuf;
+
+               if (stat(file, &statbuf) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+static int attr_filtered(const char *path)
+{
+       struct name_entry *loop_name;
+
+       /* skip devices matching the listed sysfs attributes */
+       list_for_each_entry(loop_name, &filter_attr_nomatch_list, node)
+               if (attr_match(path, loop_name->name))
+                       return 1;
+
+       /* skip devices not matching the listed sysfs attributes */
+       if (!list_empty(&filter_attr_match_list)) {
+               list_for_each_entry(loop_name, &filter_attr_match_list, node)
+                       if (attr_match(path, loop_name->name))
+                               return 0;
+               return 1;
+       }
+       return 0;
+}
+
+enum scan_type {
+       SCAN_DEVICES,
+       SCAN_SUBSYSTEM,
+};
+
+static void scan_subsystem(const char *subsys, enum scan_type scan)
+{
+       char base[PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+       const char *subdir;
+
+       if (scan == SCAN_DEVICES)
+               subdir = "/devices";
+       else if (scan == SCAN_SUBSYSTEM)
+               subdir = "/drivers";
+       else
+               return;
+
+       strlcpy(base, sysfs_path, sizeof(base));
+       strlcat(base, "/", sizeof(base));
+       strlcat(base, subsys, sizeof(base));
+
+       dir = opendir(base);
+       if (dir != NULL) {
+               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                       char dirname[PATH_SIZE];
+                       DIR *dir2;
+                       struct dirent *dent2;
+
+                       if (dent->d_name[0] == '.')
+                               continue;
+
+                       if (scan == SCAN_DEVICES)
+                               if (subsystem_filtered(dent->d_name))
+                                       continue;
+
+                       strlcpy(dirname, base, sizeof(dirname));
+                       strlcat(dirname, "/", sizeof(dirname));
+                       strlcat(dirname, dent->d_name, sizeof(dirname));
+
+                       if (scan == SCAN_SUBSYSTEM) {
+                               if (attr_filtered(dirname))
+                                       continue;
+                               if (!subsystem_filtered("subsystem"))
+                                       device_list_insert(dirname);
+                               if (subsystem_filtered("drivers"))
+                                       continue;
+                       }
+
+                       strlcat(dirname, subdir, sizeof(dirname));
+
+                       /* look for devices/drivers */
+                       dir2 = opendir(dirname);
+                       if (dir2 != NULL) {
+                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+                                       char dirname2[PATH_SIZE];
+
+                                       if (dent2->d_name[0] == '.')
+                                               continue;
+
+                                       strlcpy(dirname2, dirname, sizeof(dirname2));
+                                       strlcat(dirname2, "/", sizeof(dirname2));
+                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+                                       if (attr_filtered(dirname2))
+                                               continue;
+                                       device_list_insert(dirname2);
+                               }
+                               closedir(dir2);
+                       }
+               }
+               closedir(dir);
+       }
+}
+
+static void scan_block(void)
+{
+       char base[PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       if (subsystem_filtered("block"))
+               return;
+
+       strlcpy(base, sysfs_path, sizeof(base));
+       strlcat(base, "/block", sizeof(base));
+
+       dir = opendir(base);
+       if (dir != NULL) {
+               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                       char dirname[PATH_SIZE];
+                       DIR *dir2;
+                       struct dirent *dent2;
+
+                       if (dent->d_name[0] == '.')
+                               continue;
+
+                       strlcpy(dirname, base, sizeof(dirname));
+                       strlcat(dirname, "/", sizeof(dirname));
+                       strlcat(dirname, dent->d_name, sizeof(dirname));
+                       if (attr_filtered(dirname))
+                               continue;
+                       if (device_list_insert(dirname) != 0)
+                               continue;
+
+                       /* look for partitions */
+                       dir2 = opendir(dirname);
+                       if (dir2 != NULL) {
+                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+                                       char dirname2[PATH_SIZE];
+
+                                       if (dent2->d_name[0] == '.')
+                                               continue;
+
+                                       if (!strcmp(dent2->d_name,"device"))
+                                               continue;
+
+                                       strlcpy(dirname2, dirname, sizeof(dirname2));
+                                       strlcat(dirname2, "/", sizeof(dirname2));
+                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+                                       if (attr_filtered(dirname2))
+                                               continue;
+                                       device_list_insert(dirname2);
+                               }
+                               closedir(dir2);
+                       }
+               }
+               closedir(dir);
+       }
+}
+
+static void scan_class(void)
+{
+       char base[PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       strlcpy(base, sysfs_path, sizeof(base));
+       strlcat(base, "/class", sizeof(base));
+
+       dir = opendir(base);
+       if (dir != NULL) {
+               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                       char dirname[PATH_SIZE];
+                       DIR *dir2;
+                       struct dirent *dent2;
+
+                       if (dent->d_name[0] == '.')
+                               continue;
+
+                       if (subsystem_filtered(dent->d_name))
+                               continue;
+
+                       strlcpy(dirname, base, sizeof(dirname));
+                       strlcat(dirname, "/", sizeof(dirname));
+                       strlcat(dirname, dent->d_name, sizeof(dirname));
+                       dir2 = opendir(dirname);
+                       if (dir2 != NULL) {
+                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
+                                       char dirname2[PATH_SIZE];
+
+                                       if (dent2->d_name[0] == '.')
+                                               continue;
+
+                                       if (!strcmp(dent2->d_name, "device"))
+                                               continue;
+
+                                       strlcpy(dirname2, dirname, sizeof(dirname2));
+                                       strlcat(dirname2, "/", sizeof(dirname2));
+                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
+                                       if (attr_filtered(dirname2))
+                                               continue;
+                                       device_list_insert(dirname2);
+                               }
+                               closedir(dir2);
+                       }
+               }
+               closedir(dir);
+       }
+}
+
+static void scan_failed(void)
+{
+       char base[PATH_SIZE];
+       DIR *dir;
+       struct dirent *dent;
+
+       strlcpy(base, udev_root, sizeof(base));
+       strlcat(base, "/.udev/failed", sizeof(base));
+
+       dir = opendir(base);
+       if (dir != NULL) {
+               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                       char device[PATH_SIZE];
+                       size_t start;
+
+                       if (dent->d_name[0] == '.')
+                               continue;
+
+                       start = strlcpy(device, sysfs_path, sizeof(device));
+                       if(start >= sizeof(device))
+                               start = sizeof(device) - 1;
+                       strlcat(device, dent->d_name, sizeof(device));
+                       path_decode(&device[start]);
+                       device_list_insert(device);
+               }
+               closedir(dir);
+       }
+}
+
+int udevtrigger(int argc, char *argv[])
+{
+       int failed = 0;
+       const char *sockpath = NULL;
+       int option;
+       const char *action = "add";
+       const char *env = NULL;
+       static const struct option options[] = {
+               { "verbose", 0, NULL, 'v' },
+               { "dry-run", 0, NULL, 'n' },
+               { "retry-failed", 0, NULL, 'F' },
+               { "socket", 1, NULL, 'o' },
+               { "help", 0, NULL, 'h' },
+               { "action", 1, NULL, 'c' },
+               { "subsystem-match", 1, NULL, 's' },
+               { "subsystem-nomatch", 1, NULL, 'S' },
+               { "attr-match", 1, NULL, 'a' },
+               { "attr-nomatch", 1, NULL, 'A' },
+               { "env", 1, NULL, 'e' },
+               {}
+       };
+
+       logging_init("udevtrigger");
+       udev_config_init();
+       dbg("version %s\n", VERSION);
+       sysfs_init();
+
+       while (1) {
+               option = getopt_long(argc, argv, "vnFo:hce::s:S:a:A:", options, NULL);
+               if (option == -1)
+                       break;
+
+               switch (option) {
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 'n':
+                       dry_run = 1;
+                       break;
+               case 'F':
+                       failed = 1;
+                       break;
+               case 'o':
+                       sockpath = optarg;
+                       break;
+               case 'c':
+                       action = optarg;
+                       break;
+               case 'e':
+                       if (strchr(optarg, '=') != NULL)
+                               env = optarg;
+                       break;
+               case 's':
+                       name_list_add(&filter_subsystem_match_list, optarg, 0);
+                       break;
+               case 'S':
+                       name_list_add(&filter_subsystem_nomatch_list, optarg, 0);
+                       break;
+               case 'a':
+                       name_list_add(&filter_attr_match_list, optarg, 0);
+                       break;
+               case 'A':
+                       name_list_add(&filter_attr_nomatch_list, optarg, 0);
+                       break;
+               case 'h':
+                       printf("Usage: udevadm trigger OPTIONS\n"
+                              "  --verbose                       print the list of devices while running\n"
+                              "  --dry-run                       do not actually trigger the events\n"
+                              "  --retry-failed                  trigger only the events which have been\n"
+                              "                                  marked as failed during a previous run\n"
+                              "  --socket=<socket path>          pass events to socket instead of triggering kernel events\n"
+                              "  --env=<KEY>=<value>             pass an additional key (works only with --socket=)\n"
+                              "  --subsystem-match=<subsystem>   trigger devices from a matching subystem\n"
+                              "  --subsystem-nomatch=<subsystem> exclude devices from a matching subystem\n"
+                              "  --attr-match=<file[=<value>]>   trigger devices with a matching sysfs\n"
+                              "                                  attribute\n"
+                              "  --attr-nomatch=<file[=<value>]> exclude devices with a matching sysfs\n"
+                              "                                  attribute\n"
+                              "  --help                          print this text\n"
+                              "\n");
+                       goto exit;
+               default:
+                       goto exit;
+               }
+       }
+
+       if (sockpath != NULL) {
+               struct stat stats;
+
+               sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+               memset(&saddr, 0x00, sizeof(struct sockaddr_un));
+               saddr.sun_family = AF_LOCAL;
+               if (sockpath[0] == '@') {
+                       /* abstract namespace socket requested */
+                       strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1);
+                       saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+               } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) {
+                       /* existing socket file */
+                       strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path));
+                       saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
+               } else {
+                       /* no socket file, assume abstract namespace socket */
+                       strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1);
+                       saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+               }
+       } else if (env != NULL) {
+               fprintf(stderr, "error: --env= only valid with --socket= option\n");
+               goto exit;
+       }
+
+       if (failed) {
+               scan_failed();
+               exec_list(action, env);
+       } else {
+               char base[PATH_SIZE];
+               struct stat statbuf;
+
+               /* if we have /sys/subsystem, forget all the old stuff */
+               strlcpy(base, sysfs_path, sizeof(base));
+               strlcat(base, "/subsystem", sizeof(base));
+               if (stat(base, &statbuf) == 0) {
+                       scan_subsystem("subsystem", SCAN_SUBSYSTEM);
+                       exec_list(action, env);
+                       scan_subsystem("subsystem", SCAN_DEVICES);
+                       exec_list(action, env);
+               } else {
+                       scan_subsystem("bus", SCAN_SUBSYSTEM);
+                       exec_list(action, env);
+                       scan_subsystem("bus", SCAN_DEVICES);
+                       scan_class();
+
+                       /* scan "block" if it isn't a "class" */
+                       strlcpy(base, sysfs_path, sizeof(base));
+                       strlcat(base, "/class/block", sizeof(base));
+                       if (stat(base, &statbuf) != 0)
+                               scan_block();
+                       exec_list(action, env);
+               }
+       }
+
+exit:
+       name_list_cleanup(&filter_subsystem_match_list);
+       name_list_cleanup(&filter_subsystem_nomatch_list);
+       name_list_cleanup(&filter_attr_match_list);
+       name_list_cleanup(&filter_attr_nomatch_list);
+
+       if (sock >= 0)
+               close(sock);
+       sysfs_cleanup();
+       logging_close();
+       return 0;
+}
diff --git a/udev/udevcontrol.c b/udev/udevcontrol.c
deleted file mode 100644 (file)
index 5f19525..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include "config.h"
-
-#include <time.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/un.h>
-
-#include "udev.h"
-#include "udevd.h"
-
-static int udev_log = 0;
-
-struct udev_ctrl;
-extern struct udev_ctrl *udev_ctrl_new_from_socket(const char *socket_path);
-extern void udev_ctrl_unref(struct udev_ctrl *uctrl);
-extern int udev_ctrl_set_log_level(struct udev_ctrl *uctrl, int priority);
-extern int udev_ctrl_stop_exec_queue(struct udev_ctrl *uctrl);
-extern int udev_ctrl_start_exec_queue(struct udev_ctrl *uctrl);
-extern int udev_ctrl_reload_rules(struct udev_ctrl *uctrl);
-extern int udev_ctrl_set_env(struct udev_ctrl *uctrl, const char *key);
-extern int udev_ctrl_set_max_childs(struct udev_ctrl *uctrl, int count);
-extern int udev_ctrl_set_max_childs_running(struct udev_ctrl *uctrl, int count);
-
-struct udev_ctrl {
-       int sock;
-       struct sockaddr_un saddr;
-       socklen_t addrlen;
-};
-
-struct udev_ctrl *udev_ctrl_new_from_socket(const char *socket_path)
-{
-       struct udev_ctrl *uctrl;
-
-       uctrl = malloc(sizeof(struct udev_ctrl));
-       if (uctrl == NULL)
-               return NULL;
-       memset(uctrl, 0x00, sizeof(struct udev_ctrl));
-
-       uctrl->sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-       if (uctrl->sock < 0) {
-               err("error getting socket: %s\n", strerror(errno));
-               free(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;
-}
-
-void udev_ctrl_unref(struct udev_ctrl *uctrl)
-{
-       if (uctrl == NULL)
-               return;
-       close(uctrl->sock);
-}
-
-static int ctrl_send(struct udev_ctrl *uctrl, enum udevd_ctrl_msg_type type, int intval, const char *buf)
-{
-       struct udevd_ctrl_msg ctrl_msg;
-       int err;
-
-       memset(&ctrl_msg, 0x00, sizeof(struct udevd_ctrl_msg));
-       strcpy(ctrl_msg.magic, UDEVD_CTRL_MAGIC);
-       ctrl_msg.type = type;
-
-       if (buf != NULL)
-               strlcpy(ctrl_msg.buf, buf, sizeof(ctrl_msg.buf));
-       else
-               ctrl_msg.intval = intval;
-
-       err = sendto(uctrl->sock, &ctrl_msg, sizeof(ctrl_msg), 0, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
-       if (err == -1) {
-               err("error sending message: %s\n", strerror(errno));
-       }
-       return err;
-}
-
-int udev_ctrl_set_log_level(struct udev_ctrl *uctrl, int priority)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_SET_LOG_LEVEL, priority, NULL);
-       return 0;
-}
-
-int udev_ctrl_stop_exec_queue(struct udev_ctrl *uctrl)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_STOP_EXEC_QUEUE, 0, NULL);
-       return 0;
-}
-
-int udev_ctrl_start_exec_queue(struct udev_ctrl *uctrl)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_START_EXEC_QUEUE, 0, NULL);
-       return 0;
-}
-
-int udev_ctrl_reload_rules(struct udev_ctrl *uctrl)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_RELOAD_RULES, 0, NULL);
-       return 0;
-}
-
-int udev_ctrl_set_env(struct udev_ctrl *uctrl, const char *key)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_ENV, 0, optarg);
-       return 0;
-}
-
-int udev_ctrl_set_max_childs(struct udev_ctrl *uctrl, int count)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_SET_MAX_CHILDS, count, NULL);
-       return 0;
-}
-
-int udev_ctrl_set_max_childs_running(struct udev_ctrl *uctrl, int count)
-{
-       ctrl_send(uctrl, UDEVD_CTRL_SET_MAX_CHILDS_RUNNING, count, NULL);
-       return 0;
-}
-
-int udevcontrol(int argc, char *argv[])
-{
-       struct udev_ctrl *uctrl;
-       const char *env;
-       int rc = 1;
-
-       /* compat values with '_' will be removed in a future release */
-       static const struct option options[] = {
-               { "log-priority", 1, NULL, 'l' },
-               { "log_priority", 1, NULL, 'l' + 256 },
-               { "stop-exec-queue", 0, NULL, 's' },
-               { "stop_exec_queue", 0, NULL, 's' + 256 },
-               { "start-exec-queue", 0, NULL, 'S' },
-               { "start_exec_queue", 0, NULL, 'S' + 256},
-               { "reload-rules", 0, NULL, 'R' },
-               { "reload_rules", 0, NULL, 'R' + 256},
-               { "env", 1, NULL, 'e' },
-               { "max-childs", 1, NULL, 'm' },
-               { "max_childs", 1, NULL, 'm' + 256},
-               { "max-childs-running", 1, NULL, 'M' },
-               { "max_childs_running", 1, NULL, 'M' + 256},
-               { "help", 0, NULL, 'h' },
-               {}
-       };
-
-       env = getenv("UDEV_LOG");
-       if (env)
-               udev_log = log_priority(env);
-
-       logging_init("udevcontrol");
-       dbg("version %s\n", VERSION);
-
-       if (getuid() != 0) {
-               fprintf(stderr, "root privileges required\n");
-               goto exit;
-       }
-
-       uctrl = udev_ctrl_new_from_socket(UDEVD_CTRL_SOCK_PATH);
-       if (uctrl == NULL)
-               goto exit;
-
-       while (1) {
-               int option;
-               int i;
-               char *endp;
-
-               option = getopt_long(argc, argv, "l:sSRe:m:M:h", options, NULL);
-               if (option == -1)
-                       break;
-
-               if (option > 255) {
-                       info("udevadm control expects commands without underscore, "
-                           "this will stop working in a future release\n");
-                       fprintf(stderr, "udevadm control expects commands without underscore, "
-                               "this will stop working in a future release\n");
-               }
-
-               switch (option) {
-               case 'l':
-               case 'l' + 256:
-                       i = log_priority(optarg);
-                       if (i < 0) {
-                               fprintf(stderr, "invalid number '%s'\n", optarg);
-                               goto exit;
-                       }
-                       udev_ctrl_set_log_level(uctrl, log_priority(optarg));
-                       break;
-               case 's':
-               case 's' + 256:
-                       udev_ctrl_stop_exec_queue(uctrl);
-                       break;
-               case 'S':
-               case 'S' + 256:
-                       udev_ctrl_start_exec_queue(uctrl);
-                       break;
-               case 'R':
-               case 'R' + 256:
-                       udev_ctrl_reload_rules(uctrl);
-                       break;
-               case 'e':
-                       if (strchr(optarg, '=') == NULL) {
-                               fprintf(stderr, "expect <KEY>=<valaue> instead of '%s'\n", optarg);
-                               goto exit;
-                       }
-                       udev_ctrl_set_env(uctrl, optarg);
-                       break;
-               case 'm':
-               case 'm' + 256:
-                       i = strtoul(optarg, &endp, 0);
-                       if (endp[0] != '\0' || i < 1) {
-                               fprintf(stderr, "invalid number '%s'\n", optarg);
-                               goto exit;
-                       }
-                       udev_ctrl_set_max_childs(uctrl, i);
-                       break;
-               case 'M':
-               case 'M' + 256:
-                       i = strtoul(optarg, &endp, 0);
-                       if (endp[0] != '\0' || i < 1) {
-                               fprintf(stderr, "invalid number '%s'\n", optarg);
-                               goto exit;
-                       }
-                       udev_ctrl_set_max_childs_running(uctrl, i);
-                       break;
-                       break;
-               case 'h':
-                       printf("Usage: udevadm control COMMAND\n"
-                               "  --log-priority=<level>   set the udev log level for the daemon\n"
-                               "  --stop-exec-queue        keep udevd from executing events, queue only\n"
-                               "  --start-exec-queue       execute events, flush queue\n"
-                               "  --reload-rules           reloads the rules files\n"
-                               "  --env=<KEY>=<value>      set a global environment variable\n"
-                               "  --max-childs=<N>         maximum number of childs\n"
-                               "  --max-childs-running=<N> maximum number of childs running at the same time\n"
-                               "  --help                   print this help text\n\n");
-                       goto exit;
-               default:
-                       goto exit;
-               }
-       }
-
-       /* compat stuff which will be removed in a future release */
-       if (argv[optind] != NULL) {
-               const char *arg = argv[optind];
-
-               fprintf(stderr, "udevadm control commands requires the --<command> format, "
-                       "this will stop working in a future release\n");
-               err("udevadm control commands requires the --<command> format, "
-                   "this will stop working in a future release\n");
-
-               if (!strncmp(arg, "log_priority=", strlen("log_priority="))) {
-                       udev_ctrl_set_log_level(uctrl, log_priority(&arg[strlen("log_priority=")]));
-               } else if (!strcmp(arg, "stop_exec_queue")) {
-                       udev_ctrl_stop_exec_queue(uctrl);
-               } else if (!strcmp(arg, "start_exec_queue")) {
-                       udev_ctrl_start_exec_queue(uctrl);
-               } else if (!strcmp(arg, "reload_rules")) {
-                       udev_ctrl_reload_rules(uctrl);
-               } else if (!strncmp(arg, "max_childs=", strlen("max_childs="))) {
-                       udev_ctrl_set_max_childs(uctrl, strtoul(&arg[strlen("max_childs=")], NULL, 0));
-               } else if (!strncmp(arg, "max_childs_running=", strlen("max_childs_running="))) {
-                       udev_ctrl_set_max_childs_running(uctrl, strtoul(&arg[strlen("max_childs_running=")], NULL, 0));
-               } else if (!strncmp(arg, "env", strlen("env"))) {
-                       udev_ctrl_set_env(uctrl, &arg[strlen("env=")]);
-               } else {
-                       fprintf(stderr, "unrecognized command '%s'\n", arg);
-                       err("unrecognized command '%s'\n", arg);
-               }
-       }
-exit:
-       udev_ctrl_unref(uctrl);
-       logging_close();
-       return rc;
-}
index 7405704c7a15e66b78203afe79197c161610ddea..a22bc96e5d5564f013878ce4a667b07d18fc4455 100644 (file)
@@ -32,7 +32,7 @@
 #define UEVENT_NUM_ENVP                        32
 
 #define UDEVD_CTRL_SOCK_PATH           "@" UDEV_PREFIX "/org/kernel/udev/udevd"
-#define UDEVD_CTRL_MAGIC               "udevd_" VERSION
+#define UDEVD_CTRL_MAGIC               "udevd-128"
 
 enum udevd_ctrl_msg_type {
        UDEVD_CTRL_UNKNOWN,
diff --git a/udev/udevinfo.c b/udev/udevinfo.c
deleted file mode 100644 (file)
index 6501b57..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <errno.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "udev.h"
-
-static void print_all_attributes(const char *devpath, const char *key)
-{
-       char path[PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       strlcpy(path, sysfs_path, sizeof(path));
-       strlcat(path, devpath, sizeof(path));
-
-       dir = opendir(path);
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       struct stat statbuf;
-                       char filename[PATH_SIZE];
-                       char *attr_value;
-                       char value[NAME_SIZE];
-                       size_t len;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       if (strcmp(dent->d_name, "uevent") == 0)
-                               continue;
-                       if (strcmp(dent->d_name, "dev") == 0)
-                               continue;
-
-                       strlcpy(filename, path, sizeof(filename));
-                       strlcat(filename, "/", sizeof(filename));
-                       strlcat(filename, dent->d_name, sizeof(filename));
-                       if (lstat(filename, &statbuf) != 0)
-                               continue;
-                       if (S_ISLNK(statbuf.st_mode))
-                               continue;
-
-                       attr_value = sysfs_attr_get_value(devpath, dent->d_name);
-                       if (attr_value == NULL)
-                               continue;
-                       len = strlcpy(value, attr_value, sizeof(value));
-                       if(len >= sizeof(value))
-                               len = sizeof(value) - 1;
-                       dbg("attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
-
-                       /* remove trailing newlines */
-                       while (len && value[len-1] == '\n')
-                               value[--len] = '\0';
-
-                       /* skip nonprintable attributes */
-                       while (len && isprint(value[len-1]))
-                               len--;
-                       if (len) {
-                               dbg("attribute value of '%s' non-printable, skip\n", dent->d_name);
-                               continue;
-                       }
-
-                       printf("    %s{%s}==\"%s\"\n", key, dent->d_name, value);
-               }
-       }
-       printf("\n");
-}
-
-static int print_device_chain(const char *devpath)
-{
-       struct sysfs_device *dev;
-
-       dev = sysfs_device_get(devpath);
-       if (dev == NULL)
-               return -1;
-
-       printf("\n"
-              "Udevinfo starts with the device specified by the devpath and then\n"
-              "walks up the chain of parent devices. It prints for every device\n"
-              "found, all possible attributes in the udev rules key format.\n"
-              "A rule to match, can be composed by the attributes of the device\n"
-              "and the attributes from one single parent device.\n"
-              "\n");
-
-       printf("  looking at device '%s':\n", dev->devpath);
-       printf("    KERNEL==\"%s\"\n", dev->kernel);
-       printf("    SUBSYSTEM==\"%s\"\n", dev->subsystem);
-       printf("    DRIVER==\"%s\"\n", dev->driver);
-       print_all_attributes(dev->devpath, "ATTR");
-
-       /* walk up the chain of devices */
-       while (1) {
-               dev = sysfs_device_get_parent(dev);
-               if (dev == NULL)
-                       break;
-               printf("  looking at parent device '%s':\n", dev->devpath);
-               printf("    KERNELS==\"%s\"\n", dev->kernel);
-               printf("    SUBSYSTEMS==\"%s\"\n", dev->subsystem);
-               printf("    DRIVERS==\"%s\"\n", dev->driver);
-
-               print_all_attributes(dev->devpath, "ATTRS");
-       }
-
-       return 0;
-}
-
-static void print_record(struct udevice *udev)
-{
-       struct name_entry *name_loop;
-
-       printf("P: %s\n", udev->dev->devpath);
-       printf("N: %s\n", udev->name);
-       list_for_each_entry(name_loop, &udev->symlink_list, node)
-               printf("S: %s\n", name_loop->name);
-       if (udev->link_priority != 0)
-               printf("L: %i\n", udev->link_priority);
-       if (udev->partitions != 0)
-               printf("A:%u\n", udev->partitions);
-       if (udev->ignore_remove)
-               printf("R:%u\n", udev->ignore_remove);
-       list_for_each_entry(name_loop, &udev->env_list, node)
-               printf("E: %s\n", name_loop->name);
-}
-
-static void export_db(void) {
-       LIST_HEAD(name_list);
-       struct name_entry *name_loop;
-
-       udev_db_get_all_entries(&name_list);
-       list_for_each_entry(name_loop, &name_list, node) {
-               struct udevice *udev_db;
-
-               udev_db = udev_device_init();
-               if (udev_db == NULL)
-                       continue;
-               if (udev_db_get_device(udev_db, name_loop->name) == 0)
-                       print_record(udev_db);
-                       printf("\n");
-               udev_device_cleanup(udev_db);
-       }
-       name_list_cleanup(&name_list);
-}
-
-static int lookup_device_by_name(struct udevice **udev, const char *name)
-{
-       LIST_HEAD(name_list);
-       int count;
-       struct name_entry *device;
-       int rc  = -1;
-
-       count = udev_db_get_devices_by_name(name, &name_list);
-       if (count <= 0)
-               goto out;
-
-       info("found %i devices for '%s'\n", count, name);
-
-       /* select the device that seems to match */
-       list_for_each_entry(device, &name_list, node) {
-               struct udevice *udev_loop;
-               char filename[PATH_SIZE];
-               struct stat statbuf;
-
-               udev_loop = udev_device_init();
-               if (udev_loop == NULL)
-                       break;
-               if (udev_db_get_device(udev_loop, device->name) != 0)
-                       goto next;
-               info("found db entry '%s'\n", device->name);
-
-               /* make sure, we don't get a link of a different device */
-               strlcpy(filename, udev_root, sizeof(filename));
-               strlcat(filename, "/", sizeof(filename));
-               strlcat(filename, name, sizeof(filename));
-               if (stat(filename, &statbuf) != 0)
-                       goto next;
-               if (major(udev_loop->devt) > 0 && udev_loop->devt != statbuf.st_rdev) {
-                       info("skip '%s', dev_t doesn't match\n", udev_loop->name);
-                       goto next;
-               }
-               rc = 0;
-               *udev = udev_loop;
-               break;
-next:
-               udev_device_cleanup(udev_loop);
-       }
-out:
-       name_list_cleanup(&name_list);
-       return rc;
-}
-
-static int stat_device(const char *name, int export, const char *prefix)
-{
-       struct stat statbuf;
-
-       if (stat(name, &statbuf) != 0)
-               return -1;
-
-       if (export) {
-               if (prefix == NULL)
-                       prefix = "INFO_";
-               printf("%sMAJOR=%d\n"
-                      "%sMINOR=%d\n",
-                      prefix, major(statbuf.st_dev),
-                      prefix, minor(statbuf.st_dev));
-       } else
-               printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
-       return 0;
-}
-
-int udevinfo(int argc, char *argv[])
-{
-       int option;
-       struct udevice *udev = NULL;
-       int root = 0;
-       int export = 0;
-       const char *export_prefix = NULL;
-
-       static const struct option options[] = {
-               { "name", 1, NULL, 'n' },
-               { "path", 1, NULL, 'p' },
-               { "query", 1, NULL, 'q' },
-               { "attribute-walk", 0, NULL, 'a' },
-               { "export-db", 0, NULL, 'e' },
-               { "root", 0, NULL, 'r' },
-               { "device-id-of-file", 1, NULL, 'd' },
-               { "export", 0, NULL, 'x' },
-               { "export-prefix", 1, NULL, 'P' },
-               { "version", 0, NULL, 1 }, /* -V outputs braindead format */
-               { "help", 0, NULL, 'h' },
-               {}
-       };
-
-       enum action_type {
-               ACTION_NONE,
-               ACTION_QUERY,
-               ACTION_ATTRIBUTE_WALK,
-               ACTION_ROOT,
-               ACTION_DEVICE_ID_FILE,
-       } action = ACTION_NONE;
-
-       enum query_type {
-               QUERY_NONE,
-               QUERY_NAME,
-               QUERY_PATH,
-               QUERY_SYMLINK,
-               QUERY_ENV,
-               QUERY_ALL,
-       } query = QUERY_NONE;
-
-       char path[PATH_SIZE] = "";
-       char name[PATH_SIZE] = "";
-       struct name_entry *name_loop;
-       int rc = 0;
-
-       logging_init("udevinfo");
-       udev_config_init();
-       sysfs_init();
-
-       while (1) {
-               option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
-               if (option == -1)
-                       break;
-
-               dbg("option '%c'\n", option);
-               switch (option) {
-               case 'n':
-                       /* remove /dev if given */
-                       if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
-                               strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
-                       else
-                               strlcpy(name, optarg, sizeof(name));
-                       remove_trailing_chars(name, '/');
-                       dbg("name: %s\n", name);
-                       break;
-               case 'p':
-                       /* remove /sys if given */
-                       if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
-                               strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
-                       else
-                               strlcpy(path, optarg, sizeof(path));
-                       remove_trailing_chars(path, '/');
-
-                       /* possibly resolve to real devpath */
-                       if (sysfs_resolve_link(path, sizeof(path)) != 0) {
-                               char temp[PATH_SIZE];
-                               char *pos;
-
-                               /* also check if the parent is a link */
-                               strlcpy(temp, path, sizeof(temp));
-                               pos = strrchr(temp, '/');
-                               if (pos != 0) {
-                                       char tail[PATH_SIZE];
-
-                                       strlcpy(tail, pos, sizeof(tail));
-                                       pos[0] = '\0';
-                                       if (sysfs_resolve_link(temp, sizeof(temp)) == 0) {
-                                               strlcpy(path, temp, sizeof(path));
-                                               strlcat(path, tail, sizeof(path));
-                                       }
-                               }
-                       }
-                       dbg("path: %s\n", path);
-                       break;
-               case 'q':
-                       action = ACTION_QUERY;
-                       if (strcmp(optarg, "name") == 0) {
-                               query = QUERY_NAME;
-                               break;
-                       }
-                       if (strcmp(optarg, "symlink") == 0) {
-                               query = QUERY_SYMLINK;
-                               break;
-                       }
-                       if (strcmp(optarg, "path") == 0) {
-                               query = QUERY_PATH;
-                               break;
-                       }
-                       if (strcmp(optarg, "env") == 0) {
-                               query = QUERY_ENV;
-                               break;
-                       }
-                       if (strcmp(optarg, "all") == 0) {
-                               query = QUERY_ALL;
-                               break;
-                       }
-                       fprintf(stderr, "unknown query type\n");
-                       rc = 2;
-                       goto exit;
-               case 'r':
-                       if (action == ACTION_NONE)
-                               action = ACTION_ROOT;
-                       root = 1;
-                       break;
-               case 'd':
-                       action = ACTION_DEVICE_ID_FILE;
-                       strlcpy(name, optarg, sizeof(name));
-                       break;
-               case 'a':
-                       action = ACTION_ATTRIBUTE_WALK;
-                       break;
-               case 'e':
-                       export_db();
-                       goto exit;
-               case 'x':
-                       export = 1;
-                       break;
-               case 'P':
-                       export_prefix = optarg;
-                       break;
-               case 1:
-                       printf("%s\n", VERSION);
-                       goto exit;
-               case 'V':
-                       printf("udevinfo, version %s\n", VERSION);
-                       goto exit;
-               case 'h':
-                       printf("Usage: udevadm info OPTIONS\n"
-                              "  --query=<type>             query database for the specified value:\n"
-                              "      name                     name of device node\n"
-                              "      symlink                  pointing to node\n"
-                              "      path                     sysfs device path\n"
-                              "      env                      the device related imported environment\n"
-                              "      all                      all values\n"
-                              "  --path=<devpath>           sysfs device path used for query or chain\n"
-                              "  --name=<name>              node or symlink name used for query\n"
-                              "  --root                     prepend to query result or print udev_root\n"
-                              "  --attribute-walk           print all key matches while walking along chain\n"
-                              "                             of parent devices\n"
-                              "  --device-id-of-file=<file> print major/minor of underlying device\n"
-                              "  --export-db                export the content of the udev database\n"
-                              "  --help                     print this text\n"
-                              "\n");
-                       goto exit;
-               default:
-                       goto exit;
-               }
-       }
-
-       /* run action */
-       switch (action) {
-       case ACTION_QUERY:
-               /* needs devpath or node/symlink name for query */
-               if (path[0] != '\0') {
-                       udev = udev_device_init();
-                       if (udev == NULL) {
-                               rc = 1;
-                               goto exit;
-                       }
-                       if (udev_db_get_device(udev, path) != 0) {
-                               fprintf(stderr, "no record for '%s' in database\n", path);
-                               rc = 3;
-                               goto exit;
-                       }
-               } else if (name[0] != '\0') {
-                       if (lookup_device_by_name(&udev, name) != 0) {
-                               fprintf(stderr, "node name not found\n");
-                               rc = 4;
-                               goto exit;
-                       }
-               } else {
-                       fprintf(stderr, "query needs --path or node --name specified\n");
-                       rc = 4;
-                       goto exit;
-               }
-
-               switch(query) {
-               case QUERY_NAME:
-                       if (root)
-                               printf("%s/%s\n", udev_root, udev->name);
-                       else
-                               printf("%s\n", udev->name);
-                       break;
-               case QUERY_SYMLINK:
-                       list_for_each_entry(name_loop, &udev->symlink_list, node) {
-                               char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
-
-                               if (root)
-                                       printf("%s/%s%c", udev_root, name_loop->name, c);
-                               else
-                                       printf("%s%c", name_loop->name, c);
-                       }
-                       break;
-               case QUERY_PATH:
-                       printf("%s\n", udev->dev->devpath);
-                       goto exit;
-               case QUERY_ENV:
-                       list_for_each_entry(name_loop, &udev->env_list, node)
-                               printf("%s\n", name_loop->name);
-                       break;
-               case QUERY_ALL:
-                       print_record(udev);
-                       break;
-               default:
-                       fprintf(stderr, "unknown query type\n");
-                       break;
-               }
-               break;
-       case ACTION_ATTRIBUTE_WALK:
-               if (path[0] != '\0') {
-                       if (print_device_chain(path) != 0) {
-                               fprintf(stderr, "no valid sysfs device found\n");
-                               rc = 4;
-                               goto exit;
-                       }
-               } else if (name[0] != '\0') {
-                       if (lookup_device_by_name(&udev, name) != 0) {
-                               fprintf(stderr, "node name not found\n");
-                               rc = 4;
-                               goto exit;
-                       }
-                       if (print_device_chain(udev->dev->devpath) != 0) {
-                               fprintf(stderr, "no valid sysfs device found\n");
-                               rc = 4;
-                               goto exit;
-                       }
-               } else {
-                       fprintf(stderr, "attribute walk needs --path or node --name specified\n");
-                       rc = 5;
-                       goto exit;
-               }
-               break;
-       case ACTION_DEVICE_ID_FILE:
-               if (stat_device(name, export, export_prefix) != 0)
-                       rc = 6;
-               break;
-       case ACTION_ROOT:
-               printf("%s\n", udev_root);
-               break;
-       default:
-               fprintf(stderr, "missing option\n");
-               rc = 1;
-               break;
-       }
-
-exit:
-       udev_device_cleanup(udev);
-       sysfs_cleanup();
-       logging_close();
-       return rc;
-}
diff --git a/udev/udevmonitor.c b/udev/udevmonitor.c
deleted file mode 100644 (file)
index 3b65bca..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <getopt.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <linux/types.h>
-#include <linux/netlink.h>
-
-#include "udev.h"
-#include "udevd.h"
-
-static int uevent_netlink_sock = -1;
-static int udev_monitor_sock = -1;
-static volatile int udev_exit;
-
-static int init_udev_monitor_socket(void)
-{
-       struct sockaddr_un saddr;
-       socklen_t addrlen;
-       int retval;
-
-       memset(&saddr, 0x00, sizeof(saddr));
-       saddr.sun_family = AF_LOCAL;
-       /* use abstract namespace for socket path */
-       strcpy(&saddr.sun_path[1], "/org/kernel/udev/monitor");
-       addrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
-
-       udev_monitor_sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-       if (udev_monitor_sock == -1) {
-               fprintf(stderr, "error getting socket: %s\n", strerror(errno));
-               return -1;
-       }
-
-       /* the bind takes care of ensuring only one copy running */
-       retval = bind(udev_monitor_sock, (struct sockaddr *) &saddr, addrlen);
-       if (retval < 0) {
-               fprintf(stderr, "bind failed: %s\n", strerror(errno));
-               close(udev_monitor_sock);
-               udev_monitor_sock = -1;
-               return -1;
-       }
-
-       return 0;
-}
-
-static int init_uevent_netlink_sock(void)
-{
-       struct sockaddr_nl snl;
-       int retval;
-
-       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
-       snl.nl_family = AF_NETLINK;
-       snl.nl_pid = getpid();
-       snl.nl_groups = 1;
-
-       uevent_netlink_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
-       if (uevent_netlink_sock == -1) {
-               fprintf(stderr, "error getting socket: %s\n", strerror(errno));
-               return -1;
-       }
-
-       retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl,
-                     sizeof(struct sockaddr_nl));
-       if (retval < 0) {
-               fprintf(stderr, "bind failed: %s\n", strerror(errno));
-               close(uevent_netlink_sock);
-               uevent_netlink_sock = -1;
-               return -1;
-       }
-
-       return 0;
-}
-
-static void asmlinkage sig_handler(int signum)
-{
-       if (signum == SIGINT || signum == SIGTERM)
-               udev_exit = 1;
-}
-
-static const char *search_key(const char *searchkey, const char *buf, size_t buflen)
-{
-       size_t bufpos = 0;
-       size_t searchkeylen = strlen(searchkey);
-
-       while (bufpos < buflen) {
-               const char *key;
-               int keylen;
-
-               key = &buf[bufpos];
-               keylen = strlen(key);
-               if (keylen == 0)
-                       break;
-                if ((strncmp(searchkey, key, searchkeylen) == 0) && key[searchkeylen] == '=')
-                       return &key[searchkeylen + 1];
-               bufpos += keylen + 1;
-       }
-       return NULL;
-}
-
-int udevmonitor(int argc, char *argv[])
-{
-       struct sigaction act;
-       int option;
-       int env = 0;
-       int kernel = 0;
-       int udev = 0;
-       fd_set readfds;
-       int retval = 0;
-
-       static const struct option options[] = {
-               { "environment", 0, NULL, 'e' },
-               { "kernel", 0, NULL, 'k' },
-               { "udev", 0, NULL, 'u' },
-               { "help", 0, NULL, 'h' },
-               {}
-       };
-
-       while (1) {
-               option = getopt_long(argc, argv, "ekuh", options, NULL);
-               if (option == -1)
-                       break;
-
-               switch (option) {
-               case 'e':
-                       env = 1;
-                       break;
-               case 'k':
-                       kernel = 1;
-                       break;
-               case 'u':
-                       udev = 1;
-                       break;
-               case 'h':
-                       printf("Usage: udevadm monitor [--environment] [--kernel] [--udev] [--help]\n"
-                              "  --env    print the whole event environment\n"
-                              "  --kernel print kernel uevents\n"
-                              "  --udev   print udev events\n"
-                              "  --help   print this help text\n\n");
-               default:
-                       goto out;
-               }
-       }
-
-       if (!kernel && !udev) {
-               kernel = 1;
-               udev =1;
-       }
-
-       if (getuid() != 0 && kernel) {
-               fprintf(stderr, "root privileges needed to subscribe to kernel events\n");
-               goto out;
-       }
-
-       /* set signal handlers */
-       memset(&act, 0x00, sizeof(struct sigaction));
-       act.sa_handler = (void (*)(int)) sig_handler;
-       sigemptyset(&act.sa_mask);
-       act.sa_flags = SA_RESTART;
-       sigaction(SIGINT, &act, NULL);
-       sigaction(SIGTERM, &act, NULL);
-
-       printf("udevmonitor will print the received events for:\n");
-       if (udev) {
-               retval = init_udev_monitor_socket();
-               if (retval)
-                       goto out;
-               printf("UDEV the event which udev sends out after rule processing\n");
-       }
-       if (kernel) {
-               retval = init_uevent_netlink_sock();
-               if (retval)
-                       goto out;
-               printf("UEVENT the kernel uevent\n");
-       }
-       printf("\n");
-
-       while (!udev_exit) {
-               char buf[UEVENT_BUFFER_SIZE*2];
-               ssize_t buflen;
-               ssize_t bufpos;
-               ssize_t keys;
-               int fdcount;
-               struct timeval tv;
-               struct timezone tz;
-               char timestr[64];
-               const char *source = NULL;
-               const char *devpath, *action, *subsys;
-
-               buflen = 0;
-               FD_ZERO(&readfds);
-               if (uevent_netlink_sock >= 0)
-                       FD_SET(uevent_netlink_sock, &readfds);
-               if (udev_monitor_sock >= 0)
-                       FD_SET(udev_monitor_sock, &readfds);
-
-               fdcount = select(UDEV_MAX(uevent_netlink_sock, udev_monitor_sock)+1, &readfds, NULL, NULL, NULL);
-               if (fdcount < 0) {
-                       if (errno != EINTR)
-                               fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno));
-                       continue;
-               }
-
-               if (gettimeofday(&tv, &tz) == 0) {
-                       snprintf(timestr, sizeof(timestr), "%llu.%06u",
-                                (unsigned long long) tv.tv_sec, (unsigned int) tv.tv_usec);
-               } else
-                       timestr[0] = '\0';
-
-               if ((uevent_netlink_sock >= 0) && FD_ISSET(uevent_netlink_sock, &readfds)) {
-                       buflen = recv(uevent_netlink_sock, &buf, sizeof(buf), 0);
-                       if (buflen <= 0) {
-                               fprintf(stderr, "error receiving uevent message: %s\n", strerror(errno));
-                               continue;
-                       }
-                       source = "UEVENT";
-               }
-
-               if ((udev_monitor_sock >= 0) && FD_ISSET(udev_monitor_sock, &readfds)) {
-                       buflen = recv(udev_monitor_sock, &buf, sizeof(buf), 0);
-                       if (buflen <= 0) {
-                               fprintf(stderr, "error receiving udev message: %s\n", strerror(errno));
-                               continue;
-                       }
-                       source = "UDEV  ";
-               }
-
-               if (buflen == 0)
-                       continue;
-
-               keys = strlen(buf) + 1; /* start of payload */
-               devpath = search_key("DEVPATH", &buf[keys], buflen);
-               action = search_key("ACTION", &buf[keys], buflen);
-               subsys = search_key("SUBSYSTEM", &buf[keys], buflen);
-               printf("%s[%s] %-8s %s (%s)\n", source, timestr, action, devpath, subsys);
-
-               /* print environment */
-               bufpos = keys;
-               if (env) {
-                       while (bufpos < buflen) {
-                               int keylen;
-                               char *key;
-
-                               key = &buf[bufpos];
-                               keylen = strlen(key);
-                               if (keylen == 0)
-                                       break;
-                               printf("%s\n", key);
-                               bufpos += keylen + 1;
-                       }
-                       printf("\n");
-               }
-       }
-
-out:
-       if (uevent_netlink_sock >= 0)
-               close(uevent_netlink_sock);
-       if (udev_monitor_sock >= 0)
-               close(udev_monitor_sock);
-
-       if (retval)
-               return 1;
-       return 0;
-}
diff --git a/udev/udevsettle.c b/udev/udevsettle.c
deleted file mode 100644 (file)
index 11277f5..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2006 Kay Sievers <kay@vrfy.org>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "udev.h"
-#include "udevd.h"
-
-#define DEFAULT_TIMEOUT                        180
-#define LOOP_PER_SECOND                        20
-
-static void print_queue(const char *dir)
-{
-       LIST_HEAD(files);
-       struct name_entry *item;
-
-       if (add_matching_files(&files, dir, NULL) < 0)
-               return;
-
-       printf("\n\nAfter the udevadm settle timeout, the events queue contains:\n\n");
-
-       list_for_each_entry(item, &files, node) {
-               char target[NAME_SIZE];
-               size_t len;
-               const char *filename = strrchr(item->name, '/');
-
-               if (filename == NULL)
-                       continue;
-               filename++;
-               if (*filename == '\0')
-                       continue;
-
-               len = readlink(item->name, target, sizeof(target));
-               if (len < 0)
-                       continue;
-               target[len] = '\0';
-
-               printf("%s: %s\n", filename, target);
-       }
-
-       printf("\n\n");
-}
-
-int udevsettle(int argc, char *argv[])
-{
-       char queuename[PATH_SIZE];
-       char filename[PATH_SIZE];
-       unsigned long long seq_kernel;
-       unsigned long long seq_udev;
-       char seqnum[32];
-       int fd;
-       ssize_t len;
-       int timeout = DEFAULT_TIMEOUT;
-       int loop;
-       static const struct option options[] = {
-               { "timeout", 1, NULL, 't' },
-               { "help", 0, NULL, 'h' },
-               {}
-       };
-       int option;
-       int rc = 1;
-       int seconds;
-
-       logging_init("udevsettle");
-       udev_config_init();
-       dbg("version %s\n", VERSION);
-       sysfs_init();
-
-       while (1) {
-               option = getopt_long(argc, argv, "t:h", options, NULL);
-               if (option == -1)
-                       break;
-
-               switch (option) {
-               case 't':
-                       seconds = atoi(optarg);
-                       if (seconds > 0)
-                               timeout = seconds;
-                       else
-                               fprintf(stderr, "invalid timeout value\n");
-                       dbg("timeout=%i\n", timeout);
-                       break;
-               case 'h':
-                       printf("Usage: udevadm settle [--help] [--timeout=<seconds>]\n\n");
-                       goto exit;
-               }
-       }
-
-       strlcpy(queuename, udev_root, sizeof(queuename));
-       strlcat(queuename, "/.udev/queue", sizeof(queuename));
-
-       loop = timeout * LOOP_PER_SECOND;
-       while (loop--) {
-               /* wait for events in queue to finish */
-               while (loop--) {
-                       struct stat statbuf;
-
-                       if (stat(queuename, &statbuf) < 0) {
-                               info("queue is empty\n");
-                               break;
-                       }
-                       usleep(1000 * 1000 / LOOP_PER_SECOND);
-               }
-               if (loop <= 0) {
-                       info("timeout waiting for queue\n");
-                       print_queue(queuename);
-                       goto exit;
-               }
-
-               /* read current udev seqnum */
-               strlcpy(filename, udev_root, sizeof(filename));
-               strlcat(filename, "/.udev/uevent_seqnum", sizeof(filename));
-               fd = open(filename, O_RDONLY);
-               if (fd < 0)
-                       goto exit;
-               len = read(fd, seqnum, sizeof(seqnum)-1);
-               close(fd);
-               if (len <= 0)
-                       goto exit;
-               seqnum[len] = '\0';
-               seq_udev = strtoull(seqnum, NULL, 10);
-               info("udev seqnum = %llu\n", seq_udev);
-
-               /* read current kernel seqnum */
-               strlcpy(filename, sysfs_path, sizeof(filename));
-               strlcat(filename, "/kernel/uevent_seqnum", sizeof(filename));
-               fd = open(filename, O_RDONLY);
-               if (fd < 0)
-                       goto exit;
-               len = read(fd, seqnum, sizeof(seqnum)-1);
-               close(fd);
-               if (len <= 0)
-                       goto exit;
-               seqnum[len] = '\0';
-               seq_kernel = strtoull(seqnum, NULL, 10);
-               info("kernel seqnum = %llu\n", seq_kernel);
-
-               /* make sure all kernel events have arrived in the queue */
-               if (seq_udev >= seq_kernel) {
-                       info("queue is empty and no pending events left\n");
-                       rc = 0;
-                       goto exit;
-               }
-               usleep(1000 * 1000 / LOOP_PER_SECOND);
-               info("queue is empty, but events still pending\n");
-       }
-
-exit:
-       sysfs_cleanup();
-       logging_close();
-       return rc;
-}
diff --git a/udev/udevtest.c b/udev/udevtest.c
deleted file mode 100644 (file)
index 63603aa..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stddef.h>
-#include <unistd.h>
-#include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <syslog.h>
-#include <getopt.h>
-
-#include "udev.h"
-#include "udev_rules.h"
-
-static int import_uevent_var(const char *devpath)
-{
-       char path[PATH_SIZE];
-       static char value[4096]; /* must stay, used with putenv */
-       ssize_t size;
-       int fd;
-       char *key;
-       char *next;
-       int rc = -1;
-
-       /* read uevent file */
-       strlcpy(path, sysfs_path, sizeof(path));
-       strlcat(path, devpath, sizeof(path));
-       strlcat(path, "/uevent", sizeof(path));
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               goto out;
-       size = read(fd, value, sizeof(value));
-       close(fd);
-       if (size < 0)
-               goto out;
-       value[size] = '\0';
-
-       /* import keys into environment */
-       key = value;
-       while (key[0] != '\0') {
-               next = strchr(key, '\n');
-               if (next == NULL)
-                       goto out;
-               next[0] = '\0';
-               info("import into environment: '%s'\n", key);
-               putenv(key);
-               key = &next[1];
-       }
-       rc = 0;
-out:
-       return rc;
-}
-
-int udevtest(int argc, char *argv[])
-{
-       int force = 0;
-       const char *action = "add";
-       const char *subsystem = NULL;
-       const char *devpath = NULL;
-       struct udevice *udev;
-       struct sysfs_device *dev;
-       struct udev_rules rules = {};
-       int retval;
-       int rc = 0;
-
-       static const struct option options[] = {
-               { "action", 1, NULL, 'a' },
-               { "subsystem", 1, NULL, 's' },
-               { "force", 0, NULL, 'f' },
-               { "help", 0, NULL, 'h' },
-               {}
-       };
-
-       info("version %s\n", VERSION);
-       udev_config_init();
-       if (udev_log_priority < LOG_INFO) {
-               char priority[32];
-
-               udev_log_priority = LOG_INFO;
-               sprintf(priority, "%i", udev_log_priority);
-               setenv("UDEV_LOG", priority, 1);
-       }
-
-       while (1) {
-               int option;
-
-               option = getopt_long(argc, argv, "a:s:fh", options, NULL);
-               if (option == -1)
-                       break;
-
-               dbg("option '%c'\n", option);
-               switch (option) {
-               case 'a':
-                       action = optarg;
-                       break;
-               case 's':
-                       subsystem = optarg;
-                       break;
-               case 'f':
-                       force = 1;
-                       break;
-               case 'h':
-                       printf("Usage: udevadm test OPTIONS <devpath>\n"
-                              "  --action=<string>     set action string\n"
-                              "  --subsystem=<string>  set subsystem string\n"
-                              "  --force               don't skip node/link creation\n"
-                              "  --help                print this help text\n\n");
-                       exit(0);
-               default:
-                       exit(1);
-               }
-       }
-       devpath = argv[optind];
-
-       if (devpath == NULL) {
-               fprintf(stderr, "devpath parameter missing\n");
-               rc = 1;
-               goto exit;
-       }
-
-       printf("This program is for debugging only, it does not run any program,\n"
-              "specified by a RUN key. It may show incorrect results, because\n"
-              "some values may be different, or not available at a simulation run.\n"
-              "\n");
-
-       sysfs_init();
-       udev_rules_init(&rules, 0);
-
-       /* remove /sys if given */
-       if (strncmp(devpath, sysfs_path, strlen(sysfs_path)) == 0)
-               devpath = &devpath[strlen(sysfs_path)];
-
-       dev = sysfs_device_get(devpath);
-       if (dev == NULL) {
-               fprintf(stderr, "unable to open device '%s'\n", devpath);
-               rc = 2;
-               goto exit;
-       }
-
-       udev = udev_device_init();
-       if (udev == NULL) {
-               fprintf(stderr, "error initializing device\n");
-               rc = 3;
-               goto exit;
-       }
-
-       if (subsystem != NULL)
-               strlcpy(dev->subsystem, subsystem, sizeof(dev->subsystem));
-
-       /* override built-in sysfs device */
-       udev->dev = dev;
-       strlcpy(udev->action, action, sizeof(udev->action));
-       udev->devt = udev_device_get_devt(udev);
-
-       /* simulate node creation with test flag */
-       if (!force)
-               udev->test_run = 1;
-
-       setenv("DEVPATH", udev->dev->devpath, 1);
-       setenv("SUBSYSTEM", udev->dev->subsystem, 1);
-       setenv("ACTION", udev->action, 1);
-       import_uevent_var(udev->dev->devpath);
-
-       info("looking at device '%s' from subsystem '%s'\n", udev->dev->devpath, udev->dev->subsystem);
-       retval = udev_device_event(&rules, udev);
-
-       if (udev->event_timeout >= 0)
-               info("custom event timeout: %i\n", udev->event_timeout);
-
-       if (retval == 0 && !udev->ignore_device && udev_run) {
-               struct name_entry *name_loop;
-
-               list_for_each_entry(name_loop, &udev->run_list, node) {
-                       char program[PATH_SIZE];
-
-                       strlcpy(program, name_loop->name, sizeof(program));
-                       udev_rules_apply_format(udev, program, sizeof(program));
-                       info("run: '%s'\n", program);
-               }
-       }
-       udev_device_cleanup(udev);
-
-exit:
-       udev_rules_cleanup(&rules);
-       sysfs_cleanup();
-       return rc;
-}
diff --git a/udev/udevtrigger.c b/udev/udevtrigger.c
deleted file mode 100644 (file)
index 4a8f62a..0000000
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Kay Sievers <kay@vrfy.org>
- * Copyright (C) 2006 Hannes Reinecke <hare@suse.de>
- *
- *     This program is free software; you can redistribute it and/or modify it
- *     under the terms of the GNU General Public License as published by the
- *     Free Software Foundation version 2 of the License.
- * 
- *     This program is distributed in the hope that it will be useful, but
- *     WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *     General Public License for more details.
- * 
- *     You should have received a copy of the GNU General Public License along
- *     with this program; if not, write to the Free Software Foundation, Inc.,
- *     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- *
- */
-
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <getopt.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <syslog.h>
-#include <fnmatch.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include "udev.h"
-#include "udevd.h"
-#include "udev_rules.h"
-
-static int verbose;
-static int dry_run;
-LIST_HEAD(device_list);
-LIST_HEAD(filter_subsystem_match_list);
-LIST_HEAD(filter_subsystem_nomatch_list);
-LIST_HEAD(filter_attr_match_list);
-LIST_HEAD(filter_attr_nomatch_list);
-static int sock = -1;
-static struct sockaddr_un saddr;
-static socklen_t saddrlen;
-
-/* devices that should run last cause of their dependencies */
-static int delay_device(const char *devpath)
-{
-       static const char *delay_device_list[] = {
-               "*/md*",
-               "*/dm-*",
-               NULL
-       };
-       int i;
-
-       for (i = 0; delay_device_list[i] != NULL; i++)
-               if (fnmatch(delay_device_list[i], devpath, 0) == 0)
-                       return 1;
-       return 0;
-}
-
-static int device_list_insert(const char *path)
-{
-       char filename[PATH_SIZE];
-       char devpath[PATH_SIZE];
-       struct stat statbuf;
-
-       dbg("add '%s'\n" , path);
-
-       /* we only have a device, if we have an uevent file */
-       strlcpy(filename, path, sizeof(filename));
-       strlcat(filename, "/uevent", sizeof(filename));
-       if (stat(filename, &statbuf) < 0)
-               return -1;
-       if (!(statbuf.st_mode & S_IWUSR))
-               return -1;
-
-       strlcpy(devpath, &path[strlen(sysfs_path)], sizeof(devpath));
-
-       /* resolve possible link to real target */
-       if (lstat(path, &statbuf) < 0)
-               return -1;
-       if (S_ISLNK(statbuf.st_mode))
-               if (sysfs_resolve_link(devpath, sizeof(devpath)) != 0)
-                       return -1;
-
-       name_list_add(&device_list, devpath, 1);
-       return 0;
-}
-
-static void trigger_uevent(const char *devpath, const char *action)
-{
-       char filename[PATH_SIZE];
-       int fd;
-
-       strlcpy(filename, sysfs_path, sizeof(filename));
-       strlcat(filename, devpath, sizeof(filename));
-       strlcat(filename, "/uevent", sizeof(filename));
-
-       if (verbose)
-               printf("%s\n", devpath);
-
-       if (dry_run)
-               return;
-
-       fd = open(filename, O_WRONLY);
-       if (fd < 0) {
-               dbg("error on opening %s: %s\n", filename, strerror(errno));
-               return;
-       }
-
-       if (write(fd, action, strlen(action)) < 0)
-               info("error writing '%s' to '%s': %s\n", action, filename, strerror(errno));
-
-       close(fd);
-}
-
-static int pass_to_socket(const char *devpath, const char *action, const char *env)
-{
-       struct udevice *udev;
-       struct name_entry *name_loop;
-       char buf[4096];
-       size_t bufpos = 0;
-       ssize_t count;
-       char path[PATH_SIZE];
-       int fd;
-       char link_target[PATH_SIZE];
-       int len;
-       int err = 0;
-
-       if (verbose)
-               printf("%s\n", devpath);
-
-       udev = udev_device_init();
-       if (udev == NULL)
-               return -1;
-       udev_db_get_device(udev, devpath);
-
-       /* add header */
-       bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
-       bufpos++;
-
-       /* add cookie */
-       if (env != NULL) {
-               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "%s", env);
-               bufpos++;
-       }
-
-       /* add standard keys */
-       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVPATH=%s", devpath);
-       bufpos++;
-       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "ACTION=%s", action);
-       bufpos++;
-
-       /* add subsystem */
-       strlcpy(path, sysfs_path, sizeof(path));
-       strlcat(path, devpath, sizeof(path));
-       strlcat(path, "/subsystem", sizeof(path));
-       len = readlink(path, link_target, sizeof(link_target));
-       if (len > 0) {
-               char *pos;
-
-               link_target[len] = '\0';
-               pos = strrchr(link_target, '/');
-               if (pos != NULL) {
-                       bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "SUBSYSTEM=%s", &pos[1]);
-                       bufpos++;
-               }
-       }
-
-       /* add symlinks and node name */
-       path[0] = '\0';
-       list_for_each_entry(name_loop, &udev->symlink_list, node) {
-               strlcat(path, udev_root, sizeof(path));
-               strlcat(path, "/", sizeof(path));
-               strlcat(path, name_loop->name, sizeof(path));
-               strlcat(path, " ", sizeof(path));
-       }
-       remove_trailing_chars(path, ' ');
-       if (path[0] != '\0') {
-               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVLINKS=%s", path);
-               bufpos++;
-       }
-       if (udev->name[0] != '\0') {
-               strlcpy(path, udev_root, sizeof(path));
-               strlcat(path, "/", sizeof(path));
-               strlcat(path, udev->name, sizeof(path));
-               bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVNAME=%s", path);
-               bufpos++;
-       }
-
-       /* add keys from device "uevent" file */
-       strlcpy(path, sysfs_path, sizeof(path));
-       strlcat(path, devpath, sizeof(path));
-       strlcat(path, "/uevent", sizeof(path));
-       fd = open(path, O_RDONLY);
-       if (fd >= 0) {
-               char value[4096];
-
-               count = read(fd, value, sizeof(value));
-               close(fd);
-               if (count > 0) {
-                       char *key;
-
-                       value[count] = '\0';
-                       key = value;
-                       while (key[0] != '\0') {
-                               char *next;
-
-                               next = strchr(key, '\n');
-                               if (next == NULL)
-                                       break;
-                               next[0] = '\0';
-                               bufpos += strlcpy(&buf[bufpos], key, sizeof(buf) - bufpos-1);
-                               bufpos++;
-                               key = &next[1];
-                       }
-               }
-       }
-
-       /* add keys from database */
-       list_for_each_entry(name_loop, &udev->env_list, node) {
-               bufpos += strlcpy(&buf[bufpos], name_loop->name, sizeof(buf) - bufpos-1);
-               bufpos++;
-       }
-       if (bufpos > sizeof(buf))
-               bufpos = sizeof(buf);
-
-       count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen);
-       if (count < 0)
-               err = -1;
-
-       return err;
-}
-
-static void exec_list(const char *action, const char *env)
-{
-       struct name_entry *loop_device;
-       struct name_entry *tmp_device;
-
-       list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
-               if (delay_device(loop_device->name))
-                       continue;
-               if (sock >= 0)
-                       pass_to_socket(loop_device->name, action, env);
-               else
-                       trigger_uevent(loop_device->name, action);
-               list_del(&loop_device->node);
-               free(loop_device);
-       }
-
-       /* trigger remaining delayed devices */
-       list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) {
-               if (sock >= 0)
-                       pass_to_socket(loop_device->name, action, env);
-               else
-                       trigger_uevent(loop_device->name, action);
-               list_del(&loop_device->node);
-               free(loop_device);
-       }
-}
-
-static int subsystem_filtered(const char *subsystem)
-{
-       struct name_entry *loop_name;
-
-       /* skip devices matching the listed subsystems */
-       list_for_each_entry(loop_name, &filter_subsystem_nomatch_list, node)
-               if (fnmatch(loop_name->name, subsystem, 0) == 0)
-                       return 1;
-
-       /* skip devices not matching the listed subsystems */
-       if (!list_empty(&filter_subsystem_match_list)) {
-               list_for_each_entry(loop_name, &filter_subsystem_match_list, node)
-                       if (fnmatch(loop_name->name, subsystem, 0) == 0)
-                               return 0;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int attr_match(const char *path, const char *attr_value)
-{
-       char attr[NAME_SIZE];
-       char file[PATH_SIZE];
-       char *match_value;
-
-       strlcpy(attr, attr_value, sizeof(attr));
-
-       /* separate attr and match value */
-       match_value = strchr(attr, '=');
-       if (match_value != NULL) {
-               match_value[0] = '\0';
-               match_value = &match_value[1];
-       }
-
-       strlcpy(file, path, sizeof(file));
-       strlcat(file, "/", sizeof(file));
-       strlcat(file, attr, sizeof(file));
-
-       if (match_value != NULL) {
-               /* match file content */
-               char value[NAME_SIZE];
-               int fd;
-               ssize_t size;
-
-               fd = open(file, O_RDONLY);
-               if (fd < 0)
-                       return 0;
-               size = read(fd, value, sizeof(value));
-               close(fd);
-               if (size < 0)
-                       return 0;
-               value[size] = '\0';
-               remove_trailing_chars(value, '\n');
-
-               /* match if attribute value matches */
-               if (fnmatch(match_value, value, 0) == 0)
-                       return 1;
-       } else {
-               /* match if attribute exists */
-               struct stat statbuf;
-
-               if (stat(file, &statbuf) == 0)
-                       return 1;
-       }
-       return 0;
-}
-
-static int attr_filtered(const char *path)
-{
-       struct name_entry *loop_name;
-
-       /* skip devices matching the listed sysfs attributes */
-       list_for_each_entry(loop_name, &filter_attr_nomatch_list, node)
-               if (attr_match(path, loop_name->name))
-                       return 1;
-
-       /* skip devices not matching the listed sysfs attributes */
-       if (!list_empty(&filter_attr_match_list)) {
-               list_for_each_entry(loop_name, &filter_attr_match_list, node)
-                       if (attr_match(path, loop_name->name))
-                               return 0;
-               return 1;
-       }
-       return 0;
-}
-
-enum scan_type {
-       SCAN_DEVICES,
-       SCAN_SUBSYSTEM,
-};
-
-static void scan_subsystem(const char *subsys, enum scan_type scan)
-{
-       char base[PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-       const char *subdir;
-
-       if (scan == SCAN_DEVICES)
-               subdir = "/devices";
-       else if (scan == SCAN_SUBSYSTEM)
-               subdir = "/drivers";
-       else
-               return;
-
-       strlcpy(base, sysfs_path, sizeof(base));
-       strlcat(base, "/", sizeof(base));
-       strlcat(base, subsys, sizeof(base));
-
-       dir = opendir(base);
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       char dirname[PATH_SIZE];
-                       DIR *dir2;
-                       struct dirent *dent2;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       if (scan == SCAN_DEVICES)
-                               if (subsystem_filtered(dent->d_name))
-                                       continue;
-
-                       strlcpy(dirname, base, sizeof(dirname));
-                       strlcat(dirname, "/", sizeof(dirname));
-                       strlcat(dirname, dent->d_name, sizeof(dirname));
-
-                       if (scan == SCAN_SUBSYSTEM) {
-                               if (attr_filtered(dirname))
-                                       continue;
-                               if (!subsystem_filtered("subsystem"))
-                                       device_list_insert(dirname);
-                               if (subsystem_filtered("drivers"))
-                                       continue;
-                       }
-
-                       strlcat(dirname, subdir, sizeof(dirname));
-
-                       /* look for devices/drivers */
-                       dir2 = opendir(dirname);
-                       if (dir2 != NULL) {
-                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
-                                       char dirname2[PATH_SIZE];
-
-                                       if (dent2->d_name[0] == '.')
-                                               continue;
-
-                                       strlcpy(dirname2, dirname, sizeof(dirname2));
-                                       strlcat(dirname2, "/", sizeof(dirname2));
-                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
-                                       if (attr_filtered(dirname2))
-                                               continue;
-                                       device_list_insert(dirname2);
-                               }
-                               closedir(dir2);
-                       }
-               }
-               closedir(dir);
-       }
-}
-
-static void scan_block(void)
-{
-       char base[PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       if (subsystem_filtered("block"))
-               return;
-
-       strlcpy(base, sysfs_path, sizeof(base));
-       strlcat(base, "/block", sizeof(base));
-
-       dir = opendir(base);
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       char dirname[PATH_SIZE];
-                       DIR *dir2;
-                       struct dirent *dent2;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       strlcpy(dirname, base, sizeof(dirname));
-                       strlcat(dirname, "/", sizeof(dirname));
-                       strlcat(dirname, dent->d_name, sizeof(dirname));
-                       if (attr_filtered(dirname))
-                               continue;
-                       if (device_list_insert(dirname) != 0)
-                               continue;
-
-                       /* look for partitions */
-                       dir2 = opendir(dirname);
-                       if (dir2 != NULL) {
-                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
-                                       char dirname2[PATH_SIZE];
-
-                                       if (dent2->d_name[0] == '.')
-                                               continue;
-
-                                       if (!strcmp(dent2->d_name,"device"))
-                                               continue;
-
-                                       strlcpy(dirname2, dirname, sizeof(dirname2));
-                                       strlcat(dirname2, "/", sizeof(dirname2));
-                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
-                                       if (attr_filtered(dirname2))
-                                               continue;
-                                       device_list_insert(dirname2);
-                               }
-                               closedir(dir2);
-                       }
-               }
-               closedir(dir);
-       }
-}
-
-static void scan_class(void)
-{
-       char base[PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       strlcpy(base, sysfs_path, sizeof(base));
-       strlcat(base, "/class", sizeof(base));
-
-       dir = opendir(base);
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       char dirname[PATH_SIZE];
-                       DIR *dir2;
-                       struct dirent *dent2;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       if (subsystem_filtered(dent->d_name))
-                               continue;
-
-                       strlcpy(dirname, base, sizeof(dirname));
-                       strlcat(dirname, "/", sizeof(dirname));
-                       strlcat(dirname, dent->d_name, sizeof(dirname));
-                       dir2 = opendir(dirname);
-                       if (dir2 != NULL) {
-                               for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) {
-                                       char dirname2[PATH_SIZE];
-
-                                       if (dent2->d_name[0] == '.')
-                                               continue;
-
-                                       if (!strcmp(dent2->d_name, "device"))
-                                               continue;
-
-                                       strlcpy(dirname2, dirname, sizeof(dirname2));
-                                       strlcat(dirname2, "/", sizeof(dirname2));
-                                       strlcat(dirname2, dent2->d_name, sizeof(dirname2));
-                                       if (attr_filtered(dirname2))
-                                               continue;
-                                       device_list_insert(dirname2);
-                               }
-                               closedir(dir2);
-                       }
-               }
-               closedir(dir);
-       }
-}
-
-static void scan_failed(void)
-{
-       char base[PATH_SIZE];
-       DIR *dir;
-       struct dirent *dent;
-
-       strlcpy(base, udev_root, sizeof(base));
-       strlcat(base, "/.udev/failed", sizeof(base));
-
-       dir = opendir(base);
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       char device[PATH_SIZE];
-                       size_t start;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       start = strlcpy(device, sysfs_path, sizeof(device));
-                       if(start >= sizeof(device))
-                               start = sizeof(device) - 1;
-                       strlcat(device, dent->d_name, sizeof(device));
-                       path_decode(&device[start]);
-                       device_list_insert(device);
-               }
-               closedir(dir);
-       }
-}
-
-int udevtrigger(int argc, char *argv[])
-{
-       int failed = 0;
-       const char *sockpath = NULL;
-       int option;
-       const char *action = "add";
-       const char *env = NULL;
-       static const struct option options[] = {
-               { "verbose", 0, NULL, 'v' },
-               { "dry-run", 0, NULL, 'n' },
-               { "retry-failed", 0, NULL, 'F' },
-               { "socket", 1, NULL, 'o' },
-               { "help", 0, NULL, 'h' },
-               { "action", 1, NULL, 'c' },
-               { "subsystem-match", 1, NULL, 's' },
-               { "subsystem-nomatch", 1, NULL, 'S' },
-               { "attr-match", 1, NULL, 'a' },
-               { "attr-nomatch", 1, NULL, 'A' },
-               { "env", 1, NULL, 'e' },
-               {}
-       };
-
-       logging_init("udevtrigger");
-       udev_config_init();
-       dbg("version %s\n", VERSION);
-       sysfs_init();
-
-       while (1) {
-               option = getopt_long(argc, argv, "vnFo:hce::s:S:a:A:", options, NULL);
-               if (option == -1)
-                       break;
-
-               switch (option) {
-               case 'v':
-                       verbose = 1;
-                       break;
-               case 'n':
-                       dry_run = 1;
-                       break;
-               case 'F':
-                       failed = 1;
-                       break;
-               case 'o':
-                       sockpath = optarg;
-                       break;
-               case 'c':
-                       action = optarg;
-                       break;
-               case 'e':
-                       if (strchr(optarg, '=') != NULL)
-                               env = optarg;
-                       break;
-               case 's':
-                       name_list_add(&filter_subsystem_match_list, optarg, 0);
-                       break;
-               case 'S':
-                       name_list_add(&filter_subsystem_nomatch_list, optarg, 0);
-                       break;
-               case 'a':
-                       name_list_add(&filter_attr_match_list, optarg, 0);
-                       break;
-               case 'A':
-                       name_list_add(&filter_attr_nomatch_list, optarg, 0);
-                       break;
-               case 'h':
-                       printf("Usage: udevadm trigger OPTIONS\n"
-                              "  --verbose                       print the list of devices while running\n"
-                              "  --dry-run                       do not actually trigger the events\n"
-                              "  --retry-failed                  trigger only the events which have been\n"
-                              "                                  marked as failed during a previous run\n"
-                              "  --socket=<socket path>          pass events to socket instead of triggering kernel events\n"
-                              "  --env=<KEY>=<value>             pass an additional key (works only with --socket=)\n"
-                              "  --subsystem-match=<subsystem>   trigger devices from a matching subystem\n"
-                              "  --subsystem-nomatch=<subsystem> exclude devices from a matching subystem\n"
-                              "  --attr-match=<file[=<value>]>   trigger devices with a matching sysfs\n"
-                              "                                  attribute\n"
-                              "  --attr-nomatch=<file[=<value>]> exclude devices with a matching sysfs\n"
-                              "                                  attribute\n"
-                              "  --help                          print this text\n"
-                              "\n");
-                       goto exit;
-               default:
-                       goto exit;
-               }
-       }
-
-       if (sockpath != NULL) {
-               struct stat stats;
-
-               sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
-               memset(&saddr, 0x00, sizeof(struct sockaddr_un));
-               saddr.sun_family = AF_LOCAL;
-               if (sockpath[0] == '@') {
-                       /* abstract namespace socket requested */
-                       strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1);
-                       saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
-               } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) {
-                       /* existing socket file */
-                       strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path));
-                       saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
-               } else {
-                       /* no socket file, assume abstract namespace socket */
-                       strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1);
-                       saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
-               }
-       } else if (env != NULL) {
-               fprintf(stderr, "error: --env= only valid with --socket= option\n");
-               goto exit;
-       }
-
-       if (failed) {
-               scan_failed();
-               exec_list(action, env);
-       } else {
-               char base[PATH_SIZE];
-               struct stat statbuf;
-
-               /* if we have /sys/subsystem, forget all the old stuff */
-               strlcpy(base, sysfs_path, sizeof(base));
-               strlcat(base, "/subsystem", sizeof(base));
-               if (stat(base, &statbuf) == 0) {
-                       scan_subsystem("subsystem", SCAN_SUBSYSTEM);
-                       exec_list(action, env);
-                       scan_subsystem("subsystem", SCAN_DEVICES);
-                       exec_list(action, env);
-               } else {
-                       scan_subsystem("bus", SCAN_SUBSYSTEM);
-                       exec_list(action, env);
-                       scan_subsystem("bus", SCAN_DEVICES);
-                       scan_class();
-
-                       /* scan "block" if it isn't a "class" */
-                       strlcpy(base, sysfs_path, sizeof(base));
-                       strlcat(base, "/class/block", sizeof(base));
-                       if (stat(base, &statbuf) != 0)
-                               scan_block();
-                       exec_list(action, env);
-               }
-       }
-
-exit:
-       name_list_cleanup(&filter_subsystem_match_list);
-       name_list_cleanup(&filter_subsystem_nomatch_list);
-       name_list_cleanup(&filter_attr_match_list);
-       name_list_cleanup(&filter_attr_nomatch_list);
-
-       if (sock >= 0)
-               close(sock);
-       sysfs_cleanup();
-       logging_close();
-       return 0;
-}