Diff for /parser3/src/main/pa_exec.C between versions 1.21 and 1.48.2.17

version 1.21, 2002/01/25 12:59:05 version 1.48.2.17, 2003/03/05 11:08:26
Line 1 Line 1
 /** @file  /** @file
         Parser: program executing for different OS-es.          Parser: program executing for different OS-es.
   
         Copyright(c) 2000,2001 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2000,2001-2003 ArtLebedev Group(http://www.artlebedev.com)
         Author: Alexander Petrosyan <paf@design.ru>(http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         $Id$  
   
   
         @todo setrlimit          @todo setrlimit
 */  */
   
   static const char* IDENT_EXEC_C="$Date$";
   
 #include "pa_config_includes.h"  #include "pa_config_includes.h"
   
 #include "pa_exec.h"  #include "pa_exec.h"
Line 27 Line 26
 #ifdef WIN32  #ifdef WIN32
   
 /// this func from http://www.ccas.ru/~posp/popov/spawn.htm  /// this func from http://www.ccas.ru/~posp/popov/spawn.htm
 static BOOL WINAPI CreateHiddenConsoleProcess(LPCTSTR szChildName,  static DWORD CreateHiddenConsoleProcess(LPCTSTR szCmdLine,
                                                                                 char *szEnv,                                                                                  char *szEnv,
                                         PROCESS_INFORMATION* ppi,                                           PROCESS_INFORMATION* ppi, 
                                         LPHANDLE phInWrite,                                          LPHANDLE phInWrite,
                                         LPHANDLE phOutRead,                                          LPHANDLE phOutRead,
                                         LPHANDLE phErrRead)                                          LPHANDLE phErrRead)
 {  {
     BOOL fCreated;      DWORD result=0;
           BOOL fCreated;
     STARTUPINFO si;      STARTUPINFO si;
     SECURITY_ATTRIBUTES sa={0};      SECURITY_ATTRIBUTES sa={0};
     HANDLE hInRead;      HANDLE hInRead;
Line 70  static BOOL WINAPI CreateHiddenConsolePr Line 70  static BOOL WINAPI CreateHiddenConsolePr
     si.hStdOutput=hOutWrite;      si.hStdOutput=hOutWrite;
     si.hStdError=hErrWrite;      si.hStdError=hErrWrite;
   
           // calculating script's directory
           char dir[MAX_STRING];
           strncpy(dir, szCmdLine, MAX_STRING-1); dir[MAX_STRING-1]=0;
           lsplit(dir,' '); // trim arguments
           rsplit(dir,'/'); rsplit(dir,'\\'); // trim filename
           chdir(dir);
   
     // Create a child process (suspended)      // Create a child process (suspended)
     fCreated=CreateProcess(NULL,      fCreated=CreateProcess(NULL,
                               (LPTSTR)szChildName,                                (LPTSTR)szCmdLine,
                               NULL,                                NULL,
                               NULL,                                NULL,
                               TRUE,                                TRUE,
                               0, //todo CREATE_NO_WINDOW,                                CREATE_NO_WINDOW,
                               szEnv,                                szEnv,
                               NULL,                                dir,
                               &si,                                &si,
                               ppi);                                ppi);
           if(!fCreated)
                   result=GetLastError();
   
     CloseHandle(hInRead);      CloseHandle(hInRead);
     CloseHandle(hOutWrite);      CloseHandle(hOutWrite);
Line 89  static BOOL WINAPI CreateHiddenConsolePr Line 98  static BOOL WINAPI CreateHiddenConsolePr
     if(!fCreated)      if(!fCreated)
         goto error;          goto error;
   
     return TRUE;      return result;
   
 error:  error:
           if(!result/*yet*/)
                   result=GetLastError(); // get it
   
     CloseHandle(*phInWrite);      CloseHandle(*phInWrite);
     CloseHandle(*phOutRead);      CloseHandle(*phOutRead);
     CloseHandle(*phErrRead);      CloseHandle(*phErrRead);
   
     return FALSE;      return result;
 }  }
   
 static void read_pipe(String& result, HANDLE hOutRead, const char *file_spec){  static StringPtr read_pipe(Pool& pool, HANDLE hOutRead, const char* file_spec, 
                                             String::Untaint_lang lang){
           StringPtr result(new String);
         while(true) {          while(true) {
                 char *buf=(char *)result.pool().malloc(MAX_STRING);                  char *buf=new(pool) char[MAX_STRING];
                 unsigned long size;                  unsigned long size;
                 ReadFile(hOutRead, buf, MAX_STRING, &size, NULL);                  if(!ReadFile(hOutRead, buf, MAX_STRING, &size, NULL) || !size) 
                 if(!size)   
                         break;                          break;
                 result.APPEND_AS_IS(buf, size, file_spec, 0);                  result->APPEND(buf, size, lang, file_spec, 0);
     }      }
           return result;
 }  }
   
   static CharPtr buildCommand(CharPtr file_spec_cstr, const ArrayString& argv) {
 static const char *buildCommand(Pool& pool,           CharPtr result=file_spec_cstr;
                                                                 const String& origin_string,  
                                                                 const char *file_spec_cstr, const Array *argv) {  
         const char *result=file_spec_cstr;  
         if(FILE *f=fopen(file_spec_cstr, "r")) {          if(FILE *f=fopen(file_spec_cstr, "r")) {
                   try {
                 char buf[MAX_STRING];                  char buf[MAX_STRING];
                 size_t size=fread(buf, 1, MAX_STRING-1, f);                  size_t size=fread(buf, 1, MAX_STRING-1, f);
                 if(size>2) {                  if(size>2) {
                         buf[size]=0;                          buf[size]=0;
                         if(strncmp(buf, "#!", 2)==0) {                          if(strncmp(buf, "#!", 2)==0) {
                                 const char *begin=buf+2;                                  const char* begin=buf+2;
                                 if(*begin==' ') // alx: were an old magic for some linux-es                                  if(*begin==' ') // alx: were an old magic for some linux-es
                                         begin++;                                          begin++;
                                 if(char *end=strchr(begin, '\n')) {                                  if(char *end=strchr(begin, '\n')) {
                                         String string(pool);                                          String string(begin, end-begin);
                                         string.APPEND_AS_IS(begin, end-begin,   
                                                 origin_string.origin().file, 0);  
                                         string << " " << file_spec_cstr;                                          string << " " << file_spec_cstr;
                                         if(argv)  
                                                 for(int i=0; i<argv->size(); i++)  
                                                         string << argv->get_string(i)->cstr();  
                                         result=string.cstr();                                          result=string.cstr();
                                 }                                  }
                         }                          }
                 }                  }
                   } catch(...) {
                           fclose(f);
                           rethrow;
                   }
                 fclose(f);                  fclose(f);
         }          }
         if(argv) {          { // appending argv
                 String buf(pool);                  String string(result);
                 buf << result;                  for(int i=0; i<argv.count(); i++) {
                 for(int i=0; i<argv->size(); i++) {                          string << " ";
                         buf << " ";                          string << *argv[i];
                         buf << *argv->get_string(i);  
                 }                  }
   
                 result=buf.cstr();                  result=string.cstr();
         }          }
   
         return result;          return result;
Line 154  static const char *buildCommand(Pool& po Line 164  static const char *buildCommand(Pool& po
   
 #else  #else
   
 static int execle_piped(const char *path,   static pid_t execve_piped(const char* file_spec_cstr, 
                                                 const char *arg1, const char *arg2,                          char * const argv[], char * const env[],
                                                 const char *arg3, const char *arg4,                          int *pipe_in, int *pipe_out, int *pipe_err) {
                                                 const char *arg5, const char *arg6,          pid_t pid;
                                                 const char *arg7, const char *arg8,  
                                                 const char *arg9, const char *arg10,  
                                                 char * const env[],  
                                                 int *pipe_in, int *pipe_out, int *pipe_err) {  
         int pid;  
         int in_fds[2];          int in_fds[2];
         int out_fds[2];          int out_fds[2];
         int err_fds[2];          int err_fds[2];
Line 207  static int execle_piped(const char *path Line 212  static int execle_piped(const char *path
                         close(err_fds[0]); close(err_fds[1]);                          close(err_fds[0]); close(err_fds[1]);
                 }                  }
                 errno=save_errno;                  errno=save_errno;
                 return 0;                  return -1;
         }          }
                   
         if(!pid) {          if(!pid) {
Line 231  static int execle_piped(const char *path Line 236  static int execle_piped(const char *path
                         close(err_fds[1]);                          close(err_fds[1]);
                 }                  }
                                   
                 /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */                  /* grabbed this from Apache source: */
                   /*  HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */
                 signal(SIGCHLD, SIG_DFL);       /* Was that it? */                  signal(SIGCHLD, SIG_DFL);       /* Was that it? */
                   
                 execle(path, arg1, arg2, arg3, arg4, arg5, NULL, env);                  // chdir to script's directory
                   char dir[MAX_STRING];
                   strncpy(dir, file_spec_cstr, MAX_STRING-1); dir[MAX_STRING-1]=0;
                   rsplit(dir,'/'); // trim filename
                   chdir(dir);
   
                   //  execute
                   execve(file_spec_cstr, argv, env);
                 exit(-errno);                  exit(-errno);
         }          }
                   
Line 266  static int get_exit_status(int pid) { Line 279  static int get_exit_status(int pid) {
                 WEXITSTATUS(status) : -2;                  WEXITSTATUS(status) : -2;
 }  }
   
 static void read_pipe(String& result, int file, const char *file_spec){  static StringPtr read_pipe(Pool& pool, int file, const char* file_spec, String::Untaint_lang lang){
           StringPtr result(new String);
         while(true) {          while(true) {
                 char *buf=(char *)result.pool().malloc(MAX_STRING);                  char *buf=new(pool) char[MAX_STRING];
                 size_t size=read(file, buf, MAX_STRING);                  ssize_t size=read(file, buf, MAX_STRING);
                 if(!size)                   if(size<=0)
                         break;                          break;
                 result.APPEND_AS_IS(buf, size, file_spec, 0);                  result->APPEND(buf, size, lang, file_spec, 0);
     }      }
           return result;
 }  }
   
 #endif  #endif
   
 static void append_env_pair(const Hash::Key& key, Hash::Val *value, void *info) {  #ifndef DOXYGEN
   struct Append_env_pair_info {
 #ifdef WIN32  #ifdef WIN32
         String& string=*static_cast<String *>(info);          String* string;
           #else
         string << key << "=" << *static_cast<String *>(value);          Pool *pool;
         string.APPEND_AS_IS("", 1, 0, 0); // zero byte          char **env_ref;
   #endif
   };
   #endif
   ///@test maybe here and at argv construction --- cstr(String::UL_UNSPECIFIED
   static void append_env_pair(HashStringString::key_type key, HashStringString::value_type value,
                   Append_env_pair_info *info) {
   #ifdef WIN32
           *info->string << key << "=" << value;
           info->string->APPEND_AS_IS("", 1, 0, 0); // zero byte
 #else  #else
         String string(key.pool());          String string;
         string << key << "=" << *static_cast<String *>(value);          string << key << "=" << value;
   
         char ***env_ref=static_cast<char ***>(info);          *(info->env_ref++)=string.cstr(*info->pool, String::UL_UNSPECIFIED);
         **env_ref=string.cstr();  (*env_ref)++;  
 #endif  #endif
 }  }
 int pa_exec(const String& file_spec,   
                         const Hash *env,  
                         const Array *argv,  
                         const String& in, String& out, String& err) {  
         Pool& pool=file_spec.pool();  
   
 #ifdef WIN32  /// @todonow unix part to smart_ptr
   PA_exec_result pa_exec(Pool& pool,
                           bool forced_allow, 
                           StringPtr file_spec, 
                           const HashStringString* env, 
                           const ArrayString& argv, 
                           String& in) {
           PA_exec_result result;
   
   #ifdef NO_PA_EXECS
           if(!forced_allow)
                   throw Exception("parser.runtime",
                           file_spec,
                           "parser execs are disabled [recompile parser without --disable-execs configure option]");
   #endif
   
         char pwd[MAX_STRING];          char* file_spec_cstr=file_spec->cstr(pool, String::UL_FILE_SPEC); 
         GetCurrentDirectory(sizeof(pwd), pwd);  #ifdef WIN32
         char *dir=file_spec.cstr(String::UL_FILE_SPEC);  
         rsplit(dir, '/'); SetCurrentDirectory(dir);  
   
         PROCESS_INFORMATION pi;           PROCESS_INFORMATION pi; 
         HANDLE hInWrite, hOutRead, hErrRead;          HANDLE hInWrite, hOutRead, hErrRead;
         char *file_spec_cstr=file_spec.cstr(String::UL_FILE_SPEC);           CharPtr cmd=buildCommand(file_spec->cstr(String::UL_FILE_SPEC), argv);
         const char *cmd=buildCommand(file_spec.pool(), file_spec, file_spec_cstr, argv);          CharPtr env_cstr;
         char *env_cstr=0;  
         if(env) {          if(env) {
                 String string(env->pool());                  String string;
                 env->for_each(append_env_pair, &string);                  Append_env_pair_info info={&string};
                 env_cstr=string.cstr();                  env->for_each(append_env_pair, &info);
                   env_cstr=info.string->cstr(String::UL_UNSPECIFIED);
         }          }
         if(CreateHiddenConsoleProcess(cmd, env_cstr, &pi, &hInWrite, &hOutRead, &hErrRead)) {          if(DWORD error=CreateHiddenConsoleProcess(cmd, env_cstr, &pi, &hInWrite, &hOutRead, &hErrRead)) {
                 SetCurrentDirectory(pwd);                  char szErrorDesc[MAX_STRING];
                   const char *param="the file you tried to run";
                 const char *in_cstr=in.cstr();                  size_t error_size=FormatMessage(
                           FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ARGUMENT_ARRAY , NULL, error,
                           MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
                           szErrorDesc, sizeof(szErrorDesc), (va_list *)&param);
                   if(error_size>3) // ".\r\n"
                           szErrorDesc[error_size-3]=0;
               
                   throw Exception(0,
                           file_spec,
                           "exec failed - %s (%ld). Consider adding shbang line (#!x:\\interpreter\\command line)", 
                                   error_size?szErrorDesc:"<unknown>", (long)error);
           } else {
                   CharPtr in_cstr=in.cstr();
                 DWORD written_size;                  DWORD written_size;
                 WriteFile(hInWrite, in_cstr, in.size(), &written_size, NULL);                  WriteFile(hInWrite, in_cstr, in.size(), &written_size, NULL);
                 // EOF for stupid text reads                  // EOF for stupid text reads
Line 326  int pa_exec(const String& file_spec, Line 369  int pa_exec(const String& file_spec,
                 // without this char                  // without this char
                 WriteFile(hInWrite, "\x1A", 1, &written_size, NULL);                  WriteFile(hInWrite, "\x1A", 1, &written_size, NULL);
                 CloseHandle(hInWrite);                  CloseHandle(hInWrite);
                 read_pipe(out, hOutRead, file_spec_cstr);                  result.out=read_pipe(pool, hOutRead, file_spec_cstr, String::UL_AS_IS);
                 CloseHandle(hOutRead);                  CloseHandle(hOutRead);
                 read_pipe(err, hErrRead, file_spec_cstr);                                 result.err=read_pipe(pool, hErrRead, file_spec_cstr, String::UL_TAINTED);               
                 CloseHandle(hErrRead);                  CloseHandle(hErrRead);
 /*        /*      
 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  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
Line 338  from http://www.apache.org/websrc/cvsweb Line 381  from http://www.apache.org/websrc/cvsweb
 */        */      
                 CloseHandle(pi.hProcess);                  CloseHandle(pi.hProcess);
         CloseHandle(pi.hThread);          CloseHandle(pi.hThread);
         } else {  
                 SetCurrentDirectory(pwd);  
   
                 DWORD error=GetLastError();  
                 char szErrorDesc[MAX_STRING];  
                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, error,  
                 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),  
                 szErrorDesc, sizeof(szErrorDesc), NULL);  
                 size_t error_size=strlen(szErrorDesc);  
                 if(error_size>3) // ".\r\n"  
                         szErrorDesc[error_size-3]=0;  
               
                 throw Exception(0, 0,  
                         &file_spec,  
                         "(real filename=\"%s\") exec failed - %s (%ld)",  
                                 cmd,  
                                 szErrorDesc, (long)error);  
         }          }
   
 #else  #else
   
         int pipe_write, pipe_read, pipe_err;          int pipe_write, pipe_read, pipe_err;
         const char *argv_cstrs[10]={  
                 "", "", "", "", "",   #ifdef PA_SAFE_MODE
                 "", "", "", "", ""          if(!forced_allow) {
         };                  struct stat finfo;
         if(argv) {                  if(stat(file_spec_cstr, &finfo)!=0)
                 const int argv_size=argv->size();                          throw Exception("file.missing", 
                 const int argv_max=sizeof(argv_cstrs)/sizeof(argv_cstrs[0]);                                          file_spec, 
                 if(argv_size>argv_max)                                          "stat failed: %s (%d), actual filename '%s'", 
                         throw Exception(0, 0,                                                  strerror(errno), errno, file_spec_cstr);
                                 &file_spec,  
                                 "too many arguments (%d > max %d)", argv_size, argv_max);                  if(finfo.st_uid/*foreign?*/!=geteuid()
                 for(int i=0; i<argv_size; i++)                          && finfo.st_gid/*foreign?*/!=getegid())
                         argv_cstrs[i]=argv->get_string(i)->cstr();                          throw Exception("parser.runtime", 
                                   file_spec, 
                                   "parser is in safe mode: executing files of foreign group and user disabled [recompile parser with --disable-safe-mode configure option], actual filename '%s'", 
                                           file_spec_cstr);
         }          }
         const char *file_spec_cstr=file_spec.cstr(String::UL_FILE_SPEC);  #endif
         char **env_cstrs=0;  
         if(env) {          char * argv_cstrs[1+10+1]={file_spec_cstr, 0};
                 env_cstrs=          const int argv_size=argv.count();
                         (char **)env->pool().malloc(sizeof(char *)*(env->size()+1/*0*/));          const int argv_max=sizeof(argv_cstrs)/sizeof(argv_cstrs[0])-1-1;
                 char **env_ref=env_cstrs;          if(argv_size>argv_max)
                 env->for_each(append_env_pair, &env_ref);                  throw Exception("parser.runtime",
                 *env_ref=0;                          file_spec,
                           "too many arguments (%d > max %d)", argv_size, argv_max);
           for(int i=0; i<argv_size; i++)
                   argv_cstrs[1+i]=argv[i]->cstr(pool);
           argv_cstrs[1+argv_size]=0;
   
           char **env_cstrs=new(pool) char *[env.count()+1/*0*/];
           {
                   Append_env_pair_info info={&pool, env_cstrs}; 
                   env.for_each(append_env_pair, &info);
                   *info.env_ref=0;
         }          }
         const char *pwd=getcwd(NULL, 0);  
         char dir[MAX_STRING];          pid_t pid=execve_piped(
         strncpy(dir, file_spec_cstr, MAX_STRING);  
         rsplit(dir,'/'); // trim filename  
     chdir(dir);  
         int pid=execle_piped(  
                 file_spec_cstr,                  file_spec_cstr,
                 argv_cstrs[0], argv_cstrs[1], argv_cstrs[2], argv_cstrs[3], argv_cstrs[4],                  argv_cstrs, env_cstrs,
                 argv_cstrs[5], argv_cstrs[6], argv_cstrs[7], argv_cstrs[8], argv_cstrs[9],                  &pipe_write, &pipe_read, &pipe_err);
                 env_cstrs,          if(pid>0) {
                 &pipe_write, &pipe_read, &pipe_err));  
     if (pwd)   
                 chdir(pwd);  
         if(pid) {  
                 // in child                  // in child
                 const char *in_cstr=in.cstr();                  if(in.size()) {// there is some in data
                 write(pipe_write, in_cstr, in.size());                          CharPtr in_cstr=in.cstr();
                           write(pipe_write, in_cstr, in.size());
                   }
                 close(pipe_write);                  close(pipe_write);
                 read_pipe(out, pipe_read, file_spec_cstr);                  result.out=read_pipe(pool, pipe_read, file_spec_cstr, String::UL_AS_IS);
                 close(pipe_read);                  close(pipe_read);
                 read_pipe(err, pipe_err, file_spec_cstr);                  result.err=read_pipe(pool, pipe_err, file_spec_cstr, String::UL_TAINTED);
                 close(pipe_err);                  close(pipe_err);
   
                 return get_exit_status(pid); // negative may mean "-errno[execl()]"                  result.status=get_exit_status(pid); // negative may mean "-errno[execl()]"
         } else           } else 
                 throw Exception(0, 0,                  throw Exception(0,
                         &file_spec,                          file_spec,
                         "pipe error");                          "%s error: %s (%d)", pid<0?"fork":"pipe", strerror(errno), errno); 
 #endif  #endif
   
         return 0;          return result;
 }  }

Removed from v.1.21  
changed lines
  Added in v.1.48.2.17


E-mail: