if.c revision 1.96
1/* $NetBSD: if.c,v 1.96 2020/02/02 03:41:12 thorpej 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.96 2020/02/02 03:41:12 thorpej 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 int, 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", 156 "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs"); 157 if (dflag) 158 printf(" %6.6s", "Idrops"); 159 printf(" %8.8s %5.5s %5.5s", 160 "Opkts", "Oerrs", "Colls"); 161 } 162 if (dflag) 163 printf(" %6.6s", "Odrops"); 164 if (tflag) 165 printf(" %4.4s", "Time"); 166 putchar('\n'); 167 } 168} 169 170static void 171intpr_sysctl(void) 172{ 173 struct if_msghdr *ifm; 174 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 175 static char *buf = NULL; 176 static size_t olen; 177 char *next, *lim, *cp; 178 struct rt_msghdr *rtm; 179 struct ifa_msghdr *ifam; 180 struct if_data *ifd = NULL; 181 struct sockaddr *sa, *rti_info[RTAX_MAX]; 182 struct sockaddr_dl *sdl; 183 uint64_t total = 0; 184 size_t len; 185 int did = 1, rtax = 0, n; 186 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 187 int ifindex = 0; 188 189 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 190 err(1, "sysctl"); 191 if (len > olen) { 192 free(buf); 193 if ((buf = malloc(len)) == NULL) 194 err(1, NULL); 195 olen = len; 196 } 197 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 198 err(1, "sysctl"); 199 200 intpr_header(); 201 202 lim = buf + len; 203 for (next = buf; next < lim; next += rtm->rtm_msglen) { 204 rtm = (struct rt_msghdr *)next; 205 if (rtm->rtm_version != RTM_VERSION) 206 continue; 207 switch (rtm->rtm_type) { 208 case RTM_IFINFO: 209 total = 0; 210 ifm = (struct if_msghdr *)next; 211 ifd = &ifm->ifm_data; 212 213 sa = (struct sockaddr *)(ifm + 1); 214 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 215 216 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 217 if (sdl == NULL || sdl->sdl_family != AF_LINK) { 218 continue; 219 } 220 bzero(name, sizeof(name)); 221 if (sdl->sdl_nlen >= IFNAMSIZ) 222 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 223 else if (sdl->sdl_nlen > 0) 224 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 225 226 if (interface != 0 && strcmp(name, interface) != 0) 227 continue; 228 229 ifindex = sdl->sdl_index; 230 231 /* mark inactive interfaces with a '*' */ 232 cp = strchr(name, '\0'); 233 if ((ifm->ifm_flags & IFF_UP) == 0) 234 *cp++ = '*'; 235 *cp = '\0'; 236 237 if (qflag) { 238 total = ifd->ifi_ibytes + ifd->ifi_obytes + 239 ifd->ifi_ipackets + ifd->ifi_ierrors + 240 ifd->ifi_opackets + ifd->ifi_oerrors + 241 ifd->ifi_collisions; 242 if (dflag) 243 total += ifd->ifi_iqdrops; 244 if (total == 0) 245 continue; 246 } 247 /* Skip the first one */ 248 if (did) { 249 did = 0; 250 continue; 251 } 252 rtax = RTAX_IFP; 253 break; 254 case RTM_NEWADDR: 255 if (qflag && total == 0) 256 continue; 257 if (interface != 0 && strcmp(name, interface) != 0) 258 continue; 259 ifam = (struct ifa_msghdr *)next; 260 if ((ifam->ifam_addrs & (RTA_NETMASK | RTA_IFA | 261 RTA_BRD)) == 0) 262 break; 263 264 sa = (struct sockaddr *)(ifam + 1); 265 266 get_rtaddrs(ifam->ifam_addrs, sa, rti_info); 267 rtax = RTAX_IFA; 268 did = 1; 269 break; 270 default: 271 continue; 272 } 273 if (vflag) 274 n = strlen(name) < 5 ? 5 : strlen(name); 275 else 276 n = 5; 277 278 printf("%-*.*s %-5" PRIu64 " ", n, n, name, ifd->ifi_mtu); 279 print_addr(ifindex, rti_info[rtax], rti_info, ifd, NULL); 280 } 281} 282 283union ifaddr_u { 284 struct ifaddr ifa; 285 struct in_ifaddr in; 286#ifdef INET6 287 struct in6_ifaddr in6; 288#endif /* INET6 */ 289}; 290 291static void 292ifnet_to_ifdata_kvm(const struct ifnet * const ifp, struct if_data * const ifd) 293{ 294 295 /* 296 * Interface statistics are no longer kept in struct ifnet, 297 * and thus an if_data is no longer embedded in struct ifnet. 298 * We cannot read stats via kvm without chasing per-cpu data, 299 * and maybe someday we could do that. But for now, this is 300 * what we have. 301 * 302 * Just copy the fields that do exist. 303 */ 304 memset(ifd, 0, sizeof(*ifd)); 305 ifd->ifi_type = ifp->if_type; 306 ifd->ifi_addrlen = ifp->if_addrlen; 307 ifd->ifi_hdrlen = ifp->if_hdrlen; 308 ifd->ifi_link_state = ifp->if_link_state; 309 ifd->ifi_mtu = ifp->if_mtu; 310 ifd->ifi_metric = ifp->if_metric; 311 ifd->ifi_baudrate = ifp->if_baudrate; 312 ifd->ifi_lastchange = ifp->if_lastchange; 313} 314 315static void 316intpr_kvm(u_long ifnetaddr, void (*pfunc)(const char *)) 317{ 318 struct ifnet ifnet; 319 struct if_data ifd; 320 union ifaddr_u ifaddr; 321 u_long ifaddraddr; 322 struct ifnet_head ifhead; /* TAILQ_HEAD */ 323 char name[IFNAMSIZ + 1]; /* + 1 for `*' */ 324 325 if (ifnetaddr == 0) { 326 printf("ifnet: symbol not defined\n"); 327 return; 328 } 329 330 /* 331 * Find the pointer to the first ifnet structure. Replace 332 * the pointer to the TAILQ_HEAD with the actual pointer 333 * to the first list element. 334 */ 335 if (kread(ifnetaddr, (char *)&ifhead, sizeof ifhead)) 336 return; 337 ifnetaddr = (u_long)ifhead.tqh_first; 338 339 intpr_header(); 340 341 ifaddraddr = 0; 342 while (ifnetaddr || ifaddraddr) { 343 char *cp; 344 int n; 345 346 if (ifaddraddr == 0) { 347 if (kread(ifnetaddr, (char *)&ifnet, sizeof ifnet)) 348 return; 349 memmove(name, ifnet.if_xname, IFNAMSIZ); 350 name[IFNAMSIZ - 1] = '\0'; /* sanity */ 351 ifnetaddr = (u_long)ifnet.if_list.tqe_next; 352 if (interface != 0 && strcmp(name, interface) != 0) 353 continue; 354 cp = strchr(name, '\0'); 355 356 if (pfunc) { 357 (*pfunc)(name); 358 continue; 359 } 360 361 if ((ifnet.if_flags & IFF_UP) == 0) 362 *cp++ = '*'; 363 *cp = '\0'; 364 ifaddraddr = (u_long)ifnet.if_addrlist.tqh_first; 365 } 366 if (vflag) 367 n = strlen(name) < 5 ? 5 : strlen(name); 368 else 369 n = 5; 370 printf("%-*.*s %-5llu ", n, n, name, 371 (unsigned long long)ifnet.if_mtu); 372 if (ifaddraddr == 0) { 373 printf("%-13.13s ", "none"); 374 printf("%-17.17s ", "none"); 375 } else { 376 struct sockaddr *sa; 377 378 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 379 ifaddraddr = 0; 380 continue; 381 } 382#define CP(x) ((char *)(x)) 383 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + 384 CP(&ifaddr); 385 sa = (struct sockaddr *)cp; 386 ifnet_to_ifdata_kvm(&ifnet, &ifd); 387 print_addr(ifnet.if_index, sa, (void *)&ifaddr, 388 &ifd, &ifnet); 389 } 390 ifaddraddr = (u_long)ifaddr.ifa.ifa_list.tqe_next; 391 } 392 393} 394 395static void 396mc_print(const int ifindex, const size_t ias, const char *oid, int *mcast_oids, 397 void (*pr)(const void *)) 398{ 399 uint8_t *mcast_addrs, *p; 400 const size_t incr = 2 * ias + sizeof(uint32_t); 401 size_t len; 402 403 if (mcast_oids[0] == 0) { 404 size_t oidlen = 4; 405 if (sysctlnametomib(oid, mcast_oids, &oidlen) == -1) { 406 warnx("'%s' not found", oid); 407 return; 408 } 409 if (oidlen != 3) { 410 warnx("Wrong OID path for '%s'", oid); 411 return; 412 } 413 } 414 415 if (mcast_oids[3] == ifindex) 416 return; 417 mcast_oids[3] = ifindex; 418 419 mcast_addrs = asysctl(mcast_oids, 4, &len); 420 if (mcast_addrs == NULL && len != 0) { 421 warn("failed to read '%s'", oid); 422 return; 423 } 424 if (len) { 425 p = mcast_addrs; 426 while (len >= incr) { 427 (*pr)((p + ias)); 428 p += incr; 429 len -= incr; 430 } 431 } 432 free(mcast_addrs); 433} 434 435#ifdef INET6 436static void 437ia6_print(const struct in6_addr *ia) 438{ 439 struct sockaddr_in6 as6; 440 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 441 int n; 442 443 memset(&as6, 0, sizeof(as6)); 444 as6.sin6_len = sizeof(struct sockaddr_in6); 445 as6.sin6_family = AF_INET6; 446 as6.sin6_addr = *ia; 447 inet6_getscopeid(&as6, INET6_IS_ADDR_MC_LINKLOCAL); 448 if (getnameinfo((struct sockaddr *)&as6, as6.sin6_len, hbuf, 449 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 450 strlcpy(hbuf, "??", sizeof(hbuf)); 451 } 452 if (vflag) 453 n = strlen(hbuf) < 17 ? 17 : strlen(hbuf); 454 else 455 n = 17; 456 printf("\n%25s %-*.*s ", "", n, n, hbuf); 457} 458 459static void 460mc6_print(const int ifindex) 461{ 462 static int mcast_oids[4]; 463 464 mc_print(ifindex, sizeof(struct in6_addr), "net.inet6.multicast", 465 mcast_oids, (void (*)(const void *))ia6_print); 466} 467#endif 468 469static void 470ia4_print(const struct in_addr *ia) 471{ 472 printf("\n%25s %-17.17s ", "", routename4(ia->s_addr, nflag)); 473} 474 475static void 476mc4_print(const int ifindex) 477{ 478 static int mcast_oids[4]; 479 480 mc_print(ifindex, sizeof(struct in_addr), "net.inet.multicast", 481 mcast_oids, (void (*)(const void *))ia4_print); 482} 483 484static void 485print_addr(const int ifindex, struct sockaddr *sa, 486 struct sockaddr **rtinfo, struct if_data *ifd, struct ifnet *ifnet) 487{ 488 char hexsep = '.'; /* for hexprint */ 489 static const char hexfmt[] = "%02x%c"; /* for hexprint */ 490 char hbuf[NI_MAXHOST]; /* for getnameinfo() */ 491#ifdef INET6 492 const int niflag = NI_NUMERICHOST; 493 struct sockaddr_in6 *sin6, *netmask6; 494#endif 495 struct sockaddr_in netmask; 496 struct sockaddr_in *sin; 497 char *cp; 498 int n, m; 499 500 switch (sa->sa_family) { 501 case AF_UNSPEC: 502 printf("%-13.13s ", "none"); 503 printf("%-17.17s ", "none"); 504 break; 505 case AF_INET: 506 sin = (struct sockaddr_in *)sa; 507 if (use_sysctl) { 508 netmask = *((struct sockaddr_in *)rtinfo[RTAX_NETMASK]); 509 } else { 510 struct in_ifaddr *ifaddr_in = (void *)rtinfo; 511 netmask.sin_addr.s_addr = ifaddr_in->ia_subnetmask; 512 } 513 cp = netname4(sin, &netmask, nflag); 514 if (vflag) 515 n = strlen(cp) < 13 ? 13 : strlen(cp); 516 else 517 n = 13; 518 printf("%-*.*s ", n, n, cp); 519 cp = routename4(sin->sin_addr.s_addr, nflag); 520 if (vflag) 521 n = strlen(cp) < 17 ? 17 : strlen(cp); 522 else 523 n = 17; 524 printf("%-*.*s ", n, n, cp); 525 526 if (!aflag) 527 break; 528 if (ifnet) { 529 u_long multiaddr; 530 struct in_multi inm; 531 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 532 533 multiaddr = (u_long)ifaddr->in.ia_multiaddrs.lh_first; 534 while (multiaddr != 0) { 535 kread(multiaddr, (char *)&inm, sizeof inm); 536 ia4_print(&inm.inm_addr); 537 multiaddr = (u_long)inm.inm_list.le_next; 538 } 539 } else { 540 mc4_print(ifindex); 541 } 542 break; 543#ifdef INET6 544 case AF_INET6: 545 sin6 = (struct sockaddr_in6 *)sa; 546 inet6_getscopeid(sin6, INET6_IS_ADDR_LINKLOCAL); 547#ifdef __KAME__ 548 if (!vflag) 549 sin6->sin6_scope_id = 0; 550#endif 551 552 if (use_sysctl) { 553 netmask6 = (struct sockaddr_in6 *)rtinfo[RTAX_NETMASK]; 554 } else { 555 struct in6_ifaddr *ifaddr_in6 = (void *)rtinfo; 556 netmask6 = &ifaddr_in6->ia_prefixmask; 557 } 558 559 cp = netname6(sin6, netmask6, nflag); 560 if (vflag) 561 n = strlen(cp) < 13 ? 13 : strlen(cp); 562 else 563 n = 13; 564 printf("%-*.*s ", n, n, cp); 565 if (getnameinfo((struct sockaddr *)sin6, 566 sin6->sin6_len, 567 hbuf, sizeof(hbuf), NULL, 0, 568 niflag) != 0) { 569 strlcpy(hbuf, "?", sizeof(hbuf)); 570 } 571 cp = hbuf; 572 if (vflag) 573 n = strlen(cp) < 17 ? 17 : strlen(cp); 574 else 575 n = 17; 576 printf("%-*.*s ", n, n, cp); 577 578 if (!aflag) 579 break; 580 if (ifnet) { 581 u_long multiaddr; 582 struct in6_multi inm; 583 union ifaddr_u *ifaddr = (union ifaddr_u *)rtinfo; 584 585 multiaddr = (u_long)ifaddr->in6._ia6_multiaddrs.lh_first; 586 while (multiaddr != 0) { 587 kread(multiaddr, (char *)&inm, sizeof inm); 588 ia6_print(&inm.in6m_addr); 589 multiaddr = (u_long)inm.in6m_entry.le_next; 590 } 591 } else { 592 mc6_print(ifindex); 593 } 594 break; 595#endif /*INET6*/ 596#ifndef SMALL 597 case AF_APPLETALK: 598 printf("atalk:%-7.7s ", 599 atalk_print(sa,0x10)); 600 printf("%-17.17s ", atalk_print(sa,0x0b)); 601 break; 602#endif 603 case AF_LINK: 604 printf("%-13.13s ", "<Link>"); 605 if (getnameinfo(sa, sa->sa_len, 606 hbuf, sizeof(hbuf), NULL, 0, 607 NI_NUMERICHOST) != 0) { 608 strlcpy(hbuf, "?", sizeof(hbuf)); 609 } 610 cp = hbuf; 611 if (vflag) 612 n = strlen(cp) < 17 ? 17 : strlen(cp); 613 else 614 n = 17; 615 printf("%-*.*s ", n, n, cp); 616 break; 617 618 default: 619 m = printf("(%d)", sa->sa_family); 620 for (cp = sa->sa_len + (char *)sa; 621 --cp > sa->sa_data && (*cp == 0);) {} 622 n = cp - sa->sa_data + 1; 623 cp = sa->sa_data; 624 625 while (--n >= 0) 626 m += printf(hexfmt, *cp++ & 0xff, 627 n > 0 ? hexsep : ' '); 628 m = 32 - m; 629 while (m-- > 0) 630 putchar(' '); 631 break; 632 } 633 634 if (bflag) { 635 char humbuf[HUMBUF_SIZE]; 636 637 if (hflag && humanize_number(humbuf, sizeof(humbuf), 638 ifd->ifi_ibytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 639 printf("%10s ", humbuf); 640 else 641 printf("%10llu ", (unsigned long long)ifd->ifi_ibytes); 642 643 if (hflag && humanize_number(humbuf, sizeof(humbuf), 644 ifd->ifi_obytes, "", HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 645 printf("%10s", humbuf); 646 else 647 printf("%10llu", (unsigned long long)ifd->ifi_obytes); 648 } else { 649 printf("%8llu %5llu", 650 (unsigned long long)ifd->ifi_ipackets, 651 (unsigned long long)ifd->ifi_ierrors); 652 if (dflag) 653 printf(" %6" PRIu64, ifd->ifi_iqdrops); 654 printf(" %8llu %5llu %5llu", 655 (unsigned long long)ifd->ifi_opackets, 656 (unsigned long long)ifd->ifi_oerrors, 657 (unsigned long long)ifd->ifi_collisions); 658 } 659 if (dflag) 660 printf(" %6lld", ifnet ? 661 (unsigned long long)ifnet->if_snd.ifq_drops : 0); 662 if (tflag) 663 printf(" %4d", ifnet ? ifnet->if_timer : 0); 664 putchar('\n'); 665} 666 667static void 668iftot_banner(struct iftot *ift) 669{ 670 if (bflag) 671 printf("%7.7s in %8.8s %6.6s out %5.5s", 672 ift->ift_name, " ", 673 ift->ift_name, " "); 674 else 675 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 676 ift->ift_name, " ", 677 ift->ift_name, " ", " "); 678 if (dflag) 679 printf(" %5.5s", " "); 680 681 if (bflag) 682 printf(" %7.7s in %8.8s %6.6s out %5.5s", 683 "total", " ", "total", " "); 684 else 685 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 686 "total", " ", "total", " ", " "); 687 if (dflag) 688 printf(" %5.5s", " "); 689 putchar('\n'); 690 if (bflag) 691 printf("%10.10s %8.8s %10.10s %5.5s", 692 "bytes", " ", "bytes", " "); 693 else 694 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 695 "packets", "errs", "packets", "errs", "colls"); 696 if (dflag) 697 printf(" %5.5s", "drops"); 698 699 if (bflag) 700 printf(" %10.10s %8.8s %10.10s %5.5s", 701 "bytes", " ", "bytes", " "); 702 else 703 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 704 "packets", "errs", "packets", "errs", "colls"); 705 if (dflag) 706 printf(" %5.5s", "drops"); 707 putchar('\n'); 708 fflush(stdout); 709} 710 711static void 712iftot_print(struct iftot *cur, struct iftot *old) 713{ 714 if (bflag) 715 printf("%10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 716 cur->ift_ib - old->ift_ib, " ", 717 cur->ift_ob - old->ift_ob, " "); 718 else 719 printf("%8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 720 cur->ift_ip - old->ift_ip, 721 cur->ift_ie - old->ift_ie, 722 cur->ift_op - old->ift_op, 723 cur->ift_oe - old->ift_oe, 724 cur->ift_co - old->ift_co); 725 if (dflag) 726 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 727} 728 729static void 730iftot_print_sum(struct iftot *cur, struct iftot *old) 731{ 732 if (bflag) 733 printf(" %10" PRIu64 " %8.8s %10" PRIu64 " %5.5s", 734 cur->ift_ib - old->ift_ib, " ", 735 cur->ift_ob - old->ift_ob, " "); 736 else 737 printf(" %8" PRIu64 " %5" PRIu64 " %8" PRIu64 " %5" PRIu64 " %5" PRIu64, 738 cur->ift_ip - old->ift_ip, 739 cur->ift_ie - old->ift_ie, 740 cur->ift_op - old->ift_op, 741 cur->ift_oe - old->ift_oe, 742 cur->ift_co - old->ift_co); 743 744 if (dflag) 745 printf(" %5" PRIu64, cur->ift_dr - old->ift_dr); 746} 747 748__dead static void 749sidewaysintpr_sysctl(unsigned interval) 750{ 751 struct itimerval it; 752 sigset_t emptyset; 753 sigset_t noalrm; 754 unsigned line; 755 756 set_lines(); 757 758 fetchifs(); 759 if (ip_cur.ift_name[0] == '\0') { 760 fprintf(stderr, "%s: %s: unknown interface\n", 761 getprogname(), interface); 762 exit(1); 763 } 764 765 sigemptyset(&emptyset); 766 sigemptyset(&noalrm); 767 sigaddset(&noalrm, SIGALRM); 768 sigprocmask(SIG_SETMASK, &noalrm, NULL); 769 770 signalled = 0; 771 (void)signal(SIGALRM, catchalarm); 772 773 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 774 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 775 setitimer(ITIMER_REAL, &it, NULL); 776 777banner: 778 iftot_banner(&ip_cur); 779 780 line = 0; 781 bzero(&ip_old, sizeof(ip_old)); 782 bzero(&sum_old, sizeof(sum_old)); 783loop: 784 bzero(&sum_cur, sizeof(sum_cur)); 785 786 fetchifs(); 787 788 iftot_print(&ip_cur, &ip_old); 789 790 ip_old = ip_cur; 791 792 iftot_print_sum(&sum_cur, &sum_old); 793 794 sum_old = sum_cur; 795 796 putchar('\n'); 797 fflush(stdout); 798 line++; 799 if (signalled == 0) { 800 sigsuspend(&emptyset); 801 } 802 signalled = 0; 803 if (line == redraw_lines) 804 goto banner; 805 goto loop; 806 /*NOTREACHED*/ 807} 808 809static void 810sidewaysintpr_kvm(unsigned interval, u_long off) 811{ 812 struct itimerval it; 813 sigset_t emptyset; 814 sigset_t noalrm; 815 struct ifnet ifnet; 816 struct if_data ifd; 817 u_long firstifnet; 818 struct iftot *ip, *total; 819 unsigned line; 820 struct iftot *lastif, *sum, *interesting; 821 struct ifnet_head ifhead; /* TAILQ_HEAD */ 822 823 set_lines(); 824 825 /* 826 * Find the pointer to the first ifnet structure. Replace 827 * the pointer to the TAILQ_HEAD with the actual pointer 828 * to the first list element. 829 */ 830 if (kread(off, (char *)&ifhead, sizeof ifhead)) 831 return; 832 firstifnet = (u_long)ifhead.tqh_first; 833 834 lastif = iftot; 835 sum = iftot + MAXIF - 1; 836 total = sum - 1; 837 interesting = (interface == NULL) ? iftot : NULL; 838 for (off = firstifnet, ip = iftot; off;) { 839 if (kread(off, (char *)&ifnet, sizeof ifnet)) 840 break; 841 memset(ip->ift_name, 0, sizeof(ip->ift_name)); 842 snprintf(ip->ift_name, IFNAMSIZ, "%s", ifnet.if_xname); 843 if (interface && strcmp(ifnet.if_xname, interface) == 0) 844 interesting = ip; 845 ip++; 846 if (ip >= iftot + MAXIF - 2) 847 break; 848 off = (u_long)ifnet.if_list.tqe_next; 849 } 850 if (interesting == NULL) { 851 fprintf(stderr, "%s: %s: unknown interface\n", 852 getprogname(), interface); 853 exit(1); 854 } 855 lastif = ip; 856 857 sigemptyset(&emptyset); 858 sigemptyset(&noalrm); 859 sigaddset(&noalrm, SIGALRM); 860 sigprocmask(SIG_SETMASK, &noalrm, NULL); 861 862 signalled = 0; 863 (void)signal(SIGALRM, catchalarm); 864 865 it.it_interval.tv_sec = it.it_value.tv_sec = interval; 866 it.it_interval.tv_usec = it.it_value.tv_usec = 0; 867 setitimer(ITIMER_REAL, &it, NULL); 868 869banner: 870 if (bflag) 871 printf("%7.7s in %8.8s %6.6s out %5.5s", 872 interesting->ift_name, " ", 873 interesting->ift_name, " "); 874 else 875 printf("%5.5s in %5.5s%5.5s out %5.5s %5.5s", 876 interesting->ift_name, " ", 877 interesting->ift_name, " ", " "); 878 if (dflag) 879 printf(" %5.5s", " "); 880 if (lastif - iftot > 0) { 881 if (bflag) 882 printf(" %7.7s in %8.8s %6.6s out %5.5s", 883 "total", " ", "total", " "); 884 else 885 printf(" %5.5s in %5.5s%5.5s out %5.5s %5.5s", 886 "total", " ", "total", " ", " "); 887 if (dflag) 888 printf(" %5.5s", " "); 889 } 890 for (ip = iftot; ip < iftot + MAXIF; ip++) { 891 ip->ift_ip = 0; 892 ip->ift_ib = 0; 893 ip->ift_ie = 0; 894 ip->ift_op = 0; 895 ip->ift_ob = 0; 896 ip->ift_oe = 0; 897 ip->ift_co = 0; 898 ip->ift_dr = 0; 899 } 900 putchar('\n'); 901 if (bflag) 902 printf("%10.10s %8.8s %10.10s %5.5s", 903 "bytes", " ", "bytes", " "); 904 else 905 printf("%8.8s %5.5s %8.8s %5.5s %5.5s", 906 "packets", "errs", "packets", "errs", "colls"); 907 if (dflag) 908 printf(" %5.5s", "drops"); 909 if (lastif - iftot > 0) { 910 if (bflag) 911 printf(" %10.10s %8.8s %10.10s %5.5s", 912 "bytes", " ", "bytes", " "); 913 else 914 printf(" %8.8s %5.5s %8.8s %5.5s %5.5s", 915 "packets", "errs", "packets", "errs", "colls"); 916 if (dflag) 917 printf(" %5.5s", "drops"); 918 } 919 putchar('\n'); 920 fflush(stdout); 921 line = 0; 922loop: 923 sum->ift_ip = 0; 924 sum->ift_ib = 0; 925 sum->ift_ie = 0; 926 sum->ift_op = 0; 927 sum->ift_ob = 0; 928 sum->ift_oe = 0; 929 sum->ift_co = 0; 930 sum->ift_dr = 0; 931 for (off = firstifnet, ip = iftot; off && ip < lastif; ip++) { 932 if (kread(off, (char *)&ifnet, sizeof ifnet)) { 933 off = 0; 934 continue; 935 } 936 ifnet_to_ifdata_kvm(&ifnet, &ifd); 937 if (ip == interesting) { 938 if (bflag) { 939 char humbuf[HUMBUF_SIZE]; 940 941 if (hflag && humanize_number(humbuf, 942 sizeof(humbuf), 943 ifd.ifi_ibytes - ip->ift_ib, "", 944 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 945 printf("%10s %8.8s ", humbuf, " "); 946 else 947 printf("%10llu %8.8s ", 948 (unsigned long long) 949 (ifd.ifi_ibytes-ip->ift_ib), " "); 950 951 if (hflag && humanize_number(humbuf, 952 sizeof(humbuf), 953 ifd.ifi_obytes - ip->ift_ob, "", 954 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 955 printf("%10s %5.5s", humbuf, " "); 956 else 957 printf("%10llu %5.5s", 958 (unsigned long long) 959 (ifd.ifi_obytes-ip->ift_ob), " "); 960 } else { 961 printf("%8llu %5llu %8llu %5llu %5llu", 962 (unsigned long long) 963 (ifd.ifi_ipackets - ip->ift_ip), 964 (unsigned long long) 965 (ifd.ifi_ierrors - ip->ift_ie), 966 (unsigned long long) 967 (ifd.ifi_opackets - ip->ift_op), 968 (unsigned long long) 969 (ifd.ifi_oerrors - ip->ift_oe), 970 (unsigned long long) 971 (ifd.ifi_collisions - ip->ift_co)); 972 } 973 if (dflag) 974 printf(" %5" PRIu64, 975 ifnet.if_snd.ifq_drops - ip->ift_dr); 976 } 977 ip->ift_ip = ifd.ifi_ipackets; 978 ip->ift_ib = ifd.ifi_ibytes; 979 ip->ift_ie = ifd.ifi_ierrors; 980 ip->ift_op = ifd.ifi_opackets; 981 ip->ift_ob = ifd.ifi_obytes; 982 ip->ift_oe = ifd.ifi_oerrors; 983 ip->ift_co = ifd.ifi_collisions; 984 ip->ift_dr = ifnet.if_snd.ifq_drops; 985 sum->ift_ip += ip->ift_ip; 986 sum->ift_ib += ip->ift_ib; 987 sum->ift_ie += ip->ift_ie; 988 sum->ift_op += ip->ift_op; 989 sum->ift_ob += ip->ift_ob; 990 sum->ift_oe += ip->ift_oe; 991 sum->ift_co += ip->ift_co; 992 sum->ift_dr += ip->ift_dr; 993 off = (u_long)ifnet.if_list.tqe_next; 994 } 995 if (lastif - iftot > 0) { 996 if (bflag) { 997 char humbuf[HUMBUF_SIZE]; 998 999 if (hflag && humanize_number(humbuf, 1000 sizeof(humbuf), sum->ift_ib - total->ift_ib, "", 1001 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1002 printf(" %10s %8.8s ", humbuf, " "); 1003 else 1004 printf(" %10llu %8.8s ", 1005 (unsigned long long) 1006 (sum->ift_ib - total->ift_ib), " "); 1007 1008 if (hflag && humanize_number(humbuf, 1009 sizeof(humbuf), sum->ift_ob - total->ift_ob, "", 1010 HN_AUTOSCALE, HN_NOSPACE | HN_B) > 0) 1011 printf("%10s %5.5s", humbuf, " "); 1012 else 1013 printf("%10llu %5.5s", 1014 (unsigned long long) 1015 (sum->ift_ob - total->ift_ob), " "); 1016 } else { 1017 printf(" %8llu %5llu %8llu %5llu %5llu", 1018 (unsigned long long) 1019 (sum->ift_ip - total->ift_ip), 1020 (unsigned long long) 1021 (sum->ift_ie - total->ift_ie), 1022 (unsigned long long) 1023 (sum->ift_op - total->ift_op), 1024 (unsigned long long) 1025 (sum->ift_oe - total->ift_oe), 1026 (unsigned long long) 1027 (sum->ift_co - total->ift_co)); 1028 } 1029 if (dflag) 1030 printf(" %5llu", 1031 (unsigned long long)(sum->ift_dr - total->ift_dr)); 1032 } 1033 *total = *sum; 1034 putchar('\n'); 1035 fflush(stdout); 1036 line++; 1037 if (signalled == 0) { 1038 sigsuspend(&emptyset); 1039 } 1040 signalled = 0; 1041 if (line == redraw_lines) 1042 goto banner; 1043 goto loop; 1044 /*NOTREACHED*/ 1045} 1046 1047/* 1048 * Print a running summary of interface statistics. 1049 * Repeat display every interval seconds, showing statistics 1050 * collected over that interval. Assumes that interval is non-zero. 1051 * First line printed at top of screen is always cumulative. 1052 */ 1053static void 1054sidewaysintpr(unsigned int interval, u_long off) 1055{ 1056 1057 if (use_sysctl) { 1058 sidewaysintpr_sysctl(interval); 1059 } else { 1060 sidewaysintpr_kvm(interval, off); 1061 } 1062} 1063 1064/* 1065 * Called if an interval expires before sidewaysintpr has completed a loop. 1066 * Sets a flag to not wait for the alarm. 1067 */ 1068static void 1069catchalarm(int signo) 1070{ 1071 1072 signalled = true; 1073} 1074 1075static void 1076get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) 1077{ 1078 int i; 1079 1080 for (i = 0; i < RTAX_MAX; i++) { 1081 if (addrs & (1 << i)) { 1082 rti_info[i] = sa; 1083 sa = (struct sockaddr *)((char *)(sa) + 1084 RT_ROUNDUP(sa->sa_len)); 1085 } else 1086 rti_info[i] = NULL; 1087 } 1088} 1089 1090static void 1091fetchifs(void) 1092{ 1093 struct if_msghdr *ifm; 1094 int mib[6] = { CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0 }; 1095 struct rt_msghdr *rtm; 1096 struct if_data *ifd = NULL; 1097 struct sockaddr *sa, *rti_info[RTAX_MAX]; 1098 struct sockaddr_dl *sdl; 1099 static char *buf = NULL; 1100 static size_t olen; 1101 char *next, *lim; 1102 char name[IFNAMSIZ]; 1103 size_t len; 1104 1105 if (prog_sysctl(mib, 6, NULL, &len, NULL, 0) == -1) 1106 err(1, "sysctl"); 1107 if (len > olen) { 1108 free(buf); 1109 if ((buf = malloc(len)) == NULL) 1110 err(1, NULL); 1111 olen = len; 1112 } 1113 if (prog_sysctl(mib, 6, buf, &len, NULL, 0) == -1) 1114 err(1, "sysctl"); 1115 1116 lim = buf + len; 1117 for (next = buf; next < lim; next += rtm->rtm_msglen) { 1118 rtm = (struct rt_msghdr *)next; 1119 if (rtm->rtm_version != RTM_VERSION) 1120 continue; 1121 switch (rtm->rtm_type) { 1122 case RTM_IFINFO: 1123 ifm = (struct if_msghdr *)next; 1124 ifd = &ifm->ifm_data; 1125 1126 sa = (struct sockaddr *)(ifm + 1); 1127 get_rtaddrs(ifm->ifm_addrs, sa, rti_info); 1128 1129 sdl = (struct sockaddr_dl *)rti_info[RTAX_IFP]; 1130 if (sdl == NULL || sdl->sdl_family != AF_LINK) 1131 continue; 1132 bzero(name, sizeof(name)); 1133 if (sdl->sdl_nlen >= IFNAMSIZ) 1134 memcpy(name, sdl->sdl_data, IFNAMSIZ - 1); 1135 else if (sdl->sdl_nlen > 0) 1136 memcpy(name, sdl->sdl_data, sdl->sdl_nlen); 1137 1138 if (interface != 0 && !strcmp(name, interface)) { 1139 strlcpy(ip_cur.ift_name, name, 1140 sizeof(ip_cur.ift_name)); 1141 ip_cur.ift_ip = ifd->ifi_ipackets; 1142 ip_cur.ift_ib = ifd->ifi_ibytes; 1143 ip_cur.ift_ie = ifd->ifi_ierrors; 1144 ip_cur.ift_op = ifd->ifi_opackets; 1145 ip_cur.ift_ob = ifd->ifi_obytes; 1146 ip_cur.ift_oe = ifd->ifi_oerrors; 1147 ip_cur.ift_co = ifd->ifi_collisions; 1148 ip_cur.ift_dr = ifd->ifi_iqdrops; 1149 } 1150 1151 sum_cur.ift_ip += ifd->ifi_ipackets; 1152 sum_cur.ift_ib += ifd->ifi_ibytes; 1153 sum_cur.ift_ie += ifd->ifi_ierrors; 1154 sum_cur.ift_op += ifd->ifi_opackets; 1155 sum_cur.ift_ob += ifd->ifi_obytes; 1156 sum_cur.ift_oe += ifd->ifi_oerrors; 1157 sum_cur.ift_co += ifd->ifi_collisions; 1158 sum_cur.ift_dr += ifd->ifi_iqdrops; 1159 break; 1160 } 1161 } 1162 if (interface == NULL) { 1163 strlcpy(ip_cur.ift_name, name, 1164 sizeof(ip_cur.ift_name)); 1165 ip_cur.ift_ip = ifd->ifi_ipackets; 1166 ip_cur.ift_ib = ifd->ifi_ibytes; 1167 ip_cur.ift_ie = ifd->ifi_ierrors; 1168 ip_cur.ift_op = ifd->ifi_opackets; 1169 ip_cur.ift_ob = ifd->ifi_obytes; 1170 ip_cur.ift_oe = ifd->ifi_oerrors; 1171 ip_cur.ift_co = ifd->ifi_collisions; 1172 ip_cur.ift_dr = ifd->ifi_iqdrops; 1173 } 1174} 1175