home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume32
/
shlm
/
part01
/
shm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-20
|
16KB
|
656 lines
/*
**
** shm.c
** version 1.1
** Author - root%candle.uucp@bts.com
**
** shell layers with sxt devices
**
*/
/* tabs = 4 */
#include "config.h"
#include <fcntl.h>
#include <ctype.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <varargs.h>
#include <sys/types.h>
#include <sys/tty.h>
#include <sys/sxt.h>
#include <termio.h>
#include <malloc.h>
#ifdef USE_GETUT
# include <utmp.h>
#endif
#ifdef DEBUG
FILE *db_file;
#define DB fprintf(db_file,"shm eached line: %d\n",__LINE__)
#else
#define DB
#endif
#ifndef SXT_STEP
#define SXT_STEP MAXPCHAN
#endif
#define USED 1
#define FREE 0
#define NEXT 1
#define PREV (-1)
#define CLRSCR 1 /* define this to be 0 if you don't like your
screen being cleared when changing layers */
#define NOCLRSCR 0
#define NOT_FOUND (-1)
#define PRINT_OPTIONS fprintf(stderr,"\n\
All commands start with %c%c, then:\n\
C,Z create\n\
D delete\n\
S show layers\n\
^Z,N,^N,L,^L,Swt,Ret next layers\n\
P,^P,Bs previous layer\n\
1-%1d activate layer #\n\
B turn off blocking\n\
R,Sp resume\n\
T toggle between layers\n\
H,? help\n\
Q,^D quit\n",\
(iscntrl(layerterm.c_cc[VSWTCH]) ? '^' : ' '),\
layerterm.c_cc[VSWTCH] + (iscntrl(layerterm.c_cc[VSWTCH]) ? '@' : 0),\
MAXPCHAN-1);
#define CONTROL(x) ((x) & 0x1f)
struct {
int status;
int pid;
char *screen;
} layer[MAXPCHAN];
struct termio savedterm, layerterm, cntrlterm;
int sxt_group; /* active sxt group made up of MAXPCHAN devices */
int cur_slot; /* active sxt slot within group */
char clear_str[20]; /* string to clear screen */
int console = 0;
void exit_layers();
void manage_layer();
void layer_died();
void halt();
void exit();
#ifdef USE_GETUT
char orig_tty[15]; /* original tty in utmp */
struct utmp my_utmp;
#endif
/*--------------------------------------------------------------------------
**
** main
**
**-------------------------------------------------------------------------*/
main(argc, argv)
int argc;
char **argv;
{
int errret, args = 1, i;
char *clear_ptr,
*tty_ptr,
*getenv(),
*ttyname();
char sxt_file[40];
int slot;
#ifdef USE_GETUT
struct utmp *utmp_ptr,
*getutline();
#endif
#ifdef DEBUG
db_file = fopen("shm_debug.log","w");
#endif
#ifdef USE_CONDUMP
if (strcmp(argv[0], "condump") == 0 ||
strcmp(strrchr(argv[0],'/'), "/condump" ) == 0 ||
strcmp(argv[0], "conrestore") == 0 ||
strcmp(strrchr(argv[0],'/'), "/conrestore" ) == 0)
return con_run(argc, argv);
if ( (tty_ptr = ttyname(0)) == NULL)
halt("shm: Cannot find tty name.\n");
if (strcmp(tty_ptr, CONSOLE_DEVICE) == 0)
console = 1;
if (argc >= 2 && strcmp(argv[1], "-c") == 0)
{
console = 1;
args++;
}
if (argc >= 2 && strcmp(argv[1], "+c") == 0)
{
console = 0;
args++;
}
if (console)
open_mem_fd();
#endif
DB;
/* GET UTMP ENTRY */
#ifdef USE_GETUT
if ( (tty_ptr = ttyname(0)) == NULL)
halt("shm: Cannot find tty name.\n");
strcpy(my_utmp.ut_line, strrchr(tty_ptr, '/') + 1);
strcpy(orig_tty, strrchr(tty_ptr, '/') + 1);
if ( (utmp_ptr = getutline(&my_utmp)) == NULL)
halt("shm: Cannot find utmp entry.\n");
memcpy(&my_utmp, utmp_ptr, sizeof(struct utmp));
#endif
/* SET UP TERMINAL CHARACTERISTICS */
if (ioctl( 0, TCGETA, &savedterm ) == -1)
halt("PERROR shm: Can not get terminal driver settings.\n");
signal(SIGHUP, exit_layers);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGTERM, exit_layers);
signal(SIGCLD, SIG_DFL); /* hold dead children until we are ready */
DB;
cntrlterm = layerterm = savedterm;
if ( layerterm.c_cc[VSWTCH] == 0 ) /* stty shows this as ^` */
layerterm.c_cc[VSWTCH] = CONTROL('z');
layerterm.c_cflag |= LOBLK; /* start layer with blocking on */
/* this allows control process to sleep on read and return immediately
when one character is entered */
cntrlterm.c_lflag &= ~(ICANON|ECHO|ISIG);
cntrlterm.c_cc[VMIN] = 1;
cntrlterm.c_cc[VTIME] = 0;
cntrlterm.c_cflag &= ~LOBLK; /* no output blocking */
DB;
/* GET CLEAR SCREEN STRING */
#ifdef TERMINFO
if (setupterm(NULL, 2, &errret) == 0 && /* 0==OK in curses.h */
(clear_ptr = (char *)tigetstr("clear")) != NULL &&
clear_ptr != (char *) -1 )
#else
if (tgetent(clear_ptr, getenv("TERM")) != -1 &&
(clear_ptr = (char *)tgetstr("cl", clear_str)) != NULL )
#endif
strcpy(clear_str,clear_ptr);
else
strcpy(clear_str,"");
DB;
/* SET UP INPUT/OUTPUT IN CONTROL LAYER */
fclose( stdin );
for (sxt_group = 0; sxt_group < MAX_SXT_GROUPS; sxt_group++)
if (open_sxt_device(0) != NOT_FOUND)
break;
if (sxt_group == MAX_SXT_GROUPS)
halt("No available ttys.\n");
if ( fdopen( 0, "r" ) == NULL )
halt("PERROR child fopen failed\n");
fclose( stdout );
dup( 0 );
if ( fdopen( 1, "w" ) == NULL )
halt("PERROR child fopen stdout\n" );
DB;
/* SET UP LAYERS */
if (ioctl(0, SXTIOCLINK, MAXPCHAN) == -1)
halt(
"PERROR shm: Can not allocate layers, perhaps layers already active.\n");
/* get ownership of sxt group files */
for (slot = 0; slot < MAXPCHAN; slot++)
{
sprintf(sxt_file, "%s%03d", SXT_DEVICE, slot + sxt_group * SXT_STEP );
if ( chown(sxt_file, getuid(), getgid()) == -1)
halt("PERROR shm: Can not set ownership of sxt files.\n");
}
/* ROOT PRIV ENDS HERE */
/* needed root priv to do SXTIOCLINK, restore user privs */
setuid(getuid());
DB;
if ( ioctl(0, SXTIOCSWTCH, 0) == -1)
halt("PERROR shm: Can not switch to controlling layer.\n");
if (ioctl( 0, TCSETA, &cntrlterm ) == -1)
halt("PERROR shm: Can not set terminal.\n");
fclose( stderr ); /* all errors are done, move stderr */
dup( 0 );
if ( fdopen( 2, "w" ) == NULL )
halt("PERROR child fopen stderr\n" );
setvbuf(stderr, NULL, _IONBF, NULL); /* stderr not buffered */
DB;
for (i = 1; args < argc; args++, i++)
(void)create_layer(i, argv[args], NOCLRSCR);
manage_layer();
/*NOTREACHED*/
}
/*-------------------------------------------------------------------------
**
** manage_layer - loop that waits for control activation and does commands
**
**-------------------------------------------------------------------------*/
void manage_layer()
{
int new_slot, tog_slot, i;
char option;
if (layer[1].status == FREE)
cur_slot = create_layer(1, NULL, NOCLRSCR);
else
cur_slot = activate_layer(1, 1, NEXT);
if (cur_slot == NOT_FOUND)
halt("shm: Can not start any layer.\n");
DB;
while (1)
{
signal(SIGCLD, layer_died);
while (read(0,&option,1) <= 0)
;
signal(SIGCLD, SIG_IGN);
new_slot = cur_slot; /* layer_died may have changed cur_slot */
if ( layerterm.c_cc[VERASE] == option ) /* they hit back space */
option = 'p';
if ( layerterm.c_cc[VSWTCH] == option ) /* they hit switch char */
option = 'n';
switch (tolower(option))
{
case 'z':
case 'c':
new_slot = create_layer(cur_slot, NULL, CLRSCR);
break;
case 'd':
signal(SIGCLD, SIG_DFL);
if (layer[cur_slot].status == USED)
kill(-layer[cur_slot].pid, SIGHUP);
break;
case CONTROL('z'):
case 'n':
case CONTROL('n'):
case 'l':
case CONTROL('l'):
case CONTROL('j'):
case CONTROL('m'):
i = (cur_slot < MAXPCHAN-1 ? cur_slot + 1 : 1);
new_slot = activate_layer(i, cur_slot, NEXT);
break;
case 'p':
case CONTROL('p'):
i = (cur_slot > 1 ? cur_slot - 1 : MAXPCHAN-1);
new_slot = activate_layer(i, cur_slot, PREV);
break;
case 's':
for (i = 1; i < MAXPCHAN; i++)
if (layer[i].status == USED)
fprintf(stderr,"%d ", i);
putc('\n', stderr);
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
break;
case '?':
case 'h': PRINT_OPTIONS;
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
break;
case 'b':
if ( ioctl(0, SXTIOCUBLK, cur_slot) == -1)
fprintf(stderr, "shm: Can not turn off blocking.\n");
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
break;
case 'r':
case ' ':
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
break;
case 't':
new_slot = activate_layer(tog_slot, cur_slot, NEXT);
break;
case CONTROL('d'):
case 'q':
exit_layers(0);
break;
default :
i = option - '0';
if (i >= 1 && i < MAXPCHAN)
{
if (layer[i].status == USED)
new_slot = activate_layer(i, cur_slot, NEXT);
else
new_slot = create_layer(i, NULL, CLRSCR);
}
else
{
if (isprint(option))
fprintf(stderr,
"shm: '%c' unknown command\n",option);
else
fprintf(stderr, "shm: unknown command\n");
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
}
break;
}
if (new_slot != NOT_FOUND && new_slot != cur_slot)
{
tog_slot = cur_slot;
cur_slot = new_slot;
}
DB;
}
}
/*---------------------------------------------------------------------------
**
** activate_layer - find next used slot, test for validity
**
**--------------------------------------------------------------------------*/
int activate_layer(slot, old_slot, direct)
int slot, /* start searching at this slot */
old_slot, /* slot that was last active */
direct; /* direction of search NEXT, PREV */
{
/* SCAN USED SLOTS FOR ACTIVE PROCESSES, REMOVE DEAD SLOTS */
while ( (slot = get_slot(slot, USED, direct)) != NOT_FOUND &&
( ioctl(0, SXTIOCSWTCH, slot) == -1 ||
( kill(layer[slot].pid, 0) == -1 && errno == ESRCH) ) )
{
kill(-layer[slot].pid, SIGHUP);
layer[slot].status = FREE;
}
if (slot != NOT_FOUND)
{
#ifdef USE_GETUT
sprintf(my_utmp.ut_line,"%s%03d", strrchr(SXT_DEVICE, '/') + 1,
slot + sxt_group * SXT_STEP);
pututline(&my_utmp);
#endif
if (slot != old_slot)
{
#ifdef USE_CONDUMP
if (console)
{
if (layer[old_slot].status == USED)
condump(layer[old_slot].screen, 1, 0, 1, 1);
conrestore(layer[slot].screen, 1, 0, 1, 1);
}
else
#endif
{
putp(clear_str );
fflush(stdout);
fprintf(stderr,"[%d] ", slot);
fflush(stderr);
}
}
}
return slot;
}
/*----------------------------------------------------------------------------
**
** create_layer - create new layer using fork()
**
**--------------------------------------------------------------------------*/
int create_layer( slot, exfile, clrscr )
int slot, /* slot to start searching for FREE slot */
clrscr; /* should screen be cleared on activation */
char *exfile; /* startup executable, or NULL for shell */
{
int pid;
char layerstr[15], execstr[1024], execarg0[25];
int control_fd;
char *getenv();
#ifndef SHELL_STARTUP
char ps1str[15];
#endif
if ((slot = get_slot(slot, FREE, NEXT)) == NOT_FOUND)
{
fprintf(stderr, "shm: No more ttys.\n");
return NOT_FOUND;
}
#ifdef USE_CONDUMP
if (console)
if (layer[cur_slot].status == USED)
condump(layer[cur_slot].screen, 1, 0, 1, 1);
#endif
if ( (pid=fork()) == 0)
{
signal( SIGINT, SIG_DFL );
signal( SIGQUIT, SIG_DFL );
signal( SIGHUP, SIG_DFL );
signal( SIGTERM, SIG_DFL );
signal( SIGCLD, SIG_DFL );
setpgrp();
#ifdef DEBUG
fclose(db_file);
#endif
control_fd = dup(0);
fclose( stdin );
if (open_sxt_device(slot) == NOT_FOUND)
halt("PERROR shm: Can not open tty.\n");
if ( exfile == NULL && ioctl(control_fd, SXTIOCSWTCH, slot) == -1)
halt( "PERROR Can not activate slot %d.\n", slot);
if ( exfile != NULL && ioctl(control_fd, SXTIOCWF, slot) == -1)
halt( "PERROR shm: Can not wait for activation.\n");
if ( ioctl( 0, TCSETA, &layerterm ) == -1)
halt("PERROR shm: Can not set terminal driver characteristics.\n");
if (clrscr == CLRSCR)
putp(clear_str);
fclose(stdout); dup(0);
fclose(stderr); dup(0);
close(control_fd);
#ifdef USE_CONDUMP
if (console) close_mem_fd();
#endif
#ifdef USE_GETUT
sprintf(my_utmp.ut_line,"%s%03d", strrchr(SXT_DEVICE, '/') + 1,
slot + sxt_group * SXT_STEP );
pututline(&my_utmp);
endutent();
#endif
setpgrp();
sprintf(layerstr,"LAYER=%d",slot);
putenv(layerstr);
if (exfile == NULL || *exfile == '\0')
{
if (getenv("ISHELL") != NULL) /* interactive shell */
strcpy(execstr, getenv("ISHELL"));
else if (getenv("SHELL") != NULL)
strcpy(execstr, getenv("SHELL"));
else strcpy(execstr, "/bin/sh");
#ifdef SHELL_STARTUP
/* put dash before command name to signal startup */
strcpy(execarg0,strrchr(execstr, '/'));
execarg0[0] = '-';
#else
strcpy(execarg0,strrchr(execstr, '/') + 1);
/* if they don't run their .profile, make a prompt */
sprintf(ps1str,"PS1=(%d) ", slot);
putenv(ps1str);
#endif
execl(execstr, execarg0, (char *)0 );
halt("PERROR shm: execl failed.\n");
}
else
{
sprintf(execstr, "exec %s", exfile);
execl("/bin/sh", "sh", "-c", execstr, (char *)0 );
halt("PERROR shm: execl failed.\n");
}
/*NOTREACHED*/
}
if (pid == -1)
{
fprintf(stderr, "shm: fork failed.\n");
return(NOT_FOUND);
}
layer[slot].pid = pid;
layer[slot].status = USED;
#ifdef USE_CONDUMP
if (console)
if (layer[slot].screen == 0)
if ( (layer[slot].screen = malloc(SCREEN_SIZE+2)) == NULL)
halt("PERROR shm : can not get more memory.\n");
#endif
return slot;
}
/*----------------------------------------------------------------------------
**
** get_slot - scan slots, return desired slot number
**
**--------------------------------------------------------------------------*/
int get_slot( slot, status, direct )
int slot, /* start searching at this slot */
status, /* for this type of slot, USED or FREE */
direct; /* search in this direction, NEXT or PREV */
{
int loops = 0;
while (layer[slot].status != status && ++loops < MAXPCHAN)
{
slot += direct;
if (slot == MAXPCHAN)
slot = 1;
if (slot == 0)
slot = MAXPCHAN-1;
}
return (layer[slot].status == status) ? slot : NOT_FOUND;
}
/*----------------------------------------------------------------------------
**
** open_sxt_device - open sxt device
**
**--------------------------------------------------------------------------*/
int open_sxt_device( slot )
int slot;
{
char sxt_file[40];
sprintf(sxt_file, "%s%03d", SXT_DEVICE, slot + sxt_group * SXT_STEP );
return open(sxt_file, O_RDWR | ((slot == 0) ? O_EXCL : 0) );
}
/*----------------------------------------------------------------------------
**
** layer_died - layer died, change status
**
**--------------------------------------------------------------------------*/
void layer_died(sig)
int sig;
{
int new_slot;
signal(SIGCLD, SIG_IGN); /* discard child */
new_slot = activate_layer(cur_slot, cur_slot, NEXT);
if (new_slot != NOT_FOUND)
cur_slot = new_slot;
else
exit_layers(0);
signal(SIGCLD, layer_died);
}
/*----------------------------------------------------------------------------
**
** exit_layers - this and halt are the only exit points
**
**--------------------------------------------------------------------------*/
void exit_layers(sig)
int sig;
{
int slot;
if (sig != SIGHUP)
{
ioctl(0, SXTIOCSWTCH, 0);
(void)ioctl( 0, TCSETA, &savedterm );
putchar('\n');
}
signal(SIGHUP, SIG_IGN );
signal(SIGINT, SIG_IGN );
signal(SIGQUIT, SIG_IGN );
signal(SIGTERM, SIG_IGN );
signal(SIGCLD, SIG_IGN );
#ifdef USE_GETUT
strcpy(my_utmp.ut_line, orig_tty);
pututline(&my_utmp);
endutent();
#endif
for (slot = 1; slot < MAXPCHAN; slot++)
if (layer[slot].status == USED )
{
kill(-layer[slot].pid, (sig != 0) ? sig : SIGHUP );
ioctl(0, SXTIOCSWTCH, slot); /* activate layer and/or */
ioctl(0, SXTIOCUBLK, slot); /* unblock layer */
}
exit(sig);
}