コード例 #1
0
ファイル: misc.c プロジェクト: BackupTheBerlios/bar-svn
Errors Misc_executeCommand(const char        *commandTemplate,
                           const TextMacro   macros[],
                           uint              macroCount,
                           ExecuteIOFunction stdoutExecuteIOFunction,
                           ExecuteIOFunction stderrExecuteIOFunction,
                           void              *executeIOUserData
                          )
{
  Errors          error;
  String          commandLine;
  StringTokenizer stringTokenizer;
  String          token;
  String          command;
  StringList      argumentList;
  const char      *path;
  String          fileName;
  bool            foundFlag;
  char const      **arguments;
  int             pipeStdin[2],pipeStdout[2],pipeStderr[2];
  int             pid;
  StringNode      *stringNode;
  uint            n,z;
  int             status;
  bool            sleepFlag;
  String          stdoutLine,stderrLine;
  int             exitcode;
  int             terminateSignal;

  error = ERROR_NONE;
  if (commandTemplate != NULL)
  {
    commandLine = String_new();
    command     = File_newFileName();
    StringList_init(&argumentList);

    // expand command line
    Misc_expandMacros(commandLine,commandTemplate,macros,macroCount);
    printInfo(3,"Execute command '%s'...",String_cString(commandLine));

    // parse command
    String_initTokenizer(&stringTokenizer,commandLine,STRING_BEGIN,STRING_WHITE_SPACES,STRING_QUOTES,FALSE);
    if (!String_getNextToken(&stringTokenizer,&token,NULL))
    {
      String_doneTokenizer(&stringTokenizer);
      StringList_done(&argumentList);
      String_delete(command);
      String_delete(commandLine);
      return ERRORX_(PARSE_COMMAND,0,String_cString(commandLine));
    }
    File_setFileName(command,token);

    // parse arguments
    while (String_getNextToken(&stringTokenizer,&token,NULL))
    {
      StringList_append(&argumentList,token);
    }
    String_doneTokenizer(&stringTokenizer);

    // find command in PATH
    path = getenv("PATH");
    if (path != NULL)
    {
      fileName  = File_newFileName();
      foundFlag = FALSE;
      String_initTokenizerCString(&stringTokenizer,path,":","",FALSE);
      while (String_getNextToken(&stringTokenizer,&token,NULL) && !foundFlag)
      {
        File_setFileName(fileName,token);
        File_appendFileName(fileName,command);
        if (File_exists(fileName))
        {
          File_setFileName(command,fileName);
          foundFlag = TRUE;
        }
      }
      String_doneTokenizer(&stringTokenizer);
      File_deleteFileName(fileName);
    }

#if 0
fprintf(stderr,"%s,%d: command %s\n",__FILE__,__LINE__,String_cString(command));
stringNode = argumentList.head;
while (stringNode != NULL)
{
fprintf(stderr,"%s,%d: argument %s\n",__FILE__,__LINE__,String_cString(stringNode->string));
stringNode = stringNode->next;
}
#endif /* 0 */

    #if defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID)
#if 1
      // create i/o pipes
      if (pipe(pipeStdin) != 0)
      {
        error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine));
        StringList_done(&argumentList);
        String_delete(command);
        String_delete(commandLine);
        return error;
      }
      if (pipe(pipeStdout) != 0)
      {
        error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine));
        close(pipeStdin[0]);
        close(pipeStdin[1]);
        StringList_done(&argumentList);
        String_delete(command);
        String_delete(commandLine);
        return error;
      }
      if (pipe(pipeStderr) != 0)
      {
        error = ERRORX_(IO_REDIRECT_FAIL,errno,String_cString(commandLine));
        close(pipeStdout[0]);
        close(pipeStdout[1]);
        close(pipeStdin[0]);
        close(pipeStdin[1]);
        StringList_done(&argumentList);
        String_delete(command);
        String_delete(commandLine);
        return error;
      }

      // do fork to start separated process
      pid = fork();
      if      (pid == 0)
      {
        // close stdin, stdout, and stderr and reassign them to the pipes
        close(STDERR_FILENO);
        close(STDOUT_FILENO);
        close(STDIN_FILENO);

        // redirect stdin/stdout/stderr to pipe
        dup2(pipeStdin[0],STDIN_FILENO);
        dup2(pipeStdout[1],STDOUT_FILENO);
        dup2(pipeStderr[1],STDERR_FILENO);

        /* close unused pipe handles (the pipes are duplicated by fork(), thus
           there are two open ends of the pipes)
        */
        close(pipeStderr[0]);
        close(pipeStdout[0]);
        close(pipeStdin[1]);

        // execute of external program
        n = 1+StringList_count(&argumentList)+1;
        arguments = (char const**)malloc(n*sizeof(char*));
        if (arguments == NULL)
        {
          HALT_INSUFFICIENT_MEMORY();
        }
        z = 0;
        arguments[z] = String_cString(command); z++;
        stringNode = argumentList.head;
        while (stringNode != NULL)
        {
          assert(z < n);
          arguments[z] = String_cString(stringNode->string); z++;
          stringNode = stringNode->next;
        }
        assert(z < n);
        arguments[z] = NULL; z++;
        execvp(String_cString(command),(char**)arguments);

        // in case exec() fail, return a default exitcode
        HALT_INTERNAL_ERROR("execvp() returned");
      }
      else if (pid < 0)
      {
        error = ERRORX_(EXEC_FAIL,errno,String_cString(commandLine));
        printInfo(3,"FAIL!\n");

        close(pipeStderr[0]);
        close(pipeStderr[1]);
        close(pipeStdout[0]);
        close(pipeStdout[1]);
        close(pipeStdin[0]);
        close(pipeStdin[1]);
        StringList_done(&argumentList);
        String_delete(command);
        String_delete(commandLine);
        return error;
      }

      // close unused pipe handles (the pipe is duplicated by fork(), thus there are two open ends of the pipe)
      close(pipeStderr[1]);
      close(pipeStdout[1]);
      close(pipeStdin[0]);
