Zero automatic sockaddr
[petitboot] / discover / udev.c
1
2 #define _GNU_SOURCE
3
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11
12 #include <talloc/talloc.h>
13 #include <waiter/waiter.h>
14 #include <log/log.h>
15
16 #include "event.h"
17 #include "udev.h"
18 #include "pb-discover.h"
19 #include "device-handler.h"
20
21 #define PBOOT_DEVICE_SOCKET "/tmp/petitboot.udev"
22
23 #define max(a, b) ((a) > (b) ? (a) : (b))
24
25 struct udev {
26         struct device_handler *handler;
27         int socket;
28 };
29
30 static void udev_print_event(struct event *event)
31 {
32         const char *action, *params[] = {
33                 "DEVNAME",
34                 "DEVPATH",
35                 "ID_TYPE",
36                 "ID_BUS",
37                 "ID_FS_UUID",
38                 "ID_FS_LABEL",
39                 NULL,
40         };
41         int i;
42
43         action = event->action == EVENT_ACTION_ADD ? "add" : "remove";
44
45         pb_log("udev %s event:\n", action);
46         pb_log("\tdevice: %s\n", event->device);
47
48         for (i = 0; params[i]; i++)
49                 pb_log("\t%-12s => %s\n",
50                                 params[i], event_get_param(event, params[i]));
51 }
52
53 static void udev_handle_message(struct udev *udev, char *buf, int len)
54 {
55         int result;
56         struct event *event;
57
58         event = talloc(udev, struct event);
59         event->type = EVENT_TYPE_UDEV;
60
61         pb_log("%s\n", buf);
62
63         result = event_parse_ad_message(event, buf, len);
64
65         if (result)
66                 return;
67
68         udev_print_event(event);
69         device_handler_event(udev->handler, event);
70         talloc_free(event);
71
72         return;
73 }
74
75 static int udev_process(void *arg)
76 {
77         struct udev *udev = arg;
78         char buf[4096];
79         int len;
80
81         len = recvfrom(udev->socket, buf, sizeof(buf), 0, NULL, NULL);
82
83         if (len < 0) {
84                 pb_log("udev socket read failed: %s", strerror(errno));
85                 return -1;
86         }
87
88         if (len == 0)
89                 return 0;
90
91         udev_handle_message(udev, buf, len);
92
93         return 0;
94 }
95
96 static int udev_destructor(void *p)
97 {
98         struct udev *udev = p;
99
100         if (udev->socket >= 0)
101                 close(udev->socket);
102
103         return 0;
104 }
105
106 struct udev *udev_init(struct device_handler *handler)
107 {
108         struct sockaddr_un addr;
109         struct udev *udev;
110
111         unlink(PBOOT_DEVICE_SOCKET);
112
113         udev = talloc(NULL, struct udev);
114
115         udev->handler = handler;
116
117         udev->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
118         if (udev->socket < 0) {
119                 pb_log("Error creating udev socket: %s\n", strerror(errno));
120                 goto out_err;
121         }
122
123         talloc_set_destructor(udev, udev_destructor);
124
125         memset(&addr, 0, sizeof addr);
126         addr.sun_family = AF_UNIX;
127         strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
128
129         if (bind(udev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
130                 pb_log("Error binding udev socket: %s\n", strerror(errno));
131                 goto out_err;
132         }
133
134         waiter_register(udev->socket, WAIT_IN, udev_process, udev);
135
136         pb_log("%s: waiting on %s\n", __func__, PBOOT_DEVICE_SOCKET);
137
138         return udev;
139
140 out_err:
141         talloc_free(udev);
142         return NULL;
143 }
144
145 int udev_trigger(struct udev __attribute__((unused)) *udev)
146 {
147         int rc = system("/sbin/udevadm trigger --subsystem-match=block --action=add");
148
149         if (rc)
150                 pb_log("udev trigger failed: %d (%d)\n", rc, WEXITSTATUS(rc));
151
152         return WEXITSTATUS(rc);
153 }
154
155 void udev_destroy(struct udev *udev)
156 {
157         talloc_free(udev);
158 }