inux 下system函数原型:
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函数的返回值比较多,且存在相同的值却代表着不同的意思,针对以上问题对源码进行分析。
Libc-2.9 下sysdeps\posi\system.c源码:
int system (const char *line)
{
return __libc_system (line);
}
int __libc_system (const char *line) /*system函数实际上调用的是do_system函数*/
{
if (line == NULL)
/* Check that we have a command processor available. It might
?not be available after a chroot(), for example. */
return do_system ("exit 0") == 0; /* 当line为NULL时,返回值为0,及执行bash –c exit 0*/
if (SINGLE_THREAD_P)
return do_system (line);/*GCC cleanup exception range can cover the
LIBC_CANCEL_ASYNC() and LIBC_CANCEL_RESET():http://sourceware.org/ml/libc-alpha/2011-08/msg00063.html */
int oldtype = LIBC_CANCEL_ASYNC ();
int result = do_system (line);
LIBC_CANCEL_RESET (oldtype);
return result;
}
weak_alias (__libc_system, system) /* weak_alias 别名 */
/*通过以上分析system函数实际上调用的是do_system函数, 以下对do_system函数进行分析,以下列出主要函数:*/
/* Execute LINE as a shell command, returning its status. */
do_system (const char *line)
{
int status, save;
pid_t pid;
struct sigaction sa;
#ifndef _LIBC_REENTRANT
struct sigaction intr, quit;
#endif
sigset_t omask;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
__sigemptyset (&sa.sa_mask);
DO_LOCK (); /* mutex lock*/
if (ADD_REF () == 0)
{
if (__sigaction (SIGINT, &sa, &intr) < 0) /*执行时 SIGINT被忽略*/ { SUB_REF (); goto out; } if (__sigaction (SIGQUIT, &sa, &quit) < 0) /*执行时 SIGQUIT被忽略*/ { save = errno; SUB_REF (); goto out_restore_sigint; } } DO_UNLOCK (); /* We reuse the bitmap in the 'sa' structure. */ __sigaddset (&sa.sa_mask, SIGCHLD); save = errno; if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) /*执行时设置SIG_BLOCK标志位,SIGCHLD被阻塞,执行失败,则恢复之前的信号的bitmap*/ { #ifndef _LIBC if (errno == ENOSYS) __set_errno (save); else #endif { DO_LOCK (); if (SUB_REF () == 0) { save = errno; (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); out_restore_sigint: (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); __set_errno (save); } out: DO_UNLOCK (); return -1; } } #ifdef CLEANUP_HANDLER CLEANUP_HANDLER; #endif /*执行成功,调用fork,生成子进程执行command命令*/ #ifdef FORK pid = FORK (); /*调用SYS_CALL生成子进程*/ #else pid = __fork (); #endif if (pid == (pid_t) 0) // { /* Child side. */ const char *new_argv[4]; new_argv[0] = SHELL_NAME; new_argv[1] = "-c"; new_argv[2] = line; new_argv[3] = NULL; /* Restore the signals. */ (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); INIT_LOCK (); /* Exec the shell. */ (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); _exit (127); /*exec执行失败则返回127*/ } else if (pid < (pid_t) 0) /* The fork failed. */ status = -1; else /*父进程,waitpid*/ /* Parent side. */ { /* Note the system() is a cancellation point. But since we call waitpid() which itself is a cancellation point we do not have to do anything here. */ if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) status = -1; /*waitpid 失败返回1*/ } #ifdef CLEANUP_HANDLER CLEANUP_RESET; #endif save = errno; DO_LOCK (); if ((SUB_REF () == 0 && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) { #ifndef _LIBC /* glibc cannot be used on systems without waitpid. */ if (errno == ENOSYS) __set_errno (save); else #endif status = -1; } DO_UNLOCK (); return status; } 总结:system函数的返回值:分2大类: (1) 当参数为空时,调用do_system ("exit 0"),返回值为NULL /*网上都说是返回非0值,但我测的是NULL !!!!*/ (2) 调用result = do_system (line); 当执行忽略SIGINT和SIGQUIT信号时,错误返回-1 fork子进程时出现错误 返回值为-1 当exec执行错误或命令无效时返回值为127 当waitpid错误时 返回值为-1 if(NULL == cmdstring) //如果cmdstring为空趁早闪退吧,尽管system()函数也能处理空指针 以下可以得到返回值错在什么位置,相关知识详见APUE(摘录的具体位置忘了,作者看到后请留言) 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被信号暂停执行,取得信号值 }