rsalz@bbn.com (Rich Salz) (12/08/89)
Someone wanted a program that would write to multiple terminals at the same time. I had hacked the BSD "script" program to do that; here's the source. Compile with -DTUTOR. Usage: tutor /dev/tty3 tty4 /dev/pty2 ... (If you don't put / or . in front of the pathname, /dev is assumed.) It's a useful hack for when you want to run through a demo and show everyone in a class what's going on. /r$ #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: script.c # Wrapped by rsalz@bbn.com on Thu Dec 7 12:08:12 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'script.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'script.c'\" else echo shar: Extracting \"'script.c'\" \(7226 characters\) sed "s/^X//" >'script.c' <<'END_OF_FILE' X/* X * Copyright (c) 1980 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifdef TUTOR X/* X** Hacked on by Rich $alz <rsalz@bbn.com> so that it writes to multiple X** devices at the same time. Compile with -DTUTOR to get that effect. X** cc -DTUTOR -o tutor script.c X** Usage: X** tutor console tty3 /dev/ttyp2 ... X*/ X#endif /* TUTOR */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1980 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif /* not lint */ X X#ifndef lint Xstatic char sccsid[] = "@(#)script.c 5.6 (Berkeley) 6/29/88"; X#endif /* not lint */ X X/* X * script X */ X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/ioctl.h> X#include <sys/time.h> X#include <sys/file.h> X#include <stdio.h> X#include <signal.h> X Xchar *shell; X#ifndef TUTOR XFILE *fscript; X#else /* TUTOR */ Xint ttys[50]; Xint count; X#endif /* TUTOR */ Xint master; Xint slave; Xint child; Xint subchild; X#ifndef TUTOR Xchar *fname; X#endif /* TUTOR */ X Xstruct sgttyb b; Xstruct tchars tc; Xstruct ltchars lc; Xstruct winsize win; Xint lb; Xint l; Xchar *line = "/dev/ptyXX"; Xint aflg; X Xmain(argc, argv) X int argc; X char *argv[]; X{ X extern char *optarg; X extern int optind; X int ch; X int finish(); X char *getenv(); X X while ((ch = getopt(argc, argv, "a")) != EOF) X switch((char)ch) { X case 'a': X aflg++; X break; X case '?': X default: X#ifndef TUTOR X fprintf(stderr, "usage: script [-a] [file]\n"); X#else /* TUTOR */ X fprintf(stderr, "usage: script [-a] ttys...\n"); X#endif /* TUTOR */ X exit(1); X } X argc -= optind; X argv += optind; X X#ifndef TUTOR X if (argc > 0) X fname = argv[0]; X else X fname = "typescript"; X if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { X perror(fname); X fail(); X#else /* TUTOR */ X if (argc == 0) { X fprintf(stderr, "usage: script [-a] ttys...\n"); X exit(1); X } X openthem(argv); X#endif /* TUTOR */ X X shell = getenv("SHELL"); X if (shell == NULL) X shell = "/bin/sh"; X X getmaster(); X#ifndef TUTOR X printf("Script started, file is %s\n", fname); X#else X printf("Script started.\n"); X#endif /* TUTOR */ X fixtty(); X X (void) signal(SIGCHLD, finish); X child = fork(); X if (child < 0) { X perror("fork"); X fail(); X } X if (child == 0) { X subchild = child = fork(); X if (child < 0) { X perror("fork"); X fail(); X } X if (child) X dooutput(); X else X doshell(); X } X doinput(); X} X Xdoinput() X{ X register int cc; X char ibuf[BUFSIZ]; X X#ifndef TUTOR X (void) fclose(fscript); X#else /* TUTOR */ X closethem(); X#endif /* TUTOR */ X while ((cc = read(0, ibuf, BUFSIZ)) > 0) X (void) write(master, ibuf, cc); X done(); X} X X#include <sys/wait.h> X Xfinish() X{ X union wait status; X register int pid; X register int die = 0; X X while ((pid = wait3(&status, WNOHANG, 0)) > 0) X if (pid == child) X die = 1; X X if (die) X done(); X} X Xdooutput() X{ X register int cc; X time_t tvec, time(); X char obuf[BUFSIZ], *ctime(); X X (void) close(0); X tvec = time((time_t *)NULL); X#ifndef TUTOR X fprintf(fscript, "Script started on %s", ctime(&tvec)); X#else /* TUTOR */ X (void) sprintf(obuf, "Script started on %s", ctime(&tvec)); X writethem(obuf, strlen(obuf)); X#endif /* TUTOR */ X for (;;) { X cc = read(master, obuf, sizeof (obuf)); X if (cc <= 0) X break; X (void) write(1, obuf, cc); X#ifndef TUTOR X (void) fwrite(obuf, 1, cc, fscript); X#else /* TUTOR */ X writethem(obuf, cc); X#endif /* TUTOR */ X } X done(); X} X Xdoshell() X{ X int t; X X t = open("/dev/tty", O_RDWR); X if (t >= 0) { X (void) ioctl(t, TIOCNOTTY, (char *)0); X (void) close(t); X } X getslave(); X (void) close(master); X#ifndef TUTOR X (void) fclose(fscript); X#else /* TUTOR */ X closethem(); X#endif /* TUTOR */ X (void) dup2(slave, 0); X (void) dup2(slave, 1); X (void) dup2(slave, 2); X (void) close(slave); X execl(shell, "sh", "-i", 0); X perror(shell); X fail(); X} X Xfixtty() X{ X struct sgttyb sbuf; X X sbuf = b; X sbuf.sg_flags |= RAW; X sbuf.sg_flags &= ~ECHO; X (void) ioctl(0, TIOCSETP, (char *)&sbuf); X} X Xfail() X{ X X (void) kill(0, SIGTERM); X done(); X} X Xdone() X{ X time_t tvec, time(); X#ifndef TUTOR X char *ctime(); X#else /* TUTOR */ X char *ctime(), buff[128]; X#endif /* TUTOR */ X X if (subchild) { X tvec = time((time_t *)NULL); X#ifndef TUTOR X fprintf(fscript,"\nscript done on %s", ctime(&tvec)); X (void) fclose(fscript); X#else /* TUTOR */ X (void) sprintf(buff,"\nscript done on %s", ctime(&tvec)); X writethem(buff, strlen(buff)); X closethem(); X#endif /* TUTOR */ X (void) close(master); X } else { X (void) ioctl(0, TIOCSETP, (char *)&b); X#ifndef TUTOR X printf("Script done, file is %s\n", fname); X#else /* TUTOR */ X printf("Script done.\n"); X#endif /* TUTOR */ X } X exit(0); X} X Xgetmaster() X{ X char *pty, *bank, *cp; X struct stat stb; X X pty = &line[strlen("/dev/ptyp")]; X for (bank = "pqrs"; *bank; bank++) { X line[strlen("/dev/pty")] = *bank; X *pty = '0'; X if (stat(line, &stb) < 0) X break; X for (cp = "0123456789abcdef"; *cp; cp++) { X *pty = *cp; X master = open(line, O_RDWR); X if (master >= 0) { X char *tp = &line[strlen("/dev/")]; X int ok; X X /* verify slave side is usable */ X *tp = 't'; X ok = access(line, R_OK|W_OK) == 0; X *tp = 'p'; X if (ok) { X (void) ioctl(0, TIOCGETP, (char *)&b); X (void) ioctl(0, TIOCGETC, (char *)&tc); X (void) ioctl(0, TIOCGETD, (char *)&l); X (void) ioctl(0, TIOCGLTC, (char *)&lc); X (void) ioctl(0, TIOCLGET, (char *)&lb); X (void) ioctl(0, TIOCGWINSZ, (char *)&win); X return; X } X (void) close(master); X } X } X } X fprintf(stderr, "Out of pty's\n"); X fail(); X} X Xgetslave() X{ X X line[strlen("/dev/")] = 't'; X slave = open(line, O_RDWR); X if (slave < 0) { X perror(line); X fail(); X } X (void) ioctl(slave, TIOCSETP, (char *)&b); X (void) ioctl(slave, TIOCSETC, (char *)&tc); X (void) ioctl(slave, TIOCSLTC, (char *)&lc); X (void) ioctl(slave, TIOCLSET, (char *)&lb); X (void) ioctl(slave, TIOCSETD, (char *)&l); X (void) ioctl(slave, TIOCSWINSZ, (char *)&win); X} X X X#ifdef TUTOR Xopenthem(argv) X char **argv; X{ X char buff[BUFSIZ]; X X for ( ; *argv; argv++) { X /* If path doesn't start with . or / assume it's in /dev */ X if (**argv != '.' && **argv != '/') { X (void) sprintf(buff, "/dev/%s", *argv); X *argv = buff; X } X ttys[count] = open(*argv, O_WRONLY | O_NDELAY); X if (ttys[count] < 0) X perror(*argv); X else X count++; X } X X if (count == 0) { X fprintf(stderr, "No devices open.\n"); X exit(1); X } X} X Xwritethem(p, i) X char *p; X int i; X{ X int j; X X for (j = 0; j < count; j++) X (void) write(ttys[j], p, i); X} X Xclosethem() X{ X while (--count >= 0) X (void)close(ttys[count]); X} X#endif /* TUTOR */ END_OF_FILE if test 7226 -ne `wc -c <'script.c'`; then echo shar: \"'script.c'\" unpacked with wrong size! fi # end of 'script.c' fi echo shar: End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.
d88-sli@nada.kth.se (Stefan Lindmark) (12/08/89)
A very simple way to get output on multiple terminals is to do the demo like this: 1. Teacher writes: csh | tee /tmp/log 2. Every student writes: tail -f /tmp/log The teachers screen outputs as well as his own typing will be copied onto the file /tmp/log. The students will all listen to that file and continously display everything that gets appended to it. Rough, but simple. -- Stefan Lindmark Email: d88-sli@nada.kth.se Snail-mail: Don't even bother... Unsubscribed to newsgroup eunet.jokes.