Bug Summary

File:build-scan/../src/analyze/analyze-verify.c
Warning:line 119, column 17
Access to field 'id' results in a dereference of a null pointer

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name analyze-verify.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-analyze.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -I /usr/include/libmount -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/analyze/analyze-verify.c

../src/analyze/analyze-verify.c

1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <stdlib.h>
4
5#include "alloc-util.h"
6#include "all-units.h"
7#include "analyze-verify.h"
8#include "bus-error.h"
9#include "bus-util.h"
10#include "log.h"
11#include "manager.h"
12#include "pager.h"
13#include "path-util.h"
14#include "strv.h"
15#include "unit-name.h"
16
17static int prepare_filename(const char *filename, char **ret) {
18 int r;
19 const char *name;
20 _cleanup_free___attribute__((cleanup(freep))) char *abspath = NULL((void*)0);
21 _cleanup_free___attribute__((cleanup(freep))) char *dir = NULL((void*)0);
22 _cleanup_free___attribute__((cleanup(freep))) char *with_instance = NULL((void*)0);
23 char *c;
24
25 assert(filename)do { if ((__builtin_expect(!!(!(filename)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("filename"), "../src/analyze/analyze-verify.c"
, 25, __PRETTY_FUNCTION__); } while (0)
;
26 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/analyze/analyze-verify.c"
, 26, __PRETTY_FUNCTION__); } while (0)
;
27
28 r = path_make_absolute_cwd(filename, &abspath);
29 if (r < 0)
30 return r;
31
32 name = basename(abspath);
33 if (!unit_name_is_valid(name, UNIT_NAME_ANY))
34 return -EINVAL22;
35
36 if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
37 r = unit_name_replace_instance(name, "i", &with_instance);
38 if (r < 0)
39 return r;
40 }
41
42 dir = dirname_malloc(abspath);
43 if (!dir)
44 return -ENOMEM12;
45
46 if (with_instance)
47 c = path_join(NULL((void*)0), dir, with_instance);
48 else
49 c = path_join(NULL((void*)0), dir, name);
50 if (!c)
51 return -ENOMEM12;
52
53 *ret = c;
54 return 0;
55}
56
57static int generate_path(char **var, char **filenames) {
58 const char *old;
59 char **filename;
60
61 _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **ans = NULL((void*)0);
62 int r;
63
64 STRV_FOREACH(filename, filenames)for ((filename) = (filenames); (filename) && *(filename
); (filename)++)
{
65 char *t;
66
67 t = dirname_malloc(*filename);
68 if (!t)
69 return -ENOMEM12;
70
71 r = strv_consume(&ans, t);
72 if (r < 0)
73 return r;
74 }
75
76 assert_se(strv_uniq(ans))do { if ((__builtin_expect(!!(!(strv_uniq(ans))),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("strv_uniq(ans)"), "../src/analyze/analyze-verify.c"
, 76, __PRETTY_FUNCTION__); } while (0)
;
77
78 /* First, prepend our directories. Second, if some path was specified, use that, and
79 * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
80 * Treat explicit empty path to mean that nothing should be appended.
81 */
82 old = getenv("SYSTEMD_UNIT_PATH");
83 if (!streq_ptr(old, "")) {
84 if (!old)
85 old = ":";
86
87 r = strv_extend(&ans, old);
88 if (r < 0)
89 return r;
90 }
91
92 *var = strv_join(ans, ":");
93 if (!*var)
94 return -ENOMEM12;
95
96 return 0;
97}
98
99static int verify_socket(Unit *u) {
100 int r;
101
102 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/analyze/analyze-verify.c",
102, __PRETTY_FUNCTION__); } while (0)
;
37
Taking false branch
38
Loop condition is false. Exiting loop
103
104 if (u->type != UNIT_SOCKET)
39
Assuming field 'type' is equal to UNIT_SOCKET
40
Taking false branch
105 return 0;
106
107 /* Cannot run this without the service being around */
108
109 /* This makes sure instance is created if necessary. */
110 r = socket_instantiate_service(SOCKET(u));
111 if (r < 0)
41
Assuming 'r' is >= 0
42
Taking false branch
112 return log_unit_error_errno(u, r, "Socket cannot be started, failed to create instance: %m")({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/analyze/analyze-verify.c"
, 112, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Socket cannot be started, failed to create instance: %m") :
log_internal_realm(((LOG_REALM_SYSTEMD) << 10 | ((3)))
, r, "../src/analyze/analyze-verify.c", 112, __func__, "Socket cannot be started, failed to create instance: %m"
); })
;
113
114 /* This checks both type of sockets */
115 if (UNIT_ISSET(SOCKET(u)->service)(!!(SOCKET(u)->service).target)) {
43
Assuming field 'target' is non-null
44
Taking true branch
116 Service *service;
117
118 service = SERVICE(UNIT_DEREF(SOCKET(u)->service)((SOCKET(u)->service).target));
119 log_unit_debug(u, "Using %s", UNIT(service)->id)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/analyze/analyze-verify.c"
, 119, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Using %s", ({ typeof(service) _u_ = (service); Unit *_w_ =
_u_ ? &(_u_)->meta : ((void*)0); _w_; })->id) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/analyze/analyze-verify.c"
, 119, __func__, "Using %s", ({ typeof(service) _u_ = (service
); Unit *_w_ = _u_ ? &(_u_)->meta : ((void*)0); _w_; }
)->id); })
;
45
'?' condition is true
46
'?' condition is false
47
Access to field 'id' results in a dereference of a null pointer
120
121 if (UNIT(service)({ typeof(service) _u_ = (service); Unit *_w_ = _u_ ? &(_u_
)->meta : ((void*)0); _w_; })
->load_state != UNIT_LOADED) {
122 log_unit_error(u, "Service %s not loaded, %s cannot be started.", UNIT(service)->id, u->id)({ const Unit *_u = (u); _u ? log_object_internal(3, 0, "../src/analyze/analyze-verify.c"
, 122, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Service %s not loaded, %s cannot be started.", ({ typeof(service
) _u_ = (service); Unit *_w_ = _u_ ? &(_u_)->meta : ((
void*)0); _w_; })->id, u->id) : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), 0, "../src/analyze/analyze-verify.c",
122, __func__, "Service %s not loaded, %s cannot be started."
, ({ typeof(service) _u_ = (service); Unit *_w_ = _u_ ? &
(_u_)->meta : ((void*)0); _w_; })->id, u->id); })
;
123 return -ENOENT2;
124 }
125 }
126
127 return 0;
128}
129
130static int verify_executable(Unit *u, ExecCommand *exec) {
131 if (!exec)
132 return 0;
133
134 if (access(exec->path, X_OK1) < 0)
135 return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path)({ const Unit *_u = (u); _u ? log_object_internal(3, (*__errno_location
()), "../src/analyze/analyze-verify.c", 135, __func__, _u->
manager->unit_log_field, _u->id, _u->manager->invocation_log_field
, _u->invocation_id_string, "Command %s is not executable: %m"
, exec->path) : log_internal_realm(((LOG_REALM_SYSTEMD) <<
10 | ((3))), (*__errno_location ()), "../src/analyze/analyze-verify.c"
, 135, __func__, "Command %s is not executable: %m", exec->
path); })
;
136
137 return 0;
138}
139
140static int verify_executables(Unit *u) {
141 ExecCommand *exec;
142 int r = 0, k;
143 unsigned i;
144
145 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/analyze/analyze-verify.c",
145, __PRETTY_FUNCTION__); } while (0)
;
146
147 exec = u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
148 u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
149 u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL((void*)0);
150 k = verify_executable(u, exec);
151 if (k < 0 && r == 0)
152 r = k;
153
154 if (u->type == UNIT_SERVICE)
155 for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(SERVICE(u)->exec_command), typeof(&*(SERVICE(u
)->exec_command))), sizeof(SERVICE(u)->exec_command)/sizeof
((SERVICE(u)->exec_command)[0]), ((void)0)))
; i++) {
156 k = verify_executable(u, SERVICE(u)->exec_command[i]);
157 if (k < 0 && r == 0)
158 r = k;
159 }
160
161 if (u->type == UNIT_SOCKET)
162 for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command)__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(SOCKET(u)->exec_command), typeof(&*(SOCKET(u)->
exec_command))), sizeof(SOCKET(u)->exec_command)/sizeof((SOCKET
(u)->exec_command)[0]), ((void)0)))
; i++) {
163 k = verify_executable(u, SOCKET(u)->exec_command[i]);
164 if (k < 0 && r == 0)
165 r = k;
166 }
167
168 return r;
169}
170
171static int verify_documentation(Unit *u, bool_Bool check_man) {
172 char **p;
173 int r = 0, k;
174
175 STRV_FOREACH(p, u->documentation)for ((p) = (u->documentation); (p) && *(p); (p)++) {
176 log_unit_debug(u, "Found documentation item: %s", *p)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/analyze/analyze-verify.c"
, 176, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Found documentation item: %s", *p) : log_internal_realm(((
LOG_REALM_SYSTEMD) << 10 | ((7))), 0, "../src/analyze/analyze-verify.c"
, 176, __func__, "Found documentation item: %s", *p); })
;
177
178 if (check_man && startswith(*p, "man:")) {
179 k = show_man_page(*p + 4, true1);
180 if (k != 0) {
181 if (k < 0)
182 log_unit_error_errno(u, r, "Can't show %s: %m", *p)({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/analyze/analyze-verify.c"
, 182, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Can't show %s: %m", *p) : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((3))), r, "../src/analyze/analyze-verify.c",
182, __func__, "Can't show %s: %m", *p); })
;
183 else {
184 log_unit_error_errno(u, r, "man %s command failed with code %d", *p + 4, k)({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/analyze/analyze-verify.c"
, 184, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "man %s command failed with code %d", *p + 4, k) : log_internal_realm
(((LOG_REALM_SYSTEMD) << 10 | ((3))), r, "../src/analyze/analyze-verify.c"
, 184, __func__, "man %s command failed with code %d", *p + 4
, k); })
;
185 k = -ENOEXEC8;
186 }
187 if (r == 0)
188 r = k;
189 }
190 }
191 }
192
193 /* Check remote URLs? */
194
195 return r;
196}
197
198static int verify_unit(Unit *u, bool_Bool check_man) {
199 _cleanup_(sd_bus_error_free)__attribute__((cleanup(sd_bus_error_free))) sd_bus_error err = SD_BUS_ERROR_NULL((const sd_bus_error) {(((void*)0)), (((void*)0)), 0});
200 int r, k;
201
202 assert(u)do { if ((__builtin_expect(!!(!(u)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("u"), "../src/analyze/analyze-verify.c",
202, __PRETTY_FUNCTION__); } while (0)
;
28
Assuming 'u' is non-null
29
Taking false branch
30
Loop condition is false. Exiting loop
203
204 if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD
) >= 7),0))
)
31
Assuming the condition is false
32
Taking false branch
205 unit_dump(u, stdoutstdout, "\t");
206
207 log_unit_debug(u, "Creating %s/start job", u->id)({ const Unit *_u = (u); _u ? log_object_internal(7, 0, "../src/analyze/analyze-verify.c"
, 207, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Creating %s/start job", u->id) : log_internal_realm(((LOG_REALM_SYSTEMD
) << 10 | ((7))), 0, "../src/analyze/analyze-verify.c",
207, __func__, "Creating %s/start job", u->id); })
;
33
'?' condition is true
208 r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL((void*)0), &err, NULL((void*)0));
209 if (r < 0)
34
Assuming 'r' is >= 0
35
Taking false branch
210 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r))({ const Unit *_u = (u); _u ? log_object_internal(3, r, "../src/analyze/analyze-verify.c"
, 210, __func__, _u->manager->unit_log_field, _u->id
, _u->manager->invocation_log_field, _u->invocation_id_string
, "Failed to create %s/start: %s", u->id, bus_error_message
(&err, r)) : log_internal_realm(((LOG_REALM_SYSTEMD) <<
10 | ((3))), r, "../src/analyze/analyze-verify.c", 210, __func__
, "Failed to create %s/start: %s", u->id, bus_error_message
(&err, r)); })
;
211
212 k = verify_socket(u);
36
Calling 'verify_socket'
213 if (k < 0 && r == 0)
214 r = k;
215
216 k = verify_executables(u);
217 if (k < 0 && r == 0)
218 r = k;
219
220 k = verify_documentation(u, check_man);
221 if (k < 0 && r == 0)
222 r = k;
223
224 return r;
225}
226
227int verify_units(char **filenames, UnitFileScope scope, bool_Bool check_man, bool_Bool run_generators) {
228 const uint8_t flags = MANAGER_TEST_RUN_BASIC |
229 MANAGER_TEST_RUN_ENV_GENERATORS |
230 run_generators * MANAGER_TEST_RUN_GENERATORS;
231
232 _cleanup_(manager_freep)__attribute__((cleanup(manager_freep))) Manager *m = NULL((void*)0);
233 Unit *units[strv_length(filenames)];
234 _cleanup_free___attribute__((cleanup(freep))) char *var = NULL((void*)0);
235 int r = 0, k, i, count = 0;
236 char **filename;
237
238 if (strv_isempty(filenames))
1
Calling 'strv_isempty'
5
Returning from 'strv_isempty'
6
Taking false branch
239 return 0;
240
241 /* set the path */
242 r = generate_path(&var, filenames);
243 if (r < 0)
7
Assuming 'r' is >= 0
8
Taking false branch
244 return log_error_errno(r, "Failed to generate unit load path: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 244, __func__, "Failed to generate unit load path: %m"
) : -abs(_e); })
;
245
246 assert_se(set_unit_path(var) >= 0)do { if ((__builtin_expect(!!(!(set_unit_path(var) >= 0)),
0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("set_unit_path(var) >= 0"
), "../src/analyze/analyze-verify.c", 246, __PRETTY_FUNCTION__
); } while (0)
;
9
Assuming the condition is true
10
Taking false branch
11
Loop condition is false. Exiting loop
247
248 r = manager_new(scope, flags, &m);
249 if (r < 0)
12
Assuming 'r' is >= 0
13
Taking false branch
250 return log_error_errno(r, "Failed to initialize manager: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 250, __func__, "Failed to initialize manager: %m"
) : -abs(_e); })
;
251
252 log_debug("Starting manager...")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 252, __func__, "Starting manager..."
) : -abs(_e); })
;
14
Assuming the condition is false
15
'?' condition is false
253
254 r = manager_startup(m, NULL((void*)0), NULL((void*)0));
255 if (r < 0)
16
Assuming 'r' is >= 0
17
Taking false branch
256 return log_error_errno(r, "Failed to start manager: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 256, __func__, "Failed to start manager: %m"
) : -abs(_e); })
;
257
258 manager_clear_jobs(m);
259
260 log_debug("Loading remaining units from the command line...")({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 260, __func__, "Loading remaining units from the command line..."
) : -abs(_e); })
;
18
Assuming the condition is false
19
'?' condition is false
261
262 STRV_FOREACH(filename, filenames)for ((filename) = (filenames); (filename) && *(filename
); (filename)++)
{
20
Loop condition is true. Entering loop body
25
Loop condition is false. Execution continues on line 282
263 _cleanup_free___attribute__((cleanup(freep))) char *prepared = NULL((void*)0);
264
265 log_debug("Handling %s...", *filename)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 265, __func__, "Handling %s..."
, *filename) : -abs(_e); })
;
21
Assuming the condition is false
22
'?' condition is false
266
267 k = prepare_filename(*filename, &prepared);
268 if (k
22.1
'k' is >= 0
22.1
'k' is >= 0
< 0) {
23
Taking false branch
269 log_error_errno(k, "Failed to prepare filename %s: %m", *filename)({ int _level = ((3)), _e = ((k)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/analyze/analyze-verify.c", 269, __func__, "Failed to prepare filename %s: %m"
, *filename) : -abs(_e); })
;
270 if (r == 0)
271 r = k;
272 continue;
273 }
274
275 k = manager_load_startable_unit_or_warn(m, NULL((void*)0), prepared, &units[count]);
276 if (k < 0 && r == 0)
24
Assuming 'k' is >= 0
277 r = k;
278 else
279 count++;
280 }
281
282 for (i = 0; i < count; i++) {
26
Loop condition is true. Entering loop body
283 k = verify_unit(units[i], check_man);
27
Calling 'verify_unit'
284 if (k < 0 && r == 0)
285 r = k;
286 }
287
288 return r;
289}

