• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15263807472

26 May 2025 08:53PM UTC coverage: 72.046% (-0.002%) from 72.048%
15263807472

push

github

yuwata
src/core/manager.c: log preset activity on first boot

This gives us a little more information about what units were enabled
or disabled on that first boot and will be useful for OS developers
tracking down the source of unit state.

An example with this enabled looks like:

```
NET: Registered PF_VSOCK protocol family
systemd[1]: Applying preset policy.
systemd[1]: Unit /etc/systemd/system/dnsmasq.service is masked, ignoring.
systemd[1]: Unit /etc/systemd/system/systemd-repart.service is masked, ignoring.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket'.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir.mount' → '/etc/systemd/system/var-mnt-workdir.mount'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir\x2dtmp.mount' → '/etc/systemd/system/var-mnt-workdir\x2dtmp.mount'.
systemd[1]: Created symlink '/etc/systemd/system/afterburn-sshkeys.target.requires/afterburn-sshkeys@core.service' → '/usr/lib/systemd/system/afterburn-sshkeys@.service'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket' → '/usr/lib/systemd/system/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
systemd[1]: Populated /etc with preset unit settings.
```

Considering it only happens on first boot and not on every boot I think
the extra information is worth the extra verbosity in the logs just for
that boot.

5 of 6 new or added lines in 1 file covered. (83.33%)

5463 existing lines in 165 files now uncovered.

299151 of 415222 relevant lines covered (72.05%)

702386.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.4
/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(
2,181,995✔
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;
2,181,995✔
32
        int r;
2,181,995✔
33

34
        assert(fd >= 0 || fd == AT_FDCWD);
2,181,995✔
35
        assert(!isempty(path) || !follow);
2,181,995✔
36
        assert(verify_func);
2,181,995✔
37

38
        if (fstatat(fd, strempty(path), &st,
5,189,411✔
39
                    (isempty(path) ? AT_EMPTY_PATH : 0) | (follow ? 0 : AT_SYMLINK_NOFOLLOW)) < 0)
2,181,995✔
40
                return -errno;
7,721✔
41

42
        r = verify_func(&st);
2,174,274✔
43
        return verify ? r : r >= 0;
2,174,274✔
44
}
45

46
int stat_verify_regular(const struct stat *st) {
2,659,355✔
47
        assert(st);
2,659,355✔
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))
2,659,355✔
53
                return -EISDIR;
54

55
        if (S_ISLNK(st->st_mode))
2,657,167✔
56
                return -ELOOP;
57

58
        if (!S_ISREG(st->st_mode))
2,657,153✔
59
                return -EBADFD;
17✔
60

61
        return 0;
62
}
63

64
int verify_regular_at(int fd, const char *path, bool follow) {
825,666✔
65
        return verify_stat_at(fd, path, follow, stat_verify_regular, true);
825,666✔
66
}
67

68
int fd_verify_regular(int fd) {
825,401✔
69
        assert(fd >= 0);
825,401✔
70
        return verify_regular_at(fd, NULL, false);
825,401✔
71
}
72

73
int stat_verify_directory(const struct stat *st) {
1,375,553✔
74
        assert(st);
1,375,553✔
75

76
        if (S_ISLNK(st->st_mode))
1,375,553✔
77
                return -ELOOP;
78

79
        if (!S_ISDIR(st->st_mode))
1,375,543✔
80
                return -ENOTDIR;
8✔
81

82
        return 0;
83
}
84

85
int fd_verify_directory(int fd) {
17✔
86
        assert(fd >= 0);
17✔
87
        return verify_stat_at(fd, NULL, false, stat_verify_directory, true);
17✔
88
}
89

90
int is_dir_at(int fd, const char *path, bool follow) {
1,340,595✔
91
        return verify_stat_at(fd, path, follow, stat_verify_directory, false);
1,340,595✔
92
}
93

94
int is_dir(const char *path, bool follow) {
499,782✔
95
        assert(!isempty(path));
499,782✔
96
        return is_dir_at(AT_FDCWD, path, follow);
499,782✔
97
}
98

