1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
/*
* 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.23 1997/01/17 19:53:49 mrg Exp $";
#endif /* lint */
#include "irc.h"
#include <sys/wait.h>
#ifndef __linux__
# ifdef __svr4__
# include <sys/termios.h>
# else
# include <sgtty.h> /* 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 _((void));
static void setup_master_slave _((void));
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
*/
static 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.
*/
int
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;
}
}
|