int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) { const char *name, *devpath; 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; bool found = false; /* check if old link name still belongs to this device */ FOREACH_DEVICE_DEVLINK(dev, name_current) if (streq(name, name_current)) { found = true; break; } if (found) continue; log_device_debug(dev, "Updating old name, '%s' no longer belonging to '%s'", name, devpath); link_update(dev, name, false); } return 0; }
static int builtin_net_setup_link(sd_device *dev, int argc, char **argv, bool test) { _cleanup_free_ char *driver = NULL; const char *name = NULL; link_config *link; int r; if (argc > 1) return log_device_error_errno(dev, EINVAL, "This program takes no arguments."); r = link_get_driver(ctx, dev, &driver); if (r >= 0) udev_builtin_add_property(dev, test, "ID_NET_DRIVER", driver); r = link_config_get(ctx, dev, &link); if (r < 0) { if (r == -ENOENT) return log_device_debug_errno(dev, r, "No matching link configuration found."); return log_device_error_errno(dev, r, "Failed to get link config: %m"); } r = link_config_apply(ctx, link, dev, &name); if (r < 0) log_device_warning_errno(dev, r, "Could not apply link config, ignoring: %m"); udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->filename); if (name) udev_builtin_add_property(dev, test, "ID_NET_NAME", name); return 0; }
static int builtin_btrfs(sd_device *dev, int argc, char *argv[], bool test) { struct btrfs_ioctl_vol_args args = {}; _cleanup_close_ int fd = -1; int r; if (argc != 3 || !streq(argv[1], "ready")) return log_device_error_errno(dev, EINVAL, "Invalid arguments"); fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); if (fd < 0) return log_device_debug_errno(dev, errno, "Failed to open /dev/btrfs-control: %m"); strscpy(args.name, sizeof(args.name), argv[2]); r = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); if (r < 0) return log_device_debug_errno(dev, errno, "Failed to call BTRFS_IOC_DEVICES_READY: %m"); udev_builtin_add_property(dev, test, "ID_BTRFS_READY", one_zero(r == 0)); return 0; }
/* manage "stack of names" with possibly specified device priorities */ static int link_update(sd_device *dev, const char *slink, bool add) { _cleanup_free_ char *target = NULL, *filename = NULL, *dirname = NULL; char name_enc[PATH_MAX]; const char *id_filename; int r; assert(dev); assert(slink); r = device_get_id_filename(dev, &id_filename); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get id_filename: %m"); util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); dirname = path_join("/run/udev/links/", name_enc); if (!dirname) return log_oom(); filename = path_join(dirname, id_filename); if (!filename) return log_oom(); if (!add && unlink(filename) == 0) (void) rmdir(dirname); r = link_find_prioritized(dev, add, dirname, &target); if (r < 0) { log_device_debug(dev, "No reference left, removing '%s'", slink); if (unlink(slink) == 0) (void) rmdir_parents(slink, "/"); } else (void) node_symlink(dev, target, slink); if (add) do { _cleanup_close_ int fd = -1; r = mkdir_parents(filename, 0755); if (!IN_SET(r, 0, -ENOENT)) break; fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); if (fd < 0) r = -errno; } while (r == -ENOENT); return r; }
static int node_symlink(sd_device *dev, const char *node, const char *slink) { _cleanup_free_ char *slink_dirname = NULL, *target = NULL; const char *id_filename, *slink_tmp; struct stat stats; int r; assert(dev); assert(node); assert(slink); slink_dirname = dirname_malloc(slink); if (!slink_dirname) return log_oom(); /* 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); /* 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)) { log_device_error(dev, "Conflicting device node '%s' found, link to '%s' will not be created.", slink, node); return -EOPNOTSUPP; } else if (S_ISLNK(stats.st_mode)) { _cleanup_free_ char *buf = NULL; 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); } log_device_debug(dev, "Atomically replace '%s'", slink); r = device_get_id_filename(dev, &id_filename); if (r < 0) return log_device_error_errno(dev, r, "Failed to get id_filename: %m"); slink_tmp = strjoina(slink, ".tmp-", id_filename); (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); if (r < 0) return log_device_error_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' failed: %m", slink_tmp, slink); (void) unlink(slink_tmp); } return r; }
static int node_permissions_apply(sd_device *dev, bool apply, mode_t mode, uid_t uid, gid_t gid, Hashmap *seclabel_list) { const char *devnode, *subsystem, *id_filename = NULL; struct stat stats; dev_t devnum; int r = 0; assert(dev); r = sd_device_get_devname(dev, &devnode); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get devname: %m"); r = sd_device_get_subsystem(dev, &subsystem); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get subsystem: %m"); r = sd_device_get_devnum(dev, &devnum); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get devnum: %m"); (void) device_get_id_filename(dev, &id_filename); if (streq(subsystem, "block")) mode |= S_IFBLK; else mode |= S_IFCHR; if (lstat(devnode, &stats) < 0) return log_device_debug_errno(dev, errno, "cannot stat() node '%s' (%m)", devnode); if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) return log_device_debug_errno(dev, EEXIST, "Found node '%s' with non-matching devnum %s, skip handling", devnode, id_filename); if (apply) { bool selinux = false, smack = false; const char *name, *label; Iterator i; if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { log_device_debug(dev, "Setting permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); if (chmod(devnode, mode) < 0) r = log_device_warning_errno(dev, errno, "Failed to set mode of %s to %#o: %m", devnode, mode); if (chown(devnode, uid, gid) < 0) r = log_device_warning_errno(dev, errno, "Failed to set owner of %s to uid=%u, gid=%u: %m", devnode, uid, gid); } else log_device_debug(dev, "Preserve permissions of %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); /* apply SECLABEL{$module}=$label */ HASHMAP_FOREACH_KEY(label, name, seclabel_list, i) { int q; if (streq(name, "selinux")) { selinux = true; q = mac_selinux_apply(devnode, label); if (q < 0) log_device_error_errno(dev, q, "SECLABEL: failed to set SELinux label '%s': %m", label); else log_device_debug(dev, "SECLABEL: set SELinux label '%s'", label); } else if (streq(name, "smack")) { smack = true; q = mac_smack_apply(devnode, SMACK_ATTR_ACCESS, label); if (q < 0) log_device_error_errno(dev, q, "SECLABEL: failed to set SMACK label '%s': %m", label); else log_device_debug(dev, "SECLABEL: set SMACK label '%s'", label); } else log_device_error(dev, "SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label); } /* set the defaults */ if (!selinux) (void) mac_selinux_fix(devnode, LABEL_IGNORE_ENOENT); if (!smack) (void) mac_smack_apply(devnode, SMACK_ATTR_ACCESS, NULL); }
static int device_amend(sd_device *device, const char *key, const char *value) { int r; assert(device); assert(key); assert(value); if (streq(key, "DEVPATH")) { char *path; path = strjoina("/sys", value); /* the caller must verify or trust this data (e.g., if it comes from the kernel) */ r = device_set_syspath(device, path, false); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set syspath to '%s': %m", path); } else if (streq(key, "SUBSYSTEM")) { r = device_set_subsystem(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set subsystem to '%s': %m", value); } else if (streq(key, "DEVTYPE")) { r = device_set_devtype(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set devtype to '%s': %m", value); } else if (streq(key, "DEVNAME")) { r = device_set_devname(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set devname to '%s': %m", value); } else if (streq(key, "USEC_INITIALIZED")) { usec_t t; r = safe_atou64(value, &t); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to parse timestamp '%s': %m", value); r = device_set_usec_initialized(device, t); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set usec-initialized to '%s': %m", value); } else if (streq(key, "DRIVER")) { r = device_set_driver(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set driver to '%s': %m", value); } else if (streq(key, "IFINDEX")) { r = device_set_ifindex(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set ifindex to '%s': %m", value); } else if (streq(key, "DEVMODE")) { r = device_set_devmode(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set devmode to '%s': %m", value); } else if (streq(key, "DEVUID")) { r = device_set_devuid(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set devuid to '%s': %m", value); } else if (streq(key, "DEVGID")) { r = device_set_devgid(device, value); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value); } else if (streq(key, "DEVLINKS")) { const char *word, *state; size_t l; FOREACH_WORD(word, l, value, state) { char devlink[l + 1]; strncpy(devlink, word, l); devlink[l] = '\0'; r = device_add_devlink(device, devlink); if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to add devlink '%s': %m", devlink); } } else if (streq(key, "TAGS")) {