99
int stat_verify_symlink(const struct stat *st) {
15,602✔
100
        assert(st);
15,602✔
101

102
        if (S_ISDIR(st->st_mode))
15,602✔
103
                return -EISDIR;
104

105
        if (!S_ISLNK(st->st_mode))
15,587✔
106
                return -ENOLINK;
428✔
107

108
        return 0;
109
}
110

111
int is_symlink(const char *path) {
15,602✔
112
        assert(!isempty(path));
15,602✔
113
        return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);
15,602✔
114
}
115

116
int stat_verify_linked(const struct stat *st) {
1,804,987✔
117
        assert(st);
1,804,987✔
118

119
        if (st->st_nlink <= 0)
1,804,987✔
120
                return -EIDRM; /* recognizable error. */
2✔
121

122
        return 0;
123
}
124

125
int fd_verify_linked(int fd) {
3✔
126
        assert(fd >= 0);
3✔
127
        return verify_stat_at(fd, NULL, false, stat_verify_linked, true);
3✔
128
}
129

130
int stat_verify_device_node(const struct stat *st) {
4,599✔
131
        assert(st);
4,599✔
132

133
        if (S_ISLNK(st->st_mode))
4,599✔
134
                return -ELOOP;
135

136
        if (S_ISDIR(st->st_mode))
4,599✔
137
                return -EISDIR;
138

139
        if (!S_ISBLK(st->st_mode) && !S_ISCHR(st->st_mode))
4,495✔
140
                return -ENOTTY;
5✔
141

142
        return 0;
143
}
144

145
int is_device_node(const char *path) {
112✔
146
        assert(!isempty(path));
112✔
147
        return verify_stat_at(AT_FDCWD, path, false, stat_verify_device_node, false);
112✔
148
}
149

150
int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) {
36,786✔
151
        _cleanup_close_ int fd = -EBADF;
36,786✔
152
        struct dirent *buf;
36,786✔
153
        size_t m;
36,786✔
154

155
        fd = xopenat(dir_fd, path, O_DIRECTORY|O_CLOEXEC);
36,786✔
156
        if (fd < 0)
36,786✔
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;
2,179✔
164
        buf = alloca(m);
2,179✔
165

166
        for (;;) {
3,500✔
167
                struct dirent *de;
3,500✔
168
                ssize_t n;
3,500✔
169

170
                n = posix_getdents(fd, buf, m, /* flags = */ 0);
3,500✔
171
                if (n < 0)
3,500✔
UNCOV
172
                        return -errno;
×
173
                if (n == 0)
3,500✔
174
                        break;
175

176
                assert((size_t) n <= m);
2,179✔
177
                msan_unpoison(buf, n);
2,179✔
178

179
                FOREACH_DIRENT_IN_BUFFER(de, buf, n)
5,763✔
180
                        if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name)))
4,442✔
181
                                return 0;
182
        }
183

184
        return 1;
185
}
186

187
bool null_or_empty(struct stat *st) {
387,225✔
188
        assert(st);
387,225✔
189

190
        if (S_ISREG(st->st_mode) && st->st_size <= 0)
387,225✔
191
                return true;
192

193
        /* We don't want to hardcode the major/minor of /dev/null, hence we do a simpler "is this a character
194
         * device node?" check. */
195

196
        if (S_ISCHR(st->st_mode))
387,213✔
197
                return true;
1,029✔
198

199
        return false;
200
}
201

202
int null_or_empty_path_with_root(const char *fn, const char *root) {
294,040✔
203
        struct stat st;
294,040✔
204
        int r;
294,040✔
205

206
        assert(fn);
294,040✔
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"))
588,080✔
213
                return true;
294,040✔
214

215
        r = chase_and_stat(fn, root, CHASE_PREFIX_ROOT, NULL, &st);
293,878✔
216
        if (r < 0)
293,878✔
217
                return r;
218

219
        return null_or_empty(&st);
293,765✔
220
}
221

