/src/ssfossil/fossil/src/popen.c
C | 187 lines | 130 code | 11 blank | 46 comment | 7 complexity | a266e1183d329d7e682bc7159be35663 MD5 | raw file
- /*
- ** Copyright (c) 2010 D. Richard Hipp
- **
- ** This program is free software; you can redistribute it and/or
- ** modify it under the terms of the Simplified BSD License (also
- ** known as the "2-Clause License" or "FreeBSD License".)
- ** This program is distributed in the hope that it will be useful,
- ** but without any warranty; without even the implied warranty of
- ** merchantability or fitness for a particular purpose.
- **
- ** Author contact information:
- ** drh@hwaci.com
- ** http://www.hwaci.com/drh/
- **
- *******************************************************************************
- **
- ** This file contains an implementation of a bi-directional popen().
- */
- #include "config.h"
- #include "popen.h"
- #ifdef _WIN32
- #include <windows.h>
- #include <fcntl.h>
- /*
- ** Print a fatal error and quit.
- */
- static void win32_fatal_error(const char *zMsg){
- fossil_fatal("%s");
- }
- #endif
- #ifdef _WIN32
- /*
- ** On windows, create a child process and specify the stdin, stdout,
- ** and stderr channels for that process to use.
- **
- ** Return the number of errors.
- */
- static int win32_create_child_process(
- char *zCmd, /* The command that the child process will run */
- HANDLE hIn, /* Standard input */
- HANDLE hOut, /* Standard output */
- HANDLE hErr, /* Standard error */
- DWORD *pChildPid /* OUT: Child process handle */
- ){
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
- BOOL rc;
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- si.dwFlags = STARTF_USESTDHANDLES;
- SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, TRUE);
- si.hStdInput = hIn;
- SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, TRUE);
- si.hStdOutput = hOut;
- SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, TRUE);
- si.hStdError = hErr;
- rc = CreateProcess(
- NULL, /* Application Name */
- zCmd, /* Command-line */
- NULL, /* Process attributes */
- NULL, /* Thread attributes */
- TRUE, /* Inherit Handles */
- 0, /* Create flags */
- NULL, /* Environment */
- NULL, /* Current directory */
- &si, /* Startup Info */
- &pi /* Process Info */
- );
- if( rc ){
- CloseHandle( pi.hProcess );
- CloseHandle( pi.hThread );
- *pChildPid = pi.dwProcessId;
- }else{
- win32_fatal_error("cannot create child process");
- }
- return rc!=0;
- }
- #endif
- /*
- ** Create a child process running shell command "zCmd". *ppOut is
- ** a FILE that becomes the standard input of the child process.
- ** (The caller writes to *ppOut in order to send text to the child.)
- ** *ppIn is stdout from the child process. (The caller
- ** reads from *ppIn in order to receive input from the child.)
- ** Note that *ppIn is an unbuffered file descriptor, not a FILE.
- ** The process ID of the child is written into *pChildPid.
- **
- ** Return the number of errors.
- */
- int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
- #ifdef _WIN32
- HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
- SECURITY_ATTRIBUTES saAttr;
- DWORD childPid = 0;
- int fd;
- saAttr.nLength = sizeof(saAttr);
- saAttr.bInheritHandle = TRUE;
- saAttr.lpSecurityDescriptor = NULL;
- hStderr = GetStdHandle(STD_ERROR_HANDLE);
- if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
- win32_fatal_error("cannot create pipe for stdout");
- }
- SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
- if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
- win32_fatal_error("cannot create pipe for stdin");
- }
- SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
-
- win32_create_child_process((char*)zCmd,
- hStdinRd, hStdoutWr, hStderr,&childPid);
- *pChildPid = childPid;
- *pfdIn = _open_osfhandle((long)hStdoutRd, 0);
- fd = _open_osfhandle((long)hStdinWr, 0);
- *ppOut = _fdopen(fd, "w");
- CloseHandle(hStdinRd);
- CloseHandle(hStdoutWr);
- return 0;
- #else
- int pin[2], pout[2];
- *pfdIn = 0;
- *ppOut = 0;
- *pChildPid = 0;
- if( pipe(pin)<0 ){
- return 1;
- }
- if( pipe(pout)<0 ){
- close(pin[0]);
- close(pin[1]);
- return 1;
- }
- *pChildPid = fork();
- if( *pChildPid<0 ){
- close(pin[0]);
- close(pin[1]);
- close(pout[0]);
- close(pout[1]);
- *pChildPid = 0;
- return 1;
- }
- if( *pChildPid==0 ){
- /* This is the child process */
- close(0);
- dup(pout[0]);
- close(pout[0]);
- close(pout[1]);
- close(1);
- dup(pin[1]);
- close(pin[0]);
- close(pin[1]);
- execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
- return 1;
- }else{
- /* This is the parent process */
- close(pin[1]);
- *pfdIn = pin[0];
- close(pout[0]);
- *ppOut = fdopen(pout[1], "w");
- return 0;
- }
- #endif
- }
- /*
- ** Close the connection to a child process previously created using
- ** popen2(). Kill off the child process, then close the pipes.
- */
- void pclose2(int fdIn, FILE *pOut, int childPid){
- #ifdef _WIN32
- /* Not implemented, yet */
- close(fdIn);
- fclose(pOut);
- #else
- close(fdIn);
- fclose(pOut);
- kill(childPid, SIGINT);
- #endif
- }