mirror of
https://github.com/systemd/systemd.git
synced 2025-03-23 10:50:16 +03:00
udevd: create standard symlinks and handle /lib/udev/devices
This commit is contained in:
parent
c1332ae898
commit
cb9a0eeeab
@ -227,12 +227,15 @@ static inline void udev_selinux_init(struct udev *udev) {}
|
||||
static inline void udev_selinux_exit(struct udev *udev) {}
|
||||
static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {}
|
||||
static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {}
|
||||
static inline void udev_selinux_setfscreateconat(struct udev *udev, int dirfd, const char *file, unsigned int mode) {}
|
||||
static inline void udev_selinux_resetfscreatecon(struct udev *udev) {}
|
||||
#else
|
||||
void udev_selinux_init(struct udev *udev);
|
||||
void udev_selinux_exit(struct udev *udev);
|
||||
void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode);
|
||||
void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode);
|
||||
void udev_selinux_setfscreateconat(struct udev *udev, int dirfd, const char *file, unsigned int mode);
|
||||
void udev_selinux_resetfscreatecon(struct udev *udev);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -53,7 +53,7 @@ void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int
|
||||
if (matchpathcon(file, mode, &scontext) < 0) {
|
||||
err(udev, "matchpathcon(%s) failed\n", file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (lsetfilecon(file, scontext) < 0)
|
||||
err(udev, "setfilecon %s failed: %m\n", file);
|
||||
freecon(scontext);
|
||||
@ -65,6 +65,7 @@ void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned i
|
||||
|
||||
if (!selinux_enabled)
|
||||
return;
|
||||
|
||||
if (matchpathcon(file, mode, &scontext) < 0) {
|
||||
err(udev, "matchpathcon(%s) failed\n", file);
|
||||
return;
|
||||
@ -81,3 +82,28 @@ void udev_selinux_resetfscreatecon(struct udev *udev)
|
||||
if (setfscreatecon(selinux_prev_scontext) < 0)
|
||||
err(udev, "setfscreatecon failed: %m\n");
|
||||
}
|
||||
|
||||
void udev_selinux_setfscreateconat(struct udev *udev, int dirfd, const char *file, unsigned int mode)
|
||||
{
|
||||
char filename[UTIL_PATH_SIZE];
|
||||
|
||||
if (!selinux_enabled)
|
||||
return;
|
||||
|
||||
/* resolve relative filename */
|
||||
if (file[0] != '/') {
|
||||
char procfd[UTIL_PATH_SIZE];
|
||||
char target[UTIL_PATH_SIZE];
|
||||
ssize_t len;
|
||||
|
||||
snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dirfd);
|
||||
len = readlink(procfd, target, sizeof(target));
|
||||
if (len <= 0 || len == sizeof(target))
|
||||
return;
|
||||
target[len] = '\0';
|
||||
|
||||
util_strscpyl(filename, sizeof(filename), target, "/", file, NULL);
|
||||
file = filename;
|
||||
}
|
||||
udev_selinux_setfscreatecon(udev, file, mode);
|
||||
}
|
||||
|
149
udev/udevd.c
149
udev/udevd.c
@ -449,29 +449,6 @@ static void worker_kill(struct udev *udev, int retain)
|
||||
}
|
||||
}
|
||||
|
||||
static int mem_size_mb(void)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[4096];
|
||||
long int memsize = -1;
|
||||
|
||||
f = fopen("/proc/meminfo", "r");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f) != NULL) {
|
||||
long int value;
|
||||
|
||||
if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
|
||||
memsize = value / 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return memsize;
|
||||
}
|
||||
|
||||
/* lookup event for identical, parent, child device */
|
||||
static bool is_devpath_busy(struct event *event)
|
||||
{
|
||||
@ -768,6 +745,130 @@ static void handle_signal(struct udev *udev, int signo)
|
||||
}
|
||||
}
|
||||
|
||||
static int copy_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
|
||||
{
|
||||
struct dirent *dent;
|
||||
|
||||
for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
|
||||
struct stat stats;
|
||||
|
||||
if (dent->d_name[0] == '.')
|
||||
continue;
|
||||
if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
continue;
|
||||
|
||||
if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
|
||||
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
|
||||
if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
|
||||
fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
|
||||
fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
|
||||
} else {
|
||||
utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
|
||||
}
|
||||
udev_selinux_resetfscreatecon(udev);
|
||||
} else if (S_ISLNK(stats.st_mode)) {
|
||||
char target[UTIL_PATH_SIZE];
|
||||
ssize_t len;
|
||||
|
||||
len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
|
||||
if (len <= 0 || len == (ssize_t)sizeof(target))
|
||||
continue;
|
||||
target[len] = '\0';
|
||||
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
|
||||
if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
|
||||
utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
|
||||
udev_selinux_resetfscreatecon(udev);
|
||||
} else if (S_ISDIR(stats.st_mode)) {
|
||||
DIR *dir2_from, *dir2_to;
|
||||
|
||||
if (maxdepth == 0)
|
||||
continue;
|
||||
|
||||
udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFDIR|0755);
|
||||
mkdirat(dirfd(dir_to), dent->d_name, 0755);
|
||||
udev_selinux_resetfscreatecon(udev);
|
||||
|
||||
dir2_to = fdopendir(openat(dirfd(dir_to), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
|
||||
if (dir2_to == NULL)
|
||||
continue;
|
||||
|
||||
dir2_from = fdopendir(openat(dirfd(dir_from), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
|
||||
if (dir2_from == NULL) {
|
||||
closedir(dir2_to);
|
||||
continue;
|
||||
}
|
||||
|
||||
copy_dir(udev, dir2_from, dir2_to, maxdepth-1);
|
||||
|
||||
closedir(dir2_to);
|
||||
closedir(dir2_from);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prepare_dev(struct udev *udev)
|
||||
{
|
||||
struct stdlinks {
|
||||
const char *link;
|
||||
const char *target;
|
||||
};
|
||||
static const struct stdlinks stdlinks[] = {
|
||||
{ "core", "/proc/kcore" },
|
||||
{ "fd", "/proc/fd" },
|
||||
{ "stdin", "/proc/self/fd/0" },
|
||||
{ "stdout", "/proc/self/fd/1" },
|
||||
{ "stderr", "/proc/self/fd/2" },
|
||||
};
|
||||
unsigned int i;
|
||||
DIR *dir_from, *dir_to;
|
||||
|
||||
dir_to = opendir(udev_get_dev_path(udev));
|
||||
if (dir_to == NULL)
|
||||
return;
|
||||
|
||||
/* create standard symlinks to /proc */
|
||||
for (i = 0; i < ARRAY_SIZE(stdlinks); i++) {
|
||||
udev_selinux_setfscreateconat(udev, dirfd(dir_to), stdlinks[i].link, S_IFLNK);
|
||||
if (symlinkat(stdlinks[i].target, dirfd(dir_to), stdlinks[i].link) < 0 && errno == EEXIST)
|
||||
utimensat(dirfd(dir_to), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
|
||||
udev_selinux_resetfscreatecon(udev);
|
||||
}
|
||||
|
||||
/* copy content from /lib/udev/devices to /dev */
|
||||
dir_from = opendir(LIBEXECDIR "/devices");
|
||||
if (dir_from != NULL) {
|
||||
copy_dir(udev, dir_from, dir_to, 8);
|
||||
closedir(dir_from);
|
||||
}
|
||||
|
||||
closedir(dir_to);
|
||||
}
|
||||
|
||||
static int mem_size_mb(void)
|
||||
{
|
||||
FILE *f;
|
||||
char buf[4096];
|
||||
long int memsize = -1;
|
||||
|
||||
f = fopen("/proc/meminfo", "r");
|
||||
if (f == NULL)
|
||||
return -1;
|
||||
|
||||
while (fgets(buf, sizeof(buf), f) != NULL) {
|
||||
long int value;
|
||||
|
||||
if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
|
||||
memsize = value / 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return memsize;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct udev *udev;
|
||||
@ -858,6 +959,8 @@ int main(int argc, char *argv[])
|
||||
if (write(STDERR_FILENO, 0, 0) < 0)
|
||||
dup2(fd, STDERR_FILENO);
|
||||
|
||||
prepare_dev(udev);
|
||||
|
||||
/* init control socket, bind() ensures, that only one udevd instance is running */
|
||||
udev_ctrl = udev_ctrl_new_from_socket(udev, UDEV_CTRL_SOCK_PATH);
|
||||
if (udev_ctrl == NULL) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user