222
int fd_is_read_only_fs(int fd) {
1,766✔
223
        struct statvfs st;
1,766✔
224

225
        assert(fd >= 0);
1,766✔
226

227
        if (fstatvfs(fd, &st) < 0)
1,766✔
UNCOV
228
                return -errno;
×
229

230
        if (st.f_flag & ST_RDONLY)
1,766✔
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)
1,398✔
UNCOV
236
                return true;
×
237

238
        return false;
239
}
240

241
int path_is_read_only_fs(const char *path) {
1,493✔
242
        _cleanup_close_ int fd = -EBADF;
1,493✔
243

244
        assert(path);
1,493✔
245

246
        fd = open(path, O_CLOEXEC | O_PATH);
1,493✔
247
        if (fd < 0)
1,493✔
248
                return -errno;
146✔
249

250
        return fd_is_read_only_fs(fd);
1,347✔
251
}
252

253
int inode_same_at(int fda, const char *filea, int fdb, const char *fileb, int flags) {
14,271✔
254
        struct stat sta, stb;
14,271✔
255
        int r;
14,271✔
256

257
        assert(fda >= 0 || fda == AT_FDCWD);
14,271✔
258
        assert(fdb >= 0 || fdb == AT_FDCWD);
14,271✔
259
        assert((flags & ~(AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT)) == 0);
14,271✔
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))
28,313✔
263
                return -EINVAL;
14,271✔
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))
14,273✔
267
                return true;
268

269
        _cleanup_close_ int pin_a = -EBADF, pin_b = -EBADF;
28,541✔
270
        if (!FLAGS_SET(flags, AT_NO_AUTOMOUNT)) {
14,270✔
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)) {
14,270✔
277
                        pin_a = openat(fda, filea, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
14,042✔
278
                        if (pin_a < 0)
14,042✔
279
                                return -errno;
14,166✔
280

281
                        fda = pin_a;
13,539✔
282
                        filea = NULL;
13,539✔
283
                        flags |= AT_EMPTY_PATH;
13,539✔
284
                }
285

286
                if (!isempty(fileb)) {
13,767✔
287
                        pin_b = openat(fdb, fileb, O_PATH|O_CLOEXEC|(FLAGS_SET(flags, AT_SYMLINK_NOFOLLOW) ? O_NOFOLLOW : 0));
13,537✔
288
                        if (pin_b < 0)
13,537✔
289
                                return -errno;
4✔
290

291
                        fdb = pin_b;
13,533✔
292
                        fileb = NULL;
13,533✔
293
                        flags |= AT_EMPTY_PATH;
13,533✔
294
                }
295

296
                int ntha_flags = at_flags_normalize_follow(flags) & (AT_EMPTY_PATH|AT_SYMLINK_FOLLOW);
13,763✔
297
                _cleanup_free_ struct file_handle *ha = NULL, *hb = NULL;
13,763✔
298
                int mntida = -1, mntidb = -1;
13,763✔
299

300
                r = name_to_handle_at_try_fid(
13,763✔
301
                                fda,
302
                                filea,
303
                                &ha,
304
                                &mntida,
305
                                ntha_flags);
306
                if (r < 0) {
13,763✔
UNCOV
307
                        if (is_name_to_handle_at_fatal_error(r))
×
308
                                return r;
309

UNCOV
310
                        goto fallback;
×
311
                }
312

313
                r = name_to_handle_at_try_fid(
13,763✔
314
                                fdb,
315
                                fileb,
316
                                &hb,
317
                                &mntidb,
318
                                ntha_flags);
319
                if (r < 0) {
13,763✔
UNCOV
320
                        if (is_name_to_handle_at_fatal_error(r))
×
321
                                return r;
322

UNCOV
323
                        goto fallback;
×
324
                }
325

326
                /* Now compare the two file handles */
327
                if (!file_handle_equal(ha, hb))
13,763✔
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)
13,475✔
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

