/* cc -Wall -o do do.c -lutil */
/* This is to be used in a distributed parallel scrabble program,
where the program does one level of lookahead; its parameters
are read from stdin, and its results are printed to stdout.
It'll be wrapped in a C procedure so that the application never
sees all this behind-the-scenes stuff, and just does the equivalent
of a popen() Something like this:
int calculate(int i, char *s) {
int rc;
create_process(command, &inputfd, &outputfd);
outf = fdopen(outputfd, "w"); inf = fdopen(inputfd, "r");
fprintf(outf, "%d\n%s\n", i, s);
fscan(inf, "%d\n", &rc);
return rc;
}
noting that the command isn't just a program name like "scrabhelper",
it could be a call to ssh such as
"ssh gtoal@hive0001.honeybeegardens.net scrabhelper"
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <pwd.h>
#include <pty.h>
#include <sys/wait.h>
int master, slave, child, subchild, lb, l;
struct termios tt;
struct winsize win;
#define done() exit (((subchild ? close (master) : tcsetattr (0, TCSAFLUSH, &tt)), EXIT_SUCCESS))
static void fail (char *who) {
perror (who);
(void) kill (0, SIGTERM);
done ();
}
static char *home (void) {
struct passwd *p;
return (((p = getpwuid (getuid ())) != NULL) ? p->pw_dir : NULL);
}
void finish (int arg) {
union wait status;
register int pid;
while ((pid = wait3 ((int *) &status, WNOHANG, 0)) > 0) { if (pid == child) done (); }
}
int call(char *program) {
struct termios rtt;
int cc;
(void) home ();
/* getmaster */
(void) tcgetattr (0, &tt);
(void) ioctl (0, TIOCGWINSZ, (char *) &win);
if (openpty (&master, &slave, NULL, &tt, &win) < 0) fail ("openpty");
/* fixtty */
rtt = tt;
cfmakeraw (&rtt);
rtt.c_lflag &= ~ECHO;
(void) tcsetattr (0, TCSAFLUSH, &rtt);
(void) signal (SIGCHLD, &finish);
child = fork ();
if (child == 0) {
subchild = child = fork ();
if (child == 0) {
/* getslave */
(void) setsid ();
(void) ioctl (slave, TIOCSCTTY, 0);
/* doshell */
(void) close (master);
(void) dup2 (slave, 0); (void) dup2 (slave, 1); (void) dup2 (slave, 2);
(void) close (slave);
system(program);
return (EXIT_SUCCESS);
} else if (child > 0) {
/* dooutput */
time_t tvec, time ();
char obuf[BUFSIZ], *ctime ();
(void) close (0);
tvec = time ((time_t *) NULL); /* unused for now. Needed for games with move time limit */
(void) tvec;
for (;;) {
if ((cc = read (master, obuf, sizeof (obuf))) <= 0) break;
(void) write (1, obuf, cc);
}
done ();
}
} else if (child > 0) {
/* doinput */
char ibuf[BUFSIZ];
while ((cc = read (0, ibuf, BUFSIZ)) > 0) (void) write (master, ibuf, cc);
done ();
}
fail ("fork");
return (EXIT_FAILURE);
}
int main (int argc, char **argv) {
int rc;
rc = call("/bin/bash -i");
//rc = call("/usr/local/bin/ecce /dev/null");
//rc = call("bash -c '/usr/local/bin/ecce /dev/null'; exit 0");
fflush(stderr);
sleep(1); /* without this call to sleep, we don't see the printf below???! */
fprintf(stderr, "Exited %d.\n", rc);
fflush(stderr);
exit (rc);
return (rc);
}