github.com/afumu/libc@v0.0.6/musl/src/stdio/popen.c (about)

     1  #include <fcntl.h>
     2  #include <unistd.h>
     3  #include <errno.h>
     4  #include <string.h>
     5  #include <spawn.h>
     6  #include "stdio_impl.h"
     7  #include "syscall.h"
     8  
     9  extern char **__environ;
    10  
    11  FILE *popen(const char *cmd, const char *mode)
    12  {
    13  	int p[2], op, e;
    14  	pid_t pid;
    15  	FILE *f;
    16  	posix_spawn_file_actions_t fa;
    17  
    18  	if (*mode == 'r') {
    19  		op = 0;
    20  	} else if (*mode == 'w') {
    21  		op = 1;
    22  	} else {
    23  		errno = EINVAL;
    24  		return 0;
    25  	}
    26  	
    27  	if (pipe2(p, O_CLOEXEC)) return NULL;
    28  	f = fdopen(p[op], mode);
    29  	if (!f) {
    30  		__syscall(SYS_close, p[0]);
    31  		__syscall(SYS_close, p[1]);
    32  		return NULL;
    33  	}
    34  	FLOCK(f);
    35  
    36  	/* If the child's end of the pipe happens to already be on the final
    37  	 * fd number to which it will be assigned (either 0 or 1), it must
    38  	 * be moved to a different fd. Otherwise, there is no safe way to
    39  	 * remove the close-on-exec flag in the child without also creating
    40  	 * a file descriptor leak race condition in the parent. */
    41  	if (p[1-op] == 1-op) {
    42  		int tmp = fcntl(1-op, F_DUPFD_CLOEXEC, 0);
    43  		if (tmp < 0) {
    44  			e = errno;
    45  			goto fail;
    46  		}
    47  		__syscall(SYS_close, p[1-op]);
    48  		p[1-op] = tmp;
    49  	}
    50  
    51  	e = ENOMEM;
    52  	if (!posix_spawn_file_actions_init(&fa)) {
    53  		if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) {
    54  			if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0,
    55  			    (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ))) {
    56  				posix_spawn_file_actions_destroy(&fa);
    57  				f->pipe_pid = pid;
    58  				if (!strchr(mode, 'e'))
    59  					fcntl(p[op], F_SETFD, 0);
    60  				__syscall(SYS_close, p[1-op]);
    61  				FUNLOCK(f);
    62  				return f;
    63  			}
    64  		}
    65  		posix_spawn_file_actions_destroy(&fa);
    66  	}
    67  fail:
    68  	fclose(f);
    69  	__syscall(SYS_close, p[1-op]);
    70  
    71  	errno = e;
    72  	return 0;
    73  }