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