曾經(jīng)的曾經(jīng),,被system()函數(shù)折磨過(guò),,之所以這樣,是因?yàn)閷?duì)system()函數(shù)了解不夠深入,。只是簡(jiǎn)單的知道用這個(gè)函數(shù)執(zhí)行一個(gè)系統(tǒng)命令,,這遠(yuǎn)遠(yuǎn)不夠,它的返回值,、它所執(zhí)行命令的返回值以及命令執(zhí)行失敗原因如何定位,,這才是重點(diǎn)。當(dāng)初因?yàn)檫@個(gè)函數(shù)風(fēng)險(xiǎn)較多,,故拋棄不用,,改用其他的方法。這里先不說(shuō)我用了什么方法,,這里必須要搞懂system()函數(shù),,因?yàn)檫€是有很多人用了system()函數(shù),有時(shí)你不得不面對(duì)它,。
先來(lái)看一下system()函數(shù)的簡(jiǎn)單介紹:
2 |
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.
system()函數(shù)調(diào)用/bin/sh來(lái)執(zhí)行參數(shù)指定的命令,,/bin/sh 一般是一個(gè)軟連接,指向某個(gè)具體的shell,,比如bash,,-c選項(xiàng)是告訴shell從字符串command中讀取命令;
在該command執(zhí)行期間,,SIGCHLD是被阻塞的,,好比在說(shuō):hi,內(nèi)核,,這會(huì)不要給我送SIGCHLD信號(hào),,等我忙完再說(shuō);
在該command執(zhí)行期間,,SIGINT和SIGQUIT是被忽略的,,意思是進(jìn)程收到這兩個(gè)信號(hào)后沒(méi)有任何動(dòng)作,。
再來(lái)看一下system()函數(shù)返回值:
The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise. This latter return status is in the format specified in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127).
If the value of command is NULL, system() returns nonzero if the shell is available, and zero if not.
為了更好的理解system()函數(shù)返回值,需要了解其執(zhí)行過(guò)程,,實(shí)際上system()函數(shù)執(zhí)行了三步操作:
1.fork一個(gè)子進(jìn)程,;
2.在子進(jìn)程中調(diào)用exec函數(shù)去執(zhí)行command;
3.在父進(jìn)程中調(diào)用wait去等待子進(jìn)程結(jié)束,。
對(duì)于fork失敗,,system()函數(shù)返回-1。
如果exec執(zhí)行成功,,也即command順利執(zhí)行完畢,,則返回command通過(guò)exit或return返回的值。
(注意,,command順利執(zhí)行不代表執(zhí)行成功,,比如command:"rm debuglog.txt",不管文件存不存在該command都順利執(zhí)行了)
如果exec執(zhí)行失敗,,也即command沒(méi)有順利執(zhí)行,,比如被信號(hào)中斷,或者command命令根本不存在,,system()函數(shù)返回127.
如果command為NULL,,則system()函數(shù)返回非0值,一般為1.
看一下system()函數(shù)的源碼
看完這些,,我想肯定有人對(duì)system()函數(shù)返回值還是不清楚,,看源碼最清楚,下面給出一個(gè)system()函數(shù)的實(shí)現(xiàn):
01 |
int system ( const char * cmdstring) |
17 |
execl( "/bin/sh" , "sh" , "-c" , cmdstring, ( char *)0); |
22 |
while (waitpid(pid, &status, 0) < 0) |
仔細(xì)看完這個(gè)system()函數(shù)的簡(jiǎn)單實(shí)現(xiàn),那么該函數(shù)的返回值就清晰了吧,,那么什么時(shí)候system()函數(shù)返回0呢,?只在command命令返回0時(shí),。
看一下該怎么監(jiān)控system()函數(shù)執(zhí)行狀態(tài)
這里給我出的做法:
06 |
status = system (cmdstring); |
09 |
printf ( "cmd: %s\t error: %s" , cmdstring, strerror ( errno )); |
15 |
printf ( "normal termination, exit status = %d\n" , WEXITSTATUS(status)); |
17 |
else if (WIFSIGNALED(status)) |
19 |
printf ( "abnormal termination,signal number =%d\n" , WTERMSIG(status)); |
21 |
else if (WIFSTOPPED(status)) |
23 |
printf ( "process stopped, signal number =%d\n" , WSTOPSIG(status)); |
到于取得子進(jìn)程返回值的相關(guān)介紹可以參考另一篇文章:http://my.oschina.net/renhc/blog/35116
system()函數(shù)用起來(lái)很容易出錯(cuò),,返回值太多,,而且返回值很容易跟command的返回值混淆。這里推薦使用popen()函數(shù)替代,,關(guān)于popen()函數(shù)的簡(jiǎn)單使用也可以通過(guò)上面的鏈接查看,。
popen()函數(shù)較于system()函數(shù)的優(yōu)勢(shì)在于使用簡(jiǎn)單,popen()函數(shù)只返回兩個(gè)值: 成功返回子進(jìn)程的status,,使用WIFEXITED相關(guān)宏就可以取得command的返回結(jié)果,; 失敗返回-1,我們可以使用perro()函數(shù)或strerror()函數(shù)得到有用的錯(cuò)誤信息,。
這篇文章只涉及了system()函數(shù)的簡(jiǎn)單使用,,還沒(méi)有談及SIGCHLD、SIGINT和SIGQUIT對(duì)system()函數(shù)的影響,,事實(shí)上,之所以今天寫(xiě)這篇文章,,是因?yàn)轫?xiàng)目中因有人使用了system()函數(shù)而造成了很嚴(yán)重的事故?,F(xiàn)像是system()函數(shù)執(zhí)行時(shí)會(huì)產(chǎn)生一個(gè)錯(cuò)誤:“No child processes”。
關(guān)于這個(gè)錯(cuò)誤的分析,,將會(huì)專門(mén)寫(xiě)一篇文章分析,。
2012-04-14 任洪彩 [email protected]
|