home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume1 / 8711 / 3 / newmgr.c next >
C/C++ Source or Header  |  1990-07-13  |  8KB  |  309 lines

  1. /*    newmgr:  Loop forever, printing a status display and checking the
  2.     Suspend and Resume Keys.  Meant to be used on the top line of a Unix-PC
  3.     (7300/3B1) screen that has had the Phone Manager, Status Manager and
  4.     Window Manager disabled.  What it shows:
  5.  
  6.     - Phone line states (Idle, Busy)
  7.     - Boot date and time
  8.     - Current run level
  9.     - Current date and time
  10.     - Number of users
  11.  
  12.     Also, when Suspend is hit, it makes the next window current; Resume
  13.     makes the last window current.
  14.  
  15.     This is started by startmgr (which should be included in any
  16.     distribution) so that the fork/exec/open code doesn't have to be
  17.     carried around with this program.
  18.  
  19.     This software is Copyright (c) 1987 by Scott Hazen Mueller.
  20.  
  21.     Permission is hereby granted to copy, reproduce, redistribute or
  22.     otherwise use this software as long as: there is no monetary
  23.     profit gained specifically from the use or reproduction or this
  24.     software, it is not sold, rented, traded or otherwise marketed, and
  25.     this copyright notice is included prominently in any copy
  26.     made.
  27.  
  28.     The author make no claims as to the fitness or correctness of
  29.     this software for any use whatsoever, and it is provided as is. 
  30.     Any use of this software is at the user's own risk.
  31.  
  32.     (Copyright notice courtesy of News 2.11 :-)
  33.  
  34.     Additionally:  you break it, you bought it.  I've listed the problems
  35.     that I know of in comments in the code; if you come up with fixes, I'd
  36.     like to see them, but I'm not planning on supporting anything.  It's
  37.     "good enough"; that's all that I'm looking for.    */
  38.  
  39. #include    <stdio.h>
  40. #include    <sys/types.h>
  41. #include    <sys/phone.h>
  42. #include    <sys/window.h>
  43. #include    <sys/signal.h>
  44. #include    <fcntl.h>
  45. #include    <time.h>
  46. #include    <utmp.h>
  47.  
  48. #define        PHONE1        "ph0"
  49. #define        PHONE2        "ph1"
  50. #define        IDLE        0
  51. #define        BARFORM        "%s1 %s2 | Up Since %s | %s | %s | %d Users | w%d \r"
  52. #define        phstat( st )     ( st ? "Busy" : "Idle" )
  53. #define        MAXPATHLEN    255
  54. #define        LOCKDIR        "/usr/spool/uucp/"
  55. #define        LOCKPREFIX    "LCK.."
  56. #define        TRUE        (1)
  57. #define        FALSE        (0)
  58. #define        TIMEFORM    "%.2d/%.2d %.2d:%.2d"
  59. #define        TICK        15
  60. #define        NOWHERE        0
  61. #define        FORWARD        1
  62. #define        BACKWARD    2
  63. #define        MINWIN        1
  64. #define        MAXWIN        12
  65.  
  66. main()
  67. {
  68. int        ph1st, ph2st, nusers;
  69. char    curtime[26], boottime[26], rl[12], line[80], *fmttime();
  70. struct    utmp *ut, *getutent();
  71. long    temp;
  72.  
  73. /* Open up the utmp file and find the boot time; save for display.    */
  74.  
  75. while ( ( ut = getutent() ) != NULL )
  76.     if ( (int) ut->ut_type == BOOT_TIME ) {
  77.         strcpy( boottime, fmttime( localtime( &( ut->ut_time ) ) ) );
  78.         break;
  79.     }
  80. endutent();
  81.  
  82. for (;;) {
  83.  
  84. /*    Scan the utmp file, noting the run level and totting up users.
  85.     Skip the loop for dead processes - we don't want to confuse the
  86.     phone-check code...    */
  87.  
  88.     nusers = 0;
  89.     ph1st = IDLE;
  90.     ph2st = IDLE;
  91.     while ( ( ut = getutent() ) != NULL ) {
  92.         switch ( (int) ut->ut_type ) {
  93.             case USER_PROCESS : nusers++; break;
  94.             case RUN_LVL : strcpy( rl, ut->ut_line ); break;
  95.             case DEAD_PROCESS : continue;
  96.             default : break;
  97.             }
  98. /*    Peek at the line field and see if a phone line is mentioned.  The answer
  99.     is either yes (1 or many, don't care exactly) or no, so I can get away
  100.     with the 'or'.    */
  101.  
  102.         ph1st = ph1st | !strcmp( PHONE1, ut->ut_line );
  103.         ph2st = ph2st | !strcmp( PHONE2, ut->ut_line );
  104.         }
  105.     endutent();
  106.  
  107. /*    The phone check stuff *still* hasn't caught everything, e.g., an outgoing
  108.     uucico started by cron, so we'll now peek and see if we can find a LCK
  109.     file.  It's gross and it's nasty, and if anyone can do me better without
  110.     hanging up my voice calls, I'd be happy to replace this stuff...    */
  111.  
  112.     ph1st = ph1st | locked( PHONE1 );
  113.     ph2st = ph2st | locked( PHONE2 );
  114.  
  115. /*    Figure out the current time.  Temp is needed 'cause localtime wants
  116.     an address.    */
  117.  
  118.     temp = time( (long *) 0 );
  119.     strcpy( curtime, fmttime( localtime( &temp ) ) );
  120.  
  121. /*    Format and print.  Flush stdout to make it really get printed.    */
  122.  
  123.     sprintf( line, BARFORM, phstat( ph1st ), phstat( ph2st ),
  124.         boottime, rl, curtime, nusers, curwinno() );
  125.     printf( "%s", line );
  126.     fflush( stdout );
  127.  
  128. /*  Take care of the window management stuff; also do some sleeping down
  129.     there.    */
  130.  
  131.     wcheckz();
  132.     }
  133. }
  134.  
  135. /*    See if a lock file exists.    */
  136.  
  137. locked( device )
  138. char    *device;
  139. {
  140. char    temp[MAXPATHLEN];
  141. int        fd;
  142.  
  143. /*    Make up the full path name.    */
  144.  
  145. strcpy( temp, LOCKDIR );
  146. strcat( temp, LOCKPREFIX );
  147. strcat( temp, device );
  148.  
  149. /*    Attempt to open the lock file.  Assume that if the open fails the lock
  150.     file does not exist.    */
  151.  
  152. fd = open( temp, O_RDONLY );
  153. if ( fd == -1 )
  154.     return( FALSE );
  155. close( fd );
  156. return( TRUE );
  157. }
  158.  
  159. /*    Format a time structure into a string the way *I* want it.    */
  160.  
  161. char *fmttime( tm )
  162. struct tm *tm;
  163. {
  164. char  abuf[26];
  165.  
  166. sprintf( abuf, TIMEFORM, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min );
  167. return( abuf );
  168. }
  169.  
  170. curwinno()
  171.  
  172. /*    Figure out the current window; we need a starting point, after all.
  173.     Known bug:  this sometimes returns the wrong value if it gets into a
  174.     race condition with a terminating/restarting (eg, getty) job.  It also
  175.     doesn't check to see if the ioctl fails.    */
  176.  
  177. {
  178. int        foowin, dummy, temp;
  179.  
  180. foowin = open( "/dev/window", O_RDONLY );
  181. temp = ioctl( foowin, WIOCGCURR, dummy );
  182. close( foowin );
  183. return( temp );
  184. }
  185.  
  186. wcheckz()
  187.  
  188. /*    This is where the code to check for change-window keys lives.  Also,
  189.     sleep for the main program here.  It should return about every TICK
  190.     seconds.    */
  191.  
  192. {
  193. int        tock, newwin, dir;
  194.  
  195. tock = 0;
  196.  
  197. do {
  198. /*    Check for a command key.    */
  199.  
  200.     if ( ( dir = checkey() ) != NOWHERE ) {
  201.  
  202. /*    Determine which window is next and select it.    */
  203.  
  204.         newwin = nexwin( curwinno(), dir );
  205.         ioctl( newwin, WIOCSELECT );
  206.         close( newwin );
  207.         tock = TICK;        /*    Kludge to force return and redisplay.    */
  208.         }
  209.     }
  210.  
  211. /*    Return after TICK tocks.    */
  212.  
  213. while ( tock++ < TICK );
  214. }
  215.  
  216. /*    Stub routine to "handle" the alarm signal.  Doesn't do a lot.    */
  217.  
  218. justgoon()
  219. {
  220. return;
  221. }
  222.  
  223. checkey()
  224.  
  225. /*    Check and see if one of our keys has been poked.  The only keys this window
  226.     is supposed to respond to all generate three character escape sequences.
  227.     The print key gets ignored; I suppose it could be aliased to something
  228.     useful, like system reboot...  Set and catch an alarm signal to keep
  229.     from getting hung in the fread(); this probably could be done more
  230.     neatly some other way, but...    */
  231.  
  232. {
  233. int        direction, i;
  234. FILE    *fw;
  235. char    key[3];
  236.  
  237. /*    Set the alarm signal.    */
  238.  
  239. signal( SIGALRM, justgoon );
  240. alarm( 1 );
  241. if ( fread( key, 1, 3, stdin ) == 3 ) {
  242.  
  243. /*    Reset the alarm signal to be ignored.    */
  244.  
  245.     signal( SIGALRM, SIG_IGN );
  246.     switch ( key[2] ) {
  247.         case 'p' : 
  248.         case 'P' : direction = FORWARD; break;
  249.         case 'q' :
  250.         case 'Q' : direction = BACKWARD; break;
  251.         default : direction = NOWHERE; break;
  252.         }
  253.     }
  254.     else
  255.         direction = NOWHERE;
  256.  
  257. /*    Reset the alarm signal to be ignored.    */
  258.  
  259. signal( SIGALRM, SIG_IGN );
  260. return( direction );
  261. }
  262.  
  263. nexwin( winno, dir )
  264. int winno, dir;
  265.  
  266. /*    Decide what should be the next window.  This relies on the fact that
  267.     when you open a window device directly the open call will fail if it has
  268.     not already been opened by someone else; this is how we find the open
  269.     windows.  Invisible windows should have their user-text set to "Invisible"
  270.     if they wish to be ignored.    */
  271.  
  272. {
  273. int        wd;
  274. char    windex[12];
  275. struct    utdata    wintext;
  276.  
  277. /*    Trivial loop; at worst, we'll wind up back where we started.  I suppose
  278.     it's possible to have a system with no windows except those marked as
  279.     "Invisible"; it doesn't seem to useful, though.    */
  280.  
  281. while ( 1 ) {
  282.  
  283. /*    Forward/backward sort-of modulo arithmetic.  Real modulo arithmetic
  284.     starts at zero.    */
  285.  
  286.     winno += ( dir == FORWARD ? 1 : -1 );
  287.     if ( winno > MAXWIN )
  288.         winno = MINWIN;
  289.     else if ( winno < MINWIN )
  290.         winno = MAXWIN;
  291.  
  292. /*    Generate a window name and test for existence.    */
  293.     sprintf( windex, "/dev/w%d", winno );
  294.     if ( ( wd = open( windex, O_RDONLY ) ) != -1 ) {
  295.  
  296. /*    It exists, now look at its user text info.  This is where "Invisible"
  297.     gets skipped.    */
  298.  
  299.         wintext.ut_num = WTXTUSER;
  300.         ioctl( wd, WIOCGETTEXT, &wintext );
  301.         if ( strcmp( wintext.ut_text, "Invisible" ) )
  302.             return( wd );
  303.         else
  304.             close( wd );
  305.         }
  306.     }
  307. }
  308.  
  309.