/* * trfifo: link two users via UNIX FIFO files * * Instructions: * 1. run trfifo on the HOST PC: * trfifo host * 2. enter any name, say "test" at the prompt * 3. exit to DOS, but KEEP connection * 4. run TRHOST * 5. run trfifo on the REPLICA PC: * trfifo * 6. enter the SAME name ("test") at the prompt * 7. exit to DOS, but KEEP connection (if not using TR to log in) * 8. run TR (if not using TR to log in) * 9. when finished, exit TR with F10/3 (host PC will reboot) * 10. normally host will keep running trfifo ready for next login. To * stop trfifo on host, send DEL from host PC. */ #include #include #include #include #include #include #include #define TRUE 1 #define FALSE 0 #define OK 0 #define ERROR (-1) #define FIFO ( S_IFIFO | 0666 ) #define IN 0 #define OUT 1 #define BUFF_SIZE 128 struct termio oldtty, tty; /* used for setting RAW I/O */ int iofd = 0; /* file descriptor for setting RAW I/O */ char readfile[BUFF_SIZE]; /* name of host input FIFO */ char writefile[BUFF_SIZE]; /* name of host output FIFO */ /* * restore tty to its original state */ void terminate(status) int status; { /* * go back to normal I/O - borrowed from rbsb.c from the zmodem * package. */ (void) ioctl(iofd, TCSBRK, 1); /* wait for output to drain */ (void) ioctl(iofd, TCFLSH, 1); /* flush input queue */ (void) ioctl(iofd, TCSETAW, &oldtty); /* restore original modes */ (void) ioctl(iofd, TCXONC,1); /* restart output */ /* * don't leave inactive pipes around */ unlink(readfile); unlink(writefile); exit(status); } /* * trap interrupts so that tty state can be restored */ void int_handler() { terminate(0); } void main(argc, argv) int argc; char *argv[]; { char sys_name[256]; /* base name of FIFO link */ unsigned char buff[BUFF_SIZE]; /* buffer for transferred characters */ int n; /* number of characters read */ unsigned char c; /* a general purpose character! */ int readfd; /* file descriptor for reading FIFO */ int writefd; /* file descriptor for writing FIFO */ int child; /* PID for child process */ int host; /* is this the host end? */ static struct sigaction act; /* used for catching BREAK */ int first = TRUE; /* first time around? */ /* * store settings for later */ (void) ioctl(iofd, TCGETA, &oldtty); restart: /* come back here after each session */ /* * ignore BREAK for a bit */ tty = oldtty; /* save original settings for later */ tty.c_iflag &= ~BRKINT; /* DO NOT allow BREAK to kill */ tty.c_iflag |= IGNBRK; /* ignore BREAK */ (void) ioctl(iofd, TCSETAW, &tty); if (first) { if (argc > 3 || (argc == 3 && strcmp(argv[1], "host") != 0)) { fprintf(stderr, "Usage: trfifo [host] []\n"); terminate(1); } if (argc > 1 && strcmp(argv[1], "host") == 0) { host = TRUE; } else { host = FALSE; } if (argc != 3) { /* no output for command line version of host */ printf("TRFifo PC linking utility\n"); } if (argc == host + 1) { printf("Enter system name (e.g. as1): "); fflush(stdout); gets(sys_name); } else { strcpy(sys_name, argv[host+1]); } if (argc != 3) { /* no output for command line version of host */ printf("Setting up %s '%s'\n", host ? "host" : "replica", sys_name); } /* * Name the FIFOs - the host gets sensible names, the replica gets * reversed names! */ if (host) { sprintf(readfile, "/tmp/in_%s", sys_name); sprintf(writefile, "/tmp/out_%s", sys_name); } else { sprintf(readfile, "/tmp/out_%s", sys_name); sprintf(writefile, "/tmp/in_%s", sys_name); } } /* * Create the FIFOs */ if (host) { umask(0); /* let anyone into the FIFO */ unlink(readfile); /* kill old FIFO from last crash? */ if (mknod(readfile, FIFO) == ERROR) { perror(readfile); terminate(1); } unlink(writefile); if (mknod(writefile, FIFO) == ERROR) { perror(writefile); unlink(readfile); terminate(1); } } if (host && first) { printf("Return to DOS (keeping connection) and run TRHOST\n"); fflush(stdout); } /* * catch interrupt */ act.sa_handler = int_handler; sigaction(SIGINT, &act, NULL); /* * pipes are opened in the opposite order, so that deadlock does * not occur waiting to open pipes... */ if (host) { if ((readfd = open(readfile, O_RDONLY)) == ERROR) { perror("can't open FIFO for reading"); unlink(readfile); unlink(writefile); terminate(1); } if ((writefd = open(writefile, O_WRONLY)) == ERROR) { perror("can't open FIFO for writing"); unlink(readfile); unlink(writefile); terminate(1); } } else { if ((writefd = open(writefile, O_WRONLY)) == ERROR) { /* * This probably means the host is not running or is in use * by someone else... */ fprintf(stderr, "Sorry, '%s' is not currently available\n", sys_name); terminate(1); } if ((readfd = open(readfile, O_RDONLY)) == ERROR) { perror("can't open FIFO for reading"); terminate(1); } } /* * have established the FIFO, remove the files so no-one else can * interfere... */ unlink(readfile); unlink(writefile); if (!host) { printf("Return to DOS (keeping connection) and run TR\n"); fflush(stdout); } first = FALSE; /* * go into transparent 8-bit raw I/O etc etc - largely inspired by the * rbsb.c file in the zmodem package. See this file for ideas if you * have an incompatible flavor of UNIX... */ tty = oldtty; /* save original settings for later */ tty.c_iflag = BRKINT; /* DO allow BREAK to kill */ tty.c_lflag &= ~(ECHO | ICANON | ISIG); /* no echo etc etc*/ tty.c_oflag = 0; /* no output processing */ tty.c_cflag &= ~PARENB; /* disable parity */ tty.c_cflag |= CS8; /* set character size to 8 bits */ tty.c_cc[VMIN] = BUFF_SIZE; /* try to read a decent block */ tty.c_cc[VTIME] = 1; /* give up after 0.1 seconds */ (void) ioctl(iofd, TCSETAW, &tty); /* * One process reads the input FIFO and copies it to STDOUT; the other * reads STDIN and copies it to the output FIFO. */ switch (child = fork()) { case ERROR: perror("fork"); terminate(1); case 0: for (;;) { n = read(0, buff, BUFF_SIZE); if (n > 0) { write(writefd, buff, n); } } default: for (;;) { if ((n = read(readfd, buff, BUFF_SIZE)) <= 0) { break; } write(1, buff, n); } if (host) { /* * the replica has just terminated, so send a reboot command * to the host */ /* * ensure BREAK is ignored before rebooting PC */ tty = oldtty; /* save original settings for later */ tty.c_iflag &= ~BRKINT; /* DO NOT allow BREAK to kill */ tty.c_iflag |= IGNBRK; /* ignore BREAK */ (void) ioctl(iofd, TCSETAW, &tty); c = 0; write(1, &c, 1); write(1, &c, 1); c = 3; write(1, &c, 1); sleep(1); c = 0; write(1, &c, 1); write(1, &c, 1); c = 3; write(1, &c, 1); kill(child, SIGINT); /* don't leave orphan */ wait(NULL); goto restart; } /* * don't leave orphan processes... */ kill(child, SIGINT); wait(NULL); } terminate(0); }