]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/stat-util.c
logs-show: use journal_add_matchf() and journal_add_match_pair()
[thirdparty/systemd.git] / src / basic / stat-util.c
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.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 "hash-funcs.h"
19 #include "macro.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"
27
28 static int verify_stat_at(
29 int fd,
30 const char *path,
31 bool follow,
32 int (*verify_func)(const struct stat *st),
33 bool verify) {
34
35 struct stat st;
36 int r;
37
38 assert(fd >= 0 || fd == AT_FDCWD);
39 assert(!isempty(path) || !follow);
40 assert(verify_func);
41
42 if (fstatat(fd, strempty(path), &st,
43 (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
44 return -errno;
45
46 r = verify_func(&st);
47 return verify ? r : r >= 0;
48 }
49
50 int stat_verify_regular(const struct stat *st) {
51 assert(st);
52
53 /* Checks whether the specified stat() structure refers to a regular file. If not returns an
54 * appropriate error code. */
55
56 if (S_ISDIR(st->st_mode))
57 return -EISDIR;
58
59 if (S_ISLNK(st->st_mode))
60 return -ELOOP;
61
62 if (!S_ISREG(st->st_mode))
63 return -EBADFD;
64
65 return 0;
66 }
67
68 int verify_regular_at(int fd, const char *path, bool follow) {
69 return verify_stat_at(fd, path, follow, stat_verify_regular, true);
70 }
71
72 int fd_verify_regular(int fd) {
73 assert(fd >= 0);
74 return verify_regular_at(fd, NULL, false);
75 }
76
77 int stat_verify_directory(const struct stat *st) {
78 assert(st);
79
80 if (S_ISLNK(st->st_mode))
81 return -ELOOP;
82
83 if (!S_ISDIR(st->st_mode))
84 return -ENOTDIR;
85
86 return 0;
87 }
88
89 int fd_verify_directory(int fd) {
90 assert(fd >= 0);
91 return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
92 }
93
94 int is_dir_at(int fd, const char *path, bool follow) {
95 return verify_stat_at(fd, path, follow, stat_verify_directory, false);
96 }
97
98 int is_dir(const char *path, bool follow) {
99 assert(!isempty(path));
100 return is_dir_at(AT_FDCWD, path, follow);
101 }
102
103 int stat_verify_symlink(const struct stat *st) {
104 assert(st);
105
106 if (S_ISDIR(st->st_mode))
107 return -EISDIR;
108
109 if (!S_ISLNK(st->st_mode))
110 return -ENOLINK;
111
112 return 0;
113 }
114
115 int is_symlink(const char *path) {
116 assert(!isempty(path));
117 return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
118 }
119
120 int stat_verify_linked(const struct stat *st) {
121 assert(st);
122
123 if (st->st_nlink <= 0)
124 return -EIDRM; /* recognizable error. */
125
126 return 0;
127 }
128
129 int fd_verify_linked(int fd) {
130 assert(fd >= 0);
131 return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
132 }
133
134 int stat_verify_device_node(const struct stat *st) {
135 assert(st);
136
137 if (S_ISLNK(st->st_mode))
138 return -ELOOP;
139
140 if (S_ISDIR(st->st_mode))
141 return -EISDIR;
142
143 if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
144 return -ENOTTY;
145
146 return 0;
147 }
148
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);
152 }
153
154 int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
155 _cleanup_close_ int fd = -EBADF;
156 struct dirent *buf;
157 size_t m;
158
159 if (path) {
160 assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
161
162 fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
163 if (fd < 0)
164 return -errno;
165 } else if (dir_fd == AT_FDCWD) {
166 fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
167 if (fd < 0)
168 return -errno;
169 } else {
170 /* Note that DUPing is not enough, as the internal pointer would still be shared and moved
171 * getedents64(). */
172 assert(dir_fd >= 0);
173
174 fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
175 if (fd < 0)
176 return fd;
177 }
178
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;
184 buf = alloca(m);
185
186 for (;;) {
187 struct dirent *de;
188 ssize_t n;
189
190 n = getdents64(fd, buf, m);
191 if (n < 0)
192 return -errno;
193 if (n == 0)
194 break;
195
196 assert((size_t) n <= m);
197 msan_unpoison(buf, n);
198
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)))
201 return 0;
202 }
203
204 return 1;
205 }
206
207 bool null_or_empty(struct stat *st) {
208 assert(st);
209
210 if (S_ISREG(st->st_mode) && st->st_size <= 0)
211 return true;
212
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. */
215
216 if (S_ISCHR(st->st_mode))
217 return true;
218
219 return false;
220 }
221
222 int null_or_empty_path_with_root(const char *fn, const char *root) {
223 struct stat st;
224 int r;
225
226 assert(fn);
227
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. */
231
232 if (path_equal_ptr(path_startswith(fn, root ?: "/"), "dev/null"))
233 return true;
234
235 r = chase_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
236 if (r < 0)
237 return r;
238
239 return null_or_empty(&st);
240 }
241
242 int fd_is_read_only_fs(int fd) {
243 struct statvfs st;
244
245 assert(fd >= 0);
246
247 if (fstatvfs(fd, &st) < 0)
248 return -errno;
249
250 if (st.f_flag & ST_RDONLY)
251 return true;
252
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)
256 return true;
257
258 return false;
259 }
260
261 int path_is_read_only_fs(const char *path) {
262 _cleanup_close_ int fd = -EBADF;
263
264 assert(path);
265
266 fd = open(path, O_CLOEXEC | O_PATH);
267 if (fd < 0)
268 return -errno;
269
270 return fd_is_read_only_fs(fd);
271 }
272
273 int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags) {
274 struct stat a, b;
275
276 assert(fda >= 0 || fda == AT_FDCWD);
277 assert(fdb >= 0 || fdb == AT_FDCWD);
278
279 if (fstatat(fda, strempty(filea), &a, flags) < 0)
280 return log_debug_errno(errno, "Cannot stat %s: %m", filea);
281
282 if (fstatat(fdb, strempty(fileb), &b, flags) < 0)
283 return log_debug_errno(errno, "Cannot stat %s: %m", fileb);
284
285 return stat_inode_same(&a, &b);
286 }
287
288 bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
289 assert(s);
290 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
291
292 return F_TYPE_EQUAL(s->f_type, magic_value);
293 }
294
295 int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
296 struct statfs s;
297 int r;
298
299 r = xstatfsat(dir_fd, path, &s);
300 if (r < 0)
301 return r;
302
303 return is_fs_type(&s, magic_value);
304 }
305
306 bool is_temporary_fs(const struct statfs *s) {
307 return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
308 }
309
310 bool is_network_fs(const struct statfs *s) {
311 return fs_in_group(s, FILESYSTEM_SET_NETWORK);
312 }
313
314 int fd_is_temporary_fs(int fd) {
315 struct statfs s;
316
317 if (fstatfs(fd, &s) < 0)
318 return -errno;
319
320 return is_temporary_fs(&s);
321 }
322
323 int fd_is_network_fs(int fd) {
324 struct statfs s;
325
326 if (fstatfs(fd, &s) < 0)
327 return -errno;
328
329 return is_network_fs(&s);
330 }
331
332 int path_is_temporary_fs(const char *path) {
333 struct statfs s;
334
335 if (statfs(path, &s) < 0)
336 return -errno;
337
338 return is_temporary_fs(&s);
339 }
340
341 int path_is_network_fs(const char *path) {
342 struct statfs s;
343
344 if (statfs(path, &s) < 0)
345 return -errno;
346
347 return is_network_fs(&s);
348 }
349
350 int proc_mounted(void) {
351 int r;
352
353 /* A quick check of procfs is properly mounted */
354
355 r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
356 if (r == -ENOENT) /* not mounted at all */
357 return false;
358
359 return r;
360 }
361
362 bool stat_inode_same(const struct stat *a, const struct stat *b) {
363
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. */
366
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;
371 }
372
373 bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
374
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.
379 *
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
382 * else. */
383
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 */
389 }
390
391 bool statx_inode_same(const struct statx *a, const struct statx *b) {
392
393 /* Same as stat_inode_same() but for struct statx */
394
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;
401 }
402
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))
405 return false;
406
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;
410
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;
414 }
415
416 static bool is_statx_fatal_error(int err, int flags) {
417 assert(err < 0);
418
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)
423 return false;
424
425 /* When unsupported flags are specified, glibc's fallback function returns -EINVAL.
426 * See statx_generic() in glibc. */
427 if (err != -EINVAL)
428 return true;
429
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. */
432
433 return true;
434 }
435
436 int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct statx *sx) {
437 static bool avoid_statx = false;
438 struct stat st;
439 int r;
440
441 if (!avoid_statx) {
442 r = RET_NERRNO(statx(dfd, path, flags, mask, sx));
443 if (r >= 0 || is_statx_fatal_error(r, flags))
444 return r;
445
446 avoid_statx = true;
447 }
448
449 /* Only do fallback if fstatat() supports the flag too, or if it's one of the sync flags, which are
450 * OK to ignore */
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)
453 return -EOPNOTSUPP;
454
455 if (fstatat(dfd, path, &st, flags & (AT_EMPTY_PATH|AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW)) < 0)
456 return -errno;
457
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,
481 };
482
483 return 0;
484 }
485
486 int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
487 _cleanup_close_ int fd = -EBADF;
488
489 assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
490 assert(ret);
491
492 fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
493 if (fd < 0)
494 return fd;
495
496 return RET_NERRNO(fstatfs(fd, ret));
497 }
498
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);
502 }
503
504 int inode_compare_func(const struct stat *a, const struct stat *b) {
505 int r;
506
507 r = CMP(a->st_dev, b->st_dev);
508 if (r != 0)
509 return r;
510
511 return CMP(a->st_ino, b->st_ino);
512 }
513
514 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
515
516 const char* inode_type_to_string(mode_t m) {
517
518 /* Returns a short string for the inode type. We use the same name as the underlying macros for each
519 * inode type. */
520
521 switch (m & S_IFMT) {
522 case S_IFREG:
523 return "reg";
524 case S_IFDIR:
525 return "dir";
526 case S_IFLNK:
527 return "lnk";
528 case S_IFCHR:
529 return "chr";
530 case S_IFBLK:
531 return "blk";
532 case S_IFIFO:
533 return "fifo";
534 case S_IFSOCK:
535 return "sock";
536 }
537
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! */
540 return NULL;
541 }
542
543 mode_t inode_type_from_string(const char *s) {
544 if (!s)
545 return MODE_INVALID;
546
547 if (streq(s, "reg"))
548 return S_IFREG;
549 if (streq(s, "dir"))
550 return S_IFDIR;
551 if (streq(s, "lnk"))
552 return S_IFLNK;
553 if (streq(s, "chr"))
554 return S_IFCHR;
555 if (streq(s, "blk"))
556 return S_IFBLK;
557 if (streq(s, "fifo"))
558 return S_IFIFO;
559 if (streq(s, "sock"))
560 return S_IFSOCK;
561
562 return MODE_INVALID;
563 }