| 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 | }) |