popen.c 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. /*
  2. * Modified 3/03/2001 Manuel Novoa III
  3. *
  4. * Added check for legal mode arg.
  5. * Call fdopen and check return value before forking.
  6. * Reduced code size by using variables pr and pnr instead of array refs.
  7. */
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <sys/types.h>
  11. #include <sys/wait.h>
  12. #include <errno.h>
  13. /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
  14. #include <sys/syscall.h>
  15. #if ! defined __NR_vfork
  16. #define vfork fork
  17. #endif
  18. FILE *popen (const char *command, const char *mode)
  19. {
  20. FILE *fp;
  21. int pipe_fd[2];
  22. int pid, reading;
  23. int pr, pnr;
  24. reading = (mode[0] == 'r');
  25. if ((!reading && (mode[0] != 'w')) || mode[1]) {
  26. __set_errno(EINVAL); /* Invalid mode arg. */
  27. } else if (pipe(pipe_fd) == 0) {
  28. pr = pipe_fd[reading];
  29. pnr = pipe_fd[1-reading];
  30. if ((fp = fdopen(pnr, mode)) != NULL) {
  31. if ((pid = vfork()) == 0) { /* vfork -- child */
  32. close(pnr);
  33. if (pr != reading) {
  34. close(reading);
  35. dup2(pr, reading);
  36. close(pr);
  37. }
  38. execl("/bin/sh", "sh", "-c", command, (char *) 0);
  39. _exit(255); /* execl failed! */
  40. } else { /* vfork -- parent or failed */
  41. close(pr);
  42. if (pid > 0) { /* vfork -- parent */
  43. return fp;
  44. } else { /* vfork -- failed! */
  45. fclose(fp);
  46. }
  47. }
  48. } else { /* fdopen failed */
  49. close(pr);
  50. close(pnr);
  51. }
  52. }
  53. return NULL;
  54. }
  55. int pclose(FILE *fd)
  56. {
  57. int waitstat;
  58. if (fclose(fd) != 0) {
  59. return EOF;
  60. }
  61. if (wait(&waitstat) == -1)
  62. return -1;
  63. return waitstat;
  64. }