home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume32 / shlm / part01 / shm.c < prev    next >
C/C++ Source or Header  |  1992-09-20  |  16KB  |  656 lines

  1. /*
  2. **
  3. **    shm.c
  4. **  version 1.1
  5. **  Author - root%candle.uucp@bts.com
  6. **
  7. **    shell layers with sxt devices
  8. **
  9. */
  10.  
  11. /* tabs = 4 */
  12.  
  13. #include "config.h"
  14.  
  15. #include <fcntl.h>
  16. #include <ctype.h>
  17. #include <signal.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <varargs.h>
  22. #include <sys/types.h>
  23. #include <sys/tty.h>
  24. #include <sys/sxt.h>
  25. #include <termio.h>
  26. #include <malloc.h>
  27. #ifdef USE_GETUT
  28. #    include <utmp.h>
  29. #endif
  30.  
  31. #ifdef DEBUG
  32. FILE *db_file;
  33. #define DB            fprintf(db_file,"shm eached line:  %d\n",__LINE__)
  34. #else
  35. #define DB
  36. #endif
  37.  
  38.  
  39. #ifndef SXT_STEP
  40. #define SXT_STEP MAXPCHAN
  41. #endif
  42.  
  43. #define USED        1
  44. #define FREE        0
  45.  
  46. #define NEXT        1
  47. #define PREV        (-1)
  48.  
  49. #define CLRSCR        1    /* define this to be 0 if you don't like your
  50.                            screen being cleared when changing layers */
  51. #define NOCLRSCR     0
  52.  
  53. #define NOT_FOUND    (-1)
  54.  
  55. #define PRINT_OPTIONS    fprintf(stderr,"\n\
  56. All commands start with %c%c, then:\n\
  57. C,Z                    create\n\
  58. D                      delete\n\
  59. S                      show layers\n\
  60. ^Z,N,^N,L,^L,Swt,Ret   next layers\n\
  61. P,^P,Bs                previous layer\n\
  62. 1-%1d                    activate layer #\n\
  63. B                      turn off blocking\n\
  64. R,Sp                   resume\n\
  65. T                      toggle between layers\n\
  66. H,?                    help\n\
  67. Q,^D                   quit\n",\
  68. (iscntrl(layerterm.c_cc[VSWTCH]) ? '^' : ' '),\
  69. layerterm.c_cc[VSWTCH] + (iscntrl(layerterm.c_cc[VSWTCH]) ? '@' : 0),\
  70. MAXPCHAN-1);
  71.  
  72. #define CONTROL(x)    ((x) & 0x1f)
  73.  
  74. struct {
  75.     int     status;
  76.     int        pid;
  77.     char     *screen;
  78. }    layer[MAXPCHAN];
  79.  
  80. struct termio savedterm, layerterm, cntrlterm;
  81.  
  82.  
  83. int sxt_group;            /* active sxt group made up of MAXPCHAN devices */
  84. int cur_slot;            /* active sxt slot within group */
  85. char clear_str[20];        /* string to clear screen */
  86. int console = 0;
  87.  
  88. void exit_layers();
  89. void manage_layer();
  90. void layer_died();
  91. void halt();
  92. void exit();
  93.  
  94. #ifdef USE_GETUT
  95. char orig_tty[15];        /* original tty in utmp */
  96. struct utmp my_utmp;
  97. #endif 
  98.  
  99.             
  100. /*-------------------------------------------------------------------------- 
  101. **
  102. **    main
  103. **
  104. **-------------------------------------------------------------------------*/
  105.  
  106. main(argc, argv)
  107. int argc;
  108. char **argv;
  109. {
  110.     int     errret, args = 1, i;
  111.     char     *clear_ptr,
  112.              *tty_ptr,
  113.             *getenv(),
  114.             *ttyname();
  115.     char    sxt_file[40];
  116.     int     slot;
  117. #ifdef USE_GETUT
  118.     struct     utmp *utmp_ptr,
  119.                  *getutline();    
  120. #endif
  121.  
  122. #ifdef DEBUG
  123. db_file = fopen("shm_debug.log","w");
  124. #endif
  125.  
  126. #ifdef USE_CONDUMP
  127.      if (strcmp(argv[0], "condump") == 0 ||
  128.         strcmp(strrchr(argv[0],'/'), "/condump" ) == 0 ||
  129.          strcmp(argv[0], "conrestore") == 0 ||
  130.         strcmp(strrchr(argv[0],'/'), "/conrestore" ) == 0)
  131.         return con_run(argc, argv);
  132.  
  133.     if ( (tty_ptr = ttyname(0)) == NULL)
  134.         halt("shm:  Cannot find tty name.\n");
  135.     if (strcmp(tty_ptr, CONSOLE_DEVICE) == 0)
  136.         console = 1;
  137.     if (argc >= 2 && strcmp(argv[1], "-c") == 0)
  138.     {
  139.         console = 1;
  140.         args++;
  141.     }
  142.     if (argc >= 2 && strcmp(argv[1], "+c") == 0)
  143.     {
  144.         console = 0;
  145.         args++;
  146.     }
  147.     if (console)
  148.         open_mem_fd();
  149. #endif
  150.     DB;
  151.  
  152.                     /* GET UTMP ENTRY */
  153. #ifdef USE_GETUT
  154.     if ( (tty_ptr = ttyname(0)) == NULL)
  155.         halt("shm:  Cannot find tty name.\n");
  156.     strcpy(my_utmp.ut_line, strrchr(tty_ptr, '/') + 1);
  157.     strcpy(orig_tty, strrchr(tty_ptr, '/') + 1);
  158.     if ( (utmp_ptr = getutline(&my_utmp)) == NULL)
  159.         halt("shm:  Cannot find utmp entry.\n");
  160.     memcpy(&my_utmp, utmp_ptr, sizeof(struct utmp));
  161. #endif
  162.  
  163.                 /* SET UP TERMINAL CHARACTERISTICS */
  164.  
  165.     if (ioctl( 0, TCGETA, &savedterm ) == -1)
  166.         halt("PERROR shm:  Can not get terminal driver settings.\n");
  167.  
  168.     signal(SIGHUP, exit_layers);
  169.     signal(SIGINT, SIG_IGN);
  170.     signal(SIGQUIT, SIG_IGN);
  171.     signal(SIGTERM, exit_layers);
  172.     signal(SIGCLD, SIG_DFL);    /* hold dead children until we are ready */
  173.     DB;
  174.     
  175.     cntrlterm = layerterm = savedterm;
  176.     if ( layerterm.c_cc[VSWTCH] == 0 )     /* stty shows this as ^` */
  177.         layerterm.c_cc[VSWTCH] = CONTROL('z');
  178.     layerterm.c_cflag |= LOBLK;    /* start layer with blocking on */
  179.  
  180.     /* this allows control process to sleep on read and return immediately
  181.        when one character is entered */
  182.     cntrlterm.c_lflag &= ~(ICANON|ECHO|ISIG);
  183.     cntrlterm.c_cc[VMIN] = 1;
  184.     cntrlterm.c_cc[VTIME] = 0;
  185.     cntrlterm.c_cflag &= ~LOBLK;    /* no output blocking */
  186.     DB;
  187.  
  188.                     /* GET CLEAR SCREEN STRING */
  189.  
  190. #ifdef TERMINFO
  191.     if (setupterm(NULL, 2, &errret) == 0 &&  /* 0==OK in curses.h */
  192.        (clear_ptr = (char *)tigetstr("clear")) != NULL &&
  193.         clear_ptr != (char *) -1 )
  194. #else
  195.     if (tgetent(clear_ptr, getenv("TERM")) != -1 &&
  196.        (clear_ptr = (char *)tgetstr("cl", clear_str)) != NULL )
  197. #endif
  198.             strcpy(clear_str,clear_ptr);
  199.     else
  200.             strcpy(clear_str,"");
  201.     DB;
  202.  
  203.                 /* SET UP INPUT/OUTPUT IN CONTROL LAYER */
  204.     
  205.     fclose( stdin );
  206.     for (sxt_group = 0; sxt_group < MAX_SXT_GROUPS; sxt_group++)
  207.         if (open_sxt_device(0) != NOT_FOUND)
  208.             break;
  209.     if (sxt_group == MAX_SXT_GROUPS)
  210.         halt("No available ttys.\n");
  211.  
  212.       if ( fdopen( 0, "r" ) == NULL )
  213.         halt("PERROR child fopen failed\n");
  214.  
  215.     fclose( stdout );
  216.     dup( 0 );
  217.     if ( fdopen( 1, "w" ) == NULL )
  218.         halt("PERROR child fopen stdout\n" );
  219.     DB;
  220.                         /* SET UP LAYERS */
  221.         
  222.      if (ioctl(0, SXTIOCLINK, MAXPCHAN) == -1)
  223.         halt(
  224.     "PERROR shm: Can not allocate layers, perhaps layers already active.\n");
  225.  
  226.                         /* get ownership of sxt group files */
  227.     for (slot = 0; slot < MAXPCHAN; slot++)    
  228.     {
  229.         sprintf(sxt_file, "%s%03d", SXT_DEVICE, slot + sxt_group * SXT_STEP );
  230.         if ( chown(sxt_file, getuid(), getgid()) == -1)
  231.             halt("PERROR shm:  Can not set ownership of sxt files.\n");
  232.     }
  233.  
  234.                         /* ROOT PRIV ENDS HERE */    
  235.  
  236.     /* needed root priv to do SXTIOCLINK, restore user privs */
  237.     setuid(getuid());
  238.     DB;
  239.     
  240.     if ( ioctl(0, SXTIOCSWTCH, 0) == -1)
  241.         halt("PERROR shm: Can not switch to controlling layer.\n");
  242.     
  243.     if (ioctl( 0, TCSETA, &cntrlterm ) == -1)
  244.         halt("PERROR shm: Can not set terminal.\n");
  245.  
  246.     fclose( stderr );    /* all errors are done, move stderr */
  247.     dup( 0 );
  248.     if ( fdopen( 2, "w" ) == NULL )
  249.         halt("PERROR child fopen stderr\n" );
  250.     setvbuf(stderr, NULL, _IONBF, NULL);    /* stderr not buffered */
  251.     DB;
  252.     
  253.     for (i = 1; args < argc; args++, i++)
  254.         (void)create_layer(i, argv[args], NOCLRSCR);
  255.         
  256.     manage_layer();
  257.     /*NOTREACHED*/
  258. }
  259.  
  260. /*-------------------------------------------------------------------------
  261. **
  262. **     manage_layer    - loop that waits for control activation and does commands
  263. **
  264. **-------------------------------------------------------------------------*/
  265.  
  266. void manage_layer()
  267. {
  268.     int        new_slot, tog_slot, i;
  269.     char    option;
  270.  
  271.     
  272.     if (layer[1].status == FREE)
  273.         cur_slot = create_layer(1, NULL, NOCLRSCR);
  274.     else
  275.         cur_slot = activate_layer(1, 1, NEXT);
  276.  
  277.     if (cur_slot == NOT_FOUND)
  278.         halt("shm:  Can not start any layer.\n");
  279.  
  280.     DB;
  281.     while (1)
  282.     {
  283.         signal(SIGCLD, layer_died);
  284.         while (read(0,&option,1) <= 0)
  285.             ;
  286.         signal(SIGCLD, SIG_IGN);
  287.  
  288.         new_slot = cur_slot;     /* layer_died may have changed cur_slot */
  289.  
  290.         if ( layerterm.c_cc[VERASE] == option )    /* they hit back space */
  291.             option = 'p';
  292.             
  293.         if ( layerterm.c_cc[VSWTCH] == option )    /* they hit switch char */
  294.             option = 'n';
  295.             
  296.         switch (tolower(option))
  297.         {
  298.             case 'z':
  299.             case 'c':
  300.                         new_slot = create_layer(cur_slot, NULL, CLRSCR);
  301.                         break;
  302.             case 'd':
  303.                         signal(SIGCLD, SIG_DFL);
  304.                         if (layer[cur_slot].status == USED)
  305.                             kill(-layer[cur_slot].pid, SIGHUP);
  306.                         break;
  307.             case CONTROL('z'):
  308.             case 'n':
  309.             case CONTROL('n'):
  310.             case 'l':
  311.             case CONTROL('l'):
  312.             case CONTROL('j'):
  313.             case CONTROL('m'):
  314.                         i = (cur_slot < MAXPCHAN-1 ? cur_slot + 1 : 1);
  315.                         new_slot = activate_layer(i, cur_slot, NEXT);
  316.                         break;
  317.             case 'p':
  318.             case CONTROL('p'):
  319.                         i = (cur_slot > 1 ? cur_slot - 1 : MAXPCHAN-1);
  320.                         new_slot = activate_layer(i, cur_slot, PREV);
  321.                         break;
  322.             case 's':
  323.                         for (i = 1; i < MAXPCHAN; i++)
  324.                             if (layer[i].status == USED)
  325.                                 fprintf(stderr,"%d ", i);
  326.                         putc('\n', stderr);
  327.                         new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  328.                         break;
  329.             case '?':
  330.             case 'h':    PRINT_OPTIONS;
  331.                         new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  332.                         break;
  333.             case 'b':
  334.                         if ( ioctl(0, SXTIOCUBLK, cur_slot) == -1)
  335.                             fprintf(stderr, "shm: Can not turn off blocking.\n");
  336.                         new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  337.                         break;
  338.             case 'r':
  339.             case ' ':
  340.                         new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  341.                         break;
  342.             case 't':    
  343.                         new_slot = activate_layer(tog_slot, cur_slot, NEXT);
  344.                         break;
  345.             case CONTROL('d'):
  346.             case 'q':
  347.                         exit_layers(0);
  348.                         break;
  349.             default :
  350.                         i = option - '0';
  351.                         if (i >= 1 && i < MAXPCHAN)
  352.                         {
  353.                             if (layer[i].status == USED)
  354.                                 new_slot = activate_layer(i, cur_slot, NEXT);
  355.                             else
  356.                                 new_slot = create_layer(i, NULL, CLRSCR);
  357.                         }
  358.                         else
  359.                         {
  360.                             if (isprint(option))
  361.                                 fprintf(stderr,
  362.                                     "shm: '%c' unknown command\n",option);
  363.                             else
  364.                                 fprintf(stderr, "shm: unknown command\n");
  365.                             new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  366.                         }
  367.                         break;
  368.         }
  369.         if (new_slot != NOT_FOUND && new_slot != cur_slot)
  370.         {
  371.             tog_slot = cur_slot;
  372.             cur_slot = new_slot;
  373.         }
  374.     DB;
  375.     }
  376. }
  377.         
  378. /*---------------------------------------------------------------------------
  379. **
  380. **    activate_layer - find next used slot, test for validity
  381. **
  382. **--------------------------------------------------------------------------*/
  383.  
  384. int activate_layer(slot, old_slot, direct)
  385. int slot,        /* start searching at this slot */
  386.     old_slot,    /* slot that was last active */
  387.     direct;        /* direction of search NEXT, PREV */
  388. {
  389.     
  390.         /* SCAN USED SLOTS FOR ACTIVE PROCESSES, REMOVE DEAD SLOTS */
  391.     while ( (slot = get_slot(slot, USED, direct)) != NOT_FOUND &&
  392.             ( ioctl(0, SXTIOCSWTCH, slot) == -1  ||
  393.               ( kill(layer[slot].pid, 0) == -1 && errno == ESRCH) ) )
  394.     {
  395.         kill(-layer[slot].pid, SIGHUP);
  396.         layer[slot].status = FREE;
  397.     }
  398.  
  399.     if (slot != NOT_FOUND)
  400.     {
  401. #ifdef USE_GETUT
  402.         sprintf(my_utmp.ut_line,"%s%03d", strrchr(SXT_DEVICE, '/') + 1,
  403.                                             slot + sxt_group * SXT_STEP);
  404.         pututline(&my_utmp);
  405. #endif
  406.          if (slot != old_slot)
  407.         {
  408. #ifdef USE_CONDUMP
  409.             if (console)
  410.             {
  411.                 if (layer[old_slot].status == USED)
  412.                     condump(layer[old_slot].screen, 1, 0, 1, 1);
  413.                 conrestore(layer[slot].screen, 1, 0, 1, 1);
  414.             }
  415.             else
  416. #endif
  417.             {
  418.                 putp(clear_str );
  419.                 fflush(stdout);
  420.                 fprintf(stderr,"[%d] ", slot);
  421.                 fflush(stderr);
  422.             }
  423.         }
  424.     }
  425.     return slot;
  426. }
  427.  
  428. /*----------------------------------------------------------------------------
  429. **
  430. **    create_layer - create new layer using fork()
  431. **
  432. **--------------------------------------------------------------------------*/
  433.  
  434. int create_layer( slot, exfile, clrscr )
  435. int slot,        /* slot to start searching for FREE slot */
  436.     clrscr;        /* should screen be cleared on activation */
  437. char *exfile;    /* startup executable, or NULL for shell */
  438. {
  439.     int pid;
  440.     char layerstr[15], execstr[1024], execarg0[25];
  441.     int control_fd;
  442.     char *getenv();
  443. #ifndef SHELL_STARTUP
  444.     char ps1str[15];
  445. #endif
  446.  
  447.     if ((slot = get_slot(slot, FREE, NEXT)) == NOT_FOUND)
  448.     {
  449.         fprintf(stderr, "shm:  No more ttys.\n");
  450.         return NOT_FOUND;
  451.     }
  452.     
  453. #ifdef USE_CONDUMP
  454.     if (console)
  455.         if (layer[cur_slot].status == USED)
  456.             condump(layer[cur_slot].screen, 1, 0, 1, 1);
  457. #endif
  458.  
  459.     if ( (pid=fork()) == 0)
  460.     {
  461.         signal( SIGINT,  SIG_DFL );
  462.         signal( SIGQUIT, SIG_DFL );
  463.         signal( SIGHUP,  SIG_DFL );
  464.         signal( SIGTERM, SIG_DFL );
  465.         signal( SIGCLD,  SIG_DFL );
  466.         setpgrp();
  467.         
  468. #ifdef DEBUG
  469. fclose(db_file);
  470. #endif
  471.         
  472.         control_fd = dup(0);
  473.         fclose( stdin );
  474.         if (open_sxt_device(slot) == NOT_FOUND)
  475.             halt("PERROR shm:  Can not open tty.\n");
  476.  
  477.         if ( exfile == NULL && ioctl(control_fd, SXTIOCSWTCH, slot) == -1)
  478.             halt( "PERROR Can not activate slot %d.\n", slot);
  479.                 
  480.         if ( exfile != NULL && ioctl(control_fd, SXTIOCWF, slot) == -1)
  481.             halt( "PERROR shm: Can not wait for activation.\n");
  482.  
  483.  
  484.         if ( ioctl( 0, TCSETA, &layerterm ) == -1)
  485.             halt("PERROR shm:  Can not set terminal driver characteristics.\n");
  486.  
  487.         if (clrscr == CLRSCR)
  488.             putp(clear_str);
  489.  
  490.         fclose(stdout); dup(0);
  491.         fclose(stderr); dup(0);
  492.         close(control_fd);
  493. #ifdef USE_CONDUMP
  494.         if (console)    close_mem_fd();
  495. #endif
  496.         
  497. #ifdef USE_GETUT
  498.         sprintf(my_utmp.ut_line,"%s%03d", strrchr(SXT_DEVICE, '/') + 1,
  499.                                             slot + sxt_group * SXT_STEP );
  500.         pututline(&my_utmp);
  501.         endutent();
  502. #endif
  503.         setpgrp();
  504.         sprintf(layerstr,"LAYER=%d",slot);
  505.         putenv(layerstr);
  506.         
  507.         if (exfile == NULL || *exfile == '\0')
  508.         {
  509.             if (getenv("ISHELL") != NULL)        /* interactive shell */
  510.                 strcpy(execstr, getenv("ISHELL"));
  511.             else if (getenv("SHELL") != NULL)
  512.                 strcpy(execstr, getenv("SHELL"));
  513.             else strcpy(execstr, "/bin/sh");
  514.  
  515. #ifdef SHELL_STARTUP
  516.                 /* put dash before command name to signal startup */
  517.             strcpy(execarg0,strrchr(execstr, '/'));
  518.             execarg0[0] = '-';
  519. #else
  520.             strcpy(execarg0,strrchr(execstr, '/') + 1);
  521.             /* if they don't run their .profile, make a prompt */
  522.             sprintf(ps1str,"PS1=(%d) ", slot);
  523.             putenv(ps1str);
  524. #endif
  525.             execl(execstr, execarg0, (char *)0 );
  526.             halt("PERROR shm: execl failed.\n");
  527.         }
  528.         else
  529.         {
  530.             sprintf(execstr, "exec %s", exfile);
  531.             execl("/bin/sh", "sh", "-c", execstr, (char *)0 );
  532.             halt("PERROR shm: execl failed.\n");
  533.         }
  534.         /*NOTREACHED*/
  535.     }
  536.  
  537.     if (pid == -1)
  538.     {
  539.         fprintf(stderr, "shm: fork failed.\n");
  540.         return(NOT_FOUND);
  541.     }
  542.  
  543.     layer[slot].pid = pid;
  544.     layer[slot].status = USED;
  545. #ifdef USE_CONDUMP
  546.     if (console)
  547.         if (layer[slot].screen == 0)
  548.             if ( (layer[slot].screen = malloc(SCREEN_SIZE+2)) == NULL)
  549.                 halt("PERROR shm : can not get more memory.\n");
  550. #endif
  551.     return slot;
  552. }
  553.     
  554.     
  555. /*----------------------------------------------------------------------------
  556. **
  557. **    get_slot - scan slots, return desired slot number
  558. **
  559. **--------------------------------------------------------------------------*/
  560.  
  561. int get_slot( slot, status, direct )
  562. int slot,        /* start searching at this slot */
  563.     status,        /* for this type of slot, USED or FREE */
  564.     direct;        /* search in this direction, NEXT or PREV */
  565. {
  566.     int loops = 0;
  567.  
  568.     while (layer[slot].status != status && ++loops < MAXPCHAN)
  569.     {
  570.         slot += direct;
  571.         if (slot == MAXPCHAN)
  572.             slot = 1;
  573.         if (slot == 0)
  574.             slot = MAXPCHAN-1;
  575.     }
  576.  
  577.     return (layer[slot].status == status) ? slot : NOT_FOUND;
  578. }
  579.  
  580. /*----------------------------------------------------------------------------
  581. **
  582. **    open_sxt_device - open sxt device
  583. **
  584. **--------------------------------------------------------------------------*/
  585.  
  586. int open_sxt_device( slot )
  587. int slot;
  588. {
  589.     char    sxt_file[40];
  590.  
  591.     sprintf(sxt_file, "%s%03d", SXT_DEVICE, slot + sxt_group * SXT_STEP );
  592.     return open(sxt_file, O_RDWR | ((slot == 0) ? O_EXCL : 0) );
  593. }
  594.  
  595. /*----------------------------------------------------------------------------
  596. **
  597. **    layer_died - layer died, change status
  598. **
  599. **--------------------------------------------------------------------------*/
  600.  
  601. void layer_died(sig)
  602. int sig;
  603. {
  604.     int new_slot;
  605.  
  606.     signal(SIGCLD, SIG_IGN);    /* discard child */
  607.     new_slot = activate_layer(cur_slot, cur_slot, NEXT);
  608.     if (new_slot != NOT_FOUND)
  609.         cur_slot = new_slot;
  610.     else
  611.         exit_layers(0);
  612.     signal(SIGCLD, layer_died);
  613.  
  614. }
  615.     
  616. /*----------------------------------------------------------------------------
  617. **
  618. **    exit_layers - this and halt are the only exit points
  619. **
  620. **--------------------------------------------------------------------------*/
  621.  
  622. void exit_layers(sig)
  623. int sig;
  624. {
  625.     int slot;
  626.  
  627.     if (sig != SIGHUP)
  628.     {
  629.         ioctl(0, SXTIOCSWTCH, 0);
  630.         (void)ioctl( 0, TCSETA, &savedterm );
  631.         putchar('\n');
  632.     }
  633.         
  634.     signal(SIGHUP,  SIG_IGN );
  635.     signal(SIGINT,  SIG_IGN );
  636.     signal(SIGQUIT, SIG_IGN );
  637.     signal(SIGTERM, SIG_IGN );
  638.     signal(SIGCLD,  SIG_IGN );
  639.  
  640. #ifdef USE_GETUT
  641.     strcpy(my_utmp.ut_line, orig_tty);
  642.     pututline(&my_utmp);
  643.     endutent();
  644. #endif
  645.  
  646.     for (slot = 1; slot < MAXPCHAN; slot++)
  647.         if (layer[slot].status == USED )
  648.         {
  649.             kill(-layer[slot].pid, (sig != 0) ? sig : SIGHUP );
  650.             ioctl(0, SXTIOCSWTCH, slot);    /* activate layer and/or */
  651.             ioctl(0, SXTIOCUBLK,  slot);    /* unblock layer */
  652.         }
  653.  
  654.     exit(sig);
  655. }
  656.