eric@ms.uky.edu@mandrill.CWRU.Edu (Eric Herrin) (09/24/87)
Here's a cute little utility I had to write to allow students to record terminal sessions. It works with the System V pty driver I posted earlier for the UnixPC, but should work on any System V box with ptys. Hope it can be useful to someone else. eric | | | Eric Herrin II cbosgd!ukma!eric | | "'tis better to be silent eric@UKMA.BITNET | | and be THOUGHT a fool, than to open eric@ms.uky.csnet | | one's mouth and remove all doubt." eric@ms.uky.edu | ______________________ cut here _________________________ #! /bin/sh : This is a shell archive, meaning: : 1. Remove everything above the '#! /bin/sh' line. : 2. Save the resulting text in a file. : 3. Execute the file with /bin/sh '(not csh)' to create the files: : 'session.c' : 'session.mk' : This archive created: 'Sun Sep 20 12:02:40 1987 ' export PATH; PATH=/bin:$PATH echo shar: extracting "'session.c'" '(4397 characters)' if test -f 'session.c' then echo shar: will not over-write existing file "'session.c'" else sed 's/^X//' >'session.c' <<'SHAR_EOF' X/* Copyright (c) 1987 University of Kentucky Mathematical Sciences X * Eric H. Herrin II X * eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric X * X * Permission is hereby granted to modify and redistribute X * this program for non-commercial use, provided this copyright X * notice is retained in all versions. X */ X X/* session.c - record a terminal session into a file for UNIX System V. X * X * Usage: session [filename] X */ X#include <stdio.h> X#include <fcntl.h> X#include <errno.h> X#include <signal.h> X#include <termio.h> X#include <sys/ttold.h> X X#define SHELL "/bin/ksh" X#define SHELLARG "ksh" X#define BYTES 1 X XFILE *recordfile, *fopen(); Xint pty, tty; Xstruct sgttyb savesgbuf; Xchar *slave="/dev/ttyXX", *master="/dev/ptyXX"; X Xmain(argc, argv) X int argc; X char *argv[]; X{ X int p, s; X int bytes; X char buf[BYTES]; X char *filename; X struct sgttyb sgbuf; X void cleanup(); X X if (argc > 2) { X fprintf(stderr, "Usage: %s [filename]\n", argv[0]); X exit(1); X } else if (argc == 2) X filename = argv[1]; X else X filename = "session_file"; X X if ((recordfile = fopen(filename, "w")) == NULL) { X fprintf(stderr, "%s: cannot open %s.\n", argv[0], filename); X exit(1); X } X signal(SIGTERM, cleanup); X OpenPtys(slave, master, &tty, &pty); X /* fork off a process to handle the setup of the tty for the X * shell and execing the shell. X */ X if (fork() == 0) { X struct termio tio; X X close(pty); X /* setpgrp to associate the process with the pty. X */ X setpgrp(); X if ((tty = open(slave, O_RDWR)) < 0) { X printf("ERROR: open slave: errno = %d\n", errno); X exit(1); X } X /* set up the tty end of the pty to be the std[in,out,err] X * of the new shell. X */ X close(0); dup(tty); X close(1); dup(tty); X close(2); dup(tty); X /* set up some reasonable parameters for the pty, ie. X * let the shell have a normal environment. X */ X ioctl(0, TCGETA, &tio); X tio.c_cc[VINTR] = ''; X tio.c_cc[VERASE] = ''; X tio.c_cc[VKILL] = ''; X tio.c_cc[VEOF] = ''; X tio.c_iflag &= ~(IGNBRK | PARMRK | INPCK | INLCR | IGNCR | IUCLC); X tio.c_iflag |= (BRKINT | IGNPAR | ISTRIP | ICRNL | IXON); X tio.c_oflag &= ~(OLCUC | OCRNL | ONOCR | ONLRET | OFILL | OFDEL); X tio.c_oflag |= (OPOST); X tio.c_oflag |= (ONLCR); /*?*/ X tio.c_lflag |= (ISIG | ICANON | ECHO | ECHOK); X tio.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARODD | HUPCL | CLOCAL); X tio.c_cflag |= (B9600 | CS7 | CREAD | PARENB); X ioctl(0, TCSETAW, &tio); X /* exec the shell X */ X execl(SHELL, SHELLARG, "-i", 0); X fprintf(stderr, "exec of /bin/sh failed\n"); X exit(1); X } X close(tty); X /* master process, device end of tty X */ X ioctl(0, TIOCGETP, &savesgbuf); X sgbuf = savesgbuf; X sgbuf.sg_flags |= O_RAW; X sgbuf.sg_flags &= ~O_ECHO; X ioctl(0, TIOCSETP, &sgbuf); X /* fork off a reader of the pty master end. X */ X if (fork() == 0) { X while ((bytes=read(pty, buf, BYTES)) > 0) { X fwrite(buf, 1, bytes, stdout); X fwrite(buf, 1, bytes, recordfile); X fflush(stdout); X } X exit(0); X } X /* fork off a writer of the pty master end. X */ X if (fork() == 0) { X while ((bytes=read(0, buf, BYTES)) > 0) X write(pty, buf, bytes); X exit(0); X } X /* The shell is the only process which will exit on its own. X * wait for it. X */ X wait((int *)0); X /* terminate last line, ^D from shell won't do it. X */ X fprintf(recordfile, "\n"); X /* shell is already dead, so kill everybody else after cleanup. X */ X kill(0, SIGTERM); X close(pty); X fclose(recordfile); X} X Xvoid cleanup() X{ X fclose(recordfile); X close(tty); X close(pty); X ioctl(0, TIOCSETP, &savesgbuf); X exit(0); X} X XOpenPtys(slave, master, tty, pty) X char *slave, *master; X int *tty, *pty; X{ X int i, j; X int tmaster; X int letcnt=0, numcnt=0; X static char *letters = "pqrstuvwxyz", X *numbers = "0123456789abcdef"; X static int letmax, nummax; X X letmax=strlen(letters)-1, nummax=strlen(numbers)-1; X do { X master[strlen("/dev/pty")] = letters[letcnt]; X master[strlen("/dev/ptyX")] = numbers[numcnt]; X if (letcnt > letmax) { X fprintf(stderr, "ERROR: all ptys in use\n"); X exit(1); X } else if (++numcnt > nummax) { X letcnt++; X numcnt = 0; X } X } while ((*pty=open(master, O_RDWR)) < 0); X /* got a free pty. X */ X slave[8] = master[8]; X slave[9] = master[9]; X if ((*tty = open(slave, O_RDWR)) < 0) { X fprintf(stderr, "ERROR: opening slave: errno = %d\n", errno); X exit(1); X } X} SHAR_EOF echo shar: 4 control characters may be missing from "'session.c'" if test 4397 -ne "`wc -c < 'session.c'`" then echo shar: error transmitting "'session.c'" '(should have been 4397 characters)' fi fi # end of overwriting check echo shar: extracting "'session.mk'" '(642 characters)' if test -f 'session.mk' then echo shar: will not over-write existing file "'session.mk'" else sed 's/^X//' >'session.mk' <<'SHAR_EOF' X# session.mk X# Copyright (c) 1987 University of Kentucky Mathematical Sciences X# Eric H. Herrin II X# eric@ms.uky.edu, eric@ms.uky.csnet, !cbosgd!ukma!eric X# X# Permission is hereby granted to modify and redistribute X# this program for non-commercial use, provided this copyright X# notice is retained in all versions. X# X XSRCS = session.c XOBJS = session.o XINSDIR = /usr/local/bin XCFLAGS = -O -c X X.c.o: X ${CC} ${CFLAGS} $< X Xsession: session.o X ${CC} ${OBJS} -o session X Xinstall: session X cp session ${INSDIR} X chown bin ${INSDIR}/session X chgrp bin ${INSDIR}/session X chmod 555 ${INSDIR}/session X Xclean: X rm -f *.o X Xclobber: X rm -f *.o session SHAR_EOF if test 642 -ne "`wc -c < 'session.mk'`" then echo shar: error transmitting "'session.mk'" '(should have been 642 characters)' fi fi # end of overwriting check : End of shell archive a iness