Merge pull request #20910 from poettering/nftw-no-more
basic: add recurse_dir() function as modern replacement for nftw()
This commit is contained in:
+45
-32
@@ -1,22 +1,22 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <ftw.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cgroup-setup.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "process-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "mkdir.h"
|
||||
#include "process-util.h"
|
||||
#include "fileio.h"
|
||||
#include "user-util.h"
|
||||
#include "fd-util.h"
|
||||
|
||||
bool cg_is_unified_wanted(void) {
|
||||
static thread_local int wanted = -1;
|
||||
@@ -149,19 +149,23 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
|
||||
assert(path);
|
||||
assert(sb);
|
||||
assert(ftwbuf);
|
||||
static int trim_cb(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
if (typeflag != FTW_DP)
|
||||
return 0;
|
||||
/* Failures to delete inner cgroup we ignore (but debug log in case error code is unexpected) */
|
||||
if (event == RECURSE_DIR_LEAVE &&
|
||||
de->d_type == DT_DIR &&
|
||||
unlinkat(dir_fd, de->d_name, AT_REMOVEDIR) < 0 &&
|
||||
!IN_SET(errno, ENOENT, ENOTEMPTY, EBUSY))
|
||||
log_debug_errno(errno, "Failed to trim inner cgroup %s, ignoring: %m", path);
|
||||
|
||||
if (ftwbuf->level < 1)
|
||||
return 0;
|
||||
|
||||
(void) rmdir(path);
|
||||
return 0;
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
|
||||
int cg_trim(const char *controller, const char *path, bool delete_root) {
|
||||
@@ -169,32 +173,41 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
|
||||
int r, q;
|
||||
|
||||
assert(path);
|
||||
assert(controller);
|
||||
|
||||
r = cg_get_path(controller, path, NULL, &fs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
errno = 0;
|
||||
if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
|
||||
if (errno == ENOENT)
|
||||
r = 0;
|
||||
else
|
||||
r = errno_or_else(EIO);
|
||||
}
|
||||
r = recurse_dir_at(
|
||||
AT_FDCWD,
|
||||
fs,
|
||||
/* statx_mask= */ 0,
|
||||
/* n_depth_max= */ UINT_MAX,
|
||||
RECURSE_DIR_ENSURE_TYPE,
|
||||
trim_cb,
|
||||
NULL);
|
||||
if (r == -ENOENT) /* non-existing is the ultimate trimming, hence no error */
|
||||
r = 0;
|
||||
else if (r < 0)
|
||||
log_debug_errno(r, "Failed to iterate through cgroup %s: %m", path);
|
||||
|
||||
if (delete_root) {
|
||||
if (rmdir(fs) < 0 && errno != ENOENT)
|
||||
return -errno;
|
||||
/* If we shall delete the top-level cgroup, then propagate the faiure to do so (except if it is
|
||||
* already gone anyway). Also, let's debug log about this failure, except if the error code is an
|
||||
* expected one. */
|
||||
if (delete_root && !empty_or_root(path) &&
|
||||
rmdir(fs) < 0 && errno != ENOENT) {
|
||||
if (!IN_SET(errno, ENOTEMPTY, EBUSY))
|
||||
log_debug_errno(errno, "Failed to trim cgroup %s: %m", path);
|
||||
if (r >= 0)
|
||||
r = -errno;
|
||||
}
|
||||
|
||||
q = cg_hybrid_unified();
|
||||
if (q < 0)
|
||||
return q;
|
||||
if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
|
||||
if (q < 0)
|
||||
log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
|
||||
}
|
||||
if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER))
|
||||
(void) cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
+80
-51
@@ -1,86 +1,105 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <ftw.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "kbd-util.h"
|
||||
#include "log.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "path-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "utf8.h"
|
||||
|
||||
static thread_local const char *keymap_name = NULL;
|
||||
static thread_local Set *keymaps = NULL;
|
||||
struct recurse_dir_userdata {
|
||||
const char *keymap_name;
|
||||
Set *keymaps;
|
||||
};
|
||||
|
||||
static int nftw_cb(
|
||||
const char *fpath,
|
||||
const struct stat *sb,
|
||||
int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
static int keymap_recurse_dir_callback(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
struct recurse_dir_userdata *data = userdata;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
||||
/* If keymap_name is non-null, return true if keymap keymap_name is found.
|
||||
* Otherwise, add all keymaps to keymaps. */
|
||||
assert(de);
|
||||
|
||||
if (tflag != FTW_F)
|
||||
return 0;
|
||||
/* If 'keymap_name' is non-NULL, return true if keymap 'keymap_name' is found. Otherwise, add all
|
||||
* keymaps to 'keymaps'. */
|
||||
|
||||
fpath = basename(fpath);
|
||||
if (event != RECURSE_DIR_ENTRY)
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
const char *e = endswith(fpath, ".map") ?: endswith(fpath, ".map.gz");
|
||||
if (!IN_SET(de->d_type, DT_REG, DT_LNK))
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
const char *e = endswith(de->d_name, ".map") ?: endswith(de->d_name, ".map.gz");
|
||||
if (!e)
|
||||
return 0;
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
p = strndup(fpath, e - fpath);
|
||||
if (!p) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
p = strndup(de->d_name, e - de->d_name);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
if (keymap_name)
|
||||
return streq(p, keymap_name);
|
||||
if (data->keymap_name)
|
||||
return streq(p, data->keymap_name) ? 1 : RECURSE_DIR_CONTINUE;
|
||||
|
||||
assert(data->keymaps);
|
||||
|
||||
if (!keymap_is_valid(p))
|
||||
return 0;
|
||||
|
||||
r = set_consume(keymaps, TAKE_PTR(p));
|
||||
if (r < 0 && r != -EEXIST) {
|
||||
errno = -r;
|
||||
return -1;
|
||||
}
|
||||
r = set_consume(data->keymaps, TAKE_PTR(p));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
|
||||
int get_keymaps(char ***ret) {
|
||||
_cleanup_(set_free_freep) Set *keymaps = NULL;
|
||||
int r;
|
||||
|
||||
keymaps = set_new(&string_hash_ops);
|
||||
if (!keymaps)
|
||||
return -ENOMEM;
|
||||
|
||||
const char *dir;
|
||||
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS)
|
||||
if (nftw(dir, nftw_cb, 20, FTW_PHYS) < 0) {
|
||||
if (errno == ENOENT)
|
||||
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
|
||||
r = recurse_dir_at(
|
||||
AT_FDCWD,
|
||||
dir,
|
||||
/* statx_mask= */ 0,
|
||||
/* n_depth_max= */ UINT_MAX,
|
||||
RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE,
|
||||
keymap_recurse_dir_callback,
|
||||
&(struct recurse_dir_userdata) {
|
||||
.keymaps = keymaps,
|
||||
});
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (ERRNO_IS_RESOURCE(errno)) {
|
||||
keymaps = set_free_free(keymaps);
|
||||
return log_warning_errno(errno, "Failed to read keymap list from %s: %m", dir);
|
||||
}
|
||||
log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir);
|
||||
}
|
||||
if (ERRNO_IS_RESOURCE(r))
|
||||
return log_warning_errno(r, "Failed to read keymap list from %s: %m", dir);
|
||||
|
||||
_cleanup_strv_free_ char **l = set_get_strv(keymaps);
|
||||
if (!l) {
|
||||
keymaps = set_free_free(keymaps);
|
||||
return -ENOMEM;
|
||||
log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir);
|
||||
}
|
||||
}
|
||||
|
||||
keymaps = set_free(keymaps);
|
||||
_cleanup_strv_free_ char **l = set_get_strv(keymaps);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
keymaps = set_free(keymaps); /* If we got the strv above, then do a set_free() rather than
|
||||
* set_free_free() since the entries of the set are now owned by the
|
||||
* strv */
|
||||
|
||||
if (strv_isempty(l))
|
||||
return -ENOENT;
|
||||
@@ -88,7 +107,6 @@ int get_keymaps(char ***ret) {
|
||||
strv_sort(l);
|
||||
|
||||
*ret = TAKE_PTR(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -117,18 +135,29 @@ int keymap_exists(const char *name) {
|
||||
if (!keymap_is_valid(name))
|
||||
return -EINVAL;
|
||||
|
||||
keymap_name = name;
|
||||
|
||||
const char *dir;
|
||||
NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
|
||||
r = nftw(dir, nftw_cb, 20, FTW_PHYS);
|
||||
r = recurse_dir_at(
|
||||
AT_FDCWD,
|
||||
dir,
|
||||
/* statx_mask= */ 0,
|
||||
/* n_depth_max= */ UINT_MAX,
|
||||
RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE,
|
||||
keymap_recurse_dir_callback,
|
||||
&(struct recurse_dir_userdata) {
|
||||
.keymap_name = name,
|
||||
});
|
||||
if (r == -ENOENT)
|
||||
continue;
|
||||
if (ERRNO_IS_RESOURCE(r))
|
||||
return r;
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to read keymap list from %s, ignoring: %m", dir);
|
||||
continue;
|
||||
}
|
||||
if (r > 0)
|
||||
break;
|
||||
if (r < 0 && errno != ENOENT)
|
||||
log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir);
|
||||
}
|
||||
|
||||
keymap_name = NULL;
|
||||
|
||||
return r > 0;
|
||||
}
|
||||
|
||||
+41
-22
@@ -1,7 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <errno.h>
|
||||
#include <ftw.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/statvfs.h>
|
||||
@@ -9,9 +8,9 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "cgroup-setup.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "conf-files.h"
|
||||
#include "cgroup-setup.h"
|
||||
#include "dev-setup.h"
|
||||
#include "dirent-util.h"
|
||||
#include "efi-loader.h"
|
||||
@@ -27,6 +26,7 @@
|
||||
#include "mountpoint-util.h"
|
||||
#include "nulstr-util.h"
|
||||
#include "path-util.h"
|
||||
#include "recurse-dir.h"
|
||||
#include "set.h"
|
||||
#include "smack-util.h"
|
||||
#include "strv.h"
|
||||
@@ -365,27 +365,46 @@ int mount_cgroup_controllers(void) {
|
||||
}
|
||||
|
||||
#if HAVE_SELINUX || ENABLE_SMACK
|
||||
static int nftw_cb(
|
||||
const char *fpath,
|
||||
const struct stat *sb,
|
||||
int tflag,
|
||||
struct FTW *ftwbuf) {
|
||||
static int relabel_cb(
|
||||
RecurseDirEvent event,
|
||||
const char *path,
|
||||
int dir_fd,
|
||||
int inode_fd,
|
||||
const struct dirent *de,
|
||||
const struct statx *sx,
|
||||
void *userdata) {
|
||||
|
||||
/* No need to label /dev twice in a row... */
|
||||
if (_unlikely_(ftwbuf->level == 0))
|
||||
return FTW_CONTINUE;
|
||||
switch (event) {
|
||||
|
||||
(void) label_fix(fpath, 0);
|
||||
case RECURSE_DIR_LEAVE:
|
||||
case RECURSE_DIR_SKIP_MOUNT:
|
||||
/* If we already saw this dirent when entering it or this is a dirent that on a different
|
||||
* mount, don't relabel it. */
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
|
||||
/* /run/initramfs is static data and big, no need to
|
||||
* dynamically relabel its contents at boot... */
|
||||
if (_unlikely_(ftwbuf->level == 1 &&
|
||||
tflag == FTW_D &&
|
||||
streq(fpath, "/run/initramfs")))
|
||||
return FTW_SKIP_SUBTREE;
|
||||
case RECURSE_DIR_ENTER:
|
||||
/* /run/initramfs is static data and big, no need to dynamically relabel its contents at boot... */
|
||||
if (path_equal(path, "/run/initramfs"))
|
||||
return RECURSE_DIR_SKIP_ENTRY;
|
||||
|
||||
return FTW_CONTINUE;
|
||||
};
|
||||
_fallthrough_;
|
||||
|
||||
default:
|
||||
/* Otherwise, label it, even if we had trouble stat()ing it and similar. SELinux can figure this out */
|
||||
(void) label_fix(path, 0);
|
||||
return RECURSE_DIR_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
static int relabel_tree(const char *path) {
|
||||
int r;
|
||||
|
||||
r = recurse_dir_at(AT_FDCWD, path, 0, UINT_MAX, RECURSE_DIR_ENSURE_TYPE|RECURSE_DIR_SAME_MOUNT, relabel_cb, NULL);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to recursively relabel '%s': %m", path);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int relabel_cgroup_filesystems(void) {
|
||||
int r;
|
||||
@@ -404,7 +423,7 @@ static int relabel_cgroup_filesystems(void) {
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
|
||||
|
||||
(void) label_fix("/sys/fs/cgroup", 0);
|
||||
(void) nftw("/sys/fs/cgroup", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
|
||||
(void) relabel_tree("/sys/fs/cgroup");
|
||||
|
||||
if (st.f_flags & ST_RDONLY)
|
||||
(void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
|
||||
@@ -468,7 +487,7 @@ static int relabel_extra(void) {
|
||||
|
||||
log_debug("Relabelling additional file/directory '%s'.", line);
|
||||
(void) label_fix(line, 0);
|
||||
(void) nftw(line, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
|
||||
(void) relabel_tree(line);
|
||||
c++;
|
||||
}
|
||||
|
||||
@@ -505,7 +524,7 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
|
||||
before_relabel = now(CLOCK_MONOTONIC);
|
||||
|
||||
FOREACH_STRING(i, "/dev", "/dev/shm", "/run")
|
||||
(void) nftw(i, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
|
||||
(void) relabel_tree(i);
|
||||
|
||||
(void) relabel_cgroup_filesystems();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user