]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/stat-util.c
Revert "machine: restrict register-machine action again"
[thirdparty/systemd.git] / src / basic / stat-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8fcde012
LP
2
3#include <fcntl.h>
3fc2a440 4#include <linux/magic.h>
8fcde012
LP
5#include <sys/statvfs.h>
6#include <unistd.h>
7
846b3bd6 8#include "alloc-util.h"
f461a28d 9#include "chase.h"
8fcde012 10#include "dirent-util.h"
f4351959 11#include "errno-util.h"
8fcde012 12#include "fd-util.h"
659d1924
ILG
13#include "filesystems.h"
14#include "fs-util.h"
ddfdf86f 15#include "hash-funcs.h"
93a1f792 16#include "log.h"
f663a15a 17#include "mountpoint-util.h"
0c15577a
DDM
18#include "path-util.h"
19#include "siphash24.h"
8fcde012
LP
20#include "stat-util.h"
21#include "string-util.h"
0c15577a 22#include "time-util.h"
8fcde012 23
2560dcbf
MY
24static int verify_stat_at(
25 int fd,
26 const char *path,
27 bool follow,
28 int (*verify_func)(const struct stat *st),
29 bool verify) {
8fcde012 30
2560dcbf
MY
31 struct stat st;
32 int r;
33
34 assert(fd >= 0 || fd == AT_FDCWD);
35 assert(!isempty(path) || !follow);
36 assert(verify_func);
8fcde012 37
2560dcbf
MY
38 if (fstatat(fd, strempty(path), &st,
39 (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
8fcde012
LP
40 return -errno;
41
2560dcbf
MY
42 r = verify_func(&st);
43 return verify ? r : r >= 0;
8fcde012
LP
44}
45
2560dcbf
MY
46int stat_verify_regular(const struct stat *st) {
47 assert(st);
48
49 /* Checks whether the specified stat() structure refers to a regular file. If not returns an
50 * appropriate error code. */
8fcde012 51
2560dcbf
MY
52 if (S_ISDIR(st->st_mode))
53 return -EISDIR;
8fcde012 54
2560dcbf
MY
55 if (S_ISLNK(st->st_mode))
56 return -ELOOP;
57
58 if (!S_ISREG(st->st_mode))
59 return -EBADFD;
8fcde012 60
2560dcbf 61 return 0;
a12e4ade
FB
62}
63
2560dcbf
MY
64int verify_regular_at(int fd, const char *path, bool follow) {
65 return verify_stat_at(fd, path, follow, stat_verify_regular, true);
66}
8fcde012 67
2560dcbf
MY
68int fd_verify_regular(int fd) {
69 assert(fd >= 0);
70 return verify_regular_at(fd, NULL, false);
71}
8fcde012 72
2560dcbf
MY
73int stat_verify_directory(const struct stat *st) {
74 assert(st);
75
76 if (S_ISLNK(st->st_mode))
77 return -ELOOP;
78
79 if (!S_ISDIR(st->st_mode))
80 return -ENOTDIR;
81
82 return 0;
83}
84
85int fd_verify_directory(int fd) {
86 assert(fd >= 0);
87 return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
88}
89
90int is_dir_at(int fd, const char *path, bool follow) {
91 return verify_stat_at(fd, path, follow, stat_verify_directory, false);
92}
93
94int is_dir(const char *path, bool follow) {
95 assert(!isempty(path));
96 return is_dir_at(AT_FDCWD, path, follow);
97}
98
99int stat_verify_symlink(const struct stat *st) {
100 assert(st);
101
102 if (S_ISDIR(st->st_mode))
103 return -EISDIR;
104
105 if (!S_ISLNK(st->st_mode))
106 return -ENOLINK;
107
108 return 0;
109}
110
8be204df
LP
111int fd_verify_symlink(int fd) {
112 return verify_stat_at(fd, /* path= */ NULL, /* follow= */ false, stat_verify_symlink, /* verify= */ true);
113}
114
2560dcbf
MY
115int is_symlink(const char *path) {
116 assert(!isempty(path));
117 return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
118}
119
120int 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
129int fd_verify_linked(int fd) {
130 assert(fd >= 0);
131 return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
132}
133
134int 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}
8fcde012 148
2560dcbf
MY
149int is_device_node(const char *path) {
150 assert(!isempty(path));
151 return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
8fcde012
LP
152}
153
db55bbf2 154int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
254d1313 155 _cleanup_close_ int fd = -EBADF;
db55bbf2
LP
156 struct dirent *buf;
157 size_t m;
8fcde012 158
e4722385
MY
159 fd = xopenat(dir_fd, path, O_DIRECTORY|O_CLOEXEC);
160 if (fd < 0)
161 return fd;
d7c1a15e 162
db55bbf2
LP
163 /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
164 * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
165 * 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of
166 * entries that we end up ignoring. */
167 m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX;
168 buf = alloca(m);
169
170 for (;;) {
171 struct dirent *de;
172 ssize_t n;
173
43aacae8 174 n = getdents64(fd, buf, m);
db55bbf2
LP
175 if (n < 0)
176 return -errno;
177 if (n == 0)
178 break;
8fcde012 179
db55bbf2
LP
180 assert((size_t) n <= m);
181 msan_unpoison(buf, n);
0dbce03c 182
db55bbf2
LP
183 FOREACH_DIRENT_IN_BUFFER(de, buf, n)
184 if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
185 return 0;
186 }
8fcde012
LP
187
188 return 1;
189}
190
9d0fed7b 191bool stat_may_be_dev_null(struct stat *st) {
8fcde012
LP
192 assert(st);
193
29da4193
LP
194 /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
195 * device node?" check. */
8fcde012 196
9d0fed7b
YW
197 return S_ISCHR(st->st_mode);
198}
199
200bool stat_is_empty(struct stat *st) {
201 assert(st);
8fcde012 202
9d0fed7b 203 return S_ISREG(st->st_mode) && st->st_size <= 0;
8fcde012
LP
204}
205
48542eac 206int null_or_empty_path_with_root(const char *fn, const char *root) {
8fcde012 207 struct stat st;
48542eac 208 int r;
8fcde012
LP
209
210 assert(fn);
211
48542eac
ZJS
212 /* A symlink to /dev/null or an empty file?
213 * When looking under root_dir, we can't expect /dev/ to be mounted,
214 * so let's see if the path is a (possibly dangling) symlink to /dev/null. */
215
1934242b 216 if (path_equal(path_startswith(fn, root ?: "/"), "dev/null"))
29da4193
LP
217 return true;
218
f461a28d 219 r = chase_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
48542eac
ZJS
220 if (r < 0)
221 return r;
8fcde012
LP
222
223 return null_or_empty(&st);
224}
225
d30d4488 226int fd_is_read_only_fs(int fd) {
c136be3f 227 struct statfs st;
8fcde012 228
dc1752ea 229 assert(fd >= 0);
8fcde012 230
c136be3f 231 if (fstatfs(fd, &st) < 0)
8fcde012
LP
232 return -errno;
233
c136be3f 234 if (st.f_flags & ST_RDONLY)
8fcde012
LP
235 return true;
236
c136be3f
ZJS
237 if (is_network_fs(&st)) {
238 /* On NFS, fstatfs() might not reflect whether we can actually write to the remote share.
239 * Let's try again with access(W_OK) which is more reliable, at least sometimes. */
240 if (access_fd(fd, W_OK) == -EROFS)
241 return true;
242 }
8fcde012
LP
243
244 return false;
245}
246
dc1752ea 247int path_is_read_only_fs(const char *path) {
a5937dcf 248 _cleanup_close_ int fd = -EBADF;
dc1752ea
YW
249
250 assert(path);
251
252 fd = open(path, O_CLOEXEC | O_PATH);
253 if (fd < 0)
254 return -errno;
255
256 return fd_is_read_only_fs(fd);
257}
258
563e6846 259int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags) {
f663a15a
LP
260 struct stat sta, stb;
261 int r;
8fcde012 262
676ade31 263 assert(fda >= 0 || fda == AT_FDCWD);
676ade31 264 assert(fdb >= 0 || fdb == AT_FDCWD);
f663a15a
LP
265 assert((flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT)) == 0);
266
267 /* Refuse an unset filea or fileb early unless AT_EMPTY_PATH is set */
268 if ((isempty(filea) || isempty(fileb)) && !FLAGS_SET(flags, AT_EMPTY_PATH))
269 return -EINVAL;
270
271 /* Shortcut: comparing the same fd with itself means we can return true */
272 if (fda >= 0 && fda == fdb && isempty(filea) && isempty(fileb) && FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW))
273 return true;
274
275 _cleanup_close_ int pin_a = -EBADF, pin_b = -EBADF;
276 if (!FLAGS_SET(flags, AT_NO_AUTOMOUNT)) {
277 /* Let's try to use the name_to_handle_at() AT_HANDLE_FID API to identify identical
278 * inodes. We have to issue multiple calls on the same file for that (first, to acquire the
279 * FID, and then to check if .st_dev is actually the same). Hence let's pin the inode in
280 * between via O_PATH, unless we already have an fd for it. */
281
282 if (!isempty(filea)) {
283 pin_a = openat(fda, filea, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
284 if (pin_a < 0)
285 return -errno;
286
287 fda = pin_a;
288 filea = NULL;
289 flags |= AT_EMPTY_PATH;
290 }
291
292 if (!isempty(fileb)) {
293 pin_b = openat(fdb, fileb, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
294 if (pin_b < 0)
295 return -errno;
296
297 fdb = pin_b;
298 fileb = NULL;
299 flags |= AT_EMPTY_PATH;
300 }
301
4b11087b 302 int ntha_flags = at_flags_normalize_follow(flags) & (AT_EMPTY_PATH|AT_SYMLINK_FOLLOW);
f663a15a
LP
303 _cleanup_free_ struct file_handle *ha = NULL, *hb = NULL;
304 int mntida = -1, mntidb = -1;
305
306 r = name_to_handle_at_try_fid(
307 fda,
308 filea,
309 &ha,
310 &mntida,
311 ntha_flags);
312 if (r < 0) {
313 if (is_name_to_handle_at_fatal_error(r))
314 return r;
315
316 goto fallback;
317 }
318
319 r = name_to_handle_at_try_fid(
320 fdb,
321 fileb,
322 &hb,
323 &mntidb,
324 ntha_flags);
325 if (r < 0) {
326 if (is_name_to_handle_at_fatal_error(r))
327 return r;
328
329 goto fallback;
330 }
331
332 /* Now compare the two file handles */
333 if (!file_handle_equal(ha, hb))
334 return false;
335
336 /* If the file handles are the same and they come from the same mount ID? Great, then we are
337 * good, they are definitely the same */
338 if (mntida == mntidb)
339 return true;
340
341 /* File handles are the same, they are not on the same mount id. This might either be because
342 * they are on two entirely different file systems, that just happen to have the same FIDs
343 * (because they originally where created off the same disk images), or it could be because
344 * they are located on two distinct bind mounts of the same fs. To check that, let's look at
345 * .st_rdev of the inode. We simply reuse the fallback codepath for that, since it checks
346 * exactly that (it checks slightly more, but we don't care.) */
347 }
8fcde012 348
f663a15a
LP
349fallback:
350 if (fstatat(fda, strempty(filea), &sta, flags) < 0)
351 return log_debug_errno(errno, "Cannot stat %s: %m", strna(filea));
8fcde012 352
f663a15a
LP
353 if (fstatat(fdb, strempty(fileb), &stb, flags) < 0)
354 return log_debug_errno(errno, "Cannot stat %s: %m", strna(fileb));
8fcde012 355
f663a15a 356 return stat_inode_same(&sta, &stb);
8fcde012
LP
357}
358
359bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
360 assert(s);
361 assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
362
363 return F_TYPE_EQUAL(s->f_type, magic_value);
364}
365
b196e17e 366int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
6d965610 367 struct statfs s;
b196e17e 368 int r;
8fcde012 369
b196e17e
DDM
370 r = xstatfsat(dir_fd, path, &s);
371 if (r < 0)
372 return r;
8fcde012 373
6d965610 374 return is_fs_type(&s, magic_value);
8fcde012
LP
375}
376
377bool is_temporary_fs(const struct statfs *s) {
659d1924 378 return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
77f9fa3b
LP
379}
380
381bool is_network_fs(const struct statfs *s) {
659d1924 382 return fs_in_group(s, FILESYSTEM_SET_NETWORK);
8fcde012
LP
383}
384
385int fd_is_temporary_fs(int fd) {
386 struct statfs s;
387
388 if (fstatfs(fd, &s) < 0)
389 return -errno;
390
391 return is_temporary_fs(&s);
392}
ffeb8285 393
77f9fa3b
LP
394int fd_is_network_fs(int fd) {
395 struct statfs s;
396
397 if (fstatfs(fd, &s) < 0)
398 return -errno;
399
400 return is_network_fs(&s);
401}
402
ffeb8285 403int path_is_temporary_fs(const char *path) {
15308e50 404 struct statfs s;
ffeb8285 405
15308e50 406 if (statfs(path, &s) < 0)
ffeb8285
LP
407 return -errno;
408
15308e50 409 return is_temporary_fs(&s);
ffeb8285 410}
3cc44114 411
4e247216
YW
412int path_is_network_fs(const char *path) {
413 struct statfs s;
414
415 if (statfs(path, &s) < 0)
416 return -errno;
417
418 return is_network_fs(&s);
419}
420
883fff25
LP
421int proc_mounted(void) {
422 int r;
423
424 /* A quick check of procfs is properly mounted */
425
426 r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
427 if (r == -ENOENT) /* not mounted at all */
428 return false;
429
430 return r;
431}
fee5c52a 432
38db6211
LP
433bool stat_inode_same(const struct stat *a, const struct stat *b) {
434
435 /* Returns if the specified stat structure references the same (though possibly modified) inode. Does
436 * a thorough check, comparing inode nr, backing device and if the inode is still of the same type. */
437
1c248d7f 438 return stat_is_set(a) && stat_is_set(b) &&
38db6211
LP
439 ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 && /* same inode type */
440 a->st_dev == b->st_dev &&
441 a->st_ino == b->st_ino;
442}
443
fee5c52a
LP
444bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
445
446 /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
447 * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
448 * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
449 * size, backing device, inode type and if this refers to a device not the major/minor.
450 *
451 * Note that we don't care if file attributes such as ownership or access mode change, this here is
452 * about contents of the file. The purpose here is to detect file contents changes, and nothing
453 * else. */
454
38db6211 455 return stat_inode_same(a, b) &&
a59b0a9f
MS
456 a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
457 a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
fee5c52a 458 (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
fee5c52a
LP
459 (!(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 */
460}
ca194a2a 461
2bd315fb
LP
462bool statx_inode_same(const struct statx *a, const struct statx *b) {
463
464 /* Same as stat_inode_same() but for struct statx */
465
1c248d7f 466 return statx_is_set(a) && statx_is_set(b) &&
2bd315fb 467 FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) &&
2bd315fb
LP
468 ((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 &&
469 a->stx_dev_major == b->stx_dev_major &&
470 a->stx_dev_minor == b->stx_dev_minor &&
471 a->stx_ino == b->stx_ino;
472}
473
4424e6c8
YW
474bool statx_mount_same(const struct statx *a, const struct statx *b) {
475 if (!statx_is_set(a) || !statx_is_set(b))
52f19d96
LP
476 return false;
477
478 /* if we have the mount ID, that's all we need */
479 if (FLAGS_SET(a->stx_mask, STATX_MNT_ID) && FLAGS_SET(b->stx_mask, STATX_MNT_ID))
480 return a->stx_mnt_id == b->stx_mnt_id;
481
482 /* Otherwise, major/minor of backing device must match */
483 return a->stx_dev_major == b->stx_dev_major &&
484 a->stx_dev_minor == b->stx_dev_minor;
485}
486
6eec59f9
DDM
487int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
488 _cleanup_close_ int fd = -EBADF;
489
490 assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
6eec59f9
DDM
491 assert(ret);
492
99d704c6
YW
493 if (!isempty(path)) {
494 fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
495 if (fd < 0)
496 return fd;
497 dir_fd = fd;
498 }
6eec59f9 499
99d704c6 500 return RET_NERRNO(fstatfs(dir_fd, ret));
6eec59f9
DDM
501}
502
0c15577a
DDM
503usec_t statx_timestamp_load(const struct statx_timestamp *ts) {
504 return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
505}
506nsec_t statx_timestamp_load_nsec(const struct statx_timestamp *ts) {
507 return timespec_load_nsec(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
508}
509
ddfdf86f 510void inode_hash_func(const struct stat *q, struct siphash *state) {
c01a5c05
YW
511 siphash24_compress_typesafe(q->st_dev, state);
512 siphash24_compress_typesafe(q->st_ino, state);
ddfdf86f
DDM
513}
514
515int inode_compare_func(const struct stat *a, const struct stat *b) {
516 int r;
517
518 r = CMP(a->st_dev, b->st_dev);
519 if (r != 0)
520 return r;
521
522 return CMP(a->st_ino, b->st_ino);
523}
524
525DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
d83ce136
LP
526
527const char* inode_type_to_string(mode_t m) {
528
529 /* Returns a short string for the inode type. We use the same name as the underlying macros for each
530 * inode type. */
531
532 switch (m & S_IFMT) {
533 case S_IFREG:
534 return "reg";
535 case S_IFDIR:
536 return "dir";
e83fbf4b
LP
537 case S_IFLNK:
538 return "lnk";
d83ce136
LP
539 case S_IFCHR:
540 return "chr";
541 case S_IFBLK:
542 return "blk";
543 case S_IFIFO:
544 return "fifo";
545 case S_IFSOCK:
546 return "sock";
547 }
548
f03caa0d 549 /* Note anonymous inodes in the kernel will have a zero type. Hence fstat() of an eventfd() will
7cff2b79 550 * return an .st_mode where we'll return NULL here! */
d83ce136
LP
551 return NULL;
552}
cc037880
LP
553
554mode_t inode_type_from_string(const char *s) {
555 if (!s)
556 return MODE_INVALID;
557
558 if (streq(s, "reg"))
559 return S_IFREG;
560 if (streq(s, "dir"))
561 return S_IFDIR;
562 if (streq(s, "lnk"))
563 return S_IFLNK;
564 if (streq(s, "chr"))
565 return S_IFCHR;
566 if (streq(s, "blk"))
567 return S_IFBLK;
568 if (streq(s, "fifo"))
569 return S_IFIFO;
570 if (streq(s, "sock"))
571 return S_IFSOCK;
572
573 return MODE_INVALID;
574}