+#
+/*
+ * syswatch - login-logout monitoring
+ *
+ * Author: Howard Katseff UCB May/August 1977
+ *
+ * Syswatch monitors all logins and logouts on the system.
+ * It is a companion routine to watch which monitors specific
+ * users. The difference between these two routines is that
+ * the linked list stuff in watch has been abolished here in favor
+ * of a simpler scheme.
+ *
+ * ROOTDEV and NULLDEV are for determining when a user's tty has
+ * been chfile'd to /dev/null, in which case, the user has logged
+ * out and is probably no longer interested in the results of
+ * this program.
+ *
+ * This check will not work on non-UCB type UNIX'es.
+ * The check should be changed, or the syswatch killed explicitly.
+ */
+
+#define DLATENCY 15
+#define ROOTSYS ((5<<8) | 8)
+#define NULLDEV ((8<<8) | 2)
+
+int lastuser,valid;
+int zero[2];
+char *who_file "/etc/utmp";
+char *nil 0177777;
+
+
+struct t_entry {
+ char name[10];
+ char tty;
+ int time[2];
+ int valid;
+} people[128], newpeople[128];
+
+struct utmp {
+ char Xname[10];
+ char Xtty;
+ char pad1;
+ int ltime[2];
+ int pad2;
+};
+
+main(ct,av)
+ char **av;
+{
+ register i;
+ register char *cp,*cp2;
+ int *p,pid,LATENCY;
+ LATENCY = DLATENCY;
+ p = -2;
+ if (pid=fork())
+ {
+ printf("%d\n",pid);
+ exit(0);
+ }
+ signal(2,1);
+ signal(3,1);
+ build();
+ for (i=0;i<128;++i) assign(people[i].name, newpeople[i].name);
+ for (;;)
+ {
+ execute();
+ sleep(LATENCY);
+ }
+}
+
+execute()
+{
+ register i;
+ int buf[18];
+ if (fstat(1, buf)) exit(0);
+ if (buf[0] == ROOTSYS && buf[6] == NULLDEV) exit(0);
+ valid++;
+ build();
+ for (i=0;i<128;++i)
+ {
+ if (!dcmp(newpeople[i].time,people[i].time))
+ {
+ report(i);
+ assign(people[i].name, newpeople[i].name);
+ }
+ }
+}
+
+build()
+{
+ register fd,i;
+ struct utmp line;
+ if ((fd=open(who_file,0)) < 0)
+ {
+ perror(who_file);
+ exit(1);
+ }
+ for (i=0;i<128;++i) newpeople[i].time[0] = newpeople[i].time[1] = 0;
+ while (getuser(fd,&line))
+ {
+ i = line.Xtty;
+ newpeople[i].valid = valid;
+ copy(line.Xname, newpeople[i].name);
+ newpeople[i].tty = i;
+ newpeople[i].time[0] = line.ltime[0];
+ newpeople[i].time[1] = line.ltime[1];
+ }
+ close(fd);
+}
+
+assign(l,r)
+ struct t_entry *l,*r;
+{
+ copy(r->name, l->name);
+ l->tty = r->tty;
+ l->time[0] = r->time[0];
+ l->time[1] = r->time[1];
+ l->valid++;
+}
+
+getuser(f,w)
+ struct utmp *w;
+{
+ register c;
+ char buf[16];
+ c = read(f,buf,16);
+ if (c != 16) return(0);
+ for (c=0;c<8;++c) w->Xname[c] = (buf[c] == 040 ? 0 : buf[c]);
+ w->Xname[8] = 0;
+ w->Xtty = buf[8];
+ if (w->Xname[0] == 0)
+ {
+ w->ltime[0] = w->ltime[1] = 0;
+ return(16);
+ }
+ w->ltime[0] = ctoi(buf[11],buf[10]);
+ w->ltime[1] = ctoi(buf[13],buf[12]);
+ return(16);
+}
+
+copy(c1,c2)
+ char *c1,*c2;
+{
+ while (*c2++ = *c1++);
+}
+
+equal(left,right)
+ char *left,*right;
+{
+ while (*left && *right)
+ {
+ if (*left != *right) return(0);
+ ++left;
+ ++right;
+ }
+ return(*left == *right);
+}
+
+dcmp(a,b)
+ int a[],b[];
+{
+ return(a[0]==b[0] && a[1]==b[1]);
+}
+
+ctoi(a,b)
+ char a,b;
+{
+ return(((a & 0377) << 8) | (b & 0377));
+}
+
+report(t)
+ char t;
+{
+ if (dcmp(people[t].time, zero))
+ {
+ printf("%s on tty%c %s",newpeople[t].name,t,ctime(newpeople[t].ltime));
+ return;
+ }
+ if (dcmp(newpeople[t].time,zero))
+ {
+ printf("%s on tty%c logged out.\n",people[t].name,t);
+ return;
+ }
+ printf("%s on tty%c logged out.\n",people[t].name,t);
+ printf("%s on tty%c %s",newpeople[t].name,t,ctime(newpeople[t].ltime));
+}