chiark / gitweb /
readahead-analyze: avoid division-by-0
[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         const int on = 1;
77
78         uctrl = calloc(1, sizeof(struct udev_ctrl));
79         if (uctrl == NULL)
80                 return NULL;
81         uctrl->refcount = 1;
82         uctrl->udev = udev;
83
84         if (fd < 0) {
85                 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
86                 if (uctrl->sock < 0) {
87                         log_error("error getting socket: %m\n");
88                         udev_ctrl_unref(uctrl);
89                         return NULL;
90                 }
91         } else {
92                 uctrl->bound = true;
93                 uctrl->sock = fd;
94         }
95         setsockopt(uctrl->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
96
97         uctrl->saddr.sun_family = AF_LOCAL;
98         strscpy(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path), "/run/udev/control");
99         uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
100         return uctrl;
101 }
102
103 struct udev_ctrl *udev_ctrl_new(struct udev *udev)
104 {
105         return udev_ctrl_new_from_fd(udev, -1);
106 }
107
108 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
109 {
110         int err;
111
112         if (!uctrl->bound) {
113                 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
114                 if (err < 0 && errno == EADDRINUSE) {
115                         unlink(uctrl->saddr.sun_path);
116                         err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
117                 }
118
119                 if (err < 0) {
120                         err = -errno;
121                         log_error("bind failed: %m\n");
122                         return err;
123                 }
124
125                 err = listen(uctrl->sock, 0);
126                 if (err < 0) {
127                         err = -errno;
128                         log_error("listen failed: %m\n");
129                         return err;
130                 }
131
132                 uctrl->bound = true;
133                 uctrl->cleanup_socket = true;
134         }
135         return 0;
136 }
137
138 struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
139 {
140         return uctrl->udev;
141 }
142
143 struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
144 {
145         if (uctrl == NULL)
146                 return NULL;
147         uctrl->refcount++;
148         return uctrl;
149 }
150
151 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
152 {
153         if (uctrl == NULL)
154                 return NULL;
155         uctrl->refcount--;
156         if (uctrl->refcount > 0)
157                 return uctrl;
158         if (uctrl->sock >= 0)
159                 close(uctrl->sock);
160         free(uctrl);
161         return NULL;
162 }
163
164 int udev_ctrl_cleanup(struct udev_ctrl *uctrl)
165 {
166         if (uctrl == NULL)
167                 return 0;
168         if (uctrl->cleanup_socket)
169                 unlink(uctrl->saddr.sun_path);
170         return 0;
171 }
172
173 int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
174 {
175         if (uctrl == NULL)
176                 return -EINVAL;
177         return uctrl->sock;
178 }
179
180 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
181 {
182         struct udev_ctrl_connection *conn;
183         struct ucred ucred;
184         socklen_t slen;
185         const int on = 1;
186
187         conn = calloc(1, sizeof(struct udev_ctrl_connection));
188         if (conn == NULL)
189                 return NULL;
190         conn->refcount = 1;
191         conn->uctrl = uctrl;
192
193         conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
194         if (conn->sock < 0) {
195                 if (errno != EINTR)
196                         log_error("unable to receive ctrl connection: %m\n");
197                 goto err;
198         }
199
200         /* check peer credential of connection */
201         slen = sizeof(ucred);
202         if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
203                 log_error("unable to receive credentials of ctrl connection: %m\n");
204                 goto err;
205         }
206         if (ucred.uid > 0) {
207                 log_error("sender uid=%i, message ignored\n", ucred.uid);
208                 goto err;
209         }
210
211         /* enable receiving of the sender credentials in the messages */
212         setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
213         udev_ctrl_ref(uctrl);
214         return conn;
215 err:
216         if (conn->sock >= 0)
217                 close(conn->sock);
218         free(conn);
219         return NULL;
220 }
221
222 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn)
223 {
224         if (conn == NULL)
225                 return NULL;
226         conn->refcount++;
227         return conn;
228 }
229
230 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn)
231 {
232         if (conn == NULL)
233                 return NULL;
234         conn->refcount--;
235         if (conn->refcount > 0)
236                 return conn;
237         if (conn->sock >= 0)
238                 close(conn->sock);
239         udev_ctrl_unref(conn->uctrl);
240         free(conn);
241         return NULL;
242 }
243
244 static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
245 {
246         struct udev_ctrl_msg_wire ctrl_msg_wire;
247         int err = 0;
248
249         memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
250         strcpy(ctrl_msg_wire.version, "udev-" VERSION);
251         ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
252         ctrl_msg_wire.type = type;
253
254         if (buf != NULL)
255                 strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
256         else
257                 ctrl_msg_wire.intval = intval;
258
259         if (!uctrl->connected) {
260                 if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
261                         err = -errno;
262                         goto out;
263                 }
264                 uctrl->connected = true;
265         }
266         if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
267                 err = -errno;
268                 goto out;
269         }
270
271         /* wait for peer message handling or disconnect */
272         for (;;) {
273                 struct pollfd pfd[1];
274                 int r;
275
276                 pfd[0].fd = uctrl->sock;
277                 pfd[0].events = POLLIN;
278                 r = poll(pfd, 1, timeout * 1000);
279                 if (r  < 0) {
280                         if (errno == EINTR)
281                                 continue;
282                         err = -errno;
283                         break;
284                 }
285
286                 if (r > 0 && pfd[0].revents & POLLERR) {
287                         err = -EIO;
288                         break;
289                 }
290
291                 if (r == 0)
292                         err = -ETIMEDOUT;
293                 break;
294         }
295 out:
296         return err;
297 }
298
299 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout)
300 {
301         return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
302 }
303
304 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
305 {
306         return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
307 }
308
309 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
310 {
311         return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
312 }
313
314 int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout)
315 {
316         return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
317 }
318
319 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
320 {
321         return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
322 }
323
324 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
325 {
326         return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
327 }
328
329 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
330 {
331         return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
332 }
333
334 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
335 {
336         return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
337 }
338
339 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
340 {
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                         log_error("timeout waiting for ctrl message\n");
371                         goto err;
372                 } else {
373                         if (!(pfd[0].revents & POLLIN)) {
374                                 log_error("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                 log_error("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                 log_error("no sender credentials received, message ignored\n");
399                 goto err;
400         }
401
402         if (cred->uid != 0) {
403                 log_error("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                 log_error("message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
409                 goto err;
410         }
411
412         return uctrl_msg;
413 err:
414         udev_ctrl_msg_unref(uctrl_msg);
415         return NULL;
416 }
417
418 struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
419 {
420         if (ctrl_msg == NULL)
421                 return NULL;
422         ctrl_msg->refcount++;
423         return ctrl_msg;
424 }
425
426 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
427 {
428         if (ctrl_msg == NULL)
429                 return NULL;
430         ctrl_msg->refcount--;
431         if (ctrl_msg->refcount > 0)
432                 return ctrl_msg;
433         udev_ctrl_connection_unref(ctrl_msg->conn);
434         free(ctrl_msg);
435         return NULL;
436 }
437
438 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
439 {
440         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
441                 return ctrl_msg->ctrl_msg_wire.intval;
442         return -1;
443 }
444
445 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
446 {
447         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
448                 return 1;
449         return -1;
450 }
451
452 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
453 {
454         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
455                 return 1;
456         return -1;
457 }
458
459 int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg)
460 {
461         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
462                 return 1;
463         return -1;
464 }
465
466 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
467 {
468         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
469                 return ctrl_msg->ctrl_msg_wire.buf;
470         return NULL;
471 }
472
473 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
474 {
475         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
476                 return ctrl_msg->ctrl_msg_wire.intval;
477         return -1;
478 }
479
480 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
481 {
482         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
483                 return 1;
484         return -1;
485 }
486
487 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
488 {
489         if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
490                 return 1;
491         return -1;
492 }