/* popen(): open a file handle to a process. Works only under MiNT. * Written by Eric R. Smith, based on the TOS version by Kai-Uwe Bloem. */ #include #include #include #include #include #include #include __EXTERN int wait __PROTO((int *)); struct _pipe { int pid; /* process id of child */ FILE *pfile; /* created file descriptor */ struct _pipe *pnext; /* next pipe in the list. */ }; static struct _pipe *__pipes = NULL; /* head of pipe list */ FILE *popen(command, type) const char *command, *type; { struct _pipe *p; /* the new pipe's list entry */ int pipfd[2]; /* pipe file handles */ int savefd; /* saved file descriptor for parent */ int kidfd; /* file descriptor changed in child */ /* 1 for "r", 0 for "w" */ char *shell; FILE *pipefile = 0; extern int __mint; if (__mint == 0) { errno = EINVAL; return (FILE *)0; } shell = getenv("SHELL"); if (!shell) shell = "sh"; /* get space for the new pipe. If we can't get it then that's that */ p = (struct _pipe *) malloc(sizeof(struct _pipe)); if (p == NULL) return (FILE *)0; /* initialize the new pipe entry */ kidfd = (*type == 'r') ? 1 : 0; savefd = dup(kidfd); if (savefd < 0 || pipe(pipfd) != 0) { /* can't create pipe?? */ free(p); return (FILE *)0; } dup2(pipfd[kidfd], kidfd); close(pipfd[kidfd]); p->pid = spawnlp(P_NOWAIT, shell, shell, "-c", command, (char *)0); dup2(savefd, kidfd); close(savefd); if (p->pid > 0) { /* command ran all right */ /* note: 1-kidfd tells us which handle to use in the parent */ pipefile = fdopen(pipfd[1 - kidfd], type); } if (pipefile) { p->pfile = pipefile; p->pnext = __pipes; __pipes = p; } else { free(p); } return pipefile; } /* close a pipe created by popen(). */ int pclose(fp) FILE *fp; { struct _pipe *p, /* the pipe's list element */ *q; /* predecessor of p in the list */ int status = -1; /* return status of the command */ int pid; /* search the pipe list for a pipe matching the FILE descriptor */ for (p = __pipes, q = NULL; p && p->pfile != fp; q = p, p = p->pnext); if (p == NULL) /* Never had a popen() for this file... */ return status; /* this pclose call makes no sense ! */ fclose(p->pfile); /* close the connection */ /* now wait for the command to finish */ do { pid = wait(&status); } while (pid >= 0 && pid != p->pid); /* remove the pipe from the list */ if (q) /* not the first in the list, unlink it from previous pipe */ q->pnext = p->pnext; else /* first in the list, set new list head */ __pipes = __pipes->pnext; /* Now free the pipe entry */ free(p); return status; }