/* * Flush: A little program that tricks another program into line buffering * its output. * * By Michael Sandrof */ #ifndef lint static char rcsid[] = "@(#)$Id: ircflush.c,v 1.16 1994/07/02 02:32:13 mrg Stab $"; #endif #include "irc.h" #include #ifndef __linux__ # ifdef __svr4__ # include # else # include /* SVR4 => sgtty = yuk */ # endif /* SOLARIS */ #endif /* __linux__ */ #define BUFFER_SIZE 1024 /* descriptors of the tty and pty */ int master, slave; pid_t pid; RETSIGTYPE death(); RETSIGTYPE death() { close(0); close(master); kill(pid, SIGKILL); wait(0); exit(0); } /* * setup_master_slave: this searches for an open tty/pty pair, opening the * pty as the master device and the tty as the slace device */ void setup_master_slave() { char line[11]; char linec; int linen; for (linec = 'p'; linec <= 's'; linec++) { sprintf(line, "/dev/pty%c0", linec); if (access(line, 0) != 0) break; for (linen = 0; linen < 16; linen++) { sprintf(line, "/dev/pty%c%1x", linec, linen); if ((master = open(line, O_RDWR)) >= 0) { sprintf(line, "/dev/tty%c%1x", linec, linen); if (access(line, R_OK | W_OK) == 0) { if ((slave = open(line, O_RDWR)) >= 0) return; } close(master); } } } fprintf(stderr, "flush: Can't find a pty\n"); exit(0); } /* * What's the deal here? Well, it's like this. First we find an open * tty/pty pair. Then we fork three processes. The first reads from stdin * and sends the info to the master device. The next process reads from the * master device and sends stuff to stdout. The last processes is the rest * of the command line arguments exec'd. By doing all this, the exec'd * process is fooled into flushing each line of output as it occurs. */ void main(argc, argv) int argc; char **argv; { char buffer[BUFFER_SIZE]; int cnt; fd_set rd; if (argc < 2) { fprintf(stderr, "Usage: %s [program] [arguments to program]\n", argv[0]); exit(1); } pid = open("/dev/tty", O_RDWR); #ifdef HAVE_SETSID setsid(); #else ioctl(pid, TIOCNOTTY, 0); #endif /* HAVE_SETSID */ setup_master_slave(); switch (pid = fork()) { case -1: fprintf(stderr, "flush: Unable to fork process!\n"); exit(1); case 0: dup2(slave, 0); dup2(slave, 1); dup2(slave, 2); close(master); setuid(getuid()); setgid(getgid()); execvp(argv[1], &(argv[1])); fprintf(stderr, "flush: Error exec'ing process!\n"); exit(1); break; default: (void) MY_SIGNAL(SIGCHLD, death, 0); close(slave); while (1) { FD_ZERO(&rd); FD_SET(master, &rd); FD_SET(0, &rd); switch (select(NFDBITS, &rd, 0, 0, 0)) { case -1: case 0: break; default: if (FD_ISSET(0, &rd)) { if ((cnt = read(0, buffer,BUFFER_SIZE)) > 0) write(master, buffer, cnt); else death(); } if (FD_ISSET(master, &rd)) { if ((cnt = read(master, buffer, BUFFER_SIZE)) > 0) write(1, buffer, cnt); else death(); } } } break; } }