1 /* SPDX-License-Identifier: LGPL-2.1+ */
6 #include <linux/magic.h>
9 #include <sys/statvfs.h>
10 #include <sys/types.h>
13 #include "alloc-util.h"
14 #include "dirent-util.h"
19 #include "parse-util.h"
20 #include "stat-util.h"
21 #include "string-util.h"
23 int is_symlink(const char *path
) {
28 if (lstat(path
, &info
) < 0)
31 return !!S_ISLNK(info
.st_mode
);
34 int is_dir(const char* path
, bool follow
) {
47 return !!S_ISDIR(st
.st_mode
);
50 int is_dir_fd(int fd
) {
53 if (fstat(fd
, &st
) < 0)
56 return !!S_ISDIR(st
.st_mode
);
59 int is_device_node(const char *path
) {
64 if (lstat(path
, &info
) < 0)
67 return !!(S_ISBLK(info
.st_mode
) || S_ISCHR(info
.st_mode
));
70 int dir_is_empty_at(int dir_fd
, const char *path
) {
71 _cleanup_close_
int fd
= -1;
72 _cleanup_closedir_
DIR *d
= NULL
;
76 fd
= openat(dir_fd
, path
, O_RDONLY
|O_DIRECTORY
|O_CLOEXEC
);
78 fd
= fcntl(fd
, F_DUPFD_CLOEXEC
, 3);
87 FOREACH_DIRENT(de
, d
, return -errno
)
93 bool null_or_empty(struct stat
*st
) {
96 if (S_ISREG(st
->st_mode
) && st
->st_size
<= 0)
99 /* We don't want to hardcode the major/minor of /dev/null,
100 * hence we do a simpler "is this a device node?" check. */
102 if (S_ISCHR(st
->st_mode
) || S_ISBLK(st
->st_mode
))
108 int null_or_empty_path(const char *fn
) {
113 if (stat(fn
, &st
) < 0)
116 return null_or_empty(&st
);
119 int null_or_empty_fd(int fd
) {
124 if (fstat(fd
, &st
) < 0)
127 return null_or_empty(&st
);
130 int path_is_read_only_fs(const char *path
) {
135 if (statvfs(path
, &st
) < 0)
138 if (st
.f_flag
& ST_RDONLY
)
141 /* On NFS, statvfs() might not reflect whether we can actually
142 * write to the remote share. Let's try again with
143 * access(W_OK) which is more reliable, at least sometimes. */
144 if (access(path
, W_OK
) < 0 && errno
== EROFS
)
150 int files_same(const char *filea
, const char *fileb
, int flags
) {
156 if (fstatat(AT_FDCWD
, filea
, &a
, flags
) < 0)
159 if (fstatat(AT_FDCWD
, fileb
, &b
, flags
) < 0)
162 return a
.st_dev
== b
.st_dev
&&
163 a
.st_ino
== b
.st_ino
;
166 bool is_fs_type(const struct statfs
*s
, statfs_f_type_t magic_value
) {
168 assert_cc(sizeof(statfs_f_type_t
) >= sizeof(s
->f_type
));
170 return F_TYPE_EQUAL(s
->f_type
, magic_value
);
173 int fd_is_fs_type(int fd
, statfs_f_type_t magic_value
) {
176 if (fstatfs(fd
, &s
) < 0)
179 return is_fs_type(&s
, magic_value
);
182 int path_is_fs_type(const char *path
, statfs_f_type_t magic_value
) {
183 _cleanup_close_
int fd
= -1;
185 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
189 return fd_is_fs_type(fd
, magic_value
);
192 bool is_temporary_fs(const struct statfs
*s
) {
193 return is_fs_type(s
, TMPFS_MAGIC
) ||
194 is_fs_type(s
, RAMFS_MAGIC
);
197 bool is_network_fs(const struct statfs
*s
) {
198 return is_fs_type(s
, CIFS_MAGIC_NUMBER
) ||
199 is_fs_type(s
, CODA_SUPER_MAGIC
) ||
200 is_fs_type(s
, NCP_SUPER_MAGIC
) ||
201 is_fs_type(s
, NFS_SUPER_MAGIC
) ||
202 is_fs_type(s
, SMB_SUPER_MAGIC
) ||
203 is_fs_type(s
, V9FS_MAGIC
) ||
204 is_fs_type(s
, AFS_SUPER_MAGIC
) ||
205 is_fs_type(s
, OCFS2_SUPER_MAGIC
);
208 int fd_is_temporary_fs(int fd
) {
211 if (fstatfs(fd
, &s
) < 0)
214 return is_temporary_fs(&s
);
217 int fd_is_network_fs(int fd
) {
220 if (fstatfs(fd
, &s
) < 0)
223 return is_network_fs(&s
);
226 int path_is_temporary_fs(const char *path
) {
227 _cleanup_close_
int fd
= -1;
229 fd
= open(path
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_PATH
);
233 return fd_is_temporary_fs(fd
);
236 int stat_verify_regular(const struct stat
*st
) {
239 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
242 if (S_ISDIR(st
->st_mode
))
245 if (S_ISLNK(st
->st_mode
))
248 if (!S_ISREG(st
->st_mode
))
254 int fd_verify_regular(int fd
) {
259 if (fstat(fd
, &st
) < 0)
262 return stat_verify_regular(&st
);
265 int stat_verify_directory(const struct stat
*st
) {
268 if (S_ISLNK(st
->st_mode
))
271 if (!S_ISDIR(st
->st_mode
))
277 int fd_verify_directory(int fd
) {
282 if (fstat(fd
, &st
) < 0)
285 return stat_verify_directory(&st
);
288 int device_path_make_major_minor(mode_t mode
, dev_t devno
, char **ret
) {
291 /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */
295 else if (S_ISBLK(mode
))
300 if (asprintf(ret
, "/dev/%s/%u:%u", t
, major(devno
), minor(devno
)) < 0)
306 int device_path_make_canonical(mode_t mode
, dev_t devno
, char **ret
) {
307 _cleanup_free_
char *p
= NULL
;
310 /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */
314 if (major(devno
) == 0 && minor(devno
) == 0) {
317 /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in
318 * /dev/block/ and /dev/char/, hence we handle them specially here. */
321 s
= strdup("/run/systemd/inaccessible/chr");
322 else if (S_ISBLK(mode
))
323 s
= strdup("/run/systemd/inaccessible/blk");
334 r
= device_path_make_major_minor(mode
, devno
, &p
);
338 return chase_symlinks(p
, NULL
, 0, ret
);
341 int device_path_parse_major_minor(const char *path
, mode_t
*ret_mode
, dev_t
*ret_devno
) {
346 /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/
347 * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device
348 * path cannot be parsed like this. */
350 if (path_equal(path
, "/run/systemd/inaccessible/chr")) {
352 devno
= makedev(0, 0);
353 } else if (path_equal(path
, "/run/systemd/inaccessible/blk")) {
355 devno
= makedev(0, 0);
359 w
= path_startswith(path
, "/dev/block/");
363 w
= path_startswith(path
, "/dev/char/");
370 r
= parse_dev(w
, &devno
);