Annotation of parser3/src/main/pa_exec.C, revision 1.1
1.1 ! paf 1: /** @file
! 2: Parser: program executing for different OS-es.
! 3:
! 4: Copyright(c) 2000,2001 ArtLebedev Group(http://www.artlebedev.com)
! 5:
! 6: Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
! 7:
! 8: $Id: pa_exec.C,v 1.6 2001/04/09 14:31:43 paf Exp $
! 9: */
! 10:
! 11: #include "pa_config_includes.h"
! 12:
! 13: #ifdef WIN32
! 14: # include <windows.h>
! 15: #else
! 16: # include <signal.h>
! 17: # include <sys/types.h>
! 18: # include <sys/wait.h>
! 19: #endif
! 20:
! 21: #include <stdio.h>
! 22: #include <errno.h>
! 23:
! 24: #include "pa_exec.h"
! 25: #include "pa_exception.h"
! 26: #include "pa_common.h"
! 27:
! 28:
! 29: #ifdef WIN32
! 30:
! 31: /// this func from http://www.ccas.ru/~posp/popov/spawn.htm
! 32: static BOOL WINAPI CreateHiddenConsoleProcess( LPCTSTR szChildName,
! 33: char *szEnv,
! 34: PROCESS_INFORMATION* ppi,
! 35: LPHANDLE phInWrite,
! 36: LPHANDLE phOutRead,
! 37: LPHANDLE phErrRead )
! 38: {
! 39: BOOL fCreated;
! 40: STARTUPINFO si;
! 41: SECURITY_ATTRIBUTES sa={0};
! 42: HANDLE hInRead;
! 43: HANDLE hOutWrite;
! 44: HANDLE hErrWrite;
! 45:
! 46: // Create pipes
! 47: // initialize security attributes for handle inheritance (for WinNT)
! 48: sa.nLength = sizeof( sa );
! 49: sa.bInheritHandle = TRUE;
! 50: sa.lpSecurityDescriptor = NULL;
! 51:
! 52: // create STDIN pipe
! 53: if( !CreatePipe( &hInRead, phInWrite, &sa, 0 ))
! 54: goto error;
! 55:
! 56: // create STDOUT pipe
! 57: if( !CreatePipe( phOutRead, &hOutWrite, &sa, 0 ))
! 58: goto error;
! 59:
! 60: // create STDERR pipe
! 61: if( !CreatePipe( phErrRead, &hErrWrite, &sa, 0 ))
! 62: goto error;
! 63:
! 64: // process startup information
! 65: memset( &si, 0, sizeof( si ));
! 66: si.cb = sizeof( si );
! 67: si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
! 68: // child process' console must be hidden for Win95 compatibility
! 69: si.wShowWindow = SW_HIDE;
! 70: // assign "other" sides of pipes
! 71: // si.hStdInput = hInRead;
! 72: si.hStdOutput = hOutWrite;
! 73: si.hStdError = hErrWrite;
! 74:
! 75: // Create a child process (suspended)
! 76: fCreated = CreateProcess( NULL,
! 77: (LPTSTR)szChildName,
! 78: NULL,
! 79: NULL,
! 80: TRUE,
! 81: DETACHED_PROCESS,
! 82: szEnv,
! 83: NULL,
! 84: &si,
! 85: ppi );
! 86:
! 87: CloseHandle( hInRead );
! 88: CloseHandle( hOutWrite );
! 89: CloseHandle( hErrWrite );
! 90:
! 91: if( !fCreated )
! 92: goto error;
! 93:
! 94: return TRUE;
! 95:
! 96: error:
! 97: CloseHandle( *phInWrite );
! 98: CloseHandle( *phOutRead );
! 99: CloseHandle( *phErrRead );
! 100:
! 101: return FALSE;
! 102: }
! 103:
! 104: static read_pipe(String& result, HANDLE hOutRead, const char *file_spec){
! 105: while(true) {
! 106: char *buf=(char *)result.pool().malloc(MAX_STRING);
! 107: unsigned long size;
! 108: ReadFile( hOutRead, buf, MAX_STRING, &size, NULL );
! 109: if(!size)
! 110: break;
! 111: result.APPEND_CLEAN(buf, size, file_spec, 0);
! 112: }
! 113: }
! 114:
! 115:
! 116: static const char *buildCommand(Pool& pool,
! 117: const String& origin_string,
! 118: const char *file_spec_cstr, const Array *argv) {
! 119: FILE *f=fopen(file_spec_cstr, "r");
! 120: if(f) {
! 121: char buf[MAX_STRING];
! 122: size_t size=fread(buf, 1, MAX_STRING-1, f);
! 123: if(size>2) {
! 124: buf[size]=0;
! 125: if(strncmp(buf, "#!", 2)==0) {
! 126: char *atEOL=strchr(buf, '\n');
! 127: if(atEOL) {
! 128: String string(pool);
! 129: string.APPEND_CLEAN(buf+2, atEOL-(buf+2),
! 130: origin_string.origin().file, 0);
! 131: string << " " << file_spec_cstr;
! 132: if(argv)
! 133: for(int i=0; i<argv->size(); i++)
! 134: string << argv->get_string(i)->cstr(String::UL_AS_IS);
! 135: file_spec_cstr=string.cstr();
! 136: }
! 137: }
! 138: }
! 139: fclose(f);
! 140: }
! 141: return file_spec_cstr;
! 142: }
! 143:
! 144: #else
! 145:
! 146: static int execle_piped(const char *path,
! 147: const char *arg1,
! 148: const char *arg2,
! 149: const char *arg3,
! 150: const char *arg4,
! 151: const char *arg5,
! 152: char * const env[],
! 153: int *pipe_in, int *pipe_out, int *pipe_err) {
! 154: int pid;
! 155: int in_fds[2];
! 156: int out_fds[2];
! 157: int err_fds[2];
! 158: int save_errno;
! 159:
! 160: if(pipe_in && pipe(in_fds)<0) {
! 161: save_errno=errno;
! 162: errno=save_errno;
! 163: return 0;
! 164: }
! 165:
! 166: if(pipe_out && pipe(out_fds)<0) {
! 167: save_errno=errno;
! 168: if(pipe_in) {
! 169: close(in_fds[0]); close(in_fds[1]);
! 170: }
! 171: errno=save_errno;
! 172: return 0;
! 173: }
! 174:
! 175: if(pipe_err && pipe(err_fds)<0) {
! 176: save_errno=errno;
! 177: if(pipe_in) {
! 178: close(in_fds[0]); close(in_fds[1]);
! 179: }
! 180: if(pipe_out) {
! 181: close(out_fds[0]); close(out_fds[1]);
! 182: }
! 183: errno=save_errno;
! 184: return 0;
! 185: }
! 186:
! 187: if((pid=fork())<0) {
! 188: save_errno=errno;
! 189: if(pipe_in) {
! 190: close(in_fds[0]); close(in_fds[1]);
! 191: }
! 192: if(pipe_out) {
! 193: close(out_fds[0]); close(out_fds[1]);
! 194: }
! 195: if(pipe_err) {
! 196: close(err_fds[0]); close(err_fds[1]);
! 197: }
! 198: errno=save_errno;
! 199: return 0;
! 200: }
! 201:
! 202: if(!pid) {
! 203: /* Child process */
! 204:
! 205: if(pipe_out) {
! 206: close(out_fds[0]);
! 207: dup2(out_fds[1], STDOUT_FILENO);
! 208: close(out_fds[1]);
! 209: }
! 210:
! 211: if(pipe_in) {
! 212: close(in_fds[1]);
! 213: dup2(in_fds[0], STDIN_FILENO);
! 214: close(in_fds[0]);
! 215: }
! 216:
! 217: if(pipe_err) {
! 218: close(err_fds[0]);
! 219: dup2(err_fds[1], STDERR_FILENO);
! 220: close(err_fds[1]);
! 221: }
! 222:
! 223: /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
! 224: signal(SIGCHLD, SIG_DFL); /* Was that it? */
! 225:
! 226: execle(path, arg1, arg2, arg3, arg4, arg5, NULL, env);
! 227: exit(-errno);
! 228: }
! 229:
! 230: /* Parent process */
! 231:
! 232: if(pipe_out) {
! 233: close(out_fds[1]);
! 234: *pipe_out=out_fds[0];
! 235: }
! 236:
! 237: if(pipe_in) {
! 238: close(in_fds[0]);
! 239: *pipe_in=in_fds[1];
! 240: }
! 241:
! 242: if(pipe_err) {
! 243: close(err_fds[1]);
! 244: *pipe_err=err_fds[0];
! 245: }
! 246:
! 247: return pid;
! 248: }
! 249:
! 250: static int get_exit_status(int pid) {
! 251: int status;
! 252: if(!waitpid(pid, &status, 0))
! 253: return -1;
! 254: return WIFEXITED(status) ?
! 255: WEXITSTATUS(status) : -2;
! 256: }
! 257:
! 258: static read_pipe(String& result, int file, const char *file_spec){
! 259: while(true) {
! 260: char *buf=(char *)pool.malloc(MAX_STRING);
! 261: size_t size=read(file, buf, MAX_STRING);
! 262: if(!size)
! 263: break;
! 264: result.APPEND_CLEAN(buf, size, file_spec, 0);
! 265: }
! 266: }
! 267:
! 268: #endif
! 269:
! 270: static void append_env_pair(const Hash::Key& key, Hash::Val *value, void *info) {
! 271: #ifdef WIN32
! 272: String& string=*static_cast<String *>(info);
! 273:
! 274: string << key << "=" << *static_cast<String *>(value);
! 275: string.APPEND_CLEAN("", 1, 0, 0); // zero byte
! 276: #else
! 277: String string(key.pool());
! 278: string << key << "=" << *static_cast<String *>(value);
! 279:
! 280: char **env_ptr=static_cast<char **>(info);
! 281: *env_ptr++=string.cstr();
! 282: #endif
! 283: }
! 284: int pa_exec(const String& file_spec,
! 285: const Hash *env,
! 286: const Array *argv,
! 287: const String& in, String& out, String& err) {
! 288: Pool& pool=file_spec.pool();
! 289:
! 290: #ifdef WIN32
! 291:
! 292: char pwd[MAX_STRING];
! 293: GetCurrentDirectory(sizeof(pwd), pwd);
! 294: char *dir=file_spec.cstr(String::UL_FILE_NAME);
! 295: rsplit(dir, '/'); SetCurrentDirectory(dir);
! 296:
! 297: PROCESS_INFORMATION pi;
! 298: HANDLE hInWrite, hOutRead, hErrRead;
! 299: char *file_spec_cstr=file_spec.cstr(String::UL_FILE_NAME);
! 300: const char *cmd=buildCommand(file_spec.pool(), file_spec, file_spec_cstr, argv);
! 301: char *env_cstr=0;
! 302: if(env) {
! 303: String string(env->pool());
! 304: env->for_each(append_env_pair, &string);
! 305: env_cstr=string.cstr(String::UL_AS_IS);
! 306: }
! 307: if( CreateHiddenConsoleProcess(cmd, env_cstr, &pi, &hInWrite, &hOutRead, &hErrRead )) {
! 308: SetCurrentDirectory(pwd);
! 309:
! 310: read_pipe(out, hOutRead, file_spec_cstr);
! 311: read_pipe(err, hErrRead, file_spec_cstr);
! 312: CloseHandle( hInWrite );
! 313: CloseHandle( hOutRead );
! 314: CloseHandle( hErrRead );
! 315: /*
! 316: from http://www.apache.org/websrc/cvsweb.cgi/apache-1.3/src/main/util_script.c?rev=1.151&content-type=text/vnd.viewcvs-markup
! 317:
! 318: * We must close the handles to the new process and its main thread
! 319: * to prevent handle and memory leaks.
! 320: */
! 321: CloseHandle(pi.hProcess);
! 322: CloseHandle(pi.hThread);
! 323: } else {
! 324: SetCurrentDirectory(pwd);
! 325:
! 326: DWORD error=GetLastError();
! 327: char szErrorDesc[MAX_STRING];
! 328: FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,
! 329: MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
! 330: szErrorDesc, sizeof(szErrorDesc), NULL);
! 331: size_t error_size=strlen(szErrorDesc);
! 332: if(error_size>3) // ".\r\n"
! 333: szErrorDesc[error_size-3]=0;
! 334:
! 335: PTHROW(0, 0,
! 336: &file_spec,
! 337: "exec failed - %s (%d)",
! 338: szErrorDesc,
! 339: (long)error);
! 340: }
! 341:
! 342: #else
! 343:
! 344: int pipe_write, pipe_read, pipe_err;
! 345: const char *argv_cstr[5]={"", "", "", "", ""};
! 346: if(argv) {
! 347: int size=min(5, argv->size());
! 348: for(int i=0; i<size; i++)
! 349: argv_cstr[i]=argv->get_string(i).cstr(String::UL_AS_IS);
! 350: }
! 351: const char *file_spec_cstr=file_spec->cstr(String::UL_FILE_NAME);
! 352: char **env_cstr=0;
! 353: if(env) {
! 354: env_cstr_array=
! 355: (char **)env->pool().malloc(sizeof(char *)*(env->size()+1/*0*/));
! 356: char **env_ptr=env_cstr_array;
! 357: env->for_each(append_env_pair, &env_ptr);
! 358: *env_ptr=0;
! 359: }
! 360: if(int pid=execle_piped(sendmail_filespec,
! 361: file_spec_cstr,
! 362: argv_cstr[0], argv_cstr[1], argv_cstr[2], argv_cstr[3], argv_cstr[4],
! 363: env_cstr,
! 364: &pipe_write, &pipe_read, &pipe_err)) {
! 365:
! 366: const char *in_cstr=in.cstr(String::UL_AS_IS);
! 367: write(pipe_write, in_cstr, in.size());
! 368: close(pipe_write);
! 369: read_pipe(out, pipe_read, file_spec_cstr);
! 370: read_pipe(err, pipe_err, file_spec_cstr);
! 371: close(pipe_read);
! 372: close(pipe_err);
! 373:
! 374: return get_exit_status(pid); // negative may mean "-errno[execl()]"
! 375: } else
! 376: PTHROW(0, 0,
! 377: file_spec,
! 378: "pipe error");
! 379: #endif
! 380:
! 381: return 0;
! 382: }
E-mail: