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

systemd / systemd / 23966986054

03 Apr 2026 09:22PM UTC coverage: 72.107% (-0.3%) from 72.362%
23966986054

push

github

daandemeyer
fd-util: Add missing assert()

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

7891 existing lines in 120 files now uncovered.

318256 of 441368 relevant lines covered (72.11%)

1186882.96 hits per line

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

94.23
/src/basic/glob-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <dirent.h>
4
#include <sys/stat.h>
5

6
#include "dirent-util.h"
7
#include "errno-util.h"
8
#include "glob-util.h"
9
#include "string-util.h"
10
#include "strv.h"
11

12
#ifndef __GLIBC__
13
static bool safe_glob_verify(const char *p, const char *prefix) {
14
        POINTER_MAY_BE_NULL(p);
15
        POINTER_MAY_BE_NULL(prefix);
16

17
        if (isempty(p))
18
                return false; /* should not happen, but for safey. */
19

20
        if (prefix) {
21
                /* Skip the prefix, as we allow dots in prefix.
22
                 * Note, glob() does not normalize paths, hence do not use path_startswith(). */
23
                p = startswith(p, prefix);
24
                if (!p)
25
                        return false; /* should not happen, but for safety. */
26
        }
27

28
        for (;;) {
29
                p += strspn(p, "/");
30
                if (*p == '\0')
31
                        return true;
32
                if (*p == '.') {
33
                        p++;
34
                        if (IN_SET(*p, '/', '\0'))
35
                                return false; /* refuse dot */
36
                        if (*p == '.') {
37
                                p++;
38
                                if (IN_SET(*p, '/', '\0'))
39
                                        return false; /* refuse dot dot */
40
                        }
41
                }
42

43
                p += strcspn(p, "/");
44
                if (*p == '\0')
45
                        return true;
46
        }
47
}
48

49
static int filter_glob_result(char * const *result, const char *path, char ***ret) {
50
        int r;
51

52
        assert(path);
53

54
        if (strv_isempty(result))
55
                return -ENOENT;
56

57
        _cleanup_free_ char *prefix = NULL;
58
        r = glob_non_glob_prefix(path, &prefix);
59
        if (r < 0 && r != -ENOENT)
60
                return r;
61

62
        _cleanup_strv_free_ char **filtered = NULL;
63
        size_t n_filtered = 0;
64
        STRV_FOREACH(p, result) {
65
                if (!safe_glob_verify(*p, prefix))
66
                        continue;
67

68
                if (!ret)
69
                        return 0; /* Found at least one entry, let's return earlier. */
70

71
                /* When musl is used, each entry is not a head of allocated memory. Hence, it is
72
                 * necessary to copy the string. */
73
                r = strv_extend_with_size(&filtered, &n_filtered, *p);
74
                if (r < 0)
75
                        return r;
76
        }
77

78
        if (n_filtered == 0)
79
                return -ENOENT;
80

81
        assert(ret);
82
        *ret = TAKE_PTR(filtered);
83
        return 0;
84
}
85
#endif
86

87
DEFINE_TRIVIAL_DESTRUCTOR(closedir_wrapper, void, closedir);
12,578✔
88

89
int safe_glob_full(const char *path, int flags, opendir_t opendir_func, char ***ret) {
46,275✔
UNCOV
90
        _cleanup_(globfree) glob_t g = {
×
91
                .gl_closedir = closedir_wrapper,
92
                .gl_readdir = (struct dirent* (*)(void *)) readdir_no_dot,
93
                .gl_opendir = (void* (*)(const char *)) (opendir_func ?: opendir),
46,275✔
94
                .gl_lstat = lstat,
95
                .gl_stat = stat,
96
        };
97
        int r;
46,275✔
98

99
        assert(path);
46,275✔
100

101
        errno = 0;
46,275✔
102
        r = glob(path, flags | GLOB_ALTDIRFUNC, NULL, &g);
46,275✔
103
        if (r == GLOB_NOMATCH)
46,275✔
104
                return -ENOENT;
105
        if (r == GLOB_NOSPACE)
8,033✔
106
                return -ENOMEM;
107
        if (r != 0)
8,033✔
UNCOV
108
                return errno_or_else(EIO);
×
109

110
#ifndef __GLIBC__
111
        return filter_glob_result(g.gl_pathv, path, ret);
112
#endif
113

114
        if (strv_isempty(g.gl_pathv))
54,308✔
115
                return -ENOENT;
116

117
        if (ret) {
8,033✔
118
                *ret = g.gl_pathv;
8,033✔
119
                TAKE_STRUCT(g); /* To avoid the result being freed. */
8,033✔
120
        }
121

122
        return 0;
123
}
124

125
int glob_first(const char *path, char **ret) {
12✔
126
        _cleanup_strv_free_ char **v = NULL;
12✔
127
        int r;
12✔
128

129
        assert(path);
12✔
130

131
        r = safe_glob(path, GLOB_NOSORT|GLOB_BRACE, &v);
12✔
132
        if (r == -ENOENT) {
12✔
133
                if (ret)
6✔
134
                        *ret = NULL;
5✔
135
                return false;
6✔
136
        }
137
        if (r < 0)
6✔
138
                return r;
139

140
        assert(!strv_isempty(v));
6✔
141

142
        if (ret) {
6✔
143
                /* Free all results except for the first one. */
144
                STRV_FOREACH(p, strv_skip(v, 1))
3✔
UNCOV
145
                        *p = mfree(*p);
×
146

147
                /* Then, take the first result. */
148
                *ret = TAKE_PTR(*v);
3✔
149
        }
150

151
        return true;
152
}
153

154
int glob_extend(char ***strv, const char *path, int flags) {
4,134✔
155
        char **v;
4,134✔
156
        int r;
4,134✔
157

158
        assert(path);
4,134✔
159

160
        r = safe_glob(path, GLOB_NOSORT|GLOB_BRACE|flags, &v);
4,134✔
161
        if (r < 0)
4,134✔
162
                return r;
4,134✔
163

164
        return strv_extend_strv_consume(strv, v, /* filter_duplicates= */ false);
4,134✔
165
}
166

167
int glob_non_glob_prefix(const char *path, char **ret) {
3,390✔
168
        assert(path);
3,390✔
169
        assert(ret);
3,390✔
170

171
        /* Return the path of the path that has no glob characters. */
172

173
        size_t n = strcspn(path, GLOB_CHARS);
3,390✔
174

175
        if (path[n] != '\0')
3,390✔
176
                while (n > 0 && path[n-1] != '/')
65,854✔
177
                        n--;
178

179
        if (n == 0)
3,390✔
180
                return -ENOENT;
181

182
        char *ans = strndup(path, n);
3,389✔
183
        if (!ans)
3,389✔
184
                return -ENOMEM;
185
        *ret = ans;
3,389✔
186
        return 0;
3,389✔
187
}
188

189
bool string_is_glob(const char *p) {
251,170✔
190
        /* Check if a string contains any glob patterns. */
191
        return !!strpbrk(p, GLOB_CHARS);
251,170✔
192
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc