Diff for /parser3/src/main/pa_exec.C between versions 1.59 and 1.76

version 1.59, 2004/05/25 06:20:48 version 1.76, 2009/08/15 13:04:10
Line 1 Line 1
 /** @file  /** @file
         Parser: program executing for different OS-es.          Parser: program executing for different OS-es.
   
         Copyright(c) 2000,2001-2004 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2000-2009 ArtLebedev Group(http://www.artlebedev.com)
         Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         @todo setrlimit          @todo setrlimit
Line 27  static const char * const IDENT_EXEC_C=" Line 27  static const char * const IDENT_EXEC_C="
   
 /// this func from http://www.ccas.ru/~posp/popov/spawn.htm  /// this func from http://www.ccas.ru/~posp/popov/spawn.htm
 static DWORD CreateHiddenConsoleProcess(LPCTSTR szCmdLine,  static DWORD CreateHiddenConsoleProcess(LPCTSTR szCmdLine,
                                                                                   LPCTSTR szScriptFileSpec,
                                                                                 char *szEnv,                                                                                  char *szEnv,
                                         PROCESS_INFORMATION* ppi,                                                                                   PROCESS_INFORMATION* ppi, 
                                         LPHANDLE phInWrite,                                                                                  LPHANDLE phInWrite,
                                         LPHANDLE phOutRead,                                                                                  LPHANDLE phOutRead,
                                         LPHANDLE phErrRead)                                                                                  LPHANDLE phErrRead)
 {  {
         DWORD result=0;          DWORD result=0;
         BOOL fCreated;          BOOL fCreated;
Line 72  static DWORD CreateHiddenConsoleProcess( Line 73  static DWORD CreateHiddenConsoleProcess(
                   
         // calculating script's directory          // calculating script's directory
         char dir[MAX_STRING];          char dir[MAX_STRING];
         strncpy(dir, szCmdLine, MAX_STRING-1); dir[MAX_STRING-1]=0;          strncpy(dir, szScriptFileSpec, MAX_STRING-1); dir[MAX_STRING-1]=0;
         lsplit(dir,' '); // trim arguments          lsplit(dir,' '); // trim arguments
         rsplit(dir,'/'); rsplit(dir,'\\'); // trim filename          rsplit(dir,'/'); rsplit(dir,'\\'); // trim filename
         chdir(dir);  
                   
         // Create a child process (suspended)          // Create a child process (suspended)
         fCreated=CreateProcess(NULL,          fCreated=CreateProcess(NULL,
Line 122  static void read_pipe(String& result, HA Line 122  static void read_pipe(String& result, HA
         }          }
 }  }
   
   static void read_pipe(File_read_result& result, HANDLE hOutRead){
   
           char *buf=new(PointerFreeGC) char[MAX_STRING];
   
           unsigned long size = 0;
           unsigned long bufsize = 0;
           unsigned long newsize = 0;
   
           result.headers = 0;
           result.length = 0;
           result.str = 0;
           result.success = false;
   
           while(true) {
                   if(!ReadFile(hOutRead, buf, MAX_STRING-1, &size, NULL) || !size) 
                           break;
                   newsize = (size + result.length);
                   if(newsize > bufsize){
                           bufsize = (size==MAX_STRING-1)?newsize*2:newsize;
                           char *tmp = new(PointerFreeGC) char[bufsize];
                           if(result.str)
                                   memcpy(tmp, result.str, result.length);
                           memcpy(tmp+result.length, buf, size);
                           result.str = tmp;
                   }else{
                           memcpy(result.str+result.length, buf, size);
                   }
                   result.length = newsize;
           }
   }
   
 static const char* buildCommand(const char* file_spec_cstr, const ArrayString& argv) {  static const char* buildCommand(const char* file_spec_cstr, const ArrayString& argv) {
         const char* result=file_spec_cstr;          const char* result=file_spec_cstr;
         if(FILE *f=fopen(file_spec_cstr, "r")) {          if(FILE *f=fopen(file_spec_cstr, "r")) {
Line 132  static const char* buildCommand(const ch Line 163  static const char* buildCommand(const ch
                         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                                  while(*begin==' ') // alx: were an old magic for some linux-es
                                         begin++;                                          begin++;
                                 if(char *end=strchr(begin, '\n')) {                                  if(const char *end=strchr(begin, '\n')) {
                                         String string(pa_strdup(begin, end-begin));                                          String string(pa_strdup(begin, end-begin));
                                         string << " " << file_spec_cstr;                                          string << " " << file_spec_cstr;
                                         result=string.cstr();                                          result=string.cstr();
Line 290  static void read_pipe(String& result, in Line 321  static void read_pipe(String& result, in
         }          }
 }  }
   
   static void read_pipe(File_read_result& result, int file){
           char *buf=new(PointerFreeGC) char[MAX_STRING];
   
           unsigned long bufsize = 0;
           unsigned long newsize = 0;
   
           result.headers = 0;
           result.length = 0;
           result.str = 0;
           result.success = false;
   
           while(true) {
                   ssize_t size=read(file, buf, MAX_STRING-1);
                   if(size <= 0)
                           break;
                   newsize = (size + result.length);
                   if(newsize > bufsize){
                           bufsize = (size==MAX_STRING-1)?newsize*2:newsize;
                           char *tmp = new(PointerFreeGC) char[bufsize];
                           if(result.str)
                                   memcpy(tmp, result.str, result.length);
                           memcpy(tmp+result.length, buf, size);
                           result.str = tmp;
                   }else{
                           memcpy(result.str+result.length, buf, size);
                   }
                   result.length = newsize;
           }
   }
   
 #endif  #endif
   
 #ifndef DOXYGEN  #ifndef DOXYGEN
 struct Append_env_pair_info {  struct Append_env_pair_info {
 #ifdef WIN32  #ifdef WIN32
         String& string;          String::Body& body;
         Append_env_pair_info(String& astring): string(astring) {}          Append_env_pair_info(String::Body& abody): body(abody) {}
 #else  #else
         char **env_ref;          char **env_ref;
 #endif  #endif
 };  };
 #endif  #endif
 ///@test maybe here and at argv construction --- cstr(String::L_UNSPECIFIED  ///@test maybe here and at argv construction --- untaint_cstr(String::L_AS_IS
 static void append_env_pair(HashStringString::key_type key, HashStringString::value_type value,  static void append_env_pair(HashStringString::key_type key, HashStringString::value_type value,
                 Append_env_pair_info *info) {                  Append_env_pair_info *info) {
 #ifdef WIN32  #ifdef WIN32
         info->string << key << "=" << value;          info->body << key << "=" << value;
         info->string.append_know_length("\1", 1, String::L_AS_IS); // placeholder for of zero byte          info->body.append_know_length("\1", 1); // placeholder for of zero byte
 #else  #else
         String::Body body;          String::Body body;
         body << key << "=" << value;          body << key << "=" << value.cstr();
   
         *(info->env_ref++)=body.cstrm();          *(info->env_ref++)=body.cstrm();
 #endif  #endif
 }  }
   
 /// @todonow unix part to smart_ptr  
 PA_exec_result pa_exec(  PA_exec_result pa_exec(
                         bool                           bool 
 #if defined(NO_PA_EXEC) || defined(PA_SAFE_MODE)  #if defined(NO_PA_EXEC) || defined(PA_SAFE_MODE)
Line 331  PA_exec_result pa_exec( Line 391  PA_exec_result pa_exec(
   
 #ifdef NO_PA_EXECS  #ifdef NO_PA_EXECS
         if(!forced_allow)          if(!forced_allow)
                 throw Exception("parser.runtime",                  throw Exception(PARSER_RUNTIME,
                         &file_spec,                          &file_spec,
                         "parser execs are disabled [recompile parser without --disable-execs configure option]");                          "parser execs are disabled [recompile parser without --disable-execs configure option]");
 #endif  #endif
Line 340  PA_exec_result pa_exec( Line 400  PA_exec_result pa_exec(
   
         PROCESS_INFORMATION pi;           PROCESS_INFORMATION pi; 
         HANDLE hInWrite, hOutRead, hErrRead;          HANDLE hInWrite, hOutRead, hErrRead;
         const char* cmd=buildCommand(file_spec.cstr(String::L_FILE_SPEC), argv);          const char* script_spec_cstr=file_spec.taint_cstr(String::L_FILE_SPEC);
           const char* cmd=buildCommand(script_spec_cstr, argv);
         char* env_cstr=0;          char* env_cstr=0;
         if(env) {          if(env) {
                 String string;                  String::Body body;
                 Append_env_pair_info info(string);                  Append_env_pair_info info(body);
                 env->for_each(append_env_pair, &info);                  env->for_each<Append_env_pair_info*>(append_env_pair, &info);
                 env_cstr=info.string.cstrm(String::L_UNSPECIFIED);                  env_cstr=info.body.cstrm();
                 for(char* replacer=env_cstr; *replacer; replacer++)                  for(char* replacer=env_cstr; *replacer; replacer++)
                         if(*replacer=='\1')                          if(*replacer=='\1')
                                 *replacer=0;                                  *replacer=0;
         }          }
         if(DWORD error=CreateHiddenConsoleProcess(cmd, env_cstr, &pi, &hInWrite, &hOutRead, &hErrRead)) {          if(DWORD error=CreateHiddenConsoleProcess(cmd, script_spec_cstr, env_cstr, &pi, &hInWrite, &hOutRead, &hErrRead)) {
                 char szErrorDesc[MAX_STRING];                  char szErrorDesc[MAX_STRING];
                 const char* param="the file you tried to run";                  const char* param="the file you tried to run";
                 size_t error_size=FormatMessage(                  size_t error_size=FormatMessage(
Line 360  PA_exec_result pa_exec( Line 421  PA_exec_result pa_exec(
                         szErrorDesc, sizeof(szErrorDesc), (va_list *)&param);                          szErrorDesc, sizeof(szErrorDesc), (va_list *)&param);
                 if(error_size>3) // ".\r\n"                  if(error_size>3) // ".\r\n"
                         szErrorDesc[error_size-3]=0;                          szErrorDesc[error_size-3]=0;
               
                 throw Exception(0,                  throw Exception("file.execute",
                         &file_spec,                          &file_spec,
                         "exec failed - %s (%u). Consider adding shbang line (#!x:\\interpreter\\command line)",                           "exec failed - %s (%u). Consider adding shbang line (#!x:\\interpreter\\command line)", 
                                 error_size?szErrorDesc:"<unknown>", error);                                  error_size?szErrorDesc:"<unknown>", error);
Line 374  PA_exec_result pa_exec( Line 435  PA_exec_result pa_exec(
                 // 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(result.out, hOutRead, String::L_AS_IS);                  read_pipe(result.out, hOutRead);
                 CloseHandle(hOutRead);                  CloseHandle(hOutRead);
                 read_pipe(result.err, hErrRead, String::L_TAINTED);                               read_pipe(result.err, hErrRead, String::L_TAINTED);             
                 CloseHandle(hErrRead);                  CloseHandle(hErrRead);
Line 382  PA_exec_result pa_exec( Line 443  PA_exec_result pa_exec(
 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
   
         * We must close the handles to the new process and its main thread          * We must close the handles to the new process and its main thread
     * to prevent handle and memory leaks.          * to prevent handle and memory leaks.
 */        */      
                 CloseHandle(pi.hProcess);                  CloseHandle(pi.hProcess);
         CloseHandle(pi.hThread);                  CloseHandle(pi.hThread);
         }          }
   
 #else  #else
   
         // execve needs non const          // execve needs non const
         char* file_spec_cstr=file_spec.cstrm(String::L_FILE_SPEC);           char* file_spec_cstr=file_spec.taint_cstrm(String::L_FILE_SPEC); 
   
         int pipe_write, pipe_read, pipe_err;          int pipe_write, pipe_read, pipe_err;
   
