bc0282749fe282521c15017dbff539a69527866c
[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", "ID_TYPE", "ID_BUS", "ID_FS_UUID", "ID_FS_LABEL",
34                 NULL,
35         };
36         int i;
37
38         action = event->action == EVENT_ACTION_ADD ? "add" : "remove";
39
40         pb_log("udev %s event:\n", action);
41         pb_log("\tdevice: %s\n", event->device);
42
43         for (i = 0; params[i]; i++)
44                 pb_log("\t%-12s => %s\n",
45                                 params[i], event_get_param(event, params[i]));
46
47 }
48
49 static void udev_handle_message(struct udev *udev, char *buf, int len)
50 {
51         int result;
52         struct event *event;
53
54         event = talloc(udev, struct event);
55         event->type = EVENT_TYPE_UDEV;
56
57         pb_log("%s\n", buf);
58
59         result = event_parse_ad_message(event, buf, len);
60
61         if (result)
62                 return;
63
64         udev_print_event(event);
65         device_handler_event(udev->handler, event);
66         talloc_free(event);
67
68         return;
69 }
70
71 static int udev_process(void *arg)
72 {
73         struct udev *udev = arg;
74         char buf[4096];
75         int len;
76
77         len = recvfrom(udev->socket, buf, sizeof(buf), 0, NULL, NULL);
78
79         if (len < 0) {
80                 pb_log("udev socket read failed: %s", strerror(errno));
81                 return -1;
82         }
83
84         if (len == 0)
85                 return 0;
86
87         udev_handle_message(udev, buf, len);
88
89         return 0;
90 }
91
92 static int udev_destructor(void *p)
93 {
94         struct udev *udev = p;
95
96         if (udev->socket >= 0)
97                 close(udev->socket);
98
99         return 0;
100 }
101
102 struct udev *udev_init(struct device_handler *handler)
103 {
104         struct sockaddr_un addr;
105         struct udev *udev;
106
107         unlink(PBOOT_DEVICE_SOCKET);
108
109         udev = talloc(NULL, struct udev);
110
111         udev->handler = handler;
112
113         udev->socket = socket(PF_UNIX, SOCK_DGRAM, 0);
114         if (udev->socket < 0) {
115                 pb_log("Error creating udev socket: %s\n", strerror(errno));
116                 goto out_err;
117         }
118
119         talloc_set_destructor(udev, udev_destructor);
120
121         addr.sun_family = AF_UNIX;
122         strcpy(addr.sun_path, PBOOT_DEVICE_SOCKET);
123
124         if (bind(udev->socket, (struct sockaddr *)&addr, sizeof(addr))) {
125                 pb_log("Error binding udev socket: %s\n", strerror(errno));
126                 goto out_err;
127         }
128
129         waiter_register(udev->socket, WAIT_IN, udev_process, udev);
130
131         pb_log("%s: waiting on %s\n", __func__, PBOOT_DEVICE_SOCKET);
132
133         return udev;
134
135 out_err:
136         talloc_free(udev);
137         return NULL;
138 }
139
140 int udev_trigger(struct udev __attribute__((unused)) *udev)
141 {
142         int rc = system("/sbin/udevadm trigger --subsystem-match=block --action=add");
143
144         if (rc)
145                 pb_log("udev trigger failed: %d (%d)\n", rc, WEXITSTATUS(rc));
146
147         return WEXITSTATUS(rc);
148 }
149
150 void udev_destroy(struct udev *udev)
151 {
152         talloc_free(udev);
153 }