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