1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include <sys/statvfs.h>
10 #include "alloc-util.h"
11 #include "chase-symlinks.h"
12 #include "dirent-util.h"
13 #include "errno-util.h"
17 #include "missing_fs.h"
18 #include "missing_magic.h"
19 #include "missing_syscall.h"
20 #include "parse-util.h"
21 #include "stat-util.h"
22 #include "string-util.h"
24 int is_symlink(const char *path
) {
29 if (lstat(path
, &info
) < 0)
32 return !!S_ISLNK(info
.st_mode
);
35 int is_dir(const char* path
, bool follow
) {
48 return !!S_ISDIR(st
.st_mode
);
51 int is_dir_fd(int fd
) {
54 if (fstat(fd
, &st
) < 0)
57 return !!S_ISDIR(st
.st_mode
);
60 int is_device_node(const char *path
) {
65 if (lstat(path
, &info
) < 0)
68 return !!(S_ISBLK(info
.st_mode
) || S_ISCHR(info
.st_mode
));
71 int dir_is_empty_at(int dir_fd
, const char *path
) {
72 _cleanup_close_
int fd
= -1;
73 _cleanup_closedir_
DIR *d
= NULL
;
77 fd
= openat(dir_fd
, path
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
81 /* Note that DUPing is not enough, as the internal pointer
82 * would still be shared and moved by FOREACH_DIRENT. */
83 fd
= fd_reopen(dir_fd
, O_CLOEXEC
);
88 d
= take_fdopendir(&fd
);
92 FOREACH_DIRENT(de
, d
, return -errno
)
98 bool null_or_empty(struct stat
*st
) {
101 if (S_ISREG(st
->st_mode
) && st
->st_size
<= 0)
104 /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
105 * device node?" check. */
107 if (S_ISCHR(st
->st_mode
))
113 int null_or_empty_path(const char *fn
) {
118 /* If we have the path, let's do an easy text comparison first. */
119 if (path_equal(fn
, "/dev/null"))
122 if (stat(fn
, &st
) < 0)
125 return null_or_empty(&st
);
128 int null_or_empty_fd(int fd
) {
133 if (fstat(fd
, &st
) < 0)
136 return null_or_empty(&st
);
139 int path_is_read_only_fs(const char *path
) {
144 if (statvfs(path
, &st
) < 0)
147 if (st
.f_flag
& ST_RDONLY
)
150 /* On NFS, statvfs() might not reflect whether we can actually
151 * write to the remote share. Let's try again with
152 * access(W_OK) which is more reliable, at least sometimes. */
153 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
159 int files_same(const char *filea
, const char *fileb
, int flags
) {
165 if (fstatat(AT_FDCWD
, filea
, &a
, flags
) < 0)
168 if (fstatat(AT_FDCWD
, fileb
, &b
, flags
) < 0)
171 return a
.st_dev
== b
.st_dev
&&
172 a
.st_ino
== b
.st_ino
;
175 bool is_fs_type(const struct statfs
*s
, statfs_f_type_t magic_value
) {
177 assert_cc(sizeof(statfs_f_type_t
) >= sizeof(s
->f_type
));
179 return F_TYPE_EQUAL(s
->f_type
, magic_value
);
182 int fd_is_fs_type(int fd
, statfs_f_type_t magic_value
) {
185 if (fstatfs(fd
, &s
) < 0)
188 return is_fs_type(&s
, magic_value
);
191 int path_is_fs_type(const char *path
, statfs_f_type_t magic_value
) {
194 if (statfs(path
, &s
) < 0)
197 return is_fs_type(&s
, magic_value
);
200 bool is_temporary_fs(const struct statfs
*s
) {
201 return is_fs_type(s
, TMPFS_MAGIC
) ||
202 is_fs_type(s
, RAMFS_MAGIC
);
205 bool is_network_fs(const struct statfs
*s
) {
206 return is_fs_type(s
, CIFS_MAGIC_NUMBER
) ||
207 is_fs_type(s
, CODA_SUPER_MAGIC
) ||
208 is_fs_type(s
, NCP_SUPER_MAGIC
) ||
209 is_fs_type(s
, NFS_SUPER_MAGIC
) ||
210 is_fs_type(s
, SMB_SUPER_MAGIC
) ||
211 is_fs_type(s
, V9FS_MAGIC
) ||
212 is_fs_type(s
, AFS_SUPER_MAGIC
) ||
213 is_fs_type(s
, OCFS2_SUPER_MAGIC
);
216 int fd_is_temporary_fs(int fd
) {
219 if (fstatfs(fd
, &s
) < 0)
222 return is_temporary_fs(&s
);
225 int fd_is_network_fs(int fd
) {
228 if (fstatfs(fd
, &s
) < 0)
231 return is_network_fs(&s
);
234 int path_is_temporary_fs(const char *path
) {
237 if (statfs(path
, &s
) < 0)
240 return is_temporary_fs(&s
);
243 int stat_verify_regular(const struct stat
*st
) {
246 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
249 if (S_ISDIR(st
->st_mode
))
252 if (S_ISLNK(st
->st_mode
))
255 if (!S_ISREG(st
->st_mode
))
261 int fd_verify_regular(int fd
) {
266 if (fstat(fd
, &st
) < 0)
269 return stat_verify_regular(&st
);
272 int stat_verify_directory(const struct stat
*st
) {
275 if (S_ISLNK(st
->st_mode
))
278 if (!S_ISDIR(st
->st_mode
))
284 int fd_verify_directory(int fd
) {
289 if (fstat(fd
, &st
) < 0)
292 return stat_verify_directory(&st
);
295 int device_path_make_major_minor(mode_t mode
, dev_t devno
, char **ret
) {
298 /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
302 else if (S_ISBLK(mode
))
307 if (asprintf(ret
, "/dev/%s/%u:%u", t
, major(devno
), minor(devno
)) < 0)
313 int device_path_make_canonical(mode_t mode
, dev_t devno
, char **ret
) {
314 _cleanup_free_
char *p
= NULL
;
317 /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
321 if (major(devno
) == 0 && minor(devno
) == 0) {
324 /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
325 * /dev/block/ and /dev/char/, hence we handle them specially here. */
328 s
= strdup("/run/systemd/inaccessible/chr");
329 else if (S_ISBLK(mode
))
330 s
= strdup("/run/systemd/inaccessible/blk");
341 r
= device_path_make_major_minor(mode
, devno
, &p
);
345 return chase_symlinks(p
, NULL
, 0, ret
, NULL
);
348 int device_path_parse_major_minor(const char *path
, mode_t
*ret_mode
, dev_t
*ret_devno
) {
353 /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
354 * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
355 * path cannot be parsed like this. */
357 if (path_equal(path
, "/run/systemd/inaccessible/chr")) {
359 devno
= makedev(0, 0);
360 } else if (path_equal(path
, "/run/systemd/inaccessible/blk")) {
362 devno
= makedev(0, 0);
366 w
= path_startswith(path
, "/dev/block/");
370 w
= path_startswith(path
, "/dev/char/");
377 r
= parse_dev(w
, &devno
);
390 int proc_mounted(void) {
393 /* A quick check of procfs is properly mounted */
395 r
= path_is_fs_type("/proc/", PROC_SUPER_MAGIC
);
396 if (r
== -ENOENT
) /* not mounted at all */
402 bool stat_inode_unmodified(const struct stat
*a
, const struct stat
*b
) {
404 /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
405 * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
406 * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
407 * size, backing device, inode type and if this refers to a device not the major/minor.
409 * Note that we don't care if file attributes such as ownership or access mode change, this here is
410 * about contents of the file. The purpose here is to detect file contents changes, and nothing
414 (a
->st_mode
& S_IFMT
) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
415 ((a
->st_mode
^ b
->st_mode
) & S_IFMT
) == 0 && /* same inode type */
416 a
->st_mtim
.tv_sec
== b
->st_mtim
.tv_sec
&&
417 a
->st_mtim
.tv_nsec
== b
->st_mtim
.tv_nsec
&&
418 (!S_ISREG(a
->st_mode
) || a
->st_size
== b
->st_size
) && /* if regular file, compare file size */
419 a
->st_dev
== b
->st_dev
&&
420 a
->st_ino
== b
->st_ino
&&
421 (!(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 */
424 int statx_fallback(int dfd
, const char *path
, int flags
, unsigned mask
, struct statx
*sx
) {
425 static bool avoid_statx
= false;
429 if (statx(dfd
, path
, flags
, mask
, sx
) < 0) {
430 if (!ERRNO_IS_NOT_SUPPORTED(errno
) && errno
!= EPERM
)
433 /* If statx() is not supported or if we see EPERM (which might indicate seccomp
434 * filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
435 * since that is likely an indication of fs access issues, which we should
443 /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
445 if ((flags
& ~(AT_EMPTY_PATH
|AT_NO_AUTOMOUNT
|AT_SYMLINK_NOFOLLOW
|
446 AT_STATX_SYNC_AS_STAT
|AT_STATX_FORCE_SYNC
|AT_STATX_DONT_SYNC
)) != 0)
449 if (fstatat(dfd
, path
, &st
, flags
& (AT_EMPTY_PATH
|AT_NO_AUTOMOUNT
|AT_SYMLINK_NOFOLLOW
)) < 0)
452 *sx
= (struct statx
) {
453 .stx_mask
= STATX_TYPE
|STATX_MODE
|
454 STATX_NLINK
|STATX_UID
|STATX_GID
|
455 STATX_ATIME
|STATX_MTIME
|STATX_CTIME
|
456 STATX_INO
|STATX_SIZE
|STATX_BLOCKS
,
457 .stx_blksize
= st
.st_blksize
,
458 .stx_nlink
= st
.st_nlink
,
459 .stx_uid
= st
.st_uid
,
460 .stx_gid
= st
.st_gid
,
461 .stx_mode
= st
.st_mode
,
462 .stx_ino
= st
.st_ino
,
463 .stx_size
= st
.st_size
,
464 .stx_blocks
= st
.st_blocks
,
465 .stx_rdev_major
= major(st
.st_rdev
),
466 .stx_rdev_minor
= minor(st
.st_rdev
),
467 .stx_dev_major
= major(st
.st_dev
),
468 .stx_dev_minor
= minor(st
.st_dev
),
469 .stx_atime
.tv_sec
= st
.st_atim
.tv_sec
,
470 .stx_atime
.tv_nsec
= st
.st_atim
.tv_nsec
,
471 .stx_mtime
.tv_sec
= st
.st_mtim
.tv_sec
,
472 .stx_mtime
.tv_nsec
= st
.st_mtim
.tv_nsec
,
473 .stx_ctime
.tv_sec
= st
.st_ctim
.tv_sec
,
474 .stx_ctime
.tv_nsec
= st
.st_ctim
.tv_nsec
,