9 #include <sys/socket.h>
12 #include <talloc/talloc.h>
13 #include <waiter/waiter.h>
17 #include "pb-discover.h"
18 #include "device-handler.h"
20 #define PBOOT_DEVICE_SOCKET "/tmp/petitboot.udev"
22 #define max(a, b) ((a) > (b) ? (a) : (b))
25 struct device_handler *handler;
29 static void parse_event_params(struct udev_event *event, char *buf, int len)
31 int param_len, name_len, value_len;
35 for (; len > 0; len -= param_len + 1, buf += param_len + 1) {
37 /* find the length of the whole parameter */
38 param_len = strnlen(buf, len);
40 /* multiple NULs? skip over */
45 /* find the separator */
46 sep = memchr(buf, '=', param_len);
51 value_len = param_len - name_len - 1;
53 /* update the params array */
54 event->params = talloc_realloc(event, event->params,
55 struct param, ++event->n_params);
56 param = &event->params[event->n_params - 1];
58 param->name = talloc_strndup(event, buf, name_len);
59 param->value = talloc_strndup(event, sep + 1, value_len);
63 const char *udev_event_param(struct udev_event *event, const char *name)
67 for (i = 0; i < event->n_params; i++)
68 if (!strcasecmp(event->params[i].name, name))
69 return event->params[i].value;
74 static void print_event(struct udev_event *event)
76 const char *action, *params[] = {
77 "DEVNAME", "ID_TYPE", "ID_BUS", "ID_FS_UUID", "ID_FS_LABEL",
82 action = event->action == UDEV_ACTION_ADD ? "add" : "remove";
84 pb_log("udev %s event:\n", action);
85 printf("\tdevice: %s\n", event->device);
87 for (i = 0; params[i]; i++)
88 printf("\t%-12s => %s\n",
89 params[i], udev_event_param(event, params[i]));
93 static void handle_udev_message(struct udev *udev, char *buf, int len)
96 enum udev_action action;
97 struct udev_event *event;
100 /* we should see an <action>@<device>\0 at the head of the buffer */
101 sep = strchr(buf, '@');
105 /* terminate the action string */
107 len -= sep - buf + 1;
109 if (!strcmp(buf, "add")) {
110 action = UDEV_ACTION_ADD;
112 } else if (!strcmp(buf, "remove")) {
113 action = UDEV_ACTION_REMOVE;
119 /* initialise the device string */
121 device_len = strnlen(device, len);
125 /* now we have an action and a device, we can construct an event */
126 event = talloc(udev, struct udev_event);
127 event->action = action;
128 event->device = talloc_strndup(event, device, device_len);
130 event->params = NULL;
132 len -= device_len + 1;
133 parse_event_params(event, device + device_len + 1, len);
137 device_handler_event(udev->handler, event);
144 static int udev_process(void *arg)
146 struct udev *udev = arg;
150 len = recvfrom(udev->socket, buf, sizeof(buf), 0, NULL, NULL);
153 pb_log("udev socket read failed: %s", strerror(errno));
160 handle_udev_message(udev, buf, len);
165 static int udev_destructor(void *p)
167 struct udev *udev = p;
169 if (udev->socket >= 0)
175 struct udev *udev_init(struct device_handler *handler)
177 struct sockaddr_un addr;
180 unlink(PBOOT_DEVICE_SOCKET);
182 udev = talloc(NULL, struct udev);
184 udev->handler = handler;
186 udev->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
187 if (udev->socket < 0) {
188 pb_log("Error creating udev socket: %s\n", strerror(errno));
192 talloc_set_destructor(udev, udev_destructor);
194 addr.sun_family = AF_UNIX;
195 strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
197 if (bind(udev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
198 pb_log("Error binding udev socket: %s\n", strerror(errno));
202 waiter_register(udev->socket, WAIT_IN, udev_process, udev);
211 void udev_destroy(struct udev *udev)