popen.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:3k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <signal.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <sys/types.h>
  9. #include <sys/wait.h>
  10. static pid_t *pids = NULL;
  11. static int pids_size = 0;
  12. static int pids_top = 0;
  13. static pthread_mutex_t pids_lock = PTHREAD_MUTEX_INITIALIZER;
  14. FILE *popen(const char *cmd, const char *mode)
  15. {
  16.     int fds[2], parent_fd, child_fd, child_target, new_size, i;
  17.     pid_t pid, *new_pids;
  18.     /* Verify the mode. */
  19.     if ((*mode != 'r' && *mode != 'w') || mode[1] != 0)
  20.     return NULL;
  21.     /* Generate fds, and choose the parent and child fds. */
  22.     if (pipe(fds) < 0)
  23.     return NULL;
  24.     parent_fd = (*mode == 'r') ? fds[0] : fds[1];
  25.     child_fd = (*mode == 'r') ? fds[1] : fds[0];
  26.     /* Ensure that there is space in the pid table. */
  27.     pthread_mutex_lock(&pids_lock);
  28.     if (pids_size <= parent_fd) {
  29.     new_size = parent_fd + 1;
  30.     if ((new_pids = malloc(new_size * sizeof(pid_t))) == NULL) {
  31.      pthread_mutex_unlock(&pids_lock);
  32.         close(parent_fd);
  33.         close(child_fd);
  34.         return NULL;
  35.     }
  36. if (pids) {
  37. memcpy(new_pids, pids, pids_size * sizeof(pid_t));
  38.         free(pids);
  39. }
  40. while (pids_size < new_size)
  41.      new_pids[pids_size++] = -1;
  42. pids = new_pids;
  43.     }
  44.     pthread_mutex_unlock(&pids_lock);
  45.     /* Fork off a child process. */
  46. switch (pid = fork()) {
  47. case -1: /* Failed to fork. */
  48. close(parent_fd);
  49. close(child_fd);
  50. return NULL;
  51. break;
  52. case 0: /* Child */
  53. /*
  54.  * Set the child fd to stdout or stdin as appropriate,
  55.    * and close the parent fd. 
  56.  */
  57. child_target = (*mode == 'r') ? STDOUT_FILENO : STDIN_FILENO;
  58. if (child_fd != child_target) {
  59.      dup2(child_fd, child_target);
  60.      close(child_fd);
  61. }
  62. close(parent_fd);
  63. /* Close all parent fds from previous popens(). */
  64. for (i = 0; i < pids_top; i++) {
  65.     if (pids[i] != -1)
  66. close(i);
  67. }
  68. execl("/bin/sh", "sh", "-c", cmd, NULL);
  69. exit(1);
  70. default:
  71. break;
  72. }
  73.     /* Record the parent fd in the pids table. */
  74.     pthread_mutex_lock(&pids_lock);
  75.     pids[parent_fd] = pid;
  76.     if (pids_top < parent_fd + 1)
  77.     pids_top = parent_fd + 1;
  78.     pthread_mutex_unlock(&pids_lock);
  79.     /* Close the child fd and return a stdio buffer for the parent fd. */
  80.     close(child_fd);
  81.     return fdopen(parent_fd, mode);
  82. }
  83. int pclose(fp)
  84.     FILE *fp;
  85. {
  86.     pid_t pid, result;
  87.     int fd, pstat;
  88.     fd = fileno(fp);
  89.     pthread_mutex_lock(&pids_lock);
  90.     /* Make sure this is a popened file. */
  91.     if ((pids_top <= fd) || ((pid = pids[fd]) == -1)) {
  92.      pthread_mutex_unlock(&pids_lock);
  93. return -1;
  94. }
  95.     pids[fd] = -1;
  96.     while (pids_top > 0 && pids[pids_top - 1] == -1)
  97.     pids_top--;
  98.     pthread_mutex_unlock(&pids_lock);
  99.     fclose(fp);
  100.     /* Wait for the subprocess to quit. */
  101. return (((result = waitpid(pid, &pstat, 0)) == -1) ? -1 : pstat);
  102. }