popen.c 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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 && defined __UCLIBC_HAS_MMU__
  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. close(reading);
  34. if (pr != 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. wait(&waitstat);
  62. return waitstat;
  63. }