chiark / gitweb /
5556f1a77cff818cc24796a283d123d2f5ccd24e
[elogind.git] / src / 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,
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         free(uctrl);
160         return NULL;
161 }
162
163 int udev_ctrl_cleanup(struct udev_ctrl *uctrl)
164 {
165         if (uctrl == NULL)
166                 return 0;
167         if (uctrl->cleanup_socket)
168                 unlink(uctrl->saddr.sun_path);
169         return 0;
170 }
171
172 int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
173 {
174         if (uctrl == NULL)
175                 return -EINVAL;
176         return uctrl->sock;
177 }
178
179 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
180 {
181         struct udev_ctrl_connection *conn;
182         struct ucred ucred;
183         socklen_t slen;
184         const int on = 1;
185
186         conn = calloc(1, sizeof(struct udev_ctrl_connection));
187         if (conn == NULL)
188                 return NULL;
189         conn->refcount = 1;
190         conn->uctrl = uctrl;
191
192         conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
193         if (conn->sock < 0) {
194                 if (errno != EINTR)
195                         err(uctrl->udev, "unable to receive ctrl connection: %m\n");
196                 goto err;
197         }
198
199         /* check peer credential of connection */
200         slen = sizeof(ucred);
201         if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
202                 err(uctrl->udev, "unable to receive credentials of ctrl connection: %m\n");
203                 goto err;
204         }
205         if (ucred.uid > 0) {
206                 err(uctrl->udev, "sender uid=%i, message ignored\n", ucred.uid);
207                 goto err;
208         }
209
210         /* enable receiving of the sender credentials in the messages */
211         setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
212         udev_ctrl_ref(uctrl);
213         return conn;
214 err:
215         if (conn->sock >= 0)
216                 close(conn->sock);
217         free(conn);
218         return NULL;
219 }
220
221 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn)
222 {
223         if (conn == NULL)
224                 return NULL;
225         conn->refcount++;
226         return conn;
227 }
228
229 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn)
230 {
231         if (conn == NULL)
232                 return NULL;
233         conn->refcount--;
234         if (conn->refcount > 0)
235                 return conn;
236         if (conn->sock >= 0)
237                 close(conn->sock);
238         udev_ctrl_unref(conn->uctrl);
239         free(conn);
240         return NULL;
241 }
242
243 static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
244 {
245         struct udev_ctrl_msg_wire ctrl_msg_wire;
246         int err = 0;
247
248         memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
249         strcpy(ctrl_msg_wire.version, "udev-" VERSION);
250         ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
251         ctrl_msg_wire.type = type;
252
253         if (buf != NULL)
254                 util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
255         else
256                 ctrl_msg_wire.intval = intval;
257
258         if (!uctrl->connected) {
259                 if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
260                         err = -errno;
261                         goto out;
262                 }
263                 uctrl->connected = true;
264         }
265         if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
266                 err = -errno;
267                 goto out;
268         }
269
270         /* wait for peer message handling or disconnect */
271         for (;;) {
272                 struct pollfd pfd[1];
273                 int r;
274
275                 pfd[0].fd = uctrl->sock;
276                 pfd[0].events = POLLIN;
277                 r = poll(pfd, 1, timeout * 1000);
278                 if (r  < 0) {
279                         if (errno == EINTR)
280                                 continue;
281                         err = -errno;
282                         break;
283                 }
284
285                 if (r > 0 && pfd[0].revents & POLLERR) {
286                         err = -EIO;
287                         break;
288                 }
289
290                 if (r == 0)
291                         err = -ETIMEDOUT;
292                 break;
293         }
294 out:
295         return err;
296 }
297
298 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout)
299 {
300         return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
301 }
302
303 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
304 {
305         return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
306 }
307
308 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
309 {
310         return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
311 }
312
313 int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout)
314 {
315         return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
316 }
317
318 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
319 {
320         return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
321 }
322
323 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
324 {
325         return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
326 }
327
328 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
329 {
330         return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
331 }
332
333 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
334 {
335         return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
336 }
337
338 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
339 {
340         struct udev *udev = conn->uctrl->udev;
341         struct udev_ctrl_msg *uctrl_msg;
342         ssize_t size;
343         struct msghdr smsg;
344         struct cmsghdr *cmsg;
345         struct iovec iov;
346         struct ucred *cred;
347         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
348
349         uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
350         if (uctrl_msg == NULL)
351                 return NULL;
352         uctrl_msg->refcount = 1;
353         uctrl_msg->conn = conn;
354         udev_ctrl_connection_ref(conn);
355
356         /* wait for the incoming message */
357         for(;;) {
358                 struct pollfd pfd[1];
359                 int r;
360
361                 pfd[0].fd = conn->sock;
362                 pfd[0].events = POLLIN;
363
364                 r = poll(pfd, 1, 10000);
365                 if (r  < 0) {
366                         if (errno == EINTR)
367                                 continue;
368                         goto err;
369                 } else if (r == 0) {
370                         err(udev, "timeout waiting for ctrl message\n");
371                         goto err;
372                 } else {
373                         if (!(pfd[0].revents & POLLIN)) {
374                                 err(udev, "ctrl connection error: %m\n");
375                                 goto err;
376                         }
377                 }
378
379                 break;
380         }
381
382         iov.iov_base = &uctrl_msg->ctrl_msg_wire;
383         iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
384         memset(&smsg, 0x00, sizeof(struct msghdr));
385         smsg.msg_iov = &iov;
386         smsg.msg_iovlen = 1;
387         smsg.msg_control = cred_msg;
388         smsg.msg_controllen = sizeof(cred_msg);
389         size = recvmsg(conn->sock, &smsg, 0);
390         if (size <  0) {
391                 err(udev, "unable to receive ctrl message: %m\n");
392                 goto err;
393         }
394         cmsg = CMSG_FIRSTHDR(&smsg);
395         cred = (struct ucred *) CMSG_DATA(cmsg);
396
397         if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
398                 err(udev, "no sender credentials received, message ignored\n");
399                 goto err;
400         }
401
402         if (cred->uid != 0) {
403                 err(udev, "sender uid=%i, message ignored\n", cred->uid);
404                 goto err;
405         }
406
407         if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
408                 err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
409                 goto err;
410         }
411
412         dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
413         return uctrl_msg;
414 err:
415         udev_ctrl_msg_unref(uctrl_msg);
416         return NULL;
417 }
418
419 struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
420 {
421         if (ctrl_msg == NULL)
422                 return NULL;
423         ctrl_msg->refcount++;
424         return ctrl_msg;
425 }
426
427 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
428 {
429         if (ctrl_msg == NULL)
430                 return NULL;
431         ctrl_msg->refcount--;
432         if (ctrl_msg->refcount > 0)
433                 return ctrl_msg;
434         dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
435         udev_ctrl_connection_unref(ctrl_msg->conn);
436         free(ctrl_msg);
437         return NULL;
438 }
439
440 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
441 {
442         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
443                 return ctrl_msg->ctrl_msg_wire.intval;
444         return -1;
445 }
446
447 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
448 {
449         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
450                 return 1;
451         return -1;
452 }
453
454 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
455 {
456         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
457                 return 1;
458         return -1;
459 }
460
461 int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg)
462 {
463         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
464                 return 1;
465         return -1;
466 }
467
468 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
469 {
470         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
471                 return ctrl_msg->ctrl_msg_wire.buf;
472         return NULL;
473 }
474
475 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
476 {
477         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
478                 return ctrl_msg->ctrl_msg_wire.intval;
479         return -1;
480 }
481
482 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
483 {
484         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
485                 return 1;
486         return -1;
487 }
488
489 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
490 {
491         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
492                 return 1;
493         return -1;
494 }