]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-node.c
device-util: Declare iterator variables inline
[thirdparty/systemd.git] / src / udev / udev-node.c
CommitLineData
f13467ec 1/* SPDX-License-Identifier: GPL-2.0-or-later */
ea733a2f 2
57a27290 3#include <sys/file.h>
ea733a2f 4
e6494336
YW
5#include "sd-id128.h"
6
a2554ace 7#include "alloc-util.h"
a2554ace
YW
8#include "device-private.h"
9#include "device-util.h"
7176f06c 10#include "devnum-util.h"
8fb3f009 11#include "dirent-util.h"
26dd37f6 12#include "escape.h"
a2554ace 13#include "fd-util.h"
72a459ad 14#include "fileio.h"
f97b34a6 15#include "format-util.h"
f4f15635 16#include "fs-util.h"
e6494336 17#include "hexdecoct.h"
0690160e 18#include "label-util.h"
35cd0ba5 19#include "mkdir-label.h"
377a83f0 20#include "parse-util.h"
a2554ace 21#include "path-util.h"
07630cea
LP
22#include "selinux-util.h"
23#include "smack-util.h"
30f6dce6 24#include "stat-util.h"
07630cea 25#include "string-util.h"
a2554ace 26#include "udev-node.h"
3708c0f4 27#include "user-util.h"
9825617b 28
e6494336 29#define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
30f6dce6 30
10551728
YW
31int udev_node_cleanup(void) {
32 _cleanup_closedir_ DIR *dir = NULL;
33
34 /* This must not be called when any workers exist. It would cause a race between mkdir() called
35 * by stack_directory_lock() and unlinkat() called by this. */
36
37 dir = opendir("/run/udev/links");
38 if (!dir) {
39 if (errno == ENOENT)
40 return 0;
41
42 return log_debug_errno(errno, "Failed to open directory '/run/udev/links', ignoring: %m");
43 }
44
45 FOREACH_DIRENT_ALL(de, dir, break) {
46 _cleanup_free_ char *lockfile = NULL;
47
48 if (de->d_name[0] == '.')
49 continue;
50
51 if (de->d_type != DT_DIR)
52 continue;
53
54 /* As commented in the above, this is called when no worker exists, hence the file is not
55 * locked. On a later uevent, the lock file will be created if necessary. So, we can safely
56 * remove the file now. */
57 lockfile = path_join(de->d_name, ".lock");
58 if (!lockfile)
59 return log_oom_debug();
60
61 if (unlinkat(dirfd(dir), lockfile, 0) < 0 && errno != ENOENT) {
62 log_debug_errno(errno, "Failed to remove '/run/udev/links/%s', ignoring: %m", lockfile);
63 continue;
64 }
65
66 if (unlinkat(dirfd(dir), de->d_name, AT_REMOVEDIR) < 0 && errno != ENOTEMPTY)
67 log_debug_errno(errno, "Failed to remove '/run/udev/links/%s', ignoring: %m", de->d_name);
68 }
69
70 return 0;
71}
72
6b01e290 73static int node_symlink(sd_device *dev, const char *devnode, const char *slink) {
6b01e290 74 struct stat st;
a2554ace
YW
75 int r;
76
77 assert(dev);
a2554ace 78 assert(slink);
c1ee2674 79
541a463f
YW
80 if (!devnode) {
81 r = sd_device_get_devname(dev, &devnode);
82 if (r < 0)
83 return log_device_debug_errno(dev, r, "Failed to get device node: %m");
84 }
85
6b01e290
YW
86 if (lstat(slink, &st) >= 0) {
87 if (!S_ISLNK(st.st_mode))
242d39eb 88 return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
541a463f 89 "Conflicting inode '%s' found, symlink to '%s' will not be created.",
6b01e290 90 slink, devnode);
242d39eb
YW
91 } else if (errno != ENOENT)
92 return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
93
6d421385 94 r = mkdir_parents_label(slink, 0755);
a2554ace 95 if (r < 0)
6d421385 96 return log_device_debug_errno(dev, r, "Failed to create parent directory of '%s': %m", slink);
5802d4ea 97
6d421385
YW
98 /* use relative link */
99 r = symlink_atomic_full_label(devnode, slink, /* make_relative = */ true);
a2554ace 100 if (r < 0)
6d421385 101 return log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink, devnode);
a2554ace 102
6d421385 103 log_device_debug(dev, "Successfully created symlink '%s' to '%s'", slink, devnode);
242d39eb 104 return 0;
fa33d857
KS
105}
106
6d90488a
FB
107static int stack_directory_read_one(int dirfd, const char *id, char **devnode, int *priority) {
108 _cleanup_free_ char *buf = NULL;
13271e2d
YW
109 int tmp_prio, r;
110
111 assert(dirfd >= 0);
112 assert(id);
13271e2d
YW
113 assert(priority);
114
135e5a20
YW
115 /* This reads priority and device node from the symlink under /run/udev/links (or udev database).
116 * If 'devnode' is NULL, obtained priority is always set to '*priority'. If 'devnode' is non-NULL,
117 * this updates '*devnode' and '*priority'. */
118
6d90488a
FB
119 /* First, let's try to read the entry with the new format, which should replace the old format pretty
120 * quickly. */
6d90488a
FB
121 r = readlinkat_malloc(dirfd, id, &buf);
122 if (r >= 0) {
123 char *colon;
13271e2d 124
6d90488a 125 /* With the new format, the devnode and priority can be obtained from symlink itself. */
13271e2d
YW
126
127 colon = strchr(buf, ':');
128 if (!colon || colon == buf)
129 return -EINVAL;
130
131 *colon = '\0';
132
69928b4f
YW
133 /* Of course, this check is racy, but it is not necessary to be perfect. Even if the device
134 * node will be removed after this check, we will receive 'remove' uevent, and the invalid
135 * symlink will be removed during processing the event. The check is just for shortening the
136 * timespan that the symlink points to a non-existing device node. */
137 if (access(colon + 1, F_OK) < 0)
e8a54a4e 138 return -ENODEV;
69928b4f 139
13271e2d
YW
140 r = safe_atoi(buf, &tmp_prio);
141 if (r < 0)
142 return r;
143
135e5a20
YW
144 if (!devnode)
145 goto finalize;
146
13271e2d
YW
147 if (*devnode && tmp_prio <= *priority)
148 return 0; /* Unchanged */
149
150 r = free_and_strdup(devnode, colon + 1);
151 if (r < 0)
152 return r;
153
6d90488a 154 } else if (r == -EINVAL) { /* Not a symlink ? try the old format */
13271e2d
YW
155 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
156 const char *val;
157
158 /* Old format. The devnode and priority must be obtained from uevent and udev database. */
159
160 r = sd_device_new_from_device_id(&dev, id);
161 if (r < 0)
162 return r;
163
164 r = device_get_devlink_priority(dev, &tmp_prio);
165 if (r < 0)
166 return r;
167
135e5a20
YW
168 if (!devnode)
169 goto finalize;
170
13271e2d
YW
171 if (*devnode && tmp_prio <= *priority)
172 return 0; /* Unchanged */
173
174 r = sd_device_get_devname(dev, &val);
175 if (r < 0)
176 return r;
177
178 r = free_and_strdup(devnode, val);
179 if (r < 0)
180 return r;
6d90488a
FB
181
182 } else
183 return r == -ENOENT ? -ENODEV : r;
13271e2d 184
135e5a20 185finalize:
13271e2d
YW
186 *priority = tmp_prio;
187 return 1; /* Updated */
188}
189
72a459ad 190static int stack_directory_find_prioritized_devnode(sd_device *dev, int dirfd, bool add, char **ret) {
a2554ace 191 _cleanup_closedir_ DIR *dir = NULL;
6b01e290 192 _cleanup_free_ char *devnode = NULL;
c207a572 193 int r, priority;
d2b50631 194 const char *id;
a2554ace 195
d2b50631 196 assert(dev);
72a459ad 197 assert(dirfd >= 0);
a2554ace 198 assert(ret);
912541b0 199
d2b50631 200 /* Find device node of device with highest priority. This returns 1 if a device found, 0 if no
6b01e290 201 * device found, or a negative errno on error. */
d2b50631 202
912541b0 203 if (add) {
6b01e290 204 const char *n;
a2554ace
YW
205
206 r = device_get_devlink_priority(dev, &priority);
207 if (r < 0)
208 return r;
209
6b01e290 210 r = sd_device_get_devname(dev, &n);
a2554ace
YW
211 if (r < 0)
212 return r;
213
6b01e290
YW
214 devnode = strdup(n);
215 if (!devnode)
a2554ace 216 return -ENOMEM;
912541b0
KS
217 }
218
72a459ad 219 dir = xopendirat(dirfd, ".", O_NOFOLLOW);
a28d67a9
YW
220 if (!dir)
221 return -errno;
a2554ace 222
d2b50631
YW
223 r = device_get_device_id(dev, &id);
224 if (r < 0)
225 return r;
226
6d90488a 227 FOREACH_DIRENT(de, dir, break) {
912541b0 228
377a83f0 229 /* skip ourself */
c7f0d9e5 230 if (streq(de->d_name, id))
912541b0
KS
231 continue;
232
6d90488a
FB
233 r = stack_directory_read_one(dirfd, de->d_name, &devnode, &priority);
234 if (r < 0 && r != -ENODEV)
72a459ad 235 log_debug_errno(r, "Failed to read '%s', ignoring: %m", de->d_name);
912541b0 236 }
a2554ace 237
6b01e290 238 *ret = TAKE_PTR(devnode);
d2b50631 239 return !!*ret;
aa8734ff
KS
240}
241
a28d67a9 242static int stack_directory_update(sd_device *dev, int fd, bool add) {
a28d67a9
YW
243 const char *id;
244 int r;
377a83f0
YW
245
246 assert(dev);
a28d67a9 247 assert(fd >= 0);
377a83f0
YW
248
249 r = device_get_device_id(dev, &id);
250 if (r < 0)
a28d67a9 251 return r;
377a83f0 252
a28d67a9
YW
253 if (add) {
254 _cleanup_free_ char *data = NULL, *buf = NULL;
255 const char *devname;
256 int priority;
6df797f7 257
a28d67a9
YW
258 r = sd_device_get_devname(dev, &devname);
259 if (r < 0)
260 return r;
6df797f7 261
a28d67a9
YW
262 r = device_get_devlink_priority(dev, &priority);
263 if (r < 0)
264 return r;
6df797f7 265
a28d67a9
YW
266 if (asprintf(&data, "%i:%s", priority, devname) < 0)
267 return -ENOMEM;
0706cdf4 268
a28d67a9
YW
269 if (readlinkat_malloc(fd, id, &buf) >= 0 && streq(buf, data))
270 return 0; /* Unchanged. */
0706cdf4 271
a28d67a9 272 (void) unlinkat(fd, id, 0);
6df797f7 273
a28d67a9
YW
274 if (symlinkat(data, fd, id) < 0)
275 return -errno;
377a83f0 276
a28d67a9
YW
277 } else {
278 if (unlinkat(fd, id, 0) < 0) {
279 if (errno == ENOENT)
280 return 0; /* Unchanged. */
281 return -errno;
282 }
377a83f0
YW
283 }
284
57a27290 285 return 1; /* Updated. */
a28d67a9 286}
377a83f0 287
b9168275
YW
288size_t udev_node_escape_path(const char *src, char *dest, size_t size) {
289 size_t i, j;
290 uint64_t h;
291
292 assert(src);
293 assert(dest);
294 assert(size >= 12);
295
296 for (i = 0, j = 0; src[i] != '\0'; i++) {
297 if (src[i] == '/') {
298 if (j+4 >= size - 12 + 1)
299 goto toolong;
300 memcpy(&dest[j], "\\x2f", 4);
301 j += 4;
302 } else if (src[i] == '\\') {
303 if (j+4 >= size - 12 + 1)
304 goto toolong;
305 memcpy(&dest[j], "\\x5c", 4);
306 j += 4;
307 } else {
308 if (j+1 >= size - 12 + 1)
309 goto toolong;
310 dest[j] = src[i];
311 j++;
312 }
313 }
314 dest[j] = '\0';
315 return j;
316
317toolong:
318 /* If the input path is too long to encode as a filename, then let's suffix with a string
319 * generated from the hash of the path. */
320
321 h = siphash24_string(src, UDEV_NODE_HASH_KEY.bytes);
322
323 for (unsigned k = 0; k <= 10; k++)
324 dest[size - k - 2] = urlsafe_base64char((h >> (k * 6)) & 63);
325
326 dest[size - 1] = '\0';
327 return size - 1;
328}
329
7e7c36fb
YW
330static int stack_directory_get_name(const char *slink, char **ret) {
331 _cleanup_free_ char *s = NULL, *dirname = NULL;
e6494336 332 char name_enc[NAME_MAX+1];
7e7c36fb 333 const char *name;
a2554ace 334
7e7c36fb
YW
335 assert(slink);
336 assert(ret);
be322eca 337
7e7c36fb
YW
338 s = strdup(slink);
339 if (!s)
340 return -ENOMEM;
be322eca 341
7e7c36fb 342 path_simplify(s);
a2554ace 343
7e7c36fb
YW
344 if (!path_is_normalized(s))
345 return -EINVAL;
346
347 name = path_startswith(s, "/dev");
348 if (empty_or_root(name))
349 return -EINVAL;
350
351 udev_node_escape_path(name, name_enc, sizeof(name_enc));
cd8bcff5 352
377a83f0 353 dirname = path_join("/run/udev/links", name_enc);
a2554ace 354 if (!dirname)
7e7c36fb
YW
355 return -ENOMEM;
356
357 *ret = TAKE_PTR(dirname);
358 return 0;
359}
360
72a459ad 361static int stack_directory_open(sd_device *dev, const char *slink, int *ret_dirfd, int *ret_lockfd) {
c9032f91 362 _cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
72a459ad 363 _cleanup_free_ char *dirname = NULL;
c9032f91
FB
364 int r;
365
366 assert(dev);
72a459ad 367 assert(slink);
c9032f91
FB
368 assert(ret_dirfd);
369 assert(ret_lockfd);
370
72a459ad
FB
371 r = stack_directory_get_name(slink, &dirname);
372 if (r < 0)
373 return log_device_debug_errno(dev, r, "Failed to build stack directory name for '%s': %m", slink);
374
c9032f91
FB
375 r = mkdir_parents(dirname, 0755);
376 if (r < 0)
377 return log_device_debug_errno(dev, r, "Failed to create stack directory '%s': %m", dirname);
378
379 dirfd = open_mkdir_at(AT_FDCWD, dirname, O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW | O_RDONLY, 0755);
380 if (dirfd < 0)
381 return log_device_debug_errno(dev, dirfd, "Failed to open stack directory '%s': %m", dirname);
382
383 lockfd = openat(dirfd, ".lock", O_CLOEXEC | O_NOFOLLOW | O_RDONLY | O_CREAT, 0600);
384 if (lockfd < 0)
385 return log_device_debug_errno(dev, errno, "Failed to create lock file for stack directory '%s': %m", dirname);
386
387 if (flock(lockfd, LOCK_EX) < 0)
72a459ad 388 return log_device_debug_errno(dev, errno, "Failed to place a lock on lock file for %s: %m", dirname);
c9032f91
FB
389
390 *ret_dirfd = TAKE_FD(dirfd);
391 *ret_lockfd = TAKE_FD(lockfd);
392 return 0;
393}
394
331aa7aa
YW
395static int node_get_current(const char *slink, int dirfd, char **ret_id, int *ret_prio) {
396 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
397 _cleanup_free_ char *id_dup = NULL;
398 const char *id;
399 int r;
400
401 assert(slink);
402 assert(dirfd >= 0);
403 assert(ret_id);
404
405 r = sd_device_new_from_devname(&dev, slink);
406 if (r < 0)
407 return r;
408
409 r = device_get_device_id(dev, &id);
410 if (r < 0)
411 return r;
412
413 id_dup = strdup(id);
414 if (!id_dup)
415 return -ENOMEM;
416
417 if (ret_prio) {
418 r = stack_directory_read_one(dirfd, id, NULL, ret_prio);
419 if (r < 0)
420 return r;
421 }
422
423 *ret_id = TAKE_PTR(id_dup);
424 return 0;
425}
426
7e7c36fb 427static int link_update(sd_device *dev, const char *slink, bool add) {
331aa7aa 428 _cleanup_free_ char *current_id = NULL, *devnode = NULL;
254d1313 429 _cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
331aa7aa 430 int r, current_prio;
7e7c36fb
YW
431
432 assert(dev);
433 assert(slink);
434
72a459ad 435 r = stack_directory_open(dev, slink, &dirfd, &lockfd);
c9032f91
FB
436 if (r < 0)
437 return r;
57a27290 438
331aa7aa
YW
439 r = node_get_current(slink, dirfd, &current_id, add ? &current_prio : NULL);
440 if (r < 0 && !ERRNO_IS_DEVICE_ABSENT(r))
441 return log_device_debug_errno(dev, r, "Failed to get the current device node priority for '%s': %m", slink);
442
a28d67a9 443 r = stack_directory_update(dev, dirfd, add);
377a83f0 444 if (r < 0)
72a459ad 445 return log_device_debug_errno(dev, r, "Failed to update stack directory for '%s': %m", slink);
a2554ace 446
331aa7aa
YW
447 if (current_id) {
448 const char *id;
449
450 r = device_get_device_id(dev, &id);
451 if (r < 0)
452 return log_device_debug_errno(dev, r, "Failed to get device id: %m");
453
454 if (add) {
455 int prio;
456
457 r = device_get_devlink_priority(dev, &prio);
458 if (r < 0)
459 return log_device_debug_errno(dev, r, "Failed to get devlink priority: %m");
460
461 if (streq(current_id, id)) {
462 if (current_prio <= prio)
463 /* The devlink is ours and already exists, and the new priority is
464 * equal or higher than the previous. Hence, it is not necessary to
465 * recreate it. */
466 return 0;
467
468 /* The devlink priority is downgraded. Another device may have a higher
469 * priority now. Let's find the device node with the highest priority. */
470 } else {
471 if (current_prio >= prio)
472 /* The devlink with equal or higher priority already exists and is
473 * owned by another device. Hence, it is not necessary to recreate it. */
474 return 0;
475
476 /* This device has a higher priority than the current. Let's create the
477 * devlink to our device node. */
478 return node_symlink(dev, NULL, slink);
479 }
480
481 } else {
482 if (!streq(current_id, id))
483 /* The devlink already exists and is owned by another device. Hence, it is
484 * not necessary to recreate it. */
485 return 0;
486
487 /* The current devlink is ours, and the target device will be removed. Hence, we need
488 * to search the device that has the highest priority. and update the devlink. */
489 }
490 } else {
491 /* The requested devlink does not exist, or the target device does not exist and the devlink
9a27ef09 492 * points to a non-existing device. Let's search the device that has the highest priority,
331aa7aa
YW
493 * and update the devlink. */
494 ;
495 }
496
72a459ad 497 r = stack_directory_find_prioritized_devnode(dev, dirfd, add, &devnode);
57a27290
YW
498 if (r < 0)
499 return log_device_debug_errno(dev, r, "Failed to determine device node with the highest priority for '%s': %m", slink);
500 if (r > 0)
501 return node_symlink(dev, devnode, slink);
a33dc87e 502
57a27290 503 log_device_debug(dev, "No reference left for '%s', removing", slink);
30f6dce6 504
57a27290
YW
505 if (unlink(slink) < 0 && errno != ENOENT)
506 log_device_debug_errno(dev, errno, "Failed to remove '%s', ignoring: %m", slink);
30f6dce6 507
57a27290 508 (void) rmdir_parents(slink, "/dev");
1cd4e325 509
57a27290 510 return 0;
24f0605c
KS
511}
512
2f48561e
YW
513static int device_get_devpath_by_devnum(sd_device *dev, char **ret) {
514 const char *subsystem;
515 dev_t devnum;
516 int r;
517
518 assert(dev);
519 assert(ret);
520
521 r = sd_device_get_subsystem(dev, &subsystem);
522 if (r < 0)
523 return r;
524
525 r = sd_device_get_devnum(dev, &devnum);
526 if (r < 0)
527 return r;
528
529 return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
530}
531
532int udev_node_update(sd_device *dev, sd_device *dev_old) {
533 _cleanup_free_ char *filename = NULL;
a2554ace
YW
534 int r;
535
536 assert(dev);
537 assert(dev_old);
538
2f48561e
YW
539 /* update possible left-over symlinks */
540 FOREACH_DEVICE_DEVLINK(dev_old, devlink) {
541 /* check if old link name still belongs to this device */
542 if (device_has_devlink(dev, devlink))
912541b0
KS
543 continue;
544
e7f3b33e 545 log_device_debug(dev,
2f48561e
YW
546 "Removing/updating old device symlink '%s', which is no longer belonging to this device.",
547 devlink);
e7f3b33e 548
2f48561e 549 r = link_update(dev, devlink, /* add = */ false);
7b808295
YW
550 if (r < 0)
551 log_device_warning_errno(dev, r,
2f48561e
YW
552 "Failed to remove/update device symlink '%s', ignoring: %m",
553 devlink);
912541b0 554 }
a2554ace 555
2f48561e
YW
556 /* create/update symlinks, add symlinks to name index */
557 FOREACH_DEVICE_DEVLINK(dev, devlink) {
558 r = link_update(dev, devlink, /* add = */ true);
559 if (r < 0)
560 log_device_warning_errno(dev, r,
561 "Failed to create/update device symlink '%s', ignoring: %m",
562 devlink);
563 }
564
565 r = device_get_devpath_by_devnum(dev, &filename);
566 if (r < 0)
567 return log_device_debug_errno(dev, r, "Failed to get device path: %m");
568
569 /* always add /dev/{block,char}/$major:$minor */
541a463f 570 r = node_symlink(dev, NULL, filename);
2f48561e
YW
571 if (r < 0)
572 return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
573
574 return 0;
575}
576
577int udev_node_remove(sd_device *dev) {
578 _cleanup_free_ char *filename = NULL;
2f48561e
YW
579 int r;
580
581 assert(dev);
582
583 /* remove/update symlinks, remove symlinks from name index */
584 FOREACH_DEVICE_DEVLINK(dev, devlink) {
585 r = link_update(dev, devlink, /* add = */ false);
586 if (r < 0)
587 log_device_warning_errno(dev, r,
588 "Failed to remove/update device symlink '%s', ignoring: %m",
589 devlink);
590 }
591
592 r = device_get_devpath_by_devnum(dev, &filename);
593 if (r < 0)
594 return log_device_debug_errno(dev, r, "Failed to get device path: %m");
595
596 /* remove /dev/{block,char}/$major:$minor */
597 if (unlink(filename) < 0 && errno != ENOENT)
598 return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
599
a2554ace 600 return 0;
24f0605c
KS
601}
602
a782f2a3
YW
603static int udev_node_apply_permissions_impl(
604 sd_device *dev, /* can be NULL, only used for logging. */
605 int node_fd,
606 const char *devnode,
2f48561e
YW
607 bool apply_mac,
608 mode_t mode,
609 uid_t uid,
610 gid_t gid,
611 OrderedHashmap *seclabel_list) {
612
a7fdc6cb 613 bool apply_mode, apply_uid, apply_gid;
a2554ace 614 struct stat stats;
3708c0f4 615 int r;
a2554ace 616
a782f2a3
YW
617 assert(node_fd >= 0);
618 assert(devnode);
912541b0 619
a7fdc6cb
LP
620 if (fstat(node_fd, &stats) < 0)
621 return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode);
622
e5ddfe3e
YW
623 /* If group is set, but mode is not set, "upgrade" mode for the group. */
624 if (mode == MODE_INVALID && gid_is_valid(gid) && gid > 0)
625 mode = 0660;
626
3708c0f4
ZJS
627 apply_mode = mode != MODE_INVALID && (stats.st_mode & 0777) != (mode & 0777);
628 apply_uid = uid_is_valid(uid) && stats.st_uid != uid;
629 apply_gid = gid_is_valid(gid) && stats.st_gid != gid;
630
631 if (apply_mode || apply_uid || apply_gid || apply_mac) {
a2554ace 632 bool selinux = false, smack = false;
d838e145 633 const char *name, *label;
b7e2b764 634
3708c0f4 635 if (apply_mode || apply_uid || apply_gid) {
20f45f4b
YW
636 log_device_debug(dev, "Setting permissions %s, uid=" UID_FMT ", gid=" GID_FMT ", mode=%#o",
637 devnode,
638 uid_is_valid(uid) ? uid : stats.st_uid,
639 gid_is_valid(gid) ? gid : stats.st_gid,
640 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
4b3b5bc7 641
a7fdc6cb 642 r = fchmod_and_chown(node_fd, mode, uid, gid);
4b3b5bc7 643 if (r < 0)
ab54f12b
YW
644 log_device_full_errno(dev, r == -ENOENT ? LOG_DEBUG : LOG_ERR, r,
645 "Failed to set owner/mode of %s to uid=" UID_FMT
646 ", gid=" GID_FMT ", mode=%#o: %m",
647 devnode,
648 uid_is_valid(uid) ? uid : stats.st_uid,
649 gid_is_valid(gid) ? gid : stats.st_gid,
650 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
a2554ace 651 } else
20f45f4b
YW
652 log_device_debug(dev, "Preserve permissions of %s, uid=" UID_FMT ", gid=" GID_FMT ", mode=%#o",
653 devnode,
654 uid_is_valid(uid) ? uid : stats.st_uid,
655 gid_is_valid(gid) ? gid : stats.st_gid,
656 mode != MODE_INVALID ? mode & 0777 : stats.st_mode & 0777);
c26547d6 657
c26547d6 658 /* apply SECLABEL{$module}=$label */
90e74a66 659 ORDERED_HASHMAP_FOREACH_KEY(label, name, seclabel_list) {
a2554ace 660 int q;
c26547d6 661
c26547d6 662 if (streq(name, "selinux")) {
b7e2b764 663 selinux = true;
d53e386d 664
a7fdc6cb 665 q = mac_selinux_apply_fd(node_fd, devnode, label);
a2554ace 666 if (q < 0)
ab54f12b
YW
667 log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
668 "SECLABEL: failed to set SELinux label '%s': %m", label);
463b5dbb 669 else
e0ca42e3 670 log_device_debug(dev, "SECLABEL: set SELinux label '%s'", label);
c26547d6 671
9a4e038c 672 } else if (streq(name, "smack")) {
b7e2b764 673 smack = true;
d53e386d 674
a7fdc6cb 675 q = mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, label);
a2554ace 676 if (q < 0)
ab54f12b
YW
677 log_device_full_errno(dev, q == -ENOENT ? LOG_DEBUG : LOG_ERR, q,
678 "SECLABEL: failed to set SMACK label '%s': %m", label);
c26547d6 679 else
e0ca42e3 680 log_device_debug(dev, "SECLABEL: set SMACK label '%s'", label);
c26547d6
KS
681
682 } else
e0ca42e3 683 log_device_error(dev, "SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label);
c26547d6 684 }
b7e2b764
KS
685
686 /* set the defaults */
687 if (!selinux)
03bc11d1 688 (void) mac_selinux_fix_full(node_fd, NULL, devnode, LABEL_IGNORE_ENOENT);
9a4e038c 689 if (!smack)
a7fdc6cb 690 (void) mac_smack_apply_fd(node_fd, SMACK_ATTR_ACCESS, NULL);
48a849ee 691 }
912541b0
KS
692
693 /* always update timestamp when we re-use the node, like on media change events */
a7fdc6cb
LP
694 r = futimens_opath(node_fd, NULL);
695 if (r < 0)
696 log_device_debug_errno(dev, r, "Failed to adjust timestamp of node %s: %m", devnode);
a2554ace 697
a2554ace 698 return 0;
ea733a2f 699}
a782f2a3
YW
700
701int udev_node_apply_permissions(
702 sd_device *dev,
703 bool apply_mac,
704 mode_t mode,
705 uid_t uid,
706 gid_t gid,
707 OrderedHashmap *seclabel_list) {
708
709 const char *devnode;
254d1313 710 _cleanup_close_ int node_fd = -EBADF;
a782f2a3
YW
711 int r;
712
713 assert(dev);
714
715 r = sd_device_get_devname(dev, &devnode);
716 if (r < 0)
717 return log_device_debug_errno(dev, r, "Failed to get devname: %m");
718
719 node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC);
720 if (node_fd < 0) {
721 if (ERRNO_IS_DEVICE_ABSENT(node_fd)) {
722 log_device_debug_errno(dev, node_fd, "Device node %s is missing, skipping handling.", devnode);
723 return 0; /* This is necessarily racey, so ignore missing the device */
724 }
725
726 return log_device_debug_errno(dev, node_fd, "Cannot open node %s: %m", devnode);
727 }
728
729 return udev_node_apply_permissions_impl(dev, node_fd, devnode, apply_mac, mode, uid, gid, seclabel_list);
730}
26dd37f6
YW
731
732int static_node_apply_permissions(
733 const char *name,
734 mode_t mode,
735 uid_t uid,
736 gid_t gid,
737 char **tags) {
738
739 _cleanup_free_ char *unescaped_filename = NULL;
254d1313 740 _cleanup_close_ int node_fd = -EBADF;
26dd37f6
YW
741 const char *devnode;
742 struct stat stats;
743 int r;
744
745 assert(name);
746
747 if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID && !tags)
748 return 0;
749
750 devnode = strjoina("/dev/", name);
751
752 node_fd = open(devnode, O_PATH|O_CLOEXEC);
753 if (node_fd < 0) {
754 if (errno != ENOENT)
755 return log_error_errno(errno, "Failed to open %s: %m", devnode);
756 return 0;
757 }
758
759 if (fstat(node_fd, &stats) < 0)
760 return log_error_errno(errno, "Failed to stat %s: %m", devnode);
761
762 if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) {
763 log_warning("%s is neither block nor character device, ignoring.", devnode);
764 return 0;
765 }
766
767 if (!strv_isempty(tags)) {
768 unescaped_filename = xescape(name, "/.");
769 if (!unescaped_filename)
770 return log_oom();
771 }
772
773 /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */
774 STRV_FOREACH(t, tags) {
775 _cleanup_free_ char *p = NULL;
776
777 p = path_join("/run/udev/static_node-tags/", *t, unescaped_filename);
778 if (!p)
779 return log_oom();
780
781 r = mkdir_parents(p, 0755);
782 if (r < 0)
783 return log_error_errno(r, "Failed to create parent directory for %s: %m", p);
784
785 r = symlink(devnode, p);
786 if (r < 0 && errno != EEXIST)
787 return log_error_errno(errno, "Failed to create symlink %s -> %s: %m", p, devnode);
788 }
789
790 return udev_node_apply_permissions_impl(NULL, node_fd, devnode, false, mode, uid, gid, NULL);
791}