../src/basic/strv.h

1/* SPDX-License-Identifier: LGPL-2.1+ */
2#pragma once
3
4#include <fnmatch.h>
5#include <stdarg.h>
6#include <stdbool.h>
7#include <stddef.h>
8
9#include "alloc-util.h"
10#include "extract-word.h"
11#include "macro.h"
12#include "util.h"
13
14char *strv_find(char **l, const char *name) _pure___attribute__ ((pure));
15char *strv_find_prefix(char **l, const char *name) _pure___attribute__ ((pure));
16char *strv_find_startswith(char **l, const char *name) _pure___attribute__ ((pure));
17
18char **strv_free(char **l);
19DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free)static inline void strv_freep(char** *p) { if (*p) strv_free(
*p); }
;
20#define _cleanup_strv_free___attribute__((cleanup(strv_freep))) _cleanup_(strv_freep)__attribute__((cleanup(strv_freep)))
21
22char **strv_free_erase(char **l);
23DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase)static inline void strv_free_erasep(char** *p) { if (*p) strv_free_erase
(*p); }
;
24#define _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) _cleanup_(strv_free_erasep)__attribute__((cleanup(strv_free_erasep)))
25
26void strv_clear(char **l);
27
28char **strv_copy(char * const *l);
29size_t strv_length(char * const *l) _pure___attribute__ ((pure));
30
31int strv_extend_strv(char ***a, char **b, bool_Bool filter_duplicates);
32int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
33int strv_extend(char ***l, const char *value);
34int strv_extendf(char ***l, const char *format, ...) _printf_(2,0)__attribute__ ((format (printf, 2, 0)));
35int strv_extend_front(char ***l, const char *value);
36int strv_push(char ***l, char *value);
37int strv_push_pair(char ***l, char *a, char *b);
38int strv_insert(char ***l, size_t position, char *value);
39
40static inline int strv_push_prepend(char ***l, char *value) {
41 return strv_insert(l, 0, value);
42}
43
44int strv_consume(char ***l, char *value);
45int strv_consume_pair(char ***l, char *a, char *b);
46int strv_consume_prepend(char ***l, char *value);
47
48char **strv_remove(char **l, const char *s);
49char **strv_uniq(char **l);
50bool_Bool strv_is_uniq(char **l);
51
52bool_Bool strv_equal(char **a, char **b);
53
54#define strv_contains(l, s)(!!strv_find((l), (s))) (!!strv_find((l), (s)))
55
56char **strv_new(const char *x, ...) _sentinel___attribute__ ((sentinel));
57char **strv_new_ap(const char *x, va_list ap);
58
59#define STRV_IGNORE((const char *) -1) ((const char *) -1)
60
61static inline const char* STRV_IFNOTNULL(const char *x) {
62 return x ? x : STRV_IGNORE((const char *) -1);
63}
64
65static inline bool_Bool strv_isempty(char * const *l) {
66 return !l || !*l;
2
Assuming 'l' is non-null
3
Assuming the condition is false
4
Returning zero, which participates in a condition later
67}
68
69char **strv_split(const char *s, const char *separator);
70char **strv_split_newlines(const char *s);
71
72int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags);
73
74char *strv_join(char **l, const char *separator);
75
76char **strv_parse_nulstr(const char *s, size_t l);
77char **strv_split_nulstr(const char *s);
78int strv_make_nulstr(char **l, char **p, size_t *n);
79
80bool_Bool strv_overlap(char **a, char **b) _pure___attribute__ ((pure));
81
82#define STRV_FOREACH(s, l)for ((s) = (l); (s) && *(s); (s)++) \
83 for ((s) = (l); (s) && *(s); (s)++)
84
85#define STRV_FOREACH_BACKWARDS(s, l)for (s = ({ char **_l = l; _l ? _l + strv_length(_l) - 1U : (
(void*)0); }); (l) && ((s) >= (l)); (s)--)
\
86 for (s = ({ \
87 char **_l = l; \
88 _l ? _l + strv_length(_l) - 1U : NULL((void*)0); \
89 }); \
90 (l) && ((s) >= (l)); \
91 (s)--)
92
93#define STRV_FOREACH_PAIR(x, y, l)for ((x) = (l), (y) = (x+1); (x) && *(x) && *
(y); (x) += 2, (y) = (x + 1))
\
94 for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1))
95
96char **strv_sort(char **l);
97void strv_print(char **l);
98
99#define STRV_MAKE(...)((char**) ((const char*[]) { ..., ((void*)0) })) ((char**) ((const char*[]) { __VA_ARGS__, NULL((void*)0) }))
100
101#define STRV_MAKE_EMPTY((char*[1]) { ((void*)0) }) ((char*[1]) { NULL((void*)0) })
102
103#define strv_from_stdarg_alloca(first)({ char **_l; if (!first) _l = (char**) &first; else { size_t
_n; va_list _ap; _n = 1; __builtin_va_start(_ap, first); while
(__builtin_va_arg(_ap, char*)) _n++; __builtin_va_end(_ap); _l
= ({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow
(sizeof(char*), _n+1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(char*), _n+1)"), "../src/basic/strv.h"
, 103, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca
(sizeof(char*)*(_n+1)); }); _l[_n = 0] = (char*) first; __builtin_va_start
(_ap, first); for (;;) { _l[++_n] = __builtin_va_arg(_ap, char
*); if (!_l[_n]) break; } __builtin_va_end(_ap); } _l; })
\
104 ({ \
105 char **_l; \
106 \
107 if (!first) \
108 _l = (char**) &first; \
109 else { \
110 size_t _n; \
111 va_list _ap; \
112 \
113 _n = 1; \
114 va_start(_ap, first)__builtin_va_start(_ap, first); \
115 while (va_arg(_ap, char*)__builtin_va_arg(_ap, char*)) \
116 _n++; \
117 va_end(_ap)__builtin_va_end(_ap); \
118 \
119 _l = newa(char*, _n+1)({ do { if ((__builtin_expect(!!(!(!size_multiply_overflow(sizeof
(char*), _n+1))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("!size_multiply_overflow(sizeof(char*), _n+1)"), "../src/basic/strv.h"
, 119, __PRETTY_FUNCTION__); } while (0); (char**) __builtin_alloca
(sizeof(char*)*(_n+1)); })
; \
120 _l[_n = 0] = (char*) first; \
121 va_start(_ap, first)__builtin_va_start(_ap, first); \
122 for (;;) { \
123 _l[++_n] = va_arg(_ap, char*)__builtin_va_arg(_ap, char*); \
124 if (!_l[_n]) \
125 break; \
126 } \
127 va_end(_ap)__builtin_va_end(_ap); \
128 } \
129 _l; \
130 })
131
132#define STR_IN_SET(x, ...)(!!strv_find((((char**) ((const char*[]) { ..., ((void*)0) })
)), (x)))
strv_contains(STRV_MAKE(__VA_ARGS__), x)(!!strv_find((((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))), (x)))
133#define STRPTR_IN_SET(x, ...)({ const char* _x = (x); _x && (!!strv_find((((char**
) ((const char*[]) { ..., ((void*)0) }))), (_x))); })
\
134 ({ \
135 const char* _x = (x); \
136 _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x)(!!strv_find((((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))), (_x)))
; \
137 })
138
139#define STARTSWITH_SET(p, ...)({ const char *_p = (p); char *_found = ((void*)0), **_i; for
((_i) = (((char**) ((const char*[]) { ..., ((void*)0) }))); (
_i) && *(_i); (_i)++) { _found = startswith(_p, *_i);
if (_found) break; } _found; })
\
140 ({ \
141 const char *_p = (p); \
142 char *_found = NULL((void*)0), **_i; \
143 STRV_FOREACH(_i, STRV_MAKE(__VA_ARGS__))for ((_i) = (((char**) ((const char*[]) { __VA_ARGS__, ((void
*)0) }))); (_i) && *(_i); (_i)++)
{ \
144 _found = startswith(_p, *_i); \
145 if (_found) \
146 break; \
147 } \
148 _found; \
149 })
150
151#define FOREACH_STRING(x, ...)for (char **_l = ({ char **_ll = ((char**) ((const char*[]) {
..., ((void*)0) })); x = _ll ? _ll[0] : ((void*)0); _ll; });
_l && *_l; x = ({ _l ++; _l[0]; }))
\
152 for (char **_l = ({ \
153 char **_ll = STRV_MAKE(__VA_ARGS__)((char**) ((const char*[]) { __VA_ARGS__, ((void*)0) })); \
154 x = _ll ? _ll[0] : NULL((void*)0); \
155 _ll; \
156 }); \
157 _l && *_l; \
158 x = ({ \
159 _l ++; \
160 _l[0]; \
161 }))
162
163char **strv_reverse(char **l);
164char **strv_shell_escape(char **l, const char *bad);
165
166bool_Bool strv_fnmatch(char* const* patterns, const char *s, int flags);
167
168static inline bool_Bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) {
169 assert(s)do { if ((__builtin_expect(!!(!(s)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("s"), "../src/basic/strv.h", 169, __PRETTY_FUNCTION__
); } while (0)
;
170 return strv_isempty(patterns) ||
171 strv_fnmatch(patterns, s, flags);
172}
173
174char ***strv_free_free(char ***l);
175DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free)static inline void strv_free_freep(char*** *p) { if (*p) strv_free_free
(*p); }
;
176
177char **strv_skip(char **l, size_t n);
178
179int strv_extend_n(char ***l, const char *value, size_t n);
180
181int fputstrv(FILE *f, char **l, const char *separator, bool_Bool *space);
182
183#define strv_free_and_replace(a, b)({ strv_free(a); (a) = (b); (b) = ((void*)0); 0; }) \
184 ({ \
185 strv_free(a); \
186 (a) = (b); \
187 (b) = NULL((void*)0); \
188 0; \
189 })