rsalz@bbn.com (Rich Salz) (12/08/89)
Submitted-by: rsalz@bbn.com (Rich Salz) Posting-id: 891207.1802 Posting-number: Volume TEST, Number TEST Archive-name: tutor: write to multiple terminals at the same time [This is an experimental alt.sources re-posting from the newsgroup(s) comp.unix.questions,comp.sources.wanted. No attempt has been made to edit, clean, modify, or otherwise change the contents of the original posting, or to contact the author. Please consider cross-posting all sources postings to alt.sources as a matter of course.] [Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti)] 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.