if.c revision 1.90
1/* $NetBSD: if.c,v 1.90 2016/11/24 00:05:13 dholland Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "from: @(#)if.c 8.2 (Berkeley) 2/21/94"; 36#else 37__RCSID("$NetBSD: if.c,v 1.90 2016/11/24 00:05:13 dholland Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <sys/param.h> 42#include <sys/types.h> 43#include <sys/protosw.h> 44#include <sys/socket.h> 45#include <sys/time.h> 46#include <sys/sysctl.h> 47#include <sys/ioctl.h> 48 49#include <net/if.h> 50#include <net/if_dl.h> 51#include <net/if_types.h> 52#include <net/route.h> 53#include <netinet/in.h> 54#include <netinet/in_var.h> 55#include <arpa/inet.h> 56 57#include <kvm.h> 58#include <signal.h> 59#include <stdio.h> 60#include <stdlib.h> 61#include <string.h> 62#include <unistd.h> 63#include <netdb.h> 64#include <err.h> 65 66#include "netstat.h" 67#include "rtutil.h" 68#include "prog_ops.h" 69 70#define MAXIF 100 71 72#define HUMBUF_SIZE 7 73 74struct iftot { 75 char ift_name[IFNAMSIZ]; /* interface name */ 76 u_quad_t ift_ip; /* input packets */ 77 u_quad_t ift_ib; /* input bytes */ 78 u_quad_t ift_ie; /* input errors */ 79 u_quad_t ift_op; /* output packets */ 80 u_quad_t ift_ob; /* output bytes */ 81 u_quad_t ift_oe; /* output errors */ 82 u_quad_t ift_co; /* collisions */ 83 u_quad_t ift_dr; /* drops */ 84}; 85 86static void set_lines(void); 87static void print_addr(const char *, struct sockaddr *, struct sockaddr **, 88 struct if_data *, struct ifnet *); 89static void sidewaysintpr(u_int, u_long); 90 91static void iftot_banner(struct iftot *); 92static void iftot_print_sum(struct iftot *, struct iftot *); 93static void iftot_print(struct iftot *, struct iftot *); 94 95static void catchalarm(int); 96static void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); 97static void fetchifs(void); 98 99static void intpr_sysctl(void); 100static void intpr_kvm(u_long, void (*)(const char *)); 101 102struct iftot iftot[MAXIF], ip_cur, ip_old, sum_cur, sum_old; 103static sig_atomic_t signalled; /* set when alarm goes off */ 104 105static unsigned redraw_lines = 21; 106 107static void 108set_lines(void) 109{ 110 static bool first = true; 111 struct ttysize ts; 112 113 if (!first) 114 return; 115 first = false; 116 if (ioctl(STDOUT_FILENO, TIOCGSIZE, &ts) != -1 && ts.ts_lines) 117 redraw_lines = ts.ts_lines - 3; 118} 119 120 121/* 122 * Print a description of the network interfaces. 123 * NOTE: ifnetaddr is the location of the kernel global "ifnet", 124 * which is a TAILQ_HEAD. 125 */ 126void 127intpr(int interval, u_long ifnetaddr, void (*pfunc)(const char *)) 128{ 129 130 if (interval) { 131 sidewaysintpr((unsigned)interval, ifnetaddr); 132 return; 133 } 134 135 if (use_sysctl) { 136 intpr_sysctl(); 137 } else { 138 intpr_kvm(ifnetaddr, pfunc); 139 } 140 141} 142 143static void 144intpr_header(void) 145{ 146 147 if (!sflag && !pflag) { 148 if (bflag) { 149 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 150 "%10.10s %10.10s", 151 "Name", "Mtu", "Network", "Address", 152 "Ibytes", "Obytes"); 153 } else { 154 printf("%-5.5s %-5.5s %-13.13s %-17.17s " 155 "%8.8s %5.5s %8.8s %5.5s %5.5s", 156 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs", 157 "Opkts", "Oerrs", "Colls"); 158 } 159 if (tflag) 160 printf(" %4.4s", "Time"); 161 if (dflag) 162 printf(" %5.5s", "Drops"); 163 putchar('\n'); 164 } 165} 166 167static void 168intpr_sysctl(void) 169{ 170 struct if_msghdr *ifm; 171 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 172 char *buf = NULL, *next, *lim, *cp; 173 struct rt_msghdr *rtm; 174 struct ifa_msghdr *ifam; 175 struct if_data *ifd = NULL; 176 struct sockaddr *sa, *rti_info[RTAX_MAX]; 177 struct sockaddr_dl *sdl; 178 uint64_t total = 0; 179 size_t len; 180 int did = 1, rtax = 0, n; 181 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 182 183 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 184 err(1, "sysctl"); 185 if ((buf = malloc(len)) == NULL) 186 err(1, NULL); 187 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 188 err(1, "sysctl"); 189 190 intpr_header(); 191 192 lim = buf + len; 193 for (next = buf; next < lim; next += rtm->rtm_msglen) { 194 rtm = (struct rt_msghdr *)next; 195 if (rtm->rtm_version != RTM_VERSION) 196 continue; 197 switch (rtm->rtm_type) { 198 case RTM_IFINFO: 199 total = 0; 200 ifm = (struct if_msghdr *)next; 201 ifd = &ifm->ifm_data; 202 203 sa = (struct sockaddr *)(ifm + 1); 204 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 205 206 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 207 if (sdl == NULL || sdl->sdl_family != AF_LINK) { 208 continue; 209 } 210 bzero(name, sizeof(name)); 211 if (sdl->sdl_nlen >= IFNAMSIZ) 212 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 213 else if (sdl->sdl_nlen > 0) 214 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 215 216 if (interface != 0 && strcmp(name, interface) != 0) 217 continue; 218 219 /* mark inactive interfaces with a '*' */ 220 cp = strchr(name, '\0'); 221 if ((ifm->ifm_flags & IFF_UP) == 0) 222 *cp++ = '*'; 223 *cp = '\0'; 224 225 if (qflag) { 226 total = ifd->ifi_ibytes + ifd->ifi_obytes + 227 ifd->ifi_ipackets + ifd->ifi_ierrors + 228 ifd->ifi_opackets + ifd->ifi_oerrors + 229 ifd->ifi_collisions; 230 if (dflag) 231 total += ifd->ifi_iqdrops; 232 if (total == 0) 233 continue; 234 } 235 /* Skip the first one */ 236 if (did) { 237 did = 0; 238 continue; 239 } 240 rtax = RTAX_IFP; 241 break; 242 case RTM_NEWADDR: 243 if (qflag && total == 0) 244 continue; 245 if (interface != 0 && strcmp(name, interface) != 0) 246 continue; 247 ifam = (struct ifa_msghdr *)next; 248 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 249 RTA_BRD)) == 0) 250 break; 251 252 sa = (struct sockaddr *)(ifam + 1); 253 254 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 255 rtax = RTAX_IFA; 256 did = 1; 257 break; 258 default: 259 continue; 260 } 261 if (vflag) 262 n = strlen(name) < 5 ? 5 : strlen(name); 263 else 264 n = 5; 265 266 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 267 print_addr(name, rti_info[rtax], rti_info, ifd, NULL); 268 } 269} 270 271union ifaddr_u { 272 struct ifaddr ifa; 273 struct in_ifaddr in; 274#ifdef INET6 275 struct in6_ifaddr in6; 276#endif /* INET6 */ 277}; 278 279static void 280intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 281{ 282 struct ifnet ifnet; 283 union ifaddr_u ifaddr; 284 u_long ifaddraddr; 285 struct ifnet_head ifhead; /* TAILQ_HEAD */ 286 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 287 288 if (ifnetaddr == 0) { 289 printf("ifnet: symbol not defined\n"); 290 return; 291 } 292 293 /* 294 * Find the pointer to the first ifnet structure. Replace 295 * the pointer to the TAILQ_HEAD with the actual pointer 296 * to the first list element. 297 */ 298 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 299 return; 300 ifnetaddr = (u_long)ifhead.tqh_first; 301 302 intpr_header(); 303 304 ifaddraddr = 0; 305 while (ifnetaddr || ifaddraddr) { 306 char *cp; 307 int n; 308 309 if (ifaddraddr == 0) { 310 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 311 return; 312 memmove(name, ifnet.if_xname, IFNAMSIZ); 313 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 314 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 315 if (interface != 0 && strcmp(name, interface) != 0) 316 continue; 317 cp = strchr(name, '\0'); 318 319 if (pfunc) { 320 (*pfunc)(name); 321 continue; 322 } 323 324 if ((ifnet.if_flags & IFF_UP) == 0) 325 *cp++ = '*'; 326 *cp = '\0'; 327 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 328 } 329 if (vflag) 330 n = strlen(name) < 5 ? 5 : strlen(name); 331 else 332 n = 5; 333 printf("%-*.*s %-5llu ", n, n, name, 334 (unsigned long long)ifnet.if_mtu); 335 if (ifaddraddr == 0) { 336 printf("%-13.13s ", "none"); 337 printf("%-17.17s ", "none"); 338 } else { 339 struct sockaddr *sa; 340 341 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 342 ifaddraddr = 0; 343 continue; 344 } 345#define CP(x) ((char *)(x)) 346 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 347 CP(&ifaddr); 348 sa = (struct sockaddr *)cp; 349 print_addr(name, sa, (void *)&ifaddr, &ifnet.if_data, 350 &ifnet); 351 } 352 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 353 } 354 355} 356 357static void 358mc_print(const char *ifname, const size_t ias, const char *oid, int *mcast_oids, 359 void (*pr)(const void *)) 360{ 361 uint8_t *mcast_addrs, *p; 362 const size_t incr = 2 * ias + sizeof(uint32_t); 363 size_t len; 364 int ifindex; 365 366 if ((ifindex = if_nametoindex(ifname)) == 0) 367 warn("Interface %s not found", ifname); 368 369 if (mcast_oids[0] == 0) { 370 size_t oidlen = 4; 371 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 372 warnx("'%s' not found", oid); 373 return; 374 } 375 if (oidlen != 3) { 376 warnx("Wrong OID path for '%s'", oid); 377 return; 378 } 379 } 380 381 if (mcast_oids[3] == ifindex) 382 return; 383 mcast_oids[3] = ifindex; 384 385 mcast_addrs = asysctl(mcast_oids, 4, &len); 386 if (mcast_addrs == NULL && len != 0) { 387 warn("failed to read '%s'", oid); 388 return; 389 } 390 if (len) { 391 p = mcast_addrs; 392 while (len >= incr) { 393 (*pr)((p + ias)); 394 p += incr; 395 len -= incr; 396 } 397 } 398 free(mcast_addrs); 399} 400 401#ifdef INET6 402static void 403ia6_print(const struct in6_addr *ia) 404{ 405 struct sockaddr_in6 as6; 406 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 407 int n; 408 409 memset(&as6, 0, sizeof(as6)); 410 as6.sin6_len = sizeof(struct sockaddr_in6); 411 as6.sin6_family = AF_INET6; 412 as6.sin6_addr = *ia; 413 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 414 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 415 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 416 strlcpy(hbuf, "??", sizeof(hbuf)); 417 } 418 if (vflag) 419 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 420 else 421 n = 17; 422 printf("\n%25s %-*.*s ", "", n, n, hbuf); 423} 424 425static void 426mc6_print(const char *ifname) 427{ 428 static int mcast_oids[4]; 429 430 mc_print(ifname, sizeof(struct in6_addr), "net.inet6.multicast", 431 mcast_oids, (void (*)(const void *))ia6_print); 432} 433#endif 434 435static void 436ia4_print(const struct in_addr *ia) 437{ 438 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 439} 440 441static void 442mc4_print(const char *ifname) 443{ 444 static int mcast_oids[4]; 445 446 mc_print(ifname, sizeof(struct in_addr), "net.inet.multicast", 447 mcast_oids, (void (*)(const void *))ia4_print); 448} 449 450static void 451print_addr(const char *name, struct sockaddr *sa, struct sockaddr **rtinfo, 452 struct if_data *ifd, struct ifnet *ifnet) 453{ 454 char hexsep = '.'; /* for hexprint */ 455 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 456 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 457#ifdef INET6 458 const int niflag = NI_NUMERICHOST; 459 struct sockaddr_in6 *sin6, *netmask6; 460#endif 461 struct sockaddr_in netmask; 462 struct sockaddr_in *sin; 463 char *cp; 464 int n, m; 465 466 switch (sa->sa_family) { 467 case AF_UNSPEC: 468 printf("%-13.13s ", "none"); 469 printf("%-17.17s ", "none"); 470 break; 471 case AF_INET: 472 sin = (struct sockaddr_in *)sa; 473 if (use_sysctl) { 474 netmask = *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 475 } else { 476 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 477 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 478 } 479 cp = netname4(sin, &netmask, nflag); 480 if (vflag) 481 n = strlen(cp) < 13 ? 13 : strlen(cp); 482 else 483 n = 13; 484 printf("%-*.*s ", n, n, cp); 485 cp = routename4(sin->sin_addr.s_addr, nflag); 486 if (vflag) 487 n = strlen(cp) < 17 ? 17 : strlen(cp); 488 else 489 n = 17; 490 printf("%-*.*s ", n, n, cp); 491 492 if (!aflag) 493 break; 494 if (ifnet) { 495 u_long multiaddr; 496 struct in_multi inm; 497 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 498 499 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 500 while (multiaddr != 0) { 501 kread(multiaddr, (char *)&inm, sizeof inm); 502 ia4_print(&inm.inm_addr); 503 multiaddr = (u_long)inm.inm_list.le_next; 504 } 505 } else { 506 mc4_print(name); 507 } 508 break; 509#ifdef INET6 510 case AF_INET6: 511 sin6 = (struct sockaddr_in6 *)sa; 512 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 513#ifdef __KAME__ 514 if (!vflag) 515 sin6->sin6_scope_id = 0; 516#endif 517 518 if (use_sysctl) { 519 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 520 } else { 521 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 522 netmask6 = &ifaddr_in6->ia_prefixmask; 523 } 524 525 cp = netname6(sin6, netmask6, nflag); 526 if (vflag) 527 n = strlen(cp) < 13 ? 13 : strlen(cp); 528 else 529 n = 13; 530 printf("%-*.*s ", n, n, cp); 531 if (getnameinfo((struct sockaddr *)sin6, 532 sin6->sin6_len, 533 hbuf, sizeof(hbuf), NULL, 0, 534 niflag) != 0) { 535 strlcpy(hbuf, "?", sizeof(hbuf)); 536 } 537 cp = hbuf; 538 if (vflag) 539 n = strlen(cp) < 17 ? 17 : strlen(cp); 540 else 541 n = 17; 542 printf("%-*.*s ", n, n, cp); 543 544 if (!aflag) 545 break; 546 if (ifnet) { 547 u_long multiaddr; 548 struct in6_multi inm; 549 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 550 551 multiaddr = (u_long)ifaddr->in6.ia6_multiaddrs.lh_first; 552 while (multiaddr != 0) { 553 kread(multiaddr, (char *)&inm, sizeof inm); 554 ia6_print(&inm.in6m_addr); 555 multiaddr = (u_long)inm.in6m_entry.le_next; 556 } 557 } else { 558 mc6_print(name); 559 } 560 break; 561#endif /*INET6*/ 562#ifndef SMALL 563 case AF_APPLETALK: 564 printf("atalk:%-7.7s ", 565 atalk_print(sa,0x10)); 566 printf("%-17.17s ", atalk_print(sa,0x0b)); 567 break; 568#endif 569 case AF_LINK: 570 printf("%-13.13s ", "<Link>"); 571 if (getnameinfo(sa, sa->sa_len, 572 hbuf, sizeof(hbuf), NULL, 0, 573 NI_NUMERICHOST) != 0) { 574 strlcpy(hbuf, "?", sizeof(hbuf)); 575 } 576 cp = hbuf; 577 if (vflag) 578 n = strlen(cp) < 17 ? 17 : strlen(cp); 579 else 580 n = 17; 581 printf("%-*.*s ", n, n, cp); 582 break; 583 584 default: 585 m = printf("(%d)", sa->sa_family); 586 for (cp = sa->sa_len + (char *)sa; 587 --cp > sa->sa_data && (*cp == 0);) {} 588 n = cp - sa->sa_data + 1; 589 cp = sa->sa_data; 590 591 while (--n >= 0) 592 m += printf(hexfmt, *cp++ & 0xff, 593 n > 0 ? hexsep : ' '); 594 m = 32 - m; 595 while (m-- > 0) 596 putchar(' '); 597 break; 598 } 599 600 if (bflag) { 601 char humbuf[HUMBUF_SIZE]; 602 603 if (hflag && humanize_number(humbuf, sizeof(humbuf), 604 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 605 printf("%10s ", humbuf); 606 else 607 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 608 609 if (hflag && humanize_number(humbuf, sizeof(humbuf), 610 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 611 printf("%10s", humbuf); 612 else 613 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 614 } else { 615 printf("%8llu %5llu %8llu %5llu %5llu", 616 (unsigned long long)ifd->ifi_ipackets, 617 (unsigned long long)ifd->ifi_ierrors, 618 (unsigned long long)ifd->ifi_opackets, 619 (unsigned long long)ifd->ifi_oerrors, 620 (unsigned long long)ifd->ifi_collisions); 621 } 622 if (tflag) 623 printf(" %4d", ifnet ? ifnet->if_timer : 0); 624 if (dflag) 625 printf(" %5lld", ifnet ? 626 (unsigned long long)ifnet->if_snd.ifq_drops : 627 ifd->ifi_iqdrops); 628 putchar('\n'); 629} 630 631static void 632iftot_banner(struct iftot *ift) 633{ 634 if (bflag) 635 printf("%7.7s in %8.8s %6.6s out %5.5s", 636 ift->ift_name, " ", 637 ift->ift_name, " "); 638 else 639 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 640 ift->ift_name, " ", 641 ift->ift_name, " ", " "); 642 if (dflag) 643 printf(" %5.5s", " "); 644 645 if (bflag) 646 printf(" %7.7s in %8.8s %6.6s out %5.5s", 647 "total", " ", "total", " "); 648 else 649 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 650 "total", " ", "total", " ", " "); 651 if (dflag) 652 printf(" %5.5s", " "); 653 putchar('\n'); 654 if (bflag) 655 printf("%10.10s %8.8s %10.10s %5.5s", 656 "bytes", " ", "bytes", " "); 657 else 658 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 659 "packets", "errs", "packets", "errs", "colls"); 660 if (dflag) 661 printf(" %5.5s", "drops"); 662 663 if (bflag) 664 printf(" %10.10s %8.8s %10.10s %5.5s", 665 "bytes", " ", "bytes", " "); 666 else 667 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 668 "packets", "errs", "packets", "errs", "colls"); 669 if (dflag) 670 printf(" %5.5s", "drops"); 671 putchar('\n'); 672 fflush(stdout); 673} 674 675static void 676iftot_print(struct iftot *cur, struct iftot *old) 677{ 678 if (bflag) 679 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 680 cur->ift_ib - old->ift_ib, " ", 681 cur->ift_ob - old->ift_ob, " "); 682 else 683 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 684 cur->ift_ip - old->ift_ip, 685 cur->ift_ie - old->ift_ie, 686 cur->ift_op - old->ift_op, 687 cur->ift_oe - old->ift_oe, 688 cur->ift_co - old->ift_co); 689 if (dflag) 690 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 691} 692 693static void 694iftot_print_sum(struct iftot *cur, struct iftot *old) 695{ 696 if (bflag) 697 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 698 cur->ift_ib - old->ift_ib, " ", 699 cur->ift_ob - old->ift_ob, " "); 700 else 701 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 702 cur->ift_ip - old->ift_ip, 703 cur->ift_ie - old->ift_ie, 704 cur->ift_op - old->ift_op, 705 cur->ift_oe - old->ift_oe, 706 cur->ift_co - old->ift_co); 707 708 if (dflag) 709 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 710} 711 712__dead static void 713sidewaysintpr_sysctl(unsigned interval) 714{ 715 struct itimerval it; 716 sigset_t emptyset; 717 sigset_t noalrm; 718 unsigned line; 719 720 set_lines(); 721 722 fetchifs(); 723 if (ip_cur.ift_name[0] == '\0') { 724 fprintf(stderr, "%s: %s: unknown interface\n", 725 getprogname(), interface); 726 exit(1); 727 } 728 729 sigemptyset(&emptyset); 730 sigemptyset(&noalrm); 731 sigaddset(&noalrm, SIGALRM); 732 sigprocmask(SIG_SETMASK, &noalrm, NULL); 733 734 signalled = 0; 735 (void)signal(SIGALRM, catchalarm); 736 737 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 738 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 739 setitimer(ITIMER_REAL, &it, NULL); 740 741banner: 742 iftot_banner(&ip_cur); 743 744 line = 0; 745 bzero(&ip_old, sizeof(ip_old)); 746 bzero(&sum_old, sizeof(sum_old)); 747loop: 748 bzero(&sum_cur, sizeof(sum_cur)); 749 750 fetchifs(); 751 752 iftot_print(&ip_cur, &ip_old); 753 754 ip_old = ip_cur; 755 756 iftot_print_sum(&sum_cur, &sum_old); 757 758 sum_old = sum_cur; 759 760 putchar('\n'); 761 fflush(stdout); 762 line++; 763 if (signalled == 0) { 764 sigsuspend(&emptyset); 765 } 766 signalled = 0; 767 if (line == redraw_lines) 768 goto banner; 769 goto loop; 770 /*NOTREACHED*/ 771} 772 773static void 774sidewaysintpr_kvm(unsigned interval, u_long off) 775{ 776 struct itimerval it; 777 sigset_t emptyset; 778 sigset_t noalrm; 779 struct ifnet ifnet; 780 u_long firstifnet; 781 struct iftot *ip, *total; 782 unsigned line; 783 struct iftot *lastif, *sum, *interesting; 784 struct ifnet_head ifhead; /* TAILQ_HEAD */ 785 786 set_lines(); 787 788 /* 789 * Find the pointer to the first ifnet structure. Replace 790 * the pointer to the TAILQ_HEAD with the actual pointer 791 * to the first list element. 792 */ 793 if (kread(off, (char *)&ifhead, sizeof ifhead)) 794 return; 795 firstifnet = (u_long)ifhead.tqh_first; 796 797 lastif = iftot; 798 sum = iftot + MAXIF - 1; 799 total = sum - 1; 800 interesting = (interface == NULL) ? iftot : NULL; 801 for (off = firstifnet, ip = iftot; off;) { 802 if (kread(off, (char *)&ifnet, sizeof ifnet)) 803 break; 804 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 805 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 806 if (interface && strcmp(ifnet.if_xname, interface) == 0) 807 interesting = ip; 808 ip++; 809 if (ip >= iftot + MAXIF - 2) 810 break; 811 off = (u_long)ifnet.if_list.tqe_next; 812 } 813 if (interesting == NULL) { 814 fprintf(stderr, "%s: %s: unknown interface\n", 815 getprogname(), interface); 816 exit(1); 817 } 818 lastif = ip; 819 820 sigemptyset(&emptyset); 821 sigemptyset(&noalrm); 822 sigaddset(&noalrm, SIGALRM); 823 sigprocmask(SIG_SETMASK, &noalrm, NULL); 824 825 signalled = 0; 826 (void)signal(SIGALRM, catchalarm); 827 828 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 829 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 830 setitimer(ITIMER_REAL, &it, NULL); 831 832banner: 833 if (bflag) 834 printf("%7.7s in %8.8s %6.6s out %5.5s", 835 interesting->ift_name, " ", 836 interesting->ift_name, " "); 837 else 838 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 839 interesting->ift_name, " ", 840 interesting->ift_name, " ", " "); 841 if (dflag) 842 printf(" %5.5s", " "); 843 if (lastif - iftot > 0) { 844 if (bflag) 845 printf(" %7.7s in %8.8s %6.6s out %5.5s", 846 "total", " ", "total", " "); 847 else 848 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 849 "total", " ", "total", " ", " "); 850 if (dflag) 851 printf(" %5.5s", " "); 852 } 853 for (ip = iftot; ip < iftot + MAXIF; ip++) { 854 ip->ift_ip = 0; 855 ip->ift_ib = 0; 856 ip->ift_ie = 0; 857 ip->ift_op = 0; 858 ip->ift_ob = 0; 859 ip->ift_oe = 0; 860 ip->ift_co = 0; 861 ip->ift_dr = 0; 862 } 863 putchar('\n'); 864 if (bflag) 865 printf("%10.10s %8.8s %10.10s %5.5s", 866 "bytes", " ", "bytes", " "); 867 else 868 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 869 "packets", "errs", "packets", "errs", "colls"); 870 if (dflag) 871 printf(" %5.5s", "drops"); 872 if (lastif - iftot > 0) { 873 if (bflag) 874 printf(" %10.10s %8.8s %10.10s %5.5s", 875 "bytes", " ", "bytes", " "); 876 else 877 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 878 "packets", "errs", "packets", "errs", "colls"); 879 if (dflag) 880 printf(" %5.5s", "drops"); 881 } 882 putchar('\n'); 883 fflush(stdout); 884 line = 0; 885loop: 886 sum->ift_ip = 0; 887 sum->ift_ib = 0; 888 sum->ift_ie = 0; 889 sum->ift_op = 0; 890 sum->ift_ob = 0; 891 sum->ift_oe = 0; 892 sum->ift_co = 0; 893 sum->ift_dr = 0; 894 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 895 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 896 off = 0; 897 continue; 898 } 899 if (ip == interesting) { 900 if (bflag) { 901 char humbuf[HUMBUF_SIZE]; 902 903 if (hflag && humanize_number(humbuf, 904 sizeof(humbuf), 905 ifnet.if_ibytes - ip->ift_ib, "", 906 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 907 printf("%10s %8.8s ", humbuf, " "); 908 else 909 printf("%10llu %8.8s ", 910 (unsigned long long) 911 (ifnet.if_ibytes-ip->ift_ib), " "); 912 913 if (hflag && humanize_number(humbuf, 914 sizeof(humbuf), 915 ifnet.if_obytes - ip->ift_ob, "", 916 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 917 printf("%10s %5.5s", humbuf, " "); 918 else 919 printf("%10llu %5.5s", 920 (unsigned long long) 921 (ifnet.if_obytes-ip->ift_ob), " "); 922 } else { 923 printf("%8llu %5llu %8llu %5llu %5llu", 924 (unsigned long long) 925 (ifnet.if_ipackets - ip->ift_ip), 926 (unsigned long long) 927 (ifnet.if_ierrors - ip->ift_ie), 928 (unsigned long long) 929 (ifnet.if_opackets - ip->ift_op), 930 (unsigned long long) 931 (ifnet.if_oerrors - ip->ift_oe), 932 (unsigned long long) 933 (ifnet.if_collisions - ip->ift_co)); 934 } 935 if (dflag) 936 printf(" %5" PRIu64, 937 ifnet.if_snd.ifq_drops - ip->ift_dr); 938 } 939 ip->ift_ip = ifnet.if_ipackets; 940 ip->ift_ib = ifnet.if_ibytes; 941 ip->ift_ie = ifnet.if_ierrors; 942 ip->ift_op = ifnet.if_opackets; 943 ip->ift_ob = ifnet.if_obytes; 944 ip->ift_oe = ifnet.if_oerrors; 945 ip->ift_co = ifnet.if_collisions; 946 ip->ift_dr = ifnet.if_snd.ifq_drops; 947 sum->ift_ip += ip->ift_ip; 948 sum->ift_ib += ip->ift_ib; 949 sum->ift_ie += ip->ift_ie; 950 sum->ift_op += ip->ift_op; 951 sum->ift_ob += ip->ift_ob; 952 sum->ift_oe += ip->ift_oe; 953 sum->ift_co += ip->ift_co; 954 sum->ift_dr += ip->ift_dr; 955 off = (u_long)ifnet.if_list.tqe_next; 956 } 957 if (lastif - iftot > 0) { 958 if (bflag) { 959 char humbuf[HUMBUF_SIZE]; 960 961 if (hflag && humanize_number(humbuf, 962 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 963 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 964 printf(" %10s %8.8s ", humbuf, " "); 965 else 966 printf(" %10llu %8.8s ", 967 (unsigned long long) 968 (sum->ift_ib - total->ift_ib), " "); 969 970 if (hflag && humanize_number(humbuf, 971 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 972 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 973 printf("%10s %5.5s", humbuf, " "); 974 else 975 printf("%10llu %5.5s", 976 (unsigned long long) 977 (sum->ift_ob - total->ift_ob), " "); 978 } else { 979 printf(" %8llu %5llu %8llu %5llu %5llu", 980 (unsigned long long) 981 (sum->ift_ip - total->ift_ip), 982 (unsigned long long) 983 (sum->ift_ie - total->ift_ie), 984 (unsigned long long) 985 (sum->ift_op - total->ift_op), 986 (unsigned long long) 987 (sum->ift_oe - total->ift_oe), 988 (unsigned long long) 989 (sum->ift_co - total->ift_co)); 990 } 991 if (dflag) 992 printf(" %5llu", 993 (unsigned long long)(sum->ift_dr - total->ift_dr)); 994 } 995 *total = *sum; 996 putchar('\n'); 997 fflush(stdout); 998 line++; 999 if (signalled == 0) { 1000 sigsuspend(&emptyset); 1001 } 1002 signalled = 0; 1003 if (line == redraw_lines) 1004 goto banner; 1005 goto loop; 1006 /*NOTREACHED*/ 1007} 1008 1009/* 1010 * Print a running summary of interface statistics. 1011 * Repeat display every interval seconds, showing statistics 1012 * collected over that interval. Assumes that interval is non-zero. 1013 * First line printed at top of screen is always cumulative. 1014 */ 1015static void 1016sidewaysintpr(unsigned int interval, u_long off) 1017{ 1018 1019 if (use_sysctl) { 1020 sidewaysintpr_sysctl(interval); 1021 } else { 1022 sidewaysintpr_kvm(interval, off); 1023 } 1024} 1025 1026/* 1027 * Called if an interval expires before sidewaysintpr has completed a loop. 1028 * Sets a flag to not wait for the alarm. 1029 */ 1030static void 1031catchalarm(int signo) 1032{ 1033 1034 signalled = true; 1035} 1036 1037static void 1038get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1039{ 1040 int i; 1041 1042 for (i = 0; i < RTAX_MAX; i++) { 1043 if (addrs & (1 << i)) { 1044 rti_info[i] = sa; 1045 sa = (struct sockaddr *)((char *)(sa) + 1046 RT_ROUNDUP(sa->sa_len)); 1047 } else 1048 rti_info[i] = NULL; 1049 } 1050} 1051 1052static void 1053fetchifs(void) 1054{ 1055 struct if_msghdr *ifm; 1056 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1057 struct rt_msghdr *rtm; 1058 struct if_data *ifd = NULL; 1059 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1060 struct sockaddr_dl *sdl; 1061 char *buf, *next, *lim; 1062 char name[IFNAMSIZ]; 1063 size_t len; 1064 1065 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1066 err(1, "sysctl"); 1067 if ((buf = malloc(len)) == NULL) 1068 err(1, NULL); 1069 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1070 err(1, "sysctl"); 1071 1072 lim = buf + len; 1073 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1074 rtm = (struct rt_msghdr *)next; 1075 if (rtm->rtm_version != RTM_VERSION) 1076 continue; 1077 switch (rtm->rtm_type) { 1078 case RTM_IFINFO: 1079 ifm = (struct if_msghdr *)next; 1080 ifd = &ifm->ifm_data; 1081 1082 sa = (struct sockaddr *)(ifm + 1); 1083 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1084 1085 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1086 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1087 continue; 1088 bzero(name, sizeof(name)); 1089 if (sdl->sdl_nlen >= IFNAMSIZ) 1090 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1091 else if (sdl->sdl_nlen > 0) 1092 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1093 1094 if (interface != 0 && !strcmp(name, interface)) { 1095 strlcpy(ip_cur.ift_name, name, 1096 sizeof(ip_cur.ift_name)); 1097 ip_cur.ift_ip = ifd->ifi_ipackets; 1098 ip_cur.ift_ib = ifd->ifi_ibytes; 1099 ip_cur.ift_ie = ifd->ifi_ierrors; 1100 ip_cur.ift_op = ifd->ifi_opackets; 1101 ip_cur.ift_ob = ifd->ifi_obytes; 1102 ip_cur.ift_oe = ifd->ifi_oerrors; 1103 ip_cur.ift_co = ifd->ifi_collisions; 1104 ip_cur.ift_dr = ifd->ifi_iqdrops; 1105 } 1106 1107 sum_cur.ift_ip += ifd->ifi_ipackets; 1108 sum_cur.ift_ib += ifd->ifi_ibytes; 1109 sum_cur.ift_ie += ifd->ifi_ierrors; 1110 sum_cur.ift_op += ifd->ifi_opackets; 1111 sum_cur.ift_ob += ifd->ifi_obytes; 1112 sum_cur.ift_oe += ifd->ifi_oerrors; 1113 sum_cur.ift_co += ifd->ifi_collisions; 1114 sum_cur.ift_dr += ifd->ifi_iqdrops; 1115 break; 1116 } 1117 } 1118 if (interface == NULL) { 1119 strlcpy(ip_cur.ift_name, name, 1120 sizeof(ip_cur.ift_name)); 1121 ip_cur.ift_ip = ifd->ifi_ipackets; 1122 ip_cur.ift_ib = ifd->ifi_ibytes; 1123 ip_cur.ift_ie = ifd->ifi_ierrors; 1124 ip_cur.ift_op = ifd->ifi_opackets; 1125 ip_cur.ift_ob = ifd->ifi_obytes; 1126 ip_cur.ift_oe = ifd->ifi_oerrors; 1127 ip_cur.ift_co = ifd->ifi_collisions; 1128 ip_cur.ift_dr = ifd->ifi_iqdrops; 1129 } 1130} 1131