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

systemd / systemd / 16130628215

08 Jul 2025 12:05AM UTC coverage: 72.172% (+0.07%) from 72.1%
16130628215

push

github

yuwata
man: also use title case in systemd.service(5)

Follow-up for: 172dd81e9

301188 of 417317 relevant lines covered (72.17%)

716235.63 hits per line

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

91.67
/src/basic/mkdir.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "alloc-util.h"
6
#include "btrfs.h"
7
#include "chase.h"
8
#include "errno-util.h"
9
#include "fd-util.h"
10
#include "format-util.h"
11
#include "fs-util.h"
12
#include "log.h"
13
#include "mkdir.h"
14
#include "path-util.h"
15
#include "stat-util.h"
16
#include "string-util.h"
17
#include "time-util.h"
18
#include "user-util.h"
19

20
int mkdirat_safe_internal(
32,523✔
21
                int dir_fd,
22
                const char *path,
23
                mode_t mode,
24
                uid_t uid,
25
                gid_t gid,
26
                MkdirFlags flags,
27
                mkdirat_func_t _mkdirat) {
28

29
        struct stat st;
32,523✔
30
        int r;
32,523✔
31

32
        assert(path);
32,523✔
33
        assert(mode != MODE_INVALID);
32,523✔
34
        assert(_mkdirat && _mkdirat != mkdirat);
32,523✔
35

36
        r = _mkdirat(dir_fd, path, mode);
32,523✔
37
        if (r >= 0)
32,523✔
38
                return chmod_and_chown_at(dir_fd, path, mode, uid, gid);
32,523✔
39
        if (r != -EEXIST)
24,518✔
40
                return r;
41

42
        if (fstatat(dir_fd, path, &st, AT_SYMLINK_NOFOLLOW) < 0)
24,516✔
43
                return -errno;
×
44

45
        if ((flags & MKDIR_FOLLOW_SYMLINK) && S_ISLNK(st.st_mode)) {
24,516✔
46
                _cleanup_free_ char *p = NULL;
3✔
47

48
                r = chaseat(dir_fd, path, CHASE_NONEXISTENT, &p, NULL);
3✔
49
                if (r < 0)
3✔
50
                        return r;
51
                if (r == 0)
3✔
52
                        return mkdirat_safe_internal(dir_fd, p, mode, uid, gid,
1✔
53
                                                     flags & ~MKDIR_FOLLOW_SYMLINK,
1✔
54
                                                     _mkdirat);
55

56
                if (fstatat(dir_fd, p, &st, AT_SYMLINK_NOFOLLOW) < 0)
2✔
57
                        return -errno;
×
58
        }
59

60
        if (flags & MKDIR_IGNORE_EXISTING)
24,515✔
61
                return 0;
62

63
        if (!S_ISDIR(st.st_mode))
6,361✔
64
                return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(ENOTDIR),
1✔
65
                                      "Path \"%s\" already exists and is not a directory, refusing.", path);
66

67
        if ((st.st_mode & ~mode & 0777) != 0)
6,360✔
68
                return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST),
104✔
69
                                      "Directory \"%s\" already exists, but has mode %04o that is too permissive (%04o was requested), refusing.",
70
                                      path, st.st_mode & 0777, mode);
71

72
        if ((uid != UID_INVALID && st.st_uid != uid) ||
6,256✔
73
            (gid != GID_INVALID && st.st_gid != gid))
5,176✔
74
                return log_full_errno(flags & MKDIR_WARN_MODE ? LOG_WARNING : LOG_DEBUG, SYNTHETIC_ERRNO(EEXIST),
3✔
75
                                      "Directory \"%s\" already exists, but is owned by "UID_FMT":"GID_FMT" (%s:%s was requested), refusing.",
76
                                      path, st.st_uid, st.st_gid, uid != UID_INVALID ? FORMAT_UID(uid) : "-",
77
                                      gid != UID_INVALID ? FORMAT_GID(gid) : "-");
78

79
        return 0;
80
}
81

82
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
491,492✔
83
        return RET_NERRNO(mkdirat(dirfd, pathname, mode));
491,492✔
84
}
85

86
int mkdirat_safe(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
21✔
87
        return mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
21✔
88
}
89

90
int mkdirat_parents_internal(int dir_fd, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
836,908✔
91
        const char *e = NULL;
836,908✔
92
        int r;
836,908✔
93

94
        assert(path);
836,908✔
95
        assert(_mkdirat != mkdirat);
836,908✔
96

97
        if (isempty(path))
836,908✔
98
                return 0;
836,908✔
99

100
        if (!path_is_safe(path))
836,908✔
101
                return -ENOTDIR;
102

103
        /* return immediately if directory exists */
104
        r = path_find_last_component(path, /* accept_dot_dot= */ false, &e, NULL);
836,908✔
105
        if (r <= 0) /* r == 0 means path is equivalent to prefix. */
836,908✔
106
                return r;
107
        if (e == path)
836,905✔
108
                return 0;
109

110
        assert(e > path);
835,023✔
111
        assert(*e == '/');
835,023✔
112

113
        /* drop the last component */
114
        path = strndupa_safe(path, e - path);
835,023✔
115
        r = is_dir_at(dir_fd, path, /* follow = */ true);
835,023✔
116
        if (r > 0)
835,023✔
117
                return 0;
118
        if (r == 0)
6,139✔
119
                return -ENOTDIR;
120

121
        /* create every parent directory in the path, except the last component */
122
        for (const char *p = path;;) {
6,139✔
123
                char *s;
31,808✔
124
                int n;
31,808✔
125

126
                n = path_find_first_component(&p, /* accept_dot_dot= */ false, (const char **) &s);
31,808✔
127
                if (n <= 0)
31,808✔
128
                        return n;
6,139✔
129

130
                assert(p);
25,671✔
131
                assert(s >= path);
25,671✔
132
                assert(IN_SET(s[n], '/', '\0'));
25,671✔
133

134
                s[n] = '\0';
25,671✔
135

136
                r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat);
25,671✔
137
                if (r < 0 && r != -EEXIST)
25,671✔
138
                        return r;
139

140
                s[n] = *p == '\0' ? '\0' : '/';
45,201✔
141
        }
