123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- #include "json.h"
- #include <libudev.h>
- #include <stdio.h>
- #include <sys/select.h>
- #include <unistd.h>
- #include <errno.h>
- #include <string.h>
- #include <fcntl.h>
- #include <stdlib.h>
-
- struct udev *udev;
-
- FILE *out;
-
- struct listener
- {
- struct udev_monitor *mon;
- int fd;
- };
-
- struct listener listeners[32];
- int listenerc = 0;
-
- struct udev_monitor *mons[32];
-
- static void devinfo_print_json(
- FILE *f,
- struct udev *udev,
- struct udev_device *dev)
- {
- struct udev_list_entry *entry, *sysattrs;
- int first;
- const char *key, *val;
-
- json_obj_start(f);
-
- sysattrs = udev_device_get_properties_list_entry(dev);
- first = 1;
- udev_list_entry_foreach(entry, sysattrs)
- {
- key = udev_list_entry_get_name(entry);
- val = udev_list_entry_get_value(entry);
-
- if (!first)
- json_sep(f);
- json_obj_key(f, key);
- json_str(f, val);
-
- first = 0;
- }
-
- json_obj_end(f);
-
- udev_device_unref(dev);
- }
-
- static void enumerate(FILE *f, const char *subsystem)
- {
- struct udev_enumerate *en;
- struct udev_list_entry *device, *devices;
- struct udev_device *dev;
- int first;
- const char *name;
-
- // Create enumerator
- en = udev_enumerate_new(udev);
- if (subsystem != NULL)
- udev_enumerate_add_match_subsystem(en, subsystem);
-
- json_arr_start(f);
-
- // Enumerate
- udev_enumerate_scan_devices(en);
- devices = udev_enumerate_get_list_entry(en);
- first = 1;
- udev_list_entry_foreach(device, devices)
- {
- if (!first)
- json_sep(f);
-
- name = udev_list_entry_get_name(device);
- dev = udev_device_new_from_syspath(udev, name);
- devinfo_print_json(f, udev, dev);
-
- first = 0;
- }
-
- json_arr_end(f);
-
- printf("\n");
- fflush(f);
-
- udev_enumerate_unref(en);
- }
-
- int monitor(const char *subsystem)
- {
- struct udev_monitor *mon;
- struct listener *l;
-
- mon = udev_monitor_new_from_netlink(udev, "udev");
- if (!mon)
- return -1;
-
- if (subsystem != NULL)
- {
- udev_monitor_filter_add_match_subsystem_devtype(
- mon, subsystem, NULL);
- }
- udev_monitor_enable_receiving(mon);
-
- l = &listeners[listenerc++];
- l->mon = mon;
- l->fd = udev_monitor_get_fd(mon);
-
- return 0;
- }
-
- void oncommand(struct listener *l)
- {
- char buf[1024];
- char *cmd, *arg;
- int cnt, i;
- char c;
-
- memset(buf, 0, sizeof(buf));
-
- cnt = read(l->fd, buf, sizeof(buf));
- if (cnt == -1)
- {
- perror("stdin");
- return;
- }
- else if (cnt == 0)
- {
- // don't try to read from stdin anymore if it's closed
- l->fd = -1;
- return;
- }
- else if (cnt == sizeof(buf))
- {
- fprintf(stderr, "input buffer too big\n");
-
- // drain, so we don't end up reading stale data next time
- do {
- cnt = read(l->fd, buf, sizeof(buf));
- if (cnt == -1)
- {
- perror("stdin");
- return;
- }
- } while (cnt == sizeof(buf));
- return;
- }
-
- // parse input into command and argument
- cmd = buf;
- arg = NULL;
- i = 0;
- while (1)
- {
- c = buf[i];
-
- // colon: replace with \0 to terminate cmd,
- // update arg to point to the charcater after :
- if (c == ':')
- {
- buf[i] = '\0';
- arg = buf + i + 1;
- }
-
- // newline: replace with \0 to terminate arg,
- // respond to request, then update cmd and
- // continue reading the buffer until we reach a \0
- else if (c == '\n' || c == '\0')
- {
- buf[i] = '\0';
-
- if (*cmd == '\0')
- break;
-
- // respond to request
- if (strcmp(cmd, "list") == 0)
- {
- if (strcmp(arg, "*") == 0)
- enumerate(out, NULL);
- else
- enumerate(out, arg);
- }
- else if (strcmp(cmd, "monitor") == 0)
- {
- if (strcmp(arg, "*") == 0)
- monitor(NULL);
- else
- monitor(arg);
- }
- else
- {
- fprintf(stderr, "Unknown command: %s\n", cmd);
- }
-
- if (c == '\0')
- break;
-
- cmd = buf + i + 1;
- }
-
- i += 1;
- }
- }
-
- void onevent(struct listener *l)
- {
- struct udev_device *dev = udev_monitor_receive_device(l->mon);
- if (!dev)
- {
- fprintf(stderr, "No device even though an event occurred.\n");
- return;
- }
-
- devinfo_print_json(out, udev, dev);
- printf("\n");
- fflush(out);
- }
-
- void readinput()
- {
- fd_set set;
- FD_ZERO(&set);
- int max = -1;
- for (int i = 0; i < listenerc; ++i)
- {
- int fd = listeners[i].fd;
- if (fd == -1)
- continue;
- FD_SET(fd, &set);
- if (fd > max)
- max = fd;
- }
-
- int activity;
-
- activity = select(max + 1, &set, NULL, NULL, NULL);
- if (activity < 0)
- {
- if (errno != EINTR)
- perror("select");
- return;
- }
-
- for (int i = 0; i < listenerc; ++i)
- {
- struct listener *l = &listeners[i];
- int fd = l->fd;
- if (!FD_ISSET(fd, &set))
- continue;
-
- if (fd == STDIN_FILENO)
- oncommand(l);
- else
- onevent(l);
- }
- }
-
- int main()
- {
- out = stdout;
- memset(listeners, 0, sizeof(listeners));
-
- // read stdin
- listeners[listenerc++].fd = STDIN_FILENO;
-
- // create udev
- udev = udev_new();
- if (!udev)
- {
- fprintf(stderr, "Failed to craete udev\n");
- return 1;
- }
-
- // main loop
- while (1) {
- readinput();
- }
-
- udev_unref(udev);
- }
|