#include <stdio.h> #include <ctype.h> #include <sys/param.h> #include <sys/types.h> #include <pwd.h> #include <signal.h> #include <sgtty.h> #include "defs.h" #include "load.h" #include "msg.h" #include "scanmail.h" /* structures */ struct machdef { struct ld m_old; /* previous set of poal numbers */ struct ld m_new; /* current set of load numbers */ bool m_cpnew; /* TRUE-> a new cpu percentage exists */ bool m_rqnew; /* TRUE-> a new run queue exists */ bool m_init; /* first sample should not be displayed */ char *m_name; /* name of this node */ int m_fd; /* stream for connection to remote machine */ }; #define MAGIC '_' /* message introduction */ /* globals */ static int vismon; static struct scanmail sm; /* mail for local machine */ static struct machdef md[MAXMACHS]; /* connections are fd limited */ static int local; /* offset into md of local machine */ static int nm; /* the number of machines */ static fd_set g_fd; /* select set for the generators */ static char *blitfile; /* binary file to load into blit */ static int deathknell; /* true if we should die */ #define DEBUG if (debug) /* exported */ int debug = 0; int onlymail = 0; int lucaversion = 0; char *thissys; int sendjerq(); /* imports */ extern int errno; extern int getopt(); extern char * getsysname(); extern int initload(); extern int genload(); extern void sminit(); extern char *smnext(); extern char *strrchr(), *strncpy(), *strcpy(); extern long lseek(); extern long time(); extern char *malloc(); extern unsigned int sleep(); extern int getutmp(); extern int setutmp(); extern void resetutmp(); extern char *getlogin(), *getenv(); /* predefined */ static void die(); static int catchint(); static int forkexec(); static void error(); /* "user", "nice", "sys", "queue", "idle", */ main(ac, av) int ac; char *av[]; { int ticks; int per15secs = 15; int permin = 60; int per2mins = 120; char *p; /* get the info for a utmp entry */ if (getutmp() < 0) error("can't get login or terminal name"); /* make sure we clean up the utmp entry on termination */ signal (SIGPIPE, catchint); signal (SIGHUP, catchint); signal (SIGINT, catchint); signal (SIGQUIT, catchint); signal (SIGKILL, catchint); /* put an entry into utmp */ if (setutmp() < 0) error("can't set utmp entry"); /* initialize load gathering */ initload(); /* initialize mail spying */ thissys = getsysname(); p = getenv ("MAIL"); sminit (&sm, p, getlogin()); ticks = getargs (ac, av); dotime(); while (TRUE) { getinfo(); docpu(); if(per2mins++ >= 120/ticks){ doconnect(); per2mins = 0; } if(permin++ >= 60/ticks){ dotime(); doload(); permin = 0; } if(per15secs++ >= 15/ticks){ domail(); per15secs = 0; } scanjerq(0); sleep(ticks); } } /* * Get a request from the jerq. Return * 0 if no request or a request other than R or A * 1 if request is A * -1 if request is R */ static int scanjerq(replyflag) int replyflag; /* non-zero to indicate waiting for reply */ { int i; fd_set fds; char name[64]; char *np, *np2; FD_ZERO(fds); FD_SET(0, fds); if (select(NOFILE, (int *)&fds, (int *)0, 0) != 0) { /* read the command */ if ((i = read(0, name, sizeof(name)))<=0) die(); /* switch on command type (first letter) */ name[i-1] = 0; switch (name[0]) { case 'A': /* accept */ return 1; case 'R': /* refuse */ return -1; case 'Q': /* quit */ die(); case 'M': /* monitor request, are we already monitoring it ? */ if (replyflag) break; np = strrchr(name, '/'); np = np==NULL ? name+1 : np+1; for (i=0; i<nm; i++) { np2 = strrchr(md[i].m_name, '/'); np2 = np2==NULL ? md[i].m_name : np2+1; if (strcmp(np, np2)==0) break; } if (i < nm) { /* remove the system */ remove_sys(i); } else { /* add the system */ add_sys(name+1); } default: /* Oh well */ break; } } return 0; } /* try to connect unconnected generators */ static int doconnect () { register int i; /* don't connect to local system (i = 0) */ for (i = 0; i < nm; i++) if (md[i].m_fd < 0 && i != local) connectto(i); } /* look for new load information */ static int getinfo() { register int i, fd; fd_set rdfd; int len; char buf[128]; char noise[10], noise2[10], noise3[10]; /* look for waiting input */ rdfd = g_fd; while (select (NOFILE, (int *)&rdfd, (int *)0, 0) > 0) { /* find out which machine it's from */ for (i = 0; i < nm; i++) { fd = md[i].m_fd; if (fd < 0 || !FD_ISSET(fd, rdfd)) continue; /* read the message */ DEBUG fprintf(stderr,"info for %s\n", md[i].m_name); if ((len = read(fd, buf, sizeof(buf))) <= 0) { DEBUG fprintf (stderr, "closing\n"); close (fd); FD_CLR(fd, g_fd); md[i].m_fd = -1; continue; } if (buf[len-1] == '\n') buf[len-1] = '\0'; /* switch on message type */ switch (buf[0]) { case 'l': sscanf(buf,"%s%f%s%d%s%d%d%d%d%d", noise, &md[i].m_new.l_runq, noise2, &md[i].m_new.l_time, noise3, &md[i].m_new.l_cp[0], &md[i].m_new.l_cp[1], &md[i].m_new.l_cp[2], &md[i].m_new.l_cp[3], &md[i].m_new.l_cp[4]); md[i].m_cpnew = md[i].m_rqnew = TRUE; break; case 'f': sendmail (buf+5, i); break; } } rdfd = g_fd; } /* get local info */ if (local >= 0) { genload(); md[local].m_new = load; md[local].m_cpnew = md[local].m_rqnew = TRUE; } } /* display CPU percentages */ char vec[NOFILE*6 + 3]; static int docpu() { register int i, j, sum; char *vp = vec; int diff[5]; long l; for (i = 0; i < (onlymail ? 1 : nm); i++) { if (md[i].m_cpnew) { l = md[i].m_new.l_cp[3]; md[i].m_new.l_cp[3] = md[i].m_new.l_cp[4]; md[i].m_new.l_cp[4] = l; *vp++ = i + '0'; for (sum=j=0; j<5; j++) sum += (diff[j] = (md[i].m_new.l_cp[j] - md[i].m_old.l_cp[j])); sum = sum ? sum : 1; for (j=0; j<5; j++) { *vp++ = (diff[j] * 100) / sum; md[i].m_old.l_cp[j] = md[i].m_new.l_cp[j]; } if (md[i].m_init) { md[i].m_init = FALSE; vp -= 6; } md[i].m_cpnew = FALSE; } } if (vp != vec) sendjerq('V', vec, vp - vec); } /* read the arguments */ static int getargs (ac, av) int ac; char *av[]; { int i; int ticks = 5; char *myname, *p; myname = strrchr(av[0], '/'); myname = myname == NULL ? av[0] : myname+1; /* read the tick value and arguments */ if (ac > 1 && av[1][0] == '-') { switch (av[1][1] & 0xff) { case 'f': blitfile = av[2]; av++, ac--; break; case 'd': debug = 1; break; case 'm': onlymail = 1; break; case 'l': lucaversion = 1; break; default: ticks = -atoi(av[1]); if (ticks < 2) ticks = 2; } av++, ac--; } /* initialize entries */ for (i = 0; i<MAXMACHS; i++) md[i].m_fd = -1; /* set up the communications */ if (!debug) (void)startblit(); /* are we vismon? */ if (strcmp(myname, "vismon") == 0) { sendjerq('Q', (char *)0, 0); while(!(i=scanjerq(1))); if (i > 0) vismon++; } /* who to watch */ for (nm = 0, p = getsysname(); ac > 0; av++, ac--, p = *av) { add_sys (p); } /* get symbols and things */ return (ticks); } static int add_sys(p) char *p; { int i; md[nm].m_name = (char *)strcpy(malloc(strlen(p)+1), p); for (i = 0; i < 5; i++) md[nm].m_old.l_cp[i] = 0; md[nm].m_cpnew = FALSE; md[nm].m_rqnew = FALSE; md[nm].m_init = TRUE; md[nm].m_fd = -1; if (!onlymail || nm == 0) { p = strrchr(p, '/'); p = p==NULL ? md[nm].m_name : p+1; sendjerq('N', p, strlen(p)); while(!(i=scanjerq(1))); if (i < 0) return; } if (nm != local) connectto(nm); nm++; } static int remove_sys(i) int i; { char which; /* tell jerq to forget it */ which = i + '0'; sendjerq('R', &which, sizeof(which)); /* special case for local machine */ if (local == i) local = -1; /* close connection to server */ if (md[i].m_fd >= 0) { close(md[i].m_fd); FD_CLR(md[i].m_fd, g_fd); } /* compact what's left */ for (; i < nm; i++) md[i] = md[i+1]; --nm; } static int startblit() { char *getenv(); char *term = getenv("TERM"); int status; int pid; struct sgttyb sttybuf, savebuf; ioctl(0, TIOCGETP, &savebuf); sttybuf = savebuf; sttybuf.sg_flags|=RAW; sttybuf.sg_flags&=~ECHO; ioctl(0, TIOCSETP, &sttybuf); if (term != 0 && strcmp(term, "blit") == 0) { if (blitfile == 0) blitfile = lucaversion ? "/usr/blit/mbin/lucamon.m" : "/usr/blit/mbin/sysmon.m"; pid = forkexec("/usr/blit/bin/68ld", "68ld", blitfile, (char *)0); } else { if (blitfile == 0) blitfile = lucaversion ? "/usr/jerq/mbin/lucamon.m" : "/usr/jerq/mbin/sysmon.m"; pid = forkexec("/usr/jerq/bin/32ld", "32ld", blitfile, (char *)0); } if (pid == -1) { fprintf (stderr, "couldn't load jerq\n", status>>8); die(); } /* wait for loading to finish */ while (wait(&status) != pid) ; if (status != 0) { ioctl(0, TIOCSETP, &savebuf); error ("jerq load returns error status"); } } static int connectto (i) int i; { fprintf(stderr, "Connectto called\n"); /* int fd; senddiag("dialing", i); if ((fd = calldaemon (md[i].m_name, "mon")) <= 0) { md[i].m_fd = -1; senddiag("failed", i); } else { DEBUG fprintf (stderr, "connected to %s on %d\n", md[i].m_name, fd); md[i].m_fd = fd; FD_SET(fd, g_fd); senddiag("connected", i); } */ } char timevec[]="T01234\n"; static int dotime(){ char *p, *ctime(); long l; l = time ((long *)0); p = ctime(&l); sendjerq ('T', p+11, 5); } /* send the new run queue to the blit */ static int doload() { register int i; char buf[132]; char *bp = buf; double fabs(); for (i = 0; i < (onlymail ? 1 : nm); i++) { if (md[i].m_rqnew) { sprintf(bp, "%c %.2f %c%.2f\t", i + '0', md[i].m_new.l_runq, "-+"[md[i].m_new.l_runq>md[i].m_old.l_runq], fabs(md[i].m_new.l_runq-md[i].m_old.l_runq)); bp += strlen(bp); md[i].m_old.l_runq = md[i].m_new.l_runq; md[i].m_rqnew = FALSE; } } if (bp != buf) sendjerq ('L', buf, bp-buf); } /* * mail stuff */ static int domail () { char *p; if (local < 0) return; /* check local mail */ while ((p = smnext (&sm, (FILE *)NULL)) != NULL) sendmail (p, local); } static int sendmail(p, i) char *p; int i; { char sender[64]; char machine[64]; char buf[132]; from (p, machine, sender); buf[0] = '0' + (onlymail ? 0 : i); buf[1] = '\0'; if (*machine != '\0') { strcat(buf+1, machine); strcat(buf+1, "!"); } strcat(buf+1, sender); buf[MAXMAIL+1] = '\0'; sendjerq ('M', buf, strlen(buf)); if (vismon) sendicon(machine, sender); } static int senddiag(p, i) char *p; int i; { char buf[MAXMAIL+3]; buf[0] = '0' + (onlymail ? 0 : i); strncpy(buf+1, p, MAXMAIL); buf[MAXMAIL+1] = '\0'; sendjerq ('L', buf, strlen(buf)); } /* * send a message to the jerq */ extern int sendjerq(type, msg, len) char type; /* message type */ char *msg; /* a null terminated message */ { char buf[300]; char *bp = buf; int n; *bp++ = MAGIC; *bp++ = type; for (; len > 0; len--) { if (*msg == '\n' || *msg == '\\') *bp++ = '\\'; *bp++ = *msg++; } *bp++ = '\n'; n = write (1, buf, bp-buf); if (n != bp-buf) error("display terminated abnormally"); } static int forkexec(a1, a2, a3, a4) char *a1, *a2, *a3, *a4; { int pid; switch (pid = fork()) { case 0: execl (a1, a2, a3, a4); error ("can't execl"); case -1: fprintf(stderr, "out of processes"); } return pid; } /* catch interrupts and exit */ static int catchint() { die(); } /* cleanup and exit */ static void die() { signal (SIGPIPE, SIG_IGN); signal (SIGALRM, SIG_IGN); signal (SIGHUP, SIG_IGN); signal (SIGINT, SIG_IGN); signal (SIGQUIT, SIG_IGN); signal (SIGKILL, SIG_IGN); resetutmp(); exit (0); } /* error messges */ static void error (s) char *s; { fprintf(stderr, "sysmon: %s\n", s); die(); }