chiark / gitweb /
udevadm: control - use /run/udev/control socket instead of abstract namespace one
[elogind.git] / udev / udev-ctrl.c
1 /*
2  * libudev - interface to udev device information
3  *
4  * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  */
11
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/poll.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22
23 #include "udev.h"
24
25 /* wire protocol magic must match */
26 #define UDEV_CTRL_MAGIC                         0xdead1dea
27
28 enum udev_ctrl_msg_type {
29         UDEV_CTRL_UNKNOWN,
30         UDEV_CTRL_SET_LOG_LEVEL,
31         UDEV_CTRL_STOP_EXEC_QUEUE,
32         UDEV_CTRL_START_EXEC_QUEUE,
33         UDEV_CTRL_RELOAD_RULES,
34         UDEV_CTRL_SET_ENV,
35         UDEV_CTRL_SET_CHILDREN_MAX,
36         UDEV_CTRL_PING,
37         UDEV_CTRL_EXIT,
38 };
39
40 struct udev_ctrl_msg_wire {
41         char version[16];
42         unsigned int magic;
43         enum udev_ctrl_msg_type type;
44         union {
45                 int intval;
46                 char buf[256];
47         };
48 };
49
50 struct udev_ctrl_msg {
51         int refcount;
52         struct udev_ctrl_connection *conn;
53         struct udev_ctrl_msg_wire ctrl_msg_wire;
54 };
55
56 struct udev_ctrl {
57         int refcount;
58         struct udev *udev;
59         int sock;
60         struct sockaddr_un saddr;
61         socklen_t addrlen;
62         bool bound;
63         bool cleanup_socket;
64         bool connected;
65 };
66
67 struct udev_ctrl_connection {
68         int refcount;
69         struct udev_ctrl *uctrl;
70         int sock;
71 };
72
73 struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)
74 {
75         struct udev_ctrl *uctrl;
76
77         uctrl = calloc(1, sizeof(struct udev_ctrl));
78         if (uctrl == NULL)
79                 return NULL;
80         uctrl->refcount = 1;
81         uctrl->udev = udev;
82
83         if (fd < 0) {
84                 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
85                 if (uctrl->sock < 0) {
86                         err(udev, "error getting socket: %m\n");
87                         udev_ctrl_unref(uctrl);
88                         return NULL;
89                 }
90         } else {
91                 uctrl->bound = true;
92                 uctrl->sock = fd;
93         }
94
95         uctrl->saddr.sun_family = AF_LOCAL;
96         util_strscpyl(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path),
97                       udev_get_run_path(udev), "/control", NULL);
98         uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
99         return uctrl;
100 }
101
102 struct udev_ctrl *udev_ctrl_new(struct udev *udev)
103 {
104         return udev_ctrl_new_from_fd(udev, -1);
105 }
106
107 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
108 {
109         int err;
110
111         if (!uctrl->bound) {
112                 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
113                 if (err < 0 && errno == EADDRINUSE) {
114                         unlink(uctrl->saddr.sun_path);
115                         err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
116                 }
117
118                 if (err < 0) {
119                         err = -errno;
120                         err(uctrl->udev, "bind failed: %m\n");
121                         return err;
122                 }
123
124                 err = listen(uctrl->sock, 0);
125                 if (err < 0) {
126                         err = -errno;
127                         err(uctrl->udev, "listen failed: %m\n");
128                         return err;
129                 }
130
131                 uctrl->bound = true;
132                 uctrl->cleanup_socket = true;
133         }
134         return 0;
135 }
136
137 struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
138 {
139         return uctrl->udev;
140 }
141
142 struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
143 {
144         if (uctrl == NULL)
145                 return NULL;
146         uctrl->refcount++;
147         return uctrl;
148 }
149
150 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
151 {
152         if (uctrl == NULL)
153                 return NULL;
154         uctrl->refcount--;
155         if (uctrl->refcount > 0)
156                 return uctrl;
157         if (uctrl->sock >= 0)
158                 close(uctrl->sock);
159         if (uctrl->cleanup_socket)
160                 unlink(uctrl->saddr.sun_path);
161         free(uctrl);
162         return NULL;
163 }
164
165 int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
166 {
167         if (uctrl == NULL)
168                 return -1;
169         return uctrl->sock;
170 }
171
172 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
173 {
174         struct udev_ctrl_connection *conn;
175         struct ucred ucred;
176         socklen_t slen;
177         const int on = 1;
178
179         conn = calloc(1, sizeof(struct udev_ctrl_connection));
180         if (conn == NULL)
181                 return NULL;
182         conn->refcount = 1;
183         conn->uctrl = uctrl;
184
185         conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
186         if (conn->sock < 0) {
187                 if (errno != EINTR)
188                         err(uctrl->udev, "unable to receive ctrl connection: %m\n");
189                 goto err;
190         }
191
192         /* check peer credential of connection */
193         slen = sizeof(ucred);
194         if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
195                 err(uctrl->udev, "unable to receive credentials of ctrl connection: %m\n");
196                 goto err;
197         }
198         if (ucred.uid > 0) {
199                 err(uctrl->udev, "sender uid=%i, message ignored\n", ucred.uid);
200                 goto err;
201         }
202
203         /* enable receiving of the sender credentials in the messages */
204         setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
205         udev_ctrl_ref(uctrl);
206         return conn;
207 err:
208         if (conn->sock >= 0)
209                 close(conn->sock);
210         free(conn);
211         return NULL;
212 }
213
214 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn)
215 {
216         if (conn == NULL)
217                 return NULL;
218         conn->refcount++;
219         return conn;
220 }
221
222 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn)
223 {
224         if (conn == NULL)
225                 return NULL;
226         conn->refcount--;
227         if (conn->refcount > 0)
228                 return conn;
229         if (conn->sock >= 0)
230                 close(conn->sock);
231         udev_ctrl_unref(conn->uctrl);
232         free(conn);
233         return NULL;
234 }
235
236 static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
237 {
238         struct udev_ctrl_msg_wire ctrl_msg_wire;
239         int err = 0;
240
241         memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
242         strcpy(ctrl_msg_wire.version, "udev-" VERSION);
243         ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
244         ctrl_msg_wire.type = type;
245
246         if (buf != NULL)
247                 util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
248         else
249                 ctrl_msg_wire.intval = intval;
250
251         if (!uctrl->connected) {
252                 if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
253                         err = -errno;
254                         goto out;
255                 }
256                 uctrl->connected = true;
257         }
258         if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
259                 err = -errno;
260                 goto out;
261         }
262
263         /* wait for peer message handling or disconnect */
264         for (;;) {
265                 struct pollfd pfd[1];
266                 int r;
267
268                 pfd[0].fd = uctrl->sock;
269                 pfd[0].events = POLLIN;
270                 r = poll(pfd, 1, timeout * 1000);
271                 if (r  < 0) {
272                         if (errno == EINTR)
273                                 continue;
274                         err = -errno;
275                         break;
276                 }
277
278                 if (r > 0 && pfd[0].revents & POLLERR) {
279                         err = -EIO;
280                         break;
281                 }
282
283                 if (r == 0)
284                         err = -ETIMEDOUT;
285                 break;
286         }
287 out:
288         return err;
289 }
290
291 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout)
292 {
293         return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
294 }
295
296 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
297 {
298         return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
299 }
300
301 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
302 {
303         return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
304 }
305
306 int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl, int timeout)
307 {
308         return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL, timeout);
309 }
310
311 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
312 {
313         return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
314 }
315
316 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
317 {
318         return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
319 }
320
321 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
322 {
323         return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
324 }
325
326 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
327 {
328         return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
329 }
330
331 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
332 {
333         struct udev *udev = conn->uctrl->udev;
334         struct udev_ctrl_msg *uctrl_msg;
335         ssize_t size;
336         struct msghdr smsg;
337         struct cmsghdr *cmsg;
338         struct iovec iov;
339         struct ucred *cred;
340         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
341
342         uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
343         if (uctrl_msg == NULL)
344                 return NULL;
345         uctrl_msg->refcount = 1;
346         uctrl_msg->conn = conn;
347         udev_ctrl_connection_ref(conn);
348
349         /* wait for the incoming message */
350         for(;;) {
351                 struct pollfd pfd[1];
352                 int r;
353
354                 pfd[0].fd = conn->sock;
355                 pfd[0].events = POLLIN;
356
357                 r = poll(pfd, 1, 10000);
358                 if (r  < 0) {
359                         if (errno == EINTR)
360                                 continue;
361                         goto err;
362                 } else if (r == 0) {
363                         err(udev, "timeout waiting for ctrl message\n");
364                         goto err;
365                 } else {
366                         if (!(pfd[0].revents & POLLIN)) {
367                                 err(udev, "ctrl connection error: %m\n");
368                                 goto err;
369                         }
370                 }
371
372                 break;
373         }
374
375         iov.iov_base = &uctrl_msg->ctrl_msg_wire;
376         iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
377         memset(&smsg, 0x00, sizeof(struct msghdr));
378         smsg.msg_iov = &iov;
379         smsg.msg_iovlen = 1;
380         smsg.msg_control = cred_msg;
381         smsg.msg_controllen = sizeof(cred_msg);
382         size = recvmsg(conn->sock, &smsg, 0);
383         if (size <  0) {
384                 err(udev, "unable to receive ctrl message: %m\n");
385                 goto err;
386         }
387         cmsg = CMSG_FIRSTHDR(&smsg);
388         cred = (struct ucred *) CMSG_DATA(cmsg);
389
390         if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
391                 err(udev, "no sender credentials received, message ignored\n");
392                 goto err;
393         }
394
395         if (cred->uid != 0) {
396                 err(udev, "sender uid=%i, message ignored\n", cred->uid);
397                 goto err;
398         }
399
400         if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
401                 err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
402                 goto err;
403         }
404
405         dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
406         return uctrl_msg;
407 err:
408         udev_ctrl_msg_unref(uctrl_msg);
409         return NULL;
410 }
411
412 struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
413 {
414         if (ctrl_msg == NULL)
415                 return NULL;
416         ctrl_msg->refcount++;
417         return ctrl_msg;
418 }
419
420 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
421 {
422         if (ctrl_msg == NULL)
423                 return NULL;
424         ctrl_msg->refcount--;
425         if (ctrl_msg->refcount > 0)
426                 return ctrl_msg;
427         dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
428         udev_ctrl_connection_unref(ctrl_msg->conn);
429         free(ctrl_msg);
430         return NULL;
431 }
432
433 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
434 {
435         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
436                 return ctrl_msg->ctrl_msg_wire.intval;
437         return -1;
438 }
439
440 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
441 {
442         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
443                 return 1;
444         return -1;
445 }
446
447 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
448 {
449         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
450                 return 1;
451         return -1;
452 }
453
454 int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg)
455 {
456         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD_RULES)
457                 return 1;
458         return -1;
459 }
460
461 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
462 {
463         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
464                 return ctrl_msg->ctrl_msg_wire.buf;
465         return NULL;
466 }
467
468 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
469 {
470         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
471                 return ctrl_msg->ctrl_msg_wire.intval;
472         return -1;
473 }
474
475 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
476 {
477         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
478                 return 1;
479         return -1;
480 }
481
482 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
483 {
484         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
485                 return 1;
486         return -1;
487 }