Linux下使用system()函式一定要謹慎
阿新 • • 發佈:2019-02-10
曾經的曾經,被system()函式折磨過,之所以這樣,是因為對system()函數了解不夠深入。只是簡單的知道用這個函式執行一個系統命令,這遠遠不夠,它的返回值、它所執行命令的返回值以及命令執行失敗原因如何定位,這才是重點。當初因為這個函式風險較多,故拋棄不用,改用其他的方法。這裡先不說我用了什麼方法,這裡必須要搞懂system()函式,因為還是有很多人用了system()函式,有時你不得不面對它。
先來看一下system()函式的簡單介紹:
?
If the value of command is NULL, system() returns nonzero if the shell is available, and zero if not.
為了更好的理解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.
看一下system()函式的原始碼
看完這些,我想肯定有人對system()函式返回值還是不清楚,看原始碼最清楚,下面給出一個system()函式的實現:
仔細看完這個system()函式的簡單實現,那麼該函式的返回值就清晰了吧,那麼什麼時候system()函式返回0呢?只在command命令返回0時。 看一下該怎麼監控system()函式執行狀態 這裡給我出的做法:
1 2 |
#include
<stdlib.h>
int system ( const char *command);
|
system() executes a command specified in command by calling /bin/sh -c command,and
returns after the command has been completed.During execution of the command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored.
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”。