]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-ctrl.c
Merge pull request #11244 from yuwata/revert-udev-changes
[thirdparty/systemd.git] / src / udev / udev-ctrl.c
CommitLineData
d9215cd8
ZJS
1/* SPDX-License-Identifier: LGPL-2.1+
2 *
55e9959b 3 * libudev - interface to udev device information
d59f11e1 4 *
4061ab9f
KS
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
d59f11e1
KS
9 */
10
d59f11e1 11#include <errno.h>
cf0fbc49 12#include <poll.h>
d59f11e1 13#include <stddef.h>
cf0fbc49 14#include <stdlib.h>
d59f11e1 15#include <string.h>
d59f11e1
KS
16#include <sys/socket.h>
17#include <sys/un.h>
cf0fbc49 18#include <unistd.h>
d59f11e1 19
b5efdb8a 20#include "alloc-util.h"
3ffd4af2 21#include "fd-util.h"
f97b34a6 22#include "format-util.h"
5cfa2c3d 23#include "io-util.h"
3ffd4af2 24#include "socket-util.h"
7d68eb1b
YW
25#include "strxcpyx.h"
26#include "udev-ctrl.h"
ef118d00 27#include "util.h"
d59f11e1 28
540f4669 29/* wire protocol magic must match */
912541b0 30#define UDEV_CTRL_MAGIC 0xdead1dea
d59f11e1
KS
31
32enum udev_ctrl_msg_type {
912541b0
KS
33 UDEV_CTRL_UNKNOWN,
34 UDEV_CTRL_SET_LOG_LEVEL,
35 UDEV_CTRL_STOP_EXEC_QUEUE,
36 UDEV_CTRL_START_EXEC_QUEUE,
37 UDEV_CTRL_RELOAD,
38 UDEV_CTRL_SET_ENV,
39 UDEV_CTRL_SET_CHILDREN_MAX,
40 UDEV_CTRL_PING,
41 UDEV_CTRL_EXIT,
d59f11e1
KS
42};
43
b692a750 44struct udev_ctrl_msg_wire {
912541b0 45 char version[16];
14cb109d 46 unsigned magic;
912541b0
KS
47 enum udev_ctrl_msg_type type;
48 union {
49 int intval;
50 char buf[256];
51 };
d59f11e1
KS
52};
53
54struct udev_ctrl_msg {
8f71a0d1 55 unsigned n_ref;
912541b0
KS
56 struct udev_ctrl_connection *conn;
57 struct udev_ctrl_msg_wire ctrl_msg_wire;
d59f11e1
KS
58};
59
60struct udev_ctrl {
8f71a0d1 61 unsigned n_ref;
912541b0 62 int sock;
6421348d 63 union sockaddr_union saddr;
912541b0
KS
64 socklen_t addrlen;
65 bool bound;
66 bool cleanup_socket;
67 bool connected;
ff2c503d
KS
68};
69
70struct udev_ctrl_connection {
8f71a0d1 71 unsigned n_ref;
912541b0
KS
72 struct udev_ctrl *uctrl;
73 int sock;
d59f11e1
KS
74};
75
2024ed61 76struct udev_ctrl *udev_ctrl_new_from_fd(int fd) {
912541b0 77 struct udev_ctrl *uctrl;
4bbdff75 78 int r;
912541b0 79
955d98c9 80 uctrl = new0(struct udev_ctrl, 1);
9315f853 81 if (!uctrl)
912541b0 82 return NULL;
8f71a0d1 83 uctrl->n_ref = 1;
912541b0
KS
84
85 if (fd < 0) {
86 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
87 if (uctrl->sock < 0) {
572909a3 88 log_error_errno(errno, "Failed to create socket: %m");
912541b0
KS
89 udev_ctrl_unref(uctrl);
90 return NULL;
91 }
92 } else {
93 uctrl->bound = true;
94 uctrl->sock = fd;
95 }
25568304
KS
96
97 /*
98 * FIXME: remove it as soon as we can depend on this:
99 * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=90c6bd34f884cd9cee21f1d152baf6c18bcac949
100 */
2ff48e98 101 r = setsockopt_int(uctrl->sock, SOL_SOCKET, SO_PASSCRED, true);
4bbdff75 102 if (r < 0)
572909a3 103 log_warning_errno(r, "Failed to set SO_PASSCRED: %m");
912541b0 104
44ed5214
LP
105 uctrl->saddr.un = (struct sockaddr_un) {
106 .sun_family = AF_UNIX,
107 .sun_path = "/run/udev/control",
108 };
109
fc2fffe7 110 uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
912541b0 111 return uctrl;
fc1de713
KS
112}
113
2024ed61
YW
114struct udev_ctrl *udev_ctrl_new(void) {
115 return udev_ctrl_new_from_fd(-1);
d59f11e1
KS
116}
117
9ec6e95b 118int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
912541b0
KS
119 int err;
120
121 if (!uctrl->bound) {
6421348d 122 err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
912541b0 123 if (err < 0 && errno == EADDRINUSE) {
155b6876 124 (void) sockaddr_un_unlink(&uctrl->saddr.un);
6421348d 125 err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
912541b0
KS
126 }
127
ece174c5 128 if (err < 0)
572909a3 129 return log_error_errno(errno, "Failed to bind socket: %m");
912541b0
KS
130
131 err = listen(uctrl->sock, 0);
ece174c5 132 if (err < 0)
572909a3 133 return log_error_errno(errno, "Failed to listen: %m");
912541b0
KS
134
135 uctrl->bound = true;
136 uctrl->cleanup_socket = true;
137 }
138 return 0;
d59f11e1
KS
139}
140
8f71a0d1
YW
141static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
142 assert(uctrl);
35927d13 143
8f71a0d1
YW
144 safe_close(uctrl->sock);
145 return mfree(uctrl);
d59f11e1
KS
146}
147
8f71a0d1
YW
148DEFINE_PRIVATE_TRIVIAL_REF_FUNC(struct udev_ctrl, udev_ctrl);
149DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
d59f11e1 150
9ec6e95b 151int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
9315f853 152 if (!uctrl)
912541b0
KS
153 return 0;
154 if (uctrl->cleanup_socket)
155b6876 155 sockaddr_un_unlink(&uctrl->saddr.un);
912541b0 156 return 0;
1f5a5100
KS
157}
158
9ec6e95b 159int udev_ctrl_get_fd(struct udev_ctrl *uctrl) {
9315f853 160 if (!uctrl)
912541b0
KS
161 return -EINVAL;
162 return uctrl->sock;
d59f11e1
KS
163}
164
9ec6e95b 165struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
912541b0 166 struct udev_ctrl_connection *conn;
39883f62 167 struct ucred ucred = {};
eff05270 168 int r;
912541b0 169
eff05270 170 conn = new(struct udev_ctrl_connection, 1);
9315f853 171 if (!conn)
912541b0 172 return NULL;
8f71a0d1 173 conn->n_ref = 1;
912541b0
KS
174 conn->uctrl = uctrl;
175
176 conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
177 if (conn->sock < 0) {
178 if (errno != EINTR)
572909a3 179 log_error_errno(errno, "Failed to receive ctrl connection: %m");
912541b0
KS
180 goto err;
181 }
182
183 /* check peer credential of connection */
eff05270
LP
184 r = getpeercred(conn->sock, &ucred);
185 if (r < 0) {
572909a3 186 log_error_errno(r, "Failed to receive credentials of ctrl connection: %m");
912541b0
KS
187 goto err;
188 }
189 if (ucred.uid > 0) {
572909a3 190 log_error("Sender uid="UID_FMT", message ignored", ucred.uid);
912541b0
KS
191 goto err;
192 }
193
194 /* enable receiving of the sender credentials in the messages */
2ff48e98 195 r = setsockopt_int(conn->sock, SOL_SOCKET, SO_PASSCRED, true);
4bbdff75 196 if (r < 0)
572909a3 197 log_warning_errno(r, "Failed to set SO_PASSCRED: %m");
4bbdff75 198
912541b0
KS
199 udev_ctrl_ref(uctrl);
200 return conn;
2c64f589 201err:
a4209121 202 safe_close(conn->sock);
6b430fdb 203 return mfree(conn);
ff2c503d
KS
204}
205
8f71a0d1
YW
206static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_connection *conn) {
207 assert(conn);
35927d13 208
8f71a0d1
YW
209 safe_close(conn->sock);
210 udev_ctrl_unref(conn->uctrl);
211 return mfree(conn);
ff2c503d
KS
212}
213
8f71a0d1
YW
214DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free);
215
9ec6e95b 216static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout) {
b9da6a09
ZJS
217 struct udev_ctrl_msg_wire ctrl_msg_wire = {
218 .version = "udev-" STRINGIFY(PROJECT_VERSION),
219 .magic = UDEV_CTRL_MAGIC,
220 .type = type,
221 };
912541b0 222
9315f853 223 if (buf)
d5a89d7d 224 strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
912541b0
KS
225 else
226 ctrl_msg_wire.intval = intval;
227
228 if (!uctrl->connected) {
b9da6a09
ZJS
229 if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0)
230 return -errno;
912541b0
KS
231 uctrl->connected = true;
232 }
b9da6a09
ZJS
233 if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0)
234 return -errno;
912541b0
KS
235
236 /* wait for peer message handling or disconnect */
237 for (;;) {
b9da6a09
ZJS
238 struct pollfd pfd = {
239 .fd = uctrl->sock,
240 .events = POLLIN,
241 };
912541b0
KS
242 int r;
243
b9da6a09 244 r = poll(&pfd, 1, timeout * MSEC_PER_SEC);
49c603bd 245 if (r < 0) {
912541b0
KS
246 if (errno == EINTR)
247 continue;
b9da6a09 248 return -errno;
912541b0 249 }
912541b0 250 if (r == 0)
b9da6a09
ZJS
251 return -ETIMEDOUT;
252 if (pfd.revents & POLLERR)
253 return -EIO;
254 return 0;
912541b0 255 }
d59f11e1
KS
256}
257
9ec6e95b 258int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout) {
912541b0 259 return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
ff2c503d
KS
260}
261
9ec6e95b 262int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout) {
912541b0 263 return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
264}
265
9ec6e95b 266int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout) {
912541b0 267 return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
268}
269
9ec6e95b 270int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout) {
912541b0 271 return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
d59f11e1
KS
272}
273
9ec6e95b 274int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout) {
912541b0 275 return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
d59f11e1
KS
276}
277
9ec6e95b 278int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout) {
912541b0 279 return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
d59f11e1
KS
280}
281
9ec6e95b 282int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout) {
912541b0 283 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
d59f11e1
KS
284}
285
9ec6e95b 286int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout) {
912541b0 287 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
bb38678e
SJR
288}
289
9ec6e95b 290struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
912541b0
KS
291 struct udev_ctrl_msg *uctrl_msg;
292 ssize_t size;
912541b0
KS
293 struct cmsghdr *cmsg;
294 struct iovec iov;
912541b0 295 char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
97fec53e
ZJS
296 struct msghdr smsg = {
297 .msg_iov = &iov,
298 .msg_iovlen = 1,
299 .msg_control = cred_msg,
300 .msg_controllen = sizeof(cred_msg),
301 };
302 struct ucred *cred;
912541b0 303
97fec53e 304 uctrl_msg = new0(struct udev_ctrl_msg, 1);
9315f853 305 if (!uctrl_msg)
912541b0 306 return NULL;
8f71a0d1 307 uctrl_msg->n_ref = 1;
912541b0
KS
308 uctrl_msg->conn = conn;
309 udev_ctrl_connection_ref(conn);
310
311 /* wait for the incoming message */
f168c273 312 for (;;) {
912541b0
KS
313 struct pollfd pfd[1];
314 int r;
315
316 pfd[0].fd = conn->sock;
317 pfd[0].events = POLLIN;
318
319 r = poll(pfd, 1, 10000);
49c603bd 320 if (r < 0) {
912541b0
KS
321 if (errno == EINTR)
322 continue;
323 goto err;
324 } else if (r == 0) {
572909a3 325 log_error("Timeout waiting for ctrl message");
912541b0
KS
326 goto err;
327 } else {
328 if (!(pfd[0].revents & POLLIN)) {
572909a3 329 log_error("Invalid ctrl connection: %m");
912541b0
KS
330 goto err;
331 }
332 }
333
334 break;
335 }
336
5cfa2c3d 337 iov = IOVEC_MAKE(&uctrl_msg->ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire));
97fec53e 338
a38d9945 339 size = recvmsg(conn->sock, &smsg, 0);
572909a3
YW
340 if (size < 0) {
341 log_error_errno(errno, "Failed to receive ctrl message: %m");
912541b0
KS
342 goto err;
343 }
1c8da044
LP
344
345 cmsg_close_all(&smsg);
346
912541b0 347 cmsg = CMSG_FIRSTHDR(&smsg);
912541b0 348
9315f853 349 if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
572909a3 350 log_error("No sender credentials received, ignoring message");
912541b0
KS
351 goto err;
352 }
353
93b1da85
KZ
354 cred = (struct ucred *) CMSG_DATA(cmsg);
355
912541b0 356 if (cred->uid != 0) {
572909a3 357 log_error("Sender uid="UID_FMT", ignoring message", cred->uid);
912541b0
KS
358 goto err;
359 }
360
361 if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
572909a3 362 log_error("Message magic 0x%08x doesn't match, ignoring", uctrl_msg->ctrl_msg_wire.magic);
912541b0
KS
363 goto err;
364 }
365
912541b0 366 return uctrl_msg;
d59f11e1 367err:
912541b0
KS
368 udev_ctrl_msg_unref(uctrl_msg);
369 return NULL;
d59f11e1
KS
370}
371
8f71a0d1
YW
372static struct udev_ctrl_msg *udev_ctrl_msg_free(struct udev_ctrl_msg *ctrl_msg) {
373 assert(ctrl_msg);
35927d13 374
8f71a0d1
YW
375 udev_ctrl_connection_unref(ctrl_msg->conn);
376 return mfree(ctrl_msg);
d59f11e1
KS
377}
378
8f71a0d1
YW
379DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl_msg, udev_ctrl_msg, udev_ctrl_msg_free);
380
9ec6e95b 381int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
382 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
383 return ctrl_msg->ctrl_msg_wire.intval;
384 return -1;
d59f11e1
KS
385}
386
9ec6e95b 387int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
388 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
389 return 1;
390 return -1;
d59f11e1
KS
391}
392
9ec6e95b 393int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
394 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
395 return 1;
396 return -1;
d59f11e1
KS
397}
398
9ec6e95b 399int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
400 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
401 return 1;
402 return -1;
d59f11e1
KS
403}
404
9ec6e95b 405const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
406 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
407 return ctrl_msg->ctrl_msg_wire.buf;
408 return NULL;
d59f11e1
KS
409}
410
9ec6e95b 411int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
412 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
413 return ctrl_msg->ctrl_msg_wire.intval;
414 return -1;
d59f11e1 415}
bb38678e 416
9ec6e95b 417int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
418 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
419 return 1;
420 return -1;
ff2c503d
KS
421}
422
9ec6e95b 423int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) {
912541b0
KS
424 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
425 return 1;
426 return -1;
bb38678e 427}