home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-15 | 57.7 KB | 2,039 lines |
- Newsgroups: comp.sources.unix
- From: ssiny!gnohmon@uunet.uu.net (Ralph Betza)
- Subject: v26i008: ptyshl - shell layers via pseudo-ttys
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: ssiny!gnohmon@uunet.uu.net (Ralph Betza)
- Posting-Number: Volume 26, Issue 8
- Archive-Name: ptyshl
-
- ptyshl is a vastly enhanced replacement for shl, extensively used for 3
- years (therefore well-tested), should compile and run with no problems on
- any SysV.3 UNIX machine ( see README ).
-
- ssiny!gnohmon@uunet.uu.net (Ralph Betza)
-
- PS: It may be that it doesn't work on tty ports of some systems.
- Most of the systems that I used ptyshl on, I got to with rlogins.
-
- [ I renamed a couple of files and generalized the Makefile. --vix ]
-
- #! /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 archive 1 (of 1)."
- # Contents: MANIFEST Makefile README cpyright.h findselect makeall
- # patchlevel.h ptycmd.c ptyshl.c ptyshl.cat1 ptyshl.h
- # Wrapped by vixie@cognition.pa.dec.com on Thu Apr 16 23:21:44 1992
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(455 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X MANIFEST 1 This shipping list
- X Makefile 1
- X README 1
- X cpyright.h 1
- X findselect 1
- X makeall 1
- X patchlevel.h 1
- X ptycmd.c 1
- X ptyshl.c 1
- X ptyshl.cat1 1
- X ptyshl.h 1
- END_OF_FILE
- if test 455 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(513 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- DESTROOT =
- DESTPATH = $(DESTROOT)/usr/local
- DESTBIN = $(DESTPATH)/bin
- DESTMAN = $(DESTPATH)/man
- X
- all: ptyshl
- X
- install: ptyshl ptyshl.cat1
- X install -c ptyshl $(DESTBIN)/ptyshl
- X install -c ptyshl.cat1 $(DESTMAN)/cat/cat1/ptyshl.1
- X
- clean:
- X rm -f *.BAK *.CKP *~ *.o
- X rm -f core ptyshl ptyshl.orig
- X
- WHERE = 2
- X
- ptyshl: ptyshl.o ptycmd.o
- X -mv -f ptyshl ptyshl.orig
- X cc -g -o ptyshl ptyshl.o ptycmd.o -linet
- X
- ptyshl.o: ptyshl.c ptyshl.h
- X cc -g -c -DWHERE=$(WHERE) ptyshl.c
- X
- ptycmd.o: ptycmd.c ptyshl.h
- X cc -g -c ptycmd.c
- END_OF_FILE
- if test 513 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1709 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- This is a greatly enhanced version of the UNIX "shl" program,
- that uses the pty device found in System V.3 instead of the
- sxt or vsxt device used by shl.
- X
- The sxt or vsxt device doesn't work unless you're on a real TTY
- port; therefore, shl doesn't work.
- X
- ptyshl works on all UNIX System V.3 machines, whether you're on a
- real tty port or on a pseudotty from rlogin.
- X
- note: SCO UNIX is NOT UNIX!
- X
- If you use character terminals, this program will greatly enhance
- your lifestyle. You will find it to be extremely solid and
- bug-free; I used it extensively for three years!
- X
- It should compile and run right out of the box, if you just get
- two things right in the makefile:
- X
- The first thing is that you need the select() call from one of
- the system libraries. If you have pty devices, you have select()
- in some library. The "findselect" shell script in this directory
- will help you with this. Change the makefile if you must.
- X
- The second thing is that pty devices have different names on
- different systems. The WHERE variable set up in the makeall
- script takes care of this. Read ptyshl.c if in doubt.
- X
- After you have ptyshl running, you may need to reconfigure your
- kernel to make more pty devices than you now have.
- X
- I haven't ported it to SysV.4 because I have X now...
- X
- Send comments or flames to:
- X
- X-Ralph Betza (FM), Disclaimer: opinions
- X Systems Strategies Inc, presented here have
- X 225 West 34th Street, NY NY 10001, been changed to protect
- X 1-212-279 8400 the innocence.
- X uunet!ssiny!gnohmon
- X
- Sono un viro. Dai, coppiami nel tuo .signature.
- Ich bin ein Virus. Mach' mit und kopiere mich in Deine .signature.
- X
- XFri Dec 13 11:31:34 EST 1991
- END_OF_FILE
- if test 1709 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'cpyright.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cpyright.h'\"
- else
- echo shar: Extracting \"'cpyright.h'\" \(1324 characters\)
- sed "s/^X//" >'cpyright.h' <<'END_OF_FILE'
- X#ifndef _COPYRIGHT_
- X#define _COPYRIGHT_
- X/*========================================================================
- X*
- X* Name - cpyright.h
- X*
- X* Version: 1.0
- X*
- X* Description: copyright information for ptyshl
- X*
- X*========================================================================
- X*
- X* Copyright (C) 1990, 1991 Ralph Betza
- X*
- X* Permission to use, copy, modify, distribute, and sell this software
- X* and its documentation for any purpose is hereby granted without fee,
- X* provided that the above copyright notice appear in all copies and
- X* that both that copyright notice and this permission notice appear
- X* in supporting documentation. The author makes no representations
- X* about the suitability of this software for any purpose. It is
- X* provided "as is" without express or implied warranty.
- X*
- X* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- X* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- X* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- X* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- X* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- X* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
- X* USE OR PERFORMANCE OF THIS SOFTWARE.
- X*/
- X
- static char *Copyright = "Copyright (C) 1990, 1991 Ralph Betza";
- X#endif
- X
- X
- END_OF_FILE
- if test 1324 -ne `wc -c <'cpyright.h'`; then
- echo shar: \"'cpyright.h'\" unpacked with wrong size!
- fi
- # end of 'cpyright.h'
- fi
- if test -f 'findselect' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'findselect'\"
- else
- echo shar: Extracting \"'findselect'\" \(82 characters\)
- sed "s/^X//" >'findselect' <<'END_OF_FILE'
- cd /usr/lib
- for ff in *.a
- do
- X echo $ff $ff $ff $ff $ff
- X nm $ff | grep select
- done
- END_OF_FILE
- if test 82 -ne `wc -c <'findselect'`; then
- echo shar: \"'findselect'\" unpacked with wrong size!
- fi
- chmod +x 'findselect'
- # end of 'findselect'
- fi
- if test -f 'makeall' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'makeall'\"
- else
- echo shar: Extracting \"'makeall'\" \(283 characters\)
- sed "s/^X//" >'makeall' <<'END_OF_FILE'
- set -x
- case `uname -n` in
- X# the following system names are good for my network, but not for
- X# yours, so change them!
- iceman)
- X WHERE=1
- X# Data General
- X ;;
- ssiny|lefty)
- X# Motorola
- X WHERE=2
- X ;;
- X*)
- X# ISC or ESIX or most others.
- X WHERE=3
- X ;;
- esac
- X
- make 'WHERE = '$WHERE > makeall.out 2>&1
- END_OF_FILE
- if test 283 -ne `wc -c <'makeall'`; then
- echo shar: \"'makeall'\" unpacked with wrong size!
- fi
- chmod +x 'makeall'
- # end of 'makeall'
- fi
- if test -f 'patchlevel.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'patchlevel.h'\"
- else
- echo shar: Extracting \"'patchlevel.h'\" \(88 characters\)
- sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
- X/*
- X * p a t c h l e v e l . h
- X */
- X
- static char version[] = " version 1 patchlevel 0: ";
- END_OF_FILE
- if test 88 -ne `wc -c <'patchlevel.h'`; then
- echo shar: \"'patchlevel.h'\" unpacked with wrong size!
- fi
- # end of 'patchlevel.h'
- fi
- if test -f 'ptycmd.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ptycmd.c'\"
- else
- echo shar: Extracting \"'ptycmd.c'\" \(12809 characters\)
- sed "s/^X//" >'ptycmd.c' <<'END_OF_FILE'
- X#define Extern extern
- X#include "ptyshl.h"
- X#include "cpyright.h"
- X#include "patchlevel.h"
- X/* Copyright (c) 1990, 1991 Ralph Betza.
- X** Read the file cpyright.h for full copyright information.
- X*/
- X
- int c_auto(), c_create(), c_delete(), c_Delete(), c_list(),
- X c_main(), c_quit(), c_resume(), c_toggle(), c_Cset(),
- X c_unCset(), c_equal(), c_sh(), c_help(), c_twice(),
- X c_plus(), c_swtch(), c_Forget(), c_Attach(),
- X c_SendFile();
- X/* These commands return 1 if they switch to a new layer
- X** and we should go into layer-mode,
- X** or they return 0 if we should stay in control-mode.
- X*/
- X
- struct cmdtab
- X{ char * cmdname; /* The name of the command. */
- X int (*cmdval)(); /* The function that executes this command. */
- X int cmdexcp;
- X /* exceptions:
- X ** 1 == must be spelled out
- X ** 2 == needs no blank after 1st char
- X */
- X int cmdlen; /* strlen( cmdname ), filled in by c_init(). */
- X} Cmd[] =
- X{
- X { "auto", c_auto },
- X { "Attach", c_Attach }, /* doesn't work on ANY system. */
- X { "create", c_create },
- X { "delete", c_delete },
- X { "Delete", c_Delete },
- X { "Forget", c_Forget },
- X { "list", c_list },
- X { "main", c_main },
- X { "quit", c_quit, 1 },
- X { "resume", c_resume },
- X { "swtch", c_swtch },
- X { "toggle", c_toggle },
- X { "Twice", c_twice },
- X { "Cset", c_Cset },
- X { "unCset", c_unCset },
- X { "=", c_equal },
- X { "+", c_plus },
- X { "sh", c_sh },
- X { "!", c_sh, 2 },
- X { "?", c_help, 2 },
- X { "help", c_help },
- X { ">", c_SendFile, 2 },
- X { "" }
- X};
- X
- int cmdonce;
- int tokcnt;
- int inlen;
- X
- c_init()
- X{ struct cmdtab * C;
- X for ( C = Cmd; C->cmdname[0]; C++ )
- X { C->cmdlen = strlen( C->cmdname );
- X }
- X cmdonce = 1;
- X}
- X
- c_analyze()
- X{ /* input in cmdbuf. retval 0 to continue the loop. */
- X int i;
- X struct cmdtab * C;
- X struct layer * L;
- X
- X if ( ! cmdonce ) c_init();
- X strcpy( tokbuf, cmdbuf );
- X varg[0] = strtok( tokbuf, " \t\n" );
- X if ( varg[0] == NULL || *varg[0] == '#' ) return 0;
- X for ( tokcnt = 1;
- X tokcnt < MAXARG
- X &&
- X ( varg[tokcnt] = strtok( NULL, " \t\n" )) != NULL;
- X tokcnt++ )
- X ;
- X
- X inlen = strlen( varg[ 0 ]);
- X
- X for ( C = Cmd; C->cmdname[0]; C++ )
- X { /* check every table entry. */
- X switch ( C->cmdexcp )
- X { /* exception condition. */
- X case 0:
- X { /* Normal. */
- X if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
- X { goto gotcmd;
- X }
- X continue;
- X }
- X case 1:
- X { /* Must say the whole thing. */
- X if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
- X { if ( inlen != C->cmdlen )
- X { printf(
- X "Command \"%s\" must be spelled out in full\n",
- X C->cmdname );
- X return 0;
- X }
- X goto gotcmd;
- X }
- X continue;
- X }
- X case 2:
- X { /* Need no blank after command. */
- X if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
- X { goto gotcmd;
- X }
- X if ( ! strncmp( varg[ 0 ], C->cmdname, C->cmdlen ))
- X { goto gotcmd;
- X }
- X continue;
- X }
- X } /* end switch on command. */
- X } /* end command loop. */
- X
- X if ( tokcnt == 1 && ( i = findlayer( varg[ 0 ])) >= 0 )
- X { /* A layer name, all by itself, is a request to resume that
- X ** layer.
- X */
- X gotolayer( &ll[ i ]);
- X return 1;
- X }
- X printf(
- X "unrecognized command \"%s\" (try ? for help)\n",
- X varg[ 0 ]);
- X return 0;
- X
- gotcmd:
- X if ( inlen < C->cmdlen && findlayer( varg[ 0 ] ) >= 0 )
- X { /* check for ambiguity. */
- X printf( "Command \"%s\" is ambiguous\n", varg[ 0 ]);
- X return 0;
- X }
- X return ((*C->cmdval)());
- X}
- X
- c_auto()
- X{ if ( tokcnt == 2 && ! strcmp( varg[ 1 ], "+" ))
- X { AplusMode ^= 1;
- X printf( "AUTOPLUS mode is %s.\n",
- X (AplusMode) ? "on" : "off" );
- X return 0;
- X }
- X automode ^= 1;
- X printf( "AUTO flip mode is %s.\n",
- X (automode) ? "on" : "off" );
- X return 0;
- X}
- X
- c_create()
- X{ /* Create a layer. */
- X int i;
- X
- X if ( tokcnt != 2 )
- X { printf( "\"create\" command requires one parameter\n" );
- X return 0;
- X }
- X
- X if ( ( i = findlayer( varg[ 1 ])) >= 0 )
- X { printf( "Layer already exists; resuming it.\n" );
- X gotolayer( &ll[i] );
- X return 1;
- X }
- X if ( makelayer( varg[ 1 ]) >= 0 )
- X { ufake( l->ll_shortty );
- X return 1;
- X }
- X return 0;
- X}
- X
- c_Attach()
- X{ /* Connect to a layer. */
- X struct layer * L;
- X int i;
- X char * cp;
- X
- X if ( tokcnt != 3 )
- X { printf( "\"attach\" command requires three parameters\n" );
- X return 0;
- X }
- X
- X if ( ( i = findlayer( varg[ 1 ])) >= 0 )
- X { printf( "Layer already exists; resuming it.\n" );
- X gotolayer( &ll[i] );
- X return 1;
- X }
- X
- X L = &ll[0];
- X for ( i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 ) goto foundl;
- X }
- X printf( "No free layers\n" );
- X return ( 0 );
- foundl: /* we found a free layer table entry. */
- X
- X
- X L = &ll[i];
- X varg[1][19] = 0;
- X strcpy( L->ll_llname, varg[ 1 ]);
- X /* Layer name. */
- X
- X L->ll_ttyname[0] = L->ll_ptyname[0] = L->ll_shortty[0] = 0;
- X if ( *varg[2] != '/' )
- X { /* add "/dev/" */
- X if ( strlen( varg[2]) > 9 )
- X { printf( "\ntty name too long, \"%s\".\n", varg[2] );
- X return 0;
- X }
- X
- X strcpy( L->ll_ptyname, "/dev/" );
- X varg[2][0] = 'p';
- X strcat( L->ll_ptyname, varg[ 2 ]);
- X
- X strcpy( L->ll_ttyname, "/dev/" );
- X varg[2][0] = 't';
- X strcat( L->ll_ttyname, varg[ 2 ]);
- X
- X strcpy( L->ll_shortty, varg[ 2 ]);
- X }
- X else
- X {
- X if ( strlen( varg[2]) > 20 )
- X { printf( "\ntty name too long, \"%s\".\n", varg[2] );
- X return 0;
- X }
- X
- X cp = varg[2];
- X for (;;)
- X { /* Find pty name. */
- X ++cp;
- X if ( ! *cp )
- X { printf( "\nmalformed tty name.\n" );
- X return 0;
- X }
- X if ( *cp == '/' )
- X { /* here it is. */
- X ++cp;
- X break;
- X }
- X }
- X if ( strlen( cp) > 9 )
- X { printf( "\ntty name too long, \"%s\".\n", cp );
- X return 0;
- X }
- X *cp = 't';
- X strcpy( L->ll_shortty, cp );
- X
- X *cp = 'p';
- X strcpy( L->ll_ptyname, varg[ 2 ]);
- X
- X *cp = 't';
- X strcpy( L->ll_ttyname, varg[ 2 ]);
- X
- X }
- X
- X L->ll_resch = -1;
- X
- X L->ll_ptyfd = open( L->ll_ptyname, O_RDWR|O_EXCL, 0 );
- X if ( L->ll_ptyfd < 0 )
- X { printf( "open \"%s\" failed, errno=%d\n",
- X L->ll_ptyname, errno );
- X return 0;
- X }
- X lcount++;
- X
- X l = L;
- X l->ll_status = 1;
- X ufake( L->ll_shortty );
- X return 1;
- X}
- X
- c_delete()
- X{ /* delete layer. */
- X int i, j;
- X
- X if ( tokcnt < 2 )
- X { printf( "\"delete\" command requires at least one parameter\n" );
- X return 0;
- X }
- X
- X for ( j = 1; j < tokcnt; j++ )
- X { if ( ( i = findlayer( varg[ j ])) >= 0 )
- X { kill( -ll[i].ll_pid, SIGTERM );
- X kill( -ll[i].ll_pid, SIGHUP );
- X }
- X else printf( "No such layer %s\n", varg[ j ]);
- X }
- X
- X return 0;
- X}
- X
- c_Delete()
- X{ /* delete layer emphatically. */
- X int i, j;
- X
- X if ( tokcnt < 2 )
- X { printf( "\"Delete\" command requires at least one parameter\n" );
- X return 0;
- X }
- X
- X for ( j = 1; j < tokcnt; j++ )
- X {
- X if ( ( i = findlayer( varg[ j ])) >= 0 )
- X { kill( -ll[i].ll_pid, SIGTERM );
- X kill( -ll[i].ll_pid, SIGHUP );
- X ll[i].ll_status = 0;
- X kill( -ll[i].ll_pid, SIGKILL );
- X }
- X else printf( "No such layer %s\n", varg[ j ]);
- X }
- X
- X return 0;
- X}
- X
- c_Forget()
- X{ /* forget about layer without killing it. */
- X int i, j;
- X
- X if ( tokcnt < 2 )
- X { printf( "\"Forget\" command requires at least one parameter\n" );
- X return 0;
- X }
- X
- X for ( j = 1; j < tokcnt; j++ )
- X {
- X if ( ( i = findlayer( varg[ j ])) >= 0 )
- X { ll[i].ll_status = 0;
- X close( ll[i].ll_ptyfd );
- X }
- X else printf( "No such layer %s\n", varg[ j ]);
- X }
- X
- X return 0;
- X}
- X
- c_list()
- X{ int i, j, k;
- X if ( tokcnt == 1 )
- X { listlayers( 0, -1 );
- X return 0;
- X }
- X else if ( ! strcmp( varg[ 1 ], "-l" ))
- X { j = 1;
- X i = 2;
- X }
- X else
- X { j = 0;
- X i = 1;
- X }
- X
- X if ( tokcnt == i ) listlayers( j, -1 );
- X else for ( ; i < tokcnt; i++ )
- X { if ( ( k = findlayer( varg[ i ] )) >= 0 )
- X listlayers( j, k );
- X else printf( "No such layer \"%s\"\n", varg[ i ]);
- X }
- X return 0;
- X}
- X
- c_main()
- X{ if ( tokcnt != 2 )
- X printf( "\"main\" command requires 2 parameters.\n" );
- X else mainlayer = findlayer( varg[ 1 ]);
- X return 0;
- X}
- X
- c_quit()
- X{ myexit( 0 );
- X}
- X
- c_resume()
- X{ int i;
- X if ( tokcnt == 1 )
- X { if ( curlayer >= 0 && ll[curlayer].ll_status )
- X { gotolayer( &ll[curlayer] );
- X return 1;
- X }
- X printf( "No current layer.\n" );
- X return 0;
- X }
- X
- X if ( tokcnt != 2 )
- X { printf( "\"resume\" command requires 0 or 1 parameters\n" );
- X return 0;
- X }
- X
- X checklayers();
- X i = findlayer( varg[ 1 ]);
- X if ( i >= 0 )
- X { gotolayer( &ll[i] );
- X return 1;
- X }
- X printf( "No such layer\n" );
- X return 0;
- X}
- X
- c_SendFile()
- X{ int i;
- X FILE * inf;
- X int c;
- X
- X/**********************************************************/
- X/* */
- X/* If the file is too big, bad things happen. */
- X/* */
- X/* If you don't go to the layer right away and let the */
- X/* output come to the screen, bad things may happen. */
- X/* */
- X/* However, this is a useful facility if used with */
- X/* care: in the middle of interactive stuff, you can */
- X/* "type in" a lot of stuff by taking it from a file. */
- X/* */
- X/* Even though I now have X, and therefore don't need */
- X/* layers, I still use ptyshl about once a month just */
- X/* to take advantage of this facility! */
- X/* */
- X/**********************************************************/
- X
- X if ( tokcnt != 3 )
- X { printf( "\"> layer file\", 3 parameters.\n" );
- X return 0;
- X }
- X
- X checklayers();
- X i = findlayer( varg[ 1 ]);
- X if ( i < 0 )
- X { printf( "No such layer\n" );
- X return 0;
- X }
- X
- X inf = fopen( varg[ 2 ], "r" );
- X if ( inf == NULL )
- X { printf( "Couldn't open %s\n", varg[ 2 ] );
- X return 0;
- X }
- X while (( c = getc( inf )) != EOF )
- X { /* Transfer the file to the destination. */
- X char x;
- X
- X x = c;
- X if ( write( ll[ i ].ll_ptyfd, &x, 1 ) != 1 )
- X { printf( "\nwrite error\n" );
- X break;
- X }
- X }
- X
- X fclose( inf );
- X return 0;
- X}
- X
- c_swtch()
- X{
- X if ( tokcnt != 2 )
- X { printf( "\"swtch\" command needs 1 parameter.\n" );
- X return 0;
- X }
- X if ( *varg[1] ) my_swtch_char = *varg[1] & 0xff;
- X}
- X
- c_toggle()
- X{ /* resume last layer. */
- X if ( tokcnt != 1 )
- X { printf( "\"toggle\" command must have 0 parameters.\n" );
- X return 0;
- X }
- X
- X if ( oldlayer >= 0 && ll[oldlayer].ll_status )
- X { gotolayer( &ll[oldlayer] );
- X return 1;
- X }
- X printf( "No alternate layer.\n" );
- X return 0;
- X}
- X
- c_twice()
- X{
- X twicemode ^= 1;
- X sTwice = 0;
- X printf( "\"Twice\" mode is %s.\n",
- X (twicemode) ? "on" : "off" );
- X return 0;
- X}
- X
- c_plus()
- X{ /* next sequential layer. */
- X int i;
- X
- X if ( curlayer < 0 ) curlayer = 0;
- X for ( i = curlayer + 1; i < MAXll; i++ )
- X { if ( ll[i].ll_status == 0 ) continue;
- X goto gotdest;
- X }
- X for ( i = 0; i < curlayer; i++ )
- X { if ( ll[i].ll_status == 0 ) continue;
- X goto gotdest;
- X }
- X printf( "No next layer to be found!\n" );
- X return 0;
- gotdest:
- X gotolayer( &ll[i] );
- X return 1;
- X}
- X
- c_Cset()
- X{ int i;
- X if ( tokcnt != 3 )
- X { printf( "\"Cset layer char\" -- 3 parameters.\n" );
- X return 0;
- X }
- X if ( ( i = findlayer( varg[ 1 ] )) < 0 )
- X { printf( "No such layer %s\n", varg[ 1 ]);
- X return 0;
- X }
- X ll[i].ll_resch = *varg[2];
- X return 0;
- X}
- X
- c_unCset()
- X{ int i;
- X if ( tokcnt != 2 )
- X { printf( "\"unCset layer\" -- 2 parameters.\n" );
- X return 0;
- X }
- X if ( ( i = findlayer( varg[ 1 ] )) < 0 )
- X { printf( "No such layer %s\n", varg[ 1 ]);
- X return 0;
- X }
- X ll[i].ll_resch = -1;
- X return 0;
- X}
- X
- c_equal()
- X{
- X if ( tokcnt < 2 || tokcnt > 3 )
- X { printf( "\"=\" command requires 2 or 3 parameters.\n" );
- X }
- X else if ( ! strcmp( "OPAGE", varg[1] ))
- X { if ( tokcnt == 2 ) xOPAGE[0] = 0;
- X else strcpy( xOPAGE, varg[2] );
- X }
- X else if ( ! strcmp( "CEOP", varg[1] ))
- X { if ( tokcnt == 2 ) xCEOP[0] = 0;
- X else strcpy( xCEOP, varg[2] );
- X }
- X else printf( "\"= CEOP\" or \"= OPAGE\"\n" );
- X return 0;
- X}
- X
- c_sh()
- X{ char * cp;
- X
- X if( cmdbuf[0] == '!' ) cp = cmdbuf + 1;
- X else cp = cmdbuf + 3;
- X mysystem( cp );
- X}
- X
- c_help()
- X{
- printf( "\"auto [+]\" -- toggle autoflip or autoplus mode.\n" );
- printf( "\"create layer\" -- create named layer.\n" );
- printf( "\"delete layer [layer...]\" -- delete named layer[s].\n" );
- printf( "\"Delete layer [layer...]\" -- emphatically delete named layer[s].\n" );
- printf( "\"Forget layer [layer...]\" -- detach named layer[s].\n" );
- printf( "\"list [-l] [layer...]\" -- list the layers.\n" );
- printf( "\"main layer\" -- make layer the \"main layer\".\n" );
- printf( "\"quit\" -- kill all layers and exit.\n" );
- printf( "\"resume layer\" -- resume the named layer.\n" );
- printf( "\"resume\" -- resume the current layer.\n" );
- printf( "\"swtch char\" -- change the swtch character.\n" );
- printf( "\"toggle\" -- resume the alternate layer.\n" );
- printf( "\"Twice\" -- toggles wait-for-two-swtch-characters mode.\n" );
- printf( "\"!command\" or \"sh command\" -- execute command from the control layer.\n" );
- printf( "\"Cset layer char\" -- send x to layer whenever it is resumed.\n" );
- printf( "\"unCset layer\" -- don't send anything to layer when resumed.\n" );
- printf( "\"+\" -- go to next sequential layer.\n" );
- printf( "\"= CEOP string\" -- how to clear to end of screen.\n" );
- printf( "\"= OPAGE string\" -- how to switch display pages.\n" );
- printf( "\">layer file\" -- send file to layer.\n" );
- printf( "\"layer\" -- resume the named layer.\n" );
- X return 0;
- X}
- END_OF_FILE
- if test 12809 -ne `wc -c <'ptycmd.c'`; then
- echo shar: \"'ptycmd.c'\" unpacked with wrong size!
- fi
- # end of 'ptycmd.c'
- fi
- if test -f 'ptyshl.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ptyshl.c'\"
- else
- echo shar: Extracting \"'ptyshl.c'\" \(13837 characters\)
- sed "s/^X//" >'ptyshl.c' <<'END_OF_FILE'
- X/* PORT_CHANGE is a string to search for when porting to a new
- X** system.
- X*/
- X
- X/* Copyright (c) 1990, 1991 Ralph Betza.
- X** Read the file cpyright.h for full copyright information.
- X*/
- X
- X#define Extern
- X
- X#include "ptyshl.h"
- X#include "cpyright.h"
- X#include "patchlevel.h"
- X
- catchsig()
- X{ myexit( 0 );
- X}
- X
- childgone()
- X{ int status;
- X struct layer * L;
- X int i = wait( &status );
- X
- X signal( SIGCLD, childgone );
- X
- X for ( L = ll, i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 )
- X { continue;
- X }
- X if ( kill( L->ll_pid, 0 ) >= 0 ) continue;
- X closelayer( L );
- X }
- X}
- X
- main()
- X{
- X int c;
- X int errcount = 0;
- X char cc;
- X static char Cc[128];
- X
- X initme();
- X
- X ioctl( 0, TCSETA, &ttyset );
- X
- X for ( ;; )
- X {
- X if ( l->ll_status == 0 )
- X { switchme();
- X continue;
- X }
- X
- X nfds = l->ll_ptyfd + 1;
- X xexcpfds = xreadfds = 1 + ( 1 << l->ll_ptyfd );
- X xwrfds = 0;
- X readfds = xreadfds;
- X wrfds = xwrfds;
- X excpfds = xexcpfds;
- X c = select( nfds, &readfds, &wrfds, &excpfds,
- X /* &XX */ NULL ); /* NULL for no timeout. */
- X if ( c > 0 )
- X { errcount = 0;
- X if ( readfds & 1 )
- X { if ( ( c = read( 0, Cc, 128 )) >= 1 )
- X { /* keyboard characters. */
- X if ( c == 1
- X && (Cc[0]&0xff) == (my_swtch_char&0xff) )
- X { /* switch character must arrive
- X ** in isolation.
- X */
- X if ( twicemode )
- X { /* Do not switch until we get two
- X ** swtch characters.
- X */
- X if ( sTwice )
- X { /* This is the second one.
- X */
- X switchme();
- X sTwice = 0;
- X }
- X else
- X { /* This is only the first one.
- X */
- X ++sTwice;
- X }
- X }
- X else
- X { /* switch right away.
- X */
- X switchme();
- X }
- X continue;
- X }
- X else if ( twicemode && sTwice )
- X { /* we got a swtch followed by something
- X ** else. Send swtch char to
- X ** destination.
- X */
- X sTwice = 0;
- X cc = my_swtch_char;
- X write( l->ll_ptyfd, &cc, c );
- X }
- X if ( write( l->ll_ptyfd, Cc, c ) != c )
- X { printf( "parent write to pty %d\n", errno );
- X /* break; */
- X }
- X }
- X else
- X { printf( "parent read stdin %d\n", errno );
- X break;
- X }
- X }
- X else if ( readfds & xreadfds )
- X { c = read( l->ll_ptyfd, Cc, 128 );
- X if ( c > 0 ) write( 1, Cc, c );
- X }
- X else printf( "parent no readfds\n" );
- X }
- X else
- X { if ( errno == EINTR ) errcount = 0;
- X /* EIO happens when we time out? */
- X checklayers();
- X if ( errcount++ > 20 )
- X { printf( "Select errors; errno %d\n", errno );
- X myexit( 0 );
- X }
- X }
- X }
- X myexit( 0 );
- X}
- X
- myexit()
- X{ struct layer * L;
- X int i;
- X
- X L = &ll[0];
- X for ( i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 ) continue;
- X kill( -L->ll_pid, SIGTERM );
- X kill( -L->ll_pid, SIGHUP );
- X }
- X
- X ioctl( 0, TCSETA, &ttysave );
- X exit( 0 );
- X}
- X
- makelayer( name )
- char * name;
- X{ struct layer * L;
- X int i;
- X static char itsnumber[10];
- X static char envbuf[30];
- X
- X if ( ! *name || strlen(name) > 19 )
- X { printf( "Layer needs a name from 1 to 19 characters.\n" );
- X return ( -1 );
- X }
- X
- X L = &ll[0];
- X for ( i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 ) goto foundl;
- X }
- X printf( "too many layers\n" );
- X return ( -1 );
- foundl: /* we found a free layer table entry. */
- X
- X/**********************************************************/
- X/* */
- X/* The following is a real mess. */
- X/* */
- X/* The problem is that the pty devices have different */
- X/* names on different systems. The use of #ifdef to */
- X/* solve it isn't perfect. */
- X/* */
- X/**********************************************************/
- X
- X L->ll_resch = -1;
- X i = 0;
- X#ifndef WHERE
- X/**********************************************************/
- X/* */
- X/* Undefined */
- X/* */
- X/**********************************************************/
- X strcpy( L->ll_ptyname,"/dev/ptyp" );
- X for ( ;; )
- X { /* try to open a pty. */
- X L->ll_ptyname[9] = 0;
- X sprintf( itsnumber, "%d", i++);
- X strcat( L->ll_ptyname, itsnumber );
- X strcpy( L->ll_shortty, "ttyp" );
- X strcat( L->ll_shortty, itsnumber );
- X#else /* } ifndef WHERE */
- X#if ( WHERE == 1 ) /* DG/UX */
- X/**********************************************************/
- X/* */
- X/* ptyp0 to ptyp999 */
- X/* */
- X/**********************************************************/
- X strcpy( L->ll_ptyname,"/dev/ptyp" );
- X for ( ;; )
- X { /* try to open a pty. */
- X L->ll_ptyname[9] = 0;
- X sprintf( itsnumber, "%d", i++);
- X strcat( L->ll_ptyname, itsnumber );
- X strcpy( L->ll_shortty, "ttyp" );
- X strcat( L->ll_shortty, itsnumber );
- X#else /* } WHERE == 1 */
- X#if ( WHERE == 2 ) /* Motorola */
- X/**********************************************************/
- X/* */
- X/* ptyp0 to ptyp9, then ptypa to ptypf, then ptyq0 */
- X/* and so forth. */
- X/* */
- X/**********************************************************/
- X strcpy( L->ll_ptyname,"/dev/ptyp" );
- X for ( ;; )
- X { /* try to open a pty. */
- X L->ll_ptyname[9] = 0;
- X L->ll_ptyname[8] = 'p' + (( i >> 4 ) & 0x0f);
- X sprintf( itsnumber, "%1x", ( i++ ) & 0x0f );
- X strcat( L->ll_ptyname, itsnumber );
- X
- X strcpy( L->ll_shortty, "ttyp" );
- X L->ll_shortty[3] = 'p' + (( i >> 4 ) & 0x0f);
- X strcat( L->ll_shortty, itsnumber );
- X#else /* } WHERE == 2 */
- X/**********************************************************/
- X/* */
- X/* ISC. */
- X/* */
- X/**********************************************************/
- X strcpy( L->ll_ptyname,"/dev/ptyp" );
- X for ( ;; )
- X { /* try to open a pty. */
- X L->ll_ptyname[9] = 0;
- X sprintf( itsnumber, "%d", i++);
- X strcat( L->ll_ptyname, itsnumber );
- X strcpy( L->ll_shortty, "ttyp" );
- X strcat( L->ll_shortty, itsnumber );
- X#endif
- X#endif
- X#endif
- X L->ll_ptyfd = open( L->ll_ptyname, O_RDWR|O_EXCL, 0 );
- X if ( L->ll_ptyfd < 0 )
- X { printf( "failed %s %d\n", L->ll_ptyname, errno );
- X /* PORT_CHANGE number in following line. */
- X if ( i > 64 )
- X { printf( "No pty devices available\n" );
- X return ( -1 );
- X }
- X continue;
- X }
- X break;
- X }
- X /* printf( "opened %s %d\n", L->ll_ptyname, L->ll_ptyfd ); */
- X strcpy( L->ll_ttyname, L->ll_ptyname );
- X L->ll_ttyname[5] = 't';
- X /* PORT_CHANGE number in above line. */
- X
- X ioctl( L->ll_ptyfd, TCSETA, &ttyset );
- X L->ll_status = 1;
- X strcpy( L->ll_llname, name );
- X
- X if ( ( L->ll_pid = fork()) > 0 )
- X { /* Parent process. */
- X lcount++;
- X l = L;
- X if ( ( l - ll ) != curlayer )
- X { oldlayer = curlayer;
- X curlayer = l - ll;
- X }
- X return ( l->ll_ptyfd );
- X }
- X else if ( L->ll_pid < 0 )
- X { printf( "Fork failed! %d\n", errno );
- X return( -1 );
- X }
- X
- X /* Child process. */
- X setpgrp();
- X signal( SIGINT, SIG_DFL );
- X signal( SIGQUIT, SIG_DFL );
- X fclose( stdin );
- X if ( open( L->ll_ttyname, O_RDWR, 0 ) != 0 )
- X { printf( "child open stdin %d\n", errno );
- X exit(1);
- X }
- X if ( fdopen( 0, "r" ) == NULL )
- X { printf( "child fopen stdin %d\n", errno );
- X exit(1);
- X }
- X if ( ioctl( 0, TCSETA, &ttysave ) < 0 )
- X { printf( "child ioctl stdin %d\n", errno );
- X exit(1);
- X }
- X
- X fclose( stdout );
- X dup( 0 );
- X if ( fdopen( 1, "w" ) == NULL )
- X { fprintf( stderr, "child fopen stdout %d\n", errno );
- X exit(1);
- X }
- X
- X fclose( stderr );
- X dup( 0 );
- X if ( fdopen( 2, "w" ) == NULL )
- X { printf( "child fopen stderr %d\n", errno );
- X exit(1);
- X }
- X
- X close( L->ll_ptyfd );
- X
- X strcpy( envbuf, "LAYER=" );
- X strcat( envbuf, L->ll_llname );
- X putenv( envbuf );
- X varg[0] = shellname;
- X varg[1] = "-i";
- X varg[2] = 0;
- X
- X execvp( varg[0], varg );
- X exit( 99 );
- X}
- X
- ttyinit()
- X{
- X ioctl( 0, TCGETA, &ttysave );
- X ioctl( 0, TCGETA, &ttyset );
- X ioctl( 0, TCGETA, &ttycmd );
- X ttyset.c_iflag &= ( BRKINT | IXON | IXANY | IXOFF );
- X ttyset.c_oflag &= ( ~OPOST );
- X ttyset.c_lflag = 0;
- X ttyset.c_cc[VMIN] = 1;
- X ttyset.c_cc[VTIME] = 0;
- X my_swtch_char = ttycmd.c_cc[VSWTCH] & 0xff;
- X if ( my_swtch_char == 0 )
- X { my_swtch_char = ']'&0x1f;
- X printf( "switch character set to ^]\n" );
- X }
- X ttycmd.c_lflag &= ~ISIG;
- X}
- X
- closelayer( L )
- struct layer * L;
- X{ if ( ! L->ll_status ) return;
- X if ( L->ll_ptyfd )
- X { /* note: it can't be zero, that's stdin! */
- X close( L->ll_ptyfd );
- X }
- X L->ll_ptyfd = L->ll_status = 0;
- X if ( lcount > 0 ) lcount--;
- X}
- X
- gotolayer( L )
- struct layer * L;
- X{ char c;
- X int lnumb = L - ll;
- X
- X if ( ! L->ll_status )
- X { printf( "Layer %s has disappeared!\n", L->ll_llname );
- X return;
- X }
- X l = L;
- X printf( "Resuming %s.\n", L->ll_llname );
- X if ( L->ll_resch >= 0 )
- X { c = L->ll_resch;
- X write( L->ll_ptyfd, &c, 1 );
- X }
- X if ( lnumb != curlayer )
- X { oldlayer = curlayer;
- X curlayer = lnumb;
- X }
- X}
- X
- checklayers()
- X{ int i;
- X struct layer * L;
- X
- X for ( L = ll, i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 )
- X { continue;
- X }
- X if ( kill( L->ll_pid, 0 ) >= 0 ) continue;
- X closelayer( L ); /* he's gone! */
- X if ( L == l ) return 1;
- X }
- X return 0;
- X}
- X
- findlayer( name )
- char * name;
- X{ int i;
- X struct layer * L;
- X
- X for ( L = ll, i = 0; i < MAXll; L++, i++ )
- X { if ( L->ll_status == 0 )
- X {
- X continue;
- X }
- X if ( ! strcmp( L->ll_llname, name ))
- X { return i;
- X }
- X }
- X return -1;
- X}
- X
- initme()
- X{ char rcname[100];
- X char * rcbase = ".shlrc";
- X char * homep, *getenv();
- X FILE * rcin;
- X int i;
- X extern char * ttyname();
- X
- X uname( &ununun );
- X mainlayer = oldlayer = curlayer = -1;
- X shellname = getenv( "SHELL" );
- X if ( shellname == NULL ) shellname = "/bin/sh";
- X fstat( 0, &st );
- X if (( homep = ttyname( 0 )) == NULL )
- X { printf( "no tty!\n" );
- X exit( 1 );
- X }
- X strcpy( mytty, homep );
- X strcpy( mybasetty, ( strrchr( mytty, '/' ) + 1 ));
- X strcpy( ustart.ut_line, mybasetty );
- X if (( utmpl = getutline( &ustart )) == NULL )
- X { /* tty must have two names! */
- X setutent();
- X while ((utmpl = getutent()) != NULL)
- X {
- X if (utmpl->ut_type == USER_PROCESS)
- X { char histty[30];
- X strcpy( histty, "/dev/" );
- X strcat( histty, utmpl->ut_line );
- X if (stat( histty, &st1 ) == 0)
- X {
- X if ( st1.st_rdev == st.st_rdev)
- X {
- X strcpy( mybasetty, utmpl->ut_line );
- X goto gotty;
- X }
- X }
- X }
- X }
- X printf( "Can't find tty!\n" );
- X exit ( 1 );
- X }
- gotty:
- X l = ll;
- X signal( SIGCLD, childgone );
- X signal( SIGTERM, catchsig );
- X signal( SIGHUP, catchsig );
- X signal( SIGINT, SIG_IGN );
- X signal( SIGQUIT, SIG_IGN );
- X ttyinit();
- X XX.a = 10;
- X if ( ( rcin = fopen( rcbase, "r" )) != NULL )
- X { goto gotrc;
- X }
- X homep = getenv( "HOME" );
- X if ( homep == NULL ) return;
- X if ( ( strlen( homep ) + strlen( rcbase )) > 97 ) return;
- X strcpy( rcname, homep );
- X strcat( rcname, "/" );
- X strcat( rcname, rcbase );
- X if ( ( rcin = fopen( rcname, "r" )) == NULL ) return;
- gotrc:
- X while ( fgets( cmdbuf, 98, rcin ) != NULL )
- X { c_analyze();
- X }
- X fclose( rcin );
- X}
- X
- switchme()
- X{ /* xOPAGE processing. */
- X int lnumb = l - ll;
- X
- X if ( lnumb == mainlayer && xOPAGE[0] )
- X { /* return from main layer. */
- X printf( "%s", xOPAGE );
- X if ( xCEOP[0] ) printf( "%s", xCEOP );
- X fflush( stdout );
- X }
- X else if ( automode
- X && l->ll_status /* no flip after exit from layer. */
- X && lnumb != mainlayer
- X && mainlayer >= 0
- X && ll[mainlayer].ll_status )
- X { /* automatic flip back to main layer. */
- X oldlayer = lnumb;
- X curlayer = mainlayer;
- X l = &ll[mainlayer];
- X ufake( l->ll_shortty ); /* ??? */
- X if ( xOPAGE[0] ) printf( "%s", xOPAGE );
- X fflush( stdout );
- X return;
- X }
- X else if ( xCEOP[0] )
- X { /* clear to end of page. */
- X printf( "%s", xCEOP );
- X fflush( stdout );
- X }
- X
- X if ( AplusMode
- X && l->ll_status /* no autoplus after exit */
- X && c_plus( ))
- X {
- X return;
- X }
- X
- X docommands();
- X
- after:
- X lnumb = l - ll;
- X if ( lnumb == mainlayer && xOPAGE[0] )
- X printf( "%s", xOPAGE );
- X fflush( stdout );
- X}
- X
- listlayers( longlist, which )
- int longlist; /* boolean usage. */
- int which; /* (which < 0) means "all". */
- X{ int i, j;
- X struct layer * L;
- X char llbuf[80];
- X
- X for ( L = ll, j = i = 0; i < MAXll; L++, i++ )
- X { if ( ! L->ll_status ) continue;
- X if ( which >= 0 && i != which ) continue;
- X if ( longlist | ! j )
- X { printf( " LAYER NAME PID TTY\n" );
- X }
- X j++;
- X sprintf( llbuf,
- X "%20s %5d %s\n",
- X L->ll_llname, L->ll_pid, L->ll_ttyname );
- X if ( i == mainlayer ) llbuf[0] = (automode) ? 'M' : 'm';
- X if ( i == oldlayer ) llbuf[1] = '<';
- X if ( l == L ) llbuf[1] = '>';
- X printf( "%s", llbuf );
- X
- X if ( longlist )
- X { char psbuf[20];
- X sprintf( psbuf, "ps -fg%d", L->ll_pid );
- X mysystem( psbuf );
- X printf( "\n" );
- X }
- X if ( ( j * ((longlist)?5:1)) >= 20 )
- X { printf( "[hit return to continue]" );
- X while ( ( j = getchar()) != EOF && j != '\n' );
- X j = 1;
- X }
- X }
- X if ( ! j ) printf( "No layers\n" );
- X}
- X
- ufake( name )
- char * name;
- X{
- X strcpy( utmpl->ut_line, name );
- X pututline( utmpl );
- X}
- X
- mysystem(s)
- char *s;
- X{
- X int status;
- X int pid;
- X int i;
- X
- X signal(SIGCLD, SIG_DFL);
- X ioctl( 0, TCSETA, &ttysave );
- X
- X if((pid = fork()) == 0)
- X { signal( SIGINT, SIG_DFL );
- X signal( SIGQUIT, SIG_DFL );
- X (void) execl("/bin/sh", "sh", "-c", s, 0);
- X _exit(127);
- X }
- X
- X for (;;)
- X { i = wait(&status);
- X
- X if (i != -1 && i != pid)
- X checklayers();
- X else
- X { signal( SIGCLD, childgone );
- X ioctl( 0, TCSETA, &ttycmd );
- X return;
- X }
- X }
- X}
- X
- docommands()
- X{
- X int i;
- X char * cp;
- X struct layer * L;
- X
- X ioctl( 0, TCSETA, &ttycmd );
- X ufake( mybasetty );
- X errno = 0;
- X for ( ;; )
- X { if ( errno != EINTR ) printf( "%s>>> ", ununun.nodename );
- X checklayers();
- X errno = 0;
- X if ( fgets( cmdbuf, 254, stdin ) == NULL ) continue;
- X if ( c_analyze()) break;
- X }
- leave:
- X checklayers();
- X ioctl( 0, TCSETA, &ttyset );
- X ufake( l->ll_shortty );
- X}
- END_OF_FILE
- if test 13837 -ne `wc -c <'ptyshl.c'`; then
- echo shar: \"'ptyshl.c'\" unpacked with wrong size!
- fi
- # end of 'ptyshl.c'
- fi
- if test -f 'ptyshl.cat1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ptyshl.cat1'\"
- else
- echo shar: Extracting \"'ptyshl.cat1'\" \(19197 characters\)
- sed "s/^X//" >'ptyshl.cat1' <<'END_OF_FILE'
- X PTYSHL(1) PTYSHL(1)
- X
- X NAME
- X ptyshl - shell layer manager
- X
- X SYNOPSIS
- X ptyshl
- X
- X DESCRIPTION
- X Ptyshl allows a user to interact with more than one shell
- X from a single terminal. The user controls these shells,
- X known as layers, using the commands described below.
- X Up to 20 layers are supported; on systems where the
- X number of file descriptors is limited to twenty, the
- X practical limit is somewhat lower.
- X
- X The current layer is the layer that can receive input from
- X the keyboard. Other layers attempting to read from, or
- X write to, the keyboard are blocked. Output from multiple
- X layers is currently not multiplexed onto the terminal; a
- X layer which is not the current layer is blocked if it
- X attempts to write to the terminal.
- X
- X The stty "swtch" character is used to switch control
- X to ptyshl from a layer. If swtch is set to zero when
- X ptyshl is invoked, it gets reset to ^Z. Changing the
- X swtch character (with stty) within a layer has no
- X effect on the ptyshl control layer. Instead, there is
- X a ptyshl command to do this.
- X
- X Ptyshl has its own prompt, "`uname`>>> ", to help
- X distinguish it from a layer. uname is the name of the
- X machine that ptyshl is running on.
- X
- X A layer is a shell that has been bound to a virtual tty
- X device (/dev/pty???). The virtual device can be manipulated
- X like a real tty device using stty(1) and ioctl(2). Each
- X layer has its own process group id.
- X
- X Every layer has a name, which is a sequence of 1 to 19
- X characters chosen by you. The layer name is known within
- X the layer as the value of the $LAYER environment variable.
- X
- X Most commands may be abbreviated to any unambiguous prefix
- X of the command.
- X
- X Basic Usage
- X The "toggle", "resume", and "+" commands are used to
- X go from one layer to another, as follows: inside a
- X layer, you hit the swtch character; ptyshl enters
- X control mode, and presents its prompt; you choose one
- X of these commands, and begin talking to a different
- X shell.
- X
- X Initialization
- X If there is a file named ".shlrc" in the current directory
- X or in your $HOME directory, ptyshl reads this file at
- X startup time and executes the commands it finds therein.
- X Each line of the file should contain one command, and
- X should be no longer than 98 characters. All the normal
- X commands are recognized in the .shlrc file.
- X
- X Environment
- X Two environment variables are used:
- X
- X LAYER
- X Is set by ptyshl to the layer name when a new layer is
- X created. Using "case $LAYER in" in your .kshrc is
- X suggested. The layer name should become part of your
- X shell's PS1 variable.
- X
- X SHELL
- X Is input to ptyshl, and specifies the name of
- X the shell to use when creating new layers or
- X executing shell escapes. If $SHELL is not set,
- X the default shell, /bin/sh, is used.
- X
- X Commands
- X The following commands may be issued from the ptyshl
- X prompt level or from the .shlrc file. Any unique
- X prefix is accepted.
- X
- X auto [+]
- X This command toggles AUTO mode, or if '+' is
- X specified, it toggles AUTOPLUS mode.
- X
- X If AUTO mode is active, when you type the swtch
- X character, if a "main layer" (see "main" command)
- X is defined, and the alternate layer is the main
- X layer, the main layer will be instantly and
- X silently resumed without presenting the ptyshl
- X prompt. Naturally, this is most useful with OPAGE
- X set (see below).
- X
- X If AUTOPLUS mode is active, when you type the
- X swtch character, a '+' command is done
- X automatically. The only way you can get back to
- X ptyshl command mode from AUTOPLUS mode is by
- X exiting from a layer.
- X
- X create name
- X Create a layer called "name" and make it the
- X current layer. If a layer already exists by that
- X name, it will be resumed instead. A maximum of
- X 20 layers may be created; ptyshl will run out of
- X file descriptors on some systems before it can
- X create 20 layers.
- X
- X delete name [ name ... ]
- X For each name, delete the corresponding layer.
- X All processes in the process group of the layer
- X are sent the SIGTERM and SIGHUP signals (see
- X signal(2)). These layers remain active until the
- X processes terminate.
- X
- X The normal way to end a layer is either to use
- X the "delete" command or to type ^D at the shell
- X prompt within the layer.
- X
- X Delete name [ name ... ]
- X Send SIGKILL to each layer and "forget" the
- X layer without waiting for its processes to
- X terminate.
- X
- X This can be useful if a process inside a layer
- X freezes and can't be killed.
- X
- X Forget name [ name ... ]
- X Send no signal to the layer, and forget it ever
- X existed.
- X
- X Do not do this to an interactive shell; it is
- X only to be used for processes created by (for
- X example) "exec make > make.out 2>&1".
- X
- X Attach name
- X
- X Attempt to reconnect to a layer on which Forget
- X was used. Not even one version of UNIX System
- X V.3.2 permits this command to work, however.
- X
- X help (or ?)
- X Print the syntax of the ptyshl commands.
- X
- X list [ -l ] [ name ... ]
- X For each name, list the layer name and its
- X process group. The -l option produces a
- X ps(1)-like listing. If no arguments are given,
- X information is presented for all existing
- X layers.
- X
- X The first two characters of the line that gives
- X the layer name have the following meanings:
- X - m in column 1 means that this layer is the
- X main layer and that the "auto" flag is off.
- X - M in column 1 means that this layer is the
- X main layer and that the "auto" flag is on.
- X - > in column 2 means that this is the most current
- X layer (the target of the "resume" command).
- X - < in column 2 means that this is the alternate
- X layer, the target of the "toggle" command.
- X
- X main [ name ]
- X Make the layer referenced by name the main
- X layer. If a main layer is defined, and if the
- X OPAGE sequence is defined, ptyshl will toggle
- X the display from one page to another so that one
- X page will be reserved for the main layer, and
- X the other page will be used for ptyshl prompts
- X and commands, as well as all other layers.
- X
- X This works well if your terminal has two pages
- X of display memory and a command that toggles
- X between them.
- X
- X The "main", "auto", and "= OPAGE" commands are
- X all part of the implementation of the same idea.
- X
- X main -
- X Specify that there is no main layer.
- X
- X resume [ name ]
- X Make the layer referenced by name the current
- X layer. If no argument is given, the last
- X existing current layer will be resumed.
- X
- X Remember, all commands can be abbreviated:
- X this is simply "r".
- X
- X swtch char
- X Use char as the swtch character from now on.
- X
- X toggle
- X Resume the layer that was current before the last
- X current layer.
- X
- X Remember, all commands can be abbreviated:
- X this is simply "t".
- X
- X Twice
- X Toggle a mode that specifies, if set, that
- X switching requires two occurrences of the swtch
- X character. The first time you type ^Z (or
- X whatever your swtch character is), nothing
- X happens; if the next character is also ^Z, you
- X switch layers, but if it is anything else, ^Z is
- X sent to the current layer.
- X
- X Either this facility or the "Cset" command or
- X the "swtch" command can be used as an awkward
- X means of sending the swtch command to a layer. An
- X awkward means is better than none at all.
- X
- X quit
- X Exit ptyshl. All layers are sent the SIGHUP signal.
- X The "quit" command must be spelled out completely.
- X
- X name
- X Make the layer referenced by name the current
- X layer, and resume it. If what you type is not
- X recognized as a command, ptyshl tries to see if
- X it matches the name of a layer.
- X
- X +
- X Make the next layer the current layer and resume
- X it. "Next" is defined by incrementing the
- X internal index to the layer table, like "next
- X session" in te3279 or the ":n" command in vi.
- X
- X !command
- X sh command
- X Executes the command from the control layer. A
- X background process created in this way can write
- X to the screen while you are in a layer.
- X
- X Cset name char
- X Whenever the named layer is resumed, unless it
- X is the "main" layer, the character "char" will
- X be sent to it. Usually, "char" is ^L (you type
- X control-L, not a '^' followed by an 'L'): the
- X idea is that the layer is executing a
- X full-screen editor, and you want the editor to
- X redraw the screen as soon as you resume that
- X layer!
- X
- X This facility is primitive and experimental, but
- X very useful. It makes ptyshl seem more like
- X PowerPorts. Friendlier ways of specifying "char"
- X would be possible.
- X
- X unCset name
- X Turns off Cset mode for this layer.
- X
- X = CEOP string
- X CEOP == "clear to end of page". If CEOP is
- X defined, ptyshl sends it to the terminal before
- X it sends its prompt. Otherwise, the prompt may
- X appear in the middle of a cluttered screen.
- X
- X This command should be placed in your .shlrc
- X file.
- X
- X = OPAGE string
- X OPAGE == "other page". If OPAGE is defined,
- X ptyshl will use it to keep one page of your
- X terminal's display memory reserved for nothing
- X else but the "main" layer.
- X
- X #comment
- X Comment lines and blank lines are permitted.
- X
- X > name filename
- X filename is opened and sent to the named layer as
- X though you had typed it.
- X
- X Don't use big files! Go to the layer right away,
- X so its output can come out!
- X
- X This is an excellent facility, if used with care.
- X In effect, it provides a "." or ":source" command
- X for any program whatsoever.
- X
- X FILES
- X /dev/ttyp*
- X /dev/ptyp* Virtual tty devices
- X The exact name differs from one system to
- X another.
- X
- X SEE ALSO
- X sh(1), stty(1), pty(4), pty(7), shl(1)
- X ioctl(2), signal(2) in the UNIX System Programmer Reference
- X Manual.
- X
- X CAUTIONS
- X ptyshl is different from shl. In shl, the sxt driver
- X in the kernel performs the multiplexing of many
- X pseudoterminals into a single real tty port; in
- X ptyshl, the ptyshl program itself must continually
- X read from your keyboard and read from the master side
- X of the currently-active pty device. This is why using
- X stty to change the swtch character within a layer
- X doesn't work; this is also true of the versions of
- X shl that are implemented using pty instead of sxt (DG
- X and HP versions).
- X
- X The above difference means that no program can
- X disable switching back to the ptyshl control layer
- X when you type the swtch character, and therefore
- X there is no convenient way to send the swtch
- X character to a layer. There are three inconvenient
- X ways; one is to use the Cset facility, another is
- X to use the Twice facility, another is to change to a
- X different swtch character. In shl, "stty -isig" (or
- X the corresponding ioctl call) disables the swtch
- X character; many programs, such as "rlogin", do this,
- X and are therefore inconvenient to use with shl.
- X
- X Exiting ptyshl causes a hangup signal (SIGHUP) to be
- X sent to the process group of each existing layer.
- X This normally results in the cleanup of each layer's
- X processes, after which the set of virtual terminals
- X is available for use by another user. There are,
- X however, two cases in which, because a process
- X remains attached to a virtual terminal even after
- X ptyshl is exited, the set of virtual terminals will
- X not be immediately freed. A process nohup'd in a
- X layer remains attached to the virtual terminal if
- X standard input, output, or error is redirected to the
- X specific virtual terminal, as in the command line
- X
- X nohup who > /dev/ttyp1
- X
- X The same is true if SIGHUP is ignored in the shell
- X (e.g., via the command trap ' ' 1) before the process
- X is spawned. Both cases cause the set of virtual
- X terminals to be tied up until the process exits.
- X
- X The system does not clean up if ptyshl is killed with
- X SIGKILL (kill -9). The user may be left in a state
- X that will require disconnecting and logging back on.
- X In addition, the shell layer processes will continue
- X to run until they are explicitly killed or the system
- X rebooted. Users wishing to kill ptyshl should not use
- X SIGKILL.
- X
- X "who" will show that you are logged in on the pty
- X device of your current layer, and not on any of the
- X others. This is done by fiddling with /etc/utmp. If
- X you're not root, this may not work.
- X
- X Ptyshl reads characters in bursts, but the swtch
- X character must arrive all by itself (as the sole
- X character returned by a read() system call) if it is
- X to be interpreted correctly. This means that attempts
- X to embed it in a function key may fail.
- X
- X ENHANCEMENTS
- X
- X This version of ptyshl has been enhanced from the standard
- X UNIX version of shl.
- X
- X The layer name is in the LAYER variable instead of the PS1
- X variable, because ksh wants to adjust PS1 itself, and to
- X have a clean copy of the layer name (shl appends a blank to
- X the layer name and sets PS1 to the result) for use
- X in .kshrc, and to have a clear indication of whether the
- X current shell is a login shell, the top shell in a layer,
- X or a subshell in a layer. The absence of a value for LAYER
- X means you are not in a layer. In .kshrc, if LAYER is set to
- X some particular name, this might provoke some particular
- X action: for example, layer name "medusa" might deserve "rlogin
- X medusa".
- X
- X Screen control is provided via two environment variables,
- X OPAGE and CEOP. OPAGE is a step towards having shl behave
- X like PowerPorts, and is the best that can be done for a
- X terminal that has only two pages of display memory.
- X
- X The "main" and "auto" commands are added. The idea of a
- X "main" level is tied in with the OPAGE variable: one page
- X of the terminal's display memory is to be used for the main
- X level, and for nothing else. The "auto" command allows you
- X to switch from the main level to some other, then return by
- X merely striking the swtch key. It would be nice to toggle
- X back and forth between two layers; the only way out of the
- X toggle loop would be to exit one of the layers (^D to its
- X shell) -- "auto" is a more controlled form of this.
- X
- X Shell escapes from ptyshl itself are an idea taken from the
- X HP version of shl.
- X
- X The Cset command would not be possible to implement using
- X the sxt pseudodevice.
- X
- X USAGE NOTES
- X
- X Layer names can be used as a form of communication
- X between .shlrc and .kshrc; ptyshl looks for ./.shlrc,
- X therefore you can also have several versions of your .shlrc
- X file.
- X
- X NOTE: to avoid trouble with subshells from your layers, you
- X need to follow a standard:
- X
- X if [ "" = "$LAYER" ]
- X then # not in ptyshl; this is a login shell or subshell
- X else # this is a layer
- X PS1="$LAYER(!): "
- X if [ "" != "$INSHL" ]
- X then # this is a subshell in a layer
- X : no actions.
- X else # this is the main shell of a layer
- X INSHL=y;export INSHL
- X if [ "" != "`grep $LAYER /etc/hosts.equiv`" ]
- X then
- X # if the layer name is the name of a machine
- X # on the network, rlogin to it.
- X exec rlogin $LAYER -l $LOGNAME
- X fi
- X case $LAYER in
- X te)
- X gg=/u1/te-api-2; export gg
- X CDPATH=:..:$gg/process:$gg:$gg/generic:$HOME
- X export CDPATH
- X cd s.q
- X ;;
- X ....and so forth
- X
- X A layer is therefore a task-oriented invocation of your
- X shell. One common use is to have several layers reserved
- X for working on specific different things on the same
- X machine as ptyshl; another is to have several layers
- X defined as rlogins (layer "toro" does an rlogin to toro,
- X and so forth).
- X
- X LOCATIONS
- X
- X ptyshl requires pty devices and the select() call from the
- X C library; it requires System V.3 pty devices, not V.4 "pts"
- X devices.
- X
- X It can be run on DGUX, HPUX, all Motorola machines, or
- X Interactive or ESIX 80386 Unix machines.
- X
- X There is a chance it would work on SUN machines. The tty code
- X would need to be Berkeley-ized. The "jobs" facility of the
- X ksh used there renders ptyshl rather unnecessary in
- X Berkeley environments.
- X
- X On Pyramid, ptyshl compiles and runs, but the pty devices act
- X as though "stty -opost" were in effect.
- X
- X It won't run on SCO unix, of course.
- END_OF_FILE
- if test 19197 -ne `wc -c <'ptyshl.cat1'`; then
- echo shar: \"'ptyshl.cat1'\" unpacked with wrong size!
- fi
- # end of 'ptyshl.cat1'
- fi
- if test -f 'ptyshl.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ptyshl.h'\"
- else
- echo shar: Extracting \"'ptyshl.h'\" \(1389 characters\)
- sed "s/^X//" >'ptyshl.h' <<'END_OF_FILE'
- XExtern char cmdbuf[256];
- XExtern char tokbuf[256];
- XExtern char * SysName;
- XExtern char xCEOP[99];
- XExtern char xOPAGE[99];
- XExtern char mytty[30];
- XExtern char mybasetty[30];
- XExtern int twicemode;
- XExtern int sTwice;
- XExtern int my_swtch_char;
- XExtern int automode;
- XExtern int AplusMode;
- XExtern int mainlayer;
- XExtern int oldlayer;
- XExtern int curlayer;
- X#define MAXARG 10
- XExtern char * varg[MAXARG];
- X /* varg used for exec and for c_analyze. */
- XExtern char *shellname;
- XExtern int nfds;
- XExtern long xreadfds, readfds, xwrfds, wrfds, xexcpfds, excpfds;
- XExtern struct
- X{ long a; long b;
- X} XX;
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X/* types.h here for portability */
- X#include <fcntl.h>
- X#include <termio.h>
- X#include <sys/ioctl.h>
- X#include <signal.h>
- X#include <utmp.h>
- X#include <sys/stat.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <sys/utsname.h>
- XExtern struct utsname ununun;
- XExtern struct stat st, st1;
- XExtern struct utmp ustart, *utmpl;
- XExtern struct utmp *getutent();
- XExtern struct utmp *getutline();
- void setutline();
- XExtern struct termio ttysave, ttyset, ttycmd;
- extern int errno;
- X
- X#define MAXll 20
- XExtern struct layer
- X{ int ll_pid;
- X int ll_ptyfd;
- X int ll_status;
- X int ll_resch;
- X char ll_ttyname[20], ll_ptyname[20], ll_shortty[10];
- X char ll_llname[20]; /* layer name. */
- X} ll[MAXll];
- XExtern int lcount;
- XExtern struct layer * l;
- X
- X#ifndef VSWTCH
- X#define VSWTCH 7 /* HP */
- X#endif
- END_OF_FILE
- if test 1389 -ne `wc -c <'ptyshl.h'`; then
- echo shar: \"'ptyshl.h'\" unpacked with wrong size!
- fi
- # end of 'ptyshl.h'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-