xref: /original-bsd/usr.sbin/rwhod/rwhod.c (revision 9a96b58b)
1 #ifndef lint
2 static char sccsid[] = "@(#)rwhod.c	4.3 82/04/20";
3 #endif
4 
5 #include <stdio.h>
6 #include <signal.h>
7 #include <sys/types.h>
8 #include <net/in.h>
9 #include <sys/socket.h>
10 #include <errno.h>
11 #include <utmp.h>
12 #include "rwhod.h"
13 #include <sys/stat.h>
14 #include <nlist.h>
15 #include <sys/ioctl.h>
16 
17 struct	sockaddr_in sin = { AF_INET, IPPORT_WHOSERVER };
18 
19 extern	errno;
20 
21 char	*localnet = "localnet";
22 char	*myname = "myname";
23 
24 struct	nlist nl[] = {
25 #define	NL_AVENRUN	0
26 	{ "_avenrun" },
27 #define	NL_BOOTIME	1
28 	{ "_bootime" },
29 	0
30 };
31 
32 struct	whod mywd;
33 int	s, utmpf, kmemf = -1;
34 
35 int	onalrm();
36 char	*strcpy(), *sprintf();
37 long	lseek();
38 int	getkmem();
39 
40 main()
41 {
42 	struct sockaddr_in from;
43 	char path[64];
44 	int addr;
45 
46 #ifndef DEBUG
47 	if (fork())
48 		exit(0);
49 	{ int s;
50 	  for (s = 0; s < 10; s++)
51 		(void) close(s);
52 	  (void) open("/", 0);
53 	  (void) dup2(0, 1);
54 	  (void) dup2(0, 2);
55 	  s = open("/dev/tty", 2);
56 	  if (s >= 0) {
57 		ioctl(s, TIOCNOTTY, 0);
58 		(void) close(s);
59 	  }
60 	}
61 #endif
62 	(void) chdir("/dev");
63 	(void) signal(SIGHUP, getkmem);
64 	if (getuid()) {
65 		fprintf(stderr, "not super user\n");
66 		exit(1);
67 	}
68 	addr = rhost(&localnet);
69 	if (addr == -1) {
70 		fprintf(stderr, "no localnet for whod\n");
71 		exit(1);
72 	}
73 	sin.sin_addr.s_addr = addr;
74 	if (rhost(&myname) == -1) {
75 		fprintf(stderr, "don't know my name\n");
76 		exit(1);
77 	}
78 	strncpy(mywd.wd_hostname, myname, sizeof (mywd.wd_hostname) - 1);
79 	utmpf = open("/etc/utmp", 0);
80 	if (utmpf < 0) {
81 		(void) close(creat("/etc/utmp", 0644));
82 		utmpf = open("/etc/utmp", 0);
83 	}
84 	if (utmpf < 0) {
85 		perror("/etc/utmp");
86 		exit(1);
87 	}
88 	getkmem();
89 #ifdef vax
90 	sin.sin_port = htons(sin.sin_port);
91 #endif
92 again:
93 	if ((s = socket(SOCK_DGRAM, 0, &sin, 0)) < 0) {
94 		perror("socket");
95 		sleep(5);
96 		goto again;
97 	}
98 	sigset(SIGALRM, onalrm);
99 	onalrm();
100 	for (;;) {
101 		struct whod wd;
102 		int cc, whod;
103 
104 		cc = receive(s, &from, (char *)&wd, sizeof (struct whod));
105 		if (cc <= 0) {
106 			if (cc < 0 && errno != EINTR)
107 				perror("receive");
108 			continue;
109 		}
110 #ifdef vax
111 		from.sin_port = ntohs(from.sin_port);
112 #endif
113 		if (from.sin_port != IPPORT_WHOSERVER) {
114 			printf("bad from port %d\n", from.sin_port);
115 			continue;
116 		}
117 /*
118 		if (rhost(&wd.wd_hostname) == -1) {
119 			printf("unknown host %s\n", wd.wd_hostname);
120 			continue;
121 		}
122 */
123 		(void) sprintf(path, "/etc/whod.%s", wd.wd_hostname);
124 		whod = creat(path, 0666);
125 		if (whod < 0) {
126 			printf("can't create %s\n", path);
127 			continue;
128 		}
129 		(void) time(&wd.wd_recvtime);
130 		(void) write(whod, (char *)&wd, cc);
131 		(void) close(whod);
132 	}
133 }
134 
135 int	utmptime;
136 int	utmpent;
137 struct	utmp utmp[100];
138 int	alarmcount;
139 
140 onalrm()
141 {
142 	register int i;
143 	struct stat stb;
144 	register struct whoent *we = mywd.wd_we, *wlast;
145 	int cc;
146 	double avenrun[3];
147 	time_t now = time(0);
148 
149 	if (alarmcount % 10 == 0)
150 		getkmem();
151 	alarmcount++;
152 	(void) fstat(utmpf, &stb);
153 	if (stb.st_mtime != utmptime) {
154 		(void) lseek(utmpf, (long)0, 0);
155 		cc = read(utmpf, (char *)utmp, sizeof (utmp));
156 		if (cc < 0) {
157 			perror("/etc/utmp");
158 			return;
159 		}
160 		wlast = &mywd.wd_we[(1024 / sizeof (struct whoent)) - 1];
161 		utmpent = cc / sizeof (struct utmp);
162 		for (i = 0; i < utmpent; i++)
163 			if (utmp[i].ut_name[0]) {
164 				we->we_utmp = utmp[i];
165 				if (we >= wlast)
166 					break;
167 				we++;
168 			}
169 		utmpent = we - mywd.wd_we;
170 	}
171 	we = mywd.wd_we;
172 	for (i = 0; i < utmpent; i++) {
173 		if (stat(we->we_utmp.ut_line, &stb) >= 0)
174 			we->we_idle = now - stb.st_atime;
175 		we++;
176 	}
177 	(void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0);
178 	(void) read(kmemf, (char *)avenrun, sizeof (avenrun));
179 	for (i = 0; i < 3; i++)
180 		mywd.wd_loadav[i] = avenrun[i] * 100;
181 	cc = (char *)we - (char *)&mywd;
182 	(void) time(&mywd.wd_sendtime);
183 	send(s, &sin, (char *)&mywd, cc);
184 	(void) alarm(60);
185 }
186 
187 getkmem()
188 {
189 	struct nlist *nlp;
190 
191 	signal(SIGHUP, getkmem);
192 	if (kmemf >= 0)
193 		(void) close(kmemf);
194 loop:
195 	for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) {
196 		nlp->n_value = 0;
197 		nlp->n_type = 0;
198 	}
199 	nlist("/vmunix", nl);
200 	if (nl[0].n_value == 0) {
201 		fprintf(stderr, "/vmunix namelist botch\n");
202 		sleep(300);
203 		goto loop;
204 	}
205 	kmemf = open("/dev/kmem", 0);
206 	if (kmemf < 0) {
207 		perror("/dev/kmem");
208 		sleep(300);
209 		goto loop;
210 	}
211 	(void) lseek(kmemf, (long)nl[NL_BOOTIME].n_value, 0);
212 	(void) read(kmemf, (char *)&mywd.wd_bootime, sizeof (mywd.wd_bootime));
213 }
214