xref: /dragonfly/usr.bin/netstat/if.c (revision a8ca8ac6)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)if.c	8.3 (Berkeley) 4/28/95
34  * $FreeBSD: src/usr.bin/netstat/if.c,v 1.32.2.9 2001/09/17 14:35:46 ru Exp $
35  * $DragonFly: src/usr.bin/netstat/if.c,v 1.12 2008/03/07 11:34:21 sephe Exp $
36  */
37 
38 #include <sys/param.h>
39 #include <sys/protosw.h>
40 #include <sys/socket.h>
41 #include <sys/sysctl.h>
42 #include <sys/time.h>
43 
44 #include <net/if.h>
45 #include <net/if_var.h>
46 #include <net/if_dl.h>
47 #include <net/if_types.h>
48 #include <net/ethernet.h>
49 #include <netinet/in.h>
50 #include <netinet/in_var.h>
51 #include <netproto/ipx/ipx.h>
52 #include <netproto/ipx/ipx_if.h>
53 #ifdef NS
54 #include <netproto/ns/ns.h>
55 #include <netproto/ns/ns_if.h>
56 #endif
57 #ifdef ISO
58 #include <netiso/iso.h>
59 #include <netiso/iso_var.h>
60 #endif
61 #include <arpa/inet.h>
62 
63 #include <signal.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68 
69 #include "netstat.h"
70 
71 #define	YES	1
72 #define	NO	0
73 
74 static void sidewaysintpr (u_int, u_long);
75 static void catchalarm (int);
76 
77 #ifdef INET6
78 static char ntop_buf[INET6_ADDRSTRLEN];		/* for inet_ntop() */
79 #endif
80 
81 
82 /*
83  * Display a formatted value, or a '-' in the same space.
84  */
85 static void
86 show_stat(const char *fmt, int width, u_long value, short showvalue)
87 {
88 	char newfmt[32];
89 
90 	/* Construct the format string */
91 	if (showvalue) {
92 		sprintf(newfmt, "%%%d%s", width, fmt);
93 		printf(newfmt, value);
94 	} else {
95 		sprintf(newfmt, "%%%ds", width);
96 		printf(newfmt, "-");
97 	}
98 }
99 
100 
101 
102 /*
103  * Print a description of the network interfaces.
104  */
105 void
106 intpr(int interval1, u_long ifnetaddr, void (*pfunc)(char *))
107 {
108 	struct ifnet ifnet;
109 	struct ifaddr_container ifac;
110 	struct ifnethead ifnethead;
111 	union {
112 		struct ifaddr ifa;
113 		struct in_ifaddr in;
114 #ifdef INET6
115 		struct in6_ifaddr in6;
116 #endif
117 		struct ipx_ifaddr ipx;
118 #ifdef NS
119 		struct ns_ifaddr ns;
120 #endif
121 #ifdef ISO
122 		struct iso_ifaddr iso;
123 #endif
124 	} ifaddr;
125 	u_long ifaddraddr;
126 	u_long ifaddrcont_addr;
127 	u_long ifaddrfound;
128 	u_long ifnetfound;
129 	u_long opackets;
130 	u_long ipackets;
131 	u_long obytes;
132 	u_long ibytes;
133 	u_long oerrors;
134 	u_long ierrors;
135 	u_long collisions;
136 	short timer;
137 	int drops;
138 	struct sockaddr *sa = NULL;
139 	char name[IFNAMSIZ];
140 	short network_layer;
141 	short link_layer;
142 
143 	if (ifnetaddr == 0) {
144 		printf("ifnet: symbol not defined\n");
145 		return;
146 	}
147 	if (interval1) {
148 		sidewaysintpr((unsigned)interval1, ifnetaddr);
149 		return;
150 	}
151 	if (kread(ifnetaddr, (char *)&ifnethead, sizeof ifnethead))
152 		return;
153 	ifnetaddr = (u_long)TAILQ_FIRST(&ifnethead);
154 	if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
155 		return;
156 
157 	if (!pfunc) {
158 		printf("%-7.7s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
159 		       "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
160 		if (bflag)
161 			printf(" %10.10s","Ibytes");
162 		printf(" %8.8s %5.5s", "Opkts", "Oerrs");
163 		if (bflag)
164 			printf(" %10.10s","Obytes");
165 		printf(" %5s", "Coll");
166 		if (tflag)
167 			printf(" %s", "Time");
168 		if (dflag)
169 			printf(" %s", "Drop");
170 		putchar('\n');
171 	}
172 	ifaddraddr = 0;
173 	while (ifnetaddr || ifaddraddr) {
174 		struct sockaddr_in *sin;
175 #ifdef INET6
176 		struct sockaddr_in6 *sin6;
177 #endif
178 		char *cp;
179 		int n, m;
180 
181 		network_layer = 0;
182 		link_layer = 0;
183 
184 		if (ifaddraddr == 0) {
185 			struct ifaddrhead head;
186 
187 			ifnetfound = ifnetaddr;
188 			if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet))
189 				return;
190 			strlcpy(name, ifnet.if_xname, sizeof(name));
191 			ifnetaddr = (u_long)TAILQ_NEXT(&ifnet, if_link);
192 			if (interface != 0 && (strcmp(name, interface) != 0))
193 				continue;
194 			cp = strchr(name, '\0');
195 
196 			if (pfunc) {
197 				(*pfunc)(name);
198 				continue;
199 			}
200 
201 			if ((ifnet.if_flags&IFF_UP) == 0)
202 				*cp++ = '*';
203 			*cp = '\0';
204 
205 			if (kread((u_long)ifnet.if_addrheads,
206 				  (char *)&head, sizeof(head)))
207 				return;
208 
209 			ifaddrcont_addr =
210 				(u_long)TAILQ_FIRST(&head);
211 			if (ifaddrcont_addr == 0) {
212 				ifaddraddr = 0;
213 			} else {
214 				if (kread(ifaddrcont_addr, (char *)&ifac,
215 					  sizeof(ifac)))
216 					return;
217 				ifaddraddr = (u_long)ifac.ifa;
218 			}
219 		}
220 		ifaddrfound = ifaddraddr;
221 
222 		/*
223 		 * Get the interface stats.  These may get
224 		 * overriden below on a per-interface basis.
225 		 */
226 		opackets = ifnet.if_opackets;
227 		ipackets = ifnet.if_ipackets;
228 		obytes = ifnet.if_obytes;
229 		ibytes = ifnet.if_ibytes;
230 		oerrors = ifnet.if_oerrors;
231 		ierrors = ifnet.if_ierrors;
232 		collisions = ifnet.if_collisions;
233 		timer = ifnet.if_timer;
234 		drops = ifnet.if_snd.ifq_drops;
235 
236 		if (ifaddraddr == 0) {
237 			printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
238 			printf("%-13.13s ", "none");
239 			printf("%-15.15s ", "none");
240 		} else {
241 			if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) {
242 				ifaddraddr = 0;
243 				continue;
244 			}
245 #define CP(x) ((char *)(x))
246 			cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) +
247 				CP(&ifaddr);
248 			sa = (struct sockaddr *)cp;
249 			if (af != AF_UNSPEC && sa->sa_family != af) {
250 				ifaddrcont_addr =
251 					(u_long)TAILQ_NEXT(&ifac, ifa_link);
252 				if (ifaddrcont_addr == 0) {
253 					ifaddraddr = 0;
254 				} else {
255 					if (kread(ifaddrcont_addr,
256 					    (char *)&ifac, sizeof(ifac))) {
257 						ifaddraddr = 0;
258 						continue;
259 					}
260 					ifaddraddr = (u_long)ifac.ifa;
261 				}
262 				continue;
263 			}
264 			printf("%-7.7s %-5lu ", name, ifnet.if_mtu);
265 			switch (sa->sa_family) {
266 			case AF_UNSPEC:
267 				printf("%-13.13s ", "none");
268 				printf("%-15.15s ", "none");
269 				break;
270 			case AF_INET:
271 				sin = (struct sockaddr_in *)sa;
272 #ifdef notdef
273 				/* can't use inet_makeaddr because kernel
274 				 * keeps nets unshifted.
275 				 */
276 				in = inet_makeaddr(ifaddr.in.ia_subnet,
277 					INADDR_ANY);
278 				printf("%-13.13s ", netname(in.s_addr,
279 				    ifaddr.in.ia_subnetmask));
280 #else
281 				printf("%-13.13s ",
282 				    netname(htonl(ifaddr.in.ia_subnet),
283 				    ifaddr.in.ia_subnetmask));
284 #endif
285 				printf("%-15.15s ",
286 				    routename(sin->sin_addr.s_addr));
287 
288 				network_layer = 1;
289 				break;
290 #ifdef INET6
291 			case AF_INET6:
292 				sin6 = (struct sockaddr_in6 *)sa;
293 				printf("%-11.11s ",
294 				       netname6(&ifaddr.in6.ia_addr,
295 						&ifaddr.in6.ia_prefixmask.sin6_addr));
296 				printf("%-17.17s ",
297 				    inet_ntop(AF_INET6,
298 					&sin6->sin6_addr,
299 					ntop_buf, sizeof(ntop_buf)));
300 
301 				network_layer = 1;
302 				break;
303 #endif /*INET6*/
304 			case AF_IPX:
305 				{
306 				struct sockaddr_ipx *sipx =
307 					(struct sockaddr_ipx *)sa;
308 				u_long net;
309 				char netnum[10];
310 
311 				*(union ipx_net *) &net = sipx->sipx_addr.x_net;
312 				sprintf(netnum, "%lx", (u_long)ntohl(net));
313 				printf("ipx:%-8s  ", netnum);
314 /*				printf("ipx:%-8s ", netname(net, 0L)); */
315 				printf("%-15s ",
316 				    ipx_phost((struct sockaddr *)sipx));
317 				}
318 				break;
319 
320 			case AF_APPLETALK:
321 				printf("atalk:%-12.12s ",atalk_print(sa,0x10) );
322 				printf("%-9.9s  ",atalk_print(sa,0x0b) );
323 				break;
324 #ifdef NS
325 			case AF_NS:
326 				{
327 				struct sockaddr_ns *sns =
328 					(struct sockaddr_ns *)sa;
329 				u_long net;
330 				char netnum[10];
331 
332 				*(union ns_net *) &net = sns->sns_addr.x_net;
333 				sprintf(netnum, "%lxH", ntohl(net));
334 				upHex(netnum);
335 				printf("ns:%-8s ", netnum);
336 				printf("%-15s ",
337 				    ns_phost((struct sockaddr *)sns));
338 				}
339 				break;
340 #endif
341 			case AF_LINK:
342 				{
343 				struct sockaddr_dl *sdl =
344 					(struct sockaddr_dl *)sa;
345 				char linknum[10];
346 				cp = (char *)LLADDR(sdl);
347 				n = sdl->sdl_alen;
348 				sprintf(linknum, "<Link#%d>", sdl->sdl_index);
349 				m = printf("%-11.11s ", linknum);
350 				}
351 				goto hexprint;
352 			default:
353 				m = printf("(%d)", sa->sa_family);
354 				for (cp = sa->sa_len + (char *)sa;
355 					--cp > sa->sa_data && (*cp == 0);) {}
356 				n = cp - sa->sa_data + 1;
357 				cp = sa->sa_data;
358 			hexprint:
359 				while (--n >= 0)
360 					m += printf("%02x%c", *cp++ & 0xff,
361 						    n > 0 ? ':' : ' ');
362 				m = 30 - m;
363 				while (m-- > 0)
364 					putchar(' ');
365 
366 				link_layer = 1;
367 				break;
368 			}
369 
370 			/*
371 			 * Fixup the statistics for interfaces that
372 			 * update stats for their network addresses
373 			 */
374 			if (network_layer) {
375 				opackets = ifaddr.in.ia_ifa.if_opackets;
376 				ipackets = ifaddr.in.ia_ifa.if_ipackets;
377 				obytes = ifaddr.in.ia_ifa.if_obytes;
378 				ibytes = ifaddr.in.ia_ifa.if_ibytes;
379 			}
380 
381 			ifaddrcont_addr =
382 				(u_long)TAILQ_NEXT(&ifac, ifa_link);
383 			if (ifaddrcont_addr == 0) {
384 				ifaddraddr = 0;
385 			} else {
386 				if (kread(ifaddrcont_addr,
387 				    (char *)&ifac, sizeof(ifac))) {
388 					ifaddraddr = 0;
389 				} else {
390 					ifaddraddr = (u_long)ifac.ifa;
391 				}
392 			}
393 		}
394 
395 		show_stat("lu", 8, ipackets, link_layer|network_layer);
396 		printf(" ");
397 		show_stat("lu", 5, ierrors, link_layer);
398 		printf(" ");
399 		if (bflag) {
400 			show_stat("lu", 10, ibytes, link_layer|network_layer);
401 			printf(" ");
402 		}
403 		show_stat("lu", 8, opackets, link_layer|network_layer);
404 		printf(" ");
405 		show_stat("lu", 5, oerrors, link_layer);
406 		printf(" ");
407 		if (bflag) {
408 			show_stat("lu", 10, obytes, link_layer|network_layer);
409 			printf(" ");
410 		}
411 		show_stat("lu", 5, collisions, link_layer);
412 		if (tflag) {
413 			printf(" ");
414 			show_stat("d", 3, timer, link_layer);
415 		}
416 		if (dflag) {
417 			printf(" ");
418 			show_stat("d", 3, drops, link_layer);
419 		}
420 		putchar('\n');
421 		if (aflag && ifaddrfound) {
422 			/*
423 			 * Print family's multicast addresses
424 			 */
425 			struct ifmultiaddr *multiaddr;
426 			struct ifmultiaddr ifma;
427 			union {
428 				struct sockaddr sa;
429 				struct sockaddr_in in;
430 #ifdef INET6
431 				struct sockaddr_in6 in6;
432 #endif /* INET6 */
433 				struct sockaddr_dl dl;
434 			} msa;
435 			const char *fmt;
436 
437 			TAILQ_FOREACH(multiaddr, &ifnet.if_multiaddrs, ifma_link) {
438 				if (kread((u_long)multiaddr, (char *)&ifma,
439 					  sizeof ifma))
440 					break;
441 				multiaddr = &ifma;
442 				if (kread((u_long)ifma.ifma_addr, (char *)&msa,
443 					  sizeof msa))
444 					break;
445 				if (msa.sa.sa_family != sa->sa_family)
446 					continue;
447 
448 				fmt = 0;
449 				switch (msa.sa.sa_family) {
450 				case AF_INET:
451 					fmt = routename(msa.in.sin_addr.s_addr);
452 					break;
453 #ifdef INET6
454 				case AF_INET6:
455 					printf("%23s %-19.19s(refs: %d)\n", "",
456 					       inet_ntop(AF_INET6,
457 							 &msa.in6.sin6_addr,
458 							 ntop_buf,
459 							 sizeof(ntop_buf)),
460 					       ifma.ifma_refcount);
461 					break;
462 #endif /* INET6 */
463 				case AF_LINK:
464 					switch (msa.dl.sdl_type) {
465 					case IFT_ETHER:
466 					case IFT_FDDI:
467 						fmt = ether_ntoa(
468 							(struct ether_addr *)
469 							LLADDR(&msa.dl));
470 						break;
471 					}
472 					break;
473 				}
474 				if (fmt)
475 					printf("%23s %s\n", "", fmt);
476 			}
477 		}
478 	}
479 }
480 
481 struct	iftot {
482 	SLIST_ENTRY(iftot) chain;
483 	char	ift_name[IFNAMSIZ];	/* interface name */
484 	u_long	ift_ip;			/* input packets */
485 	u_long	ift_ie;			/* input errors */
486 	u_long	ift_op;			/* output packets */
487 	u_long	ift_oe;			/* output errors */
488 	u_long	ift_co;			/* collisions */
489 	u_int	ift_dr;			/* drops */
490 	u_long	ift_ib;			/* input bytes */
491 	u_long	ift_ob;			/* output bytes */
492 };
493 
494 u_char	signalled;			/* set if alarm goes off "early" */
495 
496 /*
497  * Print a running summary of interface statistics.
498  * Repeat display every interval1 seconds, showing statistics
499  * collected over that interval.  Assumes that interval1 is non-zero.
500  * First line printed at top of screen is always cumulative.
501  * XXX - should be rewritten to use ifmib(4).
502  */
503 static void
504 sidewaysintpr(unsigned interval1, u_long off)
505 {
506 	struct ifnet ifnet;
507 	u_long firstifnet;
508 	struct ifnethead ifnethead;
509 	struct iftot *iftot, *ip, *ipn, *total, *sum, *interesting;
510 	int line;
511 	int oldmask, first;
512 	u_long interesting_off;
513 
514 	if (kread(off, (char *)&ifnethead, sizeof ifnethead))
515 		return;
516 	firstifnet = (u_long)TAILQ_FIRST(&ifnethead);
517 
518 	if ((iftot = malloc(sizeof(struct iftot))) == NULL) {
519 		printf("malloc failed\n");
520 		exit(1);
521 	}
522 	memset(iftot, 0, sizeof(struct iftot));
523 
524 	interesting = NULL;
525 	interesting_off = 0;
526 	for (off = firstifnet, ip = iftot; off;) {
527 		char name[IFNAMSIZ];
528 
529 		if (kread(off, (char *)&ifnet, sizeof ifnet))
530 			break;
531 		strlcpy(name, ifnet.if_xname, sizeof(name));
532 		if (interface && strcmp(name, interface) == 0) {
533 			interesting = ip;
534 			interesting_off = off;
535 		}
536 		snprintf(ip->ift_name, 16, "(%s)", name);
537 		if ((ipn = malloc(sizeof(struct iftot))) == NULL) {
538 			printf("malloc failed\n");
539 			exit(1);
540 		}
541 		memset(ipn, 0, sizeof(struct iftot));
542 		SLIST_NEXT(ip, chain) = ipn;
543 		ip = ipn;
544 		off = (u_long)TAILQ_NEXT(&ifnet, if_link);
545 	}
546 	if ((total = malloc(sizeof(struct iftot))) == NULL) {
547 		printf("malloc failed\n");
548 		exit(1);
549 	}
550 	memset(total, 0, sizeof(struct iftot));
551 	if ((sum = malloc(sizeof(struct iftot))) == NULL) {
552 		printf("malloc failed\n");
553 		exit(1);
554 	}
555 	memset(sum, 0, sizeof(struct iftot));
556 
557 
558 	(void)signal(SIGALRM, catchalarm);
559 	signalled = NO;
560 	(void)alarm(interval1);
561 	first = 1;
562 banner:
563 	printf("%17s %14s %16s", "input",
564 	    interesting ? interesting->ift_name : "(Total)", "output");
565 	putchar('\n');
566 	printf("%10s %5s %10s %10s %5s %10s %5s",
567 	    "packets", "errs", "bytes", "packets", "errs", "bytes", "colls");
568 	if (dflag)
569 		printf(" %5.5s", "drops");
570 	putchar('\n');
571 	fflush(stdout);
572 	line = 0;
573 loop:
574 	if (interesting != NULL) {
575 		ip = interesting;
576 		if (kread(interesting_off, (char *)&ifnet, sizeof ifnet)) {
577 			printf("???\n");
578 			exit(1);
579 		};
580 		if (!first) {
581 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
582 				ifnet.if_ipackets - ip->ift_ip,
583 				ifnet.if_ierrors - ip->ift_ie,
584 				ifnet.if_ibytes - ip->ift_ib,
585 				ifnet.if_opackets - ip->ift_op,
586 				ifnet.if_oerrors - ip->ift_oe,
587 				ifnet.if_obytes - ip->ift_ob,
588 				ifnet.if_collisions - ip->ift_co);
589 			if (dflag)
590 				printf(" %5u", ifnet.if_snd.ifq_drops - ip->ift_dr);
591 		}
592 		ip->ift_ip = ifnet.if_ipackets;
593 		ip->ift_ie = ifnet.if_ierrors;
594 		ip->ift_ib = ifnet.if_ibytes;
595 		ip->ift_op = ifnet.if_opackets;
596 		ip->ift_oe = ifnet.if_oerrors;
597 		ip->ift_ob = ifnet.if_obytes;
598 		ip->ift_co = ifnet.if_collisions;
599 		ip->ift_dr = ifnet.if_snd.ifq_drops;
600 	} else {
601 		sum->ift_ip = 0;
602 		sum->ift_ie = 0;
603 		sum->ift_ib = 0;
604 		sum->ift_op = 0;
605 		sum->ift_oe = 0;
606 		sum->ift_ob = 0;
607 		sum->ift_co = 0;
608 		sum->ift_dr = 0;
609 		for (off = firstifnet, ip = iftot;
610 		     off && SLIST_NEXT(ip, chain) != NULL;
611 		     ip = SLIST_NEXT(ip, chain)) {
612 			if (kread(off, (char *)&ifnet, sizeof ifnet)) {
613 				off = 0;
614 				continue;
615 			}
616 			sum->ift_ip += ifnet.if_ipackets;
617 			sum->ift_ie += ifnet.if_ierrors;
618 			sum->ift_ib += ifnet.if_ibytes;
619 			sum->ift_op += ifnet.if_opackets;
620 			sum->ift_oe += ifnet.if_oerrors;
621 			sum->ift_ob += ifnet.if_obytes;
622 			sum->ift_co += ifnet.if_collisions;
623 			sum->ift_dr += ifnet.if_snd.ifq_drops;
624 			off = (u_long)TAILQ_NEXT(&ifnet, if_link);
625 		}
626 		if (!first) {
627 			printf("%10lu %5lu %10lu %10lu %5lu %10lu %5lu",
628 				sum->ift_ip - total->ift_ip,
629 				sum->ift_ie - total->ift_ie,
630 				sum->ift_ib - total->ift_ib,
631 				sum->ift_op - total->ift_op,
632 				sum->ift_oe - total->ift_oe,
633 				sum->ift_ob - total->ift_ob,
634 				sum->ift_co - total->ift_co);
635 			if (dflag)
636 				printf(" %5u", sum->ift_dr - total->ift_dr);
637 		}
638 		*total = *sum;
639 	}
640 	if (!first)
641 		putchar('\n');
642 	fflush(stdout);
643 	oldmask = sigblock(sigmask(SIGALRM));
644 	if (! signalled) {
645 		sigpause(0);
646 	}
647 	sigsetmask(oldmask);
648 	signalled = NO;
649 	(void)alarm(interval1);
650 	line++;
651 	first = 0;
652 	if (line == 21)
653 		goto banner;
654 	else
655 		goto loop;
656 	/*NOTREACHED*/
657 }
658 
659 /*
660  * Called if an interval expires before sidewaysintpr has completed a loop.
661  * Sets a flag to not wait for the alarm.
662  */
663 static void
664 catchalarm(int signo __unused)
665 {
666 	signalled = YES;
667 }
668