UNCOV
343
fallback:
×
344
        if (fstatat(fda, strempty(filea), &sta, flags) < 0)
208✔
UNCOV
345
                return log_debug_errno(errno, "Cannot stat %s: %m", strna(filea));
×
346

347
        if (fstatat(fdb, strempty(fileb), &stb, flags) < 0)
208✔
348
                return log_debug_errno(errno, "Cannot stat %s: %m", strna(fileb));
×
349

350
        return stat_inode_same(&sta, &stb);
104✔
351
}
352

353
bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
8,504,770✔
354
        assert(s);
8,504,770✔
355
        assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
8,504,770✔
356

357
        return F_TYPE_EQUAL(s->f_type, magic_value);
8,504,770✔
358
}
359

360
int is_fs_type_at(int dir_fd, const char *path, statfs_f_type_t magic_value) {
8,227,310✔
361
        struct statfs s;
8,227,310✔
362
        int r;
8,227,310✔
363

364
        r = xstatfsat(dir_fd, path, &s);
8,227,310✔
365
        if (r < 0)
8,227,310✔
366
                return r;
8,227,310✔
367

368
        return is_fs_type(&s, magic_value);
8,227,309✔
369
}
370

371
bool is_temporary_fs(const struct statfs *s) {
8,312✔
372
        return fs_in_group(s, FILESYSTEM_SET_TEMPORARY);
8,312✔
373
}
374

375
bool is_network_fs(const struct statfs *s) {
16,080✔
376
        return fs_in_group(s, FILESYSTEM_SET_NETWORK);
16,080✔
377
}
378

379
int fd_is_temporary_fs(int fd) {
147✔
380
        struct statfs s;
147✔
381

382
        if (fstatfs(fd, &s) < 0)
147✔
UNCOV
383
                return -errno;
×
384

385
        return is_temporary_fs(&s);
147✔
386
}
387

388
int fd_is_network_fs(int fd) {
15,977✔
389
        struct statfs s;
15,977✔
390

391
        if (fstatfs(fd, &s) < 0)
15,977✔
UNCOV
392
                return -errno;
×
393

394
        return is_network_fs(&s);
15,977✔
395
}
396

397
int path_is_temporary_fs(const char *path) {
11✔
398
        struct statfs s;
11✔
399

400
        if (statfs(path, &s) < 0)
11✔
401
                return -errno;
2✔
402

403
        return is_temporary_fs(&s);
9✔
404
}
405

UNCOV
406
int path_is_network_fs(const char *path) {
×
UNCOV
407
        struct statfs s;
×
408

UNCOV
409
        if (statfs(path, &s) < 0)
×
UNCOV
410
                return -errno;
×
411

412
        return is_network_fs(&s);
×
413
}
414

415
int proc_mounted(void) {
28,365✔
416
        int r;
28,365✔
417

418
        /* A quick check of procfs is properly mounted */
419

420
        r = path_is_fs_type("/proc/", PROC_SUPER_MAGIC);
28,365✔
421
        if (r == -ENOENT) /* not mounted at all */
28,365✔
UNCOV
422
                return false;
×
423

424
        return r;
425
}
426

427
bool stat_inode_same(const struct stat *a, const struct stat *b) {
1,341,559✔
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) &&
2,681,327✔
433
                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
1,302,397✔
434
                a->st_dev == b->st_dev &&
2,591,160✔
435
                a->st_ino == b->st_ino;
1,249,601✔
436
}
437

438
bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
114,898✔
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) &&
114,898✔
450
                a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
69,094✔
451
                a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
68,959✔
452
                (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
183,836✔
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 */
68,938✔
454
}
455

