int start_command(struct child_process *cmd) { int need_in, need_out, need_err; int fdin[2], fdout[2], fderr[2]; /* * In case of errors we must keep the promise to close FDs * that have been passed in via ->in and ->out. */ need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) { if (cmd->out > 0) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->in = fdin[1]; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); return -ERR_RUN_COMMAND_PIPE; } cmd->out = fdout[0]; } need_err = !cmd->no_stderr && cmd->err < 0; if (need_err) { if (pipe(fderr) < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); return -ERR_RUN_COMMAND_PIPE; } cmd->err = fderr[0]; } trace_argv_printf(cmd->argv, "trace: run_command:"); #ifndef __MINGW32__ cmd->pid = fork(); if (!cmd->pid) { if (cmd->no_stdin) dup_devnull(0); else if (need_in) { dup2(fdin[0], 0); close_pair(fdin); } else if (cmd->in) { dup2(cmd->in, 0); close(cmd->in); } if (cmd->no_stderr) dup_devnull(2); else if (need_err) { dup2(fderr[1], 2); close_pair(fderr); } if (cmd->no_stdout) dup_devnull(1); else if (cmd->stdout_to_stderr) dup2(2, 1); else if (need_out) { dup2(fdout[1], 1); close_pair(fdout); } else if (cmd->out > 1) { dup2(cmd->out, 1); close(cmd->out); } if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) putenv((char*)*cmd->env); else unsetenv(*cmd->env); } } if (cmd->git_cmd) { execv_git_cmd(cmd->argv); } else { execvp(cmd->argv[0], (char *const*) cmd->argv); } die("exec %s failed.", cmd->argv[0]); } #else int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */ const char *sargv0 = cmd->argv[0]; char **env = environ; struct strbuf git_cmd; if (cmd->no_stdin) { s0 = dup(0); dup_devnull(0); } else if (need_in) { s0 = dup(0); dup2(fdin[0], 0); } else if (cmd->in) { s0 = dup(0); dup2(cmd->in, 0); } if (cmd->no_stderr) { s2 = dup(2); dup_devnull(2); } else if (need_err) { s2 = dup(2); dup2(fderr[1], 2); } if (cmd->no_stdout) { s1 = dup(1); dup_devnull(1); } else if (cmd->stdout_to_stderr) { s1 = dup(1); dup2(2, 1); } else if (need_out) { s1 = dup(1); dup2(fdout[1], 1); } else if (cmd->out > 1) { s1 = dup(1); dup2(cmd->out, 1); } if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->env) { env = copy_environ(); for (; *cmd->env; cmd->env++) env = env_setenv(env, *cmd->env); } if (cmd->git_cmd) { strbuf_init(&git_cmd, 0); strbuf_addf(&git_cmd, "git-%s", cmd->argv[0]); cmd->argv[0] = git_cmd.buf; } cmd->pid = mingw_spawnvpe(cmd->argv[0], cmd->argv, env); if (cmd->env) free_environ(env); if (cmd->git_cmd) strbuf_release(&git_cmd); cmd->argv[0] = sargv0; if (s0 >= 0) dup2(s0, 0), close(s0); if (s1 >= 0) dup2(s1, 1), close(s1); if (s2 >= 0) dup2(s2, 2), close(s2); #endif if (cmd->pid < 0) { if (need_in) close_pair(fdin); else if (cmd->in) close(cmd->in); if (need_out) close_pair(fdout); else if (cmd->out) close(cmd->out); if (need_err) close_pair(fderr); return -ERR_RUN_COMMAND_FORK; } if (need_in) close(fdin[0]); else if (cmd->in) close(cmd->in); if (need_out) close(fdout[1]); else if (cmd->out) close(cmd->out); if (need_err) close(fderr[1]); return 0; }
int __cdecl __crtsetenv ( #endif const _TSCHAR *option, const int primary ) { int ix; int remove; /* 1 if variable is to be removed */ _TSCHAR **env; _TSCHAR *name, *value; const _TSCHAR *equal; /* * check that the option string is valid, find the equal sign * and verify '=' is not the first character in string. */ if ( (option == NULL) || ((equal = _tcschr(option, _T('='))) == NULL) || option == equal) return(-1); /* if the character following '=' is null, we are removing the * the environment variable. Otherwise, we are adding or updating * an environment variable. */ remove = (*(equal + 1) == _T('\0')); /* * the first time _[w]putenv() is called, copy the environment * block that was passed to [w]main to avoid making a * dangling pointer if the block is re-alloced. */ #ifdef WPRFLAG if (_wenviron == __winitenv) _wenviron = copy_environ(_wenviron); #else if (_environ == __initenv) _environ = copy_environ(_environ); #endif /* see if requested environment array exists */ if (_tenviron == NULL) { /* * The requested type of environment does not exist. * See if other type exists, if so convert it to requested type. * The functions that convert the enviroment (__mbtow_environ and * __wtomb_environ) will call this function (__crt[w]setenv) once * for each of the pre-existing environment variables. To avoid * an infinite loop, test the primary flag. */ #ifdef WPRFLAG if (primary && _environ) { if (__mbtow_environ() != 0) return -1; } #else if (primary && _wenviron) { if (__wtomb_environ() != 0) return -1; } #endif else { /* nothing to remove, return */ if ( remove ) return 0; else { /* create ones that do not exist */ if (_environ == NULL) { if ( (_environ = _malloc_crt(sizeof(char *))) == NULL) return -1; *_environ = NULL; } if (_wenviron == NULL) { if ( (_wenviron = _malloc_crt(sizeof(wchar_t *))) == NULL) return -1; *_wenviron = NULL; } } } } /* * At this point, the two types of environments are in sync (as much * as they can be anyway). The only way they can get out of sync * (besides users directly modifiying the environment) is if there * are conversion problems: If the user sets two Unicode EVs, * "foo1" and "foo2" and converting then to multibyte yields "foo?" * and "foo?", then the environment blocks will differ. */ /* init env pointers */ env = _tenviron; /* See if the string is already in the environment */ #ifdef WPRFLAG ix = wfindenv(option, equal - option); #else ix = findenv(option, equal - option); #endif if ((ix >= 0) && (*env != NULL)) { /* String is already in the environment - overwrite/remove it */ if (remove) { /* free the string being removed */ _free_crt(env[ix]); /* removing -- move all the later strings up */ for ( ; env[ix] != NULL; ++ix) { env[ix] = env[ix+1]; } /* shrink the environment memory block (ix now has number of strings, including NULL) -- this realloc probably can't fail, since we're shrinking a mem block, but we're careful anyway. */ if (env = (_TSCHAR **) _realloc_crt(env, ix * sizeof(_TSCHAR *))) _tenviron = env; } else { /* replace the option */ env[ix] = (_TSCHAR *) option; } } else { /* * String is NOT in the environment */ if ( !remove ) { /* * Append the string to the environ table. Note that * table must be grown to do this. */ if (ix < 0) ix = -ix; /* ix = length of environ table */ if ( (env = (_TSCHAR **)_realloc_crt(env, sizeof(_TSCHAR *) * (ix + 2))) == NULL ) return -1; env[ix] = (_TSCHAR *)option; env[ix + 1] = NULL; _tenviron = env; } else /* * We are asked to remove an environment var that * isn't there...just return success */ return 0; } /* * Update the OS environment. Don't give an error if this fails * since the failure will not affect the user unless he/she is making * direct API calls. Only need to do this for one type, OS converts * to other type automatically. */ if ( primary && (name = (_TSCHAR *)_malloc_crt((_tcslen(option) + 2) * sizeof(_TSCHAR))) != NULL ) { _tcscpy(name, option); value = name + (equal - option); *value++ = _T('\0'); SetEnvironmentVariable(name, remove ? NULL : value); _free_crt(name); } return 0; }
int start_command(struct child_process *cmd) { int need_in, need_out; int fdin[2] = { -1, -1 }; int fdout[2] = { -1, -1 }; const char **env = (const char **)environ; need_in = !cmd->no_stdin && cmd->in < 0; if (need_in) { if (pipe(fdin) < 0) return -ERR_RUN_COMMAND_PIPE; cmd->in = fdin[1]; cmd->close_in = 1; } need_out = !cmd->no_stdout && !cmd->stdout_to_stderr && cmd->out < 0; if (need_out) { if (pipe(fdout) < 0) { if (need_in) close_pair(fdin); return -ERR_RUN_COMMAND_PIPE; } cmd->out = fdout[0]; cmd->close_out = 1; } { if (cmd->no_stdin) fdin[0] = open("/dev/null", O_RDWR); else if (need_in) { /* nothing */ } else if (cmd->in) { fdin[0] = cmd->in; } if (cmd->no_stdout) fdout[1] = open("/dev/null", O_RDWR); else if (cmd->stdout_to_stderr) fdout[1] = dup(2); else if (need_out) { /* nothing */ } else if (cmd->out > 1) { fdout[1] = cmd->out; } if (cmd->dir) die("chdir in start_command() not implemented"); if (cmd->dir && chdir(cmd->dir)) die("exec %s: cd to %s failed (%s)", cmd->argv[0], cmd->dir, strerror(errno)); if (cmd->env) { if (cmd->merge_env) { env = copy_environ(); for (; *cmd->env; cmd->env++) { if (strchr(*cmd->env, '=')) die("setting environment in start_command() not implemented"); else env_unsetenv(env, *cmd->env); } } else env = cmd->env; } if (cmd->git_cmd) { cmd->pid = spawnve_git_cmd(cmd->argv, fdin, fdout, env); } else { cmd->pid = spawnvpe_pipe(cmd->cmd ? cmd->cmd : cmd->argv[0], cmd->argv, env, fdin, fdout); } } if (cmd->pid < 0) { if (need_in) close_pair(fdin); if (need_out) close_pair(fdout); return -ERR_RUN_COMMAND_FORK; } return 0; }