1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <sys/statvfs.h>
10 #include "alloc-util.h"
12 #include "dirent-util.h"
13 #include "errno-util.h"
16 #include "filesystems.h"
18 #include "hash-funcs.h"
20 #include "missing_fs.h"
21 #include "missing_magic.h"
22 #include "missing_syscall.h"
23 #include "nulstr-util.h"
24 #include "parse-util.h"
25 #include "stat-util.h"
26 #include "string-util.h"
28 static int verify_stat_at(
32 int (*verify_func
)(const struct stat
*st
),
38 assert(fd
>= 0 || fd
== AT_FDCWD
);
39 assert(!isempty(path
) || !follow
);
42 if (fstatat(fd
, strempty(path
), &st
,
43 (isempty(path
) ? AT_EMPTY_PATH
: 0) | (follow
? 0 : AT_SYMLINK_NOFOLLOW
)) < 0)
47 return verify
? r
: r
>= 0;
50 int stat_verify_regular(const struct stat
*st
) {
53 /* Checks whether the specified stat() structure refers to a regular file. If not returns an
54 * appropriate error code. */
56 if (S_ISDIR(st
->st_mode
))
59 if (S_ISLNK(st
->st_mode
))
62 if (!S_ISREG(st
->st_mode
))
68 int verify_regular_at(int fd
, const char *path
, bool follow
) {
69 return verify_stat_at(fd
, path
, follow
, stat_verify_regular
, true);
72 int fd_verify_regular(int fd
) {
74 return verify_regular_at(fd
, NULL
, false);
77 int stat_verify_directory(const struct stat
*st
) {
80 if (S_ISLNK(st
->st_mode
))
83 if (!S_ISDIR(st
->st_mode
))
89 int fd_verify_directory(int fd
) {
91 return verify_stat_at(fd
, NULL
, false, stat_verify_directory
, true);
94 int is_dir_at(int fd
, const char *path
, bool follow
) {
95 return verify_stat_at(fd
, path
, follow
, stat_verify_directory
, false);
98 int is_dir(const char *path
, bool follow
) {
99 assert(!isempty(path
));
100 return is_dir_at(AT_FDCWD
, path
, follow
);
103 int stat_verify_symlink(const struct stat
*st
) {
106 if (S_ISDIR(st
->st_mode
))
109 if (!S_ISLNK(st
->st_mode
))
115 int is_symlink(const char *path
) {
116 assert(!isempty(path
));
117 return verify_stat_at(AT_FDCWD
, path
, false, stat_verify_symlink
, false);
120 int stat_verify_linked(const struct stat
*st
) {
123 if (st
->st_nlink
<= 0)
124 return -EIDRM
; /* recognizable error. */
129 int fd_verify_linked(int fd
) {
131 return verify_stat_at(fd
, NULL
, false, stat_verify_linked
, true);
134 int stat_verify_device_node(const struct stat
*st
) {
137 if (S_ISLNK(st
->st_mode
))
140 if (S_ISDIR(st
->st_mode
))
143 if (!S_ISBLK(st
->st_mode
) && !S_ISCHR(st
->st_mode
))
149 int is_device_node(const char *path
) {
150 assert(!isempty(path
));
151 return verify_stat_at(AT_FDCWD
, path
, false, stat_verify_device_node
, false);
154 int dir_is_empty_at(int dir_fd
, const char *path
, bool ignore_hidden_or_backup
) {
155 _cleanup_close_
int fd
= -EBADF
;
160 assert(dir_fd
>= 0 || dir_fd
== AT_FDCWD
);
162 fd
= openat(dir_fd
, path
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
165 } else if (dir_fd
== AT_FDCWD
) {
166 fd
= open(".", O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
170 /* Note that DUPing is not enough, as the internal pointer would still be shared and moved
174 fd
= fd_reopen(dir_fd
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
179 /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
180 * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
181 * 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
182 * entries that we end up ignoring. */
183 m
= (ignore_hidden_or_backup
? 16 : 3) * DIRENT_SIZE_MAX
;
190 n
= getdents64(fd
, buf
, m
);
196 assert((size_t) n
<= m
);
197 msan_unpoison(buf
, n
);
199 FOREACH_DIRENT_IN_BUFFER(de
, buf
, n
)
200 if (!(ignore_hidden_or_backup
? hidden_or_backup_file(de
->d_name
) : dot_or_dot_dot(de
->d_name
)))
207 bool null_or_empty(struct stat
*st
) {
210 if (S_ISREG(st
->st_mode
) && st
->st_size
<= 0)
213 /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
214 * device node?" check. */
216 if (S_ISCHR(st
->st_mode
))
222 int null_or_empty_path_with_root(const char *fn
, const char *root
) {
228 /* A symlink to /dev/null or an empty file?
229 * When looking under root_dir, we can't expect /dev/ to be mounted,
230 * so let's see if the path is a (possibly dangling) symlink to /dev/null. */
232 if (path_equal_ptr(path_startswith(fn
, root
?: "/"), "dev/null"))
235 r
= chase_and_stat(fn
, root
, CHASE_PREFIX_ROOT
, NULL
, &st
);
239 return null_or_empty(&st
);
242 int fd_is_read_only_fs(int fd
) {
247 if (fstatvfs(fd
, &st
) < 0)
250 if (st
.f_flag
& ST_RDONLY
)
253 /* On NFS, fstatvfs() might not reflect whether we can actually write to the remote share. Let's try
254 * again with access(W_OK) which is more reliable, at least sometimes. */
255 if (access_fd(fd
, W_OK
) == -EROFS
)
261 int path_is_read_only_fs(const char *path
) {
262 _cleanup_close_
int fd
= -EBADF
;
266 fd
= open(path
, O_CLOEXEC
| O_PATH
);
270 return fd_is_read_only_fs(fd
);
273 int inode_same_at(int fda
, const char *filea
, int fdb
, const char *fileb
, int flags
) {
276 assert(fda
>= 0 || fda
== AT_FDCWD
);
277 assert(fdb
>= 0 || fdb
== AT_FDCWD
);
279 if (fstatat(fda
, strempty(filea
), &a
, flags
) < 0)
280 return log_debug_errno(errno
, "Cannot stat %s: %m", filea
);
282 if (fstatat(fdb
, strempty(fileb
), &b
, flags
) < 0)
283 return log_debug_errno(errno
, "Cannot stat %s: %m", fileb
);
285 return stat_inode_same(&a
, &b
);
288 bool is_fs_type(const struct statfs
*s
, statfs_f_type_t magic_value
) {
290 assert_cc(sizeof(statfs_f_type_t
) >= sizeof(s
->f_type
));
292 return F_TYPE_EQUAL(s
->f_type
, magic_value
);
295 int is_fs_type_at(int dir_fd
, const char *path
, statfs_f_type_t magic_value
) {
299 r
= xstatfsat(dir_fd
, path
, &s
);
303 return is_fs_type(&s
, magic_value
);
306 bool is_temporary_fs(const struct statfs
*s
) {
307 return fs_in_group(s
, FILESYSTEM_SET_TEMPORARY
);
310 bool is_network_fs(const struct statfs
*s
) {
311 return fs_in_group(s
, FILESYSTEM_SET_NETWORK
);
314 int fd_is_temporary_fs(int fd
) {
317 if (fstatfs(fd
, &s
) < 0)
320 return is_temporary_fs(&s
);
323 int fd_is_network_fs(int fd
) {
326 if (fstatfs(fd
, &s
) < 0)
329 return is_network_fs(&s
);
332 int path_is_temporary_fs(const char *path
) {
335 if (statfs(path
, &s
) < 0)
338 return is_temporary_fs(&s
);
341 int path_is_network_fs(const char *path
) {
344 if (statfs(path
, &s
) < 0)
347 return is_network_fs(&s
);
350 int proc_mounted(void) {
353 /* A quick check of procfs is properly mounted */
355 r
= path_is_fs_type("/proc/", PROC_SUPER_MAGIC
);
356 if (r
== -ENOENT
) /* not mounted at all */
362 bool stat_inode_same(const struct stat
*a
, const struct stat
*b
) {
364 /* Returns if the specified stat structure references the same (though possibly modified) inode. Does
365 * a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
367 return stat_is_set(a
) && stat_is_set(b
) &&
368 ((a
->st_mode
^ b
->st_mode
) & S_IFMT
) == 0 && /* same inode type */
369 a
->st_dev
== b
->st_dev
&&
370 a
->st_ino
== b
->st_ino
;
373 bool stat_inode_unmodified(const struct stat
*a
, const struct stat
*b
) {
375 /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
376 * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
377 * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
378 * size, backing device, inode type and if this refers to a device not the major/minor.
380 * Note that we don't care if file attributes such as ownership or access mode change, this here is
381 * about contents of the file. The purpose here is to detect file contents changes, and nothing
384 return stat_inode_same(a
, b
) &&
385 a
->st_mtim
.tv_sec
== b
->st_mtim
.tv_sec
&&
386 a
->st_mtim
.tv_nsec
== b
->st_mtim
.tv_nsec
&&
387 (!S_ISREG(a
->st_mode
) || a
->st_size
== b
->st_size
) && /* if regular file, compare file size */
388 (!(S_ISCHR(a
->st_mode
) || S_ISBLK(a
->st_mode
)) || a
->st_rdev
== b
->st_rdev
); /* if device node, also compare major/minor, because we can */
391 bool statx_inode_same(const struct statx
*a
, const struct statx
*b
) {
393 /* Same as stat_inode_same() but for struct statx */
395 return statx_is_set(a
) && statx_is_set(b
) &&
396 FLAGS_SET(a
->stx_mask
, STATX_TYPE
|STATX_INO
) && FLAGS_SET(b
->stx_mask
, STATX_TYPE
|STATX_INO
) &&
397 ((a
->stx_mode
^ b
->stx_mode
) & S_IFMT
) == 0 &&
398 a
->stx_dev_major
== b
->stx_dev_major
&&
399 a
->stx_dev_minor
== b
->stx_dev_minor
&&
400 a
->stx_ino
== b
->stx_ino
;
403 bool statx_mount_same(const struct new_statx
*a
, const struct new_statx
*b
) {
404 if (!new_statx_is_set(a
) || !new_statx_is_set(b
))
407 /* if we have the mount ID, that's all we need */
408 if (FLAGS_SET(a
->stx_mask
, STATX_MNT_ID
) && FLAGS_SET(b
->stx_mask
, STATX_MNT_ID
))
409 return a
->stx_mnt_id
== b
->stx_mnt_id
;
411 /* Otherwise, major/minor of backing device must match */
412 return a
->stx_dev_major
== b
->stx_dev_major
&&
413 a
->stx_dev_minor
== b
->stx_dev_minor
;
416 static bool is_statx_fatal_error(int err
, int flags
) {
419 /* If statx() is not supported or if we see EPERM (which might indicate seccomp filtering or so),
420 * let's do a fallback. Note that on EACCES we'll not fall back, since that is likely an indication of
421 * fs access issues, which we should propagate. */
422 if (ERRNO_IS_NOT_SUPPORTED(err
) || err
== -EPERM
)
425 /* When unsupported flags are specified, glibc's fallback function returns -EINVAL.
426 * See statx_generic() in glibc. */
430 if ((flags
& ~(AT_EMPTY_PATH
| AT_NO_AUTOMOUNT
| AT_SYMLINK_NOFOLLOW
| AT_STATX_SYNC_AS_STAT
)) != 0)
431 return false; /* Unsupported flags are specified. Let's try to use our implementation. */
436 int statx_fallback(int dfd
, const char *path
, int flags
, unsigned mask
, struct statx
*sx
) {
437 static bool avoid_statx
= false;
442 r
= RET_NERRNO(statx(dfd
, path
, flags
, mask
, sx
));
443 if (r
>= 0 || is_statx_fatal_error(r
, flags
))
449 /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
451 if ((flags
& ~(AT_EMPTY_PATH
|AT_NO_AUTOMOUNT
|AT_SYMLINK_NOFOLLOW
|
452 AT_STATX_SYNC_AS_STAT
|AT_STATX_FORCE_SYNC
|AT_STATX_DONT_SYNC
)) != 0)
455 if (fstatat(dfd
, path
, &st
, flags
& (AT_EMPTY_PATH
|AT_NO_AUTOMOUNT
|AT_SYMLINK_NOFOLLOW
)) < 0)
458 *sx
= (struct statx
) {
459 .stx_mask
= STATX_TYPE
|STATX_MODE
|
460 STATX_NLINK
|STATX_UID
|STATX_GID
|
461 STATX_ATIME
|STATX_MTIME
|STATX_CTIME
|
462 STATX_INO
|STATX_SIZE
|STATX_BLOCKS
,
463 .stx_blksize
= st
.st_blksize
,
464 .stx_nlink
= st
.st_nlink
,
465 .stx_uid
= st
.st_uid
,
466 .stx_gid
= st
.st_gid
,
467 .stx_mode
= st
.st_mode
,
468 .stx_ino
= st
.st_ino
,
469 .stx_size
= st
.st_size
,
470 .stx_blocks
= st
.st_blocks
,
471 .stx_rdev_major
= major(st
.st_rdev
),
472 .stx_rdev_minor
= minor(st
.st_rdev
),
473 .stx_dev_major
= major(st
.st_dev
),
474 .stx_dev_minor
= minor(st
.st_dev
),
475 .stx_atime
.tv_sec
= st
.st_atim
.tv_sec
,
476 .stx_atime
.tv_nsec
= st
.st_atim
.tv_nsec
,
477 .stx_mtime
.tv_sec
= st
.st_mtim
.tv_sec
,
478 .stx_mtime
.tv_nsec
= st
.st_mtim
.tv_nsec
,
479 .stx_ctime
.tv_sec
= st
.st_ctim
.tv_sec
,
480 .stx_ctime
.tv_nsec
= st
.st_ctim
.tv_nsec
,
486 int xstatfsat(int dir_fd
, const char *path
, struct statfs
*ret
) {
487 _cleanup_close_
int fd
= -EBADF
;
489 assert(dir_fd
>= 0 || dir_fd
== AT_FDCWD
);
492 fd
= xopenat(dir_fd
, path
, O_PATH
|O_CLOEXEC
|O_NOCTTY
);
496 return RET_NERRNO(fstatfs(fd
, ret
));
499 void inode_hash_func(const struct stat
*q
, struct siphash
*state
) {
500 siphash24_compress_typesafe(q
->st_dev
, state
);
501 siphash24_compress_typesafe(q
->st_ino
, state
);
504 int inode_compare_func(const struct stat
*a
, const struct stat
*b
) {
507 r
= CMP(a
->st_dev
, b
->st_dev
);
511 return CMP(a
->st_ino
, b
->st_ino
);
514 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops
, struct stat
, inode_hash_func
, inode_compare_func
, free
);
516 const char* inode_type_to_string(mode_t m
) {
518 /* Returns a short string for the inode type. We use the same name as the underlying macros for each
521 switch (m
& S_IFMT
) {
538 /* Note anonymous inodes in the kernel will have a zero type. Hence fstat() of an eventfd() will
539 * return an .st_mode where we'll return NULL here! */
543 mode_t
inode_type_from_string(const char *s
) {
557 if (streq(s
, "fifo"))
559 if (streq(s
, "sock"))