1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <sys/statvfs.h>
10 #include "alloc-util.h"
11 #include "dirent-util.h"
15 #include "missing_fs.h"
16 #include "missing_magic.h"
17 #include "parse-util.h"
18 #include "stat-util.h"
19 #include "string-util.h"
21 int is_symlink(const char *path
) {
26 if (lstat(path
, &info
) < 0)
29 return !!S_ISLNK(info
.st_mode
);
32 int is_dir(const char* path
, bool follow
) {
45 return !!S_ISDIR(st
.st_mode
);
48 int is_dir_fd(int fd
) {
51 if (fstat(fd
, &st
) < 0)
54 return !!S_ISDIR(st
.st_mode
);
57 int is_device_node(const char *path
) {
62 if (lstat(path
, &info
) < 0)
65 return !!(S_ISBLK(info
.st_mode
) || S_ISCHR(info
.st_mode
));
68 int dir_is_empty_at(int dir_fd
, const char *path
) {
69 _cleanup_close_
int fd
= -1;
70 _cleanup_closedir_
DIR *d
= NULL
;
74 fd
= openat(dir_fd
, path
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
76 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
85 FOREACH_DIRENT(de
, d
, return -errno
)
91 bool null_or_empty(struct stat
*st
) {
94 if (S_ISREG(st
->st_mode
) && st
->st_size
<= 0)
97 /* We don't want to hardcode the major/minor of /dev/null,
98 * hence we do a simpler "is this a device node?" check. */
100 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
))
106 int null_or_empty_path(const char *fn
) {
111 if (stat(fn
, &st
) < 0)
114 return null_or_empty(&st
);
117 int null_or_empty_fd(int fd
) {
122 if (fstat(fd
, &st
) < 0)
125 return null_or_empty(&st
);
128 int path_is_read_only_fs(const char *path
) {
133 if (statvfs(path
, &st
) < 0)
136 if (st
.f_flag
& ST_RDONLY
)
139 /* On NFS, statvfs() might not reflect whether we can actually
140 * write to the remote share. Let's try again with
141 * access(W_OK) which is more reliable, at least sometimes. */
142 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
148 int files_same(const char *filea
, const char *fileb
, int flags
) {
154 if (fstatat(AT_FDCWD
, filea
, &a
, flags
) < 0)
157 if (fstatat(AT_FDCWD
, fileb
, &b
, flags
) < 0)
160 return a
.st_dev
== b
.st_dev
&&
161 a
.st_ino
== b
.st_ino
;
164 bool is_fs_type(const struct statfs
*s
, statfs_f_type_t magic_value
) {
166 assert_cc(sizeof(statfs_f_type_t
) >= sizeof(s
->f_type
));
168 return F_TYPE_EQUAL(s
->f_type
, magic_value
);
171 int fd_is_fs_type(int fd
, statfs_f_type_t magic_value
) {
174 if (fstatfs(fd
, &s
) < 0)
177 return is_fs_type(&s
, magic_value
);
180 int path_is_fs_type(const char *path
, statfs_f_type_t magic_value
) {
181 _cleanup_close_
int fd
= -1;
183 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
187 return fd_is_fs_type(fd
, magic_value
);
190 bool is_temporary_fs(const struct statfs
*s
) {
191 return is_fs_type(s
, TMPFS_MAGIC
) ||
192 is_fs_type(s
, RAMFS_MAGIC
);
195 bool is_network_fs(const struct statfs
*s
) {
196 return is_fs_type(s
, CIFS_MAGIC_NUMBER
) ||
197 is_fs_type(s
, CODA_SUPER_MAGIC
) ||
198 is_fs_type(s
, NCP_SUPER_MAGIC
) ||
199 is_fs_type(s
, NFS_SUPER_MAGIC
) ||
200 is_fs_type(s
, SMB_SUPER_MAGIC
) ||
201 is_fs_type(s
, V9FS_MAGIC
) ||
202 is_fs_type(s
, AFS_SUPER_MAGIC
) ||
203 is_fs_type(s
, OCFS2_SUPER_MAGIC
);
206 int fd_is_temporary_fs(int fd
) {
209 if (fstatfs(fd
, &s
) < 0)
212 return is_temporary_fs(&s
);
215 int fd_is_network_fs(int fd
) {
218 if (fstatfs(fd
, &s
) < 0)
221 return is_network_fs(&s
);
224 int path_is_temporary_fs(const char *path
) {
225 _cleanup_close_
int fd
= -1;
227 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
231 return fd_is_temporary_fs(fd
);
234 int stat_verify_regular(const struct stat
*st
) {
237 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
240 if (S_ISDIR(st
->st_mode
))
243 if (S_ISLNK(st
->st_mode
))
246 if (!S_ISREG(st
->st_mode
))
252 int fd_verify_regular(int fd
) {
257 if (fstat(fd
, &st
) < 0)
260 return stat_verify_regular(&st
);
263 int stat_verify_directory(const struct stat
*st
) {
266 if (S_ISLNK(st
->st_mode
))
269 if (!S_ISDIR(st
->st_mode
))
275 int fd_verify_directory(int fd
) {
280 if (fstat(fd
, &st
) < 0)
283 return stat_verify_directory(&st
);
286 int device_path_make_major_minor(mode_t mode
, dev_t devno
, char **ret
) {
289 /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
293 else if (S_ISBLK(mode
))
298 if (asprintf(ret
, "/dev/%s/%u:%u", t
, major(devno
), minor(devno
)) < 0)
304 int device_path_make_canonical(mode_t mode
, dev_t devno
, char **ret
) {
305 _cleanup_free_
char *p
= NULL
;
308 /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
312 if (major(devno
) == 0 && minor(devno
) == 0) {
315 /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
316 * /dev/block/ and /dev/char/, hence we handle them specially here. */
319 s
= strdup("/run/systemd/inaccessible/chr");
320 else if (S_ISBLK(mode
))
321 s
= strdup("/run/systemd/inaccessible/blk");
332 r
= device_path_make_major_minor(mode
, devno
, &p
);
336 return chase_symlinks(p
, NULL
, 0, ret
, NULL
);
339 int device_path_parse_major_minor(const char *path
, mode_t
*ret_mode
, dev_t
*ret_devno
) {
344 /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
345 * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
346 * path cannot be parsed like this. */
348 if (path_equal(path
, "/run/systemd/inaccessible/chr")) {
350 devno
= makedev(0, 0);
351 } else if (path_equal(path
, "/run/systemd/inaccessible/blk")) {
353 devno
= makedev(0, 0);
357 w
= path_startswith(path
, "/dev/block/");
361 w
= path_startswith(path
, "/dev/char/");
368 r
= parse_dev(w
, &devno
);