<interface name="sho"
	short="Execute programs from a shell in a pseudo terminal programmatically.">

<comments>
Copyright 2003 Michael B. Allen &lt;mba2000 ioplex.com&gt;
</comments>

<include>mba/shellout.h</include>

<title>Shellout</title>
<desc>
The <def>shellout</def>(3m) module provides a robust interface to a UNIX shell such as sh or bash. Spawned programs may be controlled interactively from a terminal (i.e. "shell out") or entirely in the background (i.e. cron, network daemon, etc). For most purposes this functionality is identical to that of the popular <ident>expect</ident>(1) program.
<p/>
<example id="shello">
<title>hello, world</title>
<desc>
To use the <def>shellout</def>(3m) module effectively there are a few important rules that must be followed. One, is that the <tt>sho_close</tt> function calls <def>wait</def>(2) and will not return until the process spawned within the shell exits. If the child program is well behaved this can be achived by sending "exit $?\n" however doing so will not trigger the shell to exit if it is not ready to receive input. In this case it may be necessary to write a "\x03" which is the special Ctrl-C character. If the process does not respond to that <tt>kill</tt>(2) can be used to send a <tt>SIGKILL</tt> to the shell however even though this garunteed to get shell control back take care that it does not leave a zombie process lingering in the background.
<p/>
The below code is a minimal "hello, world" example that opens a new /bin/sh shell with <tt>sho_open</tt> and writes the command "echo hello, world\n" to it. Note the '\n' character is as important as it is equivalent to pressing the 'Enter' key. Then it calls <tt>sho_expect</tt> which will wait for the command prompt 'sh&gt; ' to come back. The command prompt is defined by the <tt>ps1</tt> parameter to <tt>sho_open</tt> so the caller will know what it is and that it is uniqe to the expected output.
<pre>
struct sho *sh;
const char *cmd = "echo hello, world\n";
const char *pv[] = { "sh&gt; " };
char buf[256];
int i;

sh = sho_open("sh", pv[0], 0);
writen(sh-&gt;ptym, cmd, strlen(cmd));

i = sho_expect(sh, pv, 1, buf, 256, 10);

if (i == 1) { 
    fprintf(stderr, "success: %s\n", buf);
} else if (i == -1) {
    perror("timeout");
} else if (i == 0) { 
    fputs("EOF\n", stderr);
}

/* output */

success: hello, world
sh&gt;
</pre>
In this example the caller knows when the command has completed when the command prompt is returned. Keep in mind that it is usually a better stategy to wait for the command prompt and then interpret the output in the buffer so that unexpected output doesn't result in a timeout. Provided the logic is equipted to handle the unexcepted output it might be perfectly reasonable to call <tt>sho_expect</tt> with other strings in the pattern vector. For example, to get a list of mounted filesystems the <def>mount</def>(8) command might be used with no arguments. If the pattern vector were change to: <tt>const char *pv[] = { "sh&gt; ", "\n" };</tt> for example the <tt>sho_expect</tt> function would return with each line in the buffer which assists in parsing the values in each mount entry.
</desc>
</example>
The <def>shellout</def>(3m) module is not available in the Win32 environment.
</desc>

<group>
<title>Shellout functions</title>

<code>
<title>The <ident>struct sho</ident> structure</title>
<pre>
SHO_FLAGS_INTERACT
SHO_FLAGS_ISATTY

struct sho {
	char ps1[32];
	int flags;
	pid_t pid;
	int ptym;
	struct termios t0;
};
</pre>
<desc>
</desc>
</code>

<meth name="open">
	<pre>struct sho *sho_open(const char *sh, const char *ps1, int flags);</pre>
	<param name="sh"/>
	<param name="ps1"/>
	<param name="flags"/>
	<desc>
The <ident>sho_open</ident> function uses <def>forkpty</def>(3) and <def>execvp</def>(3) to execute a UNIX shell in a pseudo terminial. The <tt>struct sho *</tt> object returned may be used with <tt>sho_expect</tt>, <tt>writen</tt>, etc to interact with the shell. Writing characters to the <tt>sh-&gt;ptym</tt> (PTY master) descriptor will be read by the shell as if they had been typed at a terminal. A <tt>struct sho *</tt> must be closed with <tt>sho_close</tt>.
	</desc>
	<ret>
The <ident>sho_open</ident> function returns the new shell instance or NULL if an error occured in which case errno will be set appropriately.
	</ret>
</meth>

<meth name="close">
	<pre>int sho_close(struct sho *sh);</pre>
	<param name="sh"/>
	<desc>
The <ident>sho_close</ident> function calls <tt>wait</tt>(2) to wait for the shell process to exit. The shell will not exit until it is instructed to. This can be occomplished by writing "exit $?\n" or if the program spawned within the shell is taking too long, a Ctrl-C may be written by sending "\x03\n". Or, as a last resort, <tt>SIGKILL</tt> may be sent to <tt>sh-&gt;pid</tt> with <tt>kill</tt>(2).
	</desc>
	<ret>
The <ident>sho_close</ident> function returns the exit status of the shell. However, normally it is desireable to return the exit status of the last program to run within that shell. In this case the special shell variable "$?" which evaluates to the exit status of the last program to run may passed to the exit command such as "exit $?\n".
	</ret>
</meth>

<meth name="expect">
	<pre>int sho_expect(struct sho *sh, const char *pv[], int pn, char *dst, size_t dn, int timeout);</pre>
	<param name="sh"/>
	<param name="pv"/>
	<param name="pn"/>
	<param name="dst"/>
	<param name="timeout"/>
	<desc>
The <ident>sho_expect</ident> function accepts a "pattern vector" of <tt>pn</tt> strings to match and reads characters from the shell represented by <tt>sh</tt> copying each into <tt>dst</tt> for no more than <tt>dn</tt> bytes and returns either;
<ul>
<li>the index of the matching pattern + 1,</li>
<li>zero if EOF was read from <tt>sh-&gt;ptym</tt>,</li>
<li>or -1 if <tt>timeout</tt> was exceeded or another error occured.</li>
</ul>
Tips: It is very easy to be confused about what you think the shell is doing and what it is really doing. It is important to emulate what happens when you type the equivalent input in a shell in a terminal window but consider that the shell does not echo your commands. The shell will just write the output of the program followed by the shell prompt (whatever you defined that to be). If you are issueing multiple commands or the "exit $?\n" command take care not to write the commands before the shell is ready (receive the shell prompt). Finally, the buffer passed to <tt>sho_expect</tt> will only contain the characters up to and including the pattern that matched. If the pattern matched is not the shell prompt it will be necessary to call <tt>sho_expect</tt> again to match the prompt before another command may be issued.
	</desc>
	<ret>
The <ident>sho_expect</ident> function returns the index of the matching pattern + 1, 0 if EOF was read, or -1 if an error occured in which case errno will be set appropriately. If the <tt>timeout</tt> period is exceeded <ident>sho_expect</ident> will return -1 and set errno to EINTR.
	</ret>
</meth>

<meth name="loop">
	<pre>int sho_loop(struct sho *sh, const char *pv[], int pn, int timeout);</pre>
	<param name="sh"/>
	<param name="pv"/>
	<param name="pn"/>
	<param name="timeout"/>
	<desc>
The <ident>sho_loop</ident> function uses the <def>select</def>(2) system call to read from the shell and write to <tt>stdout</tt> at the same time. The loop will exit when either one of <tt>pn</tt> patterns at the beginning of the pattern vector <tt>pv</tt> is encountered or the <tt>timeout</tt> period has expired.
<p/>
When combined with the <tt>SHO_FLAGS_INTERACT</tt> flag passed to <tt>sho_open</tt> this will effectively create a shell within a shell. Note, currently some programs will not operate correctly (e.g. vi) because certain <tt>termios</tt> flags are not optimal for interactive sessions. This would need futher study.
	</desc>
	<ret>
The <ident>sho_loop</ident> function returns the index of the matching pattern + 1, 0 if EOF was read, or -1 if an error occured in which case errno will be set appropriately. If the <tt>timeout</tt> period is exceeded <ident>sho_expect</ident> will return -1 and set errno to EINTR.
	</ret>
</meth>

</group>
</interface>

