Bug Summary

File:build-scan/../src/basic/exec-util.c
Warning:line 136, column 25
Value stored to 'fd' is never read

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 exec-util.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 pic -pic-level 2 -fhalf-no-semantic-interposition -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 src/basic/libbasic.a.p -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 . -I .. -I /usr/include/blkid -I /usr/include/libmount -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 default -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/basic/exec-util.c
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 */
28assert_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
30static 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
68static 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
164int 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
217static 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
264static 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
289static 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
318const gather_stdout_callback_t gather_environment[] = {
319 gather_environment_generate,
320 gather_environment_collect,
321 gather_environment_consume,
322};