/* * SPDX-License-Identifier: LGPL-2.1-only * */ /* these aren't used, but the wrapper table isn't happy unless they * exist */ static int wrap_execl(const char *file, const char *arg, va_list ap) { (void) file; (void) arg; (void) ap; return 0; } static int wrap_execle(const char *file, const char *arg, va_list ap) { (void) file; (void) arg; (void) ap; return 0; } static int wrap_execlp(const char *file, const char *arg, va_list ap) { (void) file; (void) arg; (void) ap; return 0; } static char ** execl_to_v(va_list ap, const char *argv0, char *const **envp) { size_t i = 0; size_t alloc_size = 256; char **argv = malloc((sizeof *argv) * alloc_size); if (!argv) { pseudo_debug(PDBGF_CLIENT, "execl failed: couldn't allocate memory for %lu arguments\n", (unsigned long) alloc_size); return NULL; } argv[i++] = (char *) argv0; while (argv[i-1]) { argv[i++] = va_arg(ap, char *const); if (i > alloc_size - 1) { alloc_size = alloc_size + 256; argv = realloc(argv, (sizeof *argv) * alloc_size); if (!argv) { pseudo_debug(PDBGF_CLIENT, "execl failed: couldn't allocate memory for %lu arguments\n", (unsigned long) alloc_size); return NULL; } } } if (envp) { *envp = va_arg(ap, char **); } return argv; } /* The following wrappers require Special Handling */ int execl(const char *file, const char *arg, ...) { sigset_t saved; va_list ap; char **argv; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers()) { /* rc was initialized to the "failure" value */ pseudo_enosys("execl"); PROFILE_DONE; return rc; } va_start(ap, arg); argv = execl_to_v(ap, arg, 0); va_end(ap); if (!argv) { errno = ENOMEM; PROFILE_DONE; return -1; } pseudo_debug(PDBGF_WRAPPER, "called: execl\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execv(file, argv); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execl\n"); errno = save_errno; free(argv); PROFILE_DONE; return rc; } int execlp(const char *file, const char *arg, ...) { sigset_t saved; va_list ap; char **argv; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers()) { /* rc was initialized to the "failure" value */ pseudo_enosys("execlp"); PROFILE_DONE; return rc; } va_start(ap, arg); argv = execl_to_v(ap, arg, 0); va_end(ap); if (!argv) { errno = ENOMEM; PROFILE_DONE; return -1; } pseudo_debug(PDBGF_WRAPPER, "called: execlp\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execvp(file, argv); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execlp\n"); errno = save_errno; free(argv); PROFILE_DONE; return rc; } int execle(const char *file, const char *arg, ...) { sigset_t saved; va_list ap; char **argv; char **envp; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers()) { /* rc was initialized to the "failure" value */ pseudo_enosys("execle"); PROFILE_DONE; return rc; } va_start(ap, arg); argv = execl_to_v(ap, arg, (char *const **)&envp); va_end(ap); if (!argv) { errno = ENOMEM; PROFILE_DONE; return -1; } pseudo_debug(PDBGF_WRAPPER, "called: execle\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execve(file, argv, envp); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execle\n"); errno = save_errno; free(argv); PROFILE_DONE; return rc; } int execv(const char *file, char *const *argv) { sigset_t saved; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers() || !real_execv) { /* rc was initialized to the "failure" value */ pseudo_enosys("execv"); PROFILE_DONE; return rc; } pseudo_debug(PDBGF_WRAPPER, "called: execv\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execv(file, argv); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execv\n"); errno = save_errno; PROFILE_DONE; return rc; } int execve(const char *file, char *const *argv, char *const *envp) { sigset_t saved; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers() || !real_execve) { /* rc was initialized to the "failure" value */ pseudo_enosys("execve"); PROFILE_DONE; return rc; } pseudo_debug(PDBGF_WRAPPER, "called: execve\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execve(file, argv, envp); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execve\n"); errno = save_errno; PROFILE_DONE; return rc; } int execvp(const char *file, char *const *argv) { sigset_t saved; int rc = -1; PROFILE_START; if (!pseudo_check_wrappers() || !real_execvp) { /* rc was initialized to the "failure" value */ pseudo_enosys("execvp"); PROFILE_DONE; return rc; } pseudo_debug(PDBGF_WRAPPER, "called: execvp\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); PROFILE_DONE; return -1; } int save_errno; /* exec*() use this to restore the sig mask */ pseudo_saved_sigmask = saved; rc = wrap_execvp(file, argv); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: execvp\n"); errno = save_errno; PROFILE_DONE; return rc; } /* no profiling in fork because it wouldn't work anyway * half the time */ int fork(void) { sigset_t saved; int rc = -1; if (!pseudo_check_wrappers() || !real_fork) { /* rc was initialized to the "failure" value */ pseudo_enosys("fork"); return rc; } pseudo_debug(PDBGF_WRAPPER, "called: fork\n"); pseudo_sigblock(&saved); if (pseudo_getlock()) { errno = EBUSY; sigprocmask(SIG_SETMASK, &saved, NULL); return -1; } int save_errno; rc = wrap_fork(); save_errno = errno; pseudo_droplock(); sigprocmask(SIG_SETMASK, &saved, NULL); pseudo_debug(PDBGF_WRAPPER, "completed: fork\n"); errno = save_errno; return rc; } int vfork(void) { /* we don't provide support for the distinct semantics * of vfork() */ return fork(); } static int wrap_execv(const char *file, char *const *argv) { int rc = -1; #include "guts/execv.c" return rc; } static int wrap_execve(const char *file, char *const *argv, char *const *envp) { int rc = -1; #include "guts/execve.c" return rc; } static int wrap_execvp(const char *file, char *const *argv) { int rc = -1; #include "guts/execvp.c" return rc; } static int wrap_fork(void) { int rc = -1; #include "guts/fork.c" return rc; }