X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udevtrigger.c;h=d4b10d06ab461516ae62e7ae8566144bf1209b03;hp=cf8f209b1c105155727fe9f186218dd19832f6de;hb=0654a21c78caf312fa612059725d1b47c78e7802;hpb=584fbf1ba459b4425c6757ca08918d760def62ef diff --git a/udevtrigger.c b/udevtrigger.c index cf8f209b1..d4b10d06a 100644 --- a/udevtrigger.c +++ b/udevtrigger.c @@ -30,9 +30,12 @@ #include #include #include +#include +#include #include "udev.h" #include "udevd.h" +#include "udev_rules.h" static int verbose; static int dry_run; @@ -41,20 +44,9 @@ LIST_HEAD(filter_subsystem_match_list); LIST_HEAD(filter_subsystem_nomatch_list); LIST_HEAD(filter_attr_match_list); LIST_HEAD(filter_attr_nomatch_list); - -#ifdef USE_LOG -void log_message(int priority, const char *format, ...) -{ - va_list args; - - if (priority > udev_log_priority) - return; - - va_start(args, format); - vsyslog(priority, format, args); - va_end(args); -} -#endif +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) @@ -78,7 +70,7 @@ static int device_list_insert(const char *path) char devpath[PATH_SIZE]; struct stat statbuf; - dbg("add '%s'" , path); + dbg("add '%s'\n" , path); /* we only have a device, if we have an uevent file */ strlcpy(filename, path, sizeof(filename)); @@ -118,17 +110,133 @@ static void trigger_uevent(const char *devpath, const char *action) fd = open(filename, O_WRONLY); if (fd < 0) { - dbg("error on opening %s: %s", filename, strerror(errno)); + 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", action, filename, strerror(errno)); + info("error writing '%s' to '%s': %s\n", action, filename, strerror(errno)); close(fd); } -static void exec_list(const char *action) +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_device_init(&udev); + 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; @@ -136,15 +244,20 @@ static void exec_list(const char *action) list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) { if (delay_device(loop_device->name)) continue; - - trigger_uevent(loop_device->name, action); + 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) { - trigger_uevent(loop_device->name, action); + 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); } @@ -435,6 +548,8 @@ static void scan_failed(void) 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); @@ -443,31 +558,35 @@ static void scan_failed(void) } } -int main(int argc, char *argv[], char *envp[]) +int udevtrigger(int argc, char *argv[], char *envp[]) { 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", UDEV_VERSION); + dbg("version %s\n", UDEV_VERSION); sysfs_init(); while (1) { - option = getopt_long(argc, argv, "vnFhc:s:S:a:A:", options, NULL); + option = getopt_long(argc, argv, "vnFo:hce::s:S:a:A:", options, NULL); if (option == -1) break; @@ -481,9 +600,16 @@ int main(int argc, char *argv[], char *envp[]) 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; @@ -497,11 +623,13 @@ int main(int argc, char *argv[], char *envp[]) name_list_add(&filter_attr_nomatch_list, optarg, 0); break; case 'h': - printf("Usage: udevtrigger OPTIONS\n" + 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= pass events to socket instead of triggering kernel events\n" + " --env== pass an additional key (works only with --socket=)\n" " --subsystem-match= trigger devices from a matching subystem\n" " --subsystem-nomatch= exclude devices from a matching subystem\n" " --attr-match=]> trigger devices with a matching sysfs\n" @@ -516,9 +644,33 @@ int main(int argc, char *argv[], char *envp[]) } } + 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); + exec_list(action, env); } else { char base[PATH_SIZE]; struct stat statbuf; @@ -528,12 +680,12 @@ int main(int argc, char *argv[], char *envp[]) strlcat(base, "/subsystem", sizeof(base)); if (stat(base, &statbuf) == 0) { scan_subsystem("subsystem", SCAN_SUBSYSTEM); - exec_list(action); + exec_list(action, env); scan_subsystem("subsystem", SCAN_DEVICES); - exec_list(action); + exec_list(action, env); } else { scan_subsystem("bus", SCAN_SUBSYSTEM); - exec_list(action); + exec_list(action, env); scan_subsystem("bus", SCAN_DEVICES); scan_class(); @@ -542,7 +694,7 @@ int main(int argc, char *argv[], char *envp[]) strlcat(base, "/class/block", sizeof(base)); if (stat(base, &statbuf) != 0) scan_block(); - exec_list(action); + exec_list(action, env); } } @@ -552,6 +704,8 @@ exit: 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;