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