2012-12-04 57 views
5

現在我正在編寫一個必須執行子進程的C程序。我不是在同時進行多個子進程或任何事情,所以這相當簡單。我確實成功地執行了內置的shell程序(即cat和echo之類的東西),但是我也需要能夠判斷這些程序中的一個何時無法成功執行。我用下面的簡化的代碼嘗試這樣的:execvp/fork - 如何捕獲不成功的執行?

int returnStatus; // The return status of the child process. 
pid_t pid = fork(); 

if (pid == -1) // error with forking. 
{ 
    // Not really important for this question. 
} 
else if (pid == 0) // We're in the child process. 
{ 
    execvp(programName, programNameAndCommandsArray); // vars declared above fork(). 

    // If this code executes the execution has failed. 
    exit(127); // This exit code was taken from a exec tutorial -- why 127? 
} 
else // We're in the parent process. 
{ 
    wait(&returnStatus); // Wait for the child process to exit. 

    if (returnStatus == -1) // The child process execution failed. 
    { 
     // Log an error of execution. 
    } 
} 

因此,舉例來說,如果我嘗試執行RM fileThatDoesntExist.txt,我想考慮的是,由於文件中的失敗並不存在。我怎樣才能做到這一點?另外,當execvp()調用成功執行內置shell程序時,它不會執行可執行文件當前目錄中的程序(即該代碼在其中運行的程序)。爲了讓它在當前目錄中運行程序,還有其他事情需要做嗎?

謝謝!

+0

[如何在fork()之後處理execvp(...)錯誤?](https:// stackoverflow。com/questions/1584956/how-to-handle-execvp-errors-after-fork) – Ruslan

回答

13

這是一個非常優雅的解決方案的經典問題。在分岔之前,在父項中創建一個pipe。在fork之後,父級應關閉管道的寫入端,並從讀取結束嘗試到read。孩子應該關閉閱讀結束,並使用fcntl設置關閉執行標誌,以便寫入結束。

現在,如果孩子叫execvp成功,該管的書寫端將沒有數據關閉,read父將返回0。如果execvp在孩子失敗,錯誤代碼寫入到管道,並且父代中的read將返回非零值,並讀取父代處理的錯誤代碼。

+0

感謝您的評論,它肯定讓我走上了正軌。我經過一番研究後意識到,我只關心捕獲子進程的stderr輸出。我想我會檢查stderr是否爲空,並且足以確定哪個執行存在問題。但是,我很難將此想法轉化爲代碼。它會涉及調用dup()嗎? –

0

在故障檢測方面,如果一個exec()函數用新的進程替換當前進程,那麼當前進程就不存在了;執行的程序是否決定要求做的事情是成功還是失敗並不重要。但是,fork之前的父進程可以發現可能具有命令成功/失敗信息的子進程代碼。

在查找可執行文件方面,execvp()複製shell的操作,搜索當前路徑。如果它在工作目錄中找不到可執行文件,則目錄可能不在搜索路徑中(或文件實際上不可執行)。您可以嘗試通過完整路徑名指定它們。

如果你只是想運行一個命令並等待結果,你可能需要使用system()函數來處理這個問題,而不是用fork/exec自己構建它。

+0

良好的信息,但是它不足以區分'execvp'失敗和外部程序以非零退出狀態退出。 –

+0

@R - 如果使用execvp(),子進程繼續運行原始程序的唯一方式是,如果execvp失敗,那麼您可以通知父進程。如果使用system(),可能需要進行一些調查才能找出如何區分故障。 –

+0

通知父母是棘手的部分。我的答案解決了如何做到這一點。 –

3

wait(2)爲您提供的不僅僅是子進程的退出狀態。爲了獲得真正的退出狀態,您需要使用WIFEXITED()宏測試孩子是否正常退出(而不是通過信號異常等),然後使用宏獲取真實退出狀態:

wait(&status); 
if(WIFEXITED(status)) 
{ 
    if(WEXITSTATUS(status) == 0) 
    { 
     // Program succeeded 
    } 
    else 
    { 
     // Program failed but exited normally 
    } 
} 
else 
{ 
    // Program exited abnormally 
} 

爲了execvp(3)在當前目錄下運行程序時,您可能需要將當前目錄添加到您的$PATH環境(通常不是一個好主意),或者通過它的完整路徑,如請使用./myprogram而不是myprogram

+2

這些信息都是正確的,但它不能告訴你execvp是否成功。 –