<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/fst/popen.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/fst/popen.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
/*
* popen, pclose - open and close pipes (Plan 9 version)
*/

#include &lt;u.h&gt;
#include &lt;libc.h&gt;

enum { Stdin, Stdout, };
enum {
       Rd,
       Wr,
       Maxfd = 200,
};

typedef struct {
       long    pid;
       char    *sts;
       char    stsset;         /* flag: sts is valid */
} Pipe;

static Pipe pipes[Maxfd];

static int
_pipefd(int rfd, int wfd)
{
       close(wfd);
       return rfd;
}

int
popen(char *file, char *mode)
{
       int pipedes[2];
       long pid;

       if (pipe(pipedes) &lt; 0)               /* cat's got the last pipe */
               return -1;
       if ((pid = fork()) &lt; 0) {    /* can't fork */
               close(pipedes[Rd]);
               close(pipedes[Wr]);
               return -1;
       }
       /*
        * The pipe was created and the fork succeeded.
        * Now fiddle the file descriptors in both processes.
        */
       if (pid == 0) {                 /* child process */
               int sts;

               /*
                * If the mode is 'r', the child writes on stdout so the
                * parent can read on its stdin from the child.
                * If the mode is not 'r', the child reads on stdin so the
                * parent can write on its stdout to the child.
                */
               if (mode[0] == 'r')             /* read from child */
                       sts = dup(pipedes[Wr], Stdout);
               else                            /* write to child */
                       sts = dup(pipedes[Rd], Stdin);
               if (sts &lt; 0)                 /* couldn't fiddle fd's */
                       _exits("no pipe");
               close(pipedes[Rd]);
               close(pipedes[Wr]);
               execl("/bin/rc", "rc", "-c", file, (char *)nil);
               _exits("no /bin/rc");           /* no shell */
               /* NOTREACHED */
               return -1;
       } else {                        /* parent process */
               int fd;

               /*
                * If the mode is 'r', the parent reads on its stdin the child;
                * otherwise the parent writes on its stdout to the child.
                */
               if (mode[0] == 'r')     /* read from child */
                       fd = _pipefd(pipedes[Rd], pipedes[Wr]);
               else
                       fd = _pipefd(pipedes[Wr], pipedes[Rd]);
               if (fd &gt;= 0 &amp;&amp; fd &lt; Maxfd) {
                       Pipe *pp = pipes + fd;

                       pp-&gt;pid = pid;               /* save fd's child's pid */
                       free(pp-&gt;sts);
                       pp-&gt;sts = nil;
                       pp-&gt;stsset = 0;
               }
               return fd;
       }
}

static volatile int waiting;

static int
gotnote(void *, char *note)
{
       if (strcmp(note, "interrupt") == 0)
               if (waiting)
                       return 1;       /* NCONT */
       return 0;                       /* not a known note: NDFLT */
}

char *
pclose(int fd)
{
       int pid;                /* pid, wait status for some child */
       Pipe *fpp, *app = nil, *spp;
       static int registered;

       if (fd &lt; 0 || fd &gt;= Maxfd)
               return "fd out of range";
       fpp = pipes + fd;
       if (fpp-&gt;pid &lt;= 0)
               return "no child process for fd";
       /*
        * Ignore notes in case this process was catching them.
        * Otherwise both this process and its child(ren) would
        * catch these notes.
        * Ideally I suppose popen should ignore the notes.
        */
       if (!registered) {
               atnotify(gotnote, 1);
               registered = 1;
       }
       waiting = 1;
       /*
        * Wait for fd's child to die.
        */
       close(fd);
       while (!fpp-&gt;stsset) {
               Waitmsg *wm = wait();

               if (wm == nil)
                       break;          /* ``can't happen'' */
               pid = wm-&gt;pid;
               /*
                * ``Bring out your dead!''
                * See if any fd is attached to this corpse;
                * if so, give that fd its wait status.
                */
               if (pid == fpp-&gt;pid) /* quick check */
                       app = fpp;
               else
                       for (spp = pipes; spp &lt; pipes + Maxfd; spp++)
                               if (pid == app-&gt;pid) {
                                       app = spp;
                                       break;
                               }
               if (app != nil) {
                       /* record pid's status, possibly for later use */
                       free(app-&gt;sts);
                       app-&gt;sts = strdup(wm-&gt;msg);
                       app-&gt;stsset = 1;
               }
       }
       waiting = 0;
       return fpp-&gt;stsset? fpp-&gt;sts: "no open pipe";
}
/* Written by [email protected] for Rangboom - fst 11/11/07 */
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>