142
}
143

144
int mkdir_parents_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
493,070✔
145
        _cleanup_close_ int fd = AT_FDCWD;
493,070✔
146
        const char *p;
493,070✔
147

148
        assert(path);
493,070✔
149
        assert(_mkdirat != mkdirat);
493,070✔
150

151
        if (prefix) {
493,070✔
152
                p = path_startswith_full(path, prefix, PATH_STARTSWITH_REFUSE_DOT_DOT);
1,756✔
153
                if (!p)
1,756✔
154
                        return -EINVAL;
155

156
                fd = open(prefix, O_PATH|O_DIRECTORY|O_CLOEXEC);
1,755✔
157
                if (fd < 0)
1,755✔
158
                        return -errno;
2✔
159
        } else
160
                p = path;
161

162
        return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat);
493,067✔
163
}
164

165
int mkdirat_parents(int dir_fd, const char *path, mode_t mode) {
167,248✔
166
        return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
167,248✔
167
}
168

169
int mkdir_parents_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
237✔
170
        return mkdir_parents_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
237✔
171
}
172

173
int mkdir_p_internal(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags, mkdirat_func_t _mkdirat) {
492,717✔
174
        int r;
492,717✔
175

176
        /* Like mkdir -p */
177

178
        assert(_mkdirat != mkdirat);
492,717✔
179

180
        r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat);
492,717✔
181
        if (r < 0)
492,717✔
182
                return r;
183

184
        if (!uid_is_valid(uid) && !gid_is_valid(gid) && flags == 0) {
984,764✔
185
                r = _mkdirat(AT_FDCWD, path, mode);
492,050✔
186
                if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
492,050✔
187
                        return r;
1✔
188
        } else {
189
                r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat);
664✔
190
                if (r < 0 && r != -EEXIST)
664✔
191
                        return r;
×
192
        }
193

194
        return 0;
195
}
196

197
int mkdir_p(const char *path, mode_t mode) {
482,940✔
198
        return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
482,940✔
199
}
200

201
int mkdir_p_safe(const char *prefix, const char *path, mode_t mode, uid_t uid, gid_t gid, MkdirFlags flags) {
1,630✔
202
        return mkdir_p_internal(prefix, path, mode, uid, gid, flags, mkdirat_errno_wrapper);
1,630✔
203
}
204

205
int mkdir_p_root_full(const char *root, const char *p, uid_t uid, gid_t gid, mode_t m, usec_t ts, char **subvolumes) {
255✔
206
        _cleanup_free_ char *pp = NULL, *bn = NULL;
255✔
207
        _cleanup_close_ int dfd = -EBADF;
255✔
208
        int r;
255✔
209

210
        assert(p);
255✔
211

212
        r = path_extract_directory(p, &pp);
255✔
213
        if (r == -EDESTADDRREQ) {
255✔
214
                /* only fname is passed, no prefix to operate on */
215
                dfd = open(".", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
×
216
                if (dfd < 0)
×
217
                        return -errno;
×
218
        } else if (r == -EADDRNOTAVAIL)
255✔
219
                /* only root dir or "." was passed, i.e. there is no parent to extract, in that case there's nothing to do. */
220
                return 0;
221
        else if (r < 0)
138✔
222
                return r;
223
        else {
224
                /* Extracting the parent dir worked, hence we aren't top-level? Recurse up first. */
225
                r = mkdir_p_root_full(root, pp, uid, gid, m, ts, subvolumes);
138✔
226
                if (r < 0)
138✔
227
                        return r;
228

229
                dfd = chase_and_open(pp, root, CHASE_PREFIX_ROOT, O_CLOEXEC|O_DIRECTORY, NULL);
138✔
230
                if (dfd < 0)
138✔
231
                        return dfd;
232
        }
233

234
        r = path_extract_filename(p, &bn);
136✔
235
        if (r == -EADDRNOTAVAIL) /* Already top-level */
136✔
236
                return 0;
237
        if (r < 0)
136✔
238
                return r;
239

240
        if (path_strv_contains(subvolumes, p))
136✔
241
                r = btrfs_subvol_make_fallback(dfd, bn, m);
×
242
        else
243
                r = RET_NERRNO(mkdirat(dfd, bn, m));
136✔
244
        if (r == -EEXIST)
72✔
245
                return 0;
246
        if (r < 0)
64✔
247
                return r;
248

249
        if (ts == USEC_INFINITY && !uid_is_valid(uid) && !gid_is_valid(gid))
125✔
250
                return 1;
251

252
        _cleanup_close_ int nfd = openat(dfd, bn, O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
258✔
253
        if (nfd < 0)
3✔
254
                return -errno;
×
255

256
        if (ts != USEC_INFINITY) {
3✔
257
                struct timespec tspec;
3✔
258
                timespec_store(&tspec, ts);
3✔
259

260
                if (futimens(dfd, (const struct timespec[2]) { TIMESPEC_OMIT, tspec }) < 0)
3✔
261
                        return -errno;
×
262

263
                if (futimens(nfd, (const struct timespec[2]) { tspec, tspec }) < 0)
3✔
264
                        return -errno;
×
265
        }
266

267
        if ((uid_is_valid(uid) || gid_is_valid(gid)) && fchown(nfd, uid, gid) < 0)
6✔
268
                return -errno;
×
269

270
        return 1;
271
}
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