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