xref: /llvm-project/clang/tools/scan-build-py/lib/libear/ear.c (revision 5674a3c88088e668b684326c2194a6282e8270ff)
1d9cf8291SDaniel Hwang /* -*- coding: utf-8 -*-
2d9cf8291SDaniel Hwang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3d9cf8291SDaniel Hwang // See https://llvm.org/LICENSE.txt for license information.
4d9cf8291SDaniel Hwang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5d9cf8291SDaniel Hwang */
6d9cf8291SDaniel Hwang 
7d9cf8291SDaniel Hwang /**
8d9cf8291SDaniel Hwang  * This file implements a shared library. This library can be pre-loaded by
9d9cf8291SDaniel Hwang  * the dynamic linker of the Operating System (OS). It implements a few function
10d9cf8291SDaniel Hwang  * related to process creation. By pre-load this library the executed process
11d9cf8291SDaniel Hwang  * uses these functions instead of those from the standard library.
12d9cf8291SDaniel Hwang  *
13d9cf8291SDaniel Hwang  * The idea here is to inject a logic before call the real methods. The logic is
14d9cf8291SDaniel Hwang  * to dump the call into a file. To call the real method this library is doing
15d9cf8291SDaniel Hwang  * the job of the dynamic linker.
16d9cf8291SDaniel Hwang  *
17d9cf8291SDaniel Hwang  * The only input for the log writing is about the destination directory.
18d9cf8291SDaniel Hwang  * This is passed as environment variable.
19d9cf8291SDaniel Hwang  */
20d9cf8291SDaniel Hwang 
21d9cf8291SDaniel Hwang // NOLINTNEXTLINE
22d9cf8291SDaniel Hwang #include "config.h"
23d9cf8291SDaniel Hwang 
24d9cf8291SDaniel Hwang #include <dlfcn.h>
25d9cf8291SDaniel Hwang #include <pthread.h>
26d9cf8291SDaniel Hwang #include <stdarg.h>
27d9cf8291SDaniel Hwang #include <stddef.h>
28d9cf8291SDaniel Hwang #include <stdio.h>
29d9cf8291SDaniel Hwang #include <stdlib.h>
30d9cf8291SDaniel Hwang #include <string.h>
31d9cf8291SDaniel Hwang #include <unistd.h>
32d9cf8291SDaniel Hwang 
33d9cf8291SDaniel Hwang #if defined HAVE_POSIX_SPAWN || defined HAVE_POSIX_SPAWNP
34d9cf8291SDaniel Hwang #include <spawn.h>
35d9cf8291SDaniel Hwang #endif
36d9cf8291SDaniel Hwang 
37d9cf8291SDaniel Hwang #if defined HAVE_NSGETENVIRON
38d9cf8291SDaniel Hwang #include <crt_externs.h>
39d9cf8291SDaniel Hwang #else
40d9cf8291SDaniel Hwang extern char **environ;
41d9cf8291SDaniel Hwang #endif
42d9cf8291SDaniel Hwang 
43d9cf8291SDaniel Hwang #define ENV_OUTPUT "INTERCEPT_BUILD_TARGET_DIR"
44d9cf8291SDaniel Hwang #ifdef APPLE
45d9cf8291SDaniel Hwang #define ENV_FLAT "DYLD_FORCE_FLAT_NAMESPACE"
46d9cf8291SDaniel Hwang #define ENV_PRELOAD "DYLD_INSERT_LIBRARIES"
47d9cf8291SDaniel Hwang #define ENV_SIZE 3
48d9cf8291SDaniel Hwang #else
49d9cf8291SDaniel Hwang #define ENV_PRELOAD "LD_PRELOAD"
50d9cf8291SDaniel Hwang #define ENV_SIZE 2
51d9cf8291SDaniel Hwang #endif
52d9cf8291SDaniel Hwang 
53d9cf8291SDaniel Hwang #define DLSYM(TYPE_, VAR_, SYMBOL_)                                            \
54d9cf8291SDaniel Hwang   union {                                                                      \
55d9cf8291SDaniel Hwang     void *from;                                                                \
56d9cf8291SDaniel Hwang     TYPE_ to;                                                                  \
57d9cf8291SDaniel Hwang   } cast;                                                                      \
58d9cf8291SDaniel Hwang   if (0 == (cast.from = dlsym(RTLD_NEXT, SYMBOL_))) {                          \
59d9cf8291SDaniel Hwang     perror("bear: dlsym");                                                     \
60d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);                                                        \
61d9cf8291SDaniel Hwang   }                                                                            \
62d9cf8291SDaniel Hwang   TYPE_ const VAR_ = cast.to;
63d9cf8291SDaniel Hwang 
64d9cf8291SDaniel Hwang typedef char const *bear_env_t[ENV_SIZE];
65d9cf8291SDaniel Hwang 
66d9cf8291SDaniel Hwang static int bear_capture_env_t(bear_env_t *env);
67d9cf8291SDaniel Hwang static int bear_reset_env_t(bear_env_t *env);
68d9cf8291SDaniel Hwang static void bear_release_env_t(bear_env_t *env);
69d9cf8291SDaniel Hwang static char const **bear_update_environment(char *const envp[],
70d9cf8291SDaniel Hwang                                             bear_env_t *env);
71d9cf8291SDaniel Hwang static char const **bear_update_environ(char const **in, char const *key,
72d9cf8291SDaniel Hwang                                         char const *value);
73d9cf8291SDaniel Hwang static char **bear_get_environment();
74d9cf8291SDaniel Hwang static void bear_report_call(char const *fun, char const *const argv[]);
75d9cf8291SDaniel Hwang static char const **bear_strings_build(char const *arg, va_list *ap);
76d9cf8291SDaniel Hwang static char const **bear_strings_copy(char const **const in);
77d9cf8291SDaniel Hwang static char const **bear_strings_append(char const **in, char const *e);
78d9cf8291SDaniel Hwang static size_t bear_strings_length(char const *const *in);
79d9cf8291SDaniel Hwang static void bear_strings_release(char const **);
80d9cf8291SDaniel Hwang 
81d9cf8291SDaniel Hwang static bear_env_t env_names = {ENV_OUTPUT, ENV_PRELOAD
82d9cf8291SDaniel Hwang #ifdef ENV_FLAT
83d9cf8291SDaniel Hwang                                ,
84d9cf8291SDaniel Hwang                                ENV_FLAT
85d9cf8291SDaniel Hwang #endif
86d9cf8291SDaniel Hwang };
87d9cf8291SDaniel Hwang 
88d9cf8291SDaniel Hwang static bear_env_t initial_env = {0, 0
89d9cf8291SDaniel Hwang #ifdef ENV_FLAT
90d9cf8291SDaniel Hwang                                  ,
91d9cf8291SDaniel Hwang                                  0
92d9cf8291SDaniel Hwang #endif
93d9cf8291SDaniel Hwang };
94d9cf8291SDaniel Hwang 
95d9cf8291SDaniel Hwang static int initialized = 0;
96d9cf8291SDaniel Hwang static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97d9cf8291SDaniel Hwang 
98d9cf8291SDaniel Hwang static void on_load(void) __attribute__((constructor));
99d9cf8291SDaniel Hwang static void on_unload(void) __attribute__((destructor));
100d9cf8291SDaniel Hwang 
101d9cf8291SDaniel Hwang #ifdef HAVE_EXECVE
102d9cf8291SDaniel Hwang static int call_execve(const char *path, char *const argv[],
103d9cf8291SDaniel Hwang                        char *const envp[]);
104d9cf8291SDaniel Hwang #endif
105d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP
106d9cf8291SDaniel Hwang static int call_execvp(const char *file, char *const argv[]);
107d9cf8291SDaniel Hwang #endif
108d9cf8291SDaniel Hwang #ifdef HAVE_EXECVPE
109d9cf8291SDaniel Hwang static int call_execvpe(const char *file, char *const argv[],
110d9cf8291SDaniel Hwang                         char *const envp[]);
111d9cf8291SDaniel Hwang #endif
112d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP2
113d9cf8291SDaniel Hwang static int call_execvP(const char *file, const char *search_path,
114d9cf8291SDaniel Hwang                        char *const argv[]);
115d9cf8291SDaniel Hwang #endif
116d9cf8291SDaniel Hwang #ifdef HAVE_EXECT
117d9cf8291SDaniel Hwang static int call_exect(const char *path, char *const argv[], char *const envp[]);
118d9cf8291SDaniel Hwang #endif
119d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWN
120d9cf8291SDaniel Hwang static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
121d9cf8291SDaniel Hwang                             const posix_spawn_file_actions_t *file_actions,
122d9cf8291SDaniel Hwang                             const posix_spawnattr_t *restrict attrp,
123d9cf8291SDaniel Hwang                             char *const argv[restrict],
124d9cf8291SDaniel Hwang                             char *const envp[restrict]);
125d9cf8291SDaniel Hwang #endif
126d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWNP
127d9cf8291SDaniel Hwang static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
128d9cf8291SDaniel Hwang                              const posix_spawn_file_actions_t *file_actions,
129d9cf8291SDaniel Hwang                              const posix_spawnattr_t *restrict attrp,
130d9cf8291SDaniel Hwang                              char *const argv[restrict],
131d9cf8291SDaniel Hwang                              char *const envp[restrict]);
132d9cf8291SDaniel Hwang #endif
133d9cf8291SDaniel Hwang 
134d9cf8291SDaniel Hwang /* Initialization method to Captures the relevant environment variables.
135d9cf8291SDaniel Hwang  */
136d9cf8291SDaniel Hwang 
on_load(void)137d9cf8291SDaniel Hwang static void on_load(void) {
138d9cf8291SDaniel Hwang   pthread_mutex_lock(&mutex);
139d9cf8291SDaniel Hwang   if (!initialized)
140d9cf8291SDaniel Hwang     initialized = bear_capture_env_t(&initial_env);
141d9cf8291SDaniel Hwang   pthread_mutex_unlock(&mutex);
142d9cf8291SDaniel Hwang }
143d9cf8291SDaniel Hwang 
on_unload(void)144d9cf8291SDaniel Hwang static void on_unload(void) {
145d9cf8291SDaniel Hwang   pthread_mutex_lock(&mutex);
146d9cf8291SDaniel Hwang   bear_release_env_t(&initial_env);
147d9cf8291SDaniel Hwang   initialized = 0;
148d9cf8291SDaniel Hwang   pthread_mutex_unlock(&mutex);
149d9cf8291SDaniel Hwang }
150d9cf8291SDaniel Hwang 
151d9cf8291SDaniel Hwang /* These are the methods we are try to hijack.
152d9cf8291SDaniel Hwang  */
153d9cf8291SDaniel Hwang 
154d9cf8291SDaniel Hwang #ifdef HAVE_EXECVE
execve(const char * path,char * const argv[],char * const envp[])155d9cf8291SDaniel Hwang int execve(const char *path, char *const argv[], char *const envp[]) {
156d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
157d9cf8291SDaniel Hwang   return call_execve(path, argv, envp);
158d9cf8291SDaniel Hwang }
159d9cf8291SDaniel Hwang #endif
160d9cf8291SDaniel Hwang 
161d9cf8291SDaniel Hwang #ifdef HAVE_EXECV
162d9cf8291SDaniel Hwang #ifndef HAVE_EXECVE
163d9cf8291SDaniel Hwang #error can not implement execv without execve
164d9cf8291SDaniel Hwang #endif
execv(const char * path,char * const argv[])165d9cf8291SDaniel Hwang int execv(const char *path, char *const argv[]) {
166d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
167d9cf8291SDaniel Hwang   char *const *envp = bear_get_environment();
168d9cf8291SDaniel Hwang   return call_execve(path, argv, envp);
169d9cf8291SDaniel Hwang }
170d9cf8291SDaniel Hwang #endif
171d9cf8291SDaniel Hwang 
172d9cf8291SDaniel Hwang #ifdef HAVE_EXECVPE
execvpe(const char * file,char * const argv[],char * const envp[])173d9cf8291SDaniel Hwang int execvpe(const char *file, char *const argv[], char *const envp[]) {
174d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
175d9cf8291SDaniel Hwang   return call_execvpe(file, argv, envp);
176d9cf8291SDaniel Hwang }
177d9cf8291SDaniel Hwang #endif
178d9cf8291SDaniel Hwang 
179d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP
execvp(const char * file,char * const argv[])180d9cf8291SDaniel Hwang int execvp(const char *file, char *const argv[]) {
181d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
182d9cf8291SDaniel Hwang   return call_execvp(file, argv);
183d9cf8291SDaniel Hwang }
184d9cf8291SDaniel Hwang #endif
185d9cf8291SDaniel Hwang 
186d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP2
execvP(const char * file,const char * search_path,char * const argv[])187d9cf8291SDaniel Hwang int execvP(const char *file, const char *search_path, char *const argv[]) {
188d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
189d9cf8291SDaniel Hwang   return call_execvP(file, search_path, argv);
190d9cf8291SDaniel Hwang }
191d9cf8291SDaniel Hwang #endif
192d9cf8291SDaniel Hwang 
193d9cf8291SDaniel Hwang #ifdef HAVE_EXECT
exect(const char * path,char * const argv[],char * const envp[])194d9cf8291SDaniel Hwang int exect(const char *path, char *const argv[], char *const envp[]) {
195d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
196d9cf8291SDaniel Hwang   return call_exect(path, argv, envp);
197d9cf8291SDaniel Hwang }
198d9cf8291SDaniel Hwang #endif
199d9cf8291SDaniel Hwang 
200d9cf8291SDaniel Hwang #ifdef HAVE_EXECL
201d9cf8291SDaniel Hwang #ifndef HAVE_EXECVE
202d9cf8291SDaniel Hwang #error can not implement execl without execve
203d9cf8291SDaniel Hwang #endif
execl(const char * path,const char * arg,...)204d9cf8291SDaniel Hwang int execl(const char *path, const char *arg, ...) {
205d9cf8291SDaniel Hwang   va_list args;
206d9cf8291SDaniel Hwang   va_start(args, arg);
207d9cf8291SDaniel Hwang   char const **argv = bear_strings_build(arg, &args);
208d9cf8291SDaniel Hwang   va_end(args);
209d9cf8291SDaniel Hwang 
210d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
211d9cf8291SDaniel Hwang   char *const *envp = bear_get_environment();
212d9cf8291SDaniel Hwang   int const result = call_execve(path, (char *const *)argv, envp);
213d9cf8291SDaniel Hwang 
214d9cf8291SDaniel Hwang   bear_strings_release(argv);
215d9cf8291SDaniel Hwang   return result;
216d9cf8291SDaniel Hwang }
217d9cf8291SDaniel Hwang #endif
218d9cf8291SDaniel Hwang 
219d9cf8291SDaniel Hwang #ifdef HAVE_EXECLP
220d9cf8291SDaniel Hwang #ifndef HAVE_EXECVP
221d9cf8291SDaniel Hwang #error can not implement execlp without execvp
222d9cf8291SDaniel Hwang #endif
execlp(const char * file,const char * arg,...)223d9cf8291SDaniel Hwang int execlp(const char *file, const char *arg, ...) {
224d9cf8291SDaniel Hwang   va_list args;
225d9cf8291SDaniel Hwang   va_start(args, arg);
226d9cf8291SDaniel Hwang   char const **argv = bear_strings_build(arg, &args);
227d9cf8291SDaniel Hwang   va_end(args);
228d9cf8291SDaniel Hwang 
229d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
230d9cf8291SDaniel Hwang   int const result = call_execvp(file, (char *const *)argv);
231d9cf8291SDaniel Hwang 
232d9cf8291SDaniel Hwang   bear_strings_release(argv);
233d9cf8291SDaniel Hwang   return result;
234d9cf8291SDaniel Hwang }
235d9cf8291SDaniel Hwang #endif
236d9cf8291SDaniel Hwang 
237d9cf8291SDaniel Hwang #ifdef HAVE_EXECLE
238d9cf8291SDaniel Hwang #ifndef HAVE_EXECVE
239d9cf8291SDaniel Hwang #error can not implement execle without execve
240d9cf8291SDaniel Hwang #endif
241d9cf8291SDaniel Hwang // int execle(const char *path, const char *arg, ..., char * const envp[]);
execle(const char * path,const char * arg,...)242d9cf8291SDaniel Hwang int execle(const char *path, const char *arg, ...) {
243d9cf8291SDaniel Hwang   va_list args;
244d9cf8291SDaniel Hwang   va_start(args, arg);
245d9cf8291SDaniel Hwang   char const **argv = bear_strings_build(arg, &args);
246d9cf8291SDaniel Hwang   char const **envp = va_arg(args, char const **);
247d9cf8291SDaniel Hwang   va_end(args);
248d9cf8291SDaniel Hwang 
249d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
250d9cf8291SDaniel Hwang   int const result =
251d9cf8291SDaniel Hwang       call_execve(path, (char *const *)argv, (char *const *)envp);
252d9cf8291SDaniel Hwang 
253d9cf8291SDaniel Hwang   bear_strings_release(argv);
254d9cf8291SDaniel Hwang   return result;
255d9cf8291SDaniel Hwang }
256d9cf8291SDaniel Hwang #endif
257d9cf8291SDaniel Hwang 
258d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWN
posix_spawn(pid_t * restrict pid,const char * restrict path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * restrict attrp,char * const argv[restrict],char * const envp[restrict])259d9cf8291SDaniel Hwang int posix_spawn(pid_t *restrict pid, const char *restrict path,
260d9cf8291SDaniel Hwang                 const posix_spawn_file_actions_t *file_actions,
261d9cf8291SDaniel Hwang                 const posix_spawnattr_t *restrict attrp,
262d9cf8291SDaniel Hwang                 char *const argv[restrict], char *const envp[restrict]) {
263d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
264d9cf8291SDaniel Hwang   return call_posix_spawn(pid, path, file_actions, attrp, argv, envp);
265d9cf8291SDaniel Hwang }
266d9cf8291SDaniel Hwang #endif
267d9cf8291SDaniel Hwang 
268d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWNP
posix_spawnp(pid_t * restrict pid,const char * restrict file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * restrict attrp,char * const argv[restrict],char * const envp[restrict])269d9cf8291SDaniel Hwang int posix_spawnp(pid_t *restrict pid, const char *restrict file,
270d9cf8291SDaniel Hwang                  const posix_spawn_file_actions_t *file_actions,
271d9cf8291SDaniel Hwang                  const posix_spawnattr_t *restrict attrp,
272d9cf8291SDaniel Hwang                  char *const argv[restrict], char *const envp[restrict]) {
273d9cf8291SDaniel Hwang   bear_report_call(__func__, (char const *const *)argv);
274d9cf8291SDaniel Hwang   return call_posix_spawnp(pid, file, file_actions, attrp, argv, envp);
275d9cf8291SDaniel Hwang }
276d9cf8291SDaniel Hwang #endif
277d9cf8291SDaniel Hwang 
278d9cf8291SDaniel Hwang /* These are the methods which forward the call to the standard implementation.
279d9cf8291SDaniel Hwang  */
280d9cf8291SDaniel Hwang 
281d9cf8291SDaniel Hwang #ifdef HAVE_EXECVE
call_execve(const char * path,char * const argv[],char * const envp[])282d9cf8291SDaniel Hwang static int call_execve(const char *path, char *const argv[],
283d9cf8291SDaniel Hwang                        char *const envp[]) {
284d9cf8291SDaniel Hwang   typedef int (*func)(const char *, char *const *, char *const *);
285d9cf8291SDaniel Hwang 
286d9cf8291SDaniel Hwang   DLSYM(func, fp, "execve");
287d9cf8291SDaniel Hwang 
288d9cf8291SDaniel Hwang   char const **const menvp = bear_update_environment(envp, &initial_env);
289d9cf8291SDaniel Hwang   int const result = (*fp)(path, argv, (char *const *)menvp);
290d9cf8291SDaniel Hwang   bear_strings_release(menvp);
291d9cf8291SDaniel Hwang   return result;
292d9cf8291SDaniel Hwang }
293d9cf8291SDaniel Hwang #endif
294d9cf8291SDaniel Hwang 
295d9cf8291SDaniel Hwang #ifdef HAVE_EXECVPE
call_execvpe(const char * file,char * const argv[],char * const envp[])296d9cf8291SDaniel Hwang static int call_execvpe(const char *file, char *const argv[],
297d9cf8291SDaniel Hwang                         char *const envp[]) {
298d9cf8291SDaniel Hwang   typedef int (*func)(const char *, char *const *, char *const *);
299d9cf8291SDaniel Hwang 
300d9cf8291SDaniel Hwang   DLSYM(func, fp, "execvpe");
301d9cf8291SDaniel Hwang 
302d9cf8291SDaniel Hwang   char const **const menvp = bear_update_environment(envp, &initial_env);
303d9cf8291SDaniel Hwang   int const result = (*fp)(file, argv, (char *const *)menvp);
304d9cf8291SDaniel Hwang   bear_strings_release(menvp);
305d9cf8291SDaniel Hwang   return result;
306d9cf8291SDaniel Hwang }
307d9cf8291SDaniel Hwang #endif
308d9cf8291SDaniel Hwang 
309d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP
call_execvp(const char * file,char * const argv[])310d9cf8291SDaniel Hwang static int call_execvp(const char *file, char *const argv[]) {
311d9cf8291SDaniel Hwang   typedef int (*func)(const char *file, char *const argv[]);
312d9cf8291SDaniel Hwang 
313d9cf8291SDaniel Hwang   DLSYM(func, fp, "execvp");
314d9cf8291SDaniel Hwang 
315d9cf8291SDaniel Hwang   bear_env_t current_env;
316d9cf8291SDaniel Hwang   bear_capture_env_t(&current_env);
317d9cf8291SDaniel Hwang   bear_reset_env_t(&initial_env);
318d9cf8291SDaniel Hwang   int const result = (*fp)(file, argv);
319d9cf8291SDaniel Hwang   bear_reset_env_t(&current_env);
320d9cf8291SDaniel Hwang   bear_release_env_t(&current_env);
321d9cf8291SDaniel Hwang 
322d9cf8291SDaniel Hwang   return result;
323d9cf8291SDaniel Hwang }
324d9cf8291SDaniel Hwang #endif
325d9cf8291SDaniel Hwang 
326d9cf8291SDaniel Hwang #ifdef HAVE_EXECVP2
call_execvP(const char * file,const char * search_path,char * const argv[])327d9cf8291SDaniel Hwang static int call_execvP(const char *file, const char *search_path,
328d9cf8291SDaniel Hwang                        char *const argv[]) {
329d9cf8291SDaniel Hwang   typedef int (*func)(const char *, const char *, char *const *);
330d9cf8291SDaniel Hwang 
331d9cf8291SDaniel Hwang   DLSYM(func, fp, "execvP");
332d9cf8291SDaniel Hwang 
333d9cf8291SDaniel Hwang   bear_env_t current_env;
334d9cf8291SDaniel Hwang   bear_capture_env_t(&current_env);
335d9cf8291SDaniel Hwang   bear_reset_env_t(&initial_env);
336d9cf8291SDaniel Hwang   int const result = (*fp)(file, search_path, argv);
337d9cf8291SDaniel Hwang   bear_reset_env_t(&current_env);
338d9cf8291SDaniel Hwang   bear_release_env_t(&current_env);
339d9cf8291SDaniel Hwang 
340d9cf8291SDaniel Hwang   return result;
341d9cf8291SDaniel Hwang }
342d9cf8291SDaniel Hwang #endif
343d9cf8291SDaniel Hwang 
344d9cf8291SDaniel Hwang #ifdef HAVE_EXECT
call_exect(const char * path,char * const argv[],char * const envp[])345d9cf8291SDaniel Hwang static int call_exect(const char *path, char *const argv[],
346d9cf8291SDaniel Hwang                       char *const envp[]) {
347d9cf8291SDaniel Hwang   typedef int (*func)(const char *, char *const *, char *const *);
348d9cf8291SDaniel Hwang 
349d9cf8291SDaniel Hwang   DLSYM(func, fp, "exect");
350d9cf8291SDaniel Hwang 
351d9cf8291SDaniel Hwang   char const **const menvp = bear_update_environment(envp, &initial_env);
352d9cf8291SDaniel Hwang   int const result = (*fp)(path, argv, (char *const *)menvp);
353d9cf8291SDaniel Hwang   bear_strings_release(menvp);
354d9cf8291SDaniel Hwang   return result;
355d9cf8291SDaniel Hwang }
356d9cf8291SDaniel Hwang #endif
357d9cf8291SDaniel Hwang 
358d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWN
call_posix_spawn(pid_t * restrict pid,const char * restrict path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * restrict attrp,char * const argv[restrict],char * const envp[restrict])359d9cf8291SDaniel Hwang static int call_posix_spawn(pid_t *restrict pid, const char *restrict path,
360d9cf8291SDaniel Hwang                             const posix_spawn_file_actions_t *file_actions,
361d9cf8291SDaniel Hwang                             const posix_spawnattr_t *restrict attrp,
362d9cf8291SDaniel Hwang                             char *const argv[restrict],
363d9cf8291SDaniel Hwang                             char *const envp[restrict]) {
364d9cf8291SDaniel Hwang   typedef int (*func)(pid_t *restrict, const char *restrict,
365d9cf8291SDaniel Hwang                       const posix_spawn_file_actions_t *,
366d9cf8291SDaniel Hwang                       const posix_spawnattr_t *restrict, char *const *restrict,
367d9cf8291SDaniel Hwang                       char *const *restrict);
368d9cf8291SDaniel Hwang 
369d9cf8291SDaniel Hwang   DLSYM(func, fp, "posix_spawn");
370d9cf8291SDaniel Hwang 
371d9cf8291SDaniel Hwang   char const **const menvp = bear_update_environment(envp, &initial_env);
372d9cf8291SDaniel Hwang   int const result =
373d9cf8291SDaniel Hwang       (*fp)(pid, path, file_actions, attrp, argv, (char *const *restrict)menvp);
374d9cf8291SDaniel Hwang   bear_strings_release(menvp);
375d9cf8291SDaniel Hwang   return result;
376d9cf8291SDaniel Hwang }
377d9cf8291SDaniel Hwang #endif
378d9cf8291SDaniel Hwang 
379d9cf8291SDaniel Hwang #ifdef HAVE_POSIX_SPAWNP
call_posix_spawnp(pid_t * restrict pid,const char * restrict file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * restrict attrp,char * const argv[restrict],char * const envp[restrict])380d9cf8291SDaniel Hwang static int call_posix_spawnp(pid_t *restrict pid, const char *restrict file,
381d9cf8291SDaniel Hwang                              const posix_spawn_file_actions_t *file_actions,
382d9cf8291SDaniel Hwang                              const posix_spawnattr_t *restrict attrp,
383d9cf8291SDaniel Hwang                              char *const argv[restrict],
384d9cf8291SDaniel Hwang                              char *const envp[restrict]) {
385d9cf8291SDaniel Hwang   typedef int (*func)(pid_t *restrict, const char *restrict,
386d9cf8291SDaniel Hwang                       const posix_spawn_file_actions_t *,
387d9cf8291SDaniel Hwang                       const posix_spawnattr_t *restrict, char *const *restrict,
388d9cf8291SDaniel Hwang                       char *const *restrict);
389d9cf8291SDaniel Hwang 
390d9cf8291SDaniel Hwang   DLSYM(func, fp, "posix_spawnp");
391d9cf8291SDaniel Hwang 
392d9cf8291SDaniel Hwang   char const **const menvp = bear_update_environment(envp, &initial_env);
393d9cf8291SDaniel Hwang   int const result =
394d9cf8291SDaniel Hwang       (*fp)(pid, file, file_actions, attrp, argv, (char *const *restrict)menvp);
395d9cf8291SDaniel Hwang   bear_strings_release(menvp);
396d9cf8291SDaniel Hwang   return result;
397d9cf8291SDaniel Hwang }
398d9cf8291SDaniel Hwang #endif
399d9cf8291SDaniel Hwang 
400d9cf8291SDaniel Hwang /* this method is to write log about the process creation. */
401d9cf8291SDaniel Hwang 
bear_report_call(char const * fun,char const * const argv[])402d9cf8291SDaniel Hwang static void bear_report_call(char const *fun, char const *const argv[]) {
403d9cf8291SDaniel Hwang   static int const GS = 0x1d;
404d9cf8291SDaniel Hwang   static int const RS = 0x1e;
405d9cf8291SDaniel Hwang   static int const US = 0x1f;
406d9cf8291SDaniel Hwang 
407d9cf8291SDaniel Hwang   if (!initialized)
408d9cf8291SDaniel Hwang     return;
409d9cf8291SDaniel Hwang 
410d9cf8291SDaniel Hwang   pthread_mutex_lock(&mutex);
411d9cf8291SDaniel Hwang   const char *cwd = getcwd(NULL, 0);
412d9cf8291SDaniel Hwang   if (0 == cwd) {
413d9cf8291SDaniel Hwang     perror("bear: getcwd");
414d919d027SBalazs Benics     pthread_mutex_unlock(&mutex);
415d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
416d9cf8291SDaniel Hwang   }
417d9cf8291SDaniel Hwang   char const *const out_dir = initial_env[0];
418d9cf8291SDaniel Hwang   size_t const path_max_length = strlen(out_dir) + 32;
419d9cf8291SDaniel Hwang   char filename[path_max_length];
420d9cf8291SDaniel Hwang   if (-1 ==
421d9cf8291SDaniel Hwang       snprintf(filename, path_max_length, "%s/%d.cmd", out_dir, getpid())) {
422d9cf8291SDaniel Hwang     perror("bear: snprintf");
423d919d027SBalazs Benics     pthread_mutex_unlock(&mutex);
424d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
425d9cf8291SDaniel Hwang   }
426d9cf8291SDaniel Hwang   FILE *fd = fopen(filename, "a+");
427d9cf8291SDaniel Hwang   if (0 == fd) {
428d9cf8291SDaniel Hwang     perror("bear: fopen");
429d919d027SBalazs Benics     pthread_mutex_unlock(&mutex);
430d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
431d9cf8291SDaniel Hwang   }
432d9cf8291SDaniel Hwang   fprintf(fd, "%d%c", getpid(), RS);
433d9cf8291SDaniel Hwang   fprintf(fd, "%d%c", getppid(), RS);
434d9cf8291SDaniel Hwang   fprintf(fd, "%s%c", fun, RS);
435d9cf8291SDaniel Hwang   fprintf(fd, "%s%c", cwd, RS);
436d9cf8291SDaniel Hwang   size_t const argc = bear_strings_length(argv);
437d9cf8291SDaniel Hwang   for (size_t it = 0; it < argc; ++it) {
438d9cf8291SDaniel Hwang     fprintf(fd, "%s%c", argv[it], US);
439d9cf8291SDaniel Hwang   }
440d9cf8291SDaniel Hwang   fprintf(fd, "%c", GS);
441d9cf8291SDaniel Hwang   if (fclose(fd)) {
442d9cf8291SDaniel Hwang     perror("bear: fclose");
443d919d027SBalazs Benics     pthread_mutex_unlock(&mutex);
444d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
445d9cf8291SDaniel Hwang   }
446d9cf8291SDaniel Hwang   free((void *)cwd);
447d9cf8291SDaniel Hwang   pthread_mutex_unlock(&mutex);
448d9cf8291SDaniel Hwang }
449d9cf8291SDaniel Hwang 
450*5674a3c8SGabriel Ravier /* update environment assure that children processes will copy the desired
451d9cf8291SDaniel Hwang  * behaviour */
452d9cf8291SDaniel Hwang 
bear_capture_env_t(bear_env_t * env)453d9cf8291SDaniel Hwang static int bear_capture_env_t(bear_env_t *env) {
454d9cf8291SDaniel Hwang   int status = 1;
455d9cf8291SDaniel Hwang   for (size_t it = 0; it < ENV_SIZE; ++it) {
456d9cf8291SDaniel Hwang     char const *const env_value = getenv(env_names[it]);
457d9cf8291SDaniel Hwang     char const *const env_copy = (env_value) ? strdup(env_value) : env_value;
458d9cf8291SDaniel Hwang     (*env)[it] = env_copy;
459d9cf8291SDaniel Hwang     status &= (env_copy) ? 1 : 0;
460d9cf8291SDaniel Hwang   }
461d9cf8291SDaniel Hwang   return status;
462d9cf8291SDaniel Hwang }
463d9cf8291SDaniel Hwang 
bear_reset_env_t(bear_env_t * env)464d9cf8291SDaniel Hwang static int bear_reset_env_t(bear_env_t *env) {
465d9cf8291SDaniel Hwang   int status = 1;
466d9cf8291SDaniel Hwang   for (size_t it = 0; it < ENV_SIZE; ++it) {
467d9cf8291SDaniel Hwang     if ((*env)[it]) {
468d9cf8291SDaniel Hwang       setenv(env_names[it], (*env)[it], 1);
469d9cf8291SDaniel Hwang     } else {
470d9cf8291SDaniel Hwang       unsetenv(env_names[it]);
471d9cf8291SDaniel Hwang     }
472d9cf8291SDaniel Hwang   }
473d9cf8291SDaniel Hwang   return status;
474d9cf8291SDaniel Hwang }
475d9cf8291SDaniel Hwang 
bear_release_env_t(bear_env_t * env)476d9cf8291SDaniel Hwang static void bear_release_env_t(bear_env_t *env) {
477d9cf8291SDaniel Hwang   for (size_t it = 0; it < ENV_SIZE; ++it) {
478d9cf8291SDaniel Hwang     free((void *)(*env)[it]);
479d9cf8291SDaniel Hwang     (*env)[it] = 0;
480d9cf8291SDaniel Hwang   }
481d9cf8291SDaniel Hwang }
482d9cf8291SDaniel Hwang 
bear_update_environment(char * const envp[],bear_env_t * env)483d9cf8291SDaniel Hwang static char const **bear_update_environment(char *const envp[],
484d9cf8291SDaniel Hwang                                             bear_env_t *env) {
485d9cf8291SDaniel Hwang   char const **result = bear_strings_copy((char const **)envp);
486d9cf8291SDaniel Hwang   for (size_t it = 0; it < ENV_SIZE && (*env)[it]; ++it)
487d9cf8291SDaniel Hwang     result = bear_update_environ(result, env_names[it], (*env)[it]);
488d9cf8291SDaniel Hwang   return result;
489d9cf8291SDaniel Hwang }
490d9cf8291SDaniel Hwang 
bear_update_environ(char const * envs[],char const * key,char const * const value)491d9cf8291SDaniel Hwang static char const **bear_update_environ(char const *envs[], char const *key,
492d9cf8291SDaniel Hwang                                         char const *const value) {
493d9cf8291SDaniel Hwang   // find the key if it's there
494d9cf8291SDaniel Hwang   size_t const key_length = strlen(key);
495d9cf8291SDaniel Hwang   char const **it = envs;
496d9cf8291SDaniel Hwang   for (; (it) && (*it); ++it) {
497d9cf8291SDaniel Hwang     if ((0 == strncmp(*it, key, key_length)) && (strlen(*it) > key_length) &&
498d9cf8291SDaniel Hwang         ('=' == (*it)[key_length]))
499d9cf8291SDaniel Hwang       break;
500d9cf8291SDaniel Hwang   }
501d9cf8291SDaniel Hwang   // allocate a environment entry
502d9cf8291SDaniel Hwang   size_t const value_length = strlen(value);
503d9cf8291SDaniel Hwang   size_t const env_length = key_length + value_length + 2;
504d9cf8291SDaniel Hwang   char *env = malloc(env_length);
505d9cf8291SDaniel Hwang   if (0 == env) {
506d9cf8291SDaniel Hwang     perror("bear: malloc [in env_update]");
507d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
508d9cf8291SDaniel Hwang   }
509d9cf8291SDaniel Hwang   if (-1 == snprintf(env, env_length, "%s=%s", key, value)) {
510d9cf8291SDaniel Hwang     perror("bear: snprintf");
511d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
512d9cf8291SDaniel Hwang   }
513d9cf8291SDaniel Hwang   // replace or append the environment entry
514d9cf8291SDaniel Hwang   if (it && *it) {
515d9cf8291SDaniel Hwang     free((void *)*it);
516d9cf8291SDaniel Hwang     *it = env;
517d9cf8291SDaniel Hwang     return envs;
518d9cf8291SDaniel Hwang   }
519d9cf8291SDaniel Hwang   return bear_strings_append(envs, env);
520d9cf8291SDaniel Hwang }
521d9cf8291SDaniel Hwang 
bear_get_environment()522d9cf8291SDaniel Hwang static char **bear_get_environment() {
523d9cf8291SDaniel Hwang #if defined HAVE_NSGETENVIRON
524d9cf8291SDaniel Hwang   return *_NSGetEnviron();
525d9cf8291SDaniel Hwang #else
526d9cf8291SDaniel Hwang   return environ;
527d9cf8291SDaniel Hwang #endif
528d9cf8291SDaniel Hwang }
529d9cf8291SDaniel Hwang 
530d9cf8291SDaniel Hwang /* util methods to deal with string arrays. environment and process arguments
531d9cf8291SDaniel Hwang  * are both represented as string arrays. */
532d9cf8291SDaniel Hwang 
bear_strings_build(char const * const arg,va_list * args)533d9cf8291SDaniel Hwang static char const **bear_strings_build(char const *const arg, va_list *args) {
534d9cf8291SDaniel Hwang   char const **result = 0;
535d9cf8291SDaniel Hwang   size_t size = 0;
536d9cf8291SDaniel Hwang   for (char const *it = arg; it; it = va_arg(*args, char const *)) {
537d9cf8291SDaniel Hwang     result = realloc(result, (size + 1) * sizeof(char const *));
538d9cf8291SDaniel Hwang     if (0 == result) {
539d9cf8291SDaniel Hwang       perror("bear: realloc");
540d9cf8291SDaniel Hwang       exit(EXIT_FAILURE);
541d9cf8291SDaniel Hwang     }
542d9cf8291SDaniel Hwang     char const *copy = strdup(it);
543d9cf8291SDaniel Hwang     if (0 == copy) {
544d9cf8291SDaniel Hwang       perror("bear: strdup");
545d9cf8291SDaniel Hwang       exit(EXIT_FAILURE);
546d9cf8291SDaniel Hwang     }
547d9cf8291SDaniel Hwang     result[size++] = copy;
548d9cf8291SDaniel Hwang   }
549d9cf8291SDaniel Hwang   result = realloc(result, (size + 1) * sizeof(char const *));
550d9cf8291SDaniel Hwang   if (0 == result) {
551d9cf8291SDaniel Hwang     perror("bear: realloc");
552d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
553d9cf8291SDaniel Hwang   }
554d9cf8291SDaniel Hwang   result[size++] = 0;
555d9cf8291SDaniel Hwang 
556d9cf8291SDaniel Hwang   return result;
557d9cf8291SDaniel Hwang }
558d9cf8291SDaniel Hwang 
bear_strings_copy(char const ** const in)559d9cf8291SDaniel Hwang static char const **bear_strings_copy(char const **const in) {
560d9cf8291SDaniel Hwang   size_t const size = bear_strings_length(in);
561d9cf8291SDaniel Hwang 
562d9cf8291SDaniel Hwang   char const **const result = malloc((size + 1) * sizeof(char const *));
563d9cf8291SDaniel Hwang   if (0 == result) {
564d9cf8291SDaniel Hwang     perror("bear: malloc");
565d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
566d9cf8291SDaniel Hwang   }
567d9cf8291SDaniel Hwang 
568d9cf8291SDaniel Hwang   char const **out_it = result;
569d9cf8291SDaniel Hwang   for (char const *const *in_it = in; (in_it) && (*in_it); ++in_it, ++out_it) {
570d9cf8291SDaniel Hwang     *out_it = strdup(*in_it);
571d9cf8291SDaniel Hwang     if (0 == *out_it) {
572d9cf8291SDaniel Hwang       perror("bear: strdup");
573d9cf8291SDaniel Hwang       exit(EXIT_FAILURE);
574d9cf8291SDaniel Hwang     }
575d9cf8291SDaniel Hwang   }
576d9cf8291SDaniel Hwang   *out_it = 0;
577d9cf8291SDaniel Hwang   return result;
578d9cf8291SDaniel Hwang }
579d9cf8291SDaniel Hwang 
bear_strings_append(char const ** const in,char const * const e)580d9cf8291SDaniel Hwang static char const **bear_strings_append(char const **const in,
581d9cf8291SDaniel Hwang                                         char const *const e) {
582d9cf8291SDaniel Hwang   size_t size = bear_strings_length(in);
583d9cf8291SDaniel Hwang   char const **result = realloc(in, (size + 2) * sizeof(char const *));
584d9cf8291SDaniel Hwang   if (0 == result) {
585d9cf8291SDaniel Hwang     perror("bear: realloc");
586d9cf8291SDaniel Hwang     exit(EXIT_FAILURE);
587d9cf8291SDaniel Hwang   }
588d9cf8291SDaniel Hwang   result[size++] = e;
589d9cf8291SDaniel Hwang   result[size++] = 0;
590d9cf8291SDaniel Hwang   return result;
591d9cf8291SDaniel Hwang }
592d9cf8291SDaniel Hwang 
bear_strings_length(char const * const * const in)593d9cf8291SDaniel Hwang static size_t bear_strings_length(char const *const *const in) {
594d9cf8291SDaniel Hwang   size_t result = 0;
595d9cf8291SDaniel Hwang   for (char const *const *it = in; (it) && (*it); ++it)
596d9cf8291SDaniel Hwang     ++result;
597d9cf8291SDaniel Hwang   return result;
598d9cf8291SDaniel Hwang }
599d9cf8291SDaniel Hwang 
bear_strings_release(char const ** in)600d9cf8291SDaniel Hwang static void bear_strings_release(char const **in) {
601d9cf8291SDaniel Hwang   for (char const *const *it = in; (it) && (*it); ++it) {
602d9cf8291SDaniel Hwang     free((void *)*it);
603d9cf8291SDaniel Hwang   }
604d9cf8291SDaniel Hwang   free((void *)in);
605d9cf8291SDaniel Hwang }
606