/* * fpopen.c --- unlike the libc popen, it directly executes the * command instead of call out to the shell. */ #include #include #include #include #include #include #define MAX_ARGV 256 extern FILE *fpopen(const char *cmd, const char *mode); FILE *fpopen(const char *cmd, const char *mode) { char *argv[MAX_ARGV]; int i = 0; char *buf, *prog = 0; char *p; int do_stdin; int fds[2]; pid_t pid; if (!mode) { errno = EFAULT; return NULL; } switch (*mode) { case 'r': do_stdin = 0; break; case 'w': do_stdin = 1; break; default: errno = EINVAL; return NULL; } /* * Create the argv vector.... */ buf = malloc(strlen(cmd)+1); if (!buf) return NULL; strcpy(buf, cmd); p = buf; while (p && *p) { if (isspace(*p)) { p++; continue; } if (i == 0) prog = p; argv[i++] = p; p = strchr(p, ' '); if (p) *p++ = 0; } argv[i] = 0; /* * Get the pipe */ if (pipe(fds) < 0) return NULL; /* Fork and execute the correct program. */ if ((pid = fork()) < 0) { perror("fork"); return NULL; } else if (pid == 0) { if (do_stdin) { close(fds[1]); dup2(fds[0], 0); } else { close(fds[0]); dup2(fds[1], 1); } (void) execvp(prog, argv); perror(prog); exit(1); } return fdopen(do_stdin ? fds[1] : fds[0], mode); }