#else /* 0 */
error = ERROR_NONE;
#endif /* 0 */

      // wait until process terminate and read stdout/stderr
      stdoutLine = String_new();
      stderrLine = String_new();
      status = 0;
      while ((waitpid(pid,&status,WNOHANG) == 0) || (!WIFEXITED(status) && !WIFSIGNALED(status)))
      {
        sleepFlag = TRUE;

        if (readProcessIO(pipeStdout[0],stdoutLine))
        {
          if (stdoutExecuteIOFunction != NULL) stdoutExecuteIOFunction(executeIOUserData,stdoutLine);
          String_clear(stdoutLine);
          sleepFlag = FALSE;
        }
        if (readProcessIO(pipeStderr[0],stderrLine))
        {
          if (stderrExecuteIOFunction != NULL) stderrExecuteIOFunction(executeIOUserData,stderrLine);
          String_clear(stderrLine);
          sleepFlag = FALSE;
        }

        if (sleepFlag)
        {
          Misc_udelay(500LL*1000LL);
        }
      }
      while (readProcessIO(pipeStdout[0],stdoutLine))
      {
        if (stdoutExecuteIOFunction != NULL) stdoutExecuteIOFunction(executeIOUserData,stdoutLine);
        String_clear(stdoutLine);
      }
      while (readProcessIO(pipeStderr[0],stderrLine))
      {
        if (stderrExecuteIOFunction != NULL) stderrExecuteIOFunction(executeIOUserData,stderrLine);
        String_clear(stderrLine);
      }
      String_delete(stderrLine);
      String_delete(stdoutLine);

      // close i/o
      close(pipeStderr[0]);
      close(pipeStdout[0]);
      close(pipeStdin[1]);

      // check exit code
      exitcode = -1;
      if      (WIFEXITED(status))
      {
        exitcode = WEXITSTATUS(status);
        printInfo(3,"ok (exitcode %d)\n",exitcode);
        if (exitcode != 0)
        {
          error = ERRORX_(EXEC_FAIL,exitcode,String_cString(commandLine));
          StringList_done(&argumentList);
          String_delete(command);
          String_delete(commandLine);
          return error;
        }
      }
      else if (WIFSIGNALED(status))
      {
        terminateSignal = WTERMSIG(status);
        error = ERRORX_(EXEC_FAIL,terminateSignal,String_cString(commandLine));
        printInfo(3,"FAIL (signal %d)\n",terminateSignal);
        StringList_done(&argumentList);
        String_delete(command);
        String_delete(commandLine);
        return error;
      }
      else
      {
        printInfo(3,"ok (unknown exit)\n");
      }
    #elif defined(WIN32)
#if 0
HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
      HANDLE hInputWriteTmp,hInputRead,hInputWrite;
      HANDLE hErrorWrite;
      HANDLE hThread;
      DWORD ThreadId;
      SECURITY_ATTRIBUTES sa;


      // Set up the security attributes struct.
      sa.nLength= sizeof(SECURITY_ATTRIBUTES);
      sa.lpSecurityDescriptor = NULL;
      sa.bInheritHandle = TRUE;


      // Create the child output pipe.
      if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
         DisplayError("CreatePipe");


      // Create a duplicate of the output write handle for the std error
      // write handle. This is necessary in case the child application
      // closes one of its std output handles.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
                           GetCurrentProcess(),&hErrorWrite,0,
                           TRUE,DUPLICATE_SAME_ACCESS))
         DisplayError("DuplicateHandle");


      // Create the child input pipe.
      if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
         DisplayError("CreatePipe");


      // Create new output read handle and the input write handles. Set
      // the Properties to FALSE. Otherwise, the child inherits the
      // properties and, as a result, non-closeable handles to the pipes
      // are created.
      if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
                           GetCurrentProcess(),
                           &hOutputRead, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
         DisplayError("DupliateHandle");

      if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
                           GetCurrentProcess(),
                           &hInputWrite, // Address of new handle.
                           0,FALSE, // Make it uninheritable.
                           DUPLICATE_SAME_ACCESS))
      DisplayError("DupliateHandle");


      // Close inheritable copies of the handles you do not want to be
      // inherited.
      if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");


      // Get std input handle so you can close it and force the ReadFile to
      // fail when you want the input thread to exit.
      if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
                                                INVALID_HANDLE_VALUE )
         DisplayError("GetStdHandle");

      PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);


      // Close pipe handles (do not continue to modify the parent).
      // You need to make sure that no handles to the write end of the
      // output pipe are maintained in this process or else the pipe will
      // not close when the child process exits and the ReadFile will hang.
      if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
      if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");


      // Launch the thread that gets the input and sends it to the child.
      hThread = CreateThread(NULL,0,GetAndSendInputThread,
                              (LPVOID)hInputWrite,0,&ThreadId);
      if (hThread == NULL) DisplayError("CreateThread");


      // Read the child's output.
      ReadAndHandleOutput(hOutputRead);
      // Redirection is complete


      // Force the read on the input to return by closing the stdin handle.
      if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");


      // Tell the thread to exit and wait for thread to die.
      bRunThread = FALSE;

      if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
         DisplayError("WaitForSingleObject");

      if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
      if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
