linux c redirect 重定向

linux c redirect 重定向

用execvp实现时,运行adb,如果adb 服务没有启动,会启动adb服务,启动adb服务时,pipe返回的管道在读的时候堵塞了。

查看了popen的源码,发现popen是用sh -c来执行的,避免了这个问题

不知道sh -c做了些什么操作,使得popen可以避免这个问题

代码如下:

 1 #ifndef __RG_REDIRECT_H
 2 #define __RG_REDIRECT_H
 3 
 4 
 5 //#ifdef _LINUX        //for linux version
 6 
 7 #include <string>
 8 
 9 #ifdef _LINUX
10 #include <signal.h>
11 #endif
12 
13 #define WAIT_FOREVER 0
14 
15 typedef void (*pReDirectCallBack)(const char* strOutput, bool bOver);
16 
17 class CRGReDirect
18 {
19 public:
20     CRGReDirect();
21     ~CRGReDirect();
22 
23 public:
24     //同步方式运行ADB命令,会阻塞。命令结果保存在strResult里面返回
25     //strCmd是需要执行的ADB命令。例如:adb_path devices
26     int RunCmdSync(std::string& strResult, const std::string& strCmd);
27     int RunCmdSync(std::string& strResult, const char *szCmd);
28 
29 
30     //nTimeOut单位是秒
31     int RunCmdWithTimeOut(std::string& strResult, const std::string& strCmd, int nTimeOut = WAIT_FOREVER);
32     int RunCmdWithTimeOut(std::string& strResult, const char *szCmd, int nTimeOut = WAIT_FOREVER);
33 
34     //异步方式执行ADB命令,不会阻塞,直接返回线程的pid(失败返回-1)
35     //strCmd是需要执行的ADB命令。例如:adb_path devices
36     //ADB运行完成之后主动条用CallBack函数pFunc
37     //成功返回非零,失败返回-1
38     int RunCmdAsync(pReDirectCallBack pFunc, const std::string&strCmd);
39     int RunCmdAsync(pReDirectCallBack pFunc, const char *szCmd);
40 //    const char*    GetCmdResultString(void) const { return m_strResult.c_str(); }
41 
42 protected:
43     int RunCmd(pReDirectCallBack pFunc = NULL);
44 
45     void CancelCommand();
46 
47 #ifdef _WIN32
48     HANDLE            m_hTimer;
49     HANDLE            m_hTimerQueue;
50     HANDLE            m_hChildProcess;
51 
52     HANDLE            m_hCmdThread;
53     static DWORD WINAPI RunProcess(void *arg);
54     static VOID CALLBACK HandleTimeOut( PVOID lpParameter, BOOLEAN TimerOrWaitFired);
55 #else
56     int SetTimer(int nSeconds, int nTimerID);
57     int KillTimer(timer_t nTimerID);
58 
59     timer_t                m_timer_id;
60     pthread_t            m_thread_id;
61     static void*        RunProcess(void* arg);
62     static void            HandleTimeOut(sigval_t v);
63 
64     pid_t                *m_childpid;    /* ptr to array allocated at run-time */
65     int                    m_maxfd;    /* from our open_max(), {Prog openmax} */
66     FILE*                m_hChildProcess;
67 
68     int open_max(void);
69     FILE * rgpopen(const char *cmdstring, const char *type);    //模拟popen实现的版本
70     int rgpkill(FILE* fp);                                        //根据文件指针关掉相应的进程
71     int rgpclose(FILE *fp);                                        //关闭文件指针
72 #endif
73 
74 private:
75     std::string            m_strResult;
76     std::string            m_strCmd;
77     pReDirectCallBack    m_adbCB;
78     volatile bool        m_bAbort;
79 };
80 
81 //#endif
82 
83 #endif
#ifndef _WIN32
    #include <unistd.h>
    #include <signal.h>    
    #include <time.h>    
    #include <pthread.h>    // Compile and link with -pthread.
    #include <cstring>
    #include <cstdlib>
    #include <sys/wait.h>
    #include <sys/time.h>
    #include <sys/resource.h>
    #include <errno.h>
#else
#include <Windows.h>
#endif

#include "RGReDirect.h"
#include <cassert>
#include <cstdio>