456
bool statx_inode_same(const struct statx *a, const struct statx *b) {
3,301,385✔
457

458
        /* Same as stat_inode_same() but for struct statx */
459

460
        return statx_is_set(a) && statx_is_set(b) &&
6,602,770✔
461
                FLAGS_SET(a->stx_mask, STATX_TYPE|STATX_INO) && FLAGS_SET(b->stx_mask, STATX_TYPE|STATX_INO) &&
3,301,385✔
462
                ((a->stx_mode ^ b->stx_mode) & S_IFMT) == 0 &&
3,301,385✔
463
                a->stx_dev_major == b->stx_dev_major &&
3,301,385✔
464
                a->stx_dev_minor == b->stx_dev_minor &&
3,092,052✔
465
                a->stx_ino == b->stx_ino;
3,076,234✔
466
}
467

468
bool statx_mount_same(const struct statx *a, const struct statx *b) {
3,047,683✔
469
        if (!statx_is_set(a) || !statx_is_set(b))
6,095,366✔
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))
3,047,683✔
474
                return a->stx_mnt_id == b->stx_mnt_id;
3,047,683✔
475

476
        /* Otherwise, major/minor of backing device must match */
UNCOV
477
        return a->stx_dev_major == b->stx_dev_major &&
×
UNCOV
478
                a->stx_dev_minor == b->stx_dev_minor;
×
479
}
480

481
int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
8,227,690✔
482
        _cleanup_close_ int fd = -EBADF;
8,227,690✔
483

484
        assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
8,227,690✔
485
        assert(ret);
8,227,690✔
486

487
        if (!isempty(path)) {
8,227,690✔
488
                fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
28,859✔
489
                if (fd < 0)
28,859✔
490
                        return fd;
491
                dir_fd = fd;
492
        }
493

494
        return RET_NERRNO(fstatfs(dir_fd, ret));
8,227,690✔
495
}
496

497
usec_t statx_timestamp_load(const struct statx_timestamp *ts) {
4,983✔
498
        return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
4,983✔
499
}
500
nsec_t statx_timestamp_load_nsec(const struct statx_timestamp *ts) {
860✔
501
        return timespec_load_nsec(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
860✔
502
}
503

504
void inode_hash_func(const struct stat *q, struct siphash *state) {
37,141✔
505
        siphash24_compress_typesafe(q->st_dev, state);
37,141✔
506
        siphash24_compress_typesafe(q->st_ino, state);
37,141✔
507
}
37,141✔
508

509
int inode_compare_func(const struct stat *a, const struct stat *b) {
30,977✔
510
        int r;
30,977✔
511

512
        r = CMP(a->st_dev, b->st_dev);
30,977✔
513
        if (r != 0)
26,197✔
514
                return r;
4,851✔
515

516
        return CMP(a->st_ino, b->st_ino);
26,126✔
517
}
518

519
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(inode_hash_ops, struct stat, inode_hash_func, inode_compare_func, free);
787✔
520

521
const char* inode_type_to_string(mode_t m) {
7,478✔
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) {
7,478✔
527
        case S_IFREG:
528
                return "reg";
529
        case S_IFDIR:
2,936✔
530
                return "dir";
2,936✔
531
        case S_IFLNK:
1✔
532
                return "lnk";
1✔
533
        case S_IFCHR:
862✔
534
                return "chr";
862✔
535
        case S_IFBLK:
416✔
536
                return "blk";
416✔
537
        case S_IFIFO:
416✔
538
                return "fifo";
416✔
539
        case S_IFSOCK:
568✔
540
                return "sock";
568✔
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;
3✔
546
}
547

548
mode_t inode_type_from_string(const char *s) {
13✔
549
        if (!s)
13✔
550
                return MODE_INVALID;
551

552
        if (streq(s, "reg"))
13✔
553
                return S_IFREG;
554
        if (streq(s, "dir"))
10✔
555
                return S_IFDIR;
556
        if (streq(s, "lnk"))
7✔
557
                return S_IFLNK;
558
        if (streq(s, "chr"))
6✔
559
                return S_IFCHR;
560
        if (streq(s, "blk"))
5✔
561
                return S_IFBLK;
562
        if (streq(s, "fifo"))
4✔
563
                return S_IFIFO;
564
        if (streq(s, "sock"))
2✔
565
                return S_IFSOCK;
2✔
566

567
        return MODE_INVALID;
568
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc