]> git.ipfire.org Git - thirdparty/systemd.git/blame - libudev/libudev-ctrl.c
require explicit "db_persist" to exclude device info from --db-cleanup
[thirdparty/systemd.git] / libudev / libudev-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
d59f11e1
KS
23#include "libudev.h"
24#include "libudev-private.h"
25
540f4669 26/* wire protocol magic must match */
b692a750 27#define UDEV_CTRL_MAGIC 0xdead1dea
d59f11e1
KS
28
29enum 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,
87d55ff6 36 UDEV_CTRL_SET_CHILDREN_MAX,
ff2c503d
KS
37 UDEV_CTRL_PING,
38 UDEV_CTRL_EXIT,
d59f11e1
KS
39};
40
b692a750
KS
41struct udev_ctrl_msg_wire {
42 char version[16];
43 unsigned int magic;
d59f11e1
KS
44 enum udev_ctrl_msg_type type;
45 union {
46 int intval;
47 char buf[256];
48 };
49};
50
51struct udev_ctrl_msg {
52 int refcount;
ff2c503d 53 struct udev_ctrl_connection *conn;
b692a750 54 struct udev_ctrl_msg_wire ctrl_msg_wire;
d59f11e1
KS
55};
56
57struct udev_ctrl {
58 int refcount;
59 struct udev *udev;
60 int sock;
61 struct sockaddr_un saddr;
62 socklen_t addrlen;
ff2c503d
KS
63 bool connected;
64};
65
66struct udev_ctrl_connection {
67 int refcount;
68 struct udev_ctrl *uctrl;
69 int sock;
d59f11e1
KS
70};
71
fc1de713 72static struct udev_ctrl *udev_ctrl_new(struct udev *udev)
d59f11e1
KS
73{
74 struct udev_ctrl *uctrl;
75
b29a5e4a 76 uctrl = calloc(1, sizeof(struct udev_ctrl));
d59f11e1
KS
77 if (uctrl == NULL)
78 return NULL;
d59f11e1
KS
79 uctrl->refcount = 1;
80 uctrl->udev = udev;
fc1de713
KS
81 return uctrl;
82}
83
84struct 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;
d59f11e1 91
ff2c503d 92 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
d59f11e1 93 if (uctrl->sock < 0) {
659353f5 94 err(udev, "error getting socket: %m\n");
d59f11e1
KS
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';
fc1de713
KS
105 return uctrl;
106}
107
108struct 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;
d59f11e1
KS
116
117 return uctrl;
118}
119
120int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
121{
122 int err;
fc1de713
KS
123
124 if (uctrl->addrlen > 0) {
125 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
126 if (err < 0) {
ff2c503d 127 err = -errno;
fc1de713
KS
128 err(uctrl->udev, "bind failed: %m\n");
129 return err;
130 }
ff2c503d
KS
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 }
d59f11e1 137 }
d59f11e1
KS
138 return 0;
139}
140
141struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
142{
143 return uctrl->udev;
144}
145
146struct 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
ff2c503d 154struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
d59f11e1
KS
155{
156 if (uctrl == NULL)
ff2c503d 157 return NULL;
d59f11e1
KS
158 uctrl->refcount--;
159 if (uctrl->refcount > 0)
ff2c503d 160 return uctrl;
d59f11e1
KS
161 if (uctrl->sock >= 0)
162 close(uctrl->sock);
163 free(uctrl);
ff2c503d 164 return NULL;
d59f11e1
KS
165}
166
167int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
168{
169 if (uctrl == NULL)
170 return -1;
171 return uctrl->sock;
172}
173
ff2c503d
KS
174struct 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
197struct 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
205struct 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
219static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
d59f11e1 220{
b692a750 221 struct udev_ctrl_msg_wire ctrl_msg_wire;
ff2c503d 222 int err = 0;
d59f11e1 223
b692a750
KS
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;
7b3a52f4 227 ctrl_msg_wire.type = type;
d59f11e1
KS
228
229 if (buf != NULL)
065db052 230 util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
d59f11e1 231 else
7b3a52f4 232 ctrl_msg_wire.intval = intval;
d59f11e1 233
ff2c503d
KS
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;
d59f11e1 244 }
ff2c503d
KS
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 }
270out:
d59f11e1
KS
271 return err;
272}
273
ff2c503d
KS
274int 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
279int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
d59f11e1 280{
ff2c503d 281 return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
282}
283
ff2c503d 284int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
d59f11e1 285{
ff2c503d 286 return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
d59f11e1
KS
287}
288
ff2c503d 289int udev_ctrl_send_reload_rules(struct udev_ctrl *uctrl, int timeout)
d59f11e1 290{
ff2c503d 291 return ctrl_send(uctrl, UDEV_CTRL_RELOAD_RULES, 0, NULL, timeout);
d59f11e1
KS
292}
293
ff2c503d 294int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
d59f11e1 295{
ff2c503d 296 return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
d59f11e1
KS
297}
298
ff2c503d 299int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
d59f11e1 300{
ff2c503d 301 return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
d59f11e1
KS
302}
303
ff2c503d 304int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
d59f11e1 305{
ff2c503d 306 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
d59f11e1
KS
307}
308
ff2c503d 309int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
bb38678e 310{
ff2c503d 311 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
bb38678e
SJR
312}
313
ff2c503d 314struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
d59f11e1 315{
ff2c503d 316 struct udev *udev = conn->uctrl->udev;
d59f11e1
KS
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
b29a5e4a 325 uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
d59f11e1
KS
326 if (uctrl_msg == NULL)
327 return NULL;
d59f11e1 328 uctrl_msg->refcount = 1;
ff2c503d 329 uctrl_msg->conn = conn;
80707e9a 330 udev_ctrl_connection_ref(conn);
d59f11e1 331
7b3a52f4 332 iov.iov_base = &uctrl_msg->ctrl_msg_wire;
b692a750 333 iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
d59f11e1
KS
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);
ff2c503d 339 size = recvmsg(conn->sock, &smsg, 0);
d59f11e1 340 if (size < 0) {
ff2c503d 341 err(udev, "unable to receive user udevd message: %m\n");
d59f11e1
KS
342 goto err;
343 }
344 cmsg = CMSG_FIRSTHDR(&smsg);
345 cred = (struct ucred *) CMSG_DATA(cmsg);
346
347 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
ff2c503d 348 err(udev, "no sender credentials received, message ignored\n");
d59f11e1
KS
349 goto err;
350 }
351
352 if (cred->uid != 0) {
ff2c503d 353 err(udev, "sender uid=%i, message ignored\n", cred->uid);
d59f11e1
KS
354 goto err;
355 }
356
b692a750 357 if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
ff2c503d 358 err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
d59f11e1
KS
359 goto err;
360 }
361
ff2c503d 362 dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
d59f11e1
KS
363 return uctrl_msg;
364err:
365 udev_ctrl_msg_unref(uctrl_msg);
366 return NULL;
367}
368
369struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
370{
371 if (ctrl_msg == NULL)
372 return NULL;
373 ctrl_msg->refcount++;
374 return ctrl_msg;
375}
376
ff2c503d 377struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
d59f11e1
KS
378{
379 if (ctrl_msg == NULL)
ff2c503d 380 return NULL;
d59f11e1
KS
381 ctrl_msg->refcount--;
382 if (ctrl_msg->refcount > 0)
ff2c503d
KS
383 return ctrl_msg;
384 dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
385 udev_ctrl_connection_unref(ctrl_msg->conn);
d59f11e1 386 free(ctrl_msg);
ff2c503d 387 return NULL;
d59f11e1
KS
388}
389
390int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
391{
7b3a52f4
KS
392 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
393 return ctrl_msg->ctrl_msg_wire.intval;
d59f11e1
KS
394 return -1;
395}
396
397int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
398{
7b3a52f4 399 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
d59f11e1
KS
400 return 1;
401 return -1;
402}
403
404int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
405{
7b3a52f4 406 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
d59f11e1
KS
407 return 1;
408 return -1;
409}
410
411int udev_ctrl_get_reload_rules(struct udev_ctrl_msg *ctrl_msg)
412{
7b3a52f4 413 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD_RULES)
d59f11e1
KS
414 return 1;
415 return -1;
416}
417
418const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
419{
7b3a52f4
KS
420 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
421 return ctrl_msg->ctrl_msg_wire.buf;
d59f11e1
KS
422 return NULL;
423}
424
87d55ff6 425int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
d59f11e1 426{
87d55ff6 427 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
7b3a52f4 428 return ctrl_msg->ctrl_msg_wire.intval;
d59f11e1
KS
429 return -1;
430}
bb38678e 431
ff2c503d 432int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
bb38678e 433{
ff2c503d
KS
434 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
435 return 1;
436 return -1;
437}
438
439int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
440{
441 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
442 return 1;
bb38678e
SJR
443 return -1;
444}