Chinaunix首页 | 论坛 | 博客
  • 博客访问: 66353
  • 博文数量: 9
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 77
  • 用 户 组: 普通用户
  • 注册时间: 2013-09-20 20:21
文章分类
文章存档

2015年(1)

2014年(1)

2013年(7)

分类: LINUX

2013-12-02 22:51:22

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源码:

点击(此处)折叠或打开

  1. int system (const char *line)
  2. {
  3.     return __libc_system (line);
  4. }
  5. int __libc_system (const char *line) /*system函数实际上调用的是do_system函数*/
  6. {
  7.     if (line == NULL)
  8.         /* Check that we have a command processor available. It might
  9.            ?not be available after a chroot(), for example. */
  10.         return do_system ("exit 0") == 0; /* 当line为NULL时,返回值为0,及执行bash –c exit 0*/
  11.     if (SINGLE_THREAD_P)
  12.         return do_system (line);

  13.     /*GCC cleanup exception range can cover the

  14.       LIBC_CANCEL_ASYNC() and LIBC_CANCEL_RESET():http://sourceware.org/ml/libc-alpha/2011-08/msg00063.html */

  15.     int oldtype = LIBC_CANCEL_ASYNC ();
  16.     int result = do_system (line);
  17.     LIBC_CANCEL_RESET (oldtype);
  18.     return result;
  19. }
  20. weak_alias (__libc_system, system) /* weak_alias 别名 */
  21.     /*通过以上分析system函数实际上调用的是do_system函数, 以下对do_system函数进行分析,以下列出主要函数:*/
  22.     /* Execute LINE as a shell command, returning its status. */
  23. do_system (const char *line)
  24. {
  25.     int status, save;
  26.     pid_t pid;
  27.     struct sigaction sa;
  28. #ifndef _LIBC_REENTRANT
  29.     struct sigaction intr, quit;
  30. #endif
  31.     sigset_t omask;
  32.     sa.sa_handler = SIG_IGN;
  33.     sa.sa_flags = 0;
  34.     __sigemptyset (&sa.sa_mask);
  35.     DO_LOCK (); /* mutex lock*/
  36.     if (ADD_REF () == 0)
  37.     {
  38.         if (__sigaction (SIGINT, &sa, &intr) < 0) /*执行时 SIGINT被忽略*/
  39.         {
  40.             SUB_REF ();
  41.             goto out;
  42.         }
  43.         if (__sigaction (SIGQUIT, &sa, &quit) < 0) /*执行时 SIGQUIT被忽略*/
  44.         {
  45.             save = errno;
  46.             SUB_REF ();
  47.             goto out_restore_sigint;
  48.         }
  49.     }
  50.     DO_UNLOCK ();
  51.     /* We reuse the bitmap in the 'sa' structure. */
  52.     __sigaddset (&sa.sa_mask, SIGCHLD);
  53.     save = errno;
  54.     if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) /*执行时设置SIG_BLOCK标志位,SIGCHLD被阻塞,执行失败,则恢复之前的信号的bitmap*/
  55.     {
  56. #ifndef _LIBC
  57.         if (errno == ENOSYS)
  58.             __set_errno (save);
  59.         else
  60. #endif
  61.         {
  62.             DO_LOCK ();
  63.             if (SUB_REF () == 0)
  64.             {
  65.                 save = errno;
  66.                 (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
  67. out_restore_sigint:
  68.                 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
  69.                 __set_errno (save);
  70.             }
  71. out:
  72.             DO_UNLOCK ();
  73.             return -1;
  74.         }
  75.     }
  76. #ifdef CLEANUP_HANDLER
  77.     CLEANUP_HANDLER;
  78. #endif
  79.     /*执行成功,调用fork,生成子进程执行command命令*/
  80. #ifdef FORK
  81.     pid = FORK (); /*调用SYS_CALL生成子进程*/
  82. #else
  83.     pid = __fork ();
  84. #endif
  85.     if (pid == (pid_t) 0) //
  86.     {
  87.         /* Child side. */
  88.         const char *new_argv[4];
  89.         new_argv[0] = SHELL_NAME;
  90.         new_argv[1] = "-c";
  91.         new_argv[2] = line;
  92.         new_argv[3] = NULL;
  93.         /* Restore the signals. */
  94.         (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
  95.         (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
  96.         (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
  97.         INIT_LOCK ();

  98.         /* Exec the shell. */
  99.         (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
  100.         _exit (127); /*exec执行失败则返回127*/
  101.     }
  102.     else if (pid < (pid_t) 0)
  103.         /* The fork failed. */
  104.         status = -1;
  105.     else /*父进程,waitpid*/
  106.         /* Parent side. */
  107.     {
  108.         /* Note the system() is a cancellation point. But since we call
  109.            waitpid() which itself is a cancellation point we do not
  110.            have to do anything here. */
  111.         if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
  112.             status = -1; /*waitpid 失败返回1*/
  113.     }
  114. #ifdef CLEANUP_HANDLER
  115.     CLEANUP_RESET;
  116. #endif
  117.     save = errno;
  118.     DO_LOCK ();
  119.     if ((SUB_REF () == 0
  120.                 && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
  121.                     | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
  122.             || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
  123.     {
  124. #ifndef _LIBC
  125.         /* glibc cannot be used on systems without waitpid. */
  126.         if (errno == ENOSYS)
  127.             __set_errno (save);
  128.         else
  129. #endif
  130.             status = -1;
  131.     }
  132.     DO_UNLOCK ();
  133.     return status;
  134. }

  135. 总结:system函数的返回值:分2大类:
  136. (1) 当参数为空时,调用do_system ("exit 0"),返回值为NULL /*网上都说是返回非0值,但我测的是NULL !!!!*/
  137. (2) 调用result = do_system (line)
  138. 当执行忽略SIGINT和SIGQUIT信号时,错误返回-1
  139. fork子进程时出现错误 返回值为-1
  140. 当exec执行错误或命令无效时返回值为127
  141. 当waitpid错误时 返回值为-1
  142. if(NULL == cmdstring) //如果cmdstring为空趁早闪退吧,尽管system()函数也能处理空指针
  143.     以下可以得到返回值错在什么位置,相关知识详见APUE(摘录的具体位置忘了,作者看到后请留言)
  144. if(NULL == cmdstring) //如果cmdstring为空趁早闪退吧,尽管system()函数也能处理空指针
  145. {
  146.     return XXX;
  147. }
  148. status = system(cmdstring);
  149. if(status < 0)
  150. {
  151.     printf("cmd: %s\t error: %s", cmdstring, strerror(errno)); // 这里务必要把errno信息输出或记入Log
  152.     return XXX;
  153. }

  154. if(WIFEXITED(status))
  155. {
  156.     printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); //取得cmdstring执行结果
  157. }
  158. else if(WIFSIGNALED(status))
  159. {
  160.     printf("abnormal termination,signal number =%d\n", WTERMSIG(status)); //如果cmdstring被信号中断,取得信号值
  161. }
  162. else if(WIFSTOPPED(status))
  163. {
  164.     printf("process stopped, signal number =%d\n", WSTOPSIG(status)); //如果cmdstring被信号暂停执行,取得信号值
  165. }


有不对之处,还请大家指正。
阅读(8811) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~