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