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