#endif
    #else /* not defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID) || WIN32 */
      #error pipe()/fork()/waitpid() not available nor Win32 system!
    #endif /* defined(HAVE_PIPE) && defined(HAVE_FORK) && defined(HAVE_WAITPID) || WIN32 */

    // free resources
    StringList_done(&argumentList);
    String_delete(command);
    String_delete(commandLine);
  }

  return error;
}
コード例 #2
0
void main ()
{
	HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
	HANDLE hInputWriteTmp,hInputRead,hInputWrite;
	HANDLE hErrorWrite;
	HANDLE hThread;
	DWORD ThreadId;
	SECURITY_ATTRIBUTES sa;


	// Set up the security attributes struct.
	sa.nLength= sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = TRUE;


	// Create the child output pipe.
	if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0))
		DisplayError("CreatePipe");


	// Create a duplicate of the output write handle for the std error
	// write handle. This is necessary in case the child application
	// closes one of its std output handles.
	if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
		GetCurrentProcess(),&hErrorWrite,0,
		TRUE,DUPLICATE_SAME_ACCESS))
		DisplayError("DuplicateHandle");


	// Create the child input pipe.
	if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0))
		DisplayError("CreatePipe");


	// Create new output read handle and the input write handles. Set
	// the Properties to FALSE. Otherwise, the child inherits the
	// properties and, as a result, non-closeable handles to the pipes
	// are created.
	if (!DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,
		GetCurrentProcess(),
		&hOutputRead, // Address of new handle.
		0,FALSE, // Make it uninheritable.
		DUPLICATE_SAME_ACCESS))
		DisplayError("DupliateHandle");

	if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,
		GetCurrentProcess(),
		&hInputWrite, // Address of new handle.
		0,FALSE, // Make it uninheritable.
		DUPLICATE_SAME_ACCESS))
		DisplayError("DupliateHandle");


	// Close inheritable copies of the handles you do not want to be
	// inherited.
	if (!CloseHandle(hOutputReadTmp)) DisplayError("CloseHandle");
	if (!CloseHandle(hInputWriteTmp)) DisplayError("CloseHandle");


	// Get std input handle so you can close it and force the ReadFile to
	// fail when you want the input thread to exit.
	if ( (hStdIn = GetStdHandle(STD_INPUT_HANDLE)) ==
		INVALID_HANDLE_VALUE )
		DisplayError("GetStdHandle");

	PrepAndLaunchRedirectedChild(hOutputWrite,hInputRead,hErrorWrite);


	// Close pipe handles (do not continue to modify the parent).
	// You need to make sure that no handles to the write end of the
	// output pipe are maintained in this process or else the pipe will
	// not close when the child process exits and the ReadFile will hang.
	if (!CloseHandle(hOutputWrite)) DisplayError("CloseHandle");
	if (!CloseHandle(hInputRead )) DisplayError("CloseHandle");
	if (!CloseHandle(hErrorWrite)) DisplayError("CloseHandle");


	// Launch the thread that gets the input and sends it to the child.
	hThread = CreateThread(NULL,0,GetAndSendInputThread,
		(LPVOID)hInputWrite,0,&ThreadId);
	if (hThread == NULL) DisplayError("CreateThread");


	// Read the child's output.
	ReadAndHandleOutput(hOutputRead);
	// Redirection is complete


	// Force the read on the input to return by closing the stdin handle.
	Sleep(5000);
	if (!CloseHandle(hStdIn)) DisplayError("CloseHandle");
	printf("closed hStdIn\n");


	// Tell the thread to exit and wait for thread to die.
	bRunThread = FALSE;

	if (WaitForSingleObject(hThread,INFINITE) == WAIT_FAILED)
		DisplayError("WaitForSingleObject");

	if (!CloseHandle(hOutputRead)) DisplayError("CloseHandle");
	if (!CloseHandle(hInputWrite)) DisplayError("CloseHandle");
}