關於linux下system()函式的總結

大雄45發表於2023-02-27
導讀 曾經的曾經,被system()函式折磨過,之所以這樣,是因為對system()函式了解不夠深入。這裡必須要搞懂system()函式,因為有時你不得不面對它。

關於linux下system()函式的總結關於linux下system()函式的總結

先來看一下system()函式的簡單介紹:
#include
int system(const char *command)

system()函式呼叫/bin/sh來執行引數指定的 ,/bin/sh 一般是一個軟連線,指向某個具體的 ,比如bash,-c選項是告訴shell從字串command中讀取 ; 在該command執行期間,SIGCHLD是被阻塞的,好比在說:hi,核心,這會不要給我送SIGCHLD訊號,等我忙完再說; 在該command執行期間,SIGINT和SIGQUIT是被忽略的,意思是程式收到這兩個訊號後沒有任何動作。

再來看一下system()函式返回值:

為了更好的理解system()函式返回值,需要了解其執行過程,實際上system()函式執行了三步操作:

  1. fork一個子程式;
  2. 在子程式中呼叫exec函式去執行command;
  3. 在父程式中呼叫wait去等待子程式結束。 對於fork失敗,system()函式返回-1。 如果exec執行成功,也即command順利執行完畢,則返回command透過exit或return返回的值。 (注意,command順利執行不代表執行成功,比如command:"rm debuglog.txt",不管檔案存不存在該command都順利執行了) 如果exec執行失敗,也即command沒有順利執行,比如被訊號中斷,或者command命令根本不存在,system()函式返回127. 如果command為NULL,則system()函式返回非0值,一般為1.

關於linux下system()函式的總結關於linux下system()函式的總結

看一下system()函式的原始碼

看完這些,我想肯定有人對system()函式返回值還是不清楚,看原始碼最清楚,下面給出一個system()函式的實現:

int system(const char * cmdstring)
{
    pid_t pid;
    int status;
    if(cmdstring == NULL)
    {
        return (1); //如果cmdstring為空,返回非零值,一般為1
    }
    if((pid = fork())<0)
    {
        status = -1; //fork失敗,返回-1
    }
    else if(pid == 0)
    {
        execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
        _exit(127); // exec執行失敗返回127,注意exec只在失敗時才返回現在的程式,成功的話現在的
        程式就不存在啦~~
    }
    else //父程式
    {
        while(waitpid(pid, &status, 0) < 0)
        {
            if(errno != EINTR)
            {
                status = -1; //如果waitpid被訊號中斷,則返回-1
                break;
            }
        }
    }
    return status; //如果waitpid成功,則返回子程式的返回狀態
}

仔細看完這個system()函式的簡單實現,那麼該函式的返回值就清晰了吧,那麼什麼時候system()函式返回0呢?只在command命令返回0時。

看一下該怎麼監控system()函式執行狀態 這裡給我出的做法:
int status;
if(NULL == cmdstring) //如果cmdstring為空趁早閃退吧,儘管system()函式也能處理空指標
{
    return XXX;
}
status = system(cmdstring);
if(status < 0)
{
    printf("cmd: %s\t error: %s", cmdstring, strerror(errno)); // 這裡務必要把errno資訊輸出或
    記入Log
    return XXX;
}
if(WIFEXITED(status))
{
    printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); //取得cmdstring執行結果 }
    else if(WIFSIGNALED(status))
{
    printf("abnormal termination,signal number =%d\n", WTERMSIG(status)); //如果cmdstring被訊號中
    斷,取得訊號值
}
else if(WIFSTOPPED(status))
{
    printf("process stopped, signal number =%d\n", WSTOPSIG(status)); //如果cmdstring被訊號暫停執
    行,取得訊號值
}

system()函式用起來很容易出錯,返回值太多,而且返回值很容易跟command的返回值混淆。這裡推薦使用popen()函式替代,關於popen()函式的簡單使用可以自己查下資料。

popen()函式較於system()函式的優勢在於使用簡單,popen()函式只返回兩個值: 成功返回子程式的status,使用WIFEXITED相關宏就可以取得command的返回結果; 失敗返回-1,我們可以使用perro()函式或strerror()函式得到有用的錯誤資訊。

這篇文章只涉及了system()函式的簡單使用,還沒有談及SIGCHLD、SIGINT和SIGQUIT對system()函式的影響,事實上,之所以今天寫這篇文章,是因為專案中因有人使用了system()函式而造成了很嚴重的事故。現像是system()函式執行時會產生一個錯誤:“No child processes”。此時呼叫my_system()來執行system函式的功能(my_system函式中是使用popen()函式來實現的), 測試了一天,沒有再次出現程式突然死掉的問題(修改前連續迴圈呼叫system()函式測試,每10次就會至少導致程式掛掉一次.連續不停頓的呼叫)。

原文來自:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2930903/,如需轉載,請註明出處,否則將追究法律責任。

相關文章