【C/C++】Linux下使用system()函数一定要谨慎
先來看一下system()函數(shù)的簡單介紹: ?
| 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.
system()函數(shù)調(diào)用/bin/sh來執(zhí)行參數(shù)指定的命令,/bin/sh 一般是一個(gè)軟連接,指向某個(gè)具體的shell,比如bash,-c選項(xiàng)是告訴shell從字符串command中讀取命令; 在該command執(zhí)行期間,SIGCHLD是被阻塞的,好比在說:hi,內(nèi)核,這會(huì)不要給我送SIGCHLD信號,等我忙完再說; 在該command執(zhí)行期間,SIGINT和SIGQUIT是被忽略的,意思是進(jìn)程收到這兩個(gè)信號后沒有任何動(dòng)作。再來看一下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í)行過程,實(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é)束。 對于fork失敗,system()函數(shù)返回-1。 如果exec執(zhí)行成功,也即command順利執(zhí)行完畢,則返回command通過exit或return返回的值。 (注意,command順利執(zhí)行不代表執(zhí)行成功,比如command:"rm debuglog.txt",不管文件存不存在該command都順利執(zhí)行了) 如果exec執(zhí)行失敗,也即command沒有順利執(zhí)行,比如被信號中斷,或者command命令根本不存在,system()函數(shù)返回127. 如果command為NULL,則system()函數(shù)返回非0值,一般為1.
看一下system()函數(shù)的源碼 看完這些,我想肯定有人對system()函數(shù)返回值還是不清楚,看源碼最清楚,下面給出一個(gè)system()函數(shù)的實(shí)現(xiàn): ?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | 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執(zhí)行失敗返回127,注意exec只在失敗時(shí)才返回現(xiàn)在的進(jìn)程,成功的話現(xiàn)在的進(jìn)程就不存在啦~~ } else //父進(jìn)程 { ????while(waitpid(pid, &status, 0) < 0) ????{ ????????if(errno != EINTR) ????????{ ????????????status = -1; //如果waitpid被信號中斷,則返回-1 ????????????break; ????????} ????} } ????return status; //如果waitpid成功,則返回子進(jìn)程的返回狀態(tài) } |
仔細(xì)看完這個(gè)system()函數(shù)的簡單實(shí)現(xiàn),那么該函數(shù)的返回值就清晰了吧,那么什么時(shí)候system()函數(shù)返回0呢?只在command命令返回0時(shí)。
看一下該怎么監(jiān)控system()函數(shù)執(zhí)行狀態(tài) 這里給我出的做法: ?
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | int status; if(NULL == cmdstring) //如果cmdstring為空趁早閃退吧,盡管system()函數(shù)也能處理空指針 { ????return XXX; } status = system(cmdstring); if(status < 0) { ????printf("cmd: %s\t error: %s", cmdstring, strerror(errno)); // 這里務(wù)必要把errno信息輸出或記入Log ????return XXX; } if(WIFEXITED(status)) { ????printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); //取得cmdstring執(zhí)行結(jié)果 } 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被信號暫停執(zhí)行,取得信號值 } |
到于取得子進(jìn)程返回值的相關(guān)介紹可以參考另一篇文章:http://my.oschina.net/renhc/blog/35116
?
system()函數(shù)用起來很容易出錯(cuò),返回值太多,而且返回值很容易跟command的返回值混淆。這里推薦使用popen()函數(shù)替代,關(guān)于popen()函數(shù)的簡單使用也可以通過上面的鏈接查看。
popen()函數(shù)較于system()函數(shù)的優(yōu)勢在于使用簡單,popen()函數(shù)只返回兩個(gè)值:
成功返回子進(jìn)程的status,使用WIFEXITED相關(guān)宏就可以取得command的返回結(jié)果;
失敗返回-1,我們可以使用perro()函數(shù)或strerror()函數(shù)得到有用的錯(cuò)誤信息。
這篇文章只涉及了system()函數(shù)的簡單使用,還沒有談及SIGCHLD、SIGINT和SIGQUIT對system()函數(shù)的影響,事實(shí)上,之所以今天寫這篇文章,是因?yàn)轫?xiàng)目中因有人使用了system()函數(shù)而造成了很嚴(yán)重的事故。現(xiàn)像是system()函數(shù)執(zhí)行時(shí)會(huì)產(chǎn)生一個(gè)錯(cuò)誤:“No child processes”。
關(guān)于這個(gè)錯(cuò)誤的分析,感興趣的朋友可以看一下:http://my.oschina.net/renhc/blog/54582
?
2012-04-14 qdurenhongcai@163.com
轉(zhuǎn)載請注明出處。
總結(jié)
以上是生活随笔為你收集整理的【C/C++】Linux下使用system()函数一定要谨慎的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LINUX任务(jobs)详解
- 下一篇: linux系统编程之进程(七):syst