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