1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <ctype.h>
  28 #include <locale.h>
  29 #include <signal.h>
  30 #include <stdarg.h>
  31 #include <stdlib.h>
  32 #include <fcntl.h>
  33 #include <string.h>
  34 #include <stropts.h>
  35 #include <sys/stat.h>
  36 #include <errno.h>
  37 #include <strings.h>
  38 #include <getopt.h>
  39 #include <unistd.h>
  40 #include <priv.h>
  41 #include <termios.h>
  42 #include <pwd.h>
  43 #include <auth_attr.h>
  44 #include <auth_list.h>
  45 #include <libintl.h>
  46 #include <libdevinfo.h>
  47 #include <libdlpi.h>
  48 #include <libdladm.h>
  49 #include <libdllink.h>
  50 #include <libdlstat.h>
  51 #include <libdlaggr.h>
  52 #include <libinetutil.h>
  53 #include <bsm/adt.h>
  54 #include <bsm/adt_event.h>
  55 #include <stddef.h>
  56 #include <ofmt.h>
  57 
  58 typedef struct link_chain_s {
  59         datalink_id_t           lc_linkid;
  60         boolean_t               lc_visited;
  61         dladm_stat_chain_t      *lc_statchain[DLADM_STAT_NUM_STATS];
  62         struct link_chain_s     *lc_next;
  63 } link_chain_t;
  64 
  65 typedef void *  (*stats2str_t)(const char *, const char *, void *,
  66                     char, boolean_t);
  67 
  68 typedef struct show_state {
  69         link_chain_t    *ls_linkchain;
  70         boolean_t       ls_stattype[DLADM_STAT_NUM_STATS];
  71         stats2str_t     ls_stats2str[DLADM_STAT_NUM_STATS];
  72         ofmt_handle_t   ls_ofmt;
  73         char            ls_unit;
  74         boolean_t       ls_parsable;
  75 } show_state_t;
  76 
  77 typedef struct show_history_state_s {
  78         boolean_t       hs_plot;
  79         boolean_t       hs_parsable;
  80         boolean_t       hs_printheader;
  81         boolean_t       hs_first;
  82         boolean_t       hs_showall;
  83         ofmt_handle_t   hs_ofmt;
  84 } show_history_state_t;
  85 
  86 /*
  87  * callback functions for printing output and error diagnostics.
  88  */
  89 static ofmt_cb_t print_default_cb;
  90 
  91 static void dlstat_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
  92 
  93 typedef void cmdfunc_t(int, char **, const char *);
  94 
  95 static cmdfunc_t do_show, do_show_history, do_show_phys, do_show_link;
  96 static cmdfunc_t do_show_aggr;
  97 
  98 static void     die(const char *, ...);
  99 static void     die_optdup(int);
 100 static void     die_opterr(int, int, const char *);
 101 static void     die_dlerr(dladm_status_t, const char *, ...);
 102 static void     warn(const char *, ...);
 103 
 104 typedef struct  cmd {
 105         char            *c_name;
 106         cmdfunc_t       *c_fn;
 107         const char      *c_usage;
 108 } cmd_t;
 109 
 110 static cmd_t    cmds[] = {
 111         { "",           do_show,
 112             "dlstat [-r | -t] [-i <interval>] [link]\n"
 113             "       dlstat [-a | -A] [-i <interval>] [-p] [ -o field[,...]]\n"
 114             "              [-u R|K|M|G|T|P] [link]"},
 115         { "show-phys", do_show_phys,
 116             "dlstat show-phys [-r | -t] [-i interval] [-a]\n"
 117             "                 [-p] [ -o field[,...]] [-u R|K|M|G|T|P] "
 118             "[link]"},
 119         { "show-link", do_show_link,
 120             "dlstat show-link [-r [-F] | -t] [-i interval] [-a]\n"
 121             "                 [-p] [ -o field[,...]] [-u R|K|M|G|T|P] "
 122             "[link]\n"
 123             "       dlstat show-link -h [-a] [-d] [-F <format>]\n"
 124             "                 [-s <DD/MM/YYYY,HH:MM:SS>] "
 125             "[-e <DD/MM/YYYY,HH:MM:SS>]\n"
 126             "                 -f <logfile> [<link>]" },
 127         { "show-aggr", do_show_aggr,
 128             "dlstat show-aggr [-r | -t] [-i interval] [-p]\n"
 129             "                 [ -o field[,...]] [-u R|K|M|G|T|P] "
 130             " [link]" }
 131 };
 132 
 133 #define MAXSTATLEN 15
 134 
 135 /*
 136  * dlstat : total stat fields
 137  */
 138 typedef struct total_fields_buf_s {
 139         char t_linkname[MAXLINKNAMELEN];
 140         char t_ipackets[MAXSTATLEN];
 141         char t_rbytes[MAXSTATLEN];
 142         char t_opackets[MAXSTATLEN];
 143         char t_obytes[MAXSTATLEN];
 144         char t_zone[ZONENAME_MAX];
 145 } total_fields_buf_t;
 146 
 147 static ofmt_field_t total_s_fields[] = {
 148 { "LINK",       15,
 149     offsetof(total_fields_buf_t, t_linkname),   print_default_cb},
 150 { "IPKTS",      8,
 151     offsetof(total_fields_buf_t, t_ipackets),   print_default_cb},
 152 { "RBYTES",     8,
 153     offsetof(total_fields_buf_t, t_rbytes),     print_default_cb},
 154 { "OPKTS",      8,
 155     offsetof(total_fields_buf_t, t_opackets),   print_default_cb},
 156 { "OBYTES",     8,
 157     offsetof(total_fields_buf_t, t_obytes),     print_default_cb},
 158 { "ZONE",       20,
 159     offsetof(total_fields_buf_t, t_zone),       print_default_cb},
 160 { NULL,         0,      0,              NULL}};
 161 
 162 /*
 163  * dlstat show-phys: both Rx and Tx stat fields
 164  */
 165 typedef struct ring_fields_buf_s {
 166         char r_linkname[MAXLINKNAMELEN];
 167         char r_type[MAXSTATLEN];
 168         char r_id[MAXSTATLEN];
 169         char r_index[MAXSTATLEN];
 170         char r_packets[MAXSTATLEN];
 171         char r_bytes[MAXSTATLEN];
 172 } ring_fields_buf_t;
 173 
 174 static ofmt_field_t ring_s_fields[] = {
 175 { "LINK",       15,
 176     offsetof(ring_fields_buf_t, r_linkname),    print_default_cb},
 177 { "TYPE",       5,
 178     offsetof(ring_fields_buf_t, r_type),        print_default_cb},
 179 { "ID",         7,
 180     offsetof(ring_fields_buf_t, r_id),          print_default_cb},
 181 { "INDEX",      6,
 182     offsetof(ring_fields_buf_t, r_index),       print_default_cb},
 183 { "PKTS",       8,
 184     offsetof(ring_fields_buf_t, r_packets),     print_default_cb},
 185 { "BYTES",      8,
 186     offsetof(ring_fields_buf_t, r_bytes),       print_default_cb},
 187 { NULL,         0,              0,              NULL}};
 188 
 189 /*
 190  * dlstat show-phys -r: Rx Ring stat fields
 191  */
 192 typedef struct rx_ring_fields_buf_s {
 193         char rr_linkname[MAXLINKNAMELEN];
 194         char rr_type[MAXSTATLEN];
 195         char rr_id[MAXSTATLEN];
 196         char rr_index[MAXSTATLEN];
 197         char rr_ipackets[MAXSTATLEN];
 198         char rr_rbytes[MAXSTATLEN];
 199 } rx_ring_fields_buf_t;
 200 
 201 static ofmt_field_t rx_ring_s_fields[] = {
 202 { "LINK",       15,
 203     offsetof(rx_ring_fields_buf_t, rr_linkname),        print_default_cb},
 204 { "TYPE",       5,
 205     offsetof(rx_ring_fields_buf_t, rr_type),            print_default_cb},
 206 { "ID",         7,
 207     offsetof(rx_ring_fields_buf_t, rr_id),              print_default_cb},
 208 { "INDEX",      6,
 209     offsetof(rx_ring_fields_buf_t, rr_index),           print_default_cb},
 210 { "IPKTS",      8,
 211     offsetof(rx_ring_fields_buf_t, rr_ipackets),        print_default_cb},
 212 { "RBYTES",     8,
 213     offsetof(rx_ring_fields_buf_t, rr_rbytes),          print_default_cb},
 214 { NULL,         0,              0,              NULL}};
 215 
 216 /*
 217  * dlstat show-phys -t: Tx Ring stat fields
 218  */
 219 typedef struct tx_ring_fields_buf_s {
 220         char tr_linkname[MAXLINKNAMELEN];
 221         char tr_type[MAXSTATLEN];
 222         char tr_id[MAXSTATLEN];
 223         char tr_index[MAXSTATLEN];
 224         char tr_opackets[MAXSTATLEN];
 225         char tr_obytes[MAXSTATLEN];
 226 } tx_ring_fields_buf_t;
 227 
 228 static ofmt_field_t tx_ring_s_fields[] = {
 229 { "LINK",       15,
 230     offsetof(tx_ring_fields_buf_t, tr_linkname),        print_default_cb},
 231 { "TYPE",       5,
 232     offsetof(tx_ring_fields_buf_t, tr_type),            print_default_cb},
 233 { "ID",         7,
 234     offsetof(tx_ring_fields_buf_t, tr_id),              print_default_cb},
 235 { "INDEX",      6,
 236     offsetof(tx_ring_fields_buf_t, tr_index),           print_default_cb},
 237 { "OPKTS",      8,
 238     offsetof(tx_ring_fields_buf_t, tr_opackets),        print_default_cb},
 239 { "OBYTES",     8,
 240     offsetof(tx_ring_fields_buf_t, tr_obytes),          print_default_cb},
 241 { NULL,         0,              0,              NULL}};
 242 
 243 /*
 244  * dlstat show-link: both Rx and Tx lane fields
 245  */
 246 typedef struct lane_fields_buf_s {
 247         char l_linkname[MAXLINKNAMELEN];
 248         char l_type[MAXSTATLEN];
 249         char l_id[MAXSTATLEN];
 250         char l_index[MAXSTATLEN];
 251         char l_packets[MAXSTATLEN];
 252         char l_bytes[MAXSTATLEN];
 253 } lane_fields_buf_t;
 254 
 255 static ofmt_field_t lane_s_fields[] = {
 256 { "LINK",       15,
 257     offsetof(lane_fields_buf_t, l_linkname),    print_default_cb},
 258 { "TYPE",       5,
 259     offsetof(lane_fields_buf_t, l_type),        print_default_cb},
 260 { "ID",         7,
 261     offsetof(lane_fields_buf_t, l_id),          print_default_cb},
 262 { "INDEX",      6,
 263     offsetof(lane_fields_buf_t, l_index),       print_default_cb},
 264 { "PKTS",       8,
 265     offsetof(lane_fields_buf_t, l_packets),     print_default_cb},
 266 { "BYTES",      8,
 267     offsetof(lane_fields_buf_t, l_bytes),       print_default_cb},
 268 { NULL,         0,              0,              NULL}};
 269 
 270 /*
 271  * dlstat show-link -r, dlstat -r: Rx Lane stat fields
 272  */
 273 typedef struct rx_lane_fields_buf_s {
 274         char rl_linkname[MAXLINKNAMELEN];
 275         char rl_type[MAXSTATLEN];
 276         char rl_id[MAXSTATLEN];
 277         char rl_index[MAXSTATLEN];
 278         char rl_ipackets[MAXSTATLEN];
 279         char rl_rbytes[MAXSTATLEN];
 280         char rl_intrs[MAXSTATLEN];
 281         char rl_polls[MAXSTATLEN];
 282         char rl_sdrops[MAXSTATLEN];
 283         char rl_chl10[MAXSTATLEN];
 284         char rl_ch10_50[MAXSTATLEN];
 285         char rl_chg50[MAXSTATLEN];
 286 } rx_lane_fields_buf_t;
 287 
 288 static ofmt_field_t rx_lane_s_fields[] = {
 289 { "LINK",       10,
 290     offsetof(rx_lane_fields_buf_t, rl_linkname),        print_default_cb},
 291 { "TYPE",       5,
 292     offsetof(rx_lane_fields_buf_t, rl_type),            print_default_cb},
 293 { "ID",         7,
 294     offsetof(rx_lane_fields_buf_t, rl_id),              print_default_cb},
 295 { "INDEX",      6,
 296     offsetof(rx_lane_fields_buf_t, rl_index),           print_default_cb},
 297 { "IPKTS",      8,
 298     offsetof(rx_lane_fields_buf_t, rl_ipackets),        print_default_cb},
 299 { "RBYTES",     8,
 300     offsetof(rx_lane_fields_buf_t, rl_rbytes),          print_default_cb},
 301 { "INTRS",      8,
 302     offsetof(rx_lane_fields_buf_t, rl_intrs),           print_default_cb},
 303 { "POLLS",      8,
 304     offsetof(rx_lane_fields_buf_t, rl_polls),           print_default_cb},
 305 { "SDROPS",     8,
 306     offsetof(rx_lane_fields_buf_t, rl_sdrops),          print_default_cb},
 307 { "CH<10",   8,
 308     offsetof(rx_lane_fields_buf_t, rl_chl10),           print_default_cb},
 309 { "CH10-50",    8,
 310     offsetof(rx_lane_fields_buf_t, rl_ch10_50),         print_default_cb},
 311 { "CH>50",   8,
 312     offsetof(rx_lane_fields_buf_t, rl_chg50),           print_default_cb},
 313 { NULL,         0,              0,              NULL}};
 314 
 315 /*
 316  * dlstat show-link -r -F: Rx fanout stat fields
 317  */
 318 typedef struct rx_fanout_lane_fields_buf_s {
 319         char rfl_linkname[MAXLINKNAMELEN];
 320         char rfl_type[MAXSTATLEN];
 321         char rfl_id[MAXSTATLEN];
 322         char rfl_index[MAXSTATLEN];
 323         char rfl_fout[MAXSTATLEN];
 324         char rfl_ipackets[MAXSTATLEN];
 325         char rfl_rbytes[MAXSTATLEN];
 326 } rx_fanout_lane_fields_buf_t;
 327 
 328 static ofmt_field_t rx_fanout_lane_s_fields[] = {
 329 { "LINK",       15,
 330     offsetof(rx_fanout_lane_fields_buf_t, rfl_linkname), print_default_cb},
 331 { "TYPE",       5,
 332     offsetof(rx_fanout_lane_fields_buf_t, rfl_type),    print_default_cb},
 333 { "ID",         7,
 334     offsetof(rx_fanout_lane_fields_buf_t, rfl_id),      print_default_cb},
 335 { "INDEX",      6,
 336     offsetof(rx_fanout_lane_fields_buf_t, rfl_index),   print_default_cb},
 337 { "FOUT",       6,
 338     offsetof(rx_fanout_lane_fields_buf_t, rfl_fout),    print_default_cb},
 339 { "IPKTS",      8,
 340     offsetof(rx_fanout_lane_fields_buf_t, rfl_ipackets), print_default_cb},
 341 { "RBYTES",     8,
 342     offsetof(rx_fanout_lane_fields_buf_t, rfl_rbytes),  print_default_cb},
 343 { NULL,         0,              0,              NULL}};
 344 
 345 /*
 346  * dlstat show-link -t: Tx Lane stat fields
 347  */
 348 typedef struct tx_lane_fields_buf_s {
 349         char tl_linkname[MAXLINKNAMELEN];
 350         char tl_index[MAXSTATLEN];
 351         char tl_type[MAXSTATLEN];
 352         char tl_id[MAXSTATLEN];
 353         char tl_opackets[MAXSTATLEN];
 354         char tl_obytes[MAXSTATLEN];
 355         char tl_blockcnt[MAXSTATLEN];
 356         char tl_unblockcnt[MAXSTATLEN];
 357         char tl_sdrops[MAXSTATLEN];
 358 } tx_lane_fields_buf_t;
 359 
 360 static ofmt_field_t tx_lane_s_fields[] = {
 361 { "LINK",       15,
 362     offsetof(tx_lane_fields_buf_t, tl_linkname),        print_default_cb},
 363 { "TYPE",       5,
 364     offsetof(tx_lane_fields_buf_t, tl_type),            print_default_cb},
 365 { "ID",         7,
 366     offsetof(tx_lane_fields_buf_t, tl_id),              print_default_cb},
 367 { "INDEX",      6,
 368     offsetof(tx_lane_fields_buf_t, tl_index),           print_default_cb},
 369 { "OPKTS",      8,
 370     offsetof(tx_lane_fields_buf_t, tl_opackets),        print_default_cb},
 371 { "OBYTES",     8,
 372     offsetof(tx_lane_fields_buf_t, tl_obytes),          print_default_cb},
 373 { "BLKCNT",     8,
 374     offsetof(tx_lane_fields_buf_t, tl_blockcnt),        print_default_cb},
 375 { "UBLKCNT",    8,
 376     offsetof(tx_lane_fields_buf_t, tl_unblockcnt),      print_default_cb},
 377 { "SDROPS",     8,
 378     offsetof(tx_lane_fields_buf_t, tl_sdrops),          print_default_cb},
 379 { NULL,         0,              0,              NULL}};
 380 
 381 /*
 382  * dlstat show-aggr: aggr port stat fields
 383  */
 384 typedef struct aggr_port_fields_buf_s {
 385         char ap_linkname[MAXLINKNAMELEN];
 386         char ap_portname[MAXLINKNAMELEN];
 387         char ap_ipackets[MAXSTATLEN];
 388         char ap_rbytes[MAXSTATLEN];
 389         char ap_opackets[MAXSTATLEN];
 390         char ap_obytes[MAXSTATLEN];
 391 } aggr_port_fields_buf_t;
 392 
 393 static ofmt_field_t aggr_port_s_fields[] = {
 394 { "LINK",       15,
 395     offsetof(aggr_port_fields_buf_t, ap_linkname),      print_default_cb},
 396 { "PORT",       15,
 397     offsetof(aggr_port_fields_buf_t, ap_portname),      print_default_cb},
 398 { "IPKTS",      8,
 399     offsetof(aggr_port_fields_buf_t, ap_ipackets),      print_default_cb},
 400 { "RBYTES",     8,
 401     offsetof(aggr_port_fields_buf_t, ap_rbytes),        print_default_cb},
 402 { "OPKTS",      8,
 403     offsetof(aggr_port_fields_buf_t, ap_opackets),      print_default_cb},
 404 { "OBYTES",     8,
 405     offsetof(aggr_port_fields_buf_t, ap_obytes),        print_default_cb},
 406 { NULL,         0,              0,              NULL}};
 407 
 408 /*
 409  * structures for 'dlstat show-link -h'
 410  */
 411 typedef struct  history_fields_buf_s {
 412         char    h_link[12];
 413         char    h_duration[10];
 414         char    h_ipackets[9];
 415         char    h_rbytes[10];
 416         char    h_opackets[9];
 417         char    h_obytes[10];
 418         char    h_bandwidth[14];
 419 } history_fields_buf_t;
 420 
 421 static ofmt_field_t history_fields[] = {
 422 { "LINK",       13,
 423         offsetof(history_fields_buf_t, h_link), print_default_cb},
 424 { "DURATION",   11,
 425         offsetof(history_fields_buf_t, h_duration), print_default_cb},
 426 { "IPKTS",      10,
 427         offsetof(history_fields_buf_t, h_ipackets), print_default_cb},
 428 { "RBYTES",     11,
 429         offsetof(history_fields_buf_t, h_rbytes), print_default_cb},
 430 { "OPKTS",      10,
 431         offsetof(history_fields_buf_t, h_opackets), print_default_cb},
 432 { "OBYTES",     11,
 433         offsetof(history_fields_buf_t, h_obytes), print_default_cb},
 434 { "BANDWIDTH",  15,
 435         offsetof(history_fields_buf_t, h_bandwidth), print_default_cb},
 436 { NULL,         0, 0, NULL}};
 437 
 438 /*
 439  * structures for 'dlstat show-link -h link'
 440  */
 441 typedef struct  history_l_fields_buf_s {
 442         char    hl_link[12];
 443         char    hl_stime[13];
 444         char    hl_etime[13];
 445         char    hl_rbytes[8];
 446         char    hl_obytes[8];
 447         char    hl_bandwidth[14];
 448 } history_l_fields_buf_t;
 449 
 450 static ofmt_field_t history_l_fields[] = {
 451 /* name,        field width,    offset */
 452 { "LINK",       13,
 453         offsetof(history_l_fields_buf_t, hl_link), print_default_cb},
 454 { "START",      14,
 455         offsetof(history_l_fields_buf_t, hl_stime), print_default_cb},
 456 { "END",        14,
 457         offsetof(history_l_fields_buf_t, hl_etime), print_default_cb},
 458 { "RBYTES",     9,
 459         offsetof(history_l_fields_buf_t, hl_rbytes), print_default_cb},
 460 { "OBYTES",     9,
 461         offsetof(history_l_fields_buf_t, hl_obytes), print_default_cb},
 462 { "BANDWIDTH",  15,
 463         offsetof(history_l_fields_buf_t, hl_bandwidth), print_default_cb},
 464 { NULL,         0, 0, NULL}}
 465 ;
 466 
 467 static char *progname;
 468 
 469 /*
 470  * Handle to libdladm.  Opened in main() before the sub-command
 471  * specific function is called.
 472  */
 473 static dladm_handle_t handle = NULL;
 474 
 475 static void
 476 usage(void)
 477 {
 478         int     i;
 479         cmd_t   *cmdp;
 480 
 481         (void) fprintf(stderr, gettext("usage: "));
 482         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 483                 cmdp = &cmds[i];
 484                 if (cmdp->c_usage != NULL)
 485                         (void) fprintf(stderr, "%s\n", gettext(cmdp->c_usage));
 486         }
 487 
 488         /* close dladm handle if it was opened */
 489         if (handle != NULL)
 490                 dladm_close(handle);
 491 
 492         exit(1);
 493 }
 494 
 495 int
 496 main(int argc, char *argv[])
 497 {
 498         int             i;
 499         cmd_t           *cmdp;
 500         dladm_status_t  status;
 501 
 502         (void) setlocale(LC_ALL, "");
 503 #if !defined(TEXT_DOMAIN)
 504 #define TEXT_DOMAIN "SYS_TEST"
 505 #endif
 506         (void) textdomain(TEXT_DOMAIN);
 507 
 508         progname = argv[0];
 509 
 510         /* Open the libdladm handle */
 511         if ((status = dladm_open(&handle)) != DLADM_STATUS_OK)
 512                 die_dlerr(status, "could not open /dev/dld");
 513 
 514         if (argc == 1) {
 515                 do_show(argc - 1, NULL, cmds[0].c_usage);
 516                 goto done;
 517         }
 518 
 519         for (i = 0; i < sizeof (cmds) / sizeof (cmds[0]); i++) {
 520                 cmdp = &cmds[i];
 521                 if (strcmp(argv[1], cmdp->c_name) == 0) {
 522                         cmdp->c_fn(argc - 1, &argv[1], cmdp->c_usage);
 523                         goto done;
 524                 }
 525         }
 526 
 527         do_show(argc, &argv[0], cmds[0].c_usage);
 528 
 529 done:
 530         dladm_close(handle);
 531         return (0);
 532 }
 533 
 534 /*ARGSUSED*/
 535 static int
 536 show_history_date(dladm_usage_t *history, void *arg)
 537 {
 538         show_history_state_t    *state = arg;
 539         time_t                  stime;
 540         char                    timebuf[20];
 541         dladm_status_t          status;
 542         uint32_t                flags;
 543 
 544         /*
 545          * Only show history information for existing links unless '-a'
 546          * is specified.
 547          */
 548         if (!state->hs_showall) {
 549                 if ((status = dladm_name2info(handle, history->du_name,
 550                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
 551                         return (status);
 552                 }
 553                 if ((flags & DLADM_OPT_ACTIVE) == 0)
 554                         return (DLADM_STATUS_LINKINVAL);
 555         }
 556 
 557         stime = history->du_stime;
 558         (void) strftime(timebuf, sizeof (timebuf), "%m/%d/%Y",
 559             localtime(&stime));
 560         (void) printf("%s\n", timebuf);
 561 
 562         return (DLADM_STATUS_OK);
 563 }
 564 
 565 static int
 566 show_history_time(dladm_usage_t *history, void *arg)
 567 {
 568         show_history_state_t    *state = arg;
 569         char                    buf[DLADM_STRSIZE];
 570         history_l_fields_buf_t  ubuf;
 571         time_t                  time;
 572         double                  bw;
 573         dladm_status_t          status;
 574         uint32_t                flags;
 575 
 576         /*
 577          * Only show history information for existing links unless '-a'
 578          * is specified.
 579          */
 580         if (!state->hs_showall) {
 581                 if ((status = dladm_name2info(handle, history->du_name,
 582                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
 583                         return (status);
 584                 }
 585                 if ((flags & DLADM_OPT_ACTIVE) == 0)
 586                         return (DLADM_STATUS_LINKINVAL);
 587         }
 588 
 589         if (state->hs_plot) {
 590                 if (!state->hs_printheader) {
 591                         if (state->hs_first) {
 592                                 (void) printf("# Time");
 593                                 state->hs_first = B_FALSE;
 594                         }
 595                         (void) printf(" %s", history->du_name);
 596                         if (history->du_last) {
 597                                 (void) printf("\n");
 598                                 state->hs_first = B_TRUE;
 599                                 state->hs_printheader = B_TRUE;
 600                         }
 601                 } else {
 602                         if (state->hs_first) {
 603                                 time = history->du_etime;
 604                                 (void) strftime(buf, sizeof (buf), "%T",
 605                                     localtime(&time));
 606                                 state->hs_first = B_FALSE;
 607                                 (void) printf("%s", buf);
 608                         }
 609                         bw = (double)history->du_bandwidth/1000;
 610                         (void) printf(" %.2f", bw);
 611                         if (history->du_last) {
 612                                 (void) printf("\n");
 613                                 state->hs_first = B_TRUE;
 614                         }
 615                 }
 616                 return (DLADM_STATUS_OK);
 617         }
 618 
 619         bzero(&ubuf, sizeof (ubuf));
 620 
 621         (void) snprintf(ubuf.hl_link, sizeof (ubuf.hl_link), "%s",
 622             history->du_name);
 623         time = history->du_stime;
 624         (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
 625         (void) snprintf(ubuf.hl_stime, sizeof (ubuf.hl_stime), "%s",
 626             buf);
 627         time = history->du_etime;
 628         (void) strftime(buf, sizeof (buf), "%T", localtime(&time));
 629         (void) snprintf(ubuf.hl_etime, sizeof (ubuf.hl_etime), "%s",
 630             buf);
 631         (void) snprintf(ubuf.hl_rbytes, sizeof (ubuf.hl_rbytes),
 632             "%llu", history->du_rbytes);
 633         (void) snprintf(ubuf.hl_obytes, sizeof (ubuf.hl_obytes),
 634             "%llu", history->du_obytes);
 635         (void) snprintf(ubuf.hl_bandwidth, sizeof (ubuf.hl_bandwidth),
 636             "%s Mbps", dladm_bw2str(history->du_bandwidth, buf));
 637 
 638         ofmt_print(state->hs_ofmt, &ubuf);
 639         return (DLADM_STATUS_OK);
 640 }
 641 
 642 static int
 643 show_history_res(dladm_usage_t *history, void *arg)
 644 {
 645         show_history_state_t    *state = arg;
 646         char                    buf[DLADM_STRSIZE];
 647         history_fields_buf_t    ubuf;
 648         dladm_status_t          status;
 649         uint32_t                flags;
 650 
 651         /*
 652          * Only show history information for existing links unless '-a'
 653          * is specified.
 654          */
 655         if (!state->hs_showall) {
 656                 if ((status = dladm_name2info(handle, history->du_name,
 657                     NULL, &flags, NULL, NULL)) != DLADM_STATUS_OK) {
 658                         return (status);
 659                 }
 660                 if ((flags & DLADM_OPT_ACTIVE) == 0)
 661                         return (DLADM_STATUS_LINKINVAL);
 662         }
 663 
 664         bzero(&ubuf, sizeof (ubuf));
 665 
 666         (void) snprintf(ubuf.h_link, sizeof (ubuf.h_link), "%s",
 667             history->du_name);
 668         (void) snprintf(ubuf.h_duration, sizeof (ubuf.h_duration),
 669             "%llu", history->du_duration);
 670         (void) snprintf(ubuf.h_ipackets, sizeof (ubuf.h_ipackets),
 671             "%llu", history->du_ipackets);
 672         (void) snprintf(ubuf.h_rbytes, sizeof (ubuf.h_rbytes),
 673             "%llu", history->du_rbytes);
 674         (void) snprintf(ubuf.h_opackets, sizeof (ubuf.h_opackets),
 675             "%llu", history->du_opackets);
 676         (void) snprintf(ubuf.h_obytes, sizeof (ubuf.h_obytes),
 677             "%llu", history->du_obytes);
 678         (void) snprintf(ubuf.h_bandwidth, sizeof (ubuf.h_bandwidth),
 679             "%s Mbps", dladm_bw2str(history->du_bandwidth, buf));
 680 
 681         ofmt_print(state->hs_ofmt, &ubuf);
 682 
 683         return (DLADM_STATUS_OK);
 684 }
 685 
 686 static boolean_t
 687 valid_formatspec(char *formatspec_str)
 688 {
 689         return (strcmp(formatspec_str, "gnuplot") == 0);
 690 }
 691 
 692 /*ARGSUSED*/
 693 static void
 694 do_show_history(int argc, char *argv[], const char *use)
 695 {
 696         char                    *file = NULL;
 697         int                     opt;
 698         dladm_status_t          status;
 699         boolean_t               d_arg = B_FALSE;
 700         char                    *stime = NULL;
 701         char                    *etime = NULL;
 702         char                    *resource = NULL;
 703         show_history_state_t    state;
 704         boolean_t               o_arg = B_FALSE;
 705         boolean_t               F_arg = B_FALSE;
 706         char                    *fields_str = NULL;
 707         char                    *formatspec_str = NULL;
 708         char                    *all_l_fields =
 709             "link,start,end,rbytes,obytes,bandwidth";
 710         ofmt_handle_t           ofmt;
 711         ofmt_status_t           oferr;
 712         uint_t                  ofmtflags = 0;
 713 
 714         bzero(&state, sizeof (show_history_state_t));
 715         state.hs_parsable = B_FALSE;
 716         state.hs_printheader = B_FALSE;
 717         state.hs_plot = B_FALSE;
 718         state.hs_first = B_TRUE;
 719 
 720         while ((opt = getopt(argc, argv, "das:e:o:f:F:")) != -1) {
 721                 switch (opt) {
 722                 case 'd':
 723                         d_arg = B_TRUE;
 724                         break;
 725                 case 'a':
 726                         state.hs_showall = B_TRUE;
 727                         break;
 728                 case 'f':
 729                         file = optarg;
 730                         break;
 731                 case 's':
 732                         stime = optarg;
 733                         break;
 734                 case 'e':
 735                         etime = optarg;
 736                         break;
 737                 case 'o':
 738                         o_arg = B_TRUE;
 739                         fields_str = optarg;
 740                         break;
 741                 case 'F':
 742                         state.hs_plot = F_arg = B_TRUE;
 743                         formatspec_str = optarg;
 744                         break;
 745                 default:
 746                         die_opterr(optopt, opt, use);
 747                         break;
 748                 }
 749         }
 750 
 751         if (file == NULL)
 752                 die("show-link -h requires a file");
 753 
 754         if (optind == (argc-1)) {
 755                 uint32_t        flags;
 756 
 757                 resource = argv[optind];
 758                 if (!state.hs_showall &&
 759                     (((status = dladm_name2info(handle, resource, NULL, &flags,
 760                     NULL, NULL)) != DLADM_STATUS_OK) ||
 761                     ((flags & DLADM_OPT_ACTIVE) == 0))) {
 762                         die("invalid link: '%s'", resource);
 763                 }
 764         }
 765 
 766         if (F_arg && d_arg)
 767                 die("incompatible -d and -F options");
 768 
 769         if (F_arg && !valid_formatspec(formatspec_str))
 770                 die("Format specifier %s not supported", formatspec_str);
 771 
 772         if (state.hs_parsable)
 773                 ofmtflags |= OFMT_PARSABLE;
 774 
 775         if (resource == NULL && stime == NULL && etime == NULL) {
 776                 oferr = ofmt_open(fields_str, history_fields, ofmtflags, 0,
 777                     &ofmt);
 778         } else {
 779                 if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0))
 780                         fields_str = all_l_fields;
 781                 oferr = ofmt_open(fields_str, history_l_fields, ofmtflags, 0,
 782                     &ofmt);
 783 
 784         }
 785         dlstat_ofmt_check(oferr, state.hs_parsable, ofmt);
 786         state.hs_ofmt = ofmt;
 787 
 788         if (d_arg) {
 789                 /* Print log dates */
 790                 status = dladm_usage_dates(show_history_date,
 791                     DLADM_LOGTYPE_LINK, file, resource, &state);
 792         } else if (resource == NULL && stime == NULL && etime == NULL &&
 793             !F_arg) {
 794                 /* Print summary */
 795                 status = dladm_usage_summary(show_history_res,
 796                     DLADM_LOGTYPE_LINK, file, &state);
 797         } else if (resource != NULL) {
 798                 /* Print log entries for named resource */
 799                 status = dladm_walk_usage_res(show_history_time,
 800                     DLADM_LOGTYPE_LINK, file, resource, stime, etime, &state);
 801         } else {
 802                 /* Print time and information for each link */
 803                 status = dladm_walk_usage_time(show_history_time,
 804                     DLADM_LOGTYPE_LINK, file, stime, etime, &state);
 805         }
 806 
 807         if (status != DLADM_STATUS_OK)
 808                 die_dlerr(status, "show-link -h");
 809         ofmt_close(ofmt);
 810 }
 811 
 812 boolean_t
 813 dlstat_unit(char *oarg, char *unit)
 814 {
 815         if ((strcmp(oarg, "R") == 0) || (strcmp(oarg, "K") == 0) ||
 816             (strcmp(oarg, "M") == 0) || (strcmp(oarg, "G") == 0) ||
 817             (strcmp(oarg, "T") == 0) || (strcmp(oarg, "P") == 0)) {
 818                 *unit = oarg[0];
 819                 return (B_TRUE);
 820         }
 821 
 822         return (B_FALSE);
 823 }
 824 
 825 void
 826 map_to_units(char *buf, uint_t bufsize, double num, char unit,
 827     boolean_t parsable)
 828 {
 829         if (parsable) {
 830                 (void) snprintf(buf, bufsize, "%.0lf", num);
 831                 return;
 832         }
 833 
 834         if (unit == '\0') {
 835                 int index;
 836 
 837                 for (index = 0; (int)(num/1000) != 0; index++, num /= 1000)
 838                         ;
 839 
 840                 switch (index) {
 841                         case 0:
 842                                 unit = '\0';
 843                                 break;
 844                         case 1:
 845                                 unit = 'K';
 846                                 break;
 847                         case 2:
 848                                 unit = 'M';
 849                                 break;
 850                         case 3:
 851                                 unit = 'G';
 852                                 break;
 853                         case 4:
 854                                 unit = 'T';
 855                                 break;
 856                         case 5:
 857                                 /* Largest unit supported */
 858                         default:
 859                                 unit = 'P';
 860                                 break;
 861                 }
 862         } else  {
 863                 switch (unit) {
 864                         case 'R':
 865                                 /* Already raw numbers */
 866                                 unit = '\0';
 867                                 break;
 868                         case 'K':
 869                                 num /= 1000;
 870                                 break;
 871                         case 'M':
 872                                 num /= (1000*1000);
 873                                 break;
 874                         case 'G':
 875                                 num /= (1000*1000*1000);
 876                                 break;
 877                         case 'T':
 878                                 num /= (1000.0*1000.0*1000.0*1000.0);
 879                                 break;
 880                         case 'P':
 881                                 /* Largest unit supported */
 882                         default:
 883                                 num /= (1000.0*1000.0*1000.0*1000.0*1000.0);
 884                                 break;
 885                 }
 886         }
 887 
 888         if (unit == '\0')
 889                 (void) snprintf(buf, bufsize, " %7.0lf%c", num, unit);
 890         else
 891                 (void) snprintf(buf, bufsize, " %6.2lf%c", num, unit);
 892 }
 893 
 894 link_chain_t *
 895 get_link_prev_stat(datalink_id_t linkid, void *arg)
 896 {
 897         show_state_t    *state = (show_state_t *)arg;
 898         link_chain_t    *link_curr = NULL;
 899 
 900         /* Scan prev linkid list and look for entry matching this entry */
 901         for (link_curr = state->ls_linkchain; link_curr;
 902             link_curr = link_curr->lc_next) {
 903                 if (link_curr->lc_linkid == linkid)
 904                         break;
 905         }
 906                                 /* New link, add it */
 907         if (link_curr == NULL) {
 908                 link_curr = (link_chain_t *)malloc(sizeof (link_chain_t));
 909                 if (link_curr == NULL)
 910                         goto done;
 911                 link_curr->lc_linkid = linkid;
 912                 bzero(&link_curr->lc_statchain,
 913                     sizeof (link_curr->lc_statchain));
 914                 link_curr->lc_next = state->ls_linkchain;
 915                 state->ls_linkchain = link_curr;
 916         }
 917 done:
 918         return (link_curr);
 919 }
 920 
 921 /*
 922  * Number of links may change while dlstat with -i is executing.
 923  * Free memory allocated for links that are no longer there.
 924  * Prepare for next iteration by marking visited = false for existing stat
 925  * entries.
 926  */
 927 static void
 928 cleanup_removed_links(show_state_t *state)
 929 {
 930         link_chain_t    *lcurr;
 931         link_chain_t    *lprev;
 932         link_chain_t    *tofree;
 933         int             i;
 934 
 935         /* Delete all nodes from the list that have lc_visited marked false */
 936         lcurr = state->ls_linkchain;
 937         while (lcurr != NULL) {
 938                 if (lcurr->lc_visited) {
 939                         lcurr->lc_visited = B_FALSE;
 940                         lprev = lcurr;
 941                         lcurr = lcurr->lc_next;
 942                         continue;
 943                 }
 944                                 /* Is it head of the list? */
 945                 if (lcurr == state->ls_linkchain)
 946                         state->ls_linkchain = lcurr->lc_next;
 947                 else
 948                         lprev->lc_next = lcurr->lc_next;
 949                                 /* lprev remains the same */
 950                 tofree = lcurr;
 951                 lcurr = lcurr->lc_next;
 952 
 953                                 /* Free stats memory for the removed link */
 954                 for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
 955                         if (state->ls_stattype[i])
 956                                 dladm_link_stat_free(tofree->lc_statchain[i]);
 957                 }
 958                 free(tofree);
 959         }
 960 }
 961 
 962 void *
 963 print_total_stats(const char *linkname, const char *zonename, void *statentry,
 964     char unit, boolean_t parsable)
 965 {
 966         total_stat_entry_t      *sentry = statentry;
 967         total_stat_t            *link_stats = &sentry->tse_stats;
 968         total_fields_buf_t      *buf;
 969 
 970         buf = malloc(sizeof (total_fields_buf_t));
 971         if (buf == NULL)
 972                 goto done;
 973 
 974         (void) snprintf(buf->t_linkname, sizeof (buf->t_linkname), "%s",
 975             linkname);
 976         (void) snprintf(buf->t_zone, sizeof (buf->t_zone), "%s", zonename);
 977 
 978         map_to_units(buf->t_ipackets, sizeof (buf->t_ipackets),
 979             link_stats->ts_ipackets, unit, parsable);
 980 
 981         map_to_units(buf->t_rbytes, sizeof (buf->t_rbytes),
 982             link_stats->ts_rbytes, unit, parsable);
 983 
 984         map_to_units(buf->t_opackets, sizeof (buf->t_opackets),
 985             link_stats->ts_opackets, unit, parsable);
 986 
 987         map_to_units(buf->t_obytes, sizeof (buf->t_obytes),
 988             link_stats->ts_obytes, unit, parsable);
 989 
 990 done:
 991         return (buf);
 992 }
 993 
 994 void *
 995 print_rx_generic_ring_stats(const char *linkname, const char *zonename, 
 996     void *statentry, char unit, boolean_t parsable)
 997 {
 998         ring_stat_entry_t       *sentry = statentry;
 999         ring_stat_t             *link_stats = &sentry->re_stats;
1000         ring_fields_buf_t       *buf;
1001 
1002         buf = malloc(sizeof (ring_fields_buf_t));
1003         if (buf == NULL)
1004                 goto done;
1005 
1006         (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s",
1007             linkname);
1008 
1009         (void) snprintf(buf->r_type, sizeof (buf->r_type), "rx");
1010 
1011         if (sentry->re_index == DLSTAT_INVALID_ENTRY) {
1012                 (void) snprintf(buf->r_index, sizeof (buf->r_index), "--");
1013         } else {
1014                 (void) snprintf(buf->r_index, sizeof (buf->r_index),
1015                     "%llu", sentry->re_index);
1016         }
1017 
1018         map_to_units(buf->r_packets, sizeof (buf->r_packets),
1019             link_stats->r_packets, unit, parsable);
1020 
1021         map_to_units(buf->r_bytes, sizeof (buf->r_bytes),
1022             link_stats->r_bytes, unit, parsable);
1023 
1024 done:
1025         return (buf);
1026 }
1027 
1028 void *
1029 print_tx_generic_ring_stats(const char *linkname, const char *zonename,
1030     void *statentry, char unit, boolean_t parsable)
1031 {
1032         ring_stat_entry_t       *sentry = statentry;
1033         ring_stat_t             *link_stats = &sentry->re_stats;
1034         ring_fields_buf_t       *buf;
1035 
1036         buf = malloc(sizeof (ring_fields_buf_t));
1037         if (buf == NULL)
1038                 goto done;
1039 
1040         (void) snprintf(buf->r_linkname, sizeof (buf->r_linkname), "%s",
1041             linkname);
1042 
1043         (void) snprintf(buf->r_type, sizeof (buf->r_type), "tx");
1044 
1045         if (sentry->re_index == DLSTAT_INVALID_ENTRY) {
1046                 (void) snprintf(buf->r_index, sizeof (buf->r_index), "--");
1047         } else {
1048                 (void) snprintf(buf->r_index, sizeof (buf->r_index),
1049                     "%llu", sentry->re_index);
1050         }
1051 
1052         map_to_units(buf->r_packets, sizeof (buf->r_packets),
1053             link_stats->r_packets, unit, parsable);
1054 
1055         map_to_units(buf->r_bytes, sizeof (buf->r_bytes),
1056             link_stats->r_bytes, unit, parsable);
1057 
1058 done:
1059         return (buf);
1060 }
1061 
1062 void *
1063 print_rx_ring_stats(const char *linkname, const char *zonename, void *statentry,
1064     char unit, boolean_t parsable)
1065 {
1066         ring_stat_entry_t       *sentry = statentry;
1067         ring_stat_t             *link_stats = &sentry->re_stats;
1068         rx_ring_fields_buf_t    *buf;
1069 
1070         buf = malloc(sizeof (rx_ring_fields_buf_t));
1071         if (buf == NULL)
1072                 goto done;
1073 
1074         (void) snprintf(buf->rr_linkname, sizeof (buf->rr_linkname), "%s",
1075             linkname);
1076 
1077         (void) snprintf(buf->rr_type, sizeof (buf->rr_type), "rx");
1078 
1079         if (sentry->re_index == DLSTAT_INVALID_ENTRY) {
1080                 (void) snprintf(buf->rr_index, sizeof (buf->rr_index), "--");
1081         } else {
1082                 (void) snprintf(buf->rr_index, sizeof (buf->rr_index),
1083                     "%llu", sentry->re_index);
1084         }
1085 
1086         map_to_units(buf->rr_ipackets, sizeof (buf->rr_ipackets),
1087             link_stats->r_packets, unit, parsable);
1088 
1089         map_to_units(buf->rr_rbytes, sizeof (buf->rr_rbytes),
1090             link_stats->r_bytes, unit, parsable);
1091 
1092 done:
1093         return (buf);
1094 }
1095 
1096 void *
1097 print_tx_ring_stats(const char *linkname, const char *zonename, void *statentry,
1098     char unit, boolean_t parsable)
1099 {
1100         ring_stat_entry_t       *sentry = statentry;
1101         ring_stat_t             *link_stats = &sentry->re_stats;
1102         tx_ring_fields_buf_t    *buf;
1103 
1104         buf = malloc(sizeof (tx_ring_fields_buf_t));
1105         if (buf == NULL)
1106                 goto done;
1107 
1108         (void) snprintf(buf->tr_linkname, sizeof (buf->tr_linkname), "%s",
1109             linkname);
1110 
1111         (void) snprintf(buf->tr_type, sizeof (buf->tr_type), "tx");
1112 
1113         if (sentry->re_index == DLSTAT_INVALID_ENTRY) {
1114                 (void) snprintf(buf->tr_index, sizeof (buf->tr_index), "--");
1115         } else {
1116                 (void) snprintf(buf->tr_index, sizeof (buf->tr_index),
1117                     "%llu", sentry->re_index);
1118         }
1119 
1120         map_to_units(buf->tr_opackets, sizeof (buf->tr_opackets),
1121             link_stats->r_packets, unit, parsable);
1122 
1123         map_to_units(buf->tr_obytes, sizeof (buf->tr_obytes),
1124             link_stats->r_bytes, unit, parsable);
1125 
1126 done:
1127         return (buf);
1128 }
1129 
1130 void *
1131 print_rx_generic_lane_stats(const char *linkname, const char *zonename,
1132     void *statentry, char unit, boolean_t parsable)
1133 {
1134         rx_lane_stat_entry_t    *sentry = statentry;
1135         rx_lane_stat_t          *link_stats = &sentry->rle_stats;
1136         lane_fields_buf_t       *buf;
1137 
1138         if (sentry->rle_id == L_DFNCT)
1139                 return (NULL);
1140 
1141         buf = malloc(sizeof (lane_fields_buf_t));
1142         if (buf == NULL)
1143                 goto done;
1144 
1145         (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s",
1146             linkname);
1147 
1148         (void) snprintf(buf->l_type, sizeof (buf->l_type), "rx");
1149 
1150         if (sentry->rle_id == L_HWLANE)
1151                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "hw");
1152         else if (sentry->rle_id == L_SWLANE)
1153                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "sw");
1154         else if (sentry->rle_id == L_LOCAL)
1155                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "local");
1156         else if (sentry->rle_id == L_BCAST)
1157                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "bcast");
1158         else
1159                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "--");
1160 
1161         if (sentry->rle_index == DLSTAT_INVALID_ENTRY) {
1162                 (void) snprintf(buf->l_index, sizeof (buf->l_index), "--");
1163         } else {
1164                 (void) snprintf(buf->l_index, sizeof (buf->l_index),
1165                     "%llu", sentry->rle_index);
1166         }
1167 
1168         map_to_units(buf->l_packets, sizeof (buf->l_packets),
1169             link_stats->rl_ipackets, unit, parsable);
1170 
1171         map_to_units(buf->l_bytes, sizeof (buf->l_bytes),
1172             link_stats->rl_rbytes, unit, parsable);
1173 
1174 done:
1175         return (buf);
1176 }
1177 
1178 void *
1179 print_tx_generic_lane_stats(const char *linkname, const char *zonename,
1180     void *statentry, char unit, boolean_t parsable)
1181 {
1182         tx_lane_stat_entry_t    *sentry = statentry;
1183         tx_lane_stat_t          *link_stats = &sentry->tle_stats;
1184         lane_fields_buf_t       *buf;
1185 
1186         if (sentry->tle_id == L_DFNCT)
1187                 return (NULL);
1188 
1189         buf = malloc(sizeof (lane_fields_buf_t));
1190         if (buf == NULL)
1191                 goto done;
1192 
1193         (void) snprintf(buf->l_linkname, sizeof (buf->l_linkname), "%s",
1194             linkname);
1195 
1196         (void) snprintf(buf->l_type, sizeof (buf->l_type), "tx");
1197 
1198         if (sentry->tle_id == L_HWLANE)
1199                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "hw");
1200         else if (sentry->tle_id == L_SWLANE)
1201                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "sw");
1202         else if (sentry->tle_id == L_BCAST)
1203                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "bcast");
1204         else
1205                 (void) snprintf(buf->l_id, sizeof (buf->l_id), "--");
1206 
1207         if (sentry->tle_index == DLSTAT_INVALID_ENTRY) {
1208                 (void) snprintf(buf->l_index, sizeof (buf->l_index), "--");
1209         } else {
1210                 (void) snprintf(buf->l_index, sizeof (buf->l_index),
1211                     "%llu", sentry->tle_index);
1212         }
1213         map_to_units(buf->l_packets, sizeof (buf->l_packets),
1214             link_stats->tl_opackets, unit, parsable);
1215 
1216         map_to_units(buf->l_bytes, sizeof (buf->l_bytes),
1217             link_stats->tl_obytes, unit, parsable);
1218 
1219 done:
1220         return (buf);
1221 }
1222 
1223 void *
1224 print_rx_lane_stats(const char *linkname, const char *zonename, void *statentry,
1225     char unit, boolean_t parsable)
1226 {
1227         rx_lane_stat_entry_t    *sentry = statentry;
1228         rx_lane_stat_t          *link_stats = &sentry->rle_stats;
1229         rx_lane_fields_buf_t    *buf;
1230 
1231         if (sentry->rle_id == L_DFNCT)
1232                 return (NULL);
1233 
1234         buf = malloc(sizeof (rx_lane_fields_buf_t));
1235         if (buf == NULL)
1236                 goto done;
1237 
1238         (void) snprintf(buf->rl_linkname, sizeof (buf->rl_linkname), "%s",
1239             linkname);
1240 
1241         (void) snprintf(buf->rl_type, sizeof (buf->rl_type), "rx");
1242 
1243         if (sentry->rle_id == L_HWLANE)
1244                 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "hw");
1245         else if (sentry->rle_id == L_SWLANE)
1246                 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "sw");
1247         else if (sentry->rle_id == L_LOCAL)
1248                 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "local");
1249         else if (sentry->rle_id == L_BCAST)
1250                 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "bcast");
1251         else
1252                 (void) snprintf(buf->rl_id, sizeof (buf->rl_id), "--");
1253 
1254         if (sentry->rle_index == DLSTAT_INVALID_ENTRY) {
1255                 (void) snprintf(buf->rl_index, sizeof (buf->rl_index), "--");
1256         } else {
1257                 (void) snprintf(buf->rl_index, sizeof (buf->rl_index),
1258                     "%llu", sentry->rle_index);
1259         }
1260 
1261         map_to_units(buf->rl_ipackets, sizeof (buf->rl_ipackets),
1262             link_stats->rl_ipackets, unit, parsable);
1263 
1264         map_to_units(buf->rl_rbytes, sizeof (buf->rl_rbytes),
1265             link_stats->rl_rbytes, unit, parsable);
1266 
1267         map_to_units(buf->rl_intrs, sizeof (buf->rl_intrs),
1268             link_stats->rl_intrs, unit, parsable);
1269 
1270         map_to_units(buf->rl_polls, sizeof (buf->rl_polls),
1271             link_stats->rl_polls, unit, parsable);
1272 
1273         map_to_units(buf->rl_sdrops, sizeof (buf->rl_sdrops),
1274             link_stats->rl_sdrops, unit, parsable);
1275 
1276         map_to_units(buf->rl_chl10, sizeof (buf->rl_chl10),
1277             link_stats->rl_chl10, unit, parsable);
1278 
1279         map_to_units(buf->rl_ch10_50, sizeof (buf->rl_ch10_50),
1280             link_stats->rl_ch10_50, unit, parsable);
1281 
1282         map_to_units(buf->rl_chg50, sizeof (buf->rl_chg50),
1283             link_stats->rl_chg50, unit, parsable);
1284 
1285 done:
1286         return (buf);
1287 }
1288 
1289 void *
1290 print_tx_lane_stats(const char *linkname, const char *zonename, void *statentry,
1291     char unit, boolean_t parsable) {
1292         tx_lane_stat_entry_t    *sentry = statentry;
1293         tx_lane_stat_t          *link_stats = &sentry->tle_stats;
1294         tx_lane_fields_buf_t    *buf = NULL;
1295 
1296         if (sentry->tle_id == L_DFNCT)
1297                 return (NULL);
1298 
1299         buf = malloc(sizeof (tx_lane_fields_buf_t));
1300         if (buf == NULL)
1301                 goto done;
1302 
1303         (void) snprintf(buf->tl_linkname, sizeof (buf->tl_linkname), "%s",
1304             linkname);
1305 
1306         (void) snprintf(buf->tl_type, sizeof (buf->tl_type), "tx");
1307 
1308         if (sentry->tle_id == L_HWLANE)
1309                 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "hw");
1310         else if (sentry->tle_id == L_SWLANE)
1311                 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "sw");
1312         else if (sentry->tle_id == L_BCAST)
1313                 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "bcast");
1314         else
1315                 (void) snprintf(buf->tl_id, sizeof (buf->tl_id), "--");
1316 
1317         if (sentry->tle_index == DLSTAT_INVALID_ENTRY) {
1318                 (void) snprintf(buf->tl_index, sizeof (buf->tl_index), "--");
1319         } else {
1320                 (void) snprintf(buf->tl_index, sizeof (buf->tl_index),
1321                     "%llu", sentry->tle_index);
1322         }
1323 
1324         map_to_units(buf->tl_opackets, sizeof (buf->tl_opackets),
1325             link_stats->tl_opackets, unit, parsable);
1326 
1327         map_to_units(buf->tl_obytes, sizeof (buf->tl_obytes),
1328             link_stats->tl_obytes, unit, parsable);
1329 
1330         map_to_units(buf->tl_blockcnt, sizeof (buf->tl_blockcnt),
1331             link_stats->tl_blockcnt, unit, parsable);
1332 
1333         map_to_units(buf->tl_unblockcnt, sizeof (buf->tl_unblockcnt),
1334             link_stats->tl_unblockcnt, unit, parsable);
1335 
1336         map_to_units(buf->tl_sdrops, sizeof (buf->tl_sdrops),
1337             link_stats->tl_sdrops, unit, parsable);
1338 
1339 done:
1340         return (buf);
1341 }
1342 
1343 void *
1344 print_fanout_stats(const char *linkname, const char *zonename, void *statentry,
1345     char unit, boolean_t parsable)
1346 {
1347         fanout_stat_entry_t             *sentry = statentry;
1348         fanout_stat_t                   *link_stats = &sentry->fe_stats;
1349         rx_fanout_lane_fields_buf_t     *buf;
1350 
1351         buf = malloc(sizeof (rx_fanout_lane_fields_buf_t));
1352         if (buf == NULL)
1353                 goto done;
1354 
1355         (void) snprintf(buf->rfl_linkname, sizeof (buf->rfl_linkname), "%s",
1356             linkname);
1357 
1358         (void) snprintf(buf->rfl_type, sizeof (buf->rfl_type), "rx");
1359 
1360         if (sentry->fe_id == L_HWLANE)
1361                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "hw");
1362         else if (sentry->fe_id == L_SWLANE)
1363                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "sw");
1364         else if (sentry->fe_id == L_LCLSWLANE)
1365                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "lcl/sw");
1366         else if (sentry->fe_id == L_LOCAL)
1367                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "local");
1368         else if (sentry->fe_id == L_BCAST)
1369                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "bcast");
1370         else
1371                 (void) snprintf(buf->rfl_id, sizeof (buf->rfl_id), "--");
1372 
1373         if (sentry->fe_index == DLSTAT_INVALID_ENTRY) {
1374                 (void) snprintf(buf->rfl_index, sizeof (buf->rfl_index), "--");
1375         } else {
1376                 (void) snprintf(buf->rfl_index, sizeof (buf->rfl_index),
1377                     "%llu", sentry->fe_index);
1378         }
1379 
1380         if (sentry->fe_foutindex == DLSTAT_INVALID_ENTRY)
1381                 (void) snprintf(buf->rfl_fout, sizeof (buf->rfl_fout), "--");
1382         else {
1383                 (void) snprintf(buf->rfl_fout, sizeof (buf->rfl_fout), "%llu",
1384                     sentry->fe_foutindex);
1385         }
1386 
1387         map_to_units(buf->rfl_ipackets, sizeof (buf->rfl_ipackets),
1388             link_stats->f_ipackets, unit, parsable);
1389 
1390         map_to_units(buf->rfl_rbytes, sizeof (buf->rfl_rbytes),
1391             link_stats->f_rbytes, unit, parsable);
1392 
1393 done:
1394         return (buf);
1395 }
1396 
1397 void *
1398 print_aggr_port_stats(const char *linkname, const char *zonename,
1399     void *statentry, char unit, boolean_t parsable)
1400 {
1401         aggr_port_stat_entry_t  *sentry = statentry;
1402         aggr_port_stat_t        *link_stats = &sentry->ape_stats;
1403         aggr_port_fields_buf_t  *buf;
1404         char                    portname[MAXLINKNAMELEN];
1405 
1406         buf = malloc(sizeof (aggr_port_fields_buf_t));
1407         if (buf == NULL)
1408                 goto done;
1409 
1410         (void) snprintf(buf->ap_linkname, sizeof (buf->ap_linkname), "%s",
1411             linkname);
1412 
1413         if (dladm_datalink_id2info(handle, sentry->ape_portlinkid, NULL,
1414             NULL, NULL, portname, DLPI_LINKNAME_MAX)
1415             != DLADM_STATUS_OK) {
1416                 (void) snprintf(buf->ap_portname,
1417                     sizeof (buf->ap_portname), "--");
1418         } else {
1419                 (void) snprintf(buf->ap_portname,
1420                     sizeof (buf->ap_portname), "%s", portname);
1421         }
1422 
1423         map_to_units(buf->ap_ipackets, sizeof (buf->ap_ipackets),
1424             link_stats->ap_ipackets, unit, parsable);
1425 
1426         map_to_units(buf->ap_rbytes, sizeof (buf->ap_rbytes),
1427             link_stats->ap_rbytes, unit, parsable);
1428 
1429         map_to_units(buf->ap_opackets, sizeof (buf->ap_opackets),
1430             link_stats->ap_opackets, unit, parsable);
1431 
1432         map_to_units(buf->ap_obytes, sizeof (buf->ap_obytes),
1433             link_stats->ap_obytes, unit, parsable);
1434 
1435 done:
1436         return (buf);
1437 }
1438 
1439 dladm_stat_chain_t *
1440 query_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg,
1441     dladm_stat_type_t stattype)
1442 {
1443         link_chain_t            *link_node;
1444         dladm_stat_chain_t      *curr_stat;
1445         dladm_stat_chain_t      *prev_stat = NULL;
1446         dladm_stat_chain_t      *diff_stat = NULL;
1447 
1448         /*  Get prev iteration stat for this link */
1449         link_node = get_link_prev_stat(linkid, arg);
1450         if (link_node == NULL)
1451                 goto done;
1452 
1453         link_node->lc_visited = B_TRUE;
1454         prev_stat = link_node->lc_statchain[stattype];
1455 
1456         /* Query library for current stats */
1457         curr_stat = dladm_link_stat_query(dh, linkid, stattype);
1458         if (curr_stat == NULL)
1459                 goto done;
1460 
1461         /* current stats - prev iteration stats */
1462         diff_stat = dladm_link_stat_diffchain(curr_stat, prev_stat, stattype);
1463 
1464         /* Free prev stats */
1465         dladm_link_stat_free(prev_stat);
1466 
1467         /* Prev <- curr stats */
1468         link_node->lc_statchain[stattype] = curr_stat;
1469 
1470 done:
1471         return (diff_stat);
1472 }
1473 
1474 void
1475 walk_dlstat_stats(show_state_t *state, const char *linkname,
1476     const char *zonename, dladm_stat_type_t stattype,
1477     dladm_stat_chain_t *diff_stat)
1478 {
1479         dladm_stat_chain_t  *curr;
1480 
1481         /* Unpack invidual stat entry and call library consumer's callback */
1482         for (curr = diff_stat; curr != NULL; curr = curr->dc_next) {
1483                 void    *fields_buf;
1484 
1485                 /* Format the raw numbers for printing */
1486                 fields_buf = state->ls_stats2str[stattype](linkname,
1487                     zonename, curr->dc_statentry, state->ls_unit,
1488                     state->ls_parsable);
1489                 /* Print the stats */
1490                 if (fields_buf != NULL)
1491                         ofmt_print(state->ls_ofmt, fields_buf);
1492                 free(fields_buf);
1493         }
1494 }
1495 
1496 static int
1497 show_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1498 {
1499         show_state_t            *state = arg;
1500         int                     i;
1501         dladm_stat_chain_t      *diff_stat;
1502         char                    linkname[DLPI_LINKNAME_MAX];
1503         char                    zonename[DLADM_PROP_VAL_MAX + 1];
1504         char                    *valptr[1];
1505         uint_t                  valcnt = 1;
1506 
1507         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1508             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
1509                 goto done;
1510         }
1511 
1512         valptr[0] = zonename;
1513         if (dladm_get_linkprop(handle, linkid, DLADM_PROP_VAL_CURRENT, "zone",
1514             (char **)valptr, &valcnt) != 0)
1515                 zonename[0] = '\0';
1516 
1517         for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
1518                 if (state->ls_stattype[i]) {
1519                         /*
1520                          * Query library for stats
1521                          * Stats are returned as chain of raw numbers
1522                          */
1523                         diff_stat = query_link_stats(handle, linkid, arg, i);
1524                         walk_dlstat_stats(state, linkname, zonename, i,
1525                             diff_stat);
1526                         dladm_link_stat_free(diff_stat);
1527                 }
1528         }
1529 done:
1530         return (DLADM_WALK_CONTINUE);
1531 }
1532 
1533 void
1534 show_link_stats(datalink_id_t linkid, show_state_t state, uint32_t interval)
1535 {
1536         for (;;) {
1537                 if (linkid == DATALINK_ALL_LINKID) {
1538                         (void) dladm_walk_datalink_id(show_queried_stats,
1539                             handle, &state, DATALINK_CLASS_ALL,
1540                             DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1541                 } else {
1542                         (void) show_queried_stats(handle, linkid, &state);
1543                 }
1544 
1545                 if (interval == 0)
1546                         break;
1547 
1548                 cleanup_removed_links(&state);
1549                 (void) sleep(interval);
1550         }
1551 }
1552 
1553 void
1554 print_all_stats(dladm_handle_t dh, datalink_id_t linkid,
1555     dladm_stat_chain_t *stat_chain)
1556 {
1557         dladm_stat_chain_t      *curr;
1558         name_value_stat_entry_t *stat_entry;
1559         name_value_stat_t       *curr_stat;
1560         boolean_t               stat_printed = B_FALSE;
1561         char                    linkname[MAXLINKNAMELEN];
1562         char                    prev_linkname[MAXLINKNAMELEN];
1563 
1564         if (dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, linkname,
1565             DLPI_LINKNAME_MAX) != DLADM_STATUS_OK)
1566                 return;
1567 
1568         for (curr = stat_chain; curr != NULL; curr = curr->dc_next) {
1569                 stat_entry = curr->dc_statentry;
1570                 /*
1571                  * Print header
1572                  * If link name is already printed in previous iteration,
1573                  * don't print again
1574                  */
1575                 if (strcmp(prev_linkname, linkname) != 0)
1576                         printf("%s \n", linkname);
1577                 printf("  %s \n", stat_entry->nve_header);
1578 
1579                 /* Print stat fields */
1580                 for (curr_stat = stat_entry->nve_stats; curr_stat != NULL;
1581                     curr_stat = curr_stat->nv_nextstat) {
1582                         printf("\t%15s", curr_stat->nv_statname);
1583                         printf("\t\t%15llu\n", curr_stat->nv_statval);
1584                 }
1585 
1586                 strncpy(prev_linkname, linkname, MAXLINKNAMELEN);
1587                 stat_printed = B_TRUE;
1588         }
1589         if (stat_printed)
1590                 printf("---------------------------------------------------\n");
1591 }
1592 
1593 static int
1594 dump_queried_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg)
1595 {
1596         boolean_t               *stattype = arg;
1597         int                     i;
1598         dladm_stat_chain_t      *stat_chain;
1599 
1600         for (i = 0; i < DLADM_STAT_NUM_STATS; i++) {
1601                 if (stattype[i]) {
1602                         stat_chain = dladm_link_stat_query_all(dh, linkid, i);
1603                         print_all_stats(dh, linkid, stat_chain);
1604                         dladm_link_stat_query_all_free(stat_chain);
1605                 }
1606         }
1607 done:
1608         return (DLADM_WALK_CONTINUE);
1609 }
1610 
1611 void
1612 dump_all_link_stats(datalink_id_t linkid, boolean_t *stattype)
1613 {
1614         if (linkid == DATALINK_ALL_LINKID) {
1615                 (void) dladm_walk_datalink_id(dump_queried_stats,
1616                     handle, stattype, DATALINK_CLASS_ALL,
1617                     DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1618         } else {
1619                 (void) dump_queried_stats(handle, linkid, stattype);
1620         }
1621 }
1622 
1623 static void
1624 do_show(int argc, char *argv[], const char *use)
1625 {
1626         int                     option;
1627         boolean_t               r_arg = B_FALSE;
1628         boolean_t               t_arg = B_FALSE;
1629         boolean_t               i_arg = B_FALSE;
1630         boolean_t               p_arg = B_FALSE;
1631         boolean_t               o_arg = B_FALSE;
1632         boolean_t               u_arg = B_FALSE;
1633         boolean_t               a_arg = B_FALSE;
1634         boolean_t               A_arg = B_FALSE;
1635         uint32_t                flags = DLADM_OPT_ACTIVE;
1636         datalink_id_t           linkid = DATALINK_ALL_LINKID;
1637         uint32_t                interval = 0;
1638         char                    unit = '\0';
1639         show_state_t            state;
1640         dladm_status_t          status;
1641         char                    *fields_str = NULL;
1642         char                    *o_fields_str = NULL;
1643 
1644         char                    *total_stat_fields =
1645             "link,ipkts,rbytes,opkts,obytes,zone";
1646         char                    *rx_total_stat_fields =
1647             "link,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
1648         char                    *tx_total_stat_fields =
1649             "link,opkts,obytes,blkcnt,ublkcnt";
1650 
1651         ofmt_handle_t           ofmt;
1652         ofmt_status_t           oferr;
1653         uint_t                  ofmtflags = OFMT_RIGHTJUST;
1654         ofmt_field_t            *oftemplate;
1655 
1656         bzero(&state, sizeof (state));
1657         opterr = 0;
1658         while ((option = getopt_long(argc, argv, ":rtaApi:o:u:",
1659             NULL, NULL)) != -1) {
1660                 switch (option) {
1661                 case 'r':
1662                         if (r_arg)
1663                                 die_optdup(option);
1664 
1665                         r_arg = B_TRUE;
1666                         break;
1667                 case 't':
1668                         if (t_arg)
1669                                 die_optdup(option);
1670 
1671                         t_arg = B_TRUE;
1672                         break;
1673                 case 'a':
1674                         if (a_arg)
1675                                 die_optdup(option);
1676 
1677                         a_arg = B_TRUE;
1678                         break;
1679                 case 'A':
1680                         if (A_arg)
1681                                 die_optdup(option);
1682 
1683                         A_arg = B_TRUE;
1684                         break;
1685                 case 'i':
1686                         if (i_arg)
1687                                 die_optdup(option);
1688 
1689                         i_arg = B_TRUE;
1690                         if (!dladm_str2interval(optarg, &interval))
1691                                 die("invalid interval value '%s'", optarg);
1692                         break;
1693                 case 'p':
1694                         if (p_arg)
1695                                 die_optdup(option);
1696 
1697                         p_arg = B_TRUE;
1698                         break;
1699                 case 'o':
1700                         o_arg = B_TRUE;
1701                         o_fields_str = optarg;
1702                         break;
1703                 case 'u':
1704                         if (u_arg)
1705                                 die_optdup(option);
1706 
1707                         u_arg = B_TRUE;
1708                         if (!dlstat_unit(optarg, &unit))
1709                                 die("invalid unit value '%s',"
1710                                     "unit must be R|K|M|G|T|P", optarg);
1711                         break;
1712                 default:
1713                         die_opterr(optopt, option, use);
1714                         break;
1715                 }
1716         }
1717 
1718         if (r_arg && t_arg)
1719                 die("the options -t and -r are not compatible");
1720 
1721         if (u_arg && p_arg)
1722                 die("the options -u and -p are not compatible");
1723 
1724         if (p_arg && !o_arg)
1725                 die("-p requires -o");
1726 
1727         if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1728                 die("\"-o all\" is invalid with -p");
1729 
1730         if (a_arg && A_arg)
1731                 die("the options -a and -A are not compatible");
1732 
1733         if (a_arg &&
1734             (p_arg || o_arg || u_arg || i_arg)) {
1735                 die("the option -a is not compatible with "
1736                     "-p, -o, -u, -i");
1737         }
1738 
1739         if (A_arg &&
1740             (r_arg || t_arg || p_arg || o_arg || u_arg || i_arg)) {
1741                 die("the option -A is not compatible with "
1742                     "-r, -t, -p, -o, -u, -i");
1743         }
1744 
1745         /* get link name (optional last argument) */
1746         if (optind == (argc-1)) {
1747                 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1748                         die("link name too long");
1749 
1750                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
1751                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
1752                         die_dlerr(status, "link %s is not valid", argv[optind]);
1753                 }
1754         } else if (optind != argc) {
1755                 if (argc != 0)
1756                         usage();
1757         }
1758 
1759         if (a_arg) {
1760                 boolean_t       stattype[DLADM_STAT_NUM_STATS];
1761 
1762                 bzero(&stattype, sizeof (stattype));
1763                 if (r_arg) {
1764                         stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE;
1765                 } else if (t_arg) {
1766                         stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE;
1767                 } else {                /* Display both Rx and Tx lanes */
1768                         stattype[DLADM_STAT_TOTAL] = B_TRUE;
1769                 }
1770 
1771                 dump_all_link_stats(linkid, stattype);
1772                 return;
1773         }
1774 
1775         if (A_arg) {
1776                 boolean_t       stattype[DLADM_STAT_NUM_STATS];
1777                 int             i;
1778 
1779                 for (i = 0; i < DLADM_STAT_NUM_STATS; i++)
1780                         stattype[i] = B_TRUE;
1781 
1782                 dump_all_link_stats(linkid, stattype);
1783                 return;
1784         }
1785 
1786         state.ls_unit = unit;
1787         state.ls_parsable = p_arg;
1788 
1789         if (state.ls_parsable)
1790                 ofmtflags |= OFMT_PARSABLE;
1791 
1792         if (r_arg) {
1793                 fields_str = rx_total_stat_fields;
1794                 oftemplate = rx_lane_s_fields;
1795                 state.ls_stattype[DLADM_STAT_RX_LANE_TOTAL] = B_TRUE;
1796                 state.ls_stats2str[DLADM_STAT_RX_LANE_TOTAL] =
1797                     print_rx_lane_stats;
1798         } else if (t_arg) {
1799                 fields_str = tx_total_stat_fields;
1800                 oftemplate = tx_lane_s_fields;
1801                 state.ls_stattype[DLADM_STAT_TX_LANE_TOTAL] = B_TRUE;
1802                 state.ls_stats2str[DLADM_STAT_TX_LANE_TOTAL] =
1803                     print_tx_lane_stats;
1804         } else {                /* Display both Rx and Tx lanes total */
1805                 fields_str = total_stat_fields;
1806                 oftemplate = total_s_fields;
1807                 state.ls_stattype[DLADM_STAT_TOTAL] = B_TRUE;
1808                 state.ls_stats2str[DLADM_STAT_TOTAL] = print_total_stats;
1809         }
1810 
1811         if (o_arg) {
1812                 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1813                     fields_str : o_fields_str;
1814         }
1815 
1816         oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1817         dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
1818         state.ls_ofmt = ofmt;
1819 
1820         show_link_stats(linkid, state, interval);
1821 
1822         ofmt_close(ofmt);
1823 }
1824 
1825 static void
1826 do_show_phys(int argc, char *argv[], const char *use)
1827 {
1828         int                     option;
1829         boolean_t               r_arg = B_FALSE;
1830         boolean_t               t_arg = B_FALSE;
1831         boolean_t               i_arg = B_FALSE;
1832         boolean_t               p_arg = B_FALSE;
1833         boolean_t               o_arg = B_FALSE;
1834         boolean_t               u_arg = B_FALSE;
1835         boolean_t               a_arg = B_FALSE;
1836         uint32_t                flags = DLADM_OPT_ACTIVE;
1837         datalink_id_t           linkid = DATALINK_ALL_LINKID;
1838         char                    linkname[MAXLINKNAMELEN];
1839         uint32_t                interval = 0;
1840         char                    unit = '\0';
1841         show_state_t            state;
1842         dladm_status_t          status;
1843         char                    *fields_str = NULL;
1844         char                    *o_fields_str = NULL;
1845         char                    *ring_stat_fields =
1846             "link,type,index,pkts,bytes";
1847         char                    *rx_ring_stat_fields =
1848             "link,type,index,ipkts,rbytes";
1849         char                    *tx_ring_stat_fields =
1850             "link,type,index,opkts,obytes";
1851 
1852         ofmt_handle_t           ofmt;
1853         ofmt_status_t           oferr;
1854         uint_t                  ofmtflags = OFMT_RIGHTJUST;
1855         ofmt_field_t            *oftemplate;
1856 
1857         bzero(&state, sizeof (state));
1858         opterr = 0;
1859         while ((option = getopt_long(argc, argv, ":rtapi:o:u:",
1860             NULL, NULL)) != -1) {
1861                 switch (option) {
1862                 case 'r':
1863                         if (r_arg)
1864                                 die_optdup(option);
1865 
1866                         r_arg = B_TRUE;
1867                         break;
1868                 case 't':
1869                         if (t_arg)
1870                                 die_optdup(option);
1871 
1872                         t_arg = B_TRUE;
1873                         break;
1874                 case 'a':
1875                         if (a_arg)
1876                                 die_optdup(option);
1877 
1878                         a_arg = B_TRUE;
1879                         break;
1880                 case 'i':
1881                         if (i_arg)
1882                                 die_optdup(option);
1883 
1884                         i_arg = B_TRUE;
1885                         if (!dladm_str2interval(optarg, &interval))
1886                                 die("invalid interval value '%s'", optarg);
1887                         break;
1888                 case 'p':
1889                         if (p_arg)
1890                                 die_optdup(option);
1891 
1892                         p_arg = B_TRUE;
1893                         break;
1894                 case 'o':
1895                         o_arg = B_TRUE;
1896                         o_fields_str = optarg;
1897                         break;
1898                 case 'u':
1899                         if (u_arg)
1900                                 die_optdup(option);
1901 
1902                         u_arg = B_TRUE;
1903                         if (!dlstat_unit(optarg, &unit))
1904                                 die("invalid unit value '%s',"
1905                                     "unit must be R|K|M|G|T|P", optarg);
1906                         break;
1907                 default:
1908                         die_opterr(optopt, option, use);
1909                         break;
1910                 }
1911         }
1912 
1913         if (r_arg && t_arg)
1914                 die("the options -t and -r are not compatible");
1915 
1916         if (u_arg && p_arg)
1917                 die("the options -u and -p are not compatible");
1918 
1919         if (p_arg && !o_arg)
1920                 die("-p requires -o");
1921 
1922         if (p_arg && strcasecmp(o_fields_str, "all") == 0)
1923                 die("\"-o all\" is invalid with -p");
1924 
1925         if (a_arg &&
1926             (p_arg || o_arg || u_arg || i_arg)) {
1927                 die("the option -a is not compatible with "
1928                     "-p, -o, -u, -i");
1929         }
1930 
1931 
1932         /* get link name (optional last argument) */
1933         if (optind == (argc-1)) {
1934                 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
1935                         die("link name too long");
1936 
1937                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
1938                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
1939                         die_dlerr(status, "link %s is not valid", argv[optind]);
1940                 }
1941         } else if (optind != argc) {
1942                 usage();
1943         }
1944 
1945         if (a_arg) {
1946                 boolean_t       stattype[DLADM_STAT_NUM_STATS];
1947 
1948                 bzero(&stattype, sizeof (stattype));
1949 
1950                 if (r_arg) {
1951                         stattype[DLADM_STAT_RX_RING] = B_TRUE;
1952                 } else if (t_arg) {
1953                         stattype[DLADM_STAT_TX_RING] = B_TRUE;
1954                 } else {                /* Display both Rx and Tx lanes */
1955                         stattype[DLADM_STAT_RX_RING] = B_TRUE;
1956                         stattype[DLADM_STAT_TX_RING] = B_TRUE;
1957                 }
1958 
1959                 dump_all_link_stats(linkid, stattype);
1960                 return;
1961         }
1962 
1963         state.ls_unit = unit;
1964         state.ls_parsable = p_arg;
1965 
1966         if (state.ls_parsable)
1967                 ofmtflags |= OFMT_PARSABLE;
1968 
1969         if (r_arg) {
1970                 fields_str = rx_ring_stat_fields;
1971                 oftemplate = rx_ring_s_fields;
1972                 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE;
1973                 state.ls_stats2str[DLADM_STAT_RX_RING] = print_rx_ring_stats;
1974         } else if (t_arg) {
1975                 fields_str = tx_ring_stat_fields;
1976                 oftemplate = tx_ring_s_fields;
1977                 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE;
1978                 state.ls_stats2str[DLADM_STAT_TX_RING] = print_tx_ring_stats;
1979         } else {                /* Display both Rx and Tx lanes */
1980                 fields_str = ring_stat_fields;
1981                 oftemplate = ring_s_fields;
1982                 state.ls_stattype[DLADM_STAT_RX_RING] = B_TRUE;
1983                 state.ls_stattype[DLADM_STAT_TX_RING] = B_TRUE;
1984                 state.ls_stats2str[DLADM_STAT_RX_RING] =
1985                     print_rx_generic_ring_stats;
1986                 state.ls_stats2str[DLADM_STAT_TX_RING] =
1987                     print_tx_generic_ring_stats;
1988         }
1989 
1990         if (o_arg) {
1991                 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
1992                     fields_str : o_fields_str;
1993         }
1994 
1995         oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
1996         dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
1997         state.ls_ofmt = ofmt;
1998 
1999         show_link_stats(linkid, state, interval);
2000 
2001         ofmt_close(ofmt);
2002 }
2003 
2004 static void
2005 do_show_link(int argc, char *argv[], const char *use)
2006 {
2007         int                     option;
2008         boolean_t               r_arg = B_FALSE;
2009         boolean_t               F_arg = B_FALSE;
2010         boolean_t               t_arg = B_FALSE;
2011         boolean_t               i_arg = B_FALSE;
2012         boolean_t               p_arg = B_FALSE;
2013         boolean_t               o_arg = B_FALSE;
2014         boolean_t               u_arg = B_FALSE;
2015         boolean_t               a_arg = B_FALSE;
2016         uint32_t                flags = DLADM_OPT_ACTIVE;
2017         datalink_id_t           linkid = DATALINK_ALL_LINKID;
2018         uint32_t                interval = 0;
2019         char                    unit = '\0';
2020         show_state_t            state;
2021         dladm_status_t          status;
2022         char                    *fields_str = NULL;
2023         char                    *o_fields_str = NULL;
2024 
2025         char                    *lane_stat_fields =
2026             "link,type,id,index,pkts,bytes";
2027         char                    *rx_lane_stat_fields =
2028             "link,type,id,index,ipkts,rbytes,intrs,polls,ch<10,ch10-50,ch>50";
2029         char                    *tx_lane_stat_fields =
2030             "link,type,id,index,opkts,obytes,blkcnt,ublkcnt";
2031         char                    *rx_fanout_stat_fields =
2032             "link,id,index,fout,ipkts,rbytes";
2033 
2034         ofmt_handle_t           ofmt;
2035         ofmt_status_t           oferr;
2036         uint_t                  ofmtflags = OFMT_RIGHTJUST;
2037         ofmt_field_t            *oftemplate;
2038 
2039         bzero(&state, sizeof (state));
2040         opterr = 0;
2041         while ((option = getopt_long(argc, argv, ":hrtFapi:o:u:",
2042             NULL, NULL)) != -1) {
2043                 switch (option) {
2044                 case 'h':
2045                         if (r_arg || F_arg || t_arg || i_arg || p_arg ||
2046                             o_arg || u_arg || a_arg) {
2047                                 die("the option -h is not compatible with "
2048                                     "-r, -F, -t, -i, -p, -o, -u, -a");
2049                         }
2050                         do_show_history(argc, &argv[0], use);
2051                         return;
2052                 case 'r':
2053                         if (r_arg)
2054                                 die_optdup(option);
2055 
2056                         r_arg = B_TRUE;
2057                         break;
2058                 case 'F':
2059                         if (F_arg)
2060                                 die_optdup(option);
2061 
2062                         F_arg = B_TRUE;
2063                         break;
2064                 case 't':
2065                         if (t_arg)
2066                                 die_optdup(option);
2067 
2068                         t_arg = B_TRUE;
2069                         break;
2070                 case 'a':
2071                         if (a_arg)
2072                                 die_optdup(option);
2073 
2074                         a_arg = B_TRUE;
2075                         break;
2076                 case 'i':
2077                         if (i_arg)
2078                                 die_optdup(option);
2079 
2080                         i_arg = B_TRUE;
2081                         if (!dladm_str2interval(optarg, &interval))
2082                                 die("invalid interval value '%s'", optarg);
2083                         break;
2084                 case 'p':
2085                         if (p_arg)
2086                                 die_optdup(option);
2087 
2088                         p_arg = B_TRUE;
2089                         break;
2090                 case 'o':
2091                         o_arg = B_TRUE;
2092                         o_fields_str = optarg;
2093                         break;
2094                 case 'u':
2095                         if (u_arg)
2096                                 die_optdup(option);
2097 
2098                         u_arg = B_TRUE;
2099                         if (!dlstat_unit(optarg, &unit))
2100                                 die("invalid unit value '%s',"
2101                                     "unit must be R|K|M|G|T|P", optarg);
2102                         break;
2103                 default:
2104                         die_opterr(optopt, option, use);
2105                         break;
2106                 }
2107         }
2108 
2109         if (r_arg && t_arg)
2110                 die("the options -t and -r are not compatible");
2111 
2112         if (u_arg && p_arg)
2113                 die("the options -u and -p are not compatible");
2114 
2115         if (F_arg && !r_arg)
2116                 die("-F must be used with -r");
2117 
2118         if (p_arg && !o_arg)
2119                 die("-p requires -o");
2120 
2121         if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2122                 die("\"-o all\" is invalid with -p");
2123 
2124         if (a_arg &&
2125             (p_arg || o_arg || u_arg || i_arg)) {
2126                 die("the option -a is not compatible with "
2127                     "-p, -o, -u, -i");
2128         }
2129 
2130         /* get link name (optional last argument) */
2131         if (optind == (argc-1)) {
2132                 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2133                         die("link name too long");
2134 
2135                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
2136                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2137                         die_dlerr(status, "link %s is not valid", argv[optind]);
2138                 }
2139         } else if (optind != argc) {
2140                 usage();
2141         }
2142 
2143         if (a_arg) {
2144                 boolean_t       stattype[DLADM_STAT_NUM_STATS];
2145 
2146                 bzero(&stattype, sizeof (stattype));
2147 
2148                 if (r_arg) {
2149                         if (F_arg) {
2150                                 stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE;
2151                         } else {
2152                                 stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2153                         }
2154                 } else if (t_arg) {
2155                         stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2156                 } else {                /* Display both Rx and Tx lanes */
2157                         stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2158                         stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2159                 }
2160 
2161                 dump_all_link_stats(linkid, stattype);
2162                 return;
2163         }
2164 
2165         state.ls_unit = unit;
2166         state.ls_parsable = p_arg;
2167 
2168         if (state.ls_parsable)
2169                 ofmtflags |= OFMT_PARSABLE;
2170 
2171         if (r_arg) {
2172                 if (F_arg) {
2173                         fields_str = rx_fanout_stat_fields;
2174                         oftemplate = rx_fanout_lane_s_fields;
2175                         state.ls_stattype[DLADM_STAT_RX_LANE_FOUT] = B_TRUE;
2176                         state.ls_stats2str[DLADM_STAT_RX_LANE_FOUT] =
2177                             print_fanout_stats;
2178                 } else {
2179                         fields_str = rx_lane_stat_fields;
2180                         oftemplate = rx_lane_s_fields;
2181                         state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2182                         state.ls_stats2str[DLADM_STAT_RX_LANE] =
2183                             print_rx_lane_stats;
2184                 }
2185         } else if (t_arg) {
2186                 fields_str = tx_lane_stat_fields;
2187                 oftemplate = tx_lane_s_fields;
2188                 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2189                 state.ls_stats2str[DLADM_STAT_TX_LANE] = print_tx_lane_stats;
2190         } else {                /* Display both Rx and Tx lanes */
2191                 fields_str = lane_stat_fields;
2192                 oftemplate = lane_s_fields;
2193                 state.ls_stattype[DLADM_STAT_RX_LANE] = B_TRUE;
2194                 state.ls_stattype[DLADM_STAT_TX_LANE] = B_TRUE;
2195                 state.ls_stats2str[DLADM_STAT_RX_LANE] =
2196                     print_rx_generic_lane_stats;
2197                 state.ls_stats2str[DLADM_STAT_TX_LANE] =
2198                     print_tx_generic_lane_stats;
2199         }
2200         if (o_arg) {
2201                 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2202                     fields_str : o_fields_str;
2203         }
2204 
2205         oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2206         dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
2207 
2208         state.ls_ofmt = ofmt;
2209 
2210         show_link_stats(linkid, state, interval);
2211 
2212         ofmt_close(ofmt);
2213 }
2214 
2215 static void
2216 do_show_aggr(int argc, char *argv[], const char *use)
2217 {
2218         int                     option;
2219         boolean_t               r_arg = B_FALSE;
2220         boolean_t               t_arg = B_FALSE;
2221         boolean_t               i_arg = B_FALSE;
2222         boolean_t               p_arg = B_FALSE;
2223         boolean_t               o_arg = B_FALSE;
2224         boolean_t               u_arg = B_FALSE;
2225         uint32_t                flags = DLADM_OPT_ACTIVE;
2226         datalink_id_t           linkid = DATALINK_ALL_LINKID;
2227         uint32_t                interval = 0;
2228         char                    unit = '\0';
2229         show_state_t            state;
2230         dladm_status_t          status;
2231         char                    *fields_str = NULL;
2232         char                    *o_fields_str = NULL;
2233 
2234         char                    *aggr_stat_fields =
2235             "link,port,ipkts,rbytes,opkts,obytes";
2236         char                    *rx_aggr_stat_fields = "link,port,ipkts,rbytes";
2237         char                    *tx_aggr_stat_fields = "link,port,opkts,obytes";
2238 
2239         ofmt_handle_t           ofmt;
2240         ofmt_status_t           oferr;
2241         uint_t                  ofmtflags = OFMT_RIGHTJUST;
2242         ofmt_field_t            *oftemplate;
2243 
2244         bzero(&state, sizeof (state));
2245         opterr = 0;
2246         while ((option = getopt_long(argc, argv, ":rtpi:o:u:",
2247             NULL, NULL)) != -1) {
2248                 switch (option) {
2249                 case 'r':
2250                         if (r_arg)
2251                                 die_optdup(option);
2252 
2253                         r_arg = B_TRUE;
2254                         break;
2255                 case 't':
2256                         if (t_arg)
2257                                 die_optdup(option);
2258 
2259                         t_arg = B_TRUE;
2260                         break;
2261                 case 'i':
2262                         if (i_arg)
2263                                 die_optdup(option);
2264 
2265                         i_arg = B_TRUE;
2266                         if (!dladm_str2interval(optarg, &interval))
2267                                 die("invalid interval value '%s'", optarg);
2268                         break;
2269                 case 'p':
2270                         if (p_arg)
2271                                 die_optdup(option);
2272 
2273                         p_arg = B_TRUE;
2274                         break;
2275                 case 'o':
2276                         o_arg = B_TRUE;
2277                         o_fields_str = optarg;
2278                         break;
2279                 case 'u':
2280                         if (u_arg)
2281                                 die_optdup(option);
2282 
2283                         u_arg = B_TRUE;
2284                         if (!dlstat_unit(optarg, &unit))
2285                                 die("invalid unit value '%s',"
2286                                     "unit must be R|K|M|G|T|P", optarg);
2287                         break;
2288                 default:
2289                         die_opterr(optopt, option, use);
2290                         break;
2291                 }
2292         }
2293 
2294         if (r_arg && t_arg)
2295                 die("the options -t and -r are not compatible");
2296 
2297         if (u_arg && p_arg)
2298                 die("the options -u and -p are not compatible");
2299 
2300         if (p_arg && !o_arg)
2301                 die("-p requires -o");
2302 
2303         if (p_arg && strcasecmp(o_fields_str, "all") == 0)
2304                 die("\"-o all\" is invalid with -p");
2305 
2306 
2307         /* get link name (optional last argument) */
2308         if (optind == (argc-1)) {
2309                 if (strlen(argv[optind]) >= MAXLINKNAMELEN)
2310                         die("link name too long");
2311 
2312                 if ((status = dladm_name2info(handle, argv[optind], &linkid,
2313                     NULL, NULL, NULL)) != DLADM_STATUS_OK) {
2314                         die_dlerr(status, "link %s is not valid", argv[optind]);
2315                 }
2316         } else if (optind != argc) {
2317                 usage();
2318         }
2319 
2320         state.ls_unit = unit;
2321         state.ls_parsable = p_arg;
2322 
2323         if (state.ls_parsable)
2324                 ofmtflags |= OFMT_PARSABLE;
2325 
2326         oftemplate = aggr_port_s_fields;
2327         state.ls_stattype[DLADM_STAT_AGGR_PORT] = B_TRUE;
2328         state.ls_stats2str[DLADM_STAT_AGGR_PORT] = print_aggr_port_stats;
2329 
2330         if (r_arg)
2331                 fields_str = rx_aggr_stat_fields;
2332         else if (t_arg)
2333                 fields_str = tx_aggr_stat_fields;
2334         else
2335                 fields_str = aggr_stat_fields;
2336 
2337         if (o_arg) {
2338                 fields_str = (strcasecmp(o_fields_str, "all") == 0) ?
2339                     fields_str : o_fields_str;
2340         }
2341 
2342         oferr = ofmt_open(fields_str, oftemplate, ofmtflags, 0, &ofmt);
2343         dlstat_ofmt_check(oferr, state.ls_parsable, ofmt);
2344         state.ls_ofmt = ofmt;
2345 
2346         show_link_stats(linkid, state, interval);
2347 
2348         ofmt_close(ofmt);
2349 }
2350 
2351 /* PRINTFLIKE1 */
2352 static void
2353 warn(const char *format, ...)
2354 {
2355         va_list alist;
2356 
2357         format = gettext(format);
2358         (void) fprintf(stderr, "%s: warning: ", progname);
2359 
2360         va_start(alist, format);
2361         (void) vfprintf(stderr, format, alist);
2362         va_end(alist);
2363 
2364         (void) putc('\n', stderr);
2365 }
2366 
2367 /*
2368  * Also closes the dladm handle if it is not NULL.
2369  */
2370 /* PRINTFLIKE2 */
2371 static void
2372 die_dlerr(dladm_status_t err, const char *format, ...)
2373 {
2374         va_list alist;
2375         char    errmsg[DLADM_STRSIZE];
2376 
2377         format = gettext(format);
2378         (void) fprintf(stderr, "%s: ", progname);
2379 
2380         va_start(alist, format);
2381         (void) vfprintf(stderr, format, alist);
2382         va_end(alist);
2383         (void) fprintf(stderr, ": %s\n", dladm_status2str(err, errmsg));
2384 
2385         /* close dladm handle if it was opened */
2386         if (handle != NULL)
2387                 dladm_close(handle);
2388 
2389         exit(EXIT_FAILURE);
2390 }
2391 
2392 /* PRINTFLIKE1 */
2393 static void
2394 die(const char *format, ...)
2395 {
2396         va_list alist;
2397 
2398         format = gettext(format);
2399         (void) fprintf(stderr, "%s: ", progname);
2400 
2401         va_start(alist, format);
2402         (void) vfprintf(stderr, format, alist);
2403         va_end(alist);
2404 
2405         (void) putc('\n', stderr);
2406 
2407         /* close dladm handle if it was opened */
2408         if (handle != NULL)
2409                 dladm_close(handle);
2410 
2411         exit(EXIT_FAILURE);
2412 }
2413 
2414 static void
2415 die_optdup(int opt)
2416 {
2417         die("the option -%c cannot be specified more than once", opt);
2418 }
2419 
2420 static void
2421 die_opterr(int opt, int opterr, const char *usage)
2422 {
2423         switch (opterr) {
2424         case ':':
2425                 die("option '-%c' requires a value\nusage: %s", opt,
2426                     gettext(usage));
2427                 break;
2428         case '?':
2429         default:
2430                 die("unrecognized option '-%c'\nusage: %s", opt,
2431                     gettext(usage));
2432                 break;
2433         }
2434 }
2435 
2436 /*
2437  * default output callback function that, when invoked,
2438  * prints string which is offset by ofmt_arg->ofmt_id within buf.
2439  */
2440 static boolean_t
2441 print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
2442 {
2443         char *value;
2444 
2445         value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id;
2446         (void) strlcpy(buf, value, bufsize);
2447         return (B_TRUE);
2448 }
2449 
2450 static void
2451 dlstat_ofmt_check(ofmt_status_t oferr, boolean_t parsable,
2452     ofmt_handle_t ofmt)
2453 {
2454         char buf[OFMT_BUFSIZE];
2455 
2456         if (oferr == OFMT_SUCCESS)
2457                 return;
2458         (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
2459         /*
2460          * All errors are considered fatal in parsable mode.
2461          * NOMEM errors are always fatal, regardless of mode.
2462          * For other errors, we print diagnostics in human-readable
2463          * mode and processs what we can.
2464          */
2465         if (parsable || oferr == OFMT_ENOFIELDS) {
2466                 ofmt_close(ofmt);
2467                 die(buf);
2468         } else {
2469                 warn(buf);
2470         }
2471 }