inux 下system函数原型:
#include
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源码:
#include
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被信号暂停执行,取得信号值
- }
本文详细解析了 Linux 下 system 函数的源码实现,包括其内部调用流程、信号处理、命令执行过程及其返回值的多种情况。
728

被折叠的 条评论
为什么被折叠?



