1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <sched.h>
6 #include <sys/statvfs.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9
10 #include "alloc-util.h"
11 #include "chase-symlinks.h"
12 #include "dirent-util.h"
13 #include "errno-util.h"
14 #include "fd-util.h"
15 #include "fileio.h"
16 #include "filesystems.h"
17 #include "fs-util.h"
18 #include "macro.h"
19 #include "missing_fs.h"
20 #include "missing_magic.h"
21 #include "missing_syscall.h"
22 #include "nulstr-util.h"
23 #include "parse-util.h"
24 #include "stat-util.h"
25 #include "string-util.h"
26
is_symlink(const char * path)27 int is_symlink(const char *path) {
28 struct stat info;
29
30 assert(path);
31
32 if (lstat(path, &info) < 0)
33 return -errno;
34
35 return !!S_ISLNK(info.st_mode);
36 }
37
is_dir(const char * path,bool follow)38 int is_dir(const char* path, bool follow) {
39 struct stat st;
40 int r;
41
42 assert(path);
43
44 if (follow)
45 r = stat(path, &st);
46 else
47 r = lstat(path, &st);
48 if (r < 0)
49 return -errno;
50
51 return !!S_ISDIR(st.st_mode);
52 }
53
is_dir_fd(int fd)54 int is_dir_fd(int fd) {
55 struct stat st;
56
57 if (fstat(fd, &st) < 0)
58 return -errno;
59
60 return !!S_ISDIR(st.st_mode);
61 }
62
is_device_node(const char * path)63 int is_device_node(const char *path) {
64 struct stat info;
65
66 assert(path);
67
68 if (lstat(path, &info) < 0)
69 return -errno;
70
71 return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
72 }
73
dir_is_empty_at(int dir_fd,const char * path,bool ignore_hidden_or_backup)74 int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
75 _cleanup_close_ int fd = -1;
76 struct dirent *buf;
77 size_t m;
78
79 if (path) {
80 assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
81
82 fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
83 if (fd < 0)
84 return -errno;
85 } else if (dir_fd == AT_FDCWD) {
86 fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
87 if (fd < 0)
88 return -errno;
89 } else {
90 /* Note that DUPing is not enough, as the internal pointer would still be shared and moved
91 * getedents64(). */
92 assert(dir_fd >= 0);
93
94 fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
95 if (fd < 0)
96 return fd;
97 }
98
99 /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
100 * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
101 * 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
102 * entries that we end up ignoring. */
103 m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX;
104 buf = alloca(m);
105
106 for (;;) {
107 struct dirent *de;
108 ssize_t n;
109
110 n = getdents64(fd, buf, m);
111 if (n < 0)
112 return -errno;
113 if (n == 0)
114 break;
115
116 assert((size_t) n <= m);
117 msan_unpoison(buf, n);
118
119 FOREACH_DIRENT_IN_BUFFER(de, buf, n)
120 if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
121 return 0;
122 }
123
124 return 1;
125 }
126
null_or_empty(struct stat * st)127 bool null_or_empty(struct stat *st) {
128 assert(st);
129
130 if (S_ISREG(st->st_mode) && st->st_size <= 0)
131 return true;
132
133 /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
134 * device node?" check. */
135
136 if (S_ISCHR(st->st_mode))
137 return true;
138
139 return false;
140 }
141
null_or_empty_path_with_root(const char * fn,const char * root)142 int null_or_empty_path_with_root(const char *fn, const char *root) {
143 struct stat st;
144 int r;
145
146 assert(fn);
147
148 /* A symlink to /dev/null or an empty file?
149 * When looking under root_dir, we can't expect /dev/ to be mounted,
150 * so let's see if the path is a (possibly dangling) symlink to /dev/null. */
151
152 if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
153 return true;
154
155 r = chase_symlinks_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st, NULL);
156 if (r < 0)
157 return r;
158
159 return null_or_empty(&st);
160 }
161
null_or_empty_fd(int fd)162 int null_or_empty_fd(int fd) {
163 struct stat st;
164
165 assert(fd >= 0);
166
167 if (fstat(fd, &st) < 0)
168 return -errno;
169
170 return null_or_empty(&st);
171 }
172
path_is_read_only_fs(const char * path)173 int path_is_read_only_fs(const char *path) {
174 struct statvfs st;
175
176 assert(path);
177
178 if (statvfs(path, &st) < 0)
179 return -errno;
180
181 if (st.f_flag & ST_RDONLY)
182 return true;
183
184 /* On NFS, statvfs() might not reflect whether we can actually
185 * write to the remote share. Let's try again with
186 * access(W_OK) which is more reliable, at least sometimes. */
187 if (access(path, W_OK) < 0 && errno == EROFS)
188 return true;
189
190 return false;
191 }
192
files_same(const char * filea,const char * fileb,int flags)193 int files_same(const char *filea, const char *fileb, int flags) {
194 struct stat a, b;
195
196 assert(filea);
197 assert(fileb);
198
199 if (fstatat(AT_FDCWD, filea, &a, flags) < 0)
200 return -errno;
201
202 if (fstatat(AT_FDCWD, fileb, &b, flags) < 0)
203 return -errno;
204
205 return stat_inode_same(&a, &b);
206 }
207
is_fs_type(const struct statfs * s,statfs_f_type_t magic_value)208 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
209 assert(s);
210 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
211
212 return F_TYPE_EQUAL(s->f_type, magic_value);
213 }
214
fd_is_fs_type(int fd,statfs_f_type_t magic_value)215 int fd_is_fs_type(int fd, statfs_f_type_t magic_value) {
216 struct statfs s;
217
218 if (fstatfs(fd, &s) < 0)
219 return -errno;
220
221 return is_fs_type(&s, magic_value);
222 }
223
path_is_fs_type(const char * path,statfs_f_type_t magic_value)224 int path_is_fs_type(const char *path, statfs_f_type_t magic_value) {
225 struct statfs s;
226
227 if (statfs(path, &s) < 0)
228 return -errno;
229
230 return is_fs_type(&s, magic_value);
231 }
232
is_temporary_fs(const struct statfs * s)233 bool is_temporary_fs(const struct statfs *s) {
234 return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
235 }
236
is_network_fs(const struct statfs * s)237 bool is_network_fs(const struct statfs *s) {
238 return fs_in_group(s, FILESYSTEM_SET_NETWORK);
239 }
240
fd_is_temporary_fs(int fd)241 int fd_is_temporary_fs(int fd) {
242 struct statfs s;
243
244 if (fstatfs(fd, &s) < 0)
245 return -errno;
246
247 return is_temporary_fs(&s);
248 }
249
fd_is_network_fs(int fd)250 int fd_is_network_fs(int fd) {
251 struct statfs s;
252
253 if (fstatfs(fd, &s) < 0)
254 return -errno;
255
256 return is_network_fs(&s);
257 }
258
path_is_temporary_fs(const char * path)259 int path_is_temporary_fs(const char *path) {
260 struct statfs s;
261
262 if (statfs(path, &s) < 0)
263 return -errno;
264
265 return is_temporary_fs(&s);
266 }
267
path_is_network_fs(const char * path)268 int path_is_network_fs(const char *path) {
269 struct statfs s;
270
271 if (statfs(path, &s) < 0)
272 return -errno;
273
274 return is_network_fs(&s);
275 }
276
stat_verify_regular(const struct stat * st)277 int stat_verify_regular(const struct stat *st) {
278 assert(st);
279
280 /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error
281 * code. */
282
283 if (S_ISDIR(st->st_mode))
284 return -EISDIR;
285
286 if (S_ISLNK(st->st_mode))
287 return -ELOOP;
288
289 if (!S_ISREG(st->st_mode))
290 return -EBADFD;
291
292 return 0;
293 }
294
fd_verify_regular(int fd)295 int fd_verify_regular(int fd) {
296 struct stat st;
297
298 assert(fd >= 0);
299
300 if (fstat(fd, &st) < 0)
301 return -errno;
302
303 return stat_verify_regular(&st);
304 }
305
stat_verify_directory(const struct stat * st)306 int stat_verify_directory(const struct stat *st) {
307 assert(st);
308
309 if (S_ISLNK(st->st_mode))
310 return -ELOOP;
311
312 if (!S_ISDIR(st->st_mode))
313 return -ENOTDIR;
314
315 return 0;
316 }
317
fd_verify_directory(int fd)318 int fd_verify_directory(int fd) {
319 struct stat st;
320
321 assert(fd >= 0);
322
323 if (fstat(fd, &st) < 0)
324 return -errno;
325
326 return stat_verify_directory(&st);
327 }
328
proc_mounted(void)329 int proc_mounted(void) {
330 int r;
331
332 /* A quick check of procfs is properly mounted */
333
334 r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
335 if (r == -ENOENT) /* not mounted at all */
336 return false;
337
338 return r;
339 }
340
stat_inode_same(const struct stat * a,const struct stat * b)341 bool stat_inode_same(const struct stat *a, const struct stat *b) {
342
343 /* Returns if the specified stat structure references the same (though possibly modified) inode. Does
344 * a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
345
346 return a && b &&
347 (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
348 ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
349 a->st_dev == b->st_dev &&
350 a->st_ino == b->st_ino;
351 }
352
stat_inode_unmodified(const struct stat * a,const struct stat * b)353 bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
354
355 /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
356 * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
357 * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
358 * size, backing device, inode type and if this refers to a device not the major/minor.
359 *
360 * Note that we don't care if file attributes such as ownership or access mode change, this here is
361 * about contents of the file. The purpose here is to detect file contents changes, and nothing
362 * else. */
363
364 return stat_inode_same(a, b) &&
365 a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
366 a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
367 (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
368 (!(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 */
369 }
370
statx_fallback(int dfd,const char * path,int flags,unsigned mask,struct statx * sx)371 int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
372 static bool avoid_statx = false;
373 struct stat st;
374
375 if (!avoid_statx) {
376 if (statx(dfd, path, flags, mask, sx) < 0) {
377 if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EPERM)
378 return -errno;
379
380 /* If statx() is not supported or if we see EPERM (which might indicate seccomp
381 * filtering or so), let's do a fallback. Not that on EACCES we'll not fall back,
382 * since that is likely an indication of fs access issues, which we should
383 * propagate */
384 } else
385 return 0;
386
387 avoid_statx = true;
388 }
389
390 /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
391 * OK to ignore */
392 if ((flags & ~(AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW|
393 AT_STATX_SYNC_AS_STAT|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC)) != 0)
394 return -EOPNOTSUPP;
395
396 if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0)
397 return -errno;
398
399 *sx = (struct statx) {
400 .stx_mask = STATX_TYPE|STATX_MODE|
401 STATX_NLINK|STATX_UID|STATX_GID|
402 STATX_ATIME|STATX_MTIME|STATX_CTIME|
403 STATX_INO|STATX_SIZE|STATX_BLOCKS,
404 .stx_blksize = st.st_blksize,
405 .stx_nlink = st.st_nlink,
406 .stx_uid = st.st_uid,
407 .stx_gid = st.st_gid,
408 .stx_mode = st.st_mode,
409 .stx_ino = st.st_ino,
410 .stx_size = st.st_size,
411 .stx_blocks = st.st_blocks,
412 .stx_rdev_major = major(st.st_rdev),
413 .stx_rdev_minor = minor(st.st_rdev),
414 .stx_dev_major = major(st.st_dev),
415 .stx_dev_minor = minor(st.st_dev),
416 .stx_atime.tv_sec = st.st_atim.tv_sec,
417 .stx_atime.tv_nsec = st.st_atim.tv_nsec,
418 .stx_mtime.tv_sec = st.st_mtim.tv_sec,
419 .stx_mtime.tv_nsec = st.st_mtim.tv_nsec,
420 .stx_ctime.tv_sec = st.st_ctim.tv_sec,
421 .stx_ctime.tv_nsec = st.st_ctim.tv_nsec,
422 };
423
424 return 0;
425 }
426