summaryrefslogtreecommitdiffstats
path: root/src/cmd/upas/common/process.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-10-29 16:26:44 +0000
committerrsc <devnull@localhost>2005-10-29 16:26:44 +0000
commit5cdb17983ae6e6367ad7a940cb219eab247a9304 (patch)
tree8ca1ef49af2a96e7daebe624d91fdf679814a057 /src/cmd/upas/common/process.c
parentcd3745196389579fb78b9b01ef1daefb5a57aa71 (diff)
downloadplan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.tar.gz
plan9port-5cdb17983ae6e6367ad7a940cb219eab247a9304.zip
Thanks to John Cummings.
Diffstat (limited to 'src/cmd/upas/common/process.c')
-rw-r--r--src/cmd/upas/common/process.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/cmd/upas/common/process.c b/src/cmd/upas/common/process.c
new file mode 100644
index 00000000..16b21aef
--- /dev/null
+++ b/src/cmd/upas/common/process.c
@@ -0,0 +1,175 @@
+#include "common.h"
+
+/* make a stream to a child process */
+extern stream *
+instream(void)
+{
+ stream *rv;
+ int pfd[2];
+
+ if ((rv = (stream *)malloc(sizeof(stream))) == 0)
+ return 0;
+ memset(rv, 0, sizeof(stream));
+ if (pipe(pfd) < 0)
+ return 0;
+ if(Binit(&rv->bb, pfd[1], OWRITE) < 0){
+ close(pfd[0]);
+ close(pfd[1]);
+ return 0;
+ }
+ rv->fp = &rv->bb;
+ rv->fd = pfd[0];
+ return rv;
+}
+
+/* make a stream from a child process */
+extern stream *
+outstream(void)
+{
+ stream *rv;
+ int pfd[2];
+
+ if ((rv = (stream *)malloc(sizeof(stream))) == 0)
+ return 0;
+ memset(rv, 0, sizeof(stream));
+ if (pipe(pfd) < 0)
+ return 0;
+ if (Binit(&rv->bb, pfd[0], OREAD) < 0){
+ close(pfd[0]);
+ close(pfd[1]);
+ return 0;
+ }
+ rv->fp = &rv->bb;
+ rv->fd = pfd[1];
+ return rv;
+}
+
+extern void
+stream_free(stream *sp)
+{
+ int fd;
+
+ close(sp->fd);
+ fd = Bfildes(sp->fp);
+ Bterm(sp->fp);
+ close(fd);
+ free((char *)sp);
+}
+
+/* start a new process */
+extern process *
+noshell_proc_start(char **av, stream *inp, stream *outp, stream *errp, int newpg, char *who)
+{
+ process *pp;
+ int i, n;
+
+ if ((pp = (process *)malloc(sizeof(process))) == 0) {
+ if (inp != 0)
+ stream_free(inp);
+ if (outp != 0)
+ stream_free(outp);
+ if (errp != 0)
+ stream_free(errp);
+ return 0;
+ }
+ pp->std[0] = inp;
+ pp->std[1] = outp;
+ pp->std[2] = errp;
+ switch (pp->pid = fork()) {
+ case -1:
+ proc_free(pp);
+ return 0;
+ case 0:
+ if(newpg)
+ sysdetach();
+ for (i=0; i<3; i++)
+ if (pp->std[i] != 0){
+ close(Bfildes(pp->std[i]->fp));
+ while(pp->std[i]->fd < 3)
+ pp->std[i]->fd = dup(pp->std[i]->fd, -1);
+ }
+ for (i=0; i<3; i++)
+ if (pp->std[i] != 0)
+ dup(pp->std[i]->fd, i);
+ for (n = sysfiles(); i < n; i++)
+ close(i);
+ if(who) {
+ fprint(2,"process.c: trying to become(%s,%s)\n",av,who);
+ // jpc become(av, who);
+ }
+ exec(av[0], av);
+ perror("proc_start");
+ exits("proc_start");
+ default:
+ for (i=0; i<3; i++)
+ if (pp->std[i] != 0) {
+ close(pp->std[i]->fd);
+ pp->std[i]->fd = -1;
+ }
+ return pp;
+ }
+}
+
+/* start a new process under a shell */
+extern process *
+proc_start(char *cmd, stream *inp, stream *outp, stream *errp, int newpg, char *who)
+{
+ char *av[4];
+
+ av[0] = unsharp(SHELL);
+ av[1] = "-c";
+ av[2] = cmd;
+ av[3] = 0;
+ return noshell_proc_start(av, inp, outp, errp, newpg, who);
+}
+
+/* wait for a process to stop */
+extern int
+proc_wait(process *pp)
+{
+ Waitmsg *status;
+ char err[Errlen];
+
+ for(;;){
+ status = wait();
+ if(status == nil){
+ errstr(err, sizeof(err));
+ if(strstr(err, "interrupt") == 0)
+ break;
+ }
+ if (status->pid==pp->pid)
+ break;
+ }
+ pp->pid = -1;
+ if(status == nil)
+ pp->status = -1;
+ else
+ pp->status = status->msg[0];
+ pp->waitmsg = status;
+ return pp->status;
+}
+
+/* free a process */
+extern int
+proc_free(process *pp)
+{
+ int i;
+
+ if(pp->std[1] == pp->std[2])
+ pp->std[2] = 0; /* avoid freeing it twice */
+ for (i = 0; i < 3; i++)
+ if (pp->std[i])
+ stream_free(pp->std[i]);
+ if (pp->pid >= 0)
+ proc_wait(pp);
+ free(pp->waitmsg);
+ free((char *)pp);
+ return 0;
+}
+
+/* kill a process */
+extern int
+proc_kill(process *pp)
+{
+ return syskill(pp->pid);
+}