diff options
-rwxr-xr-x | configure | 17 | ||||
-rwxr-xr-x | configure.ac | 11 | ||||
-rw-r--r-- | jim-exec.c | 319 | ||||
-rw-r--r-- | jim-posix.c | 2 | ||||
-rw-r--r-- | jimautoconf.h.in | 3 |
5 files changed, 91 insertions, 261 deletions
@@ -682,7 +682,6 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking -enable_fork enable_math enable_ipv6 enable_utf8 @@ -1320,7 +1319,6 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --disable-fork do not use fork (no exec, etc.) --enable-math include support for math functions --enable-ipv6 include ipv6 support in the aio extension --enable-utf8 include support for utf8-encoded strings @@ -3793,17 +3791,6 @@ case $host in ;; esac -# Check whether --enable-fork was given. -if test "${enable_fork+set}" = set; then : - enableval=$enable_fork; - if test "x$enableval" = "xno" ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: * disabling fork" >&5 -$as_echo "* disabling fork" >&6; } - EXTRA_CFLAGS="-DJIM_NOFORK" - fi - -fi - # Check whether --enable-math was given. if test "${enable_math+set}" = set; then : enableval=$enable_math; @@ -3948,7 +3935,7 @@ if test "${with_jim_regexp+set}" = set; then : fi -for ac_header in sys/un.h dlfcn.h termios.h +for ac_header in sys/un.h dlfcn.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -3970,7 +3957,7 @@ fi -for ac_func in ualarm sysinfo lstat fork vfork +for ac_func in ualarm sysinfo lstat vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.ac b/configure.ac index 9d33a81..23e3070 100755 --- a/configure.ac +++ b/configure.ac @@ -48,15 +48,6 @@ case $host in ;; esac -AC_ARG_ENABLE(fork, - [ --disable-fork do not use fork (no exec, etc.)], - [ - if test "x$enableval" = "xno" ; then - AC_MSG_RESULT(* disabling fork) - EXTRA_CFLAGS="-DJIM_NOFORK" - fi - ], -) AC_ARG_ENABLE(math, [ --enable-math include support for math functions], [ @@ -212,7 +203,7 @@ AC_ARG_WITH(jim-regexp, AC_CHECK_HEADERS([sys/un.h dlfcn.h termios.h]) AC_CHECK_HEADER(termios.h,,lineedit=0) -AC_CHECK_FUNCS([ualarm sysinfo lstat fork vfork]) +AC_CHECK_FUNCS([ualarm sysinfo lstat vfork]) AC_CHECK_FUNCS([backtrace geteuid mkstemp realpath strptime]) AC_CHECK_FUNCS([regcomp waitpid sigaction sys_signame sys_siglist]) AC_CHECK_FUNCS([syslog opendir readlink sleep usleep pipe inet_ntop getaddrinfo]) @@ -146,6 +146,24 @@ static char **JimBuildEnv(Jim_Interp *interp) #endif } +/** + * Frees the environment allocated by JimBuildEnv() + * + * Must pass original_environ. + */ +static void JimFreeEnv(Jim_Interp *interp, char **env, char **original_environ) +{ +#ifdef jim_ext_tclcompat + if (env != original_environ) { + int i; + for (i = 0; env[i]; i++) { + Jim_Free(env[i]); + } + Jim_Free(env); + } +#endif +} + /* * Create error messages for unusual process exits. An * extra newline gets appended to each error message, but @@ -180,7 +198,7 @@ static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus) type = "CHILDSUSP"; action = "suspended"; } - + Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1)); #ifdef jim_ext_signal @@ -199,7 +217,6 @@ static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus) return rc; } -#if defined(HAVE_FORK) && !defined(HAVE_NO_FORK) /* * Data structures of the following type are used by JimFork and * JimWaitPids to keep track of child processes. @@ -321,64 +338,6 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* *---------------------------------------------------------------------- * - * JimFork -- - * - * Create a new process using the vfork system call, and keep - * track of it for "safe" waiting with JimWaitPids. - * - * Results: - * The return value is the value returned by the vfork system - * call (0 means child, > 0 means parent (value is child id), - * < 0 means error). - * - * Side effects: - * A new process is created, and an entry is added to an internal - * table of child processes if the process is created successfully. - * - *---------------------------------------------------------------------- - */ -static int JimFork(Jim_Interp *interp) -{ - pid_t pid; - struct WaitInfoTable *table = Jim_CmdPrivData(interp); - - /* - * Disable SIGPIPE signals: if they were allowed, this process - * might go away unexpectedly if children misbehave. This code - * can potentially interfere with other application code that - * expects to handle SIGPIPEs; what's really needed is an - * arbiter for signals to allow them to be "shared". - */ - if (table->info == NULL) { - (void)signal(SIGPIPE, SIG_IGN); - } - - /* - * Enlarge the wait table if there isn't enough space for a new - * entry. - */ - if (table->used == table->size) { - table->size += WAIT_TABLE_GROW_BY; - table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info)); - } - - /* - * Make a new process and enter it into the table if the fork - * is successful. - */ - - pid = fork(); - if (pid > 0) { - table->info[table->used].pid = pid; - table->info[table->used].flags = 0; - table->used++; - } - return pid; -} - -/* - *---------------------------------------------------------------------- - * * JimWaitPids -- * * This procedure is used to wait for one or more processes created @@ -620,6 +579,8 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid int lastBar; char *execName; int i, pid; + char **orig_environ; + struct WaitInfoTable *table = Jim_CmdPrivData(interp); /* Holds the args which will be used to exec */ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1)); @@ -636,6 +597,10 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid } pipeIds[0] = pipeIds[1] = -1; + /* Must do this before vfork(), so do it now */ + orig_environ = environ; + environ = JimBuildEnv(interp); + /* * First, scan through all the arguments to figure out the structure * of the pipeline. Count the number of distinct processes (it's the @@ -855,7 +820,7 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid errorId = dup(lastOutputId); } else { - /* No redirection stdout, so just use 2>@stdout */ + /* No redirection of stdout, so just use 2>@stdout */ error = "stdout"; } } @@ -929,6 +894,9 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid } for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) { int pipe_dup_err = 0; + int origErrorId = errorId; + char execerr[64]; + int execerrlen; for (lastArg = firstArg; lastArg < arg_count; lastArg++) { if (arg_array[lastArg][0] == '|') { @@ -951,42 +919,74 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid outputId = pipeIds[1]; } execName = arg_array[firstArg]; - pid = JimFork(interp); - if (pid == -1) { + + /* Now fork the child */ + + /* + * Disable SIGPIPE signals: if they were allowed, this process + * might go away unexpectedly if children misbehave. This code + * can potentially interfere with other application code that + * expects to handle SIGPIPEs; what's really needed is an + * arbiter for signals to allow them to be "shared". + */ + if (table->info == NULL) { + (void)signal(SIGPIPE, SIG_IGN); + } + + /* + * Enlarge the wait table if there isn't enough space for a new + * entry. + */ + if (table->used == table->size) { + table->size += WAIT_TABLE_GROW_BY; + table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info)); + } + + /* Need to do this befor vfork() */ + if (pipe_dup_err) { + errorId = outputId; + } + + /* Need to prep an error message before vfork(), just in case */ + snprintf(execerr, sizeof(execerr), "couldn't exec \"%s\"", execName); + execerrlen = strlen(execerr); + + /* + * Make a new process and enter it into the table if the fork + * is successful. + */ + pid = vfork(); + if (pid < 0) { Jim_SetResultErrno(interp, "couldn't fork child process"); goto error; } if (pid == 0) { - char errSpace[200]; - int rc; - - if (pipe_dup_err) { - errorId = outputId; - } + /* Child */ - if ((inputId != -1 && dup2(inputId, 0) == -1) - || (outputId != -1 && dup2(outputId, 1) == -1) - || (errorId != -1 && (dup2(errorId, 2) == -1))) { + if (inputId != -1) dup2(inputId, 0); + if (outputId != -1) dup2(outputId, 1); + if (errorId != -1) dup2(errorId, 2); - static const char err[] = "forked process couldn't set up input/output\n"; - - rc = write(errorId < 0 ? 2 : errorId, err, strlen(err)); - _exit(1); - } for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) { close(i); } - /* Build new environ from the current ::env dict */ - environ = JimBuildEnv(interp); + execvp(execName, &arg_array[firstArg]); - snprintf(errSpace, sizeof(errSpace), "couldn't find \"%.150s\" to execute\n", arg_array[firstArg]); - rc = write(2, errSpace, strlen(errSpace)); + /* we really can ignore the error here! */ + write(2, execerr, execerrlen) < 0 ? -1 : 0; _exit(127); } - else { - pidPtr[numPids] = pid; - } + + /* parent */ + table->info[table->used].pid = pid; + table->info[table->used].flags = 0; + table->used++; + + pidPtr[numPids] = pid; + + /* Restore in case of pipe_dup_err */ + errorId = origErrorId; /* * Close off our copies of file descriptors that were set up for @@ -1020,6 +1020,9 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid } Jim_Free(arg_array); + JimFreeEnv(interp, environ, orig_environ); + environ = orig_environ; + return numPids; /* @@ -1114,154 +1117,6 @@ static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int return result; } -#else -/** - * Frees the environment allocated by JimBuildEnv() - * - * Must pass original_environ. - */ -static void JimFreeEnv(Jim_Interp *interp, char **env, char **original_environ) -{ -#ifdef jim_ext_tclcompat - if (env != original_environ) { - int i; - for (i = 0; env[i]; i++) { - Jim_Free(env[i]); - } - Jim_Free(env); - } -#endif -} - -static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData) -{ -} - -static struct WaitInfoTable *JimAllocWaitInfoTable(void) -{ - return NULL; -} - -/** - * Joins the given args into a single quoted, space-separate string. - */ -static Jim_Obj *JimQuoteArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp); - int i, j; - - /* Create an escape command lines */ - for (i = 0; i < argc; i++) { - int len; - const char *arg = Jim_GetString(argv[i], &len); - - if (i) { - Jim_AppendString(interp, cmdlineObj, " ", 1); - } - for (j = 0; j < len; j++) { - if (arg[j] == '\\') { - /* Need to double escape backslash */ - Jim_AppendString(interp, cmdlineObj, "\\\\\\\\", 4); - continue; - } - if (arg[j] == '"' || arg[j] == '`' || arg[j] == '\'' || arg[j] == '\n') { - /* Escape these */ - Jim_AppendString(interp, cmdlineObj, "\\", 1); - } - Jim_AppendString(interp, cmdlineObj, &arg[j], 1); - } - } - - return cmdlineObj; -} - -static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - int pid; - int tmpfd; - int status; - int result; - char *nargv[4]; - char **new_environ; - Jim_Obj *cmdlineObj; - -#define TMP_NAME "/tmp/tcl.exec.XXXXXX" - char tmpname[sizeof(TMP_NAME) + 1]; - - if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) { - Jim_SetResultString(interp, "unsupported: background exec", -1); - return JIM_ERR; - } - - /* Create a temporary file for the output from our exec command */ - strcpy(tmpname, TMP_NAME); - tmpfd = mkstemp(tmpname); - if (tmpfd < 0) { - Jim_SetResultErrno(interp, "couldn't create temp file file for exec"); - return JIM_ERR; - } - - - /* Execute: sh -c "arguments..." - * - * Note we do it this way in order to get command line redirection, etc. - */ - cmdlineObj = JimQuoteArgs(interp, argc - 1, argv + 1); - - nargv[0] = "sh"; - nargv[1] = "-c"; - nargv[2] = (char *)Jim_GetString(cmdlineObj, NULL); - nargv[3] = NULL; - - /*printf("Writing output to %s, fd=%d\n", tmpname, tmpfd); */ - unlink(tmpname); - - /* Must do this before vfork() */ - new_environ = JimBuildEnv(interp); - - /* Use vfork and send output to this temporary file */ - pid = vfork(); - if (pid == 0) { - close(0); - open("/dev/null", O_RDONLY); - close(1); - if (dup(tmpfd) != -1) { - close(2); - if (dup(tmpfd) != -1) { - close(tmpfd); - execve("/bin/sh", nargv, new_environ); - } - } - _exit(127); - } - - /* Wait for the child to exit */ - waitpid(pid, &status, 0); - - JimFreeEnv(interp, new_environ, environ); - - Jim_FreeNewObj(interp, cmdlineObj); - - result = JimCheckWaitStatus(interp, pid, status); - - /* - * Read the child's output (if any) and put it into the result. - */ - lseek(tmpfd, 0L, SEEK_SET); - - Jim_SetResultString(interp, "", 0); - - if (JimAppendStreamToString(interp, tmpfd, Jim_GetResult(interp)) != JIM_OK) { - Jim_SetResultErrno(interp, "error reading from stderr output file"); - result = JIM_ERR; - } - close(tmpfd); - - JimTrimTrailingNewline(interp); - - return result; -} -#endif int Jim_execInit(Jim_Interp *interp) { diff --git a/jim-posix.c b/jim-posix.c index ba4c6d7..eeec649 100644 --- a/jim-posix.c +++ b/jim-posix.c @@ -38,7 +38,7 @@ static void Jim_PosixSetError(Jim_Interp *interp) Jim_SetResultString(interp, strerror(errno), -1); } -#if defined(HAVE_FORK) && !defined(HAVE_NO_FORK) +#if defined(HAVE_FORK) static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { pid_t pid; diff --git a/jimautoconf.h.in b/jimautoconf.h.in index f4eb0e5..f523275 100644 --- a/jimautoconf.h.in +++ b/jimautoconf.h.in @@ -9,9 +9,6 @@ /* Have the dlopen function */ #undef HAVE_DLOPEN -/* Define to 1 if you have the `fork' function. */ -#undef HAVE_FORK - /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO |