mirror of
https://github.com/systemd/systemd.git
synced 2024-10-31 16:21:26 +03:00
Merge pull request #19796 from yuwata/udev-node-cleanups
udev: several cleanups about creating device symlink
This commit is contained in:
commit
16f9036471
@ -19,7 +19,6 @@
|
||||
#include "btrfs-util.h"
|
||||
#include "chattr-util.h"
|
||||
#include "copy.h"
|
||||
#include "device-nodes.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
|
@ -1,16 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "stdio-util.h"
|
||||
|
||||
int encode_devnode_name(const char *str, char *str_enc, size_t len);
|
||||
int allow_listed_char_for_devnode(char c, const char *additional);
|
||||
|
||||
#define DEV_NUM_PATH_MAX \
|
||||
(STRLEN("/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t))
|
||||
#define xsprintf_dev_num_path(buf, type, devno) \
|
||||
xsprintf(buf, "/dev/%s/%u:%u", type, major(devno), minor(devno))
|
@ -526,6 +526,16 @@ char base64char(int x) {
|
||||
return table[x & 63];
|
||||
}
|
||||
|
||||
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet,
|
||||
* since we don't want "/" appear in interface names (since interfaces appear in sysfs as filenames).
|
||||
* See section #5 of RFC 4648. */
|
||||
char urlsafe_base64char(int x) {
|
||||
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-_";
|
||||
return table[x & 63];
|
||||
}
|
||||
|
||||
int unbase64char(char c) {
|
||||
unsigned offset;
|
||||
|
||||
|
@ -27,6 +27,7 @@ char base32hexchar(int x) _const_;
|
||||
int unbase32hexchar(char c) _const_;
|
||||
|
||||
char base64char(int x) _const_;
|
||||
char urlsafe_base64char(int x) _const_;
|
||||
int unbase64char(char c) _const_;
|
||||
|
||||
char *base32hexmem(const void *p, size_t l, bool padding);
|
||||
|
@ -38,8 +38,6 @@ basic_sources = files('''
|
||||
creds-util.c
|
||||
creds-util.h
|
||||
def.h
|
||||
device-nodes.c
|
||||
device-nodes.h
|
||||
dirent-util.c
|
||||
dirent-util.h
|
||||
dlfcn-util.c
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "lockfile-util.h"
|
||||
#include "missing_network.h"
|
||||
#include "netif-naming-scheme.h"
|
||||
@ -200,16 +201,6 @@ static int add_veth(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet, since we
|
||||
* don't want "/" appear in interface names (since interfaces appear in sysfs as filenames). See section #5
|
||||
* of RFC 4648. */
|
||||
static char urlsafe_base64char(int x) {
|
||||
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-_";
|
||||
return table[x & 63];
|
||||
}
|
||||
|
||||
static int shorten_ifname(char *ifname) {
|
||||
char new_ifname[IFNAMSIZ];
|
||||
|
||||
|
7
src/shared/device-nodes.h
Normal file
7
src/shared/device-nodes.h
Normal file
@ -0,0 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
int encode_devnode_name(const char *str, char *str_enc, size_t len);
|
||||
int allow_listed_char_for_devnode(char c, const char *additional);
|
@ -80,6 +80,8 @@ shared_sources = files('''
|
||||
daemon-util.h
|
||||
dev-setup.c
|
||||
dev-setup.h
|
||||
device-nodes.c
|
||||
device-nodes.h
|
||||
devnode-acl.h
|
||||
discover-image.c
|
||||
discover-image.h
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-nodes.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
/* helpers for test_encode_devnode_name */
|
||||
static char *do_encode_string(const char *in) {
|
||||
|
@ -200,6 +200,12 @@ tests += [
|
||||
[threads,
|
||||
libacl]],
|
||||
|
||||
[['src/udev/test-udev-node.c'],
|
||||
[libudevd_core,
|
||||
libshared],
|
||||
[threads,
|
||||
libacl]],
|
||||
|
||||
[['src/udev/test-udev-builtin.c'],
|
||||
[libudevd_core,
|
||||
libshared],
|
||||
|
44
src/udev/test-udev-node.c
Normal file
44
src/udev/test-udev-node.c
Normal file
@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "tests.h"
|
||||
#include "udev-node.h"
|
||||
|
||||
static void test_udev_node_escape_path_one(const char *path, const char *expected) {
|
||||
char buf[NAME_MAX+1];
|
||||
size_t r;
|
||||
|
||||
r = udev_node_escape_path(path, buf, sizeof buf);
|
||||
log_debug("udev_node_escape_path(%s) -> %s (expected: %s)", path, buf, expected);
|
||||
assert_se(r == strlen(expected));
|
||||
assert_se(streq(buf, expected));
|
||||
}
|
||||
|
||||
static void test_udev_node_escape_path(void) {
|
||||
char a[NAME_MAX+1], b[NAME_MAX+1];
|
||||
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-eui.1922908022470001001b448b44ccb9d6", "\\x2fdisk\\x2fby-id\\x2fnvme-eui.1922908022470001001b448b44ccb9d6");
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-eui.1922908022470001001b448b44ccb9d6-part1", "\\x2fdisk\\x2fby-id\\x2fnvme-eui.1922908022470001001b448b44ccb9d6-part1");
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-eui.1922908022470001001b448b44ccb9d6-part2", "\\x2fdisk\\x2fby-id\\x2fnvme-eui.1922908022470001001b448b44ccb9d6-part2");
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247", "\\x2fdisk\\x2fby-id\\x2fnvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247");
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247-part1", "\\x2fdisk\\x2fby-id\\x2fnvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247-part1");
|
||||
test_udev_node_escape_path_one("/disk/by-id/nvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247-part2", "\\x2fdisk\\x2fby-id\\x2fnvme-WDC_PC_SN720_SDAQNTW-512G-1001_192290802247-part2");
|
||||
test_udev_node_escape_path_one("/disk/by-id/usb-Generic-_SD_MMC_20120501030900000-0:0", "\\x2fdisk\\x2fby-id\\x2fusb-Generic-_SD_MMC_20120501030900000-0:0");
|
||||
|
||||
memset(a, 'a', sizeof(a) - 1);
|
||||
memcpy(a, "/disk/by-id/", strlen("/disk/by-id/"));
|
||||
char_array_0(a);
|
||||
|
||||
memset(b, 'a', sizeof(b) - 1);
|
||||
memcpy(b, "\\x2fdisk\\x2fby-id\\x2f", strlen("\\x2fdisk\\x2fby-id\\x2f"));
|
||||
strcpy(b + sizeof(b) - 12, "N3YhcCqFeID");
|
||||
|
||||
test_udev_node_escape_path_one(a, b);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_INFO);
|
||||
|
||||
test_udev_node_escape_path();
|
||||
|
||||
return 0;
|
||||
}
|
@ -7,14 +7,16 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-nodes.h"
|
||||
#include "device-private.h"
|
||||
#include "device-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "mkdir.h"
|
||||
#include "path-util.h"
|
||||
#include "selinux-util.h"
|
||||
@ -26,7 +28,36 @@
|
||||
#include "udev-node.h"
|
||||
#include "user-util.h"
|
||||
|
||||
#define CREATE_LINK_MAX_RETRIES 128
|
||||
#define LINK_UPDATE_MAX_RETRIES 128
|
||||
#define TOUCH_FILE_MAX_RETRIES 128
|
||||
#define UDEV_NODE_HASH_KEY SD_ID128_MAKE(b9,6a,f1,ce,40,31,44,1a,9e,19,ec,8b,ae,f3,e3,2f)
|
||||
|
||||
static int create_symlink(const char *target, const char *slink) {
|
||||
int r;
|
||||
|
||||
assert(target);
|
||||
assert(slink);
|
||||
|
||||
for (unsigned i = 0; i < CREATE_LINK_MAX_RETRIES; i++) {
|
||||
r = mkdir_parents_label(slink, 0755);
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
mac_selinux_create_file_prepare(slink, S_IFLNK);
|
||||
if (symlink(target, slink) < 0)
|
||||
r = -errno;
|
||||
else
|
||||
r = 0;
|
||||
mac_selinux_create_file_clear();
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int node_symlink(sd_device *dev, const char *node, const char *slink) {
|
||||
_cleanup_free_ char *slink_dirname = NULL, *target = NULL;
|
||||
@ -38,87 +69,80 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) {
|
||||
assert(node);
|
||||
assert(slink);
|
||||
|
||||
slink_dirname = dirname_malloc(slink);
|
||||
if (!slink_dirname)
|
||||
return log_oom();
|
||||
r = path_extract_directory(slink, &slink_dirname);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to get parent directory of '%s': %m", slink);
|
||||
|
||||
/* use relative link */
|
||||
r = path_make_relative(slink_dirname, node, &target);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
|
||||
return log_device_debug_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node);
|
||||
|
||||
/* preserve link with correct target, do not replace node of other device */
|
||||
if (lstat(slink, &stats) == 0) {
|
||||
if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode))
|
||||
return log_device_error_errno(dev, SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"Conflicting device node '%s' found, link to '%s' will not be created.", slink, node);
|
||||
else if (S_ISLNK(stats.st_mode)) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
if (lstat(slink, &stats) >= 0) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
||||
if (!S_ISLNK(stats.st_mode))
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST),
|
||||
"Conflicting inode '%s' found, link to '%s' will not be created.", slink, node);
|
||||
|
||||
if (readlink_malloc(slink, &buf) >= 0 &&
|
||||
path_equal(target, buf)) {
|
||||
/* preserve link with correct target, do not replace node of other device */
|
||||
log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
|
||||
|
||||
(void) label_fix(slink, LABEL_IGNORE_ENOENT);
|
||||
(void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
if (readlink_malloc(slink, &buf) >= 0 &&
|
||||
streq(target, buf)) {
|
||||
log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target);
|
||||
(void) label_fix(slink, LABEL_IGNORE_ENOENT);
|
||||
(void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
|
||||
do {
|
||||
r = mkdir_parents_label(slink, 0755);
|
||||
if (!IN_SET(r, 0, -ENOENT))
|
||||
break;
|
||||
mac_selinux_create_file_prepare(slink, S_IFLNK);
|
||||
if (symlink(target, slink) < 0)
|
||||
r = -errno;
|
||||
mac_selinux_create_file_clear();
|
||||
} while (r == -ENOENT);
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
|
||||
}
|
||||
}
|
||||
} else if (errno == ENOENT) {
|
||||
log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target);
|
||||
|
||||
r = create_symlink(target, slink);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
|
||||
log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink);
|
||||
} else
|
||||
return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink);
|
||||
|
||||
log_device_debug(dev, "Atomically replace '%s'", slink);
|
||||
|
||||
r = device_get_device_id(dev, &id);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to get device id: %m");
|
||||
return log_device_debug_errno(dev, r, "Failed to get device id: %m");
|
||||
slink_tmp = strjoina(slink, ".tmp-", id);
|
||||
|
||||
(void) unlink(slink_tmp);
|
||||
do {
|
||||
r = mkdir_parents_label(slink_tmp, 0755);
|
||||
if (!IN_SET(r, 0, -ENOENT))
|
||||
break;
|
||||
mac_selinux_create_file_prepare(slink_tmp, S_IFLNK);
|
||||
if (symlink(target, slink_tmp) < 0)
|
||||
r = -errno;
|
||||
mac_selinux_create_file_clear();
|
||||
} while (r == -ENOENT);
|
||||
|
||||
r = create_symlink(target, slink_tmp);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target);
|
||||
return log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s': %m", slink_tmp, target);
|
||||
|
||||
if (rename(slink_tmp, slink) < 0) {
|
||||
r = log_device_error_errno(dev, errno, "Failed to rename '%s' to '%s': %m", slink_tmp, slink);
|
||||
r = log_device_debug_errno(dev, errno, "Failed to rename '%s' to '%s': %m", slink_tmp, slink);
|
||||
(void) unlink(slink_tmp);
|
||||
} else
|
||||
/* Tell caller that we replaced already existing symlink. */
|
||||
r = 1;
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
/* Tell caller that we replaced already existing symlink. */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find device node of device with highest priority */
|
||||
static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) {
|
||||
_cleanup_closedir_ DIR *dir = NULL;
|
||||
_cleanup_free_ char *target = NULL;
|
||||
struct dirent *dent;
|
||||
int r, priority = 0;
|
||||
const char *id;
|
||||
|
||||
assert(!add || dev);
|
||||
assert(dev);
|
||||
assert(stackdir);
|
||||
assert(ret);
|
||||
|
||||
/* Find device node of device with highest priority. This returns 1 if a device found, 0 if no
|
||||
* device found, or a negative errno. */
|
||||
|
||||
if (add) {
|
||||
const char *devnode;
|
||||
|
||||
@ -137,17 +161,21 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
|
||||
|
||||
dir = opendir(stackdir);
|
||||
if (!dir) {
|
||||
if (target) {
|
||||
if (errno == ENOENT) {
|
||||
*ret = TAKE_PTR(target);
|
||||
return 0;
|
||||
return !!*ret;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
r = device_get_device_id(dev, &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
FOREACH_DIRENT_ALL(dent, dir, break) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
|
||||
const char *devnode, *id;
|
||||
const char *devnode;
|
||||
int db_prio = 0;
|
||||
|
||||
if (dent->d_name[0] == '\0')
|
||||
@ -157,9 +185,6 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
|
||||
|
||||
log_device_debug(dev, "Found '%s' claiming '%s'", dent->d_name, stackdir);
|
||||
|
||||
if (device_get_device_id(dev, &id) < 0)
|
||||
continue;
|
||||
|
||||
/* did we find ourself? */
|
||||
if (streq(dent->d_name, id))
|
||||
continue;
|
||||
@ -184,59 +209,73 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir,
|
||||
priority = db_prio;
|
||||
}
|
||||
|
||||
if (!target)
|
||||
return -ENOENT;
|
||||
|
||||
*ret = TAKE_PTR(target);
|
||||
return 0;
|
||||
return !!*ret;
|
||||
}
|
||||
|
||||
static size_t escape_path(const char *src, char *dest, size_t size) {
|
||||
size_t udev_node_escape_path(const char *src, char *dest, size_t size) {
|
||||
size_t i, j;
|
||||
uint64_t h;
|
||||
|
||||
assert(src);
|
||||
assert(dest);
|
||||
|
||||
for (i = 0, j = 0; src[i] != '\0'; i++) {
|
||||
if (src[i] == '/') {
|
||||
if (j+4 >= size) {
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
if (j+4 >= size)
|
||||
goto toolong;
|
||||
memcpy(&dest[j], "\\x2f", 4);
|
||||
j += 4;
|
||||
} else if (src[i] == '\\') {
|
||||
if (j+4 >= size) {
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
if (j+4 >= size)
|
||||
goto toolong;
|
||||
memcpy(&dest[j], "\\x5c", 4);
|
||||
j += 4;
|
||||
} else {
|
||||
if (j+1 >= size) {
|
||||
j = 0;
|
||||
break;
|
||||
}
|
||||
if (j+1 >= size)
|
||||
goto toolong;
|
||||
dest[j] = src[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
dest[j] = '\0';
|
||||
return j;
|
||||
|
||||
toolong:
|
||||
/* If the input path is too long to encode as a filename, then let's suffix with a string
|
||||
* generated from the hash of the path. */
|
||||
|
||||
h = siphash24_string(src, UDEV_NODE_HASH_KEY.bytes);
|
||||
|
||||
assert(size >= 12);
|
||||
|
||||
for (unsigned k = 0; k <= 10; k++)
|
||||
dest[size - k - 2] = urlsafe_base64char((h >> (k * 6)) & 63);
|
||||
|
||||
dest[size - 1] = '\0';
|
||||
return size - 1;
|
||||
}
|
||||
|
||||
/* manage "stack of names" with possibly specified device priorities */
|
||||
static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||
_cleanup_free_ char *filename = NULL, *dirname = NULL;
|
||||
static int link_update(sd_device *dev, const char *slink_in, bool add) {
|
||||
_cleanup_free_ char *slink = NULL, *filename = NULL, *dirname = NULL;
|
||||
const char *slink_name, *id;
|
||||
char name_enc[PATH_MAX];
|
||||
char name_enc[NAME_MAX+1];
|
||||
int i, r, retries;
|
||||
|
||||
assert(dev);
|
||||
assert(slink);
|
||||
assert(slink_in);
|
||||
|
||||
slink = strdup(slink_in);
|
||||
if (!slink)
|
||||
return log_oom_debug();
|
||||
|
||||
path_simplify(slink);
|
||||
|
||||
slink_name = path_startswith(slink, "/dev");
|
||||
if (!slink_name)
|
||||
if (!slink_name ||
|
||||
empty_or_root(slink_name) ||
|
||||
!path_is_normalized(slink_name))
|
||||
return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Invalid symbolic link of device node: %s", slink);
|
||||
|
||||
@ -244,31 +283,31 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to get device id: %m");
|
||||
|
||||
escape_path(slink_name, name_enc, sizeof(name_enc));
|
||||
(void) udev_node_escape_path(slink_name, name_enc, sizeof(name_enc));
|
||||
dirname = path_join("/run/udev/links/", name_enc);
|
||||
if (!dirname)
|
||||
return log_oom();
|
||||
return log_oom_debug();
|
||||
|
||||
filename = path_join(dirname, id);
|
||||
if (!filename)
|
||||
return log_oom();
|
||||
return log_oom_debug();
|
||||
|
||||
if (!add) {
|
||||
if (unlink(filename) == 0)
|
||||
(void) rmdir(dirname);
|
||||
} else
|
||||
for (;;) {
|
||||
_cleanup_close_ int fd = -1;
|
||||
if (unlink(filename) < 0 && errno != ENOENT)
|
||||
log_device_debug_errno(dev, errno, "Failed to remove %s, ignoring: %m", filename);
|
||||
|
||||
r = mkdir_parents(filename, 0755);
|
||||
if (!IN_SET(r, 0, -ENOENT))
|
||||
return r;
|
||||
|
||||
fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
|
||||
if (fd >= 0)
|
||||
(void) rmdir(dirname);
|
||||
} else {
|
||||
for (unsigned j = 0; j < TOUCH_FILE_MAX_RETRIES; j++) {
|
||||
/* This may fail with -ENOENT when the parent directory is removed during
|
||||
* creating the file by another udevd worker. */
|
||||
r = touch_file(filename, /* parents= */ true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0444);
|
||||
if (r != -ENOENT)
|
||||
break;
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to create %s: %m", filename);
|
||||
}
|
||||
|
||||
/* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
|
||||
* will be fixed in the second invocation. */
|
||||
@ -280,23 +319,25 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||
|
||||
r = stat(dirname, &st1);
|
||||
if (r < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
|
||||
|
||||
r = link_find_prioritized(dev, add, dirname, &target);
|
||||
if (r == -ENOENT) {
|
||||
log_device_debug(dev, "No reference left, removing '%s'", slink);
|
||||
if (unlink(slink) == 0)
|
||||
(void) rmdir_parents(slink, "/");
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to determine highest priority for symlink '%s': %m", slink);
|
||||
if (r == 0) {
|
||||
log_device_debug(dev, "No reference left for '%s', removing", slink);
|
||||
|
||||
if (unlink(slink) < 0 && errno != ENOENT)
|
||||
log_device_debug_errno(dev, errno, "Failed to remove '%s', ignoring: %m", slink);
|
||||
|
||||
(void) rmdir_parents(slink, "/dev");
|
||||
break;
|
||||
} else if (r < 0)
|
||||
return log_device_error_errno(dev, r, "Failed to determine highest priority symlink: %m");
|
||||
}
|
||||
|
||||
r = node_symlink(dev, target, slink);
|
||||
if (r < 0) {
|
||||
(void) unlink(filename);
|
||||
break;
|
||||
} else if (r == 1)
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 1)
|
||||
/* We have replaced already existing symlink, possibly there is some other device trying
|
||||
* to claim the same symlink. Let's do one more iteration to give us a chance to fix
|
||||
* the error if other device actually claims the symlink with higher priority. */
|
||||
@ -306,7 +347,7 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||
if ((st1.st_mode & S_IFMT) != 0) {
|
||||
r = stat(dirname, &st2);
|
||||
if (r < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
return log_device_debug_errno(dev, errno, "Failed to stat %s: %m", dirname);
|
||||
|
||||
if (stat_inode_unmodified(&st1, &st2))
|
||||
break;
|
||||
@ -317,16 +358,12 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
|
||||
}
|
||||
|
||||
int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
|
||||
const char *name, *devpath;
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(dev);
|
||||
assert(dev_old);
|
||||
|
||||
r = sd_device_get_devpath(dev, &devpath);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to get devpath: %m");
|
||||
|
||||
/* update possible left-over symlinks */
|
||||
FOREACH_DEVICE_DEVLINK(dev_old, name) {
|
||||
const char *name_current;
|
||||
@ -342,8 +379,10 @@ int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
log_device_debug(dev, "Updating old name, '%s' no longer belonging to '%s'",
|
||||
name, devpath);
|
||||
log_device_debug(dev,
|
||||
"Updating old device symlink '%s', which is no longer belonging to this device.",
|
||||
name);
|
||||
|
||||
r = link_update(dev, name, false);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(dev, r,
|
||||
@ -477,7 +516,6 @@ static int node_permissions_apply(sd_device *dev, bool apply_mac,
|
||||
}
|
||||
|
||||
static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
|
||||
char filename[DEV_NUM_PATH_MAX], *s;
|
||||
const char *subsystem;
|
||||
dev_t devnum;
|
||||
int r;
|
||||
@ -492,16 +530,7 @@ static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
xsprintf_dev_num_path(filename,
|
||||
streq(subsystem, "block") ? "block" : "char",
|
||||
devnum);
|
||||
|
||||
s = strdup(filename);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = s;
|
||||
return 0;
|
||||
return device_path_make_major_minor(streq(subsystem, "block") ? S_IFBLK : S_IFCHR, devnum, ret);
|
||||
}
|
||||
|
||||
int udev_node_add(sd_device *dev, bool apply,
|
||||
@ -528,13 +557,6 @@ int udev_node_add(sd_device *dev, bool apply,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to get device path: %m");
|
||||
|
||||
/* always add /dev/{block,char}/$major:$minor */
|
||||
(void) node_symlink(dev, devnode, filename);
|
||||
|
||||
/* create/update symlinks, add symlinks to name index */
|
||||
FOREACH_DEVICE_DEVLINK(dev, devlink) {
|
||||
r = link_update(dev, devlink, true);
|
||||
@ -544,6 +566,15 @@ int udev_node_add(sd_device *dev, bool apply,
|
||||
devlink);
|
||||
}
|
||||
|
||||
r = xsprintf_dev_num_path_from_sd_device(dev, &filename);
|
||||
if (r < 0)
|
||||
return log_device_debug_errno(dev, r, "Failed to get device path: %m");
|
||||
|
||||
/* always add /dev/{block,char}/$major:$minor */
|
||||
r = node_symlink(dev, devnode, filename);
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(dev, r, "Failed to create device symlink '%s': %m", filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -568,7 +599,8 @@ int udev_node_remove(sd_device *dev) {
|
||||
return log_device_debug_errno(dev, r, "Failed to get device path: %m");
|
||||
|
||||
/* remove /dev/{block,char}/$major:$minor */
|
||||
(void) unlink(filename);
|
||||
if (unlink(filename) < 0 && errno != ENOENT)
|
||||
return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -13,3 +13,5 @@ int udev_node_add(sd_device *dev, bool apply,
|
||||
OrderedHashmap *seclabel_list);
|
||||
int udev_node_remove(sd_device *dev);
|
||||
int udev_node_update_old_links(sd_device *dev, sd_device *dev_old);
|
||||
|
||||
size_t udev_node_escape_path(const char *src, char *dest, size_t size);
|
||||
|
Loading…
Reference in New Issue
Block a user