popen.c raw

   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  
  35  	e = ENOMEM;
  36  	if (!posix_spawn_file_actions_init(&fa)) {
  37  		for (FILE *l = *__ofl_lock(); l; l=l->next)
  38  			if (l->pipe_pid && posix_spawn_file_actions_addclose(&fa, l->fd))
  39  				goto fail;
  40  		if (!posix_spawn_file_actions_adddup2(&fa, p[1-op], 1-op)) {
  41  			if (!(e = posix_spawn(&pid, "/bin/sh", &fa, 0,
  42  			    (char *[]){ "sh", "-c", (char *)cmd, 0 }, __environ))) {
  43  				posix_spawn_file_actions_destroy(&fa);
  44  				f->pipe_pid = pid;
  45  				if (!strchr(mode, 'e'))
  46  					fcntl(p[op], F_SETFD, 0);
  47  				__syscall(SYS_close, p[1-op]);
  48  				__ofl_unlock();
  49  				return f;
  50  			}
  51  		}
  52  fail:
  53  		__ofl_unlock();
  54  		posix_spawn_file_actions_destroy(&fa);
  55  	}
  56  	fclose(f);
  57  	__syscall(SYS_close, p[1-op]);
  58  
  59  	errno = e;
  60  	return 0;
  61  }
  62