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