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