home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / ptyshl < prev    next >
Encoding:
Text File  |  1992-04-15  |  57.7 KB  |  2,039 lines

  1. Newsgroups: comp.sources.unix
  2. From: ssiny!gnohmon@uunet.uu.net (Ralph Betza)
  3. Subject: v26i008: ptyshl - shell layers via pseudo-ttys
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: ssiny!gnohmon@uunet.uu.net (Ralph Betza)
  8. Posting-Number: Volume 26, Issue 8
  9. Archive-Name: ptyshl
  10.  
  11. ptyshl is a vastly enhanced replacement for shl, extensively used for 3
  12. years (therefore well-tested), should compile and run with no problems on
  13. any SysV.3 UNIX machine ( see README ).
  14.  
  15.     ssiny!gnohmon@uunet.uu.net (Ralph Betza)
  16.  
  17. PS: It may be that it doesn't work on tty ports of some systems.
  18.     Most of the systems that I used ptyshl on, I got to with rlogins.
  19.  
  20. [ I renamed a couple of files and generalized the Makefile.  --vix ]
  21.  
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line, then unpack
  24. # it by saving it into a file and typing "sh file".  To overwrite existing
  25. # files, type "sh file -c".  You can also feed this as standard input via
  26. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  27. # will see the following message at the end:
  28. #        "End of archive 1 (of 1)."
  29. # Contents:  MANIFEST Makefile README cpyright.h findselect makeall
  30. #   patchlevel.h ptycmd.c ptyshl.c ptyshl.cat1 ptyshl.h
  31. # Wrapped by vixie@cognition.pa.dec.com on Thu Apr 16 23:21:44 1992
  32. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  33. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  34.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  35. else
  36. echo shar: Extracting \"'MANIFEST'\" \(455 characters\)
  37. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  38. X   File Name        Archive #    Description
  39. X-----------------------------------------------------------
  40. X MANIFEST                   1    This shipping list
  41. X Makefile                   1    
  42. X README                     1    
  43. X cpyright.h                 1    
  44. X findselect                 1    
  45. X makeall                    1    
  46. X patchlevel.h               1    
  47. X ptycmd.c                   1    
  48. X ptyshl.c                   1    
  49. X ptyshl.cat1                1    
  50. X ptyshl.h                   1    
  51. END_OF_FILE
  52. if test 455 -ne `wc -c <'MANIFEST'`; then
  53.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  54. fi
  55. # end of 'MANIFEST'
  56. fi
  57. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  58.   echo shar: Will not clobber existing file \"'Makefile'\"
  59. else
  60. echo shar: Extracting \"'Makefile'\" \(513 characters\)
  61. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  62. DESTROOT =
  63. DESTPATH = $(DESTROOT)/usr/local
  64. DESTBIN = $(DESTPATH)/bin
  65. DESTMAN = $(DESTPATH)/man
  66. X
  67. all: ptyshl
  68. X
  69. install: ptyshl ptyshl.cat1
  70. X    install -c ptyshl $(DESTBIN)/ptyshl
  71. X    install -c ptyshl.cat1 $(DESTMAN)/cat/cat1/ptyshl.1
  72. X
  73. clean:
  74. X    rm -f *.BAK *.CKP *~ *.o
  75. X    rm -f core ptyshl ptyshl.orig
  76. X
  77. WHERE = 2
  78. X
  79. ptyshl:    ptyshl.o ptycmd.o
  80. X    -mv -f ptyshl ptyshl.orig
  81. X    cc -g -o ptyshl ptyshl.o ptycmd.o -linet
  82. X
  83. ptyshl.o:    ptyshl.c ptyshl.h
  84. X    cc -g -c -DWHERE=$(WHERE) ptyshl.c
  85. X
  86. ptycmd.o:    ptycmd.c ptyshl.h
  87. X    cc -g -c ptycmd.c
  88. END_OF_FILE
  89. if test 513 -ne `wc -c <'Makefile'`; then
  90.     echo shar: \"'Makefile'\" unpacked with wrong size!
  91. fi
  92. # end of 'Makefile'
  93. fi
  94. if test -f 'README' -a "${1}" != "-c" ; then 
  95.   echo shar: Will not clobber existing file \"'README'\"
  96. else
  97. echo shar: Extracting \"'README'\" \(1709 characters\)
  98. sed "s/^X//" >'README' <<'END_OF_FILE'
  99. This is a greatly enhanced version of the UNIX "shl" program,
  100. that uses the pty device found in System V.3 instead of the
  101. sxt or vsxt device used by shl.
  102. X
  103. The sxt or vsxt device doesn't work unless you're on a real TTY
  104. port; therefore, shl doesn't work.
  105. X
  106. ptyshl works on all UNIX System V.3 machines, whether you're on a
  107. real tty port or on a pseudotty from rlogin.
  108. X
  109. note: SCO UNIX is NOT UNIX!
  110. X
  111. If you use character terminals, this program will greatly enhance
  112. your lifestyle. You will find it to be extremely solid and
  113. bug-free; I used it extensively for three years!
  114. X
  115. It should compile and run right out of the box, if you just get
  116. two things right in the makefile:
  117. X
  118. The first thing is that you need the select() call from one of
  119. the system libraries. If you have pty devices, you have select()
  120. in some library. The "findselect" shell script in this directory
  121. will help you with this. Change the makefile if you must.
  122. X
  123. The second thing is that pty devices have different names on
  124. different systems. The WHERE variable set up in the makeall
  125. script takes care of this. Read ptyshl.c if in doubt.
  126. X
  127. After you have ptyshl running, you may need to reconfigure your
  128. kernel to make more pty devices than you now have.
  129. X
  130. I haven't ported it to SysV.4 because I have X now...
  131. X
  132. Send comments or flames to:
  133. X
  134. X-Ralph Betza (FM),                       Disclaimer: opinions
  135. X Systems Strategies Inc,                 presented here have
  136. X 225 West 34th Street, NY NY  10001,     been changed to protect
  137. X 1-212-279 8400                          the innocence.
  138. X uunet!ssiny!gnohmon
  139. X
  140. Sono un viro. Dai, coppiami nel tuo .signature.
  141. Ich bin ein Virus. Mach' mit und kopiere mich in Deine .signature.
  142. X
  143. XFri Dec 13 11:31:34 EST 1991
  144. END_OF_FILE
  145. if test 1709 -ne `wc -c <'README'`; then
  146.     echo shar: \"'README'\" unpacked with wrong size!
  147. fi
  148. # end of 'README'
  149. fi
  150. if test -f 'cpyright.h' -a "${1}" != "-c" ; then 
  151.   echo shar: Will not clobber existing file \"'cpyright.h'\"
  152. else
  153. echo shar: Extracting \"'cpyright.h'\" \(1324 characters\)
  154. sed "s/^X//" >'cpyright.h' <<'END_OF_FILE'
  155. X#ifndef _COPYRIGHT_
  156. X#define _COPYRIGHT_
  157. X/*========================================================================
  158. X*
  159. X* Name - cpyright.h
  160. X*
  161. X* Version:    1.0
  162. X*
  163. X* Description: copyright information for ptyshl
  164. X*
  165. X*========================================================================
  166. X*
  167. X* Copyright (C) 1990, 1991 Ralph Betza
  168. X*
  169. X* Permission to use, copy, modify, distribute, and sell this software
  170. X* and its documentation for any purpose is hereby granted without fee,
  171. X* provided that the above copyright notice appear in all copies and
  172. X* that both that copyright notice and this permission notice appear
  173. X* in supporting documentation.  The author makes no representations
  174. X* about the suitability of this software for any purpose.  It is
  175. X* provided "as is" without express or implied warranty.
  176. X*
  177. X* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  178. X* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
  179. X* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  180. X* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
  181. X* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  182. X* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
  183. X* USE OR PERFORMANCE OF THIS SOFTWARE.
  184. X*/
  185. X
  186. static char *Copyright = "Copyright (C) 1990, 1991 Ralph Betza";
  187. X#endif
  188. X
  189. X
  190. END_OF_FILE
  191. if test 1324 -ne `wc -c <'cpyright.h'`; then
  192.     echo shar: \"'cpyright.h'\" unpacked with wrong size!
  193. fi
  194. # end of 'cpyright.h'
  195. fi
  196. if test -f 'findselect' -a "${1}" != "-c" ; then 
  197.   echo shar: Will not clobber existing file \"'findselect'\"
  198. else
  199. echo shar: Extracting \"'findselect'\" \(82 characters\)
  200. sed "s/^X//" >'findselect' <<'END_OF_FILE'
  201. cd /usr/lib
  202. for ff in *.a
  203. do
  204. X    echo $ff $ff $ff $ff $ff
  205. X    nm $ff | grep select
  206. done
  207. END_OF_FILE
  208. if test 82 -ne `wc -c <'findselect'`; then
  209.     echo shar: \"'findselect'\" unpacked with wrong size!
  210. fi
  211. chmod +x 'findselect'
  212. # end of 'findselect'
  213. fi
  214. if test -f 'makeall' -a "${1}" != "-c" ; then 
  215.   echo shar: Will not clobber existing file \"'makeall'\"
  216. else
  217. echo shar: Extracting \"'makeall'\" \(283 characters\)
  218. sed "s/^X//" >'makeall' <<'END_OF_FILE'
  219. set -x
  220. case `uname -n` in
  221. X# the following system names are good for my network, but not for
  222. X# yours, so change them!
  223. iceman)
  224. X    WHERE=1
  225. X# Data General
  226. X    ;;
  227. ssiny|lefty)
  228. X# Motorola
  229. X    WHERE=2
  230. X    ;;
  231. X*)
  232. X# ISC or ESIX or most others.
  233. X    WHERE=3
  234. X    ;;
  235. esac
  236. X
  237. make 'WHERE = '$WHERE > makeall.out 2>&1
  238. END_OF_FILE
  239. if test 283 -ne `wc -c <'makeall'`; then
  240.     echo shar: \"'makeall'\" unpacked with wrong size!
  241. fi
  242. chmod +x 'makeall'
  243. # end of 'makeall'
  244. fi
  245. if test -f 'patchlevel.h' -a "${1}" != "-c" ; then 
  246.   echo shar: Will not clobber existing file \"'patchlevel.h'\"
  247. else
  248. echo shar: Extracting \"'patchlevel.h'\" \(88 characters\)
  249. sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE'
  250. X/*
  251. X * p a t c h l e v e l . h
  252. X */
  253. X
  254. static char version[] = " version 1 patchlevel 0: ";
  255. END_OF_FILE
  256. if test 88 -ne `wc -c <'patchlevel.h'`; then
  257.     echo shar: \"'patchlevel.h'\" unpacked with wrong size!
  258. fi
  259. # end of 'patchlevel.h'
  260. fi
  261. if test -f 'ptycmd.c' -a "${1}" != "-c" ; then 
  262.   echo shar: Will not clobber existing file \"'ptycmd.c'\"
  263. else
  264. echo shar: Extracting \"'ptycmd.c'\" \(12809 characters\)
  265. sed "s/^X//" >'ptycmd.c' <<'END_OF_FILE'
  266. X#define Extern extern
  267. X#include "ptyshl.h"
  268. X#include "cpyright.h"
  269. X#include "patchlevel.h"
  270. X/* Copyright (c) 1990, 1991 Ralph Betza.
  271. X** Read the file cpyright.h for full copyright information.
  272. X*/
  273. X
  274. int c_auto(), c_create(), c_delete(), c_Delete(), c_list(),
  275. X    c_main(), c_quit(), c_resume(), c_toggle(), c_Cset(),
  276. X    c_unCset(), c_equal(), c_sh(), c_help(), c_twice(),
  277. X    c_plus(), c_swtch(), c_Forget(), c_Attach(),
  278. X    c_SendFile();
  279. X/* These commands return 1 if they switch to a new layer
  280. X** and we should go into layer-mode,
  281. X** or they return 0 if we should stay in control-mode.
  282. X*/
  283. X
  284. struct cmdtab
  285. X{    char * cmdname;        /* The name of the command. */
  286. X    int (*cmdval)();    /* The function that executes this command. */
  287. X    int cmdexcp;
  288. X        /* exceptions:
  289. X        ** 1 == must be spelled out
  290. X        ** 2 == needs no blank after 1st char
  291. X        */
  292. X    int cmdlen;            /* strlen( cmdname ), filled in by c_init(). */
  293. X} Cmd[] =
  294. X{
  295. X    {    "auto", c_auto },
  296. X    {    "Attach", c_Attach },    /* doesn't work on ANY system. */
  297. X    {    "create", c_create },
  298. X    {    "delete", c_delete },
  299. X    {    "Delete", c_Delete },
  300. X    {    "Forget", c_Forget },
  301. X    {    "list", c_list },
  302. X    {    "main", c_main },
  303. X    {    "quit", c_quit, 1 },
  304. X    {    "resume", c_resume },
  305. X    {    "swtch", c_swtch },
  306. X    {    "toggle", c_toggle },
  307. X    {    "Twice", c_twice },
  308. X    {    "Cset", c_Cset },
  309. X    {    "unCset", c_unCset },
  310. X    {    "=", c_equal },
  311. X    {    "+", c_plus },
  312. X    {    "sh", c_sh },
  313. X    {    "!", c_sh, 2 },
  314. X    {    "?", c_help, 2 },
  315. X    {    "help", c_help },
  316. X    {    ">", c_SendFile, 2 },
  317. X    {    "" }
  318. X};
  319. X
  320. int cmdonce;
  321. int tokcnt;
  322. int inlen;
  323. X
  324. c_init()
  325. X{    struct cmdtab * C;
  326. X    for ( C = Cmd; C->cmdname[0]; C++ )
  327. X    {    C->cmdlen = strlen( C->cmdname );
  328. X    }
  329. X    cmdonce = 1;
  330. X}
  331. X
  332. c_analyze()
  333. X{    /* input in cmdbuf. retval 0 to continue the loop. */
  334. X    int i;
  335. X    struct cmdtab * C;
  336. X    struct layer * L;
  337. X
  338. X    if ( ! cmdonce ) c_init();
  339. X    strcpy( tokbuf, cmdbuf );
  340. X    varg[0] = strtok( tokbuf, " \t\n" );
  341. X    if ( varg[0] == NULL || *varg[0] == '#' ) return 0;
  342. X    for ( tokcnt = 1;
  343. X        tokcnt < MAXARG
  344. X        &&
  345. X        ( varg[tokcnt] = strtok( NULL, " \t\n" )) != NULL;
  346. X        tokcnt++ )
  347. X        ;
  348. X
  349. X    inlen = strlen( varg[ 0 ]);
  350. X
  351. X    for ( C = Cmd; C->cmdname[0]; C++ )
  352. X    {    /* check every table entry. */
  353. X        switch ( C->cmdexcp )
  354. X        {    /* exception condition. */
  355. X            case 0:
  356. X            {    /* Normal. */
  357. X                if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
  358. X                {    goto gotcmd;
  359. X                }
  360. X                continue;
  361. X            }
  362. X            case 1:
  363. X            {    /* Must say the whole thing. */
  364. X                if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
  365. X                {    if ( inlen != C->cmdlen )
  366. X                    {    printf(
  367. X                            "Command \"%s\" must be spelled out in full\n",
  368. X                            C->cmdname );
  369. X                        return 0;
  370. X                    }
  371. X                    goto gotcmd;
  372. X                }
  373. X                continue;
  374. X            }
  375. X            case 2:
  376. X            {    /* Need no blank after command. */
  377. X                if ( ! strncmp( varg[ 0 ], C->cmdname, inlen ))
  378. X                {    goto gotcmd;
  379. X                }
  380. X                if ( ! strncmp( varg[ 0 ], C->cmdname, C->cmdlen ))
  381. X                {    goto gotcmd;
  382. X                }
  383. X                continue;
  384. X            }
  385. X        }    /* end switch on command. */
  386. X    }    /* end command loop. */
  387. X
  388. X    if ( tokcnt == 1 && ( i = findlayer( varg[ 0 ])) >= 0 )
  389. X    {    /* A layer name, all by itself, is a request to resume that
  390. X        ** layer.
  391. X        */
  392. X        gotolayer( &ll[ i ]);
  393. X        return 1;
  394. X    }
  395. X    printf(
  396. X        "unrecognized command \"%s\" (try ? for help)\n",
  397. X        varg[ 0 ]);
  398. X    return 0;
  399. X
  400. gotcmd:
  401. X    if ( inlen < C->cmdlen && findlayer( varg[ 0 ] ) >= 0 )
  402. X    {    /* check for ambiguity. */
  403. X        printf( "Command \"%s\" is ambiguous\n", varg[ 0 ]);
  404. X        return 0;
  405. X    }
  406. X    return ((*C->cmdval)());
  407. X}
  408. X
  409. c_auto()
  410. X{    if ( tokcnt == 2 && ! strcmp( varg[ 1 ], "+" ))
  411. X    {    AplusMode ^= 1;
  412. X        printf( "AUTOPLUS mode is %s.\n",
  413. X            (AplusMode) ? "on" : "off" );
  414. X        return 0;
  415. X    }
  416. X    automode ^= 1;
  417. X    printf( "AUTO flip mode is %s.\n",
  418. X        (automode) ? "on" : "off" );
  419. X    return 0;
  420. X}
  421. X
  422. c_create()
  423. X{    /* Create a layer. */
  424. X    int i;
  425. X
  426. X    if ( tokcnt != 2 )
  427. X    {    printf( "\"create\" command requires one parameter\n" );
  428. X        return 0;
  429. X    }
  430. X
  431. X    if ( ( i = findlayer( varg[ 1 ])) >= 0 )
  432. X    {    printf( "Layer already exists; resuming it.\n" );
  433. X        gotolayer( &ll[i] );
  434. X        return 1;
  435. X    }
  436. X    if ( makelayer( varg[ 1 ]) >= 0 )
  437. X    {    ufake( l->ll_shortty );
  438. X        return 1;
  439. X    }
  440. X    return 0;
  441. X}
  442. X
  443. c_Attach()
  444. X{    /* Connect to a layer. */
  445. X    struct layer * L;
  446. X    int i;
  447. X    char * cp;
  448. X
  449. X    if ( tokcnt != 3 )
  450. X    {    printf( "\"attach\" command requires three parameters\n" );
  451. X        return 0;
  452. X    }
  453. X
  454. X    if ( ( i = findlayer( varg[ 1 ])) >= 0 )
  455. X    {    printf( "Layer already exists; resuming it.\n" );
  456. X        gotolayer( &ll[i] );
  457. X        return 1;
  458. X    }
  459. X
  460. X    L = &ll[0];
  461. X    for ( i = 0; i < MAXll; L++, i++ )
  462. X    {    if ( L->ll_status == 0 ) goto foundl;
  463. X    }
  464. X    printf( "No free layers\n" );
  465. X    return ( 0 );
  466. foundl:        /* we found a free layer table entry. */
  467. X
  468. X
  469. X    L = &ll[i];
  470. X    varg[1][19] = 0;
  471. X    strcpy( L->ll_llname, varg[ 1 ]);
  472. X        /* Layer name. */
  473. X
  474. X    L->ll_ttyname[0] = L->ll_ptyname[0] = L->ll_shortty[0] = 0;
  475. X    if ( *varg[2] != '/' )
  476. X    {    /* add "/dev/" */
  477. X        if ( strlen( varg[2]) > 9 )
  478. X        {    printf( "\ntty name too long, \"%s\".\n", varg[2] );
  479. X            return 0;
  480. X        }
  481. X
  482. X        strcpy( L->ll_ptyname, "/dev/" );
  483. X        varg[2][0] = 'p';
  484. X        strcat( L->ll_ptyname, varg[ 2 ]);
  485. X
  486. X        strcpy( L->ll_ttyname, "/dev/" );
  487. X        varg[2][0] = 't';
  488. X        strcat( L->ll_ttyname, varg[ 2 ]);
  489. X
  490. X        strcpy( L->ll_shortty, varg[ 2 ]);
  491. X    }
  492. X    else
  493. X    {
  494. X        if ( strlen( varg[2]) > 20 )
  495. X        {    printf( "\ntty name too long, \"%s\".\n", varg[2] );
  496. X            return 0;
  497. X        }
  498. X
  499. X        cp = varg[2];
  500. X        for (;;)
  501. X        {    /* Find pty name. */
  502. X            ++cp;
  503. X            if ( ! *cp )
  504. X            {    printf( "\nmalformed tty name.\n" );
  505. X                return 0;
  506. X            }
  507. X            if ( *cp == '/' )
  508. X            {    /* here it is. */
  509. X                ++cp;
  510. X                break;
  511. X            }
  512. X        }
  513. X        if ( strlen( cp) > 9 )
  514. X        {    printf( "\ntty name too long, \"%s\".\n", cp );
  515. X            return 0;
  516. X        }
  517. X        *cp = 't';
  518. X        strcpy( L->ll_shortty, cp );
  519. X
  520. X        *cp = 'p';
  521. X        strcpy( L->ll_ptyname, varg[ 2 ]);
  522. X
  523. X        *cp = 't';
  524. X        strcpy( L->ll_ttyname, varg[ 2 ]);
  525. X
  526. X    }
  527. X
  528. X    L->ll_resch = -1;
  529. X
  530. X    L->ll_ptyfd = open( L->ll_ptyname, O_RDWR|O_EXCL, 0 );
  531. X    if ( L->ll_ptyfd < 0 )
  532. X    {    printf( "open \"%s\" failed, errno=%d\n",
  533. X            L->ll_ptyname, errno );
  534. X        return 0;
  535. X    }
  536. X    lcount++;
  537. X
  538. X    l = L;
  539. X    l->ll_status = 1;
  540. X    ufake( L->ll_shortty );
  541. X    return 1;
  542. X}
  543. X
  544. c_delete()
  545. X{    /* delete layer. */
  546. X    int i, j;
  547. X
  548. X    if ( tokcnt < 2 )
  549. X    {    printf( "\"delete\" command requires at least one parameter\n" );
  550. X        return 0;
  551. X    }
  552. X
  553. X    for ( j = 1; j < tokcnt; j++ )
  554. X    {    if ( ( i = findlayer( varg[ j ])) >= 0 )
  555. X        {    kill( -ll[i].ll_pid, SIGTERM );
  556. X            kill( -ll[i].ll_pid, SIGHUP );
  557. X        }
  558. X        else printf( "No such layer %s\n", varg[ j ]);
  559. X    }
  560. X
  561. X    return 0;
  562. X}
  563. X
  564. c_Delete()
  565. X{    /* delete layer emphatically. */
  566. X    int i, j;
  567. X
  568. X    if ( tokcnt < 2 )
  569. X    {    printf( "\"Delete\" command requires at least one parameter\n" );
  570. X        return 0;
  571. X    }
  572. X
  573. X    for ( j = 1; j < tokcnt; j++ )
  574. X    {
  575. X        if ( ( i = findlayer( varg[ j ])) >= 0 )
  576. X        {    kill( -ll[i].ll_pid, SIGTERM );
  577. X            kill( -ll[i].ll_pid, SIGHUP );
  578. X            ll[i].ll_status = 0;
  579. X            kill( -ll[i].ll_pid, SIGKILL );
  580. X        }
  581. X        else printf( "No such layer %s\n", varg[ j ]);
  582. X    }
  583. X
  584. X    return 0;
  585. X}
  586. X
  587. c_Forget()
  588. X{    /* forget about layer without killing it. */
  589. X    int i, j;
  590. X
  591. X    if ( tokcnt < 2 )
  592. X    {    printf( "\"Forget\" command requires at least one parameter\n" );
  593. X        return 0;
  594. X    }
  595. X
  596. X    for ( j = 1; j < tokcnt; j++ )
  597. X    {
  598. X        if ( ( i = findlayer( varg[ j ])) >= 0 )
  599. X        {    ll[i].ll_status = 0;
  600. X            close( ll[i].ll_ptyfd );
  601. X        }
  602. X        else printf( "No such layer %s\n", varg[ j ]);
  603. X    }
  604. X
  605. X    return 0;
  606. X}
  607. X
  608. c_list()
  609. X{    int i, j, k;
  610. X    if ( tokcnt == 1 )
  611. X    {    listlayers( 0, -1 );
  612. X        return 0;
  613. X    }
  614. X    else if ( ! strcmp( varg[ 1 ], "-l" ))
  615. X    {    j = 1;
  616. X        i = 2;
  617. X    }
  618. X    else
  619. X    {    j = 0;
  620. X        i = 1;
  621. X    }
  622. X
  623. X    if ( tokcnt == i ) listlayers( j, -1 );
  624. X    else for ( ; i < tokcnt; i++ )
  625. X    {    if ( ( k = findlayer( varg[ i ] )) >= 0 )
  626. X            listlayers( j, k );
  627. X        else printf( "No such layer \"%s\"\n", varg[ i ]);
  628. X    }
  629. X    return 0;
  630. X}
  631. X
  632. c_main()
  633. X{    if ( tokcnt != 2 )
  634. X        printf( "\"main\" command requires 2 parameters.\n" );
  635. X    else mainlayer = findlayer( varg[ 1 ]);
  636. X    return 0;
  637. X}
  638. X
  639. c_quit()
  640. X{    myexit( 0 );
  641. X}
  642. X
  643. c_resume()
  644. X{    int i;
  645. X    if ( tokcnt == 1 )
  646. X    {    if ( curlayer >= 0 && ll[curlayer].ll_status )
  647. X        {    gotolayer( &ll[curlayer] );
  648. X            return 1;
  649. X        }
  650. X        printf( "No current layer.\n" );
  651. X        return 0;
  652. X    }
  653. X
  654. X    if ( tokcnt != 2 )
  655. X    {    printf( "\"resume\" command requires 0 or 1 parameters\n" );
  656. X        return 0;
  657. X    }
  658. X
  659. X    checklayers();
  660. X    i = findlayer( varg[ 1 ]);
  661. X    if ( i >= 0 )
  662. X    {    gotolayer( &ll[i] );
  663. X        return 1;
  664. X    }
  665. X    printf( "No such layer\n" );
  666. X    return 0;
  667. X}
  668. X
  669. c_SendFile()
  670. X{    int i;
  671. X    FILE * inf;
  672. X    int c;
  673. X
  674. X/**********************************************************/
  675. X/*                                                        */
  676. X/*  If the file is too big, bad things happen.            */
  677. X/*                                                        */
  678. X/*  If you don't go to the layer right away and let the   */
  679. X/*  output come to the screen, bad things may happen.     */
  680. X/*                                                        */
  681. X/*  However, this is a useful facility if used with       */
  682. X/*  care: in the middle of interactive stuff, you can     */
  683. X/*  "type in" a lot of stuff by taking it from a file.    */
  684. X/*                                                        */
  685. X/*  Even though I now have X, and therefore don't need    */
  686. X/*  layers, I still use ptyshl about once a month just    */
  687. X/*  to take advantage of this facility!                   */
  688. X/*                                                        */
  689. X/**********************************************************/
  690. X
  691. X    if ( tokcnt != 3 )
  692. X    {    printf( "\"> layer file\", 3 parameters.\n" );
  693. X        return 0;
  694. X    }
  695. X
  696. X    checklayers();
  697. X    i = findlayer( varg[ 1 ]);
  698. X    if ( i < 0 )
  699. X    {    printf( "No such layer\n" );
  700. X        return 0;
  701. X    }
  702. X
  703. X    inf = fopen( varg[ 2 ], "r" );
  704. X    if ( inf == NULL )
  705. X    {    printf( "Couldn't open %s\n", varg[ 2 ] );
  706. X        return 0;
  707. X    }
  708. X    while (( c = getc( inf )) != EOF )
  709. X    {    /* Transfer the file to the destination. */
  710. X        char x;
  711. X
  712. X        x = c;
  713. X        if ( write( ll[ i ].ll_ptyfd, &x, 1 ) != 1 )
  714. X        {    printf( "\nwrite error\n" );
  715. X            break;
  716. X        }
  717. X    }
  718. X
  719. X    fclose( inf );
  720. X    return 0;
  721. X}
  722. X
  723. c_swtch()
  724. X{
  725. X    if ( tokcnt != 2 )
  726. X    {    printf( "\"swtch\" command needs 1 parameter.\n" );
  727. X        return 0;
  728. X    }
  729. X    if ( *varg[1] ) my_swtch_char = *varg[1] & 0xff;
  730. X}
  731. X
  732. c_toggle()
  733. X{    /* resume last layer. */
  734. X    if ( tokcnt != 1 )
  735. X    {    printf( "\"toggle\" command must have 0 parameters.\n" );
  736. X        return 0;
  737. X    }
  738. X
  739. X    if ( oldlayer >= 0 && ll[oldlayer].ll_status )
  740. X    {    gotolayer( &ll[oldlayer] );
  741. X        return 1;
  742. X    }
  743. X    printf( "No alternate layer.\n" );
  744. X    return 0;
  745. X}
  746. X
  747. c_twice()
  748. X{
  749. X    twicemode ^= 1;
  750. X    sTwice = 0;
  751. X    printf( "\"Twice\" mode is %s.\n",
  752. X        (twicemode) ? "on" : "off" );
  753. X    return 0;
  754. X}
  755. X
  756. c_plus()
  757. X{    /* next sequential layer. */
  758. X    int i;
  759. X
  760. X    if ( curlayer < 0 ) curlayer = 0;
  761. X    for ( i = curlayer + 1; i < MAXll; i++ )
  762. X    {    if ( ll[i].ll_status == 0 ) continue;
  763. X        goto gotdest;
  764. X    }
  765. X    for ( i = 0; i < curlayer; i++ )
  766. X    {    if ( ll[i].ll_status == 0 ) continue;
  767. X        goto gotdest;
  768. X    }
  769. X    printf( "No next layer to be found!\n" );
  770. X    return 0;
  771. gotdest:
  772. X    gotolayer( &ll[i] );
  773. X    return 1;
  774. X}
  775. X
  776. c_Cset()
  777. X{    int i;
  778. X    if ( tokcnt != 3 )
  779. X    {    printf( "\"Cset layer char\" -- 3 parameters.\n" );
  780. X        return 0;
  781. X    }
  782. X    if ( ( i = findlayer( varg[ 1 ] )) < 0 )
  783. X    {    printf( "No such layer %s\n", varg[ 1 ]);
  784. X        return 0;
  785. X    }
  786. X    ll[i].ll_resch = *varg[2];
  787. X    return 0;
  788. X}
  789. X
  790. c_unCset()
  791. X{    int i;
  792. X    if ( tokcnt != 2 )
  793. X    {    printf( "\"unCset layer\" -- 2 parameters.\n" );
  794. X        return 0;
  795. X    }
  796. X    if ( ( i = findlayer( varg[ 1 ] )) < 0 )
  797. X    {    printf( "No such layer %s\n", varg[ 1 ]);
  798. X        return 0;
  799. X    }
  800. X    ll[i].ll_resch = -1;
  801. X    return 0;
  802. X}
  803. X
  804. c_equal()
  805. X{
  806. X    if ( tokcnt < 2 || tokcnt > 3 )
  807. X    {    printf( "\"=\" command requires 2 or 3 parameters.\n" );
  808. X    }
  809. X    else if ( ! strcmp( "OPAGE", varg[1] ))
  810. X    {    if ( tokcnt == 2 ) xOPAGE[0] = 0;
  811. X        else strcpy( xOPAGE, varg[2] );
  812. X    }
  813. X    else if ( ! strcmp( "CEOP", varg[1] ))
  814. X    {    if ( tokcnt == 2 ) xCEOP[0] = 0;
  815. X        else strcpy( xCEOP, varg[2] );
  816. X    }
  817. X    else printf( "\"= CEOP\" or \"= OPAGE\"\n" );
  818. X    return 0;
  819. X}
  820. X
  821. c_sh()
  822. X{    char * cp;
  823. X
  824. X    if( cmdbuf[0] == '!' ) cp = cmdbuf + 1;
  825. X    else cp = cmdbuf + 3;
  826. X    mysystem( cp );
  827. X}
  828. X
  829. c_help()
  830. X{
  831. printf( "\"auto [+]\" -- toggle autoflip or autoplus mode.\n" );
  832. printf( "\"create layer\" -- create named layer.\n" );
  833. printf( "\"delete layer [layer...]\" -- delete named layer[s].\n" );
  834. printf( "\"Delete layer [layer...]\" -- emphatically delete named layer[s].\n" );
  835. printf( "\"Forget layer [layer...]\" -- detach named layer[s].\n" );
  836. printf( "\"list [-l] [layer...]\" -- list the layers.\n" );
  837. printf( "\"main layer\" -- make layer the \"main layer\".\n" );
  838. printf( "\"quit\" -- kill all layers and exit.\n" );
  839. printf( "\"resume layer\" -- resume the named layer.\n" );
  840. printf( "\"resume\" -- resume the current layer.\n" );
  841. printf( "\"swtch char\" -- change the swtch character.\n" );
  842. printf( "\"toggle\" -- resume the alternate layer.\n" );
  843. printf( "\"Twice\" -- toggles wait-for-two-swtch-characters mode.\n" );
  844. printf( "\"!command\" or \"sh command\" -- execute command from the control layer.\n" );
  845. printf( "\"Cset layer char\" -- send x to layer whenever it is resumed.\n" );
  846. printf( "\"unCset layer\" -- don't send anything to layer when resumed.\n" );
  847. printf( "\"+\" -- go to next sequential layer.\n" );
  848. printf( "\"= CEOP string\" -- how to clear to end of screen.\n" );
  849. printf( "\"= OPAGE string\" -- how to switch display pages.\n" );
  850. printf( "\">layer file\" -- send file to layer.\n" );
  851. printf( "\"layer\" -- resume the named layer.\n" );
  852. X    return 0;
  853. X}
  854. END_OF_FILE
  855. if test 12809 -ne `wc -c <'ptycmd.c'`; then
  856.     echo shar: \"'ptycmd.c'\" unpacked with wrong size!
  857. fi
  858. # end of 'ptycmd.c'
  859. fi
  860. if test -f 'ptyshl.c' -a "${1}" != "-c" ; then 
  861.   echo shar: Will not clobber existing file \"'ptyshl.c'\"
  862. else
  863. echo shar: Extracting \"'ptyshl.c'\" \(13837 characters\)
  864. sed "s/^X//" >'ptyshl.c' <<'END_OF_FILE'
  865. X/* PORT_CHANGE is a string to search for when porting to a new
  866. X** system.
  867. X*/
  868. X
  869. X/* Copyright (c) 1990, 1991 Ralph Betza.
  870. X** Read the file cpyright.h for full copyright information.
  871. X*/
  872. X
  873. X#define Extern
  874. X
  875. X#include "ptyshl.h"
  876. X#include "cpyright.h"
  877. X#include "patchlevel.h"
  878. X
  879. catchsig()
  880. X{    myexit( 0 );
  881. X}
  882. X
  883. childgone()
  884. X{    int status;
  885. X    struct layer * L;
  886. X    int i = wait( &status );
  887. X
  888. X    signal( SIGCLD, childgone );
  889. X
  890. X    for ( L = ll, i = 0; i < MAXll; L++, i++ )
  891. X    {    if ( L->ll_status == 0 )
  892. X        {    continue;
  893. X        }
  894. X        if ( kill( L->ll_pid, 0 ) >= 0 ) continue;
  895. X        closelayer( L );
  896. X    }
  897. X}
  898. X
  899. main()
  900. X{
  901. X    int c;
  902. X    int errcount = 0;
  903. X    char cc;
  904. X    static char Cc[128];
  905. X
  906. X    initme();
  907. X
  908. X    ioctl( 0, TCSETA, &ttyset );
  909. X
  910. X    for ( ;; )
  911. X    {
  912. X        if ( l->ll_status == 0 )
  913. X        {    switchme();
  914. X            continue;
  915. X        }
  916. X
  917. X        nfds = l->ll_ptyfd + 1;
  918. X        xexcpfds = xreadfds = 1 + ( 1 << l->ll_ptyfd );
  919. X        xwrfds = 0;
  920. X        readfds = xreadfds;
  921. X        wrfds = xwrfds;
  922. X        excpfds = xexcpfds;
  923. X        c = select( nfds, &readfds, &wrfds, &excpfds,
  924. X            /* &XX */ NULL );    /* NULL for no timeout. */
  925. X        if ( c > 0 )
  926. X        {    errcount = 0;
  927. X            if ( readfds & 1 )
  928. X            {    if ( ( c = read( 0, Cc, 128 )) >= 1 )
  929. X                {    /* keyboard characters. */
  930. X                    if ( c == 1
  931. X                    && (Cc[0]&0xff) == (my_swtch_char&0xff) )
  932. X                    {    /* switch character must arrive
  933. X                        ** in isolation.
  934. X                        */
  935. X                        if ( twicemode )
  936. X                        {    /* Do not switch until we get two
  937. X                            ** swtch characters.
  938. X                            */
  939. X                            if ( sTwice )
  940. X                            {    /* This is the second one.
  941. X                                */
  942. X                                switchme();
  943. X                                sTwice = 0;
  944. X                            }
  945. X                            else
  946. X                            {    /* This is only the first one.
  947. X                                */
  948. X                                ++sTwice;
  949. X                            }
  950. X                        }
  951. X                        else
  952. X                        {    /* switch right away.
  953. X                            */
  954. X                            switchme();
  955. X                        }
  956. X                        continue;
  957. X                    }
  958. X                    else if ( twicemode && sTwice )
  959. X                    {    /* we got a swtch followed by something
  960. X                        ** else. Send swtch char to
  961. X                        ** destination.
  962. X                        */
  963. X                        sTwice = 0;
  964. X                        cc = my_swtch_char;
  965. X                        write( l->ll_ptyfd, &cc, c );
  966. X                    }
  967. X                    if ( write( l->ll_ptyfd, Cc, c ) != c )
  968. X                    {    printf( "parent write to pty %d\n", errno );
  969. X                        /* break; */
  970. X                    }
  971. X                }
  972. X                else
  973. X                {    printf( "parent read stdin %d\n", errno );
  974. X                    break;
  975. X                }
  976. X            }
  977. X            else if ( readfds & xreadfds )
  978. X            {    c = read( l->ll_ptyfd, Cc, 128 );
  979. X                if ( c > 0 ) write( 1, Cc, c );
  980. X            }
  981. X            else printf( "parent no readfds\n" );
  982. X        }
  983. X        else
  984. X        {    if ( errno == EINTR ) errcount = 0;
  985. X            /* EIO happens when we time out? */
  986. X            checklayers();
  987. X            if ( errcount++ > 20 )
  988. X            {    printf( "Select errors; errno %d\n", errno );
  989. X                myexit( 0 );
  990. X            }
  991. X        }
  992. X    }
  993. X    myexit( 0 );
  994. X}
  995. X
  996. myexit()
  997. X{    struct layer * L;
  998. X    int i;
  999. X
  1000. X    L = &ll[0];
  1001. X    for ( i = 0; i < MAXll; L++, i++ )
  1002. X    {    if ( L->ll_status == 0 ) continue;
  1003. X        kill( -L->ll_pid, SIGTERM );
  1004. X        kill( -L->ll_pid, SIGHUP );
  1005. X    }
  1006. X
  1007. X    ioctl( 0, TCSETA, &ttysave );
  1008. X    exit( 0 );
  1009. X}
  1010. X
  1011. makelayer( name )
  1012. char * name;
  1013. X{    struct layer * L;
  1014. X    int i;
  1015. X    static char itsnumber[10];
  1016. X    static char envbuf[30];
  1017. X
  1018. X    if ( ! *name || strlen(name) > 19 )
  1019. X    {    printf( "Layer needs a name from 1 to 19 characters.\n" );
  1020. X        return ( -1 );
  1021. X    }
  1022. X
  1023. X    L = &ll[0];
  1024. X    for ( i = 0; i < MAXll; L++, i++ )
  1025. X    {    if ( L->ll_status == 0 ) goto foundl;
  1026. X    }
  1027. X    printf( "too many layers\n" );
  1028. X    return ( -1 );
  1029. foundl:        /* we found a free layer table entry. */
  1030. X
  1031. X/**********************************************************/
  1032. X/*                                                        */
  1033. X/*  The following is a real mess.                         */
  1034. X/*                                                        */
  1035. X/*  The problem is that the pty devices have different    */
  1036. X/*  names on different systems. The use of #ifdef to      */
  1037. X/*  solve it isn't perfect.                               */
  1038. X/*                                                        */
  1039. X/**********************************************************/
  1040. X
  1041. X    L->ll_resch = -1;
  1042. X    i = 0;
  1043. X#ifndef WHERE
  1044. X/**********************************************************/
  1045. X/*                                                        */
  1046. X/*  Undefined                                             */
  1047. X/*                                                        */
  1048. X/**********************************************************/
  1049. X    strcpy( L->ll_ptyname,"/dev/ptyp" );
  1050. X    for ( ;; )
  1051. X    {    /* try to open a pty. */
  1052. X        L->ll_ptyname[9] = 0;
  1053. X        sprintf( itsnumber, "%d", i++);
  1054. X        strcat( L->ll_ptyname, itsnumber );
  1055. X        strcpy( L->ll_shortty, "ttyp" );
  1056. X        strcat( L->ll_shortty, itsnumber );
  1057. X#else    /* } ifndef WHERE */
  1058. X#if ( WHERE == 1 )    /* DG/UX */
  1059. X/**********************************************************/
  1060. X/*                                                        */
  1061. X/*  ptyp0 to ptyp999                                      */
  1062. X/*                                                        */
  1063. X/**********************************************************/
  1064. X    strcpy( L->ll_ptyname,"/dev/ptyp" );
  1065. X    for ( ;; )
  1066. X    {    /* try to open a pty. */
  1067. X        L->ll_ptyname[9] = 0;
  1068. X        sprintf( itsnumber, "%d", i++);
  1069. X        strcat( L->ll_ptyname, itsnumber );
  1070. X        strcpy( L->ll_shortty, "ttyp" );
  1071. X        strcat( L->ll_shortty, itsnumber );
  1072. X#else    /* } WHERE == 1 */
  1073. X#if ( WHERE == 2 )    /* Motorola */
  1074. X/**********************************************************/
  1075. X/*                                                        */
  1076. X/*  ptyp0 to ptyp9, then ptypa to ptypf, then ptyq0       */
  1077. X/*  and so forth.                                         */
  1078. X/*                                                        */
  1079. X/**********************************************************/
  1080. X    strcpy( L->ll_ptyname,"/dev/ptyp" );
  1081. X    for ( ;; )
  1082. X    {    /* try to open a pty. */
  1083. X        L->ll_ptyname[9] = 0;
  1084. X        L->ll_ptyname[8] = 'p' + (( i >> 4 ) & 0x0f);
  1085. X        sprintf( itsnumber, "%1x", ( i++ ) & 0x0f );
  1086. X        strcat( L->ll_ptyname, itsnumber );
  1087. X
  1088. X        strcpy( L->ll_shortty, "ttyp" );
  1089. X        L->ll_shortty[3] = 'p' + (( i >> 4 ) & 0x0f);
  1090. X        strcat( L->ll_shortty, itsnumber );
  1091. X#else    /* } WHERE == 2  */
  1092. X/**********************************************************/
  1093. X/*                                                        */
  1094. X/*  ISC.                                                  */
  1095. X/*                                                        */
  1096. X/**********************************************************/
  1097. X    strcpy( L->ll_ptyname,"/dev/ptyp" );
  1098. X    for ( ;; )
  1099. X    {    /* try to open a pty. */
  1100. X        L->ll_ptyname[9] = 0;
  1101. X        sprintf( itsnumber, "%d", i++);
  1102. X        strcat( L->ll_ptyname, itsnumber );
  1103. X        strcpy( L->ll_shortty, "ttyp" );
  1104. X        strcat( L->ll_shortty, itsnumber );
  1105. X#endif
  1106. X#endif
  1107. X#endif
  1108. X        L->ll_ptyfd = open( L->ll_ptyname, O_RDWR|O_EXCL, 0 );
  1109. X        if ( L->ll_ptyfd < 0 )
  1110. X        {    printf( "failed %s %d\n", L->ll_ptyname, errno );
  1111. X            /* PORT_CHANGE number in following line. */
  1112. X            if ( i > 64 )
  1113. X            {    printf( "No pty devices available\n" );
  1114. X                return ( -1 );
  1115. X            }
  1116. X            continue;
  1117. X        }
  1118. X        break;
  1119. X    }
  1120. X    /* printf( "opened %s %d\n", L->ll_ptyname, L->ll_ptyfd ); */
  1121. X    strcpy( L->ll_ttyname, L->ll_ptyname );
  1122. X    L->ll_ttyname[5] = 't';
  1123. X        /* PORT_CHANGE number in above line. */
  1124. X
  1125. X    ioctl( L->ll_ptyfd, TCSETA, &ttyset );
  1126. X    L->ll_status = 1;
  1127. X    strcpy( L->ll_llname, name );
  1128. X
  1129. X    if ( ( L->ll_pid = fork()) > 0 )
  1130. X    {    /* Parent process. */
  1131. X        lcount++;
  1132. X        l = L;
  1133. X        if ( ( l - ll ) != curlayer )
  1134. X        {    oldlayer = curlayer;
  1135. X            curlayer = l - ll;
  1136. X        }
  1137. X        return ( l->ll_ptyfd );
  1138. X    }
  1139. X    else if ( L->ll_pid < 0 )
  1140. X    {    printf( "Fork failed! %d\n", errno );
  1141. X        return( -1 );
  1142. X    }
  1143. X
  1144. X    /* Child process. */
  1145. X    setpgrp();
  1146. X    signal( SIGINT, SIG_DFL );
  1147. X    signal( SIGQUIT, SIG_DFL );
  1148. X    fclose( stdin );
  1149. X    if ( open( L->ll_ttyname, O_RDWR, 0 ) != 0 )
  1150. X    {    printf( "child open stdin %d\n", errno );
  1151. X        exit(1);
  1152. X    }
  1153. X    if ( fdopen( 0, "r" ) == NULL )
  1154. X    {    printf( "child fopen stdin %d\n", errno );
  1155. X        exit(1);
  1156. X    }
  1157. X    if ( ioctl( 0, TCSETA, &ttysave ) < 0 )
  1158. X    {    printf( "child ioctl stdin %d\n", errno );
  1159. X        exit(1);
  1160. X    }
  1161. X
  1162. X    fclose( stdout );
  1163. X    dup( 0 );
  1164. X    if ( fdopen( 1, "w" ) == NULL )
  1165. X    {    fprintf( stderr, "child fopen stdout %d\n", errno );
  1166. X        exit(1);
  1167. X    }
  1168. X
  1169. X    fclose( stderr );
  1170. X    dup( 0 );
  1171. X    if ( fdopen( 2, "w" ) == NULL )
  1172. X    {    printf( "child fopen stderr %d\n", errno );
  1173. X        exit(1);
  1174. X    }
  1175. X
  1176. X    close( L->ll_ptyfd );
  1177. X
  1178. X    strcpy( envbuf, "LAYER=" );
  1179. X    strcat( envbuf, L->ll_llname );
  1180. X    putenv( envbuf );
  1181. X    varg[0] = shellname;
  1182. X    varg[1] = "-i";
  1183. X    varg[2] = 0;
  1184. X
  1185. X    execvp( varg[0], varg );
  1186. X    exit( 99 );
  1187. X}
  1188. X
  1189. ttyinit()
  1190. X{
  1191. X    ioctl( 0, TCGETA, &ttysave );
  1192. X    ioctl( 0, TCGETA, &ttyset );
  1193. X    ioctl( 0, TCGETA, &ttycmd );
  1194. X    ttyset.c_iflag &= ( BRKINT | IXON | IXANY | IXOFF );
  1195. X    ttyset.c_oflag &= ( ~OPOST );
  1196. X    ttyset.c_lflag = 0;
  1197. X    ttyset.c_cc[VMIN] = 1;
  1198. X    ttyset.c_cc[VTIME] = 0;
  1199. X    my_swtch_char = ttycmd.c_cc[VSWTCH] & 0xff;
  1200. X    if ( my_swtch_char == 0 )
  1201. X    {    my_swtch_char = ']'&0x1f;
  1202. X        printf( "switch character set to ^]\n" );
  1203. X    }
  1204. X    ttycmd.c_lflag &= ~ISIG;
  1205. X}
  1206. X
  1207. closelayer( L )
  1208. struct layer * L;
  1209. X{    if ( ! L->ll_status ) return;
  1210. X    if ( L->ll_ptyfd )
  1211. X    {    /* note: it can't be zero, that's stdin! */
  1212. X        close( L->ll_ptyfd );
  1213. X    }
  1214. X    L->ll_ptyfd = L->ll_status = 0;
  1215. X    if ( lcount > 0 ) lcount--;
  1216. X}
  1217. X
  1218. gotolayer( L )
  1219. struct layer * L;
  1220. X{    char c;
  1221. X    int lnumb = L - ll;
  1222. X
  1223. X    if ( ! L->ll_status )
  1224. X    {    printf( "Layer %s has disappeared!\n", L->ll_llname );
  1225. X        return;
  1226. X    }
  1227. X    l = L;
  1228. X    printf( "Resuming %s.\n", L->ll_llname );
  1229. X    if ( L->ll_resch >= 0 )
  1230. X    {    c = L->ll_resch;
  1231. X        write( L->ll_ptyfd, &c, 1 );
  1232. X    }
  1233. X    if ( lnumb != curlayer )
  1234. X    {    oldlayer = curlayer;
  1235. X        curlayer = lnumb;
  1236. X    }
  1237. X}
  1238. X
  1239. checklayers()
  1240. X{    int i;
  1241. X    struct layer * L;
  1242. X
  1243. X    for ( L = ll, i = 0; i < MAXll; L++, i++ )
  1244. X    {    if ( L->ll_status == 0 )
  1245. X        {    continue;
  1246. X        }
  1247. X        if ( kill( L->ll_pid, 0 ) >= 0 ) continue;
  1248. X        closelayer( L );    /* he's gone! */
  1249. X        if ( L == l ) return 1;
  1250. X    }
  1251. X    return 0;
  1252. X}
  1253. X
  1254. findlayer( name )
  1255. char * name;
  1256. X{    int i;
  1257. X    struct layer * L;
  1258. X
  1259. X    for ( L = ll, i = 0; i < MAXll; L++, i++ )
  1260. X    {    if ( L->ll_status == 0 )
  1261. X        {
  1262. X            continue;
  1263. X        }
  1264. X        if ( ! strcmp( L->ll_llname, name ))
  1265. X        {    return i;
  1266. X        }
  1267. X    }
  1268. X    return -1;
  1269. X}
  1270. X
  1271. initme()
  1272. X{    char rcname[100];
  1273. X    char * rcbase = ".shlrc";
  1274. X    char * homep, *getenv();
  1275. X    FILE * rcin;
  1276. X    int i;
  1277. X    extern char * ttyname();
  1278. X
  1279. X    uname( &ununun );
  1280. X    mainlayer = oldlayer = curlayer = -1;
  1281. X    shellname = getenv( "SHELL" );
  1282. X    if ( shellname == NULL ) shellname = "/bin/sh";
  1283. X    fstat( 0, &st );
  1284. X    if (( homep = ttyname( 0 )) == NULL )
  1285. X    {    printf( "no tty!\n" );
  1286. X        exit( 1 );
  1287. X    }
  1288. X    strcpy( mytty, homep );
  1289. X    strcpy( mybasetty, ( strrchr( mytty, '/' ) + 1 ));
  1290. X    strcpy( ustart.ut_line, mybasetty );
  1291. X    if (( utmpl = getutline( &ustart )) == NULL )
  1292. X    {    /* tty must have two names! */
  1293. X        setutent();
  1294. X        while ((utmpl = getutent()) != NULL)
  1295. X        {
  1296. X            if (utmpl->ut_type == USER_PROCESS)
  1297. X            {    char histty[30];
  1298. X                strcpy( histty, "/dev/" );
  1299. X                strcat( histty, utmpl->ut_line );
  1300. X                if (stat( histty, &st1 ) == 0)
  1301. X                {
  1302. X                    if ( st1.st_rdev == st.st_rdev)
  1303. X                    {
  1304. X                        strcpy( mybasetty, utmpl->ut_line );
  1305. X                        goto gotty;
  1306. X                    }
  1307. X                }
  1308. X            }
  1309. X        }
  1310. X        printf( "Can't find tty!\n" );
  1311. X        exit ( 1 );
  1312. X    }
  1313. gotty:
  1314. X    l = ll;
  1315. X    signal( SIGCLD, childgone );
  1316. X    signal( SIGTERM, catchsig );
  1317. X    signal( SIGHUP, catchsig );
  1318. X    signal( SIGINT, SIG_IGN );
  1319. X    signal( SIGQUIT, SIG_IGN );
  1320. X    ttyinit();
  1321. X    XX.a = 10;
  1322. X    if ( ( rcin = fopen( rcbase, "r" )) != NULL )
  1323. X    {    goto gotrc;
  1324. X    }
  1325. X    homep = getenv( "HOME" );
  1326. X    if ( homep == NULL ) return;
  1327. X    if ( ( strlen( homep ) + strlen( rcbase )) > 97 ) return;
  1328. X    strcpy( rcname, homep );
  1329. X    strcat( rcname, "/" );
  1330. X    strcat( rcname, rcbase );
  1331. X    if ( ( rcin = fopen( rcname, "r" )) == NULL ) return;
  1332. gotrc:
  1333. X    while ( fgets( cmdbuf, 98, rcin ) != NULL )
  1334. X    {    c_analyze();
  1335. X    }
  1336. X    fclose( rcin );
  1337. X}
  1338. X
  1339. switchme()
  1340. X{    /* xOPAGE processing. */
  1341. X    int lnumb = l - ll;
  1342. X
  1343. X    if ( lnumb == mainlayer && xOPAGE[0] )
  1344. X    {    /* return from main layer. */
  1345. X        printf( "%s", xOPAGE );
  1346. X        if ( xCEOP[0] ) printf( "%s", xCEOP );
  1347. X        fflush( stdout );
  1348. X    }
  1349. X    else if ( automode
  1350. X    && l->ll_status        /* no flip after exit from layer. */
  1351. X    && lnumb != mainlayer
  1352. X    && mainlayer >= 0
  1353. X    && ll[mainlayer].ll_status )
  1354. X    {    /* automatic flip back to main layer. */
  1355. X        oldlayer = lnumb;
  1356. X        curlayer = mainlayer;
  1357. X        l = &ll[mainlayer];
  1358. X        ufake( l->ll_shortty );        /* ??? */
  1359. X        if ( xOPAGE[0] ) printf( "%s", xOPAGE );
  1360. X        fflush( stdout );
  1361. X        return;
  1362. X    }
  1363. X    else if ( xCEOP[0] )
  1364. X    {    /* clear to end of page. */
  1365. X        printf( "%s", xCEOP );
  1366. X        fflush( stdout );
  1367. X    }
  1368. X
  1369. X    if ( AplusMode
  1370. X    && l->ll_status        /* no autoplus after exit */
  1371. X    && c_plus( ))
  1372. X    {
  1373. X        return;
  1374. X    }
  1375. X
  1376. X    docommands();
  1377. X
  1378. after:
  1379. X    lnumb = l - ll;
  1380. X    if ( lnumb == mainlayer && xOPAGE[0] )
  1381. X        printf( "%s", xOPAGE );
  1382. X    fflush( stdout );
  1383. X}
  1384. X
  1385. listlayers( longlist, which )
  1386. int longlist;    /* boolean usage. */
  1387. int which;        /* (which < 0) means "all". */
  1388. X{    int i, j;
  1389. X    struct layer * L;
  1390. X    char llbuf[80];
  1391. X
  1392. X    for ( L = ll, j = i = 0; i < MAXll; L++, i++ )
  1393. X    {    if ( ! L->ll_status ) continue;
  1394. X        if ( which >= 0 && i != which ) continue;
  1395. X        if ( longlist | ! j )
  1396. X        {    printf( "          LAYER NAME  PID   TTY\n" );
  1397. X        }
  1398. X        j++;
  1399. X        sprintf( llbuf,
  1400. X            "%20s %5d %s\n",
  1401. X            L->ll_llname, L->ll_pid, L->ll_ttyname );
  1402. X        if ( i == mainlayer ) llbuf[0] = (automode) ? 'M' : 'm';
  1403. X        if ( i == oldlayer  ) llbuf[1] = '<';
  1404. X        if ( l == L ) llbuf[1] = '>';
  1405. X        printf( "%s", llbuf );
  1406. X
  1407. X        if ( longlist )
  1408. X        {    char psbuf[20];
  1409. X            sprintf( psbuf, "ps -fg%d", L->ll_pid );
  1410. X            mysystem( psbuf );
  1411. X            printf( "\n" );
  1412. X        }
  1413. X        if ( ( j * ((longlist)?5:1)) >= 20 )
  1414. X        {    printf( "[hit return to continue]" );
  1415. X            while ( ( j = getchar()) != EOF && j != '\n' );
  1416. X            j = 1;
  1417. X        }
  1418. X    }
  1419. X    if ( ! j ) printf( "No layers\n" );
  1420. X}
  1421. X
  1422. ufake( name )
  1423. char * name;
  1424. X{
  1425. X    strcpy( utmpl->ut_line, name );
  1426. X    pututline( utmpl );
  1427. X}
  1428. X
  1429. mysystem(s)
  1430. char    *s;
  1431. X{
  1432. X    int    status;
  1433. X    int     pid;
  1434. X    int     i;
  1435. X
  1436. X    signal(SIGCLD, SIG_DFL);
  1437. X    ioctl( 0, TCSETA, &ttysave );
  1438. X
  1439. X    if((pid = fork()) == 0)
  1440. X    {    signal( SIGINT, SIG_DFL );
  1441. X        signal( SIGQUIT, SIG_DFL );
  1442. X        (void) execl("/bin/sh", "sh", "-c", s, 0);
  1443. X        _exit(127);
  1444. X    }
  1445. X
  1446. X    for (;;)
  1447. X    {    i = wait(&status);
  1448. X
  1449. X        if (i != -1 && i != pid)
  1450. X            checklayers();
  1451. X        else
  1452. X        {    signal( SIGCLD, childgone );
  1453. X            ioctl( 0, TCSETA, &ttycmd );
  1454. X            return;
  1455. X        }
  1456. X    }
  1457. X}
  1458. X
  1459. docommands()
  1460. X{
  1461. X    int i;
  1462. X    char * cp;
  1463. X    struct layer * L;
  1464. X
  1465. X    ioctl( 0, TCSETA, &ttycmd );
  1466. X    ufake( mybasetty );
  1467. X    errno = 0;
  1468. X    for ( ;; )
  1469. X    {    if ( errno != EINTR ) printf( "%s>>> ", ununun.nodename );
  1470. X        checklayers();
  1471. X        errno = 0;
  1472. X        if ( fgets( cmdbuf, 254, stdin ) == NULL ) continue;
  1473. X        if ( c_analyze()) break;
  1474. X    }
  1475. leave:
  1476. X    checklayers();
  1477. X    ioctl( 0, TCSETA, &ttyset );
  1478. X    ufake( l->ll_shortty );
  1479. X}
  1480. END_OF_FILE
  1481. if test 13837 -ne `wc -c <'ptyshl.c'`; then
  1482.     echo shar: \"'ptyshl.c'\" unpacked with wrong size!
  1483. fi
  1484. # end of 'ptyshl.c'
  1485. fi
  1486. if test -f 'ptyshl.cat1' -a "${1}" != "-c" ; then 
  1487.   echo shar: Will not clobber existing file \"'ptyshl.cat1'\"
  1488. else
  1489. echo shar: Extracting \"'ptyshl.cat1'\" \(19197 characters\)
  1490. sed "s/^X//" >'ptyshl.cat1' <<'END_OF_FILE'
  1491. X     PTYSHL(1)                                               PTYSHL(1)
  1492. X
  1493. X     NAME
  1494. X          ptyshl - shell layer manager
  1495. X
  1496. X     SYNOPSIS
  1497. X          ptyshl
  1498. X
  1499. X     DESCRIPTION
  1500. X          Ptyshl allows a user to interact with more than one shell
  1501. X          from a single terminal. The user controls these shells,
  1502. X          known as layers, using the commands described below.
  1503. X          Up to 20 layers are supported; on systems where the
  1504. X          number of file descriptors is limited to twenty, the
  1505. X          practical limit is somewhat lower.
  1506. X
  1507. X          The current layer is the layer that can receive input from
  1508. X          the keyboard. Other layers attempting to read from, or
  1509. X          write to, the keyboard are blocked. Output from multiple
  1510. X          layers is currently not multiplexed onto the terminal; a
  1511. X          layer which is not the current layer is blocked if it
  1512. X          attempts to write to the terminal.
  1513. X
  1514. X          The stty "swtch" character is used to switch control
  1515. X          to ptyshl from a layer. If swtch is set to zero when
  1516. X          ptyshl is invoked, it gets reset to ^Z. Changing the
  1517. X          swtch character (with stty) within a layer has no
  1518. X          effect on the ptyshl control layer. Instead, there is
  1519. X          a ptyshl command to do this.
  1520. X
  1521. X          Ptyshl has its own prompt, "`uname`>>> ", to help
  1522. X          distinguish it from a layer. uname is the name of the
  1523. X          machine that ptyshl is running on.
  1524. X
  1525. X          A layer is a shell that has been bound to a virtual tty
  1526. X          device (/dev/pty???).  The virtual device can be manipulated
  1527. X          like a real tty device using stty(1) and ioctl(2).  Each
  1528. X          layer has its own process group id.
  1529. X
  1530. X          Every layer has a name, which is a sequence of 1 to 19
  1531. X          characters chosen by you. The layer name is known within
  1532. X          the layer as the value of the $LAYER environment variable.
  1533. X
  1534. X          Most commands may be abbreviated to any unambiguous prefix
  1535. X          of the command.
  1536. X
  1537. X        Basic Usage
  1538. X          The "toggle", "resume", and "+" commands are used to
  1539. X          go from one layer to another, as follows: inside a
  1540. X          layer, you hit the swtch character; ptyshl enters
  1541. X          control mode, and presents its prompt; you choose one
  1542. X          of these commands, and begin talking to a different
  1543. X          shell.
  1544. X
  1545. X        Initialization
  1546. X          If there is a file named ".shlrc" in the current directory
  1547. X          or in your $HOME directory, ptyshl reads this file at
  1548. X          startup time and executes the commands it finds therein.
  1549. X          Each line of the file should contain one command, and
  1550. X          should be no longer than 98 characters. All the normal
  1551. X          commands are recognized in the .shlrc file.
  1552. X
  1553. X        Environment
  1554. X          Two environment variables are used:
  1555. X
  1556. X          LAYER
  1557. X               Is set by ptyshl to the layer name when a new layer is
  1558. X               created. Using "case $LAYER in" in your .kshrc is
  1559. X               suggested. The layer name should become part of your
  1560. X               shell's PS1 variable.
  1561. X
  1562. X          SHELL
  1563. X               Is input to ptyshl, and specifies the name of
  1564. X               the shell to use when creating new layers or
  1565. X               executing shell escapes. If $SHELL is not set,
  1566. X               the default shell, /bin/sh, is used.
  1567. X
  1568. X        Commands
  1569. X          The following commands may be issued from the ptyshl
  1570. X          prompt level or from the .shlrc file.  Any unique
  1571. X          prefix is accepted.
  1572. X
  1573. X          auto [+]
  1574. X               This command toggles AUTO mode, or if '+' is
  1575. X               specified, it toggles AUTOPLUS mode.
  1576. X
  1577. X               If AUTO mode is active, when you type the swtch
  1578. X               character, if a "main layer" (see "main" command)
  1579. X               is defined, and the alternate layer is the main
  1580. X               layer, the main layer will be instantly and
  1581. X               silently resumed without presenting the ptyshl
  1582. X               prompt. Naturally, this is most useful with OPAGE
  1583. X               set (see below).
  1584. X
  1585. X               If AUTOPLUS mode is active, when you type the
  1586. X               swtch character, a '+' command is done
  1587. X               automatically. The only way you can get back to
  1588. X               ptyshl command mode from AUTOPLUS mode is by
  1589. X               exiting from a layer.
  1590. X
  1591. X          create name
  1592. X               Create a layer called "name" and make it the
  1593. X               current layer. If a layer already exists by that
  1594. X               name, it will be resumed instead. A maximum of
  1595. X               20 layers may be created; ptyshl will run out of
  1596. X               file descriptors on some systems before it can
  1597. X               create 20 layers.
  1598. X
  1599. X          delete name [ name ... ]
  1600. X               For each name, delete the corresponding layer.
  1601. X               All processes in the process group of the layer
  1602. X               are sent the SIGTERM and SIGHUP signals (see
  1603. X               signal(2)). These layers remain active until the
  1604. X               processes terminate.
  1605. X
  1606. X               The normal way to end a layer is either to use
  1607. X               the "delete" command or to type ^D at the shell
  1608. X               prompt within the layer.
  1609. X
  1610. X          Delete name [ name ... ]
  1611. X               Send SIGKILL to each layer and "forget" the
  1612. X               layer without waiting for its processes to
  1613. X               terminate.
  1614. X
  1615. X               This can be useful if a process inside a layer
  1616. X               freezes and can't be killed.
  1617. X
  1618. X          Forget name [ name ... ]
  1619. X               Send no signal to the layer, and forget it ever
  1620. X               existed.
  1621. X
  1622. X               Do not do this to an interactive shell; it is
  1623. X               only to be used for processes created by (for
  1624. X               example) "exec make > make.out 2>&1".
  1625. X
  1626. X          Attach name
  1627. X
  1628. X               Attempt to reconnect to a layer on which Forget
  1629. X               was used. Not even one version of UNIX System
  1630. X               V.3.2 permits this command to work, however.
  1631. X
  1632. X          help (or ?)
  1633. X               Print the syntax of the ptyshl commands.
  1634. X
  1635. X          list [ -l ] [ name ... ]
  1636. X               For each name, list the layer name and its
  1637. X               process group. The -l option produces a
  1638. X               ps(1)-like listing. If no arguments are given,
  1639. X               information is presented for all existing
  1640. X               layers.
  1641. X
  1642. X               The first two characters of the line that gives
  1643. X               the layer name have the following meanings:
  1644. X               -    m in column 1 means that this layer is the
  1645. X                    main layer and that the "auto" flag is off.
  1646. X               -    M in column 1 means that this layer is the
  1647. X                    main layer and that the "auto" flag is on.
  1648. X               -    > in column 2 means that this is the most current
  1649. X                    layer (the target of the "resume" command).
  1650. X               -    < in column 2 means that this is the alternate
  1651. X                    layer, the target of the "toggle" command.
  1652. X
  1653. X          main [ name ]
  1654. X               Make the layer referenced by name the main
  1655. X               layer. If a main layer is defined, and if the
  1656. X               OPAGE sequence is defined, ptyshl will toggle
  1657. X               the display from one page to another so that one
  1658. X               page will be reserved for the main layer, and
  1659. X               the other page will be used for ptyshl prompts
  1660. X               and commands, as well as all other layers.
  1661. X
  1662. X               This works well if your terminal has two pages
  1663. X               of display memory and a command that toggles
  1664. X               between them.
  1665. X
  1666. X               The "main", "auto", and "= OPAGE" commands are
  1667. X               all part of the implementation of the same idea.
  1668. X
  1669. X          main -
  1670. X               Specify that there is no main layer.
  1671. X
  1672. X          resume [ name ]
  1673. X               Make the layer referenced by name the current
  1674. X               layer. If no argument is given, the last
  1675. X               existing current layer will be resumed.
  1676. X
  1677. X               Remember, all commands can be abbreviated:
  1678. X               this is simply "r".
  1679. X
  1680. X          swtch char
  1681. X               Use char as the swtch character from now on.
  1682. X
  1683. X          toggle
  1684. X               Resume the layer that was current before the last
  1685. X               current layer.
  1686. X
  1687. X               Remember, all commands can be abbreviated:
  1688. X               this is simply "t".
  1689. X
  1690. X          Twice
  1691. X               Toggle a mode that specifies, if set, that
  1692. X               switching requires two occurrences of the swtch
  1693. X               character. The first time you type ^Z (or
  1694. X               whatever your swtch character is), nothing
  1695. X               happens; if the next character is also ^Z, you
  1696. X               switch layers, but if it is anything else, ^Z is
  1697. X               sent to the current layer.
  1698. X
  1699. X               Either this facility or the "Cset" command or
  1700. X               the "swtch" command can be used as an awkward
  1701. X               means of sending the swtch command to a layer. An
  1702. X               awkward means is better than none at all.
  1703. X
  1704. X          quit
  1705. X               Exit ptyshl.  All layers are sent the SIGHUP signal.
  1706. X               The "quit" command must be spelled out completely.
  1707. X
  1708. X          name
  1709. X               Make the layer referenced by name the current
  1710. X               layer, and resume it. If what you type is not
  1711. X               recognized as a command, ptyshl tries to see if
  1712. X               it matches the name of a layer.
  1713. X
  1714. X          +
  1715. X               Make the next layer the current layer and resume
  1716. X               it. "Next" is defined by incrementing the
  1717. X               internal index to the layer table, like "next
  1718. X               session" in te3279 or the ":n" command in vi.
  1719. X
  1720. X          !command
  1721. X          sh command
  1722. X               Executes the command from the control layer. A
  1723. X               background process created in this way can write
  1724. X               to the screen while you are in a layer.
  1725. X
  1726. X          Cset name char
  1727. X               Whenever the named layer is resumed, unless it
  1728. X               is the "main" layer, the character "char" will
  1729. X               be sent to it. Usually, "char" is ^L (you type
  1730. X               control-L, not a '^' followed by an 'L'): the
  1731. X               idea is that the layer is executing a
  1732. X               full-screen editor, and you want the editor to
  1733. X               redraw the screen as soon as you resume that
  1734. X               layer!
  1735. X
  1736. X               This facility is primitive and experimental, but
  1737. X               very useful. It makes ptyshl seem more like
  1738. X               PowerPorts. Friendlier ways of specifying "char"
  1739. X               would be possible.
  1740. X
  1741. X          unCset name
  1742. X               Turns off Cset mode for this layer.
  1743. X
  1744. X          = CEOP string
  1745. X               CEOP == "clear to end of page". If CEOP is
  1746. X               defined, ptyshl sends it to the terminal before
  1747. X               it sends its prompt. Otherwise, the prompt may
  1748. X               appear in the middle of a cluttered screen.
  1749. X
  1750. X               This command should be placed in your .shlrc
  1751. X               file.
  1752. X
  1753. X          = OPAGE string
  1754. X               OPAGE == "other page". If OPAGE is defined,
  1755. X               ptyshl will use it to keep one page of your
  1756. X               terminal's display memory reserved for nothing
  1757. X               else but the "main" layer.
  1758. X
  1759. X          #comment
  1760. X               Comment lines and blank lines are permitted.
  1761. X
  1762. X          > name filename
  1763. X                filename is opened and sent to the named layer as
  1764. X                though you had typed it.
  1765. X
  1766. X                Don't use big files! Go to the layer right away,
  1767. X                so its output can come out!
  1768. X
  1769. X                This is an excellent facility, if used with care.
  1770. X                In effect, it provides a "." or ":source" command
  1771. X                for any program whatsoever.
  1772. X
  1773. X     FILES
  1774. X          /dev/ttyp*
  1775. X          /dev/ptyp*        Virtual tty devices
  1776. X                            The exact name differs from one system to
  1777. X                            another.
  1778. X
  1779. X     SEE ALSO
  1780. X          sh(1), stty(1), pty(4), pty(7), shl(1)
  1781. X          ioctl(2), signal(2) in the UNIX System Programmer Reference
  1782. X          Manual.
  1783. X
  1784. X     CAUTIONS
  1785. X          ptyshl is different from shl. In shl, the sxt driver
  1786. X          in the kernel performs the multiplexing of many
  1787. X          pseudoterminals into a single real tty port; in
  1788. X          ptyshl, the ptyshl program itself must continually
  1789. X          read from your keyboard and read from the master side
  1790. X          of the currently-active pty device. This is why using
  1791. X          stty to change the swtch character within a layer
  1792. X          doesn't work; this is also true of the versions of
  1793. X          shl that are implemented using pty instead of sxt (DG
  1794. X          and HP versions).
  1795. X
  1796. X          The above difference means that no program can
  1797. X          disable switching back to the ptyshl control layer
  1798. X          when you type the swtch character, and therefore
  1799. X          there is no convenient way to send the swtch
  1800. X          character to a layer. There are three inconvenient
  1801. X          ways; one is to use the Cset facility, another is
  1802. X          to use the Twice facility, another is to change to a
  1803. X          different swtch character. In shl, "stty -isig" (or
  1804. X          the corresponding ioctl call) disables the swtch
  1805. X          character; many programs, such as "rlogin", do this,
  1806. X          and are therefore inconvenient to use with shl.
  1807. X
  1808. X          Exiting ptyshl causes a hangup signal (SIGHUP) to be
  1809. X          sent to the process group of each existing layer.
  1810. X          This normally results in the cleanup of each layer's
  1811. X          processes, after which the set of virtual terminals
  1812. X          is available for use by another user. There are,
  1813. X          however, two cases in which, because a process
  1814. X          remains attached to a virtual terminal even after
  1815. X          ptyshl is exited, the set of virtual terminals will
  1816. X          not be immediately freed. A process nohup'd in a
  1817. X          layer remains attached to the virtual terminal if
  1818. X          standard input, output, or error is redirected to the
  1819. X          specific virtual terminal, as in the command line
  1820. X
  1821. X               nohup who > /dev/ttyp1
  1822. X
  1823. X          The same is true if SIGHUP is ignored in the shell
  1824. X          (e.g., via the command trap ' ' 1) before the process
  1825. X          is spawned. Both cases cause the set of virtual
  1826. X          terminals to be tied up until the process exits.
  1827. X
  1828. X          The system does not clean up if ptyshl is killed with
  1829. X          SIGKILL (kill -9).  The user may be left in a state
  1830. X          that will require disconnecting and logging back on.
  1831. X          In addition, the shell layer processes will continue
  1832. X          to run until they are explicitly killed or the system
  1833. X          rebooted. Users wishing to kill ptyshl should not use
  1834. X          SIGKILL.
  1835. X
  1836. X          "who" will show that you are logged in on the pty
  1837. X          device of your current layer, and not on any of the
  1838. X          others. This is done by fiddling with /etc/utmp. If
  1839. X          you're not root, this may not work.
  1840. X
  1841. X          Ptyshl reads characters in bursts, but the swtch
  1842. X          character must arrive all by itself (as the sole
  1843. X          character returned by a read() system call) if it is
  1844. X          to be interpreted correctly. This means that attempts
  1845. X          to embed it in a function key may fail.
  1846. X
  1847. X    ENHANCEMENTS
  1848. X
  1849. X    This version of ptyshl has been enhanced from the standard
  1850. X    UNIX version of shl.
  1851. X
  1852. X    The layer name is in the LAYER variable instead of the PS1
  1853. X    variable, because ksh wants to adjust PS1 itself, and to
  1854. X    have a clean copy of the layer name (shl appends a blank to
  1855. X    the layer name and sets PS1 to the result) for use
  1856. X    in .kshrc, and to have a clear indication of whether the
  1857. X    current shell is a login shell, the top shell in a layer,
  1858. X    or a subshell in a layer. The absence of a value for LAYER
  1859. X    means you are not in a layer. In .kshrc, if LAYER is set to
  1860. X    some particular name, this might provoke some particular
  1861. X    action: for example, layer name "medusa" might deserve "rlogin
  1862. X    medusa".
  1863. X
  1864. X    Screen control is provided via two environment variables,
  1865. X    OPAGE and CEOP. OPAGE is a step towards having shl behave
  1866. X    like PowerPorts, and is the best that can be done for a
  1867. X    terminal that has only two pages of display memory.
  1868. X
  1869. X    The "main" and "auto" commands are added. The idea of a
  1870. X    "main" level is tied in with the OPAGE variable: one page
  1871. X    of the terminal's display memory is to be used for the main
  1872. X    level, and for nothing else. The "auto" command allows you
  1873. X    to switch from the main level to some other, then return by
  1874. X    merely striking the swtch key. It would be nice to toggle
  1875. X    back and forth between two layers; the only way out of the
  1876. X    toggle loop would be to exit one of the layers (^D to its
  1877. X    shell) -- "auto" is a more controlled form of this.
  1878. X
  1879. X    Shell escapes from ptyshl itself are an idea taken from the
  1880. X    HP version of shl.
  1881. X
  1882. X    The Cset command would not be possible to implement using
  1883. X    the sxt pseudodevice.
  1884. X
  1885. X    USAGE NOTES
  1886. X
  1887. X    Layer names can be used as a form of communication
  1888. X    between .shlrc and .kshrc; ptyshl looks for ./.shlrc,
  1889. X    therefore you can also have several versions of your .shlrc
  1890. X    file.
  1891. X
  1892. X    NOTE: to avoid trouble with subshells from your layers, you
  1893. X    need to follow a standard:
  1894. X
  1895. X        if [ "" = "$LAYER" ]
  1896. X        then    # not in ptyshl; this is a login shell or subshell
  1897. X        else    # this is a layer
  1898. X            PS1="$LAYER(!): "
  1899. X            if [ "" != "$INSHL" ]
  1900. X            then    # this is a subshell in a layer
  1901. X                : no actions.
  1902. X            else    # this is the main shell of a layer
  1903. X                INSHL=y;export INSHL
  1904. X                if [ "" != "`grep $LAYER /etc/hosts.equiv`" ]
  1905. X                then
  1906. X                    # if the layer name is the name of a machine
  1907. X                    # on the network, rlogin to it.
  1908. X                    exec rlogin $LAYER -l $LOGNAME
  1909. X                fi
  1910. X                case $LAYER in
  1911. X                    te)
  1912. X                        gg=/u1/te-api-2; export gg
  1913. X                        CDPATH=:..:$gg/process:$gg:$gg/generic:$HOME
  1914. X                        export CDPATH
  1915. X                        cd s.q
  1916. X                        ;;
  1917. X                    ....and so forth
  1918. X
  1919. X    A layer is therefore a task-oriented invocation of your
  1920. X    shell. One common use is to have several layers reserved
  1921. X    for working on specific different things on the same
  1922. X    machine as ptyshl; another is to have several layers
  1923. X    defined as rlogins (layer "toro" does an rlogin to toro,
  1924. X    and so forth).
  1925. X
  1926. X    LOCATIONS
  1927. X
  1928. X    ptyshl requires pty devices and the select() call from the
  1929. X    C library; it requires System V.3 pty devices, not V.4 "pts"
  1930. X    devices.
  1931. X
  1932. X    It can be run on DGUX, HPUX, all Motorola machines, or
  1933. X    Interactive or ESIX 80386 Unix machines.
  1934. X
  1935. X    There is a chance it would work on SUN machines. The tty code
  1936. X    would need to be Berkeley-ized. The "jobs" facility of the
  1937. X    ksh used there renders ptyshl rather unnecessary in
  1938. X    Berkeley environments.
  1939. X
  1940. X    On Pyramid, ptyshl compiles and runs, but the pty devices act
  1941. X    as though "stty -opost" were in effect.
  1942. X
  1943. X    It won't run on SCO unix, of course.
  1944. END_OF_FILE
  1945. if test 19197 -ne `wc -c <'ptyshl.cat1'`; then
  1946.     echo shar: \"'ptyshl.cat1'\" unpacked with wrong size!
  1947. fi
  1948. # end of 'ptyshl.cat1'
  1949. fi
  1950. if test -f 'ptyshl.h' -a "${1}" != "-c" ; then 
  1951.   echo shar: Will not clobber existing file \"'ptyshl.h'\"
  1952. else
  1953. echo shar: Extracting \"'ptyshl.h'\" \(1389 characters\)
  1954. sed "s/^X//" >'ptyshl.h' <<'END_OF_FILE'
  1955. XExtern char cmdbuf[256];
  1956. XExtern char tokbuf[256];
  1957. XExtern char * SysName;
  1958. XExtern char xCEOP[99];
  1959. XExtern char xOPAGE[99];
  1960. XExtern char mytty[30];
  1961. XExtern char mybasetty[30];
  1962. XExtern int twicemode;
  1963. XExtern int sTwice;
  1964. XExtern int my_swtch_char;
  1965. XExtern int automode;
  1966. XExtern int AplusMode;
  1967. XExtern int mainlayer;
  1968. XExtern int oldlayer;
  1969. XExtern int curlayer;
  1970. X#define MAXARG 10
  1971. XExtern char * varg[MAXARG];
  1972. X    /* varg used for exec and for c_analyze. */
  1973. XExtern char *shellname;
  1974. XExtern int nfds;
  1975. XExtern long xreadfds, readfds, xwrfds, wrfds, xexcpfds, excpfds;
  1976. XExtern struct
  1977. X{    long a; long b;
  1978. X} XX;
  1979. X
  1980. X#include <stdio.h>
  1981. X#include <sys/types.h>
  1982. X/* types.h here for portability */
  1983. X#include <fcntl.h>
  1984. X#include <termio.h>
  1985. X#include <sys/ioctl.h>
  1986. X#include <signal.h>
  1987. X#include <utmp.h>
  1988. X#include    <sys/stat.h>
  1989. X#include <string.h>
  1990. X#include <errno.h>
  1991. X#include <sys/utsname.h>
  1992. XExtern struct utsname ununun;
  1993. XExtern struct stat st, st1;
  1994. XExtern struct utmp    ustart, *utmpl;
  1995. XExtern struct utmp        *getutent();
  1996. XExtern struct utmp        *getutline();
  1997. void            setutline();
  1998. XExtern struct termio ttysave, ttyset, ttycmd;
  1999. extern int errno;
  2000. X
  2001. X#define MAXll 20
  2002. XExtern struct layer
  2003. X{    int  ll_pid;
  2004. X    int  ll_ptyfd;
  2005. X    int  ll_status;
  2006. X    int  ll_resch;
  2007. X    char ll_ttyname[20], ll_ptyname[20], ll_shortty[10];
  2008. X    char ll_llname[20];        /* layer name. */
  2009. X} ll[MAXll];
  2010. XExtern int lcount;
  2011. XExtern struct layer * l;
  2012. X
  2013. X#ifndef VSWTCH
  2014. X#define VSWTCH 7    /* HP */
  2015. X#endif
  2016. END_OF_FILE
  2017. if test 1389 -ne `wc -c <'ptyshl.h'`; then
  2018.     echo shar: \"'ptyshl.h'\" unpacked with wrong size!
  2019. fi
  2020. # end of 'ptyshl.h'
  2021. fi
  2022. echo shar: End of archive 1 \(of 1\).
  2023. cp /dev/null ark1isdone
  2024. MISSING=""
  2025. for I in 1 ; do
  2026.     if test ! -f ark${I}isdone ; then
  2027.     MISSING="${MISSING} ${I}"
  2028.     fi
  2029. done
  2030. if test "${MISSING}" = "" ; then
  2031.     echo You have the archive.
  2032.     rm -f ark[1-9]isdone
  2033. else
  2034.     echo You still need to unpack the following archives:
  2035.     echo "        " ${MISSING}
  2036. fi
  2037. ##  End of shell archive.
  2038. exit 0
  2039.