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

systemd / systemd / 14895667988

07 May 2025 08:57PM UTC coverage: 72.225% (-0.007%) from 72.232%
14895667988

push

github

yuwata
network: log_link_message_debug_errno() automatically append %m if necessary

Follow-up for d28746ef5.
Fixes CID#1609753.

0 of 1 new or added line in 1 file covered. (0.0%)

20297 existing lines in 338 files now uncovered.

297407 of 411780 relevant lines covered (72.22%)

695716.85 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 <errno.h>
4
#include <stdbool.h>
5
#include <string.h>
6

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

22
int mkdirat_safe_internal(
31,992✔
23
                int dir_fd,
24
                const char *path,
25
                mode_t mode,
26
                uid_t uid,
27
                gid_t gid,
28
                MkdirFlags flags,
29
                mkdirat_func_t _mkdirat) {
30

31
        struct stat st;
31,992✔
32
        int r;
31,992✔
33

34
        assert(path);
31,992✔
35
        assert(mode != MODE_INVALID);
31,992✔
36
        assert(_mkdirat && _mkdirat != mkdirat);
31,992✔
37

38
        r = _mkdirat(dir_fd, path, mode);
31,992✔
39
        if (r >= 0)
31,992✔
40
                return chmod_and_chown_at(dir_fd, path, mode, uid, gid);
31,992✔
41
        if (r != -EEXIST)
24,061✔
42
                return r;
43

44
        if (fstatat(dir_fd, path, &st, AT_SYMLINK_NOFOLLOW) < 0)
24,059✔
UNCOV
45
                return -errno;
×
46

47
        if ((flags & MKDIR_FOLLOW_SYMLINK) && S_ISLNK(st.st_mode)) {
24,059✔
48
                _cleanup_free_ char *p = NULL;
3✔
49

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

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

62
        if (flags & MKDIR_IGNORE_EXISTING)
24,058✔
63
                return 0;
64

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

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

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

81
        return 0;
82
}
83

84
int mkdirat_errno_wrapper(int dirfd, const char *pathname, mode_t mode) {
499,016✔
85
        return RET_NERRNO(mkdirat(dirfd, pathname, mode));
499,016✔
86
}
87

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

92
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) {
840,572✔
93
        const char *e = NULL;
840,572✔
94
        int r;
840,572✔
95

96
        assert(path);
840,572✔
97
        assert(_mkdirat != mkdirat);
840,572✔
98

99
        if (isempty(path))
840,572✔
100
                return 0;
840,572✔
101

102
        if (!path_is_safe(path))
840,572✔
103
                return -ENOTDIR;
104

105
        /* return immediately if directory exists */
106
        r = path_find_last_component(path, /* accept_dot_dot= */ false, &e, NULL);
840,572✔
107
        if (r <= 0) /* r == 0 means path is equivalent to prefix. */
840,572✔
108
                return r;
109
        if (e == path)
840,569✔
110
                return 0;
111

112
        assert(e > path);
838,760✔
113
        assert(*e == '/');
838,760✔
114

115
        /* drop the last component */
116
        path = strndupa_safe(path, e - path);
838,760✔
117
        r = is_dir_at(dir_fd, path, /* follow = */ true);
838,760✔
118
        if (r > 0)
838,760✔
119
                return 0;
120
        if (r == 0)
6,187✔
121
                return -ENOTDIR;
122

123
        /* create every parent directory in the path, except the last component */
124
        for (const char *p = path;;) {
6,187✔
125
                char *s;
32,370✔
126
                int n;
32,370✔
127

128
                n = path_find_first_component(&p, /* accept_dot_dot= */ false, (const char **) &s);
32,370✔
129
                if (n <= 0)
32,370✔
130
                        return n;
6,187✔
131

132
                assert(p);
26,185✔
133
                assert(s >= path);
26,185✔
134
                assert(IN_SET(s[n], '/', '\0'));
26,185✔
135

136
                s[n] = '\0';
26,185✔
137

138
                r = mkdirat_safe_internal(dir_fd, path, mode, uid, gid, flags | MKDIR_IGNORE_EXISTING, _mkdirat);
26,185✔
139
                if (r < 0 && r != -EEXIST)
26,185✔
140
                        return r;
141

142
                s[n] = *p == '\0' ? '\0' : '/';
46,181✔
143
        }
144
}
145

146
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) {
500,005✔
147
        _cleanup_close_ int fd = AT_FDCWD;
500,005✔
148
        const char *p;
500,005✔
149

150
        assert(path);
500,005✔
151
        assert(_mkdirat != mkdirat);
500,005✔
152

153
        if (prefix) {
500,005✔
154
                p = path_startswith_full(path, prefix, /* accept_dot_dot= */ false);
1,622✔
155
                if (!p)
1,622✔
156
                        return -EINVAL;
157

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

164
        return mkdirat_parents_internal(fd, p, mode, uid, gid, flags, _mkdirat);
500,002✔
165
}
166

167
int mkdirat_parents(int dir_fd, const char *path, mode_t mode) {
162,151✔
168
        return mkdirat_parents_internal(dir_fd, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
162,151✔
169
}
170

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

175
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) {
499,690✔
176
        int r;
499,690✔
177

178
        /* Like mkdir -p */
179

180
        assert(_mkdirat != mkdirat);
499,690✔
181

182
        r = mkdir_parents_internal(prefix, path, mode, uid, gid, flags | MKDIR_FOLLOW_SYMLINK, _mkdirat);
499,690✔
183
        if (r < 0)
499,690✔
184
                return r;
185

186
        if (!uid_is_valid(uid) && !gid_is_valid(gid) && flags == 0) {
998,794✔
187
                r = _mkdirat(AT_FDCWD, path, mode);
499,107✔
188
                if (r < 0 && (r != -EEXIST || is_dir(path, true) <= 0))
499,107✔
189
                        return r;
1✔
190
        } else {
191
                r = mkdir_safe_internal(path, mode, uid, gid, flags, _mkdirat);
580✔
192
                if (r < 0 && r != -EEXIST)
580✔
UNCOV
193
                        return r;
×
194
        }
195

196
        return 0;
197
}
198

199
int mkdir_p(const char *path, mode_t mode) {
490,163✔
200
        return mkdir_p_internal(NULL, path, mode, UID_INVALID, UID_INVALID, 0, mkdirat_errno_wrapper);
490,163✔
201
}
202

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

207
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✔
208
        _cleanup_free_ char *pp = NULL, *bn = NULL;
255✔
209
        _cleanup_close_ int dfd = -EBADF;
255✔
210
        int r;
255✔
211

212
        assert(p);
255✔
213

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

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

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

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

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

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

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

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

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

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

272
        return 1;
273
}
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