9 #include <sys/socket.h>
12 #include <talloc/talloc.h>
17 #include "pb-discover.h"
19 #define PBOOT_DEVICE_SOCKET "/tmp/petitboot.udev"
21 #define max(a, b) ((a) > (b) ? (a) : (b))
27 static void parse_event_params(struct udev_event *event, char *buf, int len)
29 int param_len, name_len, value_len;
33 for (; len > 0; len -= param_len + 1, buf += param_len + 1) {
35 /* find the length of the whole parameter */
36 param_len = strnlen(buf, len);
38 /* multiple NULs? skip over */
43 /* find the separator */
44 sep = memchr(buf, '=', param_len);
49 value_len = param_len - name_len - 1;
51 /* update the params array */
52 event->params = talloc_realloc(event, event->params,
53 struct param, ++event->n_params);
54 param = &event->params[event->n_params - 1];
56 param->name = talloc_strndup(event, buf, name_len);
57 param->value = talloc_strndup(event, sep + 1, value_len);
61 static const char *event_param(struct udev_event *event, const char *name)
65 for (i = 0; i < event->n_params; i++)
66 if (!strcasecmp(event->params[i].name, name))
67 return event->params[i].value;
72 static void print_event(struct udev_event *event)
74 const char *action, *params[] = {
75 "DEVNAME", "ID_TYPE", "ID_BUS", "ID_FS_UUID", "ID_FS_LABEL",
80 action = event->action == UDEV_ACTION_ADD ? "add" : "remove";
82 pb_log("udev %s event:\n", action);
83 printf("\tdevice: %s\n", event->device);
85 for (i = 0; params[i]; i++)
86 printf("\t%-12s => %s\n",
87 params[i], event_param(event, params[i]));
91 static void handle_udev_message(struct udev *udev, char *buf, int len)
94 enum udev_action action;
95 struct udev_event *event;
98 /* we should see an <action>@<device>\0 at the head of the buffer */
99 sep = strchr(buf, '@');
103 /* terminate the action string */
105 len -= sep - buf + 1;
107 if (!strcmp(buf, "add")) {
108 action = UDEV_ACTION_ADD;
110 } else if (!strcmp(buf, "remove")) {
111 action = UDEV_ACTION_REMOVE;
117 /* initialise the device string */
119 device_len = strnlen(device, len);
123 /* now we have an action and a device, we can construct an event */
124 event = talloc(udev, struct udev_event);
125 event->action = action;
126 event->device = talloc_strndup(event, device, device_len);
128 event->params = NULL;
130 len -= device_len + 1;
131 parse_event_params(event, device + device_len + 1, len);
140 static int udev_process(void *arg)
142 struct udev *udev = arg;
146 len = recvfrom(udev->socket, buf, sizeof(buf), 0, NULL, NULL);
149 pb_log("udev socket read failed: %s", strerror(errno));
156 handle_udev_message(udev, buf, len);
161 static int udev_destructor(void *p)
163 struct udev *udev = p;
165 if (udev->socket >= 0)
171 struct udev *udev_init(void)
173 struct sockaddr_un addr;
176 unlink(PBOOT_DEVICE_SOCKET);
178 udev = talloc(NULL, struct udev);
180 udev->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
181 if (udev->socket < 0) {
182 pb_log("Error creating udev socket: %s\n", strerror(errno));
186 talloc_set_destructor(udev, udev_destructor);
188 addr.sun_family = AF_UNIX;
189 strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
191 if (bind(udev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
192 pb_log("Error binding udev socket: %s\n", strerror(errno));
196 waiter_register(udev->socket, WAIT_IN, udev_process, udev);
205 void udev_destroy(struct udev *udev)