#define RG_TIMER_ID    51

std::string Trim(const std::string& strIn)
{
  std::string strMatch = " ";
  size_t i = strIn.find_first_not_of(strMatch);
  size_t j = strIn.find_last_not_of(strMatch);


  if (i != std::string::npos)
    return strIn.substr(i, j-i+1);


  return "";
}


CRGReDirect::CRGReDirect()
: m_adbCB(NULL)
#ifdef _WIN32
, m_hChildProcess(NULL)
, m_hCmdThread(NULL)
, m_hTimer(NULL)
, m_hTimerQueue(NULL)
#else
, m_thread_id(0)
, m_timer_id(0)
, m_childpid(NULL)
, m_maxfd(0)
, m_hChildProcess(NULL)
#endif
, m_bAbort(false)
{
}

CRGReDirect::~CRGReDirect()
{
#ifdef _WIN32
    if (m_hCmdThread)
    {
        WaitForSingleObject(m_hCmdThread, INFINITE);
        CloseHandle(m_hCmdThread);
    }
    if (m_hTimer) DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, NULL);
    if (m_hTimerQueue) DeleteTimerQueue(m_hTimerQueue);
    
#else
    if (m_thread_id) pthread_join(m_thread_id, NULL);
    if(m_timer_id) timer_delete(m_timer_id);
    if(m_childpid) free(m_childpid);
#endif
}

int CRGReDirect::RunCmd(pReDirectCallBack pFunc /* = NULL */)
{
    m_bAbort = false;
    m_strResult.clear();

#ifdef _WIN32
    std::string strTmpCmd = m_strCmd;    
    HANDLE hChildStdoutRd, hChildStdoutWr, hStdout;
    SECURITY_ATTRIBUTES saAttr; 

    // Set the bInheritHandle flag so pipe handles are inherited. 
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr.bInheritHandle = TRUE; 
    saAttr.lpSecurityDescriptor = NULL; 

    // Get the handle to the current STDOUT. 
    hStdout = GetStdHandle(STD_OUTPUT_HANDLE); 

    // Create a pipe for the child process's STDOUT. 
    if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 
        return -1; 

    // Ensure the read handle to the pipe for STDOUT is not inherited.
    SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);

    char *szCmdline = new char[strTmpCmd.size() + 1];
    memset(szCmdline, 0, strTmpCmd.size() + 1);
    strcpy(szCmdline, strTmpCmd.c_str());

    PROCESS_INFORMATION piProcInfo; 
    STARTUPINFO siStartInfo;

    // Set up members of the PROCESS_INFORMATION structure. 
    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

    // Set up members of the STARTUPINFO structure. 
    ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
    siStartInfo.cb = sizeof(STARTUPINFO); 
    siStartInfo.hStdError = hChildStdoutWr;
    siStartInfo.hStdOutput = hChildStdoutWr;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

    // Create the child process. 
    BOOL bFuncRetn = CreateProcess(NULL, 
        szCmdline,     // command line 
        NULL,          // process security attributes 
        NULL,          // primary thread security attributes 
        TRUE,          // handles are inherited 
        CREATE_NO_WINDOW,             // creation flags 
        NULL,          // use parent's environment 
        NULL,          // use parent's current directory 
        &siStartInfo,  // STARTUPINFO pointer 
        &piProcInfo);  // receives PROCESS_INFORMATION 

    if (bFuncRetn == 0) 
    {
        delete [] szCmdline;
        return -1;
    }
    else 
    {
        m_hChildProcess = piProcInfo.hProcess;
        CloseHandle(piProcInfo.hThread);

        const int BUFSIZE = 4096;
        DWORD dwRead; 
        char chBuf[BUFSIZE] = {0}; 

        // Close the write end of the pipe before reading from the 
        // read end of the pipe. 
        if (!CloseHandle(hChildStdoutWr))
        {
            delete [] szCmdline;
            return -1;
        }

        // Read output from the child process
        while (m_bAbort == false) 
        { 
            if( !ReadFile( hChildStdoutRd, chBuf, BUFSIZE, &dwRead, 
                NULL) || dwRead == 0) break; 
            chBuf[dwRead] = '