file and set operations for mc68000
[unix-history] / usr / src / usr.sbin / rwhod / rwhod.c
CommitLineData
52b4fb0c 1#ifndef lint
19bc19e0 2static char sccsid[] = "@(#)rwhod.c 4.12 (Berkeley) 83/06/01";
52b4fb0c
BJ
3#endif
4
52b4fb0c 5#include <sys/types.h>
52b4fb0c 6#include <sys/socket.h>
52b4fb0c 7#include <sys/stat.h>
52b4fb0c 8#include <sys/ioctl.h>
de3b21e8 9
7af17b3e 10#include <net/if.h>
de3b21e8
SL
11#include <netinet/in.h>
12
13#include <nlist.h>
14#include <stdio.h>
15#include <signal.h>
16#include <errno.h>
17#include <utmp.h>
a0f59ac1
SL
18#include <ctype.h>
19#include <netdb.h>
7af17b3e 20#include <rwhod.h>
de3b21e8 21
a0f59ac1 22struct sockaddr_in sin = { AF_INET };
52b4fb0c
BJ
23
24extern errno;
25
7af17b3e 26char myname[32];
52b4fb0c
BJ
27
28struct nlist nl[] = {
29#define NL_AVENRUN 0
30 { "_avenrun" },
de3b21e8
SL
31#define NL_BOOTTIME 1
32 { "_boottime" },
52b4fb0c
BJ
33 0
34};
35
7af17b3e
SL
36/*
37 * We communicate with each neighbor in
38 * a list constructed at the time we're
39 * started up. Neighbors are currently
40 * directly connected via a hardware interface.
41 */
42struct neighbor {
43 struct neighbor *n_next;
44 char *n_name; /* interface name */
45 char *n_addr; /* who to send to */
46 int n_addrlen; /* size of address */
47 int n_flags; /* should forward?, interface flags */
48};
49
50struct neighbor *neighbors;
52b4fb0c 51struct whod mywd;
7af17b3e 52struct servent *sp;
52b4fb0c
BJ
53int s, utmpf, kmemf = -1;
54
7af17b3e
SL
55#define WHDRSIZE (sizeof (mywd) - sizeof (mywd.wd_we))
56#define RWHODIR "/usr/spool/rwho"
fea387f0 57
52b4fb0c 58int onalrm();
7af17b3e 59char *strcpy(), *sprintf(), *malloc();
52b4fb0c
BJ
60long lseek();
61int getkmem();
7af17b3e 62struct in_addr inet_makeaddr();
52b4fb0c
BJ
63
64main()
65{
66 struct sockaddr_in from;
67 char path[64];
68 int addr;
7af17b3e 69 struct hostent *hp;
52b4fb0c 70
a0f59ac1
SL
71 sp = getservbyname("who", "udp");
72 if (sp == 0) {
73 fprintf(stderr, "rwhod: udp/who: unknown service\n");
74 exit(1);
75 }
52b4fb0c
BJ
76#ifndef DEBUG
77 if (fork())
78 exit(0);
79 { int s;
80 for (s = 0; s < 10; s++)
81 (void) close(s);
82 (void) open("/", 0);
83 (void) dup2(0, 1);
84 (void) dup2(0, 2);
85 s = open("/dev/tty", 2);
86 if (s >= 0) {
87 ioctl(s, TIOCNOTTY, 0);
88 (void) close(s);
89 }
90 }
91#endif
92 (void) chdir("/dev");
93 (void) signal(SIGHUP, getkmem);
94 if (getuid()) {
a0f59ac1 95 fprintf(stderr, "rwhod: not super user\n");
52b4fb0c
BJ
96 exit(1);
97 }
7af17b3e
SL
98 /*
99 * Establish host name as returned by system.
100 */
101 if (gethostname(myname, sizeof (myname) - 1) < 0) {
102 perror("gethostname");
52b4fb0c
BJ
103 exit(1);
104 }
7af17b3e 105 strncpy(mywd.wd_hostname, myname, sizeof (myname) - 1);
52b4fb0c
BJ
106 utmpf = open("/etc/utmp", 0);
107 if (utmpf < 0) {
108 (void) close(creat("/etc/utmp", 0644));
109 utmpf = open("/etc/utmp", 0);
110 }
111 if (utmpf < 0) {
a0f59ac1 112 perror("rwhod: /etc/utmp");
52b4fb0c
BJ
113 exit(1);
114 }
115 getkmem();
85b11450 116 if ((s = socket(AF_INET, SOCK_DGRAM, 0, 0)) < 0) {
a0f59ac1 117 perror("rwhod: socket");
de3b21e8
SL
118 exit(1);
119 }
7af17b3e
SL
120 hp = gethostbyname(myname);
121 if (hp == NULL) {
122 fprintf(stderr, "%s: don't know my own name\n", myname);
123 exit(1);
124 }
125 sin.sin_family = hp->h_addrtype;
126 sin.sin_port = sp->s_port;
de3b21e8
SL
127 if (bind(s, &sin, sizeof (sin), 0) < 0) {
128 perror("rwhod: bind");
129 exit(1);
52b4fb0c 130 }
7af17b3e
SL
131 if (!configure(s))
132 exit(1);
52b4fb0c
BJ
133 sigset(SIGALRM, onalrm);
134 onalrm();
135 for (;;) {
136 struct whod wd;
7af17b3e 137 int cc, whod, len = sizeof (from);
52b4fb0c 138
7af17b3e
SL
139 cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
140 &from, &len);
52b4fb0c
BJ
141 if (cc <= 0) {
142 if (cc < 0 && errno != EINTR)
de3b21e8 143 perror("rwhod: recv");
52b4fb0c
BJ
144 continue;
145 }
a0f59ac1
SL
146 if (from.sin_port != sp->s_port) {
147 fprintf(stderr, "rwhod: %d: bad from port\n",
148 ntohs(from.sin_port));
52b4fb0c
BJ
149 continue;
150 }
a0f59ac1
SL
151#ifdef notdef
152 if (gethostbyname(wd.wd_hostname) == 0) {
153 fprintf(stderr, "rwhod: %s: unknown host\n",
154 wd.wd_hostname);
155 continue;
156 }
157#endif
aaddf8a1
SL
158 if (wd.wd_vers != WHODVERSION)
159 continue;
7af17b3e
SL
160 if (wd.wd_type != WHODTYPE_STATUS)
161 continue;
a0f59ac1
SL
162 if (!verify(wd.wd_hostname)) {
163 fprintf(stderr, "rwhod: malformed host name from %x\n",
164 from.sin_addr);
52b4fb0c
BJ
165 continue;
166 }
a82aa56a 167 (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
52b4fb0c
BJ
168 whod = creat(path, 0666);
169 if (whod < 0) {
a0f59ac1
SL
170 fprintf(stderr, "rwhod: ");
171 perror(path);
52b4fb0c
BJ
172 continue;
173 }
fea387f0
SL
174#if vax || pdp11
175 {
176 int i, n = (cc - WHDRSIZE)/sizeof(struct utmp);
177 struct whoent *we;
178
179 /* undo header byte swapping before writing to file */
180 wd.wd_sendtime = ntohl(wd.wd_sendtime);
181 for (i = 0; i < 3; i++)
182 wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]);
183 wd.wd_boottime = ntohl(wd.wd_boottime);
184 we = wd.wd_we;
185 for (i = 0; i < n; i++) {
186 we->we_idle = ntohl(we->we_idle);
19bc19e0
SL
187 we->we_utmp.ut_time =
188 ntohl(we->we_utmp.ut_time);
fea387f0
SL
189 we++;
190 }
191 }
192#endif
52b4fb0c
BJ
193 (void) time(&wd.wd_recvtime);
194 (void) write(whod, (char *)&wd, cc);
195 (void) close(whod);
196 }
197}
198
a0f59ac1
SL
199/*
200 * Check out host name for unprintables
201 * and other funnies before allowing a file
202 * to be created. Sorry, but blanks aren't allowed.
203 */
204verify(name)
205 register char *name;
206{
207 register int size = 0;
208
209 while (*name) {
210 if (!isascii(*name) || !isalnum(*name))
211 return (0);
212 name++, size++;
213 }
214 return (size > 0);
215}
216
52b4fb0c
BJ
217int utmptime;
218int utmpent;
76886f32 219struct utmp utmp[100];
52b4fb0c
BJ
220int alarmcount;
221
222onalrm()
223{
224 register int i;
225 struct stat stb;
76886f32 226 register struct whoent *we = mywd.wd_we, *wlast;
52b4fb0c
BJ
227 int cc;
228 double avenrun[3];
229 time_t now = time(0);
7af17b3e 230 register struct neighbor *np;
52b4fb0c
BJ
231
232 if (alarmcount % 10 == 0)
233 getkmem();
234 alarmcount++;
235 (void) fstat(utmpf, &stb);
236 if (stb.st_mtime != utmptime) {
237 (void) lseek(utmpf, (long)0, 0);
238 cc = read(utmpf, (char *)utmp, sizeof (utmp));
239 if (cc < 0) {
240 perror("/etc/utmp");
241 return;
242 }
7af17b3e 243 wlast = &mywd.wd_we[1024 / sizeof (struct whoent) - 1];
52b4fb0c
BJ
244 utmpent = cc / sizeof (struct utmp);
245 for (i = 0; i < utmpent; i++)
246 if (utmp[i].ut_name[0]) {
b1456c48
SL
247 bcopy(utmp[i].ut_line, we->we_utmp.out_line,
248 sizeof (utmp[i].ut_line));
249 bcopy(utmp[i].ut_name, we->we_utmp.out_name,
250 sizeof (utmp[i].ut_name));
b1456c48 251 we->we_utmp.out_time = htonl(utmp[i].ut_time);
76886f32
SL
252 if (we >= wlast)
253 break;
52b4fb0c
BJ
254 we++;
255 }
256 utmpent = we - mywd.wd_we;
257 }
258 we = mywd.wd_we;
259 for (i = 0; i < utmpent; i++) {
b1456c48 260 if (stat(we->we_utmp.out_line, &stb) >= 0)
b1456c48 261 we->we_idle = htonl(now - stb.st_atime);
52b4fb0c
BJ
262 we++;
263 }
264 (void) lseek(kmemf, (long)nl[NL_AVENRUN].n_value, 0);
265 (void) read(kmemf, (char *)avenrun, sizeof (avenrun));
266 for (i = 0; i < 3; i++)
b1456c48 267 mywd.wd_loadav[i] = htonl(avenrun[i] * 100);
b1456c48 268 cc = (char *)we - (char *)&mywd;
b1456c48 269 mywd.wd_sendtime = htonl(time(0));
7af17b3e
SL
270 mywd.wd_vers = WHODVERSION;
271 mywd.wd_type = WHODTYPE_STATUS;
272 for (np = neighbors; np != NULL; np = np->n_next)
273 (void) sendto(s, (char *)&mywd, cc, 0,
274 np->n_addr, np->n_addrlen);
52b4fb0c
BJ
275 (void) alarm(60);
276}
277
278getkmem()
279{
280 struct nlist *nlp;
281
282 signal(SIGHUP, getkmem);
283 if (kmemf >= 0)
284 (void) close(kmemf);
285loop:
286 for (nlp = &nl[sizeof (nl) / sizeof (nl[0])]; --nlp >= nl; ) {
287 nlp->n_value = 0;
288 nlp->n_type = 0;
289 }
290 nlist("/vmunix", nl);
291 if (nl[0].n_value == 0) {
292 fprintf(stderr, "/vmunix namelist botch\n");
293 sleep(300);
294 goto loop;
295 }
296 kmemf = open("/dev/kmem", 0);
297 if (kmemf < 0) {
298 perror("/dev/kmem");
299 sleep(300);
300 goto loop;
301 }
de3b21e8
SL
302 (void) lseek(kmemf, (long)nl[NL_BOOTTIME].n_value, 0);
303 (void) read(kmemf, (char *)&mywd.wd_boottime, sizeof (mywd.wd_boottime));
b1456c48 304 mywd.wd_boottime = htonl(mywd.wd_boottime);
52b4fb0c 305}
7af17b3e
SL
306
307/*
308 * Figure out device configuration and select
309 * networks which deserve status information.
310 */
311configure(s)
312 int s;
313{
314 char buf[BUFSIZ];
315 struct ifconf ifc;
316 struct ifreq ifreq, *ifr;
317 int n;
318 struct sockaddr_in *sin;
319 register struct neighbor *np;
320
321 ifc.ifc_len = sizeof (buf);
322 ifc.ifc_buf = buf;
323 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
324 perror("rwhod: ioctl (get interface configuration)");
325 return (0);
326 }
327 ifr = ifc.ifc_req;
328 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifr++) {
329 for (np = neighbors; np != NULL; np = np->n_next)
330 if (np->n_name &&
331 strcmp(ifr->ifr_name, np->n_name) == 0)
332 break;
333 if (np != NULL)
334 continue;
335 ifreq = *ifr;
336 np = (struct neighbor *)malloc(sizeof (*np));
337 if (np == NULL)
338 continue;
339 np->n_name = malloc(strlen(ifr->ifr_name) + 1);
340 if (np->n_name == NULL) {
341 free((char *)np);
342 continue;
343 }
344 strcpy(np->n_name, ifr->ifr_name);
345 np->n_addrlen = sizeof (ifr->ifr_addr);
346 np->n_addr = malloc(np->n_addrlen);
347 if (np->n_addr == NULL) {
348 free(np->n_name);
349 free((char *)np);
350 continue;
351 }
352 bcopy((char *)&ifr->ifr_addr, np->n_addr, np->n_addrlen);
353 if (ioctl(s, SIOCGIFFLAGS, (char *)&ifreq) < 0) {
354 perror("rwhod: ioctl (get interface flags)");
355 free((char *)np);
356 continue;
357 }
358 if ((ifreq.ifr_flags & (IFF_BROADCAST|IFF_POINTOPOINT)) == 0) {
359 free((char *)np);
360 continue;
361 }
362 np->n_flags = ifreq.ifr_flags;
363 if (np->n_flags & IFF_POINTOPOINT) {
364 if (ioctl(s, SIOCGIFDSTADDR, (char *)&ifreq) < 0) {
365 perror("rwhod: ioctl (get dstaddr)");
366 free((char *)np);
367 continue;
368 }
369 /* we assume addresses are all the same size */
370 bcopy((char *)&ifreq.ifr_dstaddr,
371 np->n_addr, np->n_addrlen);
372 }
373 if (np->n_flags & IFF_BROADCAST) {
374 /* we assume addresses are all the same size */
375 sin = (struct sockaddr_in *)np->n_addr;
376 sin->sin_addr =
377 inet_makeaddr(inet_netof(sin->sin_addr), INADDR_ANY);
378 }
379 /* gag, wish we could get rid of Internet dependencies */
380 sin = (struct sockaddr_in *)np->n_addr;
381 sin->sin_port = sp->s_port;
382 np->n_next = neighbors;
383 neighbors = np;
384 }
385 return (1);
386}
b1456c48
SL
387
388#ifdef DEBUG
389sendto(s, buf, cc, flags, to, tolen)
390 int s;
391 char *buf;
392 int cc, flags;
393 char *to;
394 int tolen;
395{
396 register struct whod *w = (struct whod *)buf;
397 register struct whoent *we;
398 struct sockaddr_in *sin = (struct sockaddr_in *)to;
399 char *interval();
400
401 printf("sendto %x.%d\n", ntohl(sin->sin_addr), ntohs(sin->sin_port));
402 printf("hostname %s %s\n", w->wd_hostname,
403 interval(w->wd_sendtime - w->wd_boottime, " up"));
404 printf("load %4.2f, %4.2f, %4.2f\n",
405 w->wd_loadav[0] / 100.0, w->wd_loadav[1] / 100.0,
406 w->wd_loadav[2] / 100.0);
407 cc -= WHDRSIZE;
408 for (we = w->wd_we, cc /= sizeof (struct whoent); cc > 0; cc--, we++) {
409 printf("%-8.8s %s:%s %.12s",
410 we->we_utmp.out_name,
411 w->wd_hostname, we->we_utmp.out_line,
412 ctime((time_t *)&we->we_utmp.out_time)+4);
413 we->we_idle /= 60;
414 if (we->we_idle) {
415 if (we->we_idle >= 100*60)
416 we->we_idle = 100*60 - 1;
417 if (we->we_idle >= 60)
418 printf(" %2d", we->we_idle / 60);
419 else
420 printf(" ");
421 printf(":%02d", we->we_idle % 60);
422 }
423 printf("\n");
424 }
425}
426
427char *
428interval(time, updown)
429 int time;
430 char *updown;
431{
432 static char resbuf[32];
433 int days, hours, minutes;
434
435 if (time < 0 || time > 3*30*24*60*60) {
436 (void) sprintf(resbuf, " %s ??:??", updown);
437 return (resbuf);
438 }
439 minutes = (time + 59) / 60; /* round to minutes */
440 hours = minutes / 60; minutes %= 60;
441 days = hours / 24; hours %= 24;
442 if (days)
443 (void) sprintf(resbuf, "%s %2d+%02d:%02d",
444 updown, days, hours, minutes);
445 else
446 (void) sprintf(resbuf, "%s %2d:%02d",
447 updown, hours, minutes);
448 return (resbuf);
449}
450#endif