Writing to multiple terminals (BSD)
Rich Salz
rsalz at bbn.com
Fri Dec 8 04:10:11 AEST 1989
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 at 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 at 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 at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.unix.questions
mailing list