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: