]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev-ctrl.c
add test/src to .gitignore
[thirdparty/systemd.git] / src / udev-ctrl.c
CommitLineData
d59f11e1 1/*
55e9959b 2 * libudev - interface to udev device information
d59f11e1 3 *
55e9959b 4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
d59f11e1 5 *
4061ab9f
KS
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.
d59f11e1
KS
10 */
11
d59f11e1
KS
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>
ff2c503d 19#include <sys/poll.h>
d59f11e1
KS
20#include <sys/socket.h>
21#include <sys/un.h>
22
c15d02e5 23#include "udev.h"
d59f11e1 24
540f4669 25/* wire protocol magic must match */
b692a750 26#define UDEV_CTRL_MAGIC 0xdead1dea
d59f11e1
KS
27
28enum 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,
7c85d636 33 UDEV_CTRL_RELOAD,
d59f11e1 34 UDEV_CTRL_SET_ENV,
87d55ff6 35 UDEV_CTRL_SET_CHILDREN_MAX,
ff2c503d
KS
36 UDEV_CTRL_PING,
37 UDEV_CTRL_EXIT,
d59f11e1
KS
38};
39
b692a750
KS
40struct udev_ctrl_msg_wire {
41 char version[16];
42 unsigned int magic;
d59f11e1
KS
43 enum udev_ctrl_msg_type type;
44 union {
45 int intval;
46 char buf[256];
47 };
48};
49
50struct udev_ctrl_msg {
51 int refcount;
ff2c503d 52 struct udev_ctrl_connection *conn;
b692a750 53 struct udev_ctrl_msg_wire ctrl_msg_wire;
d59f11e1
KS
54};
55
56struct udev_ctrl {
57 int refcount;
58 struct udev *udev;
59 int sock;
60 struct sockaddr_un saddr;
61 socklen_t addrlen;
7459bcdc 62 bool bound;
5cc4112e 63 bool cleanup_socket;
ff2c503d
KS
64 bool connected;
65};
66
67struct udev_ctrl_connection {
68 int refcount;
69 struct udev_ctrl *uctrl;
70 int sock;
d59f11e1
KS
71};
72
5cc4112e 73struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)
d59f11e1
KS
74{
75 struct udev_ctrl *uctrl;
76
b29a5e4a 77 uctrl = calloc(1, sizeof(struct udev_ctrl));
d59f11e1
KS
78 if (uctrl == NULL)
79 return NULL;
d59f11e1
KS
80 uctrl->refcount = 1;
81 uctrl->udev = udev;
82
7459bcdc 83 if (fd < 0) {
fdf52f5e 84 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
7459bcdc
KS
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;
d59f11e1
KS
93 }
94
95 uctrl->saddr.sun_family = AF_LOCAL;
5cc4112e
KS
96 util_strscpyl(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path),
97 udev_get_run_path(udev), "/control", NULL);
d59f11e1 98 uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
fc1de713
KS
99 return uctrl;
100}
101
5cc4112e 102struct udev_ctrl *udev_ctrl_new(struct udev *udev)
fc1de713 103{
5cc4112e 104 return udev_ctrl_new_from_fd(udev, -1);
d59f11e1
KS
105}
106
107int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
108{
109 int err;
fc1de713 110
7459bcdc 111 if (!uctrl->bound) {
fc1de713 112 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
5cc4112e
KS
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
fc1de713 118 if (err < 0) {
ff2c503d 119 err = -errno;
fc1de713
KS
120 err(uctrl->udev, "bind failed: %m\n");
121 return err;
122 }
7459bcdc 123
ff2c503d
KS
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 }
7459bcdc
KS
130
131 uctrl->bound = true;
5cc4112e 132 uctrl->cleanup_socket = true;
d59f11e1 133 }
d59f11e1
KS
134 return 0;
135}
136
137struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
138{
139 return uctrl->udev;
140}
141
142struct 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
ff2c503d 150struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
d59f11e1
KS
151{
152 if (uctrl == NULL)
ff2c503d 153 return NULL;
d59f11e1
KS
154 uctrl->refcount--;
155 if (uctrl->refcount > 0)
ff2c503d 156 return uctrl;
d59f11e1
KS
157 if (uctrl->sock >= 0)
158 close(uctrl->sock);
159 free(uctrl);
ff2c503d 160 return NULL;
d59f11e1
KS
161}
162
1f5a5100
KS
163int udev_ctrl_cleanup(struct udev_ctrl *uctrl)
164{
29282732
KS
165 if (uctrl == NULL)
166 return 0;
1f5a5100
KS
167 if (uctrl->cleanup_socket)
168 unlink(uctrl->saddr.sun_path);
169 return 0;
170}
171
d59f11e1
KS
172int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
173{
174 if (uctrl == NULL)
29282732 175 return -EINVAL;
d59f11e1
KS
176 return uctrl->sock;
177}
178
ff2c503d
KS
179struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
180{
181 struct udev_ctrl_connection *conn;
2c64f589
KS
182 struct ucred ucred;
183 socklen_t slen;
ff2c503d
KS
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
1547687a 192 conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
ff2c503d 193 if (conn->sock < 0) {
1547687a
KS
194 if (errno != EINTR)
195 err(uctrl->udev, "unable to receive ctrl connection: %m\n");
2c64f589
KS
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;
ff2c503d
KS
208 }
209
2c64f589 210 /* enable receiving of the sender credentials in the messages */
ff2c503d
KS
211 setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
212 udev_ctrl_ref(uctrl);
213 return conn;
2c64f589
KS
214err:
215 if (conn->sock >= 0)
216 close(conn->sock);
217 free(conn);
218 return NULL;
ff2c503d
KS
219}
220
221struct 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
229struct 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
243static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
d59f11e1 244{
b692a750 245 struct udev_ctrl_msg_wire ctrl_msg_wire;
ff2c503d 246 int err = 0;
d59f11e1 247
b692a750
KS
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;
7b3a52f4 251 ctrl_msg_wire.type = type;
d59f11e1
KS
252
253 if (buf != NULL)
065db052 254 util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
d59f11e1 255 else
7b3a52f4 256 ctrl_msg_wire.intval = intval;
d59f11e1 257
ff2c503d
KS
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;
d59f11e1 268 }
ff2c503d
KS
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 }
294out:
d59f11e1
KS
295 return err;
296}
297
ff2c503d
KS
298int 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
303int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
d59f11e1 304{
ff2c503d 305 return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
306}
307
ff2c503d 308int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
d59f11e1 309{
ff2c503d 310 return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
311}
312
7c85d636 313int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout)
d59f11e1 314{
7c85d636 315 return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
d59f11e1
KS
316}
317
ff2c503d 318int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
d59f11e1 319{
ff2c503d 320 return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
d59f11e1
KS
321}
322
ff2c503d 323int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
d59f11e1 324{
ff2c503d 325 return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
d59f11e1
KS
326}
327
ff2c503d 328int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
d59f11e1 329{
ff2c503d 330 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
d59f11e1
KS
331}
332
ff2c503d 333int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
bb38678e 334{
ff2c503d 335 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
bb38678e
SJR
336}
337
ff2c503d 338struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
d59f11e1 339{
ff2c503d 340 struct udev *udev = conn->uctrl->udev;
d59f11e1
KS
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
b29a5e4a 349 uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
d59f11e1
KS
350 if (uctrl_msg == NULL)
351 return NULL;
d59f11e1 352 uctrl_msg->refcount = 1;
ff2c503d 353 uctrl_msg->conn = conn;
80707e9a 354 udev_ctrl_connection_ref(conn);
d59f11e1 355
2c64f589
KS
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
7b3a52f4 382 iov.iov_base = &uctrl_msg->ctrl_msg_wire;
b692a750 383 iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
d59f11e1
KS
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);
ff2c503d 389 size = recvmsg(conn->sock, &smsg, 0);
d59f11e1 390 if (size < 0) {
2c64f589 391 err(udev, "unable to receive ctrl message: %m\n");
d59f11e1
KS
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) {
ff2c503d 398 err(udev, "no sender credentials received, message ignored\n");
d59f11e1
KS
399 goto err;
400 }
401
402 if (cred->uid != 0) {
ff2c503d 403 err(udev, "sender uid=%i, message ignored\n", cred->uid);
d59f11e1
KS
404 goto err;
405 }
406
b692a750 407 if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
ff2c503d 408 err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
d59f11e1
KS
409 goto err;
410 }
411
ff2c503d 412 dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
d59f11e1
KS
413 return uctrl_msg;
414err:
415 udev_ctrl_msg_unref(uctrl_msg);
416 return NULL;
417}
418
419struct 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
ff2c503d 427struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
d59f11e1
KS
428{
429 if (ctrl_msg == NULL)
ff2c503d 430 return NULL;
d59f11e1
KS
431 ctrl_msg->refcount--;
432 if (ctrl_msg->refcount > 0)
ff2c503d
KS
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);
d59f11e1 436 free(ctrl_msg);
ff2c503d 437 return NULL;
d59f11e1
KS
438}
439
440int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
441{
7b3a52f4
KS
442 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
443 return ctrl_msg->ctrl_msg_wire.intval;
d59f11e1
KS
444 return -1;
445}
446
447int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
448{
7b3a52f4 449 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
d59f11e1
KS
450 return 1;
451 return -1;
452}
453
454int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
455{
7b3a52f4 456 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
d59f11e1
KS
457 return 1;
458 return -1;
459}
460
7c85d636 461int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg)
d59f11e1 462{
7c85d636 463 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
d59f11e1
KS
464 return 1;
465 return -1;
466}
467
468const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
469{
7b3a52f4
KS
470 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
471 return ctrl_msg->ctrl_msg_wire.buf;
d59f11e1
KS
472 return NULL;
473}
474
87d55ff6 475int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
d59f11e1 476{
87d55ff6 477 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
7b3a52f4 478 return ctrl_msg->ctrl_msg_wire.intval;
d59f11e1
KS
479 return -1;
480}
bb38678e 481
ff2c503d 482int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
bb38678e 483{
ff2c503d
KS
484 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
485 return 1;
486 return -1;
487}
488
489int 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;
bb38678e
SJR
493 return -1;
494}