/* 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); }