make popen cancellation-safe
[musl] / src / stdio / popen.c
1 #include "stdio_impl.h"
2 #include "syscall.h"
3
4 static inline void nc_close(int fd)
5 {
6         __syscall(SYS_close, fd);
7 }
8 #define close(x) nc_close(x)
9
10 FILE *popen(const char *cmd, const char *mode)
11 {
12         int p[2];
13         int op;
14         pid_t pid;
15         FILE *f;
16         const char *modes = "rw", *mi = strchr(modes, *mode);
17
18         if (mi) {
19                 op = mi-modes;
20         } else {
21                 errno = EINVAL;
22                 return 0;
23         }
24         
25         if (pipe(p)) return NULL;
26         f = fdopen(p[op], mode);
27         if (!f) {
28                 close(p[0]);
29                 close(p[1]);
30                 return NULL;
31         }
32         
33         pid = fork();
34         switch (pid) {
35         case -1:
36                 fclose(f);
37                 close(p[0]);
38                 close(p[1]);
39                 return NULL;
40         case 0:
41                 if (dup2(p[1-op], 1-op) < 0) _exit(127);
42                 if (p[0] != 1-op) close(p[0]);
43                 if (p[1] != 1-op) close(p[1]);
44                 execl("/bin/sh", "sh", "-c", cmd, (char *)0);
45                 _exit(127);
46         }
47         close(p[1-op]);
48         f->pipe_pid = pid;
49         return f;
50 }