home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume1
/
8711
/
3
/
newmgr.c
next >
Wrap
C/C++ Source or Header
|
1990-07-13
|
8KB
|
309 lines
/* newmgr: Loop forever, printing a status display and checking the
Suspend and Resume Keys. Meant to be used on the top line of a Unix-PC
(7300/3B1) screen that has had the Phone Manager, Status Manager and
Window Manager disabled. What it shows:
- Phone line states (Idle, Busy)
- Boot date and time
- Current run level
- Current date and time
- Number of users
Also, when Suspend is hit, it makes the next window current; Resume
makes the last window current.
This is started by startmgr (which should be included in any
distribution) so that the fork/exec/open code doesn't have to be
carried around with this program.
This software is Copyright (c) 1987 by Scott Hazen Mueller.
Permission is hereby granted to copy, reproduce, redistribute or
otherwise use this software as long as: there is no monetary
profit gained specifically from the use or reproduction or this
software, it is not sold, rented, traded or otherwise marketed, and
this copyright notice is included prominently in any copy
made.
The author make no claims as to the fitness or correctness of
this software for any use whatsoever, and it is provided as is.
Any use of this software is at the user's own risk.
(Copyright notice courtesy of News 2.11 :-)
Additionally: you break it, you bought it. I've listed the problems
that I know of in comments in the code; if you come up with fixes, I'd
like to see them, but I'm not planning on supporting anything. It's
"good enough"; that's all that I'm looking for. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/phone.h>
#include <sys/window.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <time.h>
#include <utmp.h>
#define PHONE1 "ph0"
#define PHONE2 "ph1"
#define IDLE 0
#define BARFORM "%s1 %s2 | Up Since %s | %s | %s | %d Users | w%d \r"
#define phstat( st ) ( st ? "Busy" : "Idle" )
#define MAXPATHLEN 255
#define LOCKDIR "/usr/spool/uucp/"
#define LOCKPREFIX "LCK.."
#define TRUE (1)
#define FALSE (0)
#define TIMEFORM "%.2d/%.2d %.2d:%.2d"
#define TICK 15
#define NOWHERE 0
#define FORWARD 1
#define BACKWARD 2
#define MINWIN 1
#define MAXWIN 12
main()
{
int ph1st, ph2st, nusers;
char curtime[26], boottime[26], rl[12], line[80], *fmttime();
struct utmp *ut, *getutent();
long temp;
/* Open up the utmp file and find the boot time; save for display. */
while ( ( ut = getutent() ) != NULL )
if ( (int) ut->ut_type == BOOT_TIME ) {
strcpy( boottime, fmttime( localtime( &( ut->ut_time ) ) ) );
break;
}
endutent();
for (;;) {
/* Scan the utmp file, noting the run level and totting up users.
Skip the loop for dead processes - we don't want to confuse the
phone-check code... */
nusers = 0;
ph1st = IDLE;
ph2st = IDLE;
while ( ( ut = getutent() ) != NULL ) {
switch ( (int) ut->ut_type ) {
case USER_PROCESS : nusers++; break;
case RUN_LVL : strcpy( rl, ut->ut_line ); break;
case DEAD_PROCESS : continue;
default : break;
}
/* Peek at the line field and see if a phone line is mentioned. The answer
is either yes (1 or many, don't care exactly) or no, so I can get away
with the 'or'. */
ph1st = ph1st | !strcmp( PHONE1, ut->ut_line );
ph2st = ph2st | !strcmp( PHONE2, ut->ut_line );
}
endutent();
/* The phone check stuff *still* hasn't caught everything, e.g., an outgoing
uucico started by cron, so we'll now peek and see if we can find a LCK
file. It's gross and it's nasty, and if anyone can do me better without
hanging up my voice calls, I'd be happy to replace this stuff... */
ph1st = ph1st | locked( PHONE1 );
ph2st = ph2st | locked( PHONE2 );
/* Figure out the current time. Temp is needed 'cause localtime wants
an address. */
temp = time( (long *) 0 );
strcpy( curtime, fmttime( localtime( &temp ) ) );
/* Format and print. Flush stdout to make it really get printed. */
sprintf( line, BARFORM, phstat( ph1st ), phstat( ph2st ),
boottime, rl, curtime, nusers, curwinno() );
printf( "%s", line );
fflush( stdout );
/* Take care of the window management stuff; also do some sleeping down
there. */
wcheckz();
}
}
/* See if a lock file exists. */
locked( device )
char *device;
{
char temp[MAXPATHLEN];
int fd;
/* Make up the full path name. */
strcpy( temp, LOCKDIR );
strcat( temp, LOCKPREFIX );
strcat( temp, device );
/* Attempt to open the lock file. Assume that if the open fails the lock
file does not exist. */
fd = open( temp, O_RDONLY );
if ( fd == -1 )
return( FALSE );
close( fd );
return( TRUE );
}
/* Format a time structure into a string the way *I* want it. */
char *fmttime( tm )
struct tm *tm;
{
char abuf[26];
sprintf( abuf, TIMEFORM, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min );
return( abuf );
}
curwinno()
/* Figure out the current window; we need a starting point, after all.
Known bug: this sometimes returns the wrong value if it gets into a
race condition with a terminating/restarting (eg, getty) job. It also
doesn't check to see if the ioctl fails. */
{
int foowin, dummy, temp;
foowin = open( "/dev/window", O_RDONLY );
temp = ioctl( foowin, WIOCGCURR, dummy );
close( foowin );
return( temp );
}
wcheckz()
/* This is where the code to check for change-window keys lives. Also,
sleep for the main program here. It should return about every TICK
seconds. */
{
int tock, newwin, dir;
tock = 0;
do {
/* Check for a command key. */
if ( ( dir = checkey() ) != NOWHERE ) {
/* Determine which window is next and select it. */
newwin = nexwin( curwinno(), dir );
ioctl( newwin, WIOCSELECT );
close( newwin );
tock = TICK; /* Kludge to force return and redisplay. */
}
}
/* Return after TICK tocks. */
while ( tock++ < TICK );
}
/* Stub routine to "handle" the alarm signal. Doesn't do a lot. */
justgoon()
{
return;
}
checkey()
/* Check and see if one of our keys has been poked. The only keys this window
is supposed to respond to all generate three character escape sequences.
The print key gets ignored; I suppose it could be aliased to something
useful, like system reboot... Set and catch an alarm signal to keep
from getting hung in the fread(); this probably could be done more
neatly some other way, but... */
{
int direction, i;
FILE *fw;
char key[3];
/* Set the alarm signal. */
signal( SIGALRM, justgoon );
alarm( 1 );
if ( fread( key, 1, 3, stdin ) == 3 ) {
/* Reset the alarm signal to be ignored. */
signal( SIGALRM, SIG_IGN );
switch ( key[2] ) {
case 'p' :
case 'P' : direction = FORWARD; break;
case 'q' :
case 'Q' : direction = BACKWARD; break;
default : direction = NOWHERE; break;
}
}
else
direction = NOWHERE;
/* Reset the alarm signal to be ignored. */
signal( SIGALRM, SIG_IGN );
return( direction );
}
nexwin( winno, dir )
int winno, dir;
/* Decide what should be the next window. This relies on the fact that
when you open a window device directly the open call will fail if it has
not already been opened by someone else; this is how we find the open
windows. Invisible windows should have their user-text set to "Invisible"
if they wish to be ignored. */
{
int wd;
char windex[12];
struct utdata wintext;
/* Trivial loop; at worst, we'll wind up back where we started. I suppose
it's possible to have a system with no windows except those marked as
"Invisible"; it doesn't seem to useful, though. */
while ( 1 ) {
/* Forward/backward sort-of modulo arithmetic. Real modulo arithmetic
starts at zero. */
winno += ( dir == FORWARD ? 1 : -1 );
if ( winno > MAXWIN )
winno = MINWIN;
else if ( winno < MINWIN )
winno = MAXWIN;
/* Generate a window name and test for existence. */
sprintf( windex, "/dev/w%d", winno );
if ( ( wd = open( windex, O_RDONLY ) ) != -1 ) {
/* It exists, now look at its user text info. This is where "Invisible"
gets skipped. */
wintext.ut_num = WTXTUSER;
ioctl( wd, WIOCGETTEXT, &wintext );
if ( strcmp( wintext.ut_text, "Invisible" ) )
return( wd );
else
close( wd );
}
}
}