Line 408  from http://www.apache.org/websrc/cvsweb Line 469  from http://www.apache.org/websrc/cvsweb
         }          }
 #endif  #endif
   
         char* argv_cstrs[1+10+1]={file_spec_cstr, 0};          char* argv_cstrs[1+100+1]={file_spec_cstr, 0};
         const int argv_size=argv.count();          const int argv_size=argv.count();
         const int argv_max=sizeof(argv_cstrs)/sizeof(argv_cstrs[0])-1-1;          const int argv_max=sizeof(argv_cstrs)/sizeof(argv_cstrs[0])-1-1;
         if(argv_size>argv_max)          if(argv_size>argv_max)
                 throw Exception("parser.runtime",                  throw Exception(PARSER_RUNTIME,
                         &file_spec,                          &file_spec,
                         "too many arguments (%d > max %d)", argv_size, argv_max);                          "too many arguments (%d > max %d)", argv_size, argv_max);
         for(int i=0; i<argv_size; i++)          for(int i=0; i<argv_size; i++)
Line 434  from http://www.apache.org/websrc/cvsweb Line 495  from http://www.apache.org/websrc/cvsweb
                 &pipe_write, &pipe_read, &pipe_err);                  &pipe_write, &pipe_read, &pipe_err);
         if(pid>0) {          if(pid>0) {
                 // in child                  // in child
                 if(in.length()) {// there is some in data                  if(!in.is_empty()) {// there is some in data
                         const char* in_cstr=in.cstr();                          const char* in_cstr=in.cstr();
                         write(pipe_write, in_cstr, in.length());                          write(pipe_write, in_cstr, in.length());
                 }                  }
                 close(pipe_write);                  close(pipe_write);
                 read_pipe(result.out, pipe_read, String::L_AS_IS);                  read_pipe(result.out, pipe_read);
                 close(pipe_read);                  close(pipe_read);
                 read_pipe(result.err, pipe_err, String::L_TAINTED);                  read_pipe(result.err, pipe_err, String::L_TAINTED);
                 close(pipe_err);                  close(pipe_err);
Line 447  from http://www.apache.org/websrc/cvsweb Line 508  from http://www.apache.org/websrc/cvsweb
                 result.status=get_exit_status(pid); // negative may mean "-errno[execl()]"                  result.status=get_exit_status(pid); // negative may mean "-errno[execl()]"
         } else {           } else { 
                 const char* str=strerror(errno);                  const char* str=strerror(errno);
                 throw Exception(0,                  throw Exception("file.execute",
                         &file_spec,                          &file_spec,
                         "%s error: %s (%d)", pid<0?"fork":"pipe", str?str:"<unknown>", errno);                           "%s error: %s (%d)", pid<0?"fork":"pipe", str?str:"<unknown>", errno); 
         }          }

Removed from v.1.59  
changed lines
  Added in v.1.76


E-mail: