| File: | build-scan/../src/basic/exec-util.c |
| Warning: | line 136, column 25 Value stored to 'fd' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
| 2 | |
| 3 | #include <dirent.h> |
| 4 | #include <errno(*__errno_location ()).h> |
| 5 | #include <sys/prctl.h> |
| 6 | #include <sys/types.h> |
| 7 | #include <unistd.h> |
| 8 | #include <stdio.h> |
| 9 | |
| 10 | #include "alloc-util.h" |
| 11 | #include "conf-files.h" |
| 12 | #include "env-util.h" |
| 13 | #include "exec-util.h" |
| 14 | #include "fd-util.h" |
| 15 | #include "fileio.h" |
| 16 | #include "hashmap.h" |
| 17 | #include "macro.h" |
| 18 | #include "process-util.h" |
| 19 | #include "set.h" |
| 20 | #include "signal-util.h" |
| 21 | #include "stat-util.h" |
| 22 | #include "string-util.h" |
| 23 | #include "strv.h" |
| 24 | #include "terminal-util.h" |
| 25 | #include "util.h" |
| 26 | |
| 27 | /* Put this test here for a lack of better place */ |
| 28 | assert_cc(EAGAIN == EWOULDBLOCK)GCC diagnostic push
; GCC diagnostic ignored "-Wdeclaration-after-statement" ; struct _assert_struct_4 { char x[(11 == 11) ? 0 : -1]; }; GCC diagnostic pop ; |
| 29 | |
| 30 | static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) { |
| 31 | |
| 32 | pid_t _pid; |
| 33 | int r; |
| 34 | |
| 35 | if (null_or_empty_path(path)) { |
| 36 | log_debug("%s is empty (a mask).", path)({ 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/basic/exec-util.c", 36, __func__, "%s is empty (a mask)." , path) : -abs(_e); }); |
| 37 | return 0; |
| 38 | } |
| 39 | |
| 40 | r = safe_fork("(direxec)", FORK_DEATHSIG|FORK_LOG, &_pid); |
| 41 | if (r < 0) |
| 42 | return r; |
| 43 | if (r == 0) { |
| 44 | char *_argv[2]; |
| 45 | |
| 46 | if (stdout_fd >= 0) { |
| 47 | r = rearrange_stdio(STDIN_FILENO0, stdout_fd, STDERR_FILENO2); |
| 48 | if (r < 0) |
| 49 | _exit(EXIT_FAILURE1); |
| 50 | } |
| 51 | |
| 52 | if (!argv) { |
| 53 | _argv[0] = (char*) path; |
| 54 | _argv[1] = NULL((void*)0); |
| 55 | argv = _argv; |
| 56 | } else |
| 57 | argv[0] = (char*) path; |
| 58 | |
| 59 | execv(path, argv); |
| 60 | log_error_errno(errno, "Failed to execute %s: %m", path)({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/basic/exec-util.c", 60, __func__ , "Failed to execute %s: %m", path) : -abs(_e); }); |
| 61 | _exit(EXIT_FAILURE1); |
| 62 | } |
| 63 | |
| 64 | *pid = _pid; |
| 65 | return 1; |
| 66 | } |
| 67 | |
| 68 | static int do_execute( |
| 69 | char **directories, |
| 70 | usec_t timeout, |
| 71 | gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], |
| 72 | void* const callback_args[_STDOUT_CONSUME_MAX], |
| 73 | int output_fd, |
| 74 | char *argv[]) { |
| 75 | |
| 76 | _cleanup_hashmap_free_free___attribute__((cleanup(hashmap_free_freep))) Hashmap *pids = NULL((void*)0); |
| 77 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **paths = NULL((void*)0); |
| 78 | char **path; |
| 79 | int r; |
| 80 | |
| 81 | /* We fork this all off from a child process so that we can somewhat cleanly make |
| 82 | * use of SIGALRM to set a time limit. |
| 83 | * |
| 84 | * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel. |
| 85 | */ |
| 86 | |
| 87 | r = conf_files_list_strv(&paths, NULL((void*)0), NULL((void*)0), CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories); |
| 88 | if (r < 0) |
| 89 | return r; |
| 90 | |
| 91 | if (!callbacks) { |
| 92 | pids = hashmap_new(NULL)internal_hashmap_new(((void*)0) ); |
| 93 | if (!pids) |
| 94 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/basic/exec-util.c" , 94, __func__); |
| 95 | } |
| 96 | |
| 97 | /* Abort execution of this process after the timout. We simply rely on SIGALRM as |
| 98 | * default action terminating the process, and turn on alarm(). */ |
| 99 | |
| 100 | if (timeout != USEC_INFINITY((usec_t) -1)) |
| 101 | alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC)({ const typeof((timeout)) __unique_prefix_X5 = ((timeout)); const typeof((((usec_t) 1000000ULL))) __unique_prefix_Y6 = ((((usec_t ) 1000000ULL))); (__unique_prefix_X5 / __unique_prefix_Y6 + ! !(__unique_prefix_X5 % __unique_prefix_Y6)); })); |
| 102 | |
| 103 | STRV_FOREACH(path, paths)for ((path) = (paths); (path) && *(path); (path)++) { |
| 104 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); |
| 105 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; |
| 106 | pid_t pid; |
| 107 | |
| 108 | t = strdup(*path); |
| 109 | if (!t) |
| 110 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/basic/exec-util.c" , 110, __func__); |
| 111 | |
| 112 | if (callbacks) { |
| 113 | fd = open_serialization_fd(basename(*path)); |
| 114 | if (fd < 0) |
| 115 | return log_error_errno(fd, "Failed to open serialization file: %m")({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/basic/exec-util.c", 115, __func__, "Failed to open serialization file: %m" ) : -abs(_e); }); |
| 116 | } |
| 117 | |
| 118 | r = do_spawn(t, argv, fd, &pid); |
| 119 | if (r <= 0) |
| 120 | continue; |
| 121 | |
| 122 | if (pids) { |
| 123 | r = hashmap_put(pids, PID_TO_PTR(pid), t); |
| 124 | if (r < 0) |
| 125 | return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/basic/exec-util.c" , 125, __func__); |
| 126 | t = NULL((void*)0); |
| 127 | } else { |
| 128 | r = wait_for_terminate_and_check(t, pid, WAIT_LOG); |
| 129 | if (r < 0) |
| 130 | continue; |
| 131 | |
| 132 | if (lseek(fd, 0, SEEK_SET0) < 0) |
| 133 | return log_error_errno(errno, "Failed to seek on serialization fd: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/basic/exec-util.c", 133, __func__ , "Failed to seek on serialization fd: %m") : -abs(_e); }); |
| 134 | |
| 135 | r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]); |
| 136 | fd = -1; |
Value stored to 'fd' is never read | |
| 137 | if (r < 0) |
| 138 | return log_error_errno(r, "Failed to process output from %s: %m", *path)({ 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/basic/exec-util.c", 138, __func__, "Failed to process output from %s: %m" , *path) : -abs(_e); }); |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | if (callbacks) { |
| 143 | r = callbacks[STDOUT_COLLECT](output_fd, callback_args[STDOUT_COLLECT]); |
| 144 | if (r < 0) |
| 145 | return log_error_errno(r, "Callback two failed: %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/basic/exec-util.c", 145, __func__, "Callback two failed: %m" ) : -abs(_e); }); |
| 146 | } |
| 147 | |
| 148 | while (!hashmap_isempty(pids)) { |
| 149 | _cleanup_free___attribute__((cleanup(freep))) char *t = NULL((void*)0); |
| 150 | pid_t pid; |
| 151 | |
| 152 | pid = PTR_TO_PID(hashmap_first_key(pids)); |
| 153 | assert(pid > 0)do { if ((__builtin_expect(!!(!(pid > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("pid > 0"), "../src/basic/exec-util.c" , 153, __PRETTY_FUNCTION__); } while (0); |
| 154 | |
| 155 | t = hashmap_remove(pids, PID_TO_PTR(pid)); |
| 156 | assert(t)do { if ((__builtin_expect(!!(!(t)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("t"), "../src/basic/exec-util.c", 156, __PRETTY_FUNCTION__ ); } while (0); |
| 157 | |
| 158 | (void) wait_for_terminate_and_check(t, pid, WAIT_LOG); |
| 159 | } |
| 160 | |
| 161 | return 0; |
| 162 | } |
| 163 | |
| 164 | int execute_directories( |
| 165 | const char* const* directories, |
| 166 | usec_t timeout, |
| 167 | gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], |
| 168 | void* const callback_args[_STDOUT_CONSUME_MAX], |
| 169 | char *argv[]) { |
| 170 | |
| 171 | char **dirs = (char**) directories; |
| 172 | _cleanup_close___attribute__((cleanup(closep))) int fd = -1; |
| 173 | char *name; |
| 174 | int r; |
| 175 | |
| 176 | assert(!strv_isempty(dirs))do { if ((__builtin_expect(!!(!(!strv_isempty(dirs))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!strv_isempty(dirs)"), "../src/basic/exec-util.c" , 176, __PRETTY_FUNCTION__); } while (0); |
| 177 | |
| 178 | name = basename(dirs[0]); |
| 179 | assert(!isempty(name))do { if ((__builtin_expect(!!(!(!isempty(name))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!isempty(name)"), "../src/basic/exec-util.c" , 179, __PRETTY_FUNCTION__); } while (0); |
| 180 | |
| 181 | if (callbacks) { |
| 182 | assert(callback_args)do { if ((__builtin_expect(!!(!(callback_args)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("callback_args"), "../src/basic/exec-util.c" , 182, __PRETTY_FUNCTION__); } while (0); |
| 183 | assert(callbacks[STDOUT_GENERATE])do { if ((__builtin_expect(!!(!(callbacks[STDOUT_GENERATE])), 0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("callbacks[STDOUT_GENERATE]" ), "../src/basic/exec-util.c", 183, __PRETTY_FUNCTION__); } while (0); |
| 184 | assert(callbacks[STDOUT_COLLECT])do { if ((__builtin_expect(!!(!(callbacks[STDOUT_COLLECT])),0 ))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("callbacks[STDOUT_COLLECT]" ), "../src/basic/exec-util.c", 184, __PRETTY_FUNCTION__); } while (0); |
| 185 | assert(callbacks[STDOUT_CONSUME])do { if ((__builtin_expect(!!(!(callbacks[STDOUT_CONSUME])),0 ))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("callbacks[STDOUT_CONSUME]" ), "../src/basic/exec-util.c", 185, __PRETTY_FUNCTION__); } while (0); |
| 186 | |
| 187 | fd = open_serialization_fd(name); |
| 188 | if (fd < 0) |
| 189 | return log_error_errno(fd, "Failed to open serialization file: %m")({ int _level = ((3)), _e = ((fd)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/basic/exec-util.c", 189, __func__, "Failed to open serialization file: %m" ) : -abs(_e); }); |
| 190 | } |
| 191 | |
| 192 | /* Executes all binaries in the directories serially or in parallel and waits for |
| 193 | * them to finish. Optionally a timeout is applied. If a file with the same name |
| 194 | * exists in more than one directory, the earliest one wins. */ |
| 195 | |
| 196 | r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL((void*)0)); |
| 197 | if (r < 0) |
| 198 | return r; |
| 199 | if (r == 0) { |
| 200 | r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv); |
| 201 | _exit(r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0); |
| 202 | } |
| 203 | |
| 204 | if (!callbacks) |
| 205 | return 0; |
| 206 | |
| 207 | if (lseek(fd, 0, SEEK_SET0) < 0) |
| 208 | return log_error_errno(errno, "Failed to rewind serialization fd: %m")({ int _level = ((3)), _e = (((*__errno_location ()))), _realm = (LOG_REALM_SYSTEMD); (log_get_max_level_realm(_realm) >= ((_level) & 0x07)) ? log_internal_realm(((_realm) << 10 | (_level)), _e, "../src/basic/exec-util.c", 208, __func__ , "Failed to rewind serialization fd: %m") : -abs(_e); }); |
| 209 | |
| 210 | r = callbacks[STDOUT_CONSUME](fd, callback_args[STDOUT_CONSUME]); |
| 211 | fd = -1; |
| 212 | if (r < 0) |
| 213 | return log_error_errno(r, "Failed to parse returned data: %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/basic/exec-util.c", 213, __func__, "Failed to parse returned data: %m" ) : -abs(_e); }); |
| 214 | return 0; |
| 215 | } |
| 216 | |
| 217 | static int gather_environment_generate(int fd, void *arg) { |
| 218 | char ***env = arg, **x, **y; |
| 219 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); |
| 220 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **new = NULL((void*)0); |
| 221 | int r; |
| 222 | |
| 223 | /* Read a series of VAR=value assignments from fd, use them to update the list of |
| 224 | * variables in env. Also update the exported environment. |
| 225 | * |
| 226 | * fd is always consumed, even on error. |
| 227 | */ |
| 228 | |
| 229 | assert(env)do { if ((__builtin_expect(!!(!(env)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("env"), "../src/basic/exec-util.c", 229, __PRETTY_FUNCTION__); } while (0); |
| 230 | |
| 231 | f = fdopen(fd, "r"); |
| 232 | if (!f) { |
| 233 | safe_close(fd); |
| 234 | return -errno(*__errno_location ()); |
| 235 | } |
| 236 | |
| 237 | r = load_env_file_pairs(f, NULL((void*)0), NULL((void*)0), &new); |
| 238 | if (r < 0) |
| 239 | return r; |
| 240 | |
| 241 | STRV_FOREACH_PAIR(x, y, new)for ((x) = (new), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) { |
| 242 | char *p; |
| 243 | |
| 244 | if (!env_name_is_valid(*x)) { |
| 245 | log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/basic/exec-util.c", 245, __func__, "Invalid variable assignment \"%s=...\", ignoring." , *x) : -abs(_e); }); |
| 246 | continue; |
| 247 | } |
| 248 | |
| 249 | p = strjoin(*x, "=", *y)strjoin_real((*x), "=", *y, ((void*)0)); |
| 250 | if (!p) |
| 251 | return -ENOMEM12; |
| 252 | |
| 253 | r = strv_env_replace(env, p); |
| 254 | if (r < 0) |
| 255 | return r; |
| 256 | |
| 257 | if (setenv(*x, *y, true1) < 0) |
| 258 | return -errno(*__errno_location ()); |
| 259 | } |
| 260 | |
| 261 | return r; |
| 262 | } |
| 263 | |
| 264 | static int gather_environment_collect(int fd, void *arg) { |
| 265 | char ***env = arg; |
| 266 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); |
| 267 | int r; |
| 268 | |
| 269 | /* Write out a series of env=cescape(VAR=value) assignments to fd. */ |
| 270 | |
| 271 | assert(env)do { if ((__builtin_expect(!!(!(env)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("env"), "../src/basic/exec-util.c", 271, __PRETTY_FUNCTION__); } while (0); |
| 272 | |
| 273 | f = fdopen(fd, "w"); |
| 274 | if (!f) { |
| 275 | safe_close(fd); |
| 276 | return -errno(*__errno_location ()); |
| 277 | } |
| 278 | |
| 279 | r = serialize_environment(f, *env); |
| 280 | if (r < 0) |
| 281 | return r; |
| 282 | |
| 283 | if (ferror(f)) |
| 284 | return errno(*__errno_location ()) > 0 ? -errno(*__errno_location ()) : -EIO5; |
| 285 | |
| 286 | return 0; |
| 287 | } |
| 288 | |
| 289 | static int gather_environment_consume(int fd, void *arg) { |
| 290 | char ***env = arg; |
| 291 | _cleanup_fclose___attribute__((cleanup(fclosep))) FILE *f = NULL((void*)0); |
| 292 | char line[LINE_MAX2048]; |
| 293 | int r = 0, k; |
| 294 | |
| 295 | /* Read a series of env=cescape(VAR=value) assignments from fd into env. */ |
| 296 | |
| 297 | assert(env)do { if ((__builtin_expect(!!(!(env)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("env"), "../src/basic/exec-util.c", 297, __PRETTY_FUNCTION__); } while (0); |
| 298 | |
| 299 | f = fdopen(fd, "r"); |
| 300 | if (!f) { |
| 301 | safe_close(fd); |
| 302 | return -errno(*__errno_location ()); |
| 303 | } |
| 304 | |
| 305 | FOREACH_LINE(line, f, return -EIO)for (;;) if (!fgets(line, sizeof(line), f)) { if (ferror(f)) { return -5; } break; } else { |
| 306 | truncate_nl(line); |
| 307 | |
| 308 | k = deserialize_environment(env, line); |
| 309 | if (k < 0) |
| 310 | log_error_errno(k, "Invalid line \"%s\": %m", line)({ 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/basic/exec-util.c", 310, __func__, "Invalid line \"%s\": %m" , line) : -abs(_e); }); |
| 311 | if (k < 0 && r == 0) |
| 312 | r = k; |
| 313 | } |
| 314 | |
| 315 | return r; |
| 316 | } |
| 317 | |
| 318 | const gather_stdout_callback_t gather_environment[] = { |
| 319 | gather_environment_generate, |
| 320 | gather_environment_collect, |
| 321 | gather_environment_consume, |
| 322 | }; |