Linux에서 process 생성하기 (fork/exec)

Linux에서 process를 생성하기 위해서는 fork를 실행한후 exec 함수군을 사용하면 됩니다.
제가 한동안 Windows 개발자라 Windows convention에 맞게 만든 CreateProcess를 공유합니다.
물론, Linux에서 사용되는 함수입니다.
  1. // ...은 argument list (char*)  
  2. bool CreateProcess(IN LPCSTR lpszCmdFullPath, IN bool bWait, OPTIONAL OUT int* pnExitCode, IN int nCountArg, ...)  
  3. {  
  4.     bool    bRtnValue           = false;  
  5.     int     nStatVal            = 0;  
  6.     pid_t   nPid                = -1;  
  7.     va_list arg                 = 0;  
  8.     LPCSTR  lpszArgList[256]    = {0,};  
  9.     int     nArgNum             = 0;  
  10.   
  11.     if (NULL != pnExitCode)  
  12.     {  
  13.         *pnExitCode = -1;  
  14.     }  
  15.   
  16.     if (nCountArg >= 256)  
  17.     {  
  18.         ERRORLOG("Too many argument");  
  19.         bRtnValue = false;  
  20.         goto FINAL;  
  21.     }  
  22.   
  23.     if (-1 == access(lpszCmdFullPath, X_OK))  
  24.     {  
  25.         // 명령을 실행할 수 없음  
  26.         bRtnValue = false;  
  27.         ERRORLOG("Error to access(%s), errno=%d", lpszCmdFullPath, errno);  
  28.         goto FINAL;  
  29.     }  
  30.   
  31.     INFOLOG("before call fork");  
  32.     nPid = fork();  
  33.     if (-1 == nPid)  
  34.     {  
  35.         ERRORLOG("Fail to fork, errno=%d", errno);  
  36.         bRtnValue = false;  
  37.         goto FINAL;  
  38.     }  
  39.     else if (nPid == 0)  
  40.     {  
  41.         // child  
  42.         INFOLOG("in fork child, before exec %s", lpszCmdFullPath);  
  43.   
  44.         // 첫번째 파라미터는 경로  
  45.         lpszArgList[0] = lpszCmdFullPath;  
  46.         nArgNum = 1;  
  47.   
  48.         va_start(arg, nCountArg);  
  49.         {  
  50.             for (;;)  
  51.             {  
  52.                 if (nArgNum >= nCountArg+1)  
  53.                 {  
  54.                     break;  
  55.                 }  
  56.   
  57.                 lpszArgList[nArgNum] = va_arg(arg, char*);  
  58.                 if (NULL == lpszArgList[nArgNum])  
  59.                 {  
  60.                     break;  
  61.                 }  
  62.                 INFOLOG("\tParameter : %s", lpszArgList[nArgNum]);  
  63.                 nArgNum++;  
  64.             }  
  65.         }  
  66.         va_end(arg);  
  67.   
  68.         if (-1 == execvp(lpszCmdFullPath, (charconst*)lpszArgList))  
  69.         {  
  70.             ERRORLOG("Fail to execl, errno=%d", errno);  
  71.             if (errno != 0)  
  72.             {  
  73.                 _exit(errno);  
  74.             }  
  75.         }  
  76.   
  77.         _exit(255);  
  78.     }  
  79.     else  
  80.     {  
  81.         INFOLOG("parent");  
  82.         if (true == bWait)  
  83.         {  
  84.             INFOLOG("Start to wait");  
  85.             if (-1 == wait(&nStatVal))  
  86.             {  
  87.                 ERRORLOG("Fail to wait, errno=%d", errno);  
  88.                 goto FINAL;  
  89.             }  
  90.             INFOLOG("Finished to wait");  
  91.             if (NULL != pnExitCode)  
  92.             {  
  93.                 if (true == WIFEXITED(nStatVal))  
  94.                 {  
  95.                     // 정상 종료 했음  
  96.                     *pnExitCode = WEXITSTATUS(nStatVal);  
  97.                 }  
  98.             }  
  99.         }  
  100.     }  
  101.   
  102.     bRtnValue = true;  
  103.   
  104. FINAL:  
  105.     return bRtnValue;  
  106. }  

와 같습니다.

각 argument는 다음과 같습니다.
  • lpszCmdFullPath
    ; 명령의 Full path. argument가 없다. 예) /bin/ls
  • bWait
    ; 종료까지 기다릴지 여부
  • nCountArg
    ; 가변인자(...)의 개수
  • pnExitCode
    ; 프로세스의 Exit Code. 종료시까지 기다리고 제대로 종료되었을 때 의미있음
  • ...
    ; 프로세스에 전달될 Argument. 여러개 가능. 예) -la
  • 리턴값
    ; 성공시 : true / 실패시 : false
ERRORLOG와 INFOLOG는 직접 사용하는 에러 출력 함수로 연결하시면 됩니다.
필요없는 경우는 지우셔도 됩니다.

그리고, 필요한 경우 다음 define이 필요합니다.
  1. // char type  
  2. typedef const charLPCSTR;  
  3. typedef char*       LPSTR;  
  4. #define IN  
  5. #define OUT  
  6. #define OPTIONAL  
  7. #define COUNTOF(array) (sizeof(array)/sizeof(array[0]))  

사용법은 다음과 같습니다.
  1. int nExitCode = 0;  
  2. if (true == CreateProcess("/bin/mount",   
  3.                           true,   
  4.                           &nExitCode,   
  5.                           2,   
  6.                           "/dev/sda1""/mnt/sda1_mnt"))  
  7. {  
  8.     // 실행 성공  
  9.     if (0 == nExitCode)  
  10.     {  
  11.         // 성공  
  12.     }  
  13.     else  
  14.     {  
  15.         // 실패  
  16.         // man mount의 마지막 RETURN CODE 참고  
  17.     }  
  18. }  
  19. else  
  20. {  
  21.     // 실행 실패  
  22. }  

위는, /dev/sda1 장치를 mount하는 예를 나타낸 것입니다.