199ca880aSopenharmony_ci/* 299ca880aSopenharmony_ci * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org> 399ca880aSopenharmony_ci * 499ca880aSopenharmony_ci * This program is free software: you can redistribute it and/or modify 599ca880aSopenharmony_ci * it under the terms of the GNU General Public License as published by 699ca880aSopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 799ca880aSopenharmony_ci * (at your option) any later version. 899ca880aSopenharmony_ci * 999ca880aSopenharmony_ci * This program is distributed in the hope that it will be useful, 1099ca880aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1199ca880aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1299ca880aSopenharmony_ci * GNU General Public License for more details. 1399ca880aSopenharmony_ci * 1499ca880aSopenharmony_ci * You should have received a copy of the GNU General Public License 1599ca880aSopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 1699ca880aSopenharmony_ci */ 1799ca880aSopenharmony_ci 1899ca880aSopenharmony_ci#include <stdlib.h> 1999ca880aSopenharmony_ci#include <string.h> 2099ca880aSopenharmony_ci#include <stdio.h> 2199ca880aSopenharmony_ci#include <stddef.h> 2299ca880aSopenharmony_ci#include <stdbool.h> 2399ca880aSopenharmony_ci#include <fcntl.h> 2499ca880aSopenharmony_ci#include <unistd.h> 2599ca880aSopenharmony_ci#include <errno.h> 2699ca880aSopenharmony_ci#include <grp.h> 2799ca880aSopenharmony_ci#include <dirent.h> 2899ca880aSopenharmony_ci#include <sys/time.h> 2999ca880aSopenharmony_ci#include <sys/stat.h> 3099ca880aSopenharmony_ci#include <sys/types.h> 3199ca880aSopenharmony_ci#include <sys/sysmacros.h> 3299ca880aSopenharmony_ci 3399ca880aSopenharmony_ci#include "udev.h" 3499ca880aSopenharmony_ci#include "smack-util.h" 3599ca880aSopenharmony_ci 3699ca880aSopenharmony_cistatic int node_symlink(struct udev_device *dev, const char *node, const char *slink) { 3799ca880aSopenharmony_ci struct stat stats; 3899ca880aSopenharmony_ci char target[UTIL_PATH_SIZE]; 3999ca880aSopenharmony_ci char *s; 4099ca880aSopenharmony_ci size_t l; 4199ca880aSopenharmony_ci char slink_tmp[UTIL_PATH_SIZE + 32]; 4299ca880aSopenharmony_ci int i = 0; 4399ca880aSopenharmony_ci int tail = 0; 4499ca880aSopenharmony_ci int err = 0; 4599ca880aSopenharmony_ci 4699ca880aSopenharmony_ci /* use relative link */ 4799ca880aSopenharmony_ci target[0] = '\0'; 4899ca880aSopenharmony_ci while (node[i] && (node[i] == slink[i])) { 4999ca880aSopenharmony_ci if (node[i] == '/') 5099ca880aSopenharmony_ci tail = i+1; 5199ca880aSopenharmony_ci i++; 5299ca880aSopenharmony_ci } 5399ca880aSopenharmony_ci s = target; 5499ca880aSopenharmony_ci l = sizeof(target); 5599ca880aSopenharmony_ci while (slink[i] != '\0') { 5699ca880aSopenharmony_ci if (slink[i] == '/') 5799ca880aSopenharmony_ci l = strpcpy(&s, l, "../"); 5899ca880aSopenharmony_ci i++; 5999ca880aSopenharmony_ci } 6099ca880aSopenharmony_ci l = strscpy(s, l, &node[tail]); 6199ca880aSopenharmony_ci if (l == 0) { 6299ca880aSopenharmony_ci err = -EINVAL; 6399ca880aSopenharmony_ci goto exit; 6499ca880aSopenharmony_ci } 6599ca880aSopenharmony_ci 6699ca880aSopenharmony_ci /* preserve link with correct target, do not replace node of other device */ 6799ca880aSopenharmony_ci if (lstat(slink, &stats) == 0) { 6899ca880aSopenharmony_ci if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) { 6999ca880aSopenharmony_ci log_error("conflicting device node '%s' found, link to '%s' will not be created", slink, node); 7099ca880aSopenharmony_ci goto exit; 7199ca880aSopenharmony_ci } else if (S_ISLNK(stats.st_mode)) { 7299ca880aSopenharmony_ci char buf[UTIL_PATH_SIZE]; 7399ca880aSopenharmony_ci int len; 7499ca880aSopenharmony_ci 7599ca880aSopenharmony_ci len = readlink(slink, buf, sizeof(buf)); 7699ca880aSopenharmony_ci if (len > 0 && len < (int)sizeof(buf)) { 7799ca880aSopenharmony_ci buf[len] = '\0'; 7899ca880aSopenharmony_ci if (streq(target, buf)) { 7999ca880aSopenharmony_ci log_debug("preserve already existing symlink '%s' to '%s'", slink, target); 8099ca880aSopenharmony_ci label_fix(slink, true, false); 8199ca880aSopenharmony_ci utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); 8299ca880aSopenharmony_ci goto exit; 8399ca880aSopenharmony_ci } 8499ca880aSopenharmony_ci } 8599ca880aSopenharmony_ci } 8699ca880aSopenharmony_ci } else { 8799ca880aSopenharmony_ci log_debug("creating symlink '%s' to '%s'", slink, target); 8899ca880aSopenharmony_ci do { 8999ca880aSopenharmony_ci err = mkdir_parents_label(slink, 0755); 9099ca880aSopenharmony_ci if (err != 0 && err != -ENOENT) 9199ca880aSopenharmony_ci break; 9299ca880aSopenharmony_ci mac_selinux_create_file_prepare(slink, S_IFLNK); 9399ca880aSopenharmony_ci err = symlink(target, slink); 9499ca880aSopenharmony_ci if (err != 0) 9599ca880aSopenharmony_ci err = -errno; 9699ca880aSopenharmony_ci mac_selinux_create_file_clear(); 9799ca880aSopenharmony_ci } while (err == -ENOENT); 9899ca880aSopenharmony_ci if (err == 0) 9999ca880aSopenharmony_ci goto exit; 10099ca880aSopenharmony_ci } 10199ca880aSopenharmony_ci 10299ca880aSopenharmony_ci log_debug("atomically replace '%s'", slink); 10399ca880aSopenharmony_ci strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL); 10499ca880aSopenharmony_ci unlink(slink_tmp); 10599ca880aSopenharmony_ci do { 10699ca880aSopenharmony_ci err = mkdir_parents_label(slink_tmp, 0755); 10799ca880aSopenharmony_ci if (err != 0 && err != -ENOENT) 10899ca880aSopenharmony_ci break; 10999ca880aSopenharmony_ci mac_selinux_create_file_prepare(slink_tmp, S_IFLNK); 11099ca880aSopenharmony_ci err = symlink(target, slink_tmp); 11199ca880aSopenharmony_ci if (err != 0) 11299ca880aSopenharmony_ci err = -errno; 11399ca880aSopenharmony_ci mac_selinux_create_file_clear(); 11499ca880aSopenharmony_ci } while (err == -ENOENT); 11599ca880aSopenharmony_ci if (err != 0) { 11699ca880aSopenharmony_ci log_error_errno(errno, "symlink '%s' '%s' failed: %m", target, slink_tmp); 11799ca880aSopenharmony_ci goto exit; 11899ca880aSopenharmony_ci } 11999ca880aSopenharmony_ci err = rename(slink_tmp, slink); 12099ca880aSopenharmony_ci if (err != 0) { 12199ca880aSopenharmony_ci log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink); 12299ca880aSopenharmony_ci unlink(slink_tmp); 12399ca880aSopenharmony_ci } 12499ca880aSopenharmony_ciexit: 12599ca880aSopenharmony_ci return err; 12699ca880aSopenharmony_ci} 12799ca880aSopenharmony_ci 12899ca880aSopenharmony_ci/* find device node of device with highest priority */ 12999ca880aSopenharmony_cistatic const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) { 13099ca880aSopenharmony_ci struct udev *udev = udev_device_get_udev(dev); 13199ca880aSopenharmony_ci DIR *dir; 13299ca880aSopenharmony_ci int priority = 0; 13399ca880aSopenharmony_ci const char *target = NULL; 13499ca880aSopenharmony_ci 13599ca880aSopenharmony_ci if (add) { 13699ca880aSopenharmony_ci priority = udev_device_get_devlink_priority(dev); 13799ca880aSopenharmony_ci strscpy(buf, bufsize, udev_device_get_devnode(dev)); 13899ca880aSopenharmony_ci target = buf; 13999ca880aSopenharmony_ci } 14099ca880aSopenharmony_ci 14199ca880aSopenharmony_ci dir = opendir(stackdir); 14299ca880aSopenharmony_ci if (dir == NULL) 14399ca880aSopenharmony_ci return target; 14499ca880aSopenharmony_ci for (;;) { 14599ca880aSopenharmony_ci struct udev_device *dev_db; 14699ca880aSopenharmony_ci struct dirent *dent; 14799ca880aSopenharmony_ci 14899ca880aSopenharmony_ci dent = readdir(dir); 14999ca880aSopenharmony_ci if (dent == NULL || dent->d_name[0] == '\0') 15099ca880aSopenharmony_ci break; 15199ca880aSopenharmony_ci if (dent->d_name[0] == '.') 15299ca880aSopenharmony_ci continue; 15399ca880aSopenharmony_ci 15499ca880aSopenharmony_ci log_debug("found '%s' claiming '%s'", dent->d_name, stackdir); 15599ca880aSopenharmony_ci 15699ca880aSopenharmony_ci /* did we find ourself? */ 15799ca880aSopenharmony_ci if (streq(dent->d_name, udev_device_get_id_filename(dev))) 15899ca880aSopenharmony_ci continue; 15999ca880aSopenharmony_ci 16099ca880aSopenharmony_ci dev_db = udev_device_new_from_device_id(udev, dent->d_name); 16199ca880aSopenharmony_ci if (dev_db != NULL) { 16299ca880aSopenharmony_ci const char *devnode; 16399ca880aSopenharmony_ci 16499ca880aSopenharmony_ci devnode = udev_device_get_devnode(dev_db); 16599ca880aSopenharmony_ci if (devnode != NULL) { 16699ca880aSopenharmony_ci if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { 16799ca880aSopenharmony_ci log_debug("'%s' claims priority %i for '%s'", 16899ca880aSopenharmony_ci udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); 16999ca880aSopenharmony_ci priority = udev_device_get_devlink_priority(dev_db); 17099ca880aSopenharmony_ci strscpy(buf, bufsize, devnode); 17199ca880aSopenharmony_ci target = buf; 17299ca880aSopenharmony_ci } 17399ca880aSopenharmony_ci } 17499ca880aSopenharmony_ci udev_device_unref(dev_db); 17599ca880aSopenharmony_ci } 17699ca880aSopenharmony_ci } 17799ca880aSopenharmony_ci closedir(dir); 17899ca880aSopenharmony_ci return target; 17999ca880aSopenharmony_ci} 18099ca880aSopenharmony_ci 18199ca880aSopenharmony_ci/* manage "stack of names" with possibly specified device priorities */ 18299ca880aSopenharmony_cistatic void link_update(struct udev_device *dev, const char *slink, bool add) { 18399ca880aSopenharmony_ci char name_enc[UTIL_PATH_SIZE]; 18499ca880aSopenharmony_ci char filename[UTIL_PATH_SIZE * 2]; 18599ca880aSopenharmony_ci char dirname[UTIL_PATH_SIZE]; 18699ca880aSopenharmony_ci const char *target; 18799ca880aSopenharmony_ci char buf[UTIL_PATH_SIZE]; 18899ca880aSopenharmony_ci 18999ca880aSopenharmony_ci util_path_encode(slink + strlen("/dev"), name_enc, sizeof(name_enc)); 19099ca880aSopenharmony_ci strscpyl(dirname, sizeof(dirname), UDEV_ROOT_RUN "/udev/links/", name_enc, NULL); 19199ca880aSopenharmony_ci strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); 19299ca880aSopenharmony_ci 19399ca880aSopenharmony_ci if (!add && unlink(filename) == 0) 19499ca880aSopenharmony_ci rmdir(dirname); 19599ca880aSopenharmony_ci 19699ca880aSopenharmony_ci target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); 19799ca880aSopenharmony_ci if (target == NULL) { 19899ca880aSopenharmony_ci log_debug("no reference left, remove '%s'", slink); 19999ca880aSopenharmony_ci if (unlink(slink) == 0) 20099ca880aSopenharmony_ci rmdir_parents(slink, "/"); 20199ca880aSopenharmony_ci } else { 20299ca880aSopenharmony_ci log_debug("creating link '%s' to '%s'", slink, target); 20399ca880aSopenharmony_ci node_symlink(dev, target, slink); 20499ca880aSopenharmony_ci } 20599ca880aSopenharmony_ci 20699ca880aSopenharmony_ci if (add) { 20799ca880aSopenharmony_ci int err; 20899ca880aSopenharmony_ci 20999ca880aSopenharmony_ci do { 21099ca880aSopenharmony_ci int fd; 21199ca880aSopenharmony_ci 21299ca880aSopenharmony_ci err = mkdir_parents(filename, 0755); 21399ca880aSopenharmony_ci if (err != 0 && err != -ENOENT) 21499ca880aSopenharmony_ci break; 21599ca880aSopenharmony_ci fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); 21699ca880aSopenharmony_ci if (fd >= 0) 21799ca880aSopenharmony_ci close(fd); 21899ca880aSopenharmony_ci else 21999ca880aSopenharmony_ci err = -errno; 22099ca880aSopenharmony_ci } while (err == -ENOENT); 22199ca880aSopenharmony_ci } 22299ca880aSopenharmony_ci} 22399ca880aSopenharmony_ci 22499ca880aSopenharmony_civoid udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) { 22599ca880aSopenharmony_ci struct udev_list_entry *list_entry; 22699ca880aSopenharmony_ci 22799ca880aSopenharmony_ci /* update possible left-over symlinks */ 22899ca880aSopenharmony_ci udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { 22999ca880aSopenharmony_ci const char *name = udev_list_entry_get_name(list_entry); 23099ca880aSopenharmony_ci struct udev_list_entry *list_entry_current; 23199ca880aSopenharmony_ci int found; 23299ca880aSopenharmony_ci 23399ca880aSopenharmony_ci /* check if old link name still belongs to this device */ 23499ca880aSopenharmony_ci found = 0; 23599ca880aSopenharmony_ci udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { 23699ca880aSopenharmony_ci const char *name_current = udev_list_entry_get_name(list_entry_current); 23799ca880aSopenharmony_ci 23899ca880aSopenharmony_ci if (streq(name, name_current)) { 23999ca880aSopenharmony_ci found = 1; 24099ca880aSopenharmony_ci break; 24199ca880aSopenharmony_ci } 24299ca880aSopenharmony_ci } 24399ca880aSopenharmony_ci if (found) 24499ca880aSopenharmony_ci continue; 24599ca880aSopenharmony_ci 24699ca880aSopenharmony_ci log_debug("update old name, '%s' no longer belonging to '%s'", 24799ca880aSopenharmony_ci name, udev_device_get_devpath(dev)); 24899ca880aSopenharmony_ci link_update(dev, name, false); 24999ca880aSopenharmony_ci } 25099ca880aSopenharmony_ci} 25199ca880aSopenharmony_ci 25299ca880aSopenharmony_cistatic int node_permissions_apply(struct udev_device *dev, bool apply, 25399ca880aSopenharmony_ci mode_t mode, uid_t uid, gid_t gid, 25499ca880aSopenharmony_ci struct udev_list *seclabel_list) { 25599ca880aSopenharmony_ci const char *devnode = udev_device_get_devnode(dev); 25699ca880aSopenharmony_ci dev_t devnum = udev_device_get_devnum(dev); 25799ca880aSopenharmony_ci struct stat stats; 25899ca880aSopenharmony_ci struct udev_list_entry *entry; 25999ca880aSopenharmony_ci int err = 0; 26099ca880aSopenharmony_ci 26199ca880aSopenharmony_ci if (streq(udev_device_get_subsystem(dev), "block")) 26299ca880aSopenharmony_ci mode |= S_IFBLK; 26399ca880aSopenharmony_ci else 26499ca880aSopenharmony_ci mode |= S_IFCHR; 26599ca880aSopenharmony_ci 26699ca880aSopenharmony_ci if (lstat(devnode, &stats) != 0) { 26799ca880aSopenharmony_ci err = -errno; 26899ca880aSopenharmony_ci log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); 26999ca880aSopenharmony_ci goto out; 27099ca880aSopenharmony_ci } 27199ca880aSopenharmony_ci 27299ca880aSopenharmony_ci if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) { 27399ca880aSopenharmony_ci err = -EEXIST; 27499ca880aSopenharmony_ci log_debug("found node '%s' with non-matching devnum %s, skip handling", 27599ca880aSopenharmony_ci udev_device_get_devnode(dev), udev_device_get_id_filename(dev)); 27699ca880aSopenharmony_ci goto out; 27799ca880aSopenharmony_ci } 27899ca880aSopenharmony_ci 27999ca880aSopenharmony_ci if (apply) { 28099ca880aSopenharmony_ci bool selinux = false; 28199ca880aSopenharmony_ci bool smack = false; 28299ca880aSopenharmony_ci 28399ca880aSopenharmony_ci if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) { 28499ca880aSopenharmony_ci log_debug("set permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); 28599ca880aSopenharmony_ci err = chmod(devnode, mode); 28699ca880aSopenharmony_ci if (err < 0) 28799ca880aSopenharmony_ci log_warning_errno(errno, "setting mode of %s to %#o failed: %m", devnode, mode); 28899ca880aSopenharmony_ci err = chown(devnode, uid, gid); 28999ca880aSopenharmony_ci if (err < 0) 29099ca880aSopenharmony_ci log_warning_errno(errno, "setting owner of %s to uid=%u, gid=%u failed: %m", devnode, uid, gid); 29199ca880aSopenharmony_ci } else { 29299ca880aSopenharmony_ci log_debug("preserve permissions %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid); 29399ca880aSopenharmony_ci } 29499ca880aSopenharmony_ci 29599ca880aSopenharmony_ci /* apply SECLABEL{$module}=$label */ 29699ca880aSopenharmony_ci udev_list_entry_foreach(entry, udev_list_get_entry(seclabel_list)) { 29799ca880aSopenharmony_ci const char *name, *label; 29899ca880aSopenharmony_ci int r; 29999ca880aSopenharmony_ci 30099ca880aSopenharmony_ci name = udev_list_entry_get_name(entry); 30199ca880aSopenharmony_ci label = udev_list_entry_get_value(entry); 30299ca880aSopenharmony_ci 30399ca880aSopenharmony_ci if (streq(name, "selinux")) { 30499ca880aSopenharmony_ci selinux = true; 30599ca880aSopenharmony_ci 30699ca880aSopenharmony_ci r = mac_selinux_apply(devnode, label); 30799ca880aSopenharmony_ci if (r < 0) 30899ca880aSopenharmony_ci log_error_errno(r, "SECLABEL: failed to set SELinux label '%s': %m", label); 30999ca880aSopenharmony_ci else 31099ca880aSopenharmony_ci log_debug("SECLABEL: set SELinux label '%s'", label); 31199ca880aSopenharmony_ci 31299ca880aSopenharmony_ci } else if (streq(name, "smack")) { 31399ca880aSopenharmony_ci smack = true; 31499ca880aSopenharmony_ci 31599ca880aSopenharmony_ci r = mac_smack_apply(devnode, label); 31699ca880aSopenharmony_ci if (r < 0) 31799ca880aSopenharmony_ci log_error_errno(r, "SECLABEL: failed to set SMACK label '%s': %m", label); 31899ca880aSopenharmony_ci else 31999ca880aSopenharmony_ci log_debug("SECLABEL: set SMACK label '%s'", label); 32099ca880aSopenharmony_ci 32199ca880aSopenharmony_ci } else 32299ca880aSopenharmony_ci log_error("SECLABEL: unknown subsystem, ignoring '%s'='%s'", name, label); 32399ca880aSopenharmony_ci } 32499ca880aSopenharmony_ci 32599ca880aSopenharmony_ci /* set the defaults */ 32699ca880aSopenharmony_ci if (!selinux) 32799ca880aSopenharmony_ci mac_selinux_fix(devnode, true, false); 32899ca880aSopenharmony_ci if (!smack) 32999ca880aSopenharmony_ci mac_smack_apply(devnode, NULL); 33099ca880aSopenharmony_ci } 33199ca880aSopenharmony_ci 33299ca880aSopenharmony_ci /* always update timestamp when we re-use the node, like on media change events */ 33399ca880aSopenharmony_ci utimensat(AT_FDCWD, devnode, NULL, 0); 33499ca880aSopenharmony_ciout: 33599ca880aSopenharmony_ci return err; 33699ca880aSopenharmony_ci} 33799ca880aSopenharmony_ci 33899ca880aSopenharmony_civoid udev_node_add(struct udev_device *dev, bool apply, 33999ca880aSopenharmony_ci mode_t mode, uid_t uid, gid_t gid, 34099ca880aSopenharmony_ci struct udev_list *seclabel_list) { 34199ca880aSopenharmony_ci char filename[UTIL_PATH_SIZE]; 34299ca880aSopenharmony_ci struct udev_list_entry *list_entry; 34399ca880aSopenharmony_ci 34499ca880aSopenharmony_ci log_debug("handling device node '%s', devnum=%s, mode=%#o, uid="UID_FMT", gid="GID_FMT, 34599ca880aSopenharmony_ci udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid); 34699ca880aSopenharmony_ci 34799ca880aSopenharmony_ci if (node_permissions_apply(dev, apply, mode, uid, gid, seclabel_list) < 0) 34899ca880aSopenharmony_ci return; 34999ca880aSopenharmony_ci 35099ca880aSopenharmony_ci /* always add /dev/{block,char}/$major:$minor */ 35199ca880aSopenharmony_ci snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", 35299ca880aSopenharmony_ci streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", 35399ca880aSopenharmony_ci major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); 35499ca880aSopenharmony_ci node_symlink(dev, udev_device_get_devnode(dev), filename); 35599ca880aSopenharmony_ci 35699ca880aSopenharmony_ci /* create/update symlinks, add symlinks to name index */ 35799ca880aSopenharmony_ci udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) 35899ca880aSopenharmony_ci link_update(dev, udev_list_entry_get_name(list_entry), true); 35999ca880aSopenharmony_ci} 36099ca880aSopenharmony_ci 36199ca880aSopenharmony_civoid udev_node_remove(struct udev_device *dev) { 36299ca880aSopenharmony_ci struct udev_list_entry *list_entry; 36399ca880aSopenharmony_ci char filename[UTIL_PATH_SIZE]; 36499ca880aSopenharmony_ci 36599ca880aSopenharmony_ci /* remove/update symlinks, remove symlinks from name index */ 36699ca880aSopenharmony_ci udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) 36799ca880aSopenharmony_ci link_update(dev, udev_list_entry_get_name(list_entry), false); 36899ca880aSopenharmony_ci 36999ca880aSopenharmony_ci /* remove /dev/{block,char}/$major:$minor */ 37099ca880aSopenharmony_ci snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", 37199ca880aSopenharmony_ci streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", 37299ca880aSopenharmony_ci major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); 37399ca880aSopenharmony_ci unlink(filename); 37499ca880aSopenharmony_ci} 375