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 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |||||
17 | static 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 | |||||
57 | static 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 | |||||
99 | static 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); | ||||
103 | |||||
104 | if (u->type != UNIT_SOCKET) | ||||
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) | ||||
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)) { | ||||
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); }); | ||||
| |||||
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 | |||||
130 | static 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 | |||||
140 | static 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 | |||||
171 | static 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 | |||||
198 | static 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); | ||||
203 | |||||
204 | if (DEBUG_LOGGING(__builtin_expect(!!(log_get_max_level_realm(LOG_REALM_SYSTEMD ) >= 7),0))) | ||||
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); }); | ||||
208 | r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL((void*)0), &err, NULL((void*)0)); | ||||
209 | if (r < 0) | ||||
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); | ||||
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 | |||||
227 | int 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)) | ||||
| |||||
239 | return 0; | ||||
240 | |||||
241 | /* set the path */ | ||||
242 | r = generate_path(&var, filenames); | ||||
243 | if (r < 0) | ||||
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); | ||||
247 | |||||
248 | r = manager_new(scope, flags, &m); | ||||
249 | if (r < 0) | ||||
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); }); | ||||
253 | |||||
254 | r = manager_startup(m, NULL((void*)0), NULL((void*)0)); | ||||
255 | if (r < 0) | ||||
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); }); | ||||
261 | |||||
262 | STRV_FOREACH(filename, filenames)for ((filename) = (filenames); (filename) && *(filename ); (filename)++) { | ||||
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); }); | ||||
266 | |||||
267 | k = prepare_filename(*filename, &prepared); | ||||
268 | if (k
| ||||
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) | ||||
277 | r = k; | ||||
278 | else | ||||
279 | count++; | ||||
280 | } | ||||
281 | |||||
282 | for (i = 0; i < count; i++) { | ||||
283 | k = verify_unit(units[i], check_man); | ||||
284 | if (k < 0 && r == 0) | ||||
285 | r = k; | ||||
286 | } | ||||
287 | |||||
288 | return r; | ||||
289 | } |
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 | |
14 | char *strv_find(char **l, const char *name) _pure___attribute__ ((pure)); |
15 | char *strv_find_prefix(char **l, const char *name) _pure___attribute__ ((pure)); |
16 | char *strv_find_startswith(char **l, const char *name) _pure___attribute__ ((pure)); |
17 | |
18 | char **strv_free(char **l); |
19 | DEFINE_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 | |
22 | char **strv_free_erase(char **l); |
23 | DEFINE_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 | |
26 | void strv_clear(char **l); |
27 | |
28 | char **strv_copy(char * const *l); |
29 | size_t strv_length(char * const *l) _pure___attribute__ ((pure)); |
30 | |
31 | int strv_extend_strv(char ***a, char **b, bool_Bool filter_duplicates); |
32 | int strv_extend_strv_concat(char ***a, char **b, const char *suffix); |
33 | int strv_extend(char ***l, const char *value); |
34 | int strv_extendf(char ***l, const char *format, ...) _printf_(2,0)__attribute__ ((format (printf, 2, 0))); |
35 | int strv_extend_front(char ***l, const char *value); |
36 | int strv_push(char ***l, char *value); |
37 | int strv_push_pair(char ***l, char *a, char *b); |
38 | int strv_insert(char ***l, size_t position, char *value); |
39 | |
40 | static inline int strv_push_prepend(char ***l, char *value) { |
41 | return strv_insert(l, 0, value); |
42 | } |
43 | |
44 | int strv_consume(char ***l, char *value); |
45 | int strv_consume_pair(char ***l, char *a, char *b); |
46 | int strv_consume_prepend(char ***l, char *value); |
47 | |
48 | char **strv_remove(char **l, const char *s); |
49 | char **strv_uniq(char **l); |
50 | bool_Bool strv_is_uniq(char **l); |
51 | |
52 | bool_Bool strv_equal(char **a, char **b); |
53 | |
54 | #define strv_contains(l, s)(!!strv_find((l), (s))) (!!strv_find((l), (s))) |
55 | |
56 | char **strv_new(const char *x, ...) _sentinel___attribute__ ((sentinel)); |
57 | char **strv_new_ap(const char *x, va_list ap); |
58 | |
59 | #define STRV_IGNORE((const char *) -1) ((const char *) -1) |
60 | |
61 | static inline const char* STRV_IFNOTNULL(const char *x) { |
62 | return x ? x : STRV_IGNORE((const char *) -1); |
63 | } |
64 | |
65 | static inline bool_Bool strv_isempty(char * const *l) { |
66 | return !l || !*l; |
67 | } |
68 | |
69 | char **strv_split(const char *s, const char *separator); |
70 | char **strv_split_newlines(const char *s); |
71 | |
72 | int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); |
73 | |
74 | char *strv_join(char **l, const char *separator); |
75 | |
76 | char **strv_parse_nulstr(const char *s, size_t l); |
77 | char **strv_split_nulstr(const char *s); |
78 | int strv_make_nulstr(char **l, char **p, size_t *n); |
79 | |
80 | bool_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 | |
96 | char **strv_sort(char **l); |
97 | void 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 | |
163 | char **strv_reverse(char **l); |
164 | char **strv_shell_escape(char **l, const char *bad); |
165 | |
166 | bool_Bool strv_fnmatch(char* const* patterns, const char *s, int flags); |
167 | |
168 | static 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 | |
174 | char ***strv_free_free(char ***l); |
175 | DEFINE_TRIVIAL_CLEANUP_FUNC(char***, strv_free_free)static inline void strv_free_freep(char*** *p) { if (*p) strv_free_free (*p); }; |
176 | |
177 | char **strv_skip(char **l, size_t n); |
178 | |
179 | int strv_extend_n(char ***l, const char *value, size_t n); |
180 | |
181 | int 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 | }) |