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