Example 6. hello, world
To use the shellout(3m) module effectively there are a few important rules that must be followed. One, is that the sho_close function calls wait(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.
Tip: If your program is not responding it is possible to write the special Ctrl-C chacter. For example on Linux at least this appears to be "\x03". If the process still does not respond a kill(2) can be used to send a SIGKILL to sh->pid however even though this is almost garunteed to get shell control back take care that it does not leave a zombie process lingering in the background.
The below code is a minimal "hello, world" example that opens a new /bin/sh shell with sho_open 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 sho_expect which will wait for the command prompt 'sh> ' to come back. The command prompt is defined by the ps1 parameter to sho_open so the caller will know what it is and that it is uniqe to the expected output.
struct sho *sh; const char *cmd = "echo hello, world\n"; const char *pv[] = { "sh> " }; char buf[256]; int i; sh = sho_open("sh", pv[0], 0); writen(sh->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>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 sho_expect with other strings in the pattern vector. For example, to get a list of mounted filesystems the mount(8) command might be used with no arguments. If the pattern vector were change to: const char *pv[] = { "sh> ", "\n" }; for example the sho_expect function would return with each line in the buffer which assists in parsing the values in each mount entry.
The svcond(3m) module is not available in the Win32 environment. This module also does not work on HP-UX because it does not support the forkpty(3) function.
The struct sho structure
Synopsis
Description
#include <mba/shellout.h> SHO_FLAGS_INTERACT SHO_FLAGS_ISATTY struct sho { char ps1[32]; int flags; pid_t pid; int ptym; struct termios t0; };
The sho_open function
Description
#include <mba/shellout.h> struct sho *sho_open(const char *sh, const char *ps1, int flags);
The sho_close function
Description
#include <mba/shellout.h> int sho_close(struct sho *sh);
The sho_expect function
Description
#include <mba/shellout.h> int sho_expect(struct sho *sh, const char *pv[], int pn, char *dst, size_t dn, int timeout);
The sho_loop function
Description
#include <mba/shellout.h> int sho_loop(struct sho *sh, const char *pv[], int pn, int timeout);
When combined with the SHO_FLAGS_INTERACT flag passed to sho_open this will effectively create a shell within a shell. Note, currently some programs will not operate correctly (e.g. vi) because certain termios flags are not optimal for interactive sessions. This would need futher study.