|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 24155 (0x5e5b)
Types: TextFile
Names: »tapemgr.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/tapemgr/tapemgr.c«
#ifndef lint
static char rcsid[] =
"$Header: tapemgr.c,v 2.3 86/08/15 13:19:39 thompson Exp $";
#endif
/*
*
* T A P E M G R
*
* AUTHOR: Written by Michael A . Thompson at Dalhousie University
* Department of Mathematics, Statistics and Computing Science.
*
* PURPOSE: To restrict access to tapedrives to one user at a time.
* See tapemgr.1 for details of usage.
*
* NOTICE: This is free software, do with it what you will.
*
*/
/*
* $Locker: $
* $Source: /usr/src/local/tapemgr/RCS/tapemgr.c,v $
*
* $Log: tapemgr.c,v $
* Revision 2.3 86/08/15 13:19:39 thompson
* shorter logmessage
*
* Revision 2.2 86/04/08 04:27:06 thompson
* fix comments.
*
* Revision 2.1 86/03/25 11:50:59 thompson
* author info.
*
* Revision 2.0 86/03/24 23:50:30 thompson
* First, release.
*
* Revision 1.1 86/03/22 23:23:43 thompson
* Initial revision
*
*/
#include <ctype.h>
#include <pwd.h>
#include <stdio.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/mtio.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#define RESTORE_TERMINAL /* Define this if you want the terminal
state restored upon termination */
#define KERNAL_PAGER /* Define this if you have the kernal
pager installed on you system
<2037@utcsstat.UUCP> */
#define MAX_DRIVES 4 /* The maximum number of drives that your
system is designed to support. */
#define NUM_DRIVES 1 /* The number of drives that you system
actually has. */
#define MAX_RETRIES 5 /* How many times the program will attempt
to allocate the requested number of
drives after finding that no more are
currently available (NOTE: it sleeps
for SLEEP3 seconds between attempts */
#ifndef DEBUG
#define SLEEP1 1 /* Short sleep */
#define SLEEP2 5 /* Med. sleep */
#define SLEEP3 120 /* Long sleep */
#define TIME_OUT (60 * 60 * 6)
/* 6 hours -- how long before timeout
occurs */
#define WARNING (60 * 5)/* 5 minutes -- how long after timeout
occures before everything is actually
shutdown */
#else DEBUG
#define SLEEP1 1
#define SLEEP2 5
#define SLEEP3 5
#define TIME_OUT (45)
#define WARNING (15)
#endif DEBUG
/* the following defines calculate the various device numbers for a
given drive x: AR indicates auto-rewind on close, nnnBPI indicates the
number of bit per inch. */
#define AR_800BPI(x) (0 + (x - 1))
#define NAR_800BPI(x) (AR_800BPI(x) + MAX_DRIVES)
#define AR_1600BPI(x) (NAR_800BPI(x) + MAX_DRIVES)
#define NAR_1600BPI(x) (AR_1600BPI(x) + MAX_DRIVES)
#define AR_6250BPI(x) (NAR_1600BPI(x) + MAX_DRIVES)
#define NAR_6250BPI(x) (AR_6250BPI(x) + MAX_DRIVES)
#define MT_NAME "/dev/mt"/* prefix for the block devices */
#define RMT_NAME "/dev/rmt"/* prefix for the raw devices */
#define ROOT 0 /* uid of root */
#define TAPEMGR_UID 30 /* uid of the user tapemgr */
#define TAPEMGR_GID 300 /* gid of the user tapemgr */
#define DRIVE_PROT 0600 /* the protection modes for the tape
devices */
#define SHELL "/bin/sh"/* the default shell */
#ifndef DEBUG
#define LOGFILE "/usr/adm/tapelog"
/* where the log is kept, if this file
does not exist no log is kept */
#else DEBUG
#define LOGFILE "tapelog"
#endif
#define ENV_VAR "TAPE_DRIVES"
/* Environment variable to inform children
about which drives are available */
#define ENV_VAR_EQ "TAPE_DRIVES="
/* This should be the same as ENV_VAR with
an = tagged on */
#define NO_SIGNAL EOF /* these are just used as fill for when
clean_up is called directly rather than
by an interupt */
#define NO_CODE EOF
#define NO_CONTEXT ((struct sigcontext *) EOF)
#define TRUE (logical) '\1'
#define FALSE (logical) '\0'
typedef char logical;
struct mtop mtoffl = { /* tape operation offline */
MTOFFL, 1
};
int otpgrp; /* for storing and restoring the state of
the terminal */
#ifdef RESTORE_TERMINAL
int oldisc;
struct sgttyb otty;
struct tchars otchars;
#ifdef KERNAL_PAGER
struct tpage otpage;
#endif KERNAL_PAGER
int olocalm;
struct ltchars oltchars;
#endif RESTORE_TERMINAL
int fd_tty = EOF; /* equal to the fd of the terminal */
struct sigvec ovec;
struct sigvec vec_dfl = { /* to restore the original signal handler
*/
SIG_DFL, 0, 0
};
int kill_and_clean (), clean_up (), timeout ();
struct sigvec vec_kill_and_clean = {
/* to cause kill_and_clean to be called
when a signal is received */
kill_and_clean, 0, 0
};
struct sigvec vec_clean_up = {/* to cause clean_up to be called when a
signal is received */
clean_up, 0, 0
};
struct sigvec vec_timeout = { /* to cause timeout to be called when a
signal is received */
timeout, 0, 0
};
struct itimerval time_out, /* the values for the interval timer */
ovalue;
int pid; /* the pid of the child */
char **tapemgr_env = 0; /* the environment to be passed to the
child */
logical allocated[MAX_DRIVES + 1];/* which drives have been allocated
allocated[0] == TRUE means that reset
is being performed and no allocations
are to be performed */
logical verbose = TRUE; /* TRUE for a mouthy program */
char *getenv (), *getlogin (), *malloc (), *realloc (), *calloc ();
/*---------------------------------------------------------------------------
*
* P R I V I L E G E D _ U S E R
*
* This program returns TRUE if the user who is running it is root or
* is in the group tapemgr.
*
* Entry Conditions: none.
*
* Exit Conditions: once the status of the person running the
* program has been determined.
*
* Returns: TRUE iff the user is privileged
* FALSE otherwise.
*
* Side Effects: none.
*
* Static Variables: first_time, gidset, ngrps, cur_grp,
* privileged
*
* External Variables: none.
*
* Non-library Functions: none.
*
*---------------------------------------------------------------------------
*/
logical privileged_user () {
static logical first_time = TRUE;
static int gidset[NGROUPS],
ngrps,
cur_grp;
static logical privileged = FALSE;
if (first_time && !(privileged = getuid () == ROOT)) {
ngrps = getgroups (NGROUPS, gidset);
first_time = FALSE;
for (cur_grp = 0; cur_grp < ngrps && !privileged; cur_grp++)
privileged = gidset[cur_grp] == TAPEMGR_GID;
}
return privileged;
}
/*---------------------------------------------------------------------------
*
* L O G M E S G
*
* Log an action in the tapelog file if it exists.
*
* Entry Conditions: none.
*
* Exit Conditions: none.
*
* Returns: nothing.
*
* Side Effects: none.
*
* Static Variables: none.
*
* External Variables: none.
*
* Non-library Functions: none.
*
*---------------------------------------------------------------------------
*/
void logmesg (action, drive)
char *action;
int drive;
{
FILE * logfile;
struct stat logfile_stat;
struct timeval tp;
struct timezone tzp;
struct passwd *pwdent;
if (stat (LOGFILE, &logfile_stat))
#ifndef DEBUG
return;
#else DEBUG
perror (LOGFILE);
#endif DEBUG
(void) gettimeofday (&tp, &tzp);
pwdent = getpwuid (getuid ());
if (!(logfile = fopen (LOGFILE, "a")))
return;
fprintf (logfile,
#ifndef DEBUG
"%d,%s,%s/%s(%d),%s",
#else DEBUG
"drive=%d,action=%s,login/user(uid)=%s/%s(%d),date and time=%s",
#endif DEBUG
drive - 1, action, getlogin (), pwdent -> pw_name,
getuid (), ctime ((time_t *) & tp.tv_sec));
(void) fclose (logfile);
}
/*---------------------------------------------------------------------------
*
* K I L L _ A N D _ C L E A N
*
* Kill the children.
*
* Entry Conditions: SIGALRM
*
* Exit Conditions: all children killed.
*
* Returns: nothing.
*
* Side Effects: resets the handler for SIGALRM and turns off
* the interval timer.
*
* Static Variables: none.
*
* External Variables: pid, vec_dfl, verbose, otpgrp.
*
* Non-library Functions: logmesg.
*
*---------------------------------------------------------------------------
*/
int kill_and_clean (sig, code, scp)
int sig,
code;
struct sigcontext *scp;
{
int cur_tpgrp,
prev_tpgrp;
(void) setitimer (ITIMER_REAL, &ovalue, &time_out);
(void) sigvec (SIGALRM, &vec_dfl, &ovec);
if (pid) {
if (sig == SIGALRM) {
logmesg ("Timeout", 0);
fprintf (stderr, "Timeout has arrived!!!!\007\n");
}
else {
logmesg ("Killed", 0);
fprintf (stderr, "I been shot jim!!!\007\n");
}
if (fd_tty != EOF) {
if (verbose) {
printf ("Take That(pid=%d)", pid);
(void) fflush (stdout);
}
(void) kill (pid, SIGHUP);
sleep (SLEEP2);
(void) kill (pid, SIGKILL);
sleep (SLEEP2);
(void) ioctl (fd_tty, (int) TIOCGPGRP, (char *) & cur_tpgrp);
for (prev_tpgrp = EOF;
cur_tpgrp != prev_tpgrp && cur_tpgrp != otpgrp;) {
if (verbose) {
printf ("...and That(pgrp=%d)", cur_tpgrp);
(void) fflush (stdout);
}
(void) killpg (cur_tpgrp, SIGHUP);
sleep (SLEEP2);
(void) killpg (cur_tpgrp, SIGKILL);
prev_tpgrp = cur_tpgrp;
sleep (SLEEP2);
(void) ioctl (fd_tty, (int) TIOCGPGRP, (char *) & cur_tpgrp);
}
if (verbose)
printf ("...I think it's dead now.\n");
}
}
}
/*---------------------------------------------------------------------------
*
* T I M E O U T
*
* nothing much really, just sets things up for the kill.
*
* Entry Conditions: SIGALRM
*
* Exit Conditions: none.
*
* Returns: nothing.
*
* Side Effects: sets the handler for SIGALRM to
* kill_and_clean.
*
* Static Variables: none.
*
* External Variables: vec_kill_and_clean.
*
* Non-library Functions: none.
*
*---------------------------------------------------------------------------
*/
int timeout (sig, code, scp)
int sig,
code;
struct sigcontext *scp;
{
fprintf (stderr,
"You have %d minutes %d seconds in which to clean up, timeout has arrived.\007\n",
(int) WARNING / 60, WARNING % 60);
(void) sigvec (SIGALRM, &vec_kill_and_clean, &ovec);
}
/*---------------------------------------------------------------------------
*
* S E T _ D E V I C E
* Sets the ownership and protection of the specified device, if chutzpah
* is set then it just pretends to set the ownership and protection.
*
* Entry Conditions: none.
*
* Exit Conditions: none.
*
* Returns: nothing.
*
* Side Effects: none.
*
* Static Variables: none.
*
* External Variables: verbose.
*
* Non-library Functions: none.
*
*---------------------------------------------------------------------------
*/
void set_device (drive, uid, silently, chutzpah)
char *drive;
int uid;
logical silently, chutzpah;
{
struct stat drive_stat;
if (stat (drive, &drive_stat)) {
if (!silently || chutzpah)
if (verbose)
printf ("%15s", "");
return;
}
if (!chutzpah) {
(void) chown (drive, uid, TAPEMGR_GID);
(void) chmod (drive, DRIVE_PROT);
}
if (!silently || chutzpah)
if (verbose)
printf ("%15s", drive);
}
/*---------------------------------------------------------------------------
*
* S E T _ D R I V E
*
* Runs set_device for every device for a given drive, except for
* the raw no auto rewind 800bpi device which is run with chutzpah TRUE
* it is left up to the calling routine to run set_device for that device.
*
* Entry Conditions: none.
*
* Exit Conditions: none.
*
* Returns: nothing.
*
* Side Effects: none.
*
* Static Variables: none.
*
* External Variables: verbose.
*
* Non-library Functions: set_device.
*
*---------------------------------------------------------------------------
*/
void set_drive (drive, uid)
int drive,
uid;
{
char cur_drive[BUFSIZ];
if (verbose) {
printf ("BLOCK Devices available with drive %d.\n", drive - 1);
printf ("%15s%15s%15s%15s\n", "", "800bpi", "1600bpi", "6250bpi");
printf ("%15s", "Auto Rewind:");
}
set_device (sprintf (cur_drive, "%s%d", MT_NAME, AR_800BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", MT_NAME, AR_1600BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", MT_NAME, AR_6250BPI (drive)),
uid, FALSE, FALSE);
if (verbose)
printf ("\n%15s", "No Auto Rewind:");
set_device (sprintf (cur_drive, "%s%d", MT_NAME, NAR_800BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", MT_NAME, NAR_1600BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", MT_NAME, NAR_6250BPI (drive)),
uid, FALSE, FALSE);
if (verbose) {
printf ("\nRAW Devices available with drive %d.\n", drive - 1);
printf ("%15s%15s%15s%15s\n", "", "800bpi", "1600bpi", "6250bpi");
printf ("%15s", "Auto Rewind:");
}
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, AR_800BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, AR_1600BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, AR_6250BPI (drive)),
uid, FALSE, FALSE);
if (verbose)
printf ("\n%15s", "No Auto Rewind:");
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, NAR_800BPI (drive)),
uid, FALSE, TRUE);
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, NAR_1600BPI (drive)),
uid, FALSE, FALSE);
set_device (sprintf (cur_drive, "%s%d", RMT_NAME, NAR_6250BPI (drive)),
uid, FALSE, FALSE);
if (verbose)
printf ("\n");
}
/*---------------------------------------------------------------------------
*
* C L E A N _ U P
*
* restore the terminal, and reset all the allocated drives.
*
* Entry Conditions: SIGINT or called from the main program.
*
* Exit Conditions: all allocated drives released.
*
* Returns: never.
*
* Side Effects: blocks all signals
*
* Static Variables: none.
*
* External Variables: verbose, allocated, mtoffl, oldisc, otty,
* otpgrp, otchars, otpage, olocalm, oltchars.
*
* Non-library Functions: priviliged_user, logmesg.
*
*---------------------------------------------------------------------------
*/
int clean_up (sig, code, scp)
int sig,
code;
struct sigcontext *scp;
{
FILE * fdrive;
struct stat drive_stat;
int drive;
char cur_drive[BUFSIZ];
(void) sigsetmask (~0);
if (verbose)
printf ("Cleaning up...\n");
for (drive = 1; drive <= NUM_DRIVES; drive++)
if (allocated[drive]) {
(void) sprintf (cur_drive, "%s%d", RMT_NAME, NAR_800BPI (drive));
if (stat (cur_drive, &drive_stat)) {
perror (cur_drive);
continue;
}
if (privileged_user () || getuid () == drive_stat.st_uid) {
if (verbose)
printf ("Reseting drive %d.\n", drive - 1);
if ((fdrive = fopen (cur_drive, "r"))) {
(void) ioctl (fileno (fdrive), (int) MTIOCTOP,
(char *) & mtoffl);
(void) fclose (fdrive);
}
set_drive (drive, TAPEMGR_UID);
set_device (cur_drive, TAPEMGR_UID, TRUE, FALSE);
logmesg ("Reset", drive);
}
}
#ifdef RESTORE_TERMINAL
if (fd_tty != EOF) {
(void) ioctl (fd_tty, (int) TIOCSETD, (char *) & oldisc);
(void) ioctl (fd_tty, (int) TIOCSETP, (char *) & otty);
(void) ioctl (fd_tty, (int) TIOCSPGRP, (char *) & otpgrp);
(void) ioctl (fd_tty, (int) TIOCSETC, (char *) & otchars);
#ifdef KERNAL_PAGER
(void) ioctl (fd_tty, (int) TIOCSPAG, (char *) & otpage);
#endif KERNAL_PAGER
(void) ioctl (fd_tty, (int) TIOCLSET, (char *) & olocalm);
(void) ioctl (fd_tty, (int) TIOCSLTC, (char *) & oltchars);
}
#endif RESTORE_TERMINAL
exit (0);
}
/*---------------------------------------------------------------------------
*
* S E T _ E N V
*
* Adds the specified drive to the environment variable ENV_VAR
*
* Entry Conditions: none.
*
* Exit Conditions: none.
*
* Returns: nothing.
*
* Side Effects: modifies tapemgr_env.
*
* Static Variables: first_time, space.
*
* External Variables: none.
*
* Non-library Functions: none.
*
*---------------------------------------------------------------------------
*/
void set_env (drive, envp)
int drive;
char **envp;
{
static logical first_time = TRUE;
static logical space = TRUE;
unsigned int count;
char **tenvp,
**nenvp,
env_buf[BUFSIZ];
if (!tapemgr_env)
if (getenv (ENV_VAR))
tapemgr_env = envp;
else {
for (count = 2, tenvp = envp; *tenvp; tenvp++, count++);
tapemgr_env = (char **) calloc (count, sizeof (char *));
for (tenvp = envp, nenvp = tapemgr_env; *tenvp;
*(nenvp++) = *(tenvp++));
*nenvp = ENV_VAR_EQ;
*++nenvp = NULL;
space = FALSE;
}
for (nenvp = tapemgr_env;
strncmp (*nenvp, ENV_VAR_EQ, strlen (ENV_VAR_EQ)); nenvp++);
if (space)
(void) sprintf (env_buf, "%s %d", *nenvp, drive);
else {
(void) sprintf (env_buf, "%s%d", *nenvp, drive);
space = TRUE;
}
if (first_time) {
*nenvp = strcpy (malloc ((unsigned int) strlen (env_buf) + 1),
env_buf);
first_time = FALSE;
}
else
*nenvp = strcpy (realloc (*nenvp,
(unsigned int) strlen (env_buf) + 1),
env_buf);
}
main (argc, argv, envp)
int argc;
char **argv,
**envp;
{
struct stat drive_stat;
union wait status;
int drive,
num_allocated,
num_optarg,
option,
org_sigmask;
int num_drives = 1;
int retries = 0;
char *called = *argv;
char cur_drive[BUFSIZ];
char *tape_command = getenv ("SHELL") ? getenv ("SHELL") : SHELL;
extern char *optarg;
logical one_allocated;
logical t_out = TRUE;
if (geteuid () != ROOT) {
fprintf (stderr,
"This program must be suid to root for it to work.\n");
exit (13);
}
while ((option = getopt (argc, argv, "r:n:c:vt")) != EOF)
switch (option) {
case 'r':
if (!strcmp (optarg, "all")) {
fprintf (stderr, "Reseting all drives\n");
for (drive = 0; drive <= NUM_DRIVES; drive++)
allocated[drive] = TRUE;
}
else {
if (!isdigit (optarg[0])) {
fprintf (stderr,
"The -r option expects a numeric argument in the range (0,%d)%s",
NUM_DRIVES - 1, "\n\tor the string all.\n");
exit (13);
}
num_optarg = atoi (optarg);
if (num_optarg < 0 || num_optarg > NUM_DRIVES - 1) {
fprintf (stderr,
"%d is not a valid drive number, valid drive numbers are in the range (0,%d).\n",
num_optarg, NUM_DRIVES - 1);
exit (13);
}
allocated[0] = TRUE;
allocated[num_optarg + 1] = TRUE;
}
break;
case 'n':
if (!strcmp (optarg, "all")) {
fprintf (stderr, "Allocating all drives\n");
num_drives = NUM_DRIVES;
}
else {
if (!isdigit (optarg[0])) {
fprintf (stderr,
"The -n option expects a numeric argument in the range (1,%d)%s",
NUM_DRIVES, "\n\tor the string all.\n");
exit (13);
}
num_optarg = atoi (optarg);
if (num_optarg < 1 || num_optarg > NUM_DRIVES) {
fprintf (stderr,
"%d is not a valid number of drives,\n\tvalid numbers of drives are in the range (1,%d).\n",
num_optarg, NUM_DRIVES);
exit (13);
}
num_drives = num_optarg;
}
break;
case 'c':
tape_command = optarg;
break;
case 'v':
verbose = !verbose;
break;
case 't':
if (!privileged_user ())
fprintf (stderr,
"You have to be root or belong the the group tapemgr to use the -t option.\n");
else
t_out = !t_out;
break;
case '?':
default:
fprintf (stderr,
"Usage: %s [-r DRIVE_NUMBER|all] | [-n NUMBER_OF_DRIVES|all]%s",
called, "\n\t[-c TAPE_COMMAND] [-v] [-t]\n");
exit (13);
break;
}
if (!allocated[0]) { /* oh boy, we get some drives */
(void) sigvec (SIGINT, &vec_clean_up, &ovec);
/* clean up after ^C */
org_sigmask = sigsetmask (~(1 << (SIGINT - 1)));
if (verbose)
printf ("Attempting to allocate %d drives.\n", num_drives);
for (num_allocated = 0; num_allocated < num_drives;) {
for (drive = 1, one_allocated = FALSE;
drive <= NUM_DRIVES && !one_allocated; drive++) {
if (allocated[drive])
continue;
(void) sprintf (cur_drive,
"%s%d", RMT_NAME, NAR_800BPI (drive));
if (stat (cur_drive, &drive_stat)) {
perror (cur_drive);
continue;
}
if (drive_stat.st_uid != TAPEMGR_UID)
continue;
allocated[drive] = TRUE;
fprintf (stderr, "Allocating drive %d.\n", drive - 1);
set_device (cur_drive, getuid (), TRUE, FALSE);
sleep (SLEEP1);
(void) stat (cur_drive, &drive_stat);
if (drive_stat.st_uid != getuid ()) {
allocated[drive] = FALSE;
fprintf (stderr,
"Thought we had drive %d but I guess I was wrong.\n",
drive - 1);
continue;
}
set_drive (drive, getuid ());
set_env (drive - 1, envp);
one_allocated = TRUE;
num_allocated++;
logmesg ("Allocation", drive);
}
if (!one_allocated) {
if (retries > MAX_RETRIES) {
fprintf (stderr,
"Could not allocate the requested number of drives.\n");
clean_up (NO_SIGNAL, NO_CODE, NO_CONTEXT);
}
else {
if (verbose)
printf ("Retrying...snore for %d secs", SLEEP3);
sleep (SLEEP3);
if (verbose)
printf ("...yawn let's try again.\n");
retries++;
}
}
}
(void) sigsetmask (~0);
if (isatty (fileno (stderr)))/* are we attached to a terminal? */
fd_tty = fileno (stderr);
else
if (isatty (fileno (stdout)))
fd_tty = fileno (stdout);
else
if (isatty (fileno (stdin)))
fd_tty = fileno (stdin);
if (fd_tty != EOF) {
(void) ioctl (fd_tty, (int) TIOCGPGRP, (char *) & otpgrp);
#ifdef RESTORE_TERMINAL
(void) ioctl (fd_tty, (int) TIOCGETD, (char *) & oldisc);
(void) ioctl (fd_tty, (int) TIOCGETP, (char *) & otty);
(void) ioctl (fd_tty, (int) TIOCGETC, (char *) & otchars);
#ifdef KERNAL_PAGER
(void) ioctl (fd_tty, (int) TIOCGPAG, (char *) & otpage);
#endif KERNAL_PAGER
(void) ioctl (fd_tty, (int) TIOCLGET, (char *) & olocalm);
(void) ioctl (fd_tty, (int) TIOCGLTC, (char *) & oltchars);
#endif RESTORE_TERMINAL
}
if ((pid = fork ()) == EOF)
perror (called);
else
if (pid) {
if (t_out) {
time_out.it_value.tv_sec = TIME_OUT;
time_out.it_interval.tv_sec = WARNING;
(void) sigvec (SIGALRM, &vec_timeout, &ovec);
sleep (SLEEP1);
if (verbose)
printf ("Timeout in %d hours %d minutes %d seconds.\n",
(int) TIME_OUT / 3600,
(int) (TIME_OUT % 3600) / 60, TIME_OUT % 60);
(void) setitimer (ITIMER_REAL, &time_out, &ovalue);
}
(void) sigvec (SIGHUP, &vec_kill_and_clean, &ovec);
(void) sigsetmask (~((1 << (SIGHUP - 1)) |
((t_out ? 1 : 0) << (SIGALRM - 1))));
(void) wait (&status);
pid = 0;
if (t_out) {
(void) setitimer (ITIMER_REAL, &ovalue, &time_out);
(void) sigvec (SIGALRM, &vec_dfl, &ovec);
}
}
else {
if (verbose)
printf ("Starting up: `%s'\n", tape_command);
(void) setuid (getuid ());
(void) sigsetmask (org_sigmask);
(void) sigblock (1 << (SIGINT - 1));
(void) sigblock (1 << (SIGQUIT - 1));
(void) sigblock (1 << (SIGTSTP - 1));
(void) execle (SHELL, SHELL, "-c", tape_command, 0,
tapemgr_env);
perror (tape_command);
exit (13);
}
}
clean_up (NO_SIGNAL, NO_CODE, NO_CONTEXT);
}