diff options
| author | Sowmini Varadhan <Sowmini.Varadhan@Sun.COM> | 2009-03-17 19:00:36 -0400 |
|---|---|---|
| committer | Sowmini Varadhan <Sowmini.Varadhan@Sun.COM> | 2009-03-17 19:00:36 -0400 |
| commit | 8002d4117c1ea26aff1f16f584ae97bdbd5b21d5 (patch) | |
| tree | b5ce2731eff163feaf43cbd0b6a64bfb5dd37930 /usr | |
| parent | c5f9a89643b6d7175323dcb29f1a665661143c67 (diff) | |
| download | illumos-joyent-8002d4117c1ea26aff1f16f584ae97bdbd5b21d5.tar.gz | |
6782154 one copy of parse_output_fields() & friends is enough.
6751617 dladm show-link -s -i needs to flush stdout after each line
6687693 dladm show-aggr -s -i 1 in nv shows the column header only once per invocation
Diffstat (limited to 'usr')
| -rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile | 2 | ||||
| -rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c | 747 | ||||
| -rw-r--r-- | usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.xcl | 3 | ||||
| -rw-r--r-- | usr/src/cmd/dladm/dladm.c | 1820 | ||||
| -rw-r--r-- | usr/src/cmd/dladm/dladm.xcl | 5 | ||||
| -rw-r--r-- | usr/src/cmd/flowadm/Makefile | 4 | ||||
| -rw-r--r-- | usr/src/cmd/flowadm/flowadm.c | 606 | ||||
| -rw-r--r-- | usr/src/lib/Makefile | 1 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/Makefile | 15 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/Makefile.com | 6 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/common/llib-linetutil | 12 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/common/mapfile-vers | 5 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/common/ofmt.c | 480 | ||||
| -rw-r--r-- | usr/src/lib/libinetutil/common/ofmt.h | 198 | ||||
| -rw-r--r-- | usr/src/pkgdefs/etc/exception_list_i386 | 1 | ||||
| -rw-r--r-- | usr/src/pkgdefs/etc/exception_list_sparc | 1 |
16 files changed, 1844 insertions, 2062 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile index a256cf5f49..fb30e8af09 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile @@ -29,7 +29,7 @@ ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%) include $(SRC)/cmd/Makefile.cmd C99MODE = $(C99_ENABLE) -LDLIBS += -lipmp -lsocket -lsysevent -lnvpair +LDLIBS += -lipmp -lsocket -lsysevent -lnvpair -linetutil XGETFLAGS += -a -x $(PROG).xcl .KEEP_STATE: diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c index c28c426d4f..f5155e6745 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.c @@ -33,6 +33,7 @@ #include <libsysevent.h> #include <locale.h> #include <netdb.h> +#include <ofmt.h> #include <signal.h> #include <stdarg.h> #include <stdio.h> @@ -62,28 +63,27 @@ * Since target information is included with the interface information, * both -i and -t use the interface walker (walk_if()). * - * * The ipmpstat_sfunc_t function pointers (sfunc_*) obtain a given - * value for a given IPMP object. Each ipmpstat_sunc_t is passed a - * buffer to write its result into, the buffer's size, and an - * ipmpstat_sfunc_arg_t state structure. The state structure consists - * of a pointer to the IPMP object to obtain information from - * (sa_data), and an open libipmp handle (sa_ih) which can be used to - * do additional libipmp queries, if necessary (e.g., because the - * object does not have all of the needed information). + * * The ofmt_sfunc_t function pointers (sfunc_*) obtain a given value + * for a given IPMP object. Each ofmt_sfunc_t is passed a buffer to + * write its result into, the buffer's size, and an ipmpstat_sfunc_arg_t + * state structure. The state structure consists of a pointer to the + * IPMP object to obtain information from (sa_data), and an open libipmp + * handle (sa_ih) which can be used to do additional libipmp queries, if + * necessary (e.g., because the object does not have all of the needed + * information). * - * * The ipmpstat_field_t structure provides the list of supported fields - * for a given output format, along with output formatting information - * (e.g., field width), and a pointer to an ipmpstat_sfunc_t function - * that can obtain the value for a IPMP given object. For a given - * ipmpstat output format, there's a corresponding array of - * ipmpstat_field_t structures. Thus, one ipmpstat_field_t array is - * used per ipmpstat invocation. + * * The ofmt_field_t arrays (*_fields[]) provide the supported fields for + * a given output format, along with output formatting information + * (e.g., field width) and a pointer to an ofmt_sfunc_t function that + * can obtain the value for a given IPMP object. One ofmt_field_t array + * is used per ipmpstat invocation, and is passed to ofmt_open() (along + * with the output fields and modes requested by the user) to create an + * ofmt_t. * - * * The ipmpstat_ofmt_t provides an ordered list of the requested - * ipmpstat_field_t's (e.g., via -o) for a given ipmpstat invocation. - * It is built at runtime from the command-line arguments. This - * structure (and a given IPMP object) is used by ofmt_output() to - * output a single line of information about that IPMP object. + * * The ofmt_t structure is a handle that tracks all information + * related to output formatting and is used by libinetutil`ofmt_print() + * (indirectly through our local ofmt_output() utility routine) to + * output a single line of information about the provided IPMP object. * * * The ipmpstat_cbfunc_t function pointers (*_cbfunc) are called back * by the walkers. They are used both internally to implement nested @@ -105,25 +105,6 @@ typedef struct ipmpstat_sfunc_arg { void *sa_data; } ipmpstat_sfunc_arg_t; -typedef void ipmpstat_sfunc_t(ipmpstat_sfunc_arg_t *, char *, uint_t); - -/* - * Data type that describes how to output a field; used by ofmt_output*(). - */ -typedef struct ipmpstat_field { - const char *f_name; /* field name */ - uint_t f_width; /* output width */ - ipmpstat_sfunc_t *f_sfunc; /* value->string function */ -} ipmpstat_field_t; - -/* - * Data type that specifies the output field order; used by ofmt_output*() - */ -typedef struct ipmpstat_ofmt { - const ipmpstat_field_t *o_field; /* current field info */ - struct ipmpstat_ofmt *o_next; /* next field */ -} ipmpstat_ofmt_t; - /* * Function pointers used to iterate through IPMP objects. */ @@ -150,8 +131,8 @@ typedef struct ipmpstat_enum { * Data type used to pass state between probe_output() and probe_event(). */ typedef struct ipmpstat_probe_state { - ipmp_handle_t ps_ih; /* open IPMP handle */ - ipmpstat_ofmt_t *ps_ofmt; /* requested ofmt string */ + ipmp_handle_t ps_ih; /* open IPMP handle */ + ofmt_handle_t ps_ofmt; /* open formatted-output handle */ } ipmpstat_probe_state_t; /* @@ -177,22 +158,19 @@ enum { static const char *progname; static hrtime_t probe_output_start; -static struct winsize winsize; static ipmpstat_opt_t opt; +static ofmt_handle_t ofmt; static ipmpstat_enum_t addr_state[], group_state[], if_state[], if_link[]; static ipmpstat_enum_t if_probe[], targ_mode[]; -static ipmpstat_field_t addr_fields[], group_fields[], if_fields[]; -static ipmpstat_field_t probe_fields[], targ_fields[]; +static ofmt_field_t addr_fields[], group_fields[], if_fields[]; +static ofmt_field_t probe_fields[], targ_fields[]; static ipmpstat_cbfunc_t walk_addr_cbfunc, walk_if_cbfunc; static ipmpstat_cbfunc_t info_output_cbfunc, targinfo_output_cbfunc; static ipmpstat_walker_t walk_addr, walk_if, walk_group; static int probe_event(sysevent_t *, void *); -static void probe_output(ipmp_handle_t, ipmpstat_ofmt_t *); -static ipmpstat_field_t *field_find(ipmpstat_field_t *, const char *); -static ipmpstat_ofmt_t *ofmt_create(const char *, ipmpstat_field_t []); -static void ofmt_output(const ipmpstat_ofmt_t *, ipmp_handle_t, void *); -static void ofmt_destroy(ipmpstat_ofmt_t *); +static void probe_output(ipmp_handle_t, ofmt_handle_t); +static void ofmt_output(ofmt_handle_t, ipmp_handle_t, void *); static void enum2str(const ipmpstat_enum_t *, int, char *, uint_t); static void sockaddr2str(const struct sockaddr_storage *, char *, uint_t); static void sighandler(int); @@ -208,12 +186,14 @@ main(int argc, char **argv) int c; int err; const char *ofields = NULL; + ofmt_status_t ofmterr; + ofmt_field_t *fields = NULL; + uint_t ofmtflags = 0; ipmp_handle_t ih; ipmp_qcontext_t qcontext = IPMP_QCONTEXT_SNAP; - ipmpstat_ofmt_t *ofmt; - ipmpstat_field_t *fields = NULL; ipmpstat_cbfunc_t *cbfunc; ipmpstat_walker_t *walker; + char errbuf[OFMT_BUFSIZE]; if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; @@ -237,6 +217,7 @@ main(int argc, char **argv) break; case 'P': opt |= IPMPSTAT_OPT_PARSABLE; + ofmtflags |= OFMT_PARSABLE; break; case 'o': ofields = optarg; @@ -273,13 +254,20 @@ main(int argc, char **argv) if (argc > optind || fields == NULL) usage(); - if (opt & IPMPSTAT_OPT_PARSABLE) { - if (ofields == NULL) { - die("output field list (-o) required in parsable " - "output mode\n"); - } else if (strcasecmp(ofields, "all") == 0) { - die("\"all\" not allowed in parsable output mode\n"); - } + /* + * Open a handle to the formatted output engine. + */ + ofmterr = ofmt_open(ofields, fields, ofmtflags, IPMPSTAT_NCOL, &ofmt); + if (ofmterr != OFMT_SUCCESS) { + /* + * If some fields were badly formed in human-friendly mode, we + * emit a warning and continue. Otherwise exit immediately. + */ + (void) ofmt_strerror(ofmt, ofmterr, errbuf, sizeof (errbuf)); + if (ofmterr != OFMT_EBADFIELDS || (opt & IPMPSTAT_OPT_PARSABLE)) + die("%s\n", errbuf); + else + warn("%s\n", errbuf); } /* @@ -287,7 +275,6 @@ main(int argc, char **argv) * is used to redisplay the output headers when necessary. */ (void) sigset(SIGWINCH, sighandler); - sighandler(SIGWINCH); if ((err = ipmp_open(&ih)) != IPMP_SUCCESS) die_ipmperr(err, "cannot create IPMP handle"); @@ -296,12 +283,6 @@ main(int argc, char **argv) die("cannot contact in.mpathd(1M) -- is IPMP in use?\n"); /* - * Create the ofmt linked list that will eventually be passed to - * to ofmt_output() to output the fields. - */ - ofmt = ofmt_create(ofields, fields); - - /* * If we've been asked to display probes, then call the probe output * function. Otherwise, snapshot IPMP state (or use live state) and * invoke the specified walker with the specified callback function. @@ -318,7 +299,7 @@ main(int argc, char **argv) (*walker)(ih, cbfunc, ofmt); } - ofmt_destroy(ofmt); + ofmt_close(ofmt); ipmp_close(ih); return (EXIT_SUCCESS); @@ -430,24 +411,27 @@ walk_addr_cbfunc(ipmp_handle_t ih, void *infop, void *arg) } } -static void -sfunc_nvwarn(const char *nvname, char *buf, uint_t bufsize) +static boolean_t +sfunc_nvwarn(const char *nvname) { warn("cannot retrieve %s\n", nvname); - (void) strlcpy(buf, "?", bufsize); + return (B_FALSE); } -static void -sfunc_addr_address(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_addr_address(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_addrinfo_t *adinfop = arg->sa_data; sockaddr2str(&adinfop->ad_addr, buf, bufsize); + return (B_TRUE); } -static void -sfunc_addr_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_addr_group(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int err; ipmp_addrinfo_t *adinfop = arg->sa_data; ipmp_groupinfo_t *grinfop; @@ -456,32 +440,37 @@ sfunc_addr_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) if (err != IPMP_SUCCESS) { warn_ipmperr(err, "cannot get info for group `%s'", adinfop->ad_group); - (void) strlcpy(buf, "?", bufsize); - return; + return (B_FALSE); } (void) strlcpy(buf, grinfop->gr_ifname, bufsize); ipmp_freegroupinfo(grinfop); + return (B_TRUE); } -static void -sfunc_addr_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_addr_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_addrinfo_t *adinfop = arg->sa_data; enum2str(addr_state, adinfop->ad_state, buf, bufsize); + return (B_TRUE); } -static void -sfunc_addr_inbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_addr_inbound(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_addrinfo_t *adinfop = arg->sa_data; (void) strlcpy(buf, adinfop->ad_binding, bufsize); + return (B_TRUE); } -static void -sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_addr_outbound(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int err; uint_t i, nactive = 0; ipmp_ifinfo_t *ifinfop; @@ -490,14 +479,14 @@ sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) ipmp_groupinfo_t *grinfop; if (adinfop->ad_state == IPMP_ADDR_DOWN) - return; + return (B_TRUE); /* * If there's no inbound interface for this address, there can't * be any outbound traffic. */ if (adinfop->ad_binding[0] == '\0') - return; + return (B_TRUE); /* * The address can use any active interface in the group, so @@ -507,8 +496,7 @@ sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) if (err != IPMP_SUCCESS) { warn_ipmperr(err, "cannot get info for group `%s'", adinfop->ad_group); - (void) strlcpy(buf, "?", bufsize); - return; + return (B_FALSE); } iflistp = grinfop->gr_iflistp; @@ -528,46 +516,56 @@ sfunc_addr_outbound(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) ipmp_freeifinfo(ifinfop); } ipmp_freegroupinfo(grinfop); + return (B_TRUE); } -static void -sfunc_group_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_group_name(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_groupinfo_t *grinfop = arg->sa_data; (void) strlcpy(buf, grinfop->gr_name, bufsize); + return (B_TRUE); } -static void -sfunc_group_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_group_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_groupinfo_t *grinfop = arg->sa_data; (void) strlcpy(buf, grinfop->gr_ifname, bufsize); + return (B_TRUE); } -static void -sfunc_group_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_group_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_groupinfo_t *grinfop = arg->sa_data; enum2str(group_state, grinfop->gr_state, buf, bufsize); + return (B_TRUE); } -static void -sfunc_group_fdt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_group_fdt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_groupinfo_t *grinfop = arg->sa_data; if (grinfop->gr_fdt == 0) - return; + return (B_TRUE); (void) snprintf(buf, bufsize, "%.2fs", MS2FLOATSEC(grinfop->gr_fdt)); + return (B_TRUE); } -static void -sfunc_group_interfaces(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_group_interfaces(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int err; uint_t i; char *active, *inactive, *unusable; @@ -627,30 +625,36 @@ sfunc_group_interfaces(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) (void) strlcat(buf, unusable, bufsize); (void) strlcat(buf, "]", bufsize); } + return (B_TRUE); } -static void -sfunc_if_name(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_name(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_ifinfo_t *ifinfop = arg->sa_data; (void) strlcpy(buf, ifinfop->if_name, bufsize); + return (B_TRUE); } -static void -sfunc_if_active(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_active(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_ifinfo_t *ifinfop = arg->sa_data; if (ifinfop->if_flags & IPMP_IFFLAG_ACTIVE) (void) strlcpy(buf, "yes", bufsize); else (void) strlcpy(buf, "no", bufsize); + return (B_TRUE); } -static void -sfunc_if_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_group(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int err; ipmp_ifinfo_t *ifinfop = arg->sa_data; ipmp_groupinfo_t *grinfop; @@ -659,17 +663,18 @@ sfunc_if_group(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) if (err != IPMP_SUCCESS) { warn_ipmperr(err, "cannot get info for group `%s'", ifinfop->if_group); - (void) strlcpy(buf, "?", bufsize); - return; + return (B_TRUE); } (void) strlcpy(buf, grinfop->gr_ifname, bufsize); ipmp_freegroupinfo(grinfop); + return (B_TRUE); } -static void -sfunc_if_flags(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_flags(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int err; ipmp_ifinfo_t *ifinfop = arg->sa_data; ipmp_groupinfo_t *grinfop; @@ -695,7 +700,7 @@ sfunc_if_flags(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) if (err != IPMP_SUCCESS) { warn_ipmperr(err, "cannot get broadcast/multicast info for " "group `%s'", ifinfop->if_group); - return; + return (B_TRUE); } if (strcmp(grinfop->gr_m4ifname, ifinfop->if_name) == 0) @@ -708,175 +713,174 @@ sfunc_if_flags(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) buf[IPMPSTAT_BFLAG_INDEX] = 'b'; ipmp_freegroupinfo(grinfop); + return (B_TRUE); } -static void -sfunc_if_link(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_link(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_ifinfo_t *ifinfop = arg->sa_data; enum2str(if_link, ifinfop->if_linkstate, buf, bufsize); + return (B_TRUE); } -static void -sfunc_if_probe(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_probe(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_ifinfo_t *ifinfop = arg->sa_data; enum2str(if_probe, ifinfop->if_probestate, buf, bufsize); + return (B_TRUE); } -static void -sfunc_if_state(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_if_state(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_ifinfo_t *ifinfop = arg->sa_data; enum2str(if_state, ifinfop->if_state, buf, bufsize); + return (B_TRUE); } -static void -sfunc_probe_id(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_id(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; uint32_t probe_id; nvlist_t *nvl = arg->sa_data; - if (nvlist_lookup_uint32(nvl, IPMP_PROBE_ID, &probe_id) != 0) { - sfunc_nvwarn("IPMP_PROBE_ID", buf, bufsize); - return; - } + if (nvlist_lookup_uint32(nvl, IPMP_PROBE_ID, &probe_id) != 0) + return (sfunc_nvwarn("IPMP_PROBE_ID")); (void) snprintf(buf, bufsize, "%u", probe_id); + return (B_TRUE); } -static void -sfunc_probe_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; char *ifname; nvlist_t *nvl = arg->sa_data; - if (nvlist_lookup_string(nvl, IPMP_IF_NAME, &ifname) != 0) { - sfunc_nvwarn("IPMP_IF_NAME", buf, bufsize); - return; - } + if (nvlist_lookup_string(nvl, IPMP_IF_NAME, &ifname) != 0) + return (sfunc_nvwarn("IPMP_IF_NAME")); (void) strlcpy(buf, ifname, bufsize); + return (B_TRUE); } -static void -sfunc_probe_time(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_time(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; hrtime_t start; nvlist_t *nvl = arg->sa_data; - if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) { - sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize); - return; - } + if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) + return (sfunc_nvwarn("IPMP_PROBE_START_TIME")); (void) snprintf(buf, bufsize, "%.2fs", (float)(start - probe_output_start) / NANOSEC); + return (B_TRUE); } -static void -sfunc_probe_target(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_target(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; uint_t nelem; struct sockaddr_storage *target; nvlist_t *nvl = arg->sa_data; if (nvlist_lookup_byte_array(nvl, IPMP_PROBE_TARGET, - (uchar_t **)&target, &nelem) != 0) { - sfunc_nvwarn("IPMP_PROBE_TARGET", buf, bufsize); - return; - } + (uchar_t **)&target, &nelem) != 0) + return (sfunc_nvwarn("IPMP_PROBE_TARGET")); sockaddr2str(target, buf, bufsize); + return (B_TRUE); } -static void -sfunc_probe_rtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_rtt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; hrtime_t start, ackproc; nvlist_t *nvl = arg->sa_data; uint32_t state; - if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) { - sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize); - return; - } + if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) + return (sfunc_nvwarn("IPMP_PROBE_STATE")); if (state != IPMP_PROBE_ACKED) - return; + return (B_TRUE); - if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) { - sfunc_nvwarn("IPMP_PROBE_START_TIME", buf, bufsize); - return; - } + if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_START_TIME, &start) != 0) + return (sfunc_nvwarn("IPMP_PROBE_START_TIME")); - if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, &ackproc) != 0) { - sfunc_nvwarn("IPMP_PROBE_ACKPROC_TIME", buf, bufsize); - return; - } + if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKPROC_TIME, &ackproc) != 0) + return (sfunc_nvwarn("IPMP_PROBE_ACKPROC_TIME")); (void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackproc - start)); + return (B_TRUE); } -static void -sfunc_probe_netrtt(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_netrtt(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; hrtime_t sent, ackrecv; nvlist_t *nvl = arg->sa_data; uint32_t state; - if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) { - sfunc_nvwarn("IPMP_PROBE_STATE", buf, bufsize); - return; - } + if (nvlist_lookup_uint32(nvl, IPMP_PROBE_STATE, &state) != 0) + return (sfunc_nvwarn("IPMP_PROBE_STATE")); if (state != IPMP_PROBE_ACKED) - return; + return (B_TRUE); - if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_SENT_TIME, &sent) != 0) { - sfunc_nvwarn("IPMP_PROBE_SENT_TIME", buf, bufsize); - return; - } + if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_SENT_TIME, &sent) != 0) + return (sfunc_nvwarn("IPMP_PROBE_SENT_TIME")); - if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, &ackrecv) != 0) { - sfunc_nvwarn("IPMP_PROBE_ACKRECV_TIME", buf, bufsize); - return; - } + if (nvlist_lookup_hrtime(nvl, IPMP_PROBE_ACKRECV_TIME, &ackrecv) != 0) + return (sfunc_nvwarn("IPMP_PROBE_ACKRECV_TIME")); (void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(ackrecv - sent)); + return (B_TRUE); } -static void -sfunc_probe_rttavg(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_rttavg(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int64_t rttavg; nvlist_t *nvl = arg->sa_data; - if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, &rttavg) != 0) { - sfunc_nvwarn("IPMP_PROBE_TARGET_RTTAVG", buf, bufsize); - return; - } + if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTAVG, &rttavg) != 0) + return (sfunc_nvwarn("IPMP_PROBE_TARGET_RTTAVG")); if (rttavg != 0) (void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttavg)); + return (B_TRUE); } -static void -sfunc_probe_rttdev(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_probe_rttdev(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; int64_t rttdev; nvlist_t *nvl = arg->sa_data; - if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, &rttdev) != 0) { - sfunc_nvwarn("IPMP_PROBE_TARGET_RTTDEV", buf, bufsize); - return; - } + if (nvlist_lookup_int64(nvl, IPMP_PROBE_TARGET_RTTDEV, &rttdev) != 0) + return (sfunc_nvwarn("IPMP_PROBE_TARGET_RTTDEV")); if (rttdev != 0) (void) snprintf(buf, bufsize, "%.2fms", NS2FLOATMS(rttdev)); + return (B_TRUE); } /* ARGSUSED */ @@ -891,7 +895,7 @@ probe_enabled_cbfunc(ipmp_handle_t ih, void *infop, void *arg) } static void -probe_output(ipmp_handle_t ih, ipmpstat_ofmt_t *ofmt) +probe_output(ipmp_handle_t ih, ofmt_handle_t ofmt) { char sub[MAX_SUBID_LEN]; evchan_t *evch; @@ -972,34 +976,41 @@ out: return (0); } -static void -sfunc_targ_ifname(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_targ_ifname(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_targinfo_t *targinfop = arg->sa_data; (void) strlcpy(buf, targinfop->it_name, bufsize); + return (B_TRUE); } -static void -sfunc_targ_mode(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_targ_mode(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_targinfo_t *targinfop = arg->sa_data; enum2str(targ_mode, targinfop->it_targmode, buf, bufsize); + return (B_TRUE); } -static void -sfunc_targ_testaddr(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_targ_testaddr(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; ipmp_targinfo_t *targinfop = arg->sa_data; if (targinfop->it_targmode != IPMP_TARG_DISABLED) sockaddr2str(&targinfop->it_testaddr, buf, bufsize); + return (B_TRUE); } -static void -sfunc_targ_targets(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) +static boolean_t +sfunc_targ_targets(ofmt_arg_t *ofmtarg, char *buf, uint_t bufsize) { + ipmpstat_sfunc_arg_t *arg = ofmtarg->ofmt_cbarg; uint_t i; char *targname = alloca(bufsize); ipmp_targinfo_t *targinfop = arg->sa_data; @@ -1011,6 +1022,7 @@ sfunc_targ_targets(ipmpstat_sfunc_arg_t *arg, char *buf, uint_t bufsize) if ((i + 1) < targlistp->al_naddr) (void) strlcat(buf, " ", bufsize); } + return (B_TRUE); } static void @@ -1039,227 +1051,18 @@ targinfo_output_cbfunc(ipmp_handle_t ih, void *infop, void *arg) } /* - * Creates an ipmpstat_ofmt_t field list from the comma-separated list of - * user-specified fields passed via `ofields'. The table of known fields - * (and their attributes) is passed via `fields'. - */ -static ipmpstat_ofmt_t * -ofmt_create(const char *ofields, ipmpstat_field_t fields[]) -{ - char *token, *lasts, *ofields_dup; - const char *fieldname; - ipmpstat_ofmt_t *ofmt, *ofmt_head = NULL, *ofmt_tail; - ipmpstat_field_t *fieldp; - uint_t cols = 0; - - /* - * If "-o" was omitted or "-o all" was specified, build a list of - * field names. If "-o" was omitted, stop building the list when - * we run out of columns. - */ - if (ofields == NULL || strcasecmp(ofields, "all") == 0) { - for (fieldp = fields; fieldp->f_name != NULL; fieldp++) { - cols += fieldp->f_width; - if (ofields == NULL && cols > IPMPSTAT_NCOL) - break; - - if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL) - die("cannot allocate output format list"); - - ofmt->o_field = fieldp; - if (ofmt_head == NULL) { - ofmt_head = ofmt; - ofmt_tail = ofmt; - } else { - ofmt_tail->o_next = ofmt; - ofmt_tail = ofmt; - } - } - return (ofmt_head); - } - - if ((ofields_dup = strdup(ofields)) == NULL) - die("cannot allocate output format list"); - - token = ofields_dup; - while ((fieldname = strtok_r(token, ",", &lasts)) != NULL) { - token = NULL; - - if ((fieldp = field_find(fields, fieldname)) == NULL) { - /* - * Since machine parsers are unlikely to be able to - * gracefully handle missing fields, die if we're in - * parsable mode. Otherwise, just print a warning. - */ - if (opt & IPMPSTAT_OPT_PARSABLE) - die("unknown output field `%s'\n", fieldname); - - warn("ignoring unknown output field `%s'\n", fieldname); - continue; - } - - if ((ofmt = calloc(sizeof (*ofmt), 1)) == NULL) - die("cannot allocate output format list"); - - ofmt->o_field = fieldp; - if (ofmt_head == NULL) { - ofmt_head = ofmt; - ofmt_tail = ofmt; - } else { - ofmt_tail->o_next = ofmt; - ofmt_tail = ofmt; - } - } - - free(ofields_dup); - if (ofmt_head == NULL) - die("no valid output fields specified\n"); - - return (ofmt_head); -} - -/* - * Destroys the provided `ofmt' field list. + * Outputs one row of values. The values to output are obtained through the + * callback function pointers. The actual values are computed from the `ih' + * and `arg' structures passed to the callback function. */ static void -ofmt_destroy(ipmpstat_ofmt_t *ofmt) +ofmt_output(const ofmt_handle_t ofmt, ipmp_handle_t ih, void *arg) { - ipmpstat_ofmt_t *ofmt_next; + ipmpstat_sfunc_arg_t sfunc_arg; - for (; ofmt != NULL; ofmt = ofmt_next) { - ofmt_next = ofmt->o_next; - free(ofmt); - } -} - -/* - * Outputs a header for the fields named by `ofmt'. - */ -static void -ofmt_output_header(const ipmpstat_ofmt_t *ofmt) -{ - const ipmpstat_field_t *fieldp; - - for (; ofmt != NULL; ofmt = ofmt->o_next) { - fieldp = ofmt->o_field; - - if (ofmt->o_next == NULL) - (void) printf("%s", fieldp->f_name); - else - (void) printf("%-*s", fieldp->f_width, fieldp->f_name); - } - (void) printf("\n"); -} - -/* - * Outputs one row of values for the fields named by `ofmt'. The values to - * output are obtained through the `ofmt' function pointers, which are - * indirectly passed the `ih' and `arg' structures for state; see the block - * comment at the start of this file for details. - */ -static void -ofmt_output(const ipmpstat_ofmt_t *ofmt, ipmp_handle_t ih, void *arg) -{ - int i; - char buf[1024]; - boolean_t escsep; - static int nrow; - const char *value; - uint_t width, valwidth; - uint_t compress, overflow = 0; - const ipmpstat_field_t *fieldp; - ipmpstat_sfunc_arg_t sfunc_arg; - - /* - * For each screenful of data, display the header. - */ - if ((nrow++ % winsize.ws_row) == 0 && !(opt & IPMPSTAT_OPT_PARSABLE)) { - ofmt_output_header(ofmt); - nrow++; - } - - /* - * Check if we'll be displaying multiple fields per line, and thus - * need to escape the field separator. - */ - escsep = (ofmt != NULL && ofmt->o_next != NULL); - - for (; ofmt != NULL; ofmt = ofmt->o_next) { - fieldp = ofmt->o_field; - - sfunc_arg.sa_ih = ih; - sfunc_arg.sa_data = arg; - - buf[0] = '\0'; - (*fieldp->f_sfunc)(&sfunc_arg, buf, sizeof (buf)); - - if (opt & IPMPSTAT_OPT_PARSABLE) { - for (i = 0; buf[i] != '\0'; i++) { - if (escsep && (buf[i] == ':' || buf[i] == '\\')) - (void) putchar('\\'); - (void) putchar(buf[i]); - } - if (ofmt->o_next != NULL) - (void) putchar(':'); - } else { - value = (buf[0] == '\0') ? "--" : buf; - - /* - * To avoid needless line-wraps, for the last field, - * don't include any trailing whitespace. - */ - if (ofmt->o_next == NULL) { - (void) printf("%s", value); - continue; - } - - /* - * For other fields, grow the width as necessary to - * ensure the value completely fits. However, if - * there's unused whitespace in subsequent fields, - * then "compress" that whitespace to attempt to get - * the columns to line up again. - */ - width = fieldp->f_width; - valwidth = strlen(value); - - if (valwidth + overflow >= width) { - overflow += valwidth - width + 1; - (void) printf("%s ", value); - continue; - } - - if (overflow > 0) { - compress = MIN(overflow, width - valwidth); - overflow -= compress; - width -= compress; - } - (void) printf("%-*s", width, value); - } - } - (void) printf("\n"); - - /* - * In case stdout has been redirected to e.g. a pipe, flush stdout so - * that commands can act on our output immediately. - */ - (void) fflush(stdout); -} - -/* - * Searches the `fields' array for a field matching `fieldname'. Returns - * a pointer to that field on success, or NULL on failure. - */ -static ipmpstat_field_t * -field_find(ipmpstat_field_t *fields, const char *fieldname) -{ - ipmpstat_field_t *fieldp; - - for (fieldp = fields; fieldp->f_name != NULL; fieldp++) { - if (strcasecmp(fieldp->f_name, fieldname) == 0) - return (fieldp); - } - return (NULL); + sfunc_arg.sa_ih = ih; + sfunc_arg.sa_data = arg; + ofmt_print(ofmt, &sfunc_arg); } /* @@ -1318,11 +1121,7 @@ sighandler(int sig) { assert(sig == SIGWINCH); - if (ioctl(1, TIOCGWINSZ, &winsize) == -1 || - winsize.ws_col == 0 || winsize.ws_row == 0) { - winsize.ws_col = 80; - winsize.ws_row = 24; - } + ofmt_update_winsize(ofmt); } static void @@ -1415,94 +1214,94 @@ die_ipmperr(int ipmperr, const char *format, ...) exit(EXIT_FAILURE); } -static ipmpstat_field_t addr_fields[] = { - { "ADDRESS", 26, sfunc_addr_address }, - { "STATE", 7, sfunc_addr_state }, - { "GROUP", 12, sfunc_addr_group }, - { "INBOUND", 12, sfunc_addr_inbound }, - { "OUTBOUND", 23, sfunc_addr_outbound }, - { NULL, 0, NULL } +static ofmt_field_t addr_fields[] = { + { "ADDRESS", 26, 0, sfunc_addr_address }, + { "STATE", 7, 0, sfunc_addr_state }, + { "GROUP", 12, 0, sfunc_addr_group }, + { "INBOUND", 12, 0, sfunc_addr_inbound }, + { "OUTBOUND", 23, 0, sfunc_addr_outbound }, + { NULL, 0, 0, NULL } }; -static ipmpstat_field_t group_fields[] = { - { "GROUP", 12, sfunc_group_ifname }, - { "GROUPNAME", 12, sfunc_group_name }, - { "STATE", 10, sfunc_group_state }, - { "FDT", 10, sfunc_group_fdt }, - { "INTERFACES", 30, sfunc_group_interfaces }, - { NULL, 0, NULL } +static ofmt_field_t group_fields[] = { + { "GROUP", 12, 0, sfunc_group_ifname }, + { "GROUPNAME", 12, 0, sfunc_group_name }, + { "STATE", 10, 0, sfunc_group_state }, + { "FDT", 10, 0, sfunc_group_fdt }, + { "INTERFACES", 30, 0, sfunc_group_interfaces }, + { NULL, 0, 0, NULL } }; -static ipmpstat_field_t if_fields[] = { - { "INTERFACE", 12, sfunc_if_name }, - { "ACTIVE", 8, sfunc_if_active }, - { "GROUP", 12, sfunc_if_group }, - { "FLAGS", 10, sfunc_if_flags }, - { "LINK", 10, sfunc_if_link }, - { "PROBE", 10, sfunc_if_probe }, - { "STATE", 10, sfunc_if_state }, - { NULL, 0, NULL } +static ofmt_field_t if_fields[] = { + { "INTERFACE", 12, 0, sfunc_if_name }, + { "ACTIVE", 8, 0, sfunc_if_active }, + { "GROUP", 12, 0, sfunc_if_group }, + { "FLAGS", 10, 0, sfunc_if_flags }, + { "LINK", 10, 0, sfunc_if_link }, + { "PROBE", 10, 0, sfunc_if_probe }, + { "STATE", 10, 0, sfunc_if_state }, + { NULL, 0, 0, NULL } }; -static ipmpstat_field_t probe_fields[] = { - { "TIME", 10, sfunc_probe_time }, - { "INTERFACE", 12, sfunc_probe_ifname }, - { "PROBE", 7, sfunc_probe_id }, - { "NETRTT", 10, sfunc_probe_netrtt }, - { "RTT", 10, sfunc_probe_rtt }, - { "RTTAVG", 10, sfunc_probe_rttavg }, - { "TARGET", 20, sfunc_probe_target }, - { "RTTDEV", 10, sfunc_probe_rttdev }, - { NULL, 0, NULL } +static ofmt_field_t probe_fields[] = { + { "TIME", 10, 0, sfunc_probe_time }, + { "INTERFACE", 12, 0, sfunc_probe_ifname }, + { "PROBE", 7, 0, sfunc_probe_id }, + { "NETRTT", 10, 0, sfunc_probe_netrtt }, + { "RTT", 10, 0, sfunc_probe_rtt }, + { "RTTAVG", 10, 0, sfunc_probe_rttavg }, + { "TARGET", 20, 0, sfunc_probe_target }, + { "RTTDEV", 10, 0, sfunc_probe_rttdev }, + { NULL, 0, 0, NULL } }; -static ipmpstat_field_t targ_fields[] = { - { "INTERFACE", 12, sfunc_targ_ifname }, - { "MODE", 10, sfunc_targ_mode }, - { "TESTADDR", 20, sfunc_targ_testaddr }, - { "TARGETS", 38, sfunc_targ_targets }, - { NULL, 0, NULL } +static ofmt_field_t targ_fields[] = { + { "INTERFACE", 12, 0, sfunc_targ_ifname }, + { "MODE", 10, 0, sfunc_targ_mode }, + { "TESTADDR", 20, 0, sfunc_targ_testaddr }, + { "TARGETS", 38, 0, sfunc_targ_targets }, + { NULL, 0, 0, NULL } }; static ipmpstat_enum_t addr_state[] = { - { "up", IPMP_ADDR_UP }, - { "down", IPMP_ADDR_DOWN }, - { NULL, 0 } + { "up", IPMP_ADDR_UP }, + { "down", IPMP_ADDR_DOWN }, + { NULL, 0 } }; static ipmpstat_enum_t group_state[] = { - { "ok", IPMP_GROUP_OK }, - { "failed", IPMP_GROUP_FAILED }, - { "degraded", IPMP_GROUP_DEGRADED }, - { NULL, 0 } + { "ok", IPMP_GROUP_OK }, + { "failed", IPMP_GROUP_FAILED }, + { "degraded", IPMP_GROUP_DEGRADED }, + { NULL, 0 } }; static ipmpstat_enum_t if_link[] = { - { "up", IPMP_LINK_UP }, - { "down", IPMP_LINK_DOWN }, - { "unknown", IPMP_LINK_UNKNOWN }, - { NULL, 0 } + { "up", IPMP_LINK_UP }, + { "down", IPMP_LINK_DOWN }, + { "unknown", IPMP_LINK_UNKNOWN }, + { NULL, 0 } }; static ipmpstat_enum_t if_probe[] = { - { "ok", IPMP_PROBE_OK }, - { "failed", IPMP_PROBE_FAILED }, - { "unknown", IPMP_PROBE_UNKNOWN }, - { "disabled", IPMP_PROBE_DISABLED }, - { NULL, 0 } + { "ok", IPMP_PROBE_OK }, + { "failed", IPMP_PROBE_FAILED }, + { "unknown", IPMP_PROBE_UNKNOWN }, + { "disabled", IPMP_PROBE_DISABLED }, + { NULL, 0 } }; static ipmpstat_enum_t if_state[] = { - { "ok", IPMP_IF_OK }, - { "failed", IPMP_IF_FAILED }, - { "unknown", IPMP_IF_UNKNOWN }, - { "offline", IPMP_IF_OFFLINE }, - { NULL, 0 } + { "ok", IPMP_IF_OK }, + { "failed", IPMP_IF_FAILED }, + { "unknown", IPMP_IF_UNKNOWN }, + { "offline", IPMP_IF_OFFLINE }, + { NULL, 0 } }; static ipmpstat_enum_t targ_mode[] = { - { "disabled", IPMP_TARG_DISABLED }, - { "routes", IPMP_TARG_ROUTES }, - { "multicast", IPMP_TARG_MULTICAST }, - { NULL, 0 } + { "disabled", IPMP_TARG_DISABLED }, + { "routes", IPMP_TARG_ROUTES }, + { "multicast", IPMP_TARG_MULTICAST }, + { NULL, 0 } }; diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.xcl b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.xcl index e2398aaf64..3948397e7f 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.xcl +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/ipmpstat.xcl @@ -27,15 +27,14 @@ msgid "%.2fms" msgid "%.2fs" msgid "%d-%s" msgid "%s" +msgid "%s\n" msgid "%s " msgid "%s: " msgid "%u" msgid "(" msgid ")" msgid "," -msgid "--" msgid ": %s\n" -msgid "?" msgid "[" msgid "]" msgid "<%d>" diff --git a/usr/src/cmd/dladm/dladm.c b/usr/src/cmd/dladm/dladm.c index d8be7d92da..d98fba69f1 100644 --- a/usr/src/cmd/dladm/dladm.c +++ b/usr/src/cmd/dladm/dladm.c @@ -65,8 +65,8 @@ #include <arpa/inet.h> #include <net/if_types.h> #include <stddef.h> +#include <ofmt.h> -#define STR_UNDEF_VAL "--" #define MAXPORT 256 #define MAXVNIC 256 #define BUFLEN(lim, ptr) (((lim) > (ptr)) ? ((lim) - (ptr)) : 0) @@ -74,141 +74,23 @@ #define SMF_UPGRADE_FILE "/var/svc/profile/upgrade" #define SMF_UPGRADEDATALINK_FILE "/var/svc/profile/upgrade_datalink" #define SMF_DLADM_UPGRADE_MSG " # added by dladm(1M)" +#define DLADM_DEFAULT_COL 80 -#define CMD_TYPE_ANY 0xffffffff +/* + * used by the wifi show-* commands to set up ofmt_field_t structures. + */ #define WIFI_CMD_SCAN 0x00000001 #define WIFI_CMD_SHOW 0x00000002 #define WIFI_CMD_ALL (WIFI_CMD_SCAN | WIFI_CMD_SHOW) -/* - * Data structures and routines for printing output. - * All non-parseable output is assumed to be in a columnar format. - * Multiple fields in parsable output are separated by ':'; single - * field output is printed as-is. - * - * Each sub-command is associated with a global array of pointers, - * print_field_t *fields[], where the print_field_t contains information - * about the format in which the output is to be printed. - * - * Sub-commands may be implemented in one of two ways: - * (i) the implementation could get all field values into a character - * buffer, with pf_offset containing the offset (for pf_name) within - * the buffer. The sub-command would make the needed system calls - * to obtain all possible column values and then invoke the - * dladm_print_field() function to print the specific fields - * requested in the command line. See the comments for dladm_print_field - * for further details. - * (ii) Alternatively, each fields[i] entry could store a pf_index value - * that uniquely identifies the column to be printed. The implementation - * of the sub-command would then invoke dladm_print_output() with a - * callback function whose semantics are described below (see comments - * for dladm_print_output()) - * - * Thus, an implementation of a sub-command must provide the following: - * - * static print_field_t sub_command_fields[] = { - * {<name>, <header>,<field width>, <offset_or_index>, cmdtype}, - * : - * {<name>, <header>,<field width>, <offset_or_index>, cmdtype} - * }; - * - * #define SUB_COMMAND_MAX_FIELDS sizeof \ - * (sub_comand_fields) / sizeof (print_field_t)) - * - * print_state_t sub_command_print_state; - * - * The function that parses command line arguments (typically - * do_sub_command()) should then contain an invocation like: - * - * fields = parse_output_fields(fields_str, sub_command_fields, - * SUB_COMMAND_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - * - * and store the resulting fields and nfields value in a print_state_t - * structure tracked for the command. - * - * sub_command_print_state.ps_fields = fields; - * sub_command_print_state.ps_nfields = nfields; - * - * To print the column header for the output, the print_header() - * function must then be invoked by do_sub_command(). - * - * Then if method (i) is used for the sub_command, the do_sub_command() - * function should make the necessary system calls to fill up the buffer - * and then invoke dladm_print_field(). An example of this method is - * the implementation of do_show_link() and show_link(); - * - * If method (ii) is used, do_sub_command should invoke dladm_print_output() - * with a callback function that will be called for each field to be printed. - * The callback function will be passed a pointer to the print_field_t - * for the field, and the pf_index may then be used to identify the - * system call required to find the value to be printed. - */ - -typedef struct print_field_s { - const char *pf_name; /* name of column to be printed */ - const char *pf_header; /* header for this column */ - uint_t pf_width; - union { - uint_t _pf_index; /* private index for sub-command */ - size_t _pf_offset; - }_pf_un; -#define pf_index _pf_un._pf_index -#define pf_offset _pf_un._pf_offset; - uint_t pf_cmdtype; -} print_field_t; - -/* - * The state of the output is tracked in a print_state_t structure. - * Each ps_fields[i] entry points at the global print_field_t array for - * the sub-command, where ps_nfields is the number of requested fields. - */ -typedef struct print_state_s { - print_field_t **ps_fields; - uint_t ps_nfields; - boolean_t ps_lastfield; - uint_t ps_overflow; -} print_state_t; - -typedef char *(*print_callback_t)(print_field_t *, void *); -static print_field_t **parse_output_fields(char *, print_field_t *, int, - uint_t, uint_t *); -/* - * print the header for the output - */ -static void print_header(print_state_t *); -static void print_field(print_state_t *, print_field_t *, const char *, - boolean_t); - -/* - * to print output values, call dladm_print_output with a callback - * function (*func)() that should parse the args and return an - * unformatted character buffer with the value to be printed. - * - * dladm_print_output() prints the character buffer using the formatting - * information provided in the print_field_t for that column. - */ -static void dladm_print_output(print_state_t *, boolean_t, - print_callback_t, void *); - -/* - * helper function that, when invoked as dladm_print_field(pf, buf) - * prints string which is offset by pf->pf_offset within buf. - */ -static char *dladm_print_field(print_field_t *, void *); - - -#define MAX_FIELD_LEN 32 - - typedef struct show_state { boolean_t ls_firstonly; boolean_t ls_donefirst; pktsum_t ls_prevstats; uint32_t ls_flags; dladm_status_t ls_status; - print_state_t ls_print; - boolean_t ls_parseable; - boolean_t ls_printheader; + ofmt_handle_t ls_ofmt; + boolean_t ls_parsable; boolean_t ls_mac; boolean_t ls_hwgrp; } show_state_t; @@ -217,14 +99,13 @@ typedef struct show_grp_state { pktsum_t gs_prevstats[MAXPORT]; uint32_t gs_flags; dladm_status_t gs_status; - boolean_t gs_parseable; + boolean_t gs_parsable; boolean_t gs_lacp; boolean_t gs_extended; boolean_t gs_stats; boolean_t gs_firstonly; boolean_t gs_donefirst; - boolean_t gs_printheader; - print_state_t gs_print; + ofmt_handle_t gs_ofmt; } show_grp_state_t; typedef struct show_vnic_state { @@ -232,8 +113,7 @@ typedef struct show_vnic_state { datalink_id_t vs_link_id; char vs_vnic[MAXLINKNAMELEN]; char vs_link[MAXLINKNAMELEN]; - boolean_t vs_parseable; - boolean_t vs_printheader; + boolean_t vs_parsable; boolean_t vs_found; boolean_t vs_firstonly; boolean_t vs_donefirst; @@ -244,18 +124,28 @@ typedef struct show_vnic_state { boolean_t vs_etherstub; dladm_status_t vs_status; uint32_t vs_flags; - print_state_t vs_print; + ofmt_handle_t vs_ofmt; } show_vnic_state_t; typedef struct show_usage_state_s { boolean_t us_plot; - boolean_t us_parseable; + boolean_t us_parsable; boolean_t us_printheader; boolean_t us_first; boolean_t us_showall; - print_state_t us_print; + ofmt_handle_t us_ofmt; } show_usage_state_t; +/* + * callback functions for printing output and error diagnostics. + */ +static ofmt_cb_t print_default_cb, print_link_stats_cb, print_linkprop_cb; +static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb; +static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb; +static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb; +static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb; +static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); + typedef void cmdfunc_t(int, char **, const char *); static cmdfunc_t do_show_link, do_show_wifi, do_show_phys; @@ -420,6 +310,7 @@ static const struct option show_lopts[] = { {"statistics", no_argument, 0, 's'}, {"continuous", no_argument, 0, 'S'}, {"interval", required_argument, 0, 'i'}, + {"parsable", no_argument, 0, 'p'}, {"parseable", no_argument, 0, 'p'}, {"extended", no_argument, 0, 'x'}, {"output", required_argument, 0, 'o'}, @@ -433,12 +324,14 @@ static const struct option prop_longopts[] = { {"output", required_argument, 0, 'o' }, {"root-dir", required_argument, 0, 'R' }, {"prop", required_argument, 0, 'p' }, + {"parsable", no_argument, 0, 'c' }, {"parseable", no_argument, 0, 'c' }, {"persistent", no_argument, 0, 'P' }, { 0, 0, 0, 0 } }; static const struct option wifi_longopts[] = { + {"parsable", no_argument, 0, 'p' }, {"parseable", no_argument, 0, 'p' }, {"output", required_argument, 0, 'o' }, {"essid", required_argument, 0, 'e' }, @@ -457,6 +350,7 @@ static const struct option wifi_longopts[] = { { 0, 0, 0, 0 } }; static const struct option showeth_lopts[] = { + {"parsable", no_argument, 0, 'p' }, {"parseable", no_argument, 0, 'p' }, {"extended", no_argument, 0, 'x' }, {"output", required_argument, 0, 'o' }, @@ -505,31 +399,33 @@ typedef struct ether_fields_buf_s char eth_rem_fault[16]; } ether_fields_buf_t; -static print_field_t ether_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 15, - offsetof(ether_fields_buf_t, eth_link), CMD_TYPE_ANY}, -{ "ptype", "PTYPE", 8, - offsetof(ether_fields_buf_t, eth_ptype), CMD_TYPE_ANY}, -{ "state", "STATE", 8, - offsetof(ether_fields_buf_t, eth_state), CMD_TYPE_ANY}, -{ "auto", "AUTO", 5, - offsetof(ether_fields_buf_t, eth_autoneg), CMD_TYPE_ANY}, -{ "speed-duplex", "SPEED-DUPLEX", 31, - offsetof(ether_fields_buf_t, eth_spdx), CMD_TYPE_ANY}, -{ "pause", "PAUSE", 6, - offsetof(ether_fields_buf_t, eth_pause), CMD_TYPE_ANY}, -{ "rem_fault", "REM_FAULT", 16, - offsetof(ether_fields_buf_t, eth_rem_fault), CMD_TYPE_ANY}} +static ofmt_field_t ether_fields[] = { +/* name, field width, offset callback */ +{ "LINK", 16, + offsetof(ether_fields_buf_t, eth_link), print_default_cb}, +{ "PTYPE", 9, + offsetof(ether_fields_buf_t, eth_ptype), print_default_cb}, +{ "STATE", 9, + offsetof(ether_fields_buf_t, eth_state), + print_default_cb}, +{ "AUTO", 6, + offsetof(ether_fields_buf_t, eth_autoneg), print_default_cb}, +{ "SPEED-DUPLEX", 32, + offsetof(ether_fields_buf_t, eth_spdx), print_default_cb}, +{ "PAUSE", 7, + offsetof(ether_fields_buf_t, eth_pause), print_default_cb}, +{ "REM_FAULT", 17, + offsetof(ether_fields_buf_t, eth_rem_fault), print_default_cb}, +{NULL, 0, + 0, NULL}} ; -#define ETHER_MAX_FIELDS (sizeof (ether_fields) / sizeof (print_field_t)) typedef struct print_ether_state { const char *es_link; - boolean_t es_parseable; + boolean_t es_parsable; boolean_t es_header; boolean_t es_extended; - print_state_t es_print; + ofmt_handle_t es_ofmt; } print_ether_state_t; /* @@ -545,24 +441,21 @@ typedef enum { LINK_S_OERRORS } link_s_field_index_t; -static print_field_t link_s_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "link", "LINK", 15, LINK_S_LINK, CMD_TYPE_ANY}, -{ "ipackets", "IPACKETS", 10, LINK_S_IPKTS, CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 8, LINK_S_RBYTES, CMD_TYPE_ANY}, -{ "ierrors", "IERRORS", 10, LINK_S_IERRORS, CMD_TYPE_ANY}, -{ "opackets", "OPACKETS", 12, LINK_S_OPKTS, CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 12, LINK_S_OBYTES, CMD_TYPE_ANY}, -{ "oerrors", "OERRORS", 8, LINK_S_OERRORS, CMD_TYPE_ANY}} +static ofmt_field_t link_s_fields[] = { +/* name, field width, index, callback */ +{ "LINK", 15, LINK_S_LINK, print_link_stats_cb}, +{ "IPACKETS", 10, LINK_S_IPKTS, print_link_stats_cb}, +{ "RBYTES", 8, LINK_S_RBYTES, print_link_stats_cb}, +{ "IERRORS", 10, LINK_S_IERRORS, print_link_stats_cb}, +{ "OPACKETS", 12, LINK_S_OPKTS, print_link_stats_cb}, +{ "OBYTES", 12, LINK_S_OBYTES, print_link_stats_cb}, +{ "OERRORS", 8, LINK_S_OERRORS, print_link_stats_cb}} ; -#define LINK_S_MAX_FIELDS \ - (sizeof (link_s_fields) / sizeof (print_field_t)) typedef struct link_args_s { char *link_s_link; pktsum_t *link_s_psum; } link_args_t; -static char *print_link_stats(print_field_t *, void *); /* * buffer used by print functions for show-{link,phys,vlan} commands. @@ -585,20 +478,20 @@ typedef struct link_fields_buf_s { /* * structures for 'dladm show-link' */ -static print_field_t link_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 11, - offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, -{ "class", "CLASS", 8, - offsetof(link_fields_buf_t, link_class), CMD_TYPE_ANY}, -{ "mtu", "MTU", 6, - offsetof(link_fields_buf_t, link_mtu), CMD_TYPE_ANY}, -{ "state", "STATE", 8, - offsetof(link_fields_buf_t, link_state), CMD_TYPE_ANY}, -{ "over", "OVER", DLPI_LINKNAME_MAX, - offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}} +static ofmt_field_t link_fields[] = { +/* name, field width, index, callback */ +{ "LINK", 12, + offsetof(link_fields_buf_t, link_name), print_default_cb}, +{ "CLASS", 9, + offsetof(link_fields_buf_t, link_class), print_default_cb}, +{ "MTU", 7, + offsetof(link_fields_buf_t, link_mtu), print_default_cb}, +{ "STATE", 9, + offsetof(link_fields_buf_t, link_state), print_default_cb}, +{ "OVER", DLPI_LINKNAME_MAX, + offsetof(link_fields_buf_t, link_over), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define DEV_LINK_FIELDS (sizeof (link_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-aggr' @@ -619,25 +512,25 @@ typedef struct laggr_args_s { dladm_status_t *laggr_status; pktsum_t *laggr_pktsumtot; /* -s only */ pktsum_t *laggr_prevstats; /* -s only */ - boolean_t laggr_parseable; + boolean_t laggr_parsable; } laggr_args_t; -static print_field_t laggr_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 15, - offsetof(laggr_fields_buf_t, laggr_name), CMD_TYPE_ANY}, -{ "policy", "POLICY", 8, - offsetof(laggr_fields_buf_t, laggr_policy), CMD_TYPE_ANY}, -{ "addrpolicy", "ADDRPOLICY", ETHERADDRL * 3 + 2, - offsetof(laggr_fields_buf_t, laggr_addrpolicy), CMD_TYPE_ANY}, -{ "lacpactivity", "LACPACTIVITY", 13, - offsetof(laggr_fields_buf_t, laggr_lacpactivity), CMD_TYPE_ANY}, -{ "lacptimer", "LACPTIMER", 11, - offsetof(laggr_fields_buf_t, laggr_lacptimer), CMD_TYPE_ANY}, -{ "flags", "FLAGS", 7, - offsetof(laggr_fields_buf_t, laggr_flags), CMD_TYPE_ANY}} +static ofmt_field_t laggr_fields[] = { +/* name, field width, offset, callback */ +{ "LINK", 16, + offsetof(laggr_fields_buf_t, laggr_name), print_default_cb}, +{ "POLICY", 9, + offsetof(laggr_fields_buf_t, laggr_policy), print_default_cb}, +{ "ADDRPOLICY", ETHERADDRL * 3 + 3, + offsetof(laggr_fields_buf_t, laggr_addrpolicy), print_default_cb}, +{ "LACPACTIVITY", 14, + offsetof(laggr_fields_buf_t, laggr_lacpactivity), print_default_cb}, +{ "LACPTIMER", 12, + offsetof(laggr_fields_buf_t, laggr_lacptimer), print_default_cb}, +{ "FLAGS", 8, + offsetof(laggr_fields_buf_t, laggr_flags), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define LAGGR_MAX_FIELDS (sizeof (laggr_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-aggr -x'. @@ -652,18 +545,17 @@ typedef enum { AGGR_X_PORTSTATE } aggr_x_field_index_t; -static print_field_t aggr_x_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "link", "LINK", 11, AGGR_X_LINK, CMD_TYPE_ANY}, -{ "port", "PORT", 14, AGGR_X_PORT, CMD_TYPE_ANY}, -{ "speed", "SPEED", 4, AGGR_X_SPEED, CMD_TYPE_ANY}, -{ "duplex", "DUPLEX", 9, AGGR_X_DUPLEX, CMD_TYPE_ANY}, -{ "state", "STATE", 9, AGGR_X_STATE, CMD_TYPE_ANY}, -{ "address", "ADDRESS", 18, AGGR_X_ADDRESS, CMD_TYPE_ANY}, -{ "portstate", "PORTSTATE", 15, AGGR_X_PORTSTATE, CMD_TYPE_ANY}} +static ofmt_field_t aggr_x_fields[] = { +/* name, field width, index callback */ +{ "LINK", 12, AGGR_X_LINK, print_xaggr_cb}, +{ "PORT", 15, AGGR_X_PORT, print_xaggr_cb}, +{ "SPEED", 5, AGGR_X_SPEED, print_xaggr_cb}, +{ "DUPLEX", 10, AGGR_X_DUPLEX, print_xaggr_cb}, +{ "STATE", 10, AGGR_X_STATE, print_xaggr_cb}, +{ "ADDRESS", 19, AGGR_X_ADDRESS, print_xaggr_cb}, +{ "PORTSTATE", 16, AGGR_X_PORTSTATE, print_xaggr_cb}, +{ NULL, 0, 0, NULL}} ; -#define AGGR_X_MAX_FIELDS \ - (sizeof (aggr_x_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-aggr -s'. @@ -679,27 +571,17 @@ typedef enum { AGGR_S_OPKTDIST } aggr_s_field_index_t; -static print_field_t aggr_s_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "link", "LINK", 11, AGGR_S_LINK, - CMD_TYPE_ANY}, -{ "port", "PORT", 9, AGGR_S_PORT, - CMD_TYPE_ANY}, -{ "ipackets", "IPACKETS", 7, AGGR_S_IPKTS, - CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 7, AGGR_S_RBYTES, - CMD_TYPE_ANY}, -{ "opackets", "OPACKETS", 7, AGGR_S_OPKTS, - CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 7, AGGR_S_OBYTES, - CMD_TYPE_ANY}, -{ "ipktdist", "IPKTDIST", 8, AGGR_S_IPKTDIST, - CMD_TYPE_ANY}, -{ "opktdist", "OPKTDIST", 14, AGGR_S_OPKTDIST, - CMD_TYPE_ANY}} +static ofmt_field_t aggr_s_fields[] = { +{ "LINK", 12, AGGR_S_LINK, print_aggr_stats_cb}, +{ "PORT", 10, AGGR_S_PORT, print_aggr_stats_cb}, +{ "IPACKETS", 8, AGGR_S_IPKTS, print_aggr_stats_cb}, +{ "RBYTES", 8, AGGR_S_RBYTES, print_aggr_stats_cb}, +{ "OPACKETS", 8, AGGR_S_OPKTS, print_aggr_stats_cb}, +{ "OBYTES", 8, AGGR_S_OBYTES, print_aggr_stats_cb}, +{ "IPKTDIST", 9, AGGR_S_IPKTDIST, print_aggr_stats_cb}, +{ "OPKTDIST", 15, AGGR_S_OPKTDIST, print_aggr_stats_cb}, +{ NULL, 0, 0, NULL}} ; -#define AGGR_S_MAX_FIELDS \ - (sizeof (aggr_s_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-aggr -L'. @@ -715,50 +597,41 @@ typedef enum { AGGR_L_EXPIRED } aggr_l_field_index_t; -static print_field_t aggr_l_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "link", "LINK", 11, AGGR_L_LINK, - CMD_TYPE_ANY}, -{ "port", "PORT", 12, AGGR_L_PORT, - CMD_TYPE_ANY}, -{ "aggregatable", "AGGREGATABLE", 12, AGGR_L_AGGREGATABLE, - CMD_TYPE_ANY}, -{ "sync", "SYNC", 4, AGGR_L_SYNC, - CMD_TYPE_ANY}, -{ "coll", "COLL", 4, AGGR_L_COLL, - CMD_TYPE_ANY}, -{ "dist", "DIST", 4, AGGR_L_DIST, - CMD_TYPE_ANY}, -{ "defaulted", "DEFAULTED", 9, AGGR_L_DEFAULTED, - CMD_TYPE_ANY}, -{ "expired", "EXPIRED", 14, AGGR_L_EXPIRED, - CMD_TYPE_ANY}} +static ofmt_field_t aggr_l_fields[] = { +/* name, field width, index */ +{ "LINK", 12, AGGR_L_LINK, print_lacp_cb}, +{ "PORT", 13, AGGR_L_PORT, print_lacp_cb}, +{ "AGGREGATABLE", 13, AGGR_L_AGGREGATABLE, print_lacp_cb}, +{ "SYNC", 5, AGGR_L_SYNC, print_lacp_cb}, +{ "COLL", 5, AGGR_L_COLL, print_lacp_cb}, +{ "DIST", 5, AGGR_L_DIST, print_lacp_cb}, +{ "DEFAULTED", 10, AGGR_L_DEFAULTED, print_lacp_cb}, +{ "EXPIRED", 15, AGGR_L_EXPIRED, print_lacp_cb}, +{ NULL, 0, 0, NULL}} ; -#define AGGR_L_MAX_FIELDS \ - (sizeof (aggr_l_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-phys' */ -static print_field_t phys_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, - offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, -{ "media", "MEDIA", 20, - offsetof(link_fields_buf_t, link_phys_media), CMD_TYPE_ANY}, -{ "state", "STATE", 10, - offsetof(link_fields_buf_t, link_phys_state), CMD_TYPE_ANY}, -{ "speed", "SPEED", 6, - offsetof(link_fields_buf_t, link_phys_speed), CMD_TYPE_ANY}, -{ "duplex", "DUPLEX", 9, - offsetof(link_fields_buf_t, link_phys_duplex), CMD_TYPE_ANY}, -{ "device", "DEVICE", 12, - offsetof(link_fields_buf_t, link_phys_device), CMD_TYPE_ANY}, -{ "flags", "FLAGS", 6, - offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +static ofmt_field_t phys_fields[] = { +/* name, field width, offset */ +{ "LINK", 13, + offsetof(link_fields_buf_t, link_name), print_default_cb}, +{ "MEDIA", 21, + offsetof(link_fields_buf_t, link_phys_media), print_default_cb}, +{ "STATE", 11, + offsetof(link_fields_buf_t, link_phys_state), print_default_cb}, +{ "SPEED", 7, + offsetof(link_fields_buf_t, link_phys_speed), print_default_cb}, +{ "DUPLEX", 10, + offsetof(link_fields_buf_t, link_phys_duplex), print_default_cb}, +{ "DEVICE", 13, + offsetof(link_fields_buf_t, link_phys_device), print_default_cb}, +{ "FLAGS", 7, + offsetof(link_fields_buf_t, link_flags), print_default_cb}, +{ NULL, 0, NULL, 0}} ; -#define PHYS_MAX_FIELDS (sizeof (phys_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-phys -m' @@ -772,15 +645,15 @@ typedef enum { PHYS_M_CLIENT } phys_m_field_index_t; -static print_field_t phys_m_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, PHYS_M_LINK, CMD_TYPE_ANY}, -{ "slot", "SLOT", 8, PHYS_M_SLOT, CMD_TYPE_ANY}, -{ "address", "ADDRESS", 18, PHYS_M_ADDRESS, CMD_TYPE_ANY}, -{ "inuse", "INUSE", 4, PHYS_M_INUSE, CMD_TYPE_ANY}, -{ "client", "CLIENT", 12, PHYS_M_CLIENT, CMD_TYPE_ANY}} +static ofmt_field_t phys_m_fields[] = { +/* name, field width, offset */ +{ "LINK", 13, PHYS_M_LINK, print_phys_one_mac_cb}, +{ "SLOT", 9, PHYS_M_SLOT, print_phys_one_mac_cb}, +{ "ADDRESS", 19, PHYS_M_ADDRESS, print_phys_one_mac_cb}, +{ "INUSE", 5, PHYS_M_INUSE, print_phys_one_mac_cb}, +{ "CLIENT", 13, PHYS_M_CLIENT, print_phys_one_mac_cb}, +{ NULL, 0, 0, NULL}} ; -#define PHYS_M_MAX_FIELDS (sizeof (phys_m_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-phys -H' @@ -794,49 +667,55 @@ typedef enum { PHYS_H_CLIENTS } phys_h_field_index_t; -static print_field_t phys_h_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, PHYS_H_LINK, CMD_TYPE_ANY}, -{ "group", "GROUP", 8, PHYS_H_GROUP, CMD_TYPE_ANY}, -{ "grouptype", "TYPE", 6, PHYS_H_GRPTYPE, CMD_TYPE_ANY}, -{ "rings", "NUM-RINGS", 16, PHYS_H_RINGS, CMD_TYPE_ANY}, -{ "clients", "CLIENTS", 20, PHYS_H_CLIENTS, CMD_TYPE_ANY}} +static ofmt_field_t phys_h_fields[] = { +{ "LINK", 13, PHYS_H_LINK, print_phys_one_hwgrp_cb}, +{ "GROUP", 9, PHYS_H_GROUP, print_phys_one_hwgrp_cb}, +{ "GROUPTYPE", 7, PHYS_H_GRPTYPE, print_phys_one_hwgrp_cb}, +{ "RINGS", 17, PHYS_H_RINGS, print_phys_one_hwgrp_cb}, +{ "CLIENTS", 21, PHYS_H_CLIENTS, print_phys_one_hwgrp_cb}, +{ NULL, 0, 0, NULL}} ; -#define PHYS_H_MAX_FIELDS (sizeof (phys_h_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-vlan' */ -static print_field_t vlan_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 15, - offsetof(link_fields_buf_t, link_name), CMD_TYPE_ANY}, -{ "vid", "VID", 8, - offsetof(link_fields_buf_t, link_vlan_vid), CMD_TYPE_ANY}, -{ "over", "OVER", 12, - offsetof(link_fields_buf_t, link_over), CMD_TYPE_ANY}, -{ "flags", "FLAGS", 6, - offsetof(link_fields_buf_t, link_flags), CMD_TYPE_ANY}} +static ofmt_field_t vlan_fields[] = { +{ "LINK", 16, + offsetof(link_fields_buf_t, link_name), print_default_cb}, +{ "VID", 9, + offsetof(link_fields_buf_t, link_vlan_vid), print_default_cb}, +{ "OVER", 13, + offsetof(link_fields_buf_t, link_over), print_default_cb}, +{ "FLAGS", 7, + offsetof(link_fields_buf_t, link_flags), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define VLAN_MAX_FIELDS (sizeof (vlan_fields) / sizeof (print_field_t)) +/* + * structures common to 'dladm scan-wifi' and 'dladm show-wifi' + * callback will be determined in parse_wifi_fields. + */ +static ofmt_field_t wifi_common_fields[] = { +{ "LINK", 11, 0, NULL}, +{ "ESSID", 20, DLADM_WLAN_ATTR_ESSID, NULL}, +{ "BSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, +{ "IBSSID", 18, DLADM_WLAN_ATTR_BSSID, NULL}, +{ "MODE", 7, DLADM_WLAN_ATTR_MODE, NULL}, +{ "SPEED", 7, DLADM_WLAN_ATTR_SPEED, NULL}, +{ "BSSTYPE", 9, DLADM_WLAN_ATTR_BSSTYPE, NULL}, +{ "SEC", 7, DLADM_WLAN_ATTR_SECMODE, NULL}, +{ "STRENGTH", 11, DLADM_WLAN_ATTR_STRENGTH, NULL}, +{ NULL, 0, 0, NULL}}; /* - * structures for 'dladm show-wifi' + * the 'show-wifi' command supports all the fields in wifi_common_fields + * plus the AUTH and STATUS fields. */ -static print_field_t wifi_fields[] = { -{ "link", "LINK", 10, 0, WIFI_CMD_ALL}, -{ "essid", "ESSID", 19, DLADM_WLAN_ATTR_ESSID, WIFI_CMD_ALL}, -{ "bssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "ibssid", "BSSID/IBSSID", 17, DLADM_WLAN_ATTR_BSSID, WIFI_CMD_ALL}, -{ "mode", "MODE", 6, DLADM_WLAN_ATTR_MODE, WIFI_CMD_ALL}, -{ "speed", "SPEED", 6, DLADM_WLAN_ATTR_SPEED, WIFI_CMD_ALL}, -{ "auth", "AUTH", 8, DLADM_WLAN_ATTR_AUTH, WIFI_CMD_SHOW}, -{ "bsstype", "BSSTYPE", 8, DLADM_WLAN_ATTR_BSSTYPE, WIFI_CMD_ALL}, -{ "sec", "SEC", 6, DLADM_WLAN_ATTR_SECMODE, WIFI_CMD_ALL}, -{ "status", "STATUS", 17, DLADM_WLAN_LINKATTR_STATUS, WIFI_CMD_SHOW}, -{ "strength", "STRENGTH", 10, DLADM_WLAN_ATTR_STRENGTH, WIFI_CMD_ALL}} -; +static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = { +{ "AUTH", 9, DLADM_WLAN_ATTR_AUTH, NULL}, +{ "STATUS", 18, DLADM_WLAN_LINKATTR_STATUS, print_wifi_status_cb}, +/* copy wifi_common_fields here */ +}; static char *all_scan_wifi_fields = "link,essid,bssid,sec,strength,mode,speed,bsstype"; @@ -847,8 +726,6 @@ static char *def_scan_wifi_fields = static char *def_show_wifi_fields = "link,status,essid,sec,strength,mode,speed"; -#define WIFI_MAX_FIELDS (sizeof (wifi_fields) / sizeof (print_field_t)) - /* * structures for 'dladm show-linkprop' */ @@ -861,17 +738,16 @@ typedef enum { LINKPROP_POSSIBLE } linkprop_field_index_t; -static print_field_t linkprop_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "link", "LINK", 12, LINKPROP_LINK, CMD_TYPE_ANY}, -{ "property", "PROPERTY", 15, LINKPROP_PROPERTY, CMD_TYPE_ANY}, -{ "perm", "PERM", 4, LINKPROP_PERM, CMD_TYPE_ANY}, -{ "value", "VALUE", 14, LINKPROP_VALUE, CMD_TYPE_ANY}, -{ "default", "DEFAULT", 14, LINKPROP_DEFAULT, CMD_TYPE_ANY}, -{ "possible", "POSSIBLE", 20, LINKPROP_POSSIBLE, CMD_TYPE_ANY}} +static ofmt_field_t linkprop_fields[] = { +/* name, field width, index */ +{ "LINK", 13, LINKPROP_LINK, print_linkprop_cb}, +{ "PROPERTY", 16, LINKPROP_PROPERTY, print_linkprop_cb}, +{ "PERM", 5, LINKPROP_PERM, print_linkprop_cb}, +{ "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb}, +{ "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb}, +{ "POSSIBLE", 21, LINKPROP_POSSIBLE, print_linkprop_cb}, +{ NULL, 0, 0, NULL}} ; -#define LINKPROP_MAX_FIELDS \ - (sizeof (linkprop_fields) / sizeof (print_field_t)) #define MAX_PROP_LINE 512 @@ -880,12 +756,12 @@ typedef struct show_linkprop_state { char *ls_line; char **ls_propvals; dladm_arg_list_t *ls_proplist; - boolean_t ls_parseable; + boolean_t ls_parsable; boolean_t ls_persist; boolean_t ls_header; dladm_status_t ls_status; dladm_status_t ls_retstatus; - print_state_t ls_print; + ofmt_handle_t ls_ofmt; } show_linkprop_state_t; typedef struct set_linkprop_state { @@ -909,16 +785,16 @@ typedef struct secobj_fields_buf_s { char ss_class[20]; char ss_val[30]; } secobj_fields_buf_t; -static print_field_t secobj_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "object", "OBJECT", 20, - offsetof(secobj_fields_buf_t, ss_obj_name), CMD_TYPE_ANY}, -{ "class", "CLASS", 20, - offsetof(secobj_fields_buf_t, ss_class), CMD_TYPE_ANY}, -{ "value", "VALUE", 30, - offsetof(secobj_fields_buf_t, ss_val), CMD_TYPE_ANY}} + +static ofmt_field_t secobj_fields[] = { +{ "OBJECT", 21, + offsetof(secobj_fields_buf_t, ss_obj_name), print_default_cb}, +{ "CLASS", 21, + offsetof(secobj_fields_buf_t, ss_class), print_default_cb}, +{ "VALUE", 31, + offsetof(secobj_fields_buf_t, ss_val), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define DEV_SOBJ_FIELDS (sizeof (secobj_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-vnic' @@ -933,22 +809,21 @@ typedef struct vnic_fields_buf_s char vnic_vid[6]; } vnic_fields_buf_t; -static print_field_t vnic_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, - offsetof(vnic_fields_buf_t, vnic_link), CMD_TYPE_ANY}, -{ "over", "OVER", 12, - offsetof(vnic_fields_buf_t, vnic_over), CMD_TYPE_ANY}, -{ "speed", "SPEED", 6, - offsetof(vnic_fields_buf_t, vnic_speed), CMD_TYPE_ANY}, -{ "macaddress", "MACADDRESS", 20, - offsetof(vnic_fields_buf_t, vnic_macaddr), CMD_TYPE_ANY}, -{ "macaddrtype", "MACADDRTYPE", 19, - offsetof(vnic_fields_buf_t, vnic_macaddrtype), CMD_TYPE_ANY}, -{ "vid", "VID", 6, - offsetof(vnic_fields_buf_t, vnic_vid), CMD_TYPE_ANY}} +static ofmt_field_t vnic_fields[] = { +{ "LINK", 13, + offsetof(vnic_fields_buf_t, vnic_link), print_default_cb}, +{ "OVER", 13, + offsetof(vnic_fields_buf_t, vnic_over), print_default_cb}, +{ "SPEED", 7, + offsetof(vnic_fields_buf_t, vnic_speed), print_default_cb}, +{ "MACADDRESS", 21, + offsetof(vnic_fields_buf_t, vnic_macaddr), print_default_cb}, +{ "MACADDRTYPE", 20, + offsetof(vnic_fields_buf_t, vnic_macaddrtype), print_default_cb}, +{ "VID", 7, + offsetof(vnic_fields_buf_t, vnic_vid), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define VNIC_MAX_FIELDS (sizeof (vnic_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-usage' @@ -964,25 +839,24 @@ typedef struct usage_fields_buf_s { char usage_bandwidth[14]; } usage_fields_buf_t; -static print_field_t usage_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, - offsetof(usage_fields_buf_t, usage_link), CMD_TYPE_ANY}, -{ "duration", "DURATION", 10, - offsetof(usage_fields_buf_t, usage_duration), CMD_TYPE_ANY}, -{ "ipackets", "IPACKETS", 9, - offsetof(usage_fields_buf_t, usage_ipackets), CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 10, - offsetof(usage_fields_buf_t, usage_rbytes), CMD_TYPE_ANY}, -{ "opackets", "OPACKETS", 9, - offsetof(usage_fields_buf_t, usage_opackets), CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 10, - offsetof(usage_fields_buf_t, usage_obytes), CMD_TYPE_ANY}, -{ "bandwidth", "BANDWIDTH", 14, - offsetof(usage_fields_buf_t, usage_bandwidth), CMD_TYPE_ANY}} +static ofmt_field_t usage_fields[] = { +{ "LINK", 13, + offsetof(usage_fields_buf_t, usage_link), print_default_cb}, +{ "DURATION", 11, + offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, +{ "IPACKETS", 10, + offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, +{ "RBYTES", 11, + offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, +{ "OPACKETS", 10, + offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, +{ "OBYTES", 11, + offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, +{ "BANDWIDTH", 15, + offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define USAGE_MAX_FIELDS (sizeof (usage_fields) / sizeof (print_field_t)) /* * structures for 'dladm show-usage link' @@ -997,25 +871,23 @@ typedef struct usage_l_fields_buf_s { char usage_l_bandwidth[14]; } usage_l_fields_buf_t; -static print_field_t usage_l_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "link", "LINK", 12, - offsetof(usage_l_fields_buf_t, usage_l_link), CMD_TYPE_ANY}, -{ "start", "START", 13, - offsetof(usage_l_fields_buf_t, usage_l_stime), CMD_TYPE_ANY}, -{ "end", "END", 13, - offsetof(usage_l_fields_buf_t, usage_l_etime), CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 8, - offsetof(usage_l_fields_buf_t, usage_l_rbytes), CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 8, - offsetof(usage_l_fields_buf_t, usage_l_obytes), CMD_TYPE_ANY}, -{ "bandwidth", "BANDWIDTH", 14, - offsetof(usage_l_fields_buf_t, usage_l_bandwidth), CMD_TYPE_ANY}} +static ofmt_field_t usage_l_fields[] = { +/* name, field width, offset */ +{ "LINK", 13, + offsetof(usage_l_fields_buf_t, usage_l_link), print_default_cb}, +{ "START", 14, + offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, +{ "END", 14, + offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, +{ "RBYTES", 9, + offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, +{ "OBYTES", 9, + offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, +{ "BANDWIDTH", 15, + offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, +{ NULL, 0, 0, NULL}} ; -#define USAGE_L_MAX_FIELDS \ - (sizeof (usage_l_fields) /sizeof (print_field_t)) - static char *progname; static sig_atomic_t signalled; @@ -1193,14 +1065,7 @@ show_usage_time(dladm_usage_t *usage, void *arg) (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); - if (!state->us_parseable && !state->us_printheader) { - print_header(&state->us_print); - state->us_printheader = B_TRUE; - } - - dladm_print_output(&state->us_print, state->us_parseable, - dladm_print_field, (void *)&ubuf); - + ofmt_print(state->us_ofmt, &ubuf); return (DLADM_STATUS_OK); } @@ -1243,13 +1108,7 @@ show_usage_res(dladm_usage_t *usage, void *arg) (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); - if (!state->us_parseable && !state->us_printheader) { - print_header(&state->us_print); - state->us_printheader = B_TRUE; - } - - dladm_print_output(&state->us_print, state->us_parseable, - dladm_print_field, (void *)&ubuf); + ofmt_print(state->us_ofmt, &ubuf); return (DLADM_STATUS_OK); } @@ -1279,15 +1138,14 @@ do_show_usage(int argc, char *argv[], const char *use) boolean_t F_arg = B_FALSE; char *fields_str = NULL; char *formatspec_str = NULL; - print_field_t **fields; - uint_t nfields; - char *all_fields = - "link,duration,ipackets,rbytes,opackets,obytes,bandwidth"; char *all_l_fields = "link,start,end,rbytes,obytes,bandwidth"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (show_usage_state_t)); - state.us_parseable = B_FALSE; + state.us_parsable = B_FALSE; state.us_printheader = B_FALSE; state.us_plot = B_FALSE; state.us_first = B_TRUE; @@ -1339,30 +1197,27 @@ do_show_usage(int argc, char *argv[], const char *use) } } + if (F_arg && d_arg) + die("incompatible -d and -F options"); + + if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) + die("Format specifier %s not supported", formatspec_str); + + if (state.us_parsable) + ofmtflags |= OFMT_PARSABLE; + if (resource == NULL && stime == NULL && etime == NULL) { - if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) - fields_str = all_fields; - fields = parse_output_fields(fields_str, usage_fields, - USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + oferr = ofmt_open(fields_str, usage_fields, ofmtflags, 0, + &ofmt); } else { if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) fields_str = all_l_fields; - fields = parse_output_fields(fields_str, usage_l_fields, - USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - } + oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, 0, + &ofmt); - if (fields == NULL) { - die("invalid fields(s) specified"); - return; } - state.us_print.ps_fields = fields; - state.us_print.ps_nfields = nfields; - - if (F_arg && d_arg) - die("incompatible -d and -F options"); - - if (F_arg && valid_formatspec(formatspec_str) == B_FALSE) - die("Format specifier %s not supported", formatspec_str); + dladm_ofmt_check(oferr, state.us_parsable, ofmt); + state.us_ofmt = ofmt; if (d_arg) { /* Print log dates */ @@ -1385,6 +1240,7 @@ do_show_usage(int argc, char *argv[], const char *use) if (status != DLADM_STATUS_OK) die_dlerr(status, "show-usage"); + ofmt_close(ofmt); } static void @@ -2233,11 +2089,7 @@ print_link_topology(show_state_t *state, datalink_id_t linkid, dladm_status_t status = DLADM_STATUS_OK; char tmpbuf[MAXLINKNAMELEN]; - if (!state->ls_parseable) - (void) sprintf(lbuf->link_over, STR_UNDEF_VAL); - else - (void) sprintf(lbuf->link_over, ""); - + (void) sprintf(lbuf->link_over, ""); if (class == DATALINK_CLASS_VLAN) { dladm_vlan_attr_t vinfo; @@ -2389,59 +2241,46 @@ show_link(dladm_handle_t dh, datalink_id_t linkid, void *arg) if (status != DLADM_STATUS_OK) goto done; - if (!state->ls_parseable && !state->ls_printheader) { - print_header(&state->ls_print); - state->ls_printheader = B_TRUE; - } - - dladm_print_output(&state->ls_print, state->ls_parseable, - dladm_print_field, (void *)&lbuf); + ofmt_print(state->ls_ofmt, &lbuf); done: state->ls_status = status; return (DLADM_WALK_CONTINUE); } -static char * -print_link_stats(print_field_t *pf, void *arg) +static boolean_t +print_link_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - link_args_t *largs = arg; + link_args_t *largs = ofarg->ofmt_cbarg; pktsum_t *diff_stats = largs->link_s_psum; - static char buf[DLADM_STRSIZE]; - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case LINK_S_LINK: - (void) snprintf(buf, sizeof (buf), "%s", largs->link_s_link); + (void) snprintf(buf, bufsize, "%s", largs->link_s_link); break; case LINK_S_IPKTS: - (void) snprintf(buf, sizeof (buf), "%llu", - diff_stats->ipackets); + (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); break; case LINK_S_RBYTES: - (void) snprintf(buf, sizeof (buf), "%llu", - diff_stats->rbytes); + (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); break; case LINK_S_IERRORS: - (void) snprintf(buf, sizeof (buf), "%u", - diff_stats->ierrors); + (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); break; case LINK_S_OPKTS: - (void) snprintf(buf, sizeof (buf), "%llu", - diff_stats->opackets); + (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); break; case LINK_S_OBYTES: - (void) snprintf(buf, sizeof (buf), "%llu", - diff_stats->obytes); + (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); break; case LINK_S_OERRORS: - (void) snprintf(buf, sizeof (buf), "%u", - diff_stats->oerrors); + (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); break; default: die("invalid input"); break; } - return (buf); + return (B_TRUE); } static int @@ -2483,8 +2322,7 @@ show_link_stats(dladm_handle_t dh, datalink_id_t linkid, void *arg) largs.link_s_link = link; largs.link_s_psum = &diff_stats; - dladm_print_output(&state->ls_print, state->ls_parseable, - print_link_stats, &largs); + ofmt_print(state->ls_ofmt, &largs); state->ls_prevstats = stats; return (DLADM_WALK_CONTINUE); @@ -2521,36 +2359,29 @@ print_aggr_info(show_grp_state_t *state, const char *link, (void) snprintf(lbuf.laggr_flags, sizeof (lbuf.laggr_flags), "%c----", ginfop->lg_force ? 'f' : '-'); - if (!state->gs_parseable && !state->gs_printheader) { - print_header(&state->gs_print); - state->gs_printheader = B_TRUE; - } - - dladm_print_output(&state->gs_print, state->gs_parseable, - dladm_print_field, (void *)&lbuf); + ofmt_print(state->gs_ofmt, &lbuf); return (DLADM_STATUS_OK); } -static char * -print_xaggr_callback(print_field_t *pf, void *arg) +static boolean_t +print_xaggr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - const laggr_args_t *l = arg; + const laggr_args_t *l = ofarg->ofmt_cbarg; int portnum; - static char buf[DLADM_STRSIZE]; boolean_t is_port = (l->laggr_lport >= 0); + static char tmpbuf[DLADM_STRSIZE]; dladm_aggr_port_attr_t *portp; dladm_phys_attr_t dpa; - dladm_status_t *stat, status; + dladm_status_t *stat, status = DLADM_STATUS_OK; stat = l->laggr_status; - *stat = DLADM_STATUS_OK; if (is_port) { portnum = l->laggr_lport; portp = &(l->laggr_ginfop->lg_ports[portnum]); if ((status = dladm_datalink_id2info(handle, - portp->lp_linkid, NULL, NULL, NULL, buf, sizeof (buf))) != + portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) { goto err; } @@ -2561,24 +2392,24 @@ print_xaggr_callback(print_field_t *pf, void *arg) } } - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case AGGR_X_LINK: - (void) snprintf(buf, sizeof (buf), "%s", - (is_port && !l->laggr_parseable ? " " : l->laggr_link)); + (void) snprintf(buf, bufsize, "%s", + (is_port && !l->laggr_parsable ? " " : l->laggr_link)); break; case AGGR_X_PORT: if (is_port) break; - return (""); - break; + *stat = DLADM_STATUS_OK; + return (B_TRUE); case AGGR_X_SPEED: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%uMb", + (void) snprintf(buf, bufsize, "%uMb", (uint_t)((get_ifspeed(dpa.dp_dev, B_FALSE)) / 1000000ull)); } else { - (void) snprintf(buf, sizeof (buf), "%uMb", + (void) snprintf(buf, bufsize, "%uMb", (uint_t)((get_ifspeed(l->laggr_link, B_TRUE)) / 1000000ull)); } @@ -2586,36 +2417,36 @@ print_xaggr_callback(print_field_t *pf, void *arg) case AGGR_X_DUPLEX: if (is_port) - (void) get_linkduplex(dpa.dp_dev, B_FALSE, buf); + (void) get_linkduplex(dpa.dp_dev, B_FALSE, tmpbuf); else - (void) get_linkduplex(l->laggr_link, B_TRUE, buf); + (void) get_linkduplex(l->laggr_link, B_TRUE, tmpbuf); + (void) strlcpy(buf, tmpbuf, bufsize); break; case AGGR_X_STATE: if (is_port) - (void) get_linkstate(dpa.dp_dev, B_FALSE, buf); + (void) get_linkstate(dpa.dp_dev, B_FALSE, tmpbuf); else - (void) get_linkstate(l->laggr_link, B_TRUE, buf); + (void) get_linkstate(l->laggr_link, B_TRUE, tmpbuf); + (void) strlcpy(buf, tmpbuf, bufsize); break; case AGGR_X_ADDRESS: (void) dladm_aggr_macaddr2str( (is_port ? portp->lp_mac : l->laggr_ginfop->lg_mac), - buf); + tmpbuf); + (void) strlcpy(buf, tmpbuf, bufsize); break; case AGGR_X_PORTSTATE: - if (is_port) - (void) dladm_aggr_portstate2str( - portp->lp_state, buf); - else - return (""); + if (is_port) { + (void) dladm_aggr_portstate2str(portp->lp_state, + tmpbuf); + (void) strlcpy(buf, tmpbuf, bufsize); + } break; } - return (buf); - err: *stat = status; - buf[0] = '\0'; - return (buf); + return (B_TRUE); } static dladm_status_t @@ -2626,27 +2457,20 @@ print_aggr_extended(show_grp_state_t *state, const char *link, dladm_status_t status; laggr_args_t largs; - if (!state->gs_parseable && !state->gs_printheader) { - print_header(&state->gs_print); - state->gs_printheader = B_TRUE; - } - largs.laggr_lport = -1; largs.laggr_link = link; largs.laggr_ginfop = ginfop; largs.laggr_status = &status; - largs.laggr_parseable = state->gs_parseable; + largs.laggr_parsable = state->gs_parsable; - dladm_print_output(&state->gs_print, state->gs_parseable, - print_xaggr_callback, &largs); + ofmt_print(state->gs_ofmt, &largs); if (status != DLADM_STATUS_OK) goto done; for (i = 0; i < ginfop->lg_nports; i++) { largs.laggr_lport = i; - dladm_print_output(&state->gs_print, state->gs_parseable, - print_xaggr_callback, &largs); + ofmt_print(state->gs_ofmt, &largs); if (status != DLADM_STATUS_OK) goto done; } @@ -2656,20 +2480,18 @@ done: return (status); } - -static char * -print_lacp_callback(print_field_t *pf, void *arg) +static boolean_t +print_lacp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - const laggr_args_t *l = arg; + const laggr_args_t *l = ofarg->ofmt_cbarg; int portnum; - static char buf[DLADM_STRSIZE]; boolean_t is_port = (l->laggr_lport >= 0); dladm_aggr_port_attr_t *portp; dladm_status_t *stat, status; aggr_lacp_state_t *lstate; if (!is_port) { - return (NULL); /* cannot happen! */ + return (B_FALSE); /* cannot happen! */ } stat = l->laggr_status; @@ -2678,58 +2500,61 @@ print_lacp_callback(print_field_t *pf, void *arg) portp = &(l->laggr_ginfop->lg_ports[portnum]); if ((status = dladm_datalink_id2info(handle, portp->lp_linkid, - NULL, NULL, NULL, buf, sizeof (buf))) != DLADM_STATUS_OK) { + NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) { goto err; } lstate = &(portp->lp_lacp_state); - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case AGGR_L_LINK: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (portnum > 0 ? "" : l->laggr_link)); break; case AGGR_L_PORT: + /* + * buf already contains portname as a result of the + * earlier call to dladm_datalink_id2info(). + */ break; case AGGR_L_AGGREGATABLE: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.aggregation ? "yes" : "no")); break; case AGGR_L_SYNC: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.sync ? "yes" : "no")); break; case AGGR_L_COLL: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.collecting ? "yes" : "no")); break; case AGGR_L_DIST: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.distributing ? "yes" : "no")); break; case AGGR_L_DEFAULTED: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.defaulted ? "yes" : "no")); break; case AGGR_L_EXPIRED: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (lstate->bit.expired ? "yes" : "no")); break; } *stat = DLADM_STATUS_OK; - return (buf); + return (B_TRUE); err: *stat = status; - buf[0] = '\0'; - return (buf); + return (B_TRUE); } static dladm_status_t @@ -2740,19 +2565,13 @@ print_aggr_lacp(show_grp_state_t *state, const char *link, dladm_status_t status; laggr_args_t largs; - if (!state->gs_parseable && !state->gs_printheader) { - print_header(&state->gs_print); - state->gs_printheader = B_TRUE; - } - largs.laggr_link = link; largs.laggr_ginfop = ginfop; largs.laggr_status = &status; for (i = 0; i < ginfop->lg_nports; i++) { largs.laggr_lport = i; - dladm_print_output(&state->gs_print, state->gs_parseable, - print_lacp_callback, &largs); + ofmt_print(state->gs_ofmt, &largs); if (status != DLADM_STATUS_OK) goto done; } @@ -2762,12 +2581,11 @@ done: return (status); } -static char * -print_aggr_stats_callback(print_field_t *pf, void *arg) +static boolean_t +print_aggr_stats_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - const laggr_args_t *l = arg; + const laggr_args_t *l = ofarg->ofmt_cbarg; int portnum; - static char buf[DLADM_STRSIZE]; boolean_t is_port = (l->laggr_lport >= 0); dladm_aggr_port_attr_t *portp; dladm_phys_attr_t dpa; @@ -2788,7 +2606,7 @@ print_aggr_stats_callback(print_field_t *pf, void *arg) get_mac_stats(dpa.dp_dev, &port_stat); if ((status = dladm_datalink_id2info(handle, - portp->lp_linkid, NULL, NULL, NULL, buf, sizeof (buf))) != + portp->lp_linkid, NULL, NULL, NULL, buf, bufsize)) != DLADM_STATUS_OK) { goto err; } @@ -2796,81 +2614,77 @@ print_aggr_stats_callback(print_field_t *pf, void *arg) dladm_stats_diff(&diff_stats, &port_stat, l->laggr_prevstats); } - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case AGGR_S_LINK: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", (is_port ? "" : l->laggr_link)); break; case AGGR_S_PORT: - if (is_port) - break; - return (""); + /* + * if (is_port), buf has port name. Otherwise we print + * STR_UNDEF_VAL + */ break; case AGGR_S_IPKTS: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats.ipackets); } else { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", l->laggr_pktsumtot->ipackets); } break; case AGGR_S_RBYTES: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats.rbytes); } else { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", l->laggr_pktsumtot->rbytes); } break; case AGGR_S_OPKTS: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats.opackets); } else { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", l->laggr_pktsumtot->opackets); } break; case AGGR_S_OBYTES: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats.obytes); } else { - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", l->laggr_pktsumtot->obytes); } break; case AGGR_S_IPKTDIST: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%-6.1f", + (void) snprintf(buf, bufsize, "%-6.1f", (double)diff_stats.opackets/ (double)l->laggr_pktsumtot->ipackets * 100); - } else { - return (""); } break; case AGGR_S_OPKTDIST: if (is_port) { - (void) snprintf(buf, sizeof (buf), "%-6.1f", + (void) snprintf(buf, bufsize, "%-6.1f", (double)diff_stats.opackets/ (double)l->laggr_pktsumtot->opackets * 100); - } else { - return (""); } break; } - return (buf); + return (B_TRUE); err: *stat = status; - buf[0] = '\0'; - return (buf); + return (B_TRUE); } static dladm_status_t @@ -2900,19 +2714,13 @@ print_aggr_stats(show_grp_state_t *state, const char *link, &state->gs_prevstats[i]); } - if (!state->gs_parseable && !state->gs_printheader) { - print_header(&state->gs_print); - state->gs_printheader = B_TRUE; - } - largs.laggr_lport = -1; largs.laggr_link = link; largs.laggr_ginfop = ginfop; largs.laggr_status = &status; largs.laggr_pktsumtot = &pktsumtot; - dladm_print_output(&state->gs_print, state->gs_parseable, - print_aggr_stats_callback, &largs); + ofmt_print(state->gs_ofmt, &largs); if (status != DLADM_STATUS_OK) goto done; @@ -2920,8 +2728,7 @@ print_aggr_stats(show_grp_state_t *state, const char *link, for (i = 0; i < ginfop->lg_nports; i++) { largs.laggr_lport = i; largs.laggr_prevstats = &state->gs_prevstats[i]; - dladm_print_output(&state->gs_print, state->gs_parseable, - print_aggr_stats_callback, &largs); + ofmt_print(state->gs_ofmt, &largs); if (status != DLADM_STATUS_OK) goto done; } @@ -2971,13 +2778,8 @@ static int show_aggr(dladm_handle_t dh, datalink_id_t linkid, void *arg) { show_grp_state_t *state = arg; - dladm_status_t status; - - if ((status = print_aggr(state, linkid)) != DLADM_STATUS_OK) - goto done; -done: - state->gs_status = status; + state->gs_status = print_aggr(state, linkid); return (DLADM_WALK_CONTINUE); } @@ -2997,12 +2799,13 @@ do_show_link(int argc, char *argv[], const char *use) dladm_status_t status; boolean_t o_arg = B_FALSE; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; char *all_active_fields = "link,class,mtu,state,over"; char *all_inactive_fields = "link,class,over"; char *allstat_fields = "link,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); @@ -3110,7 +2913,7 @@ do_show_link(int argc, char *argv[], const char *use) fields_str = all_inactive_fields; } - state.ls_parseable = p_arg; + state.ls_parsable = p_arg; state.ls_flags = flags; state.ls_donefirst = B_FALSE; @@ -3118,15 +2921,11 @@ do_show_link(int argc, char *argv[], const char *use) link_stats(linkid, interval, fields_str, &state); return; } - - fields = parse_output_fields(fields_str, link_fields, DEV_LINK_FIELDS, - CMD_TYPE_ANY, &nfields); - - if (fields == NULL) - die("invalid field(s) specified"); - - state.ls_print.ps_fields = fields; - state.ls_print.ps_nfields = nfields; + if (state.ls_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, link_fields, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.ls_parsable, ofmt); + state.ls_ofmt = ofmt; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_link, handle, &state, @@ -3138,6 +2937,7 @@ do_show_link(int argc, char *argv[], const char *use) argv[optind]); } } + ofmt_close(ofmt); } static void @@ -3157,8 +2957,6 @@ do_show_aggr(int argc, char *argv[], const char *use) dladm_status_t status; boolean_t o_arg = B_FALSE; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; char *all_fields = "link,policy,addrpolicy,lacpactivity,lacptimer,flags"; char *all_lacp_fields = @@ -3167,8 +2965,10 @@ do_show_aggr(int argc, char *argv[], const char *use) "link,port,ipackets,rbytes,opackets,obytes,ipktdist,opktdist"; char *all_extended_fields = "link,port,speed,duplex,state,address,portstate"; - print_field_t *pf; - int pfmax; + ofmt_field_t *pf; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); @@ -3265,7 +3065,7 @@ do_show_aggr(int argc, char *argv[], const char *use) state.gs_lacp = L_arg; state.gs_stats = s_arg; state.gs_flags = flags; - state.gs_parseable = p_arg; + state.gs_parsable = p_arg; state.gs_extended = x_arg; if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { @@ -3281,30 +3081,23 @@ do_show_aggr(int argc, char *argv[], const char *use) if (state.gs_lacp) { pf = aggr_l_fields; - pfmax = AGGR_L_MAX_FIELDS; } else if (state.gs_stats) { pf = aggr_s_fields; - pfmax = AGGR_S_MAX_FIELDS; } else if (state.gs_extended) { pf = aggr_x_fields; - pfmax = AGGR_X_MAX_FIELDS; } else { pf = laggr_fields; - pfmax = LAGGR_MAX_FIELDS; } - fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, - &nfields); - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - - state.gs_print.ps_fields = fields; - state.gs_print.ps_nfields = nfields; + if (state.gs_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.gs_parsable, ofmt); + state.gs_ofmt = ofmt; if (s_arg) { aggr_stats(linkid, &state, interval); + ofmt_close(ofmt); return; } @@ -3318,6 +3111,7 @@ do_show_aggr(int argc, char *argv[], const char *use) argv[optind]); } } + ofmt_close(ofmt); } static dladm_status_t @@ -3367,13 +3161,7 @@ print_phys_default(show_state_t *state, datalink_id_t linkid, "%c----", flags & DLADM_OPT_ACTIVE ? '-' : 'r'); } - if (!state->ls_parseable && !state->ls_printheader) { - print_header(&state->ls_print); - state->ls_printheader = B_TRUE; - } - - dladm_print_output(&state->ls_print, state->ls_parseable, - dladm_print_field, (void *)&pattr); + ofmt_print(state->ls_ofmt, &pattr); done: return (status); @@ -3385,32 +3173,33 @@ typedef struct { dladm_macaddr_attr_t *ms_mac_attr; } print_phys_mac_state_t; -/* callback of dladm_print_output() */ -static char * -print_phys_one_mac_callback(print_field_t *pf, void *arg) +/* + * callback for ofmt_print() + */ +static boolean_t +print_phys_one_mac_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - print_phys_mac_state_t *mac_state = arg; + print_phys_mac_state_t *mac_state = ofarg->ofmt_cbarg; dladm_macaddr_attr_t *attr = mac_state->ms_mac_attr; - static char buf[DLADM_STRSIZE]; boolean_t is_primary = (attr->ma_slot == 0); - boolean_t is_parseable = mac_state->ms_state->ls_parseable; + boolean_t is_parsable = mac_state->ms_state->ls_parsable; - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case PHYS_M_LINK: - (void) snprintf(buf, sizeof (buf), "%s", - (is_primary || is_parseable) ? mac_state->ms_link : " "); + (void) snprintf(buf, bufsize, "%s", + (is_primary || is_parsable) ? mac_state->ms_link : " "); break; case PHYS_M_SLOT: if (is_primary) - (void) snprintf(buf, sizeof (buf), gettext("primary")); + (void) snprintf(buf, bufsize, gettext("primary")); else - (void) snprintf(buf, sizeof (buf), "%d", attr->ma_slot); + (void) snprintf(buf, bufsize, "%d", attr->ma_slot); break; case PHYS_M_ADDRESS: (void) dladm_aggr_macaddr2str(attr->ma_addr, buf); break; case PHYS_M_INUSE: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", attr->ma_flags & DLADM_MACADDR_USED ? gettext("yes") : gettext("no")); break; @@ -3419,11 +3208,11 @@ print_phys_one_mac_callback(print_field_t *pf, void *arg) * CR 6678526: resolve link id to actual link name if * it is valid. */ - (void) snprintf(buf, sizeof (buf), "%s", attr->ma_client_name); + (void) snprintf(buf, bufsize, "%s", attr->ma_client_name); break; } - return (buf); + return (B_TRUE); } typedef struct { @@ -3432,60 +3221,57 @@ typedef struct { dladm_hwgrp_attr_t *hs_grp_attr; } print_phys_hwgrp_state_t; -static char * -print_phys_one_hwgrp_callback(print_field_t *pf, void *arg) +static boolean_t +print_phys_one_hwgrp_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - print_phys_hwgrp_state_t *hg_state = arg; + print_phys_hwgrp_state_t *hg_state = ofarg->ofmt_cbarg; dladm_hwgrp_attr_t *attr = hg_state->hs_grp_attr; - static char buf[DLADM_STRSIZE]; - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case PHYS_H_LINK: - (void) snprintf(buf, sizeof (buf), "%s", attr->hg_link_name); + (void) snprintf(buf, bufsize, "%s", attr->hg_link_name); break; case PHYS_H_GROUP: - (void) snprintf(buf, sizeof (buf), "%d", attr->hg_grp_num); + (void) snprintf(buf, bufsize, "%d", attr->hg_grp_num); break; case PHYS_H_GRPTYPE: - (void) snprintf(buf, sizeof (buf), "%s", + (void) snprintf(buf, bufsize, "%s", attr->hg_grp_type == DLADM_HWGRP_TYPE_RX ? "RX" : "TX"); break; case PHYS_H_RINGS: - (void) snprintf(buf, sizeof (buf), "%d", attr->hg_n_rings); + (void) snprintf(buf, bufsize, "%d", attr->hg_n_rings); break; case PHYS_H_CLIENTS: if (attr->hg_client_names[0] == '\0') { - (void) snprintf(buf, sizeof (buf), "--"); + (void) snprintf(buf, bufsize, "--"); } else { - (void) snprintf(buf, sizeof (buf), "%s ", + (void) snprintf(buf, bufsize, "%s ", attr->hg_client_names); } break; } - return (buf); + return (B_TRUE); } -/* callback of dladm_walk_macaddr, invoked for each MAC address slot */ +/* + * callback for dladm_walk_macaddr, invoked for each MAC address slot + */ static boolean_t print_phys_mac_callback(void *arg, dladm_macaddr_attr_t *attr) { print_phys_mac_state_t *mac_state = arg; show_state_t *state = mac_state->ms_state; - if (!state->ls_parseable && !state->ls_printheader) { - print_header(&state->ls_print); - state->ls_printheader = B_TRUE; - } - mac_state->ms_mac_attr = attr; - dladm_print_output(&state->ls_print, state->ls_parseable, - print_phys_one_mac_callback, mac_state); + ofmt_print(state->ls_ofmt, mac_state); return (B_TRUE); } -/* invoked by show-phys -m for each physical data-link */ +/* + * invoked by show-phys -m for each physical data-link + */ static dladm_status_t print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) { @@ -3498,20 +3284,17 @@ print_phys_mac(show_state_t *state, datalink_id_t linkid, char *link) print_phys_mac_callback)); } -/* callback of dladm_walk_hwgrp, invoked for each MAC hwgrp */ +/* + * callback for dladm_walk_hwgrp, invoked for each MAC hwgrp + */ static boolean_t print_phys_hwgrp_callback(void *arg, dladm_hwgrp_attr_t *attr) { print_phys_hwgrp_state_t *hwgrp_state = arg; show_state_t *state = hwgrp_state->hs_state; - if (!state->ls_parseable && !state->ls_printheader) { - print_header(&state->ls_print); - state->ls_printheader = B_TRUE; - } hwgrp_state->hs_grp_attr = attr; - dladm_print_output(&state->ls_print, state->ls_parseable, - print_phys_one_hwgrp_callback, hwgrp_state); + ofmt_print(state->ls_ofmt, hwgrp_state); return (B_TRUE); } @@ -3623,13 +3406,7 @@ show_vlan(dladm_handle_t dh, datalink_id_t linkid, void *arg) if (status != DLADM_STATUS_OK) goto done; - if (!state->ls_parseable && !state->ls_printheader) { - print_header(&state->ls_print); - state->ls_printheader = B_TRUE; - } - - dladm_print_output(&state->ls_print, state->ls_parseable, - dladm_print_field, (void *)&lbuf); + ofmt_print(state->ls_ofmt, &lbuf); done: state->ls_status = status; @@ -3649,16 +3426,16 @@ do_show_phys(int argc, char *argv[], const char *use) show_state_t state; dladm_status_t status; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; char *all_active_fields = "link,media,state,speed,duplex,device"; char *all_inactive_fields = "link,device,media,flags"; char *all_mac_fields = "link,slot,address,inuse,client"; char *all_hwgrp_fields = "link,group,grouptype,rings,clients"; - print_field_t *pf; - int pfmax; + ofmt_field_t *pf; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); opterr = 0; @@ -3712,7 +3489,7 @@ do_show_phys(int argc, char *argv[], const char *use) usage(); } - state.ls_parseable = p_arg; + state.ls_parsable = p_arg; state.ls_flags = flags; state.ls_donefirst = B_FALSE; state.ls_mac = m_arg; @@ -3740,25 +3517,17 @@ do_show_phys(int argc, char *argv[], const char *use) if (state.ls_mac) { pf = phys_m_fields; - pfmax = PHYS_M_MAX_FIELDS; } else if (state.ls_hwgrp) { pf = phys_h_fields; - pfmax = PHYS_H_MAX_FIELDS; } else { pf = phys_fields; - pfmax = PHYS_MAX_FIELDS; - } - - fields = parse_output_fields(fields_str, pf, - pfmax, CMD_TYPE_ANY, &nfields); - - if (fields == NULL) { - die("invalid field(s) specified"); - return; } - state.ls_print.ps_fields = fields; - state.ls_print.ps_nfields = nfields; + if (state.ls_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.ls_parsable, ofmt); + state.ls_ofmt = ofmt; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_phys, handle, &state, @@ -3770,6 +3539,7 @@ do_show_phys(int argc, char *argv[], const char *use) "failed to show physical link %s", argv[optind]); } } + ofmt_close(ofmt); } static void @@ -3783,9 +3553,9 @@ do_show_vlan(int argc, char *argv[], const char *use) dladm_status_t status; boolean_t o_arg = B_FALSE; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; - char *all_fields = "link,vid,over,flags"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); @@ -3815,12 +3585,6 @@ do_show_vlan(int argc, char *argv[], const char *use) } } - if (p_arg && !o_arg) - die("-p requires -o"); - - if (p_arg && strcasecmp(fields_str, "all") == 0) - die("\"-o all\" is invalid with -p"); - /* get link name (optional last argument) */ if (optind == (argc-1)) { if ((status = dladm_name2info(handle, argv[optind], &linkid, @@ -3831,22 +3595,18 @@ do_show_vlan(int argc, char *argv[], const char *use) usage(); } - state.ls_parseable = p_arg; + state.ls_parsable = p_arg; state.ls_flags = flags; state.ls_donefirst = B_FALSE; if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) - fields_str = all_fields; - - fields = parse_output_fields(fields_str, vlan_fields, VLAN_MAX_FIELDS, - CMD_TYPE_ANY, &nfields); + fields_str = NULL; - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - state.ls_print.ps_fields = fields; - state.ls_print.ps_nfields = nfields; + if (state.ls_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, vlan_fields, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.ls_parsable, ofmt); + state.ls_ofmt = ofmt; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_vlan, handle, &state, @@ -3858,6 +3618,7 @@ do_show_vlan(int argc, char *argv[], const char *use) argv[optind]); } } + ofmt_close(ofmt); } static void @@ -4289,13 +4050,7 @@ print_vnic(show_vnic_state_t *state, datalink_id_t linkid) "%d", vnic->va_vid); } - if (!state->vs_parseable && !state->vs_printheader) { - print_header(&state->vs_print); - state->vs_printheader = B_TRUE; - } - - dladm_print_output(&state->vs_print, state->vs_parseable, - dladm_print_field, (void *)&vbuf); + ofmt_print(state->vs_ofmt, &vbuf); return (DLADM_STATUS_OK); } @@ -4326,14 +4081,11 @@ do_show_vnic_common(int argc, char *argv[], const char *use, dladm_status_t status; boolean_t o_arg = B_FALSE; char *fields_str = NULL; - print_field_t **fields; - print_field_t *pf; - int pfmax; - uint_t nfields; - char *all_fields = - "link,over,speed,macaddress,macaddrtype,vid"; - char *all_e_fields = - "link"; + ofmt_field_t *pf; + char *all_e_fields = "link"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); opterr = 0; @@ -4341,7 +4093,7 @@ do_show_vnic_common(int argc, char *argv[], const char *use, NULL)) != -1) { switch (option) { case 'p': - state.vs_parseable = B_TRUE; + state.vs_parsable = B_TRUE; break; case 'P': flags = DLADM_OPT_PERSIST; @@ -4381,12 +4133,6 @@ do_show_vnic_common(int argc, char *argv[], const char *use, } } - if (state.vs_parseable && !o_arg) - die("-p requires -o"); - - if (state.vs_parseable && strcasecmp(fields_str, "all") == 0) - die("\"-o all\" is invalid with -p"); - if (i_arg && !s_arg) die("the option -i can be used only with -s"); @@ -4421,27 +4167,19 @@ do_show_vnic_common(int argc, char *argv[], const char *use, if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { if (etherstub) fields_str = all_e_fields; - else - fields_str = all_fields; } - pf = vnic_fields; - pfmax = VNIC_MAX_FIELDS; - - fields = parse_output_fields(fields_str, pf, pfmax, CMD_TYPE_ANY, - &nfields); - - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - state.vs_print.ps_fields = fields; - state.vs_print.ps_nfields = nfields; + if (state.vs_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, pf, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.vs_parsable, ofmt); + state.vs_ofmt = ofmt; if (s_arg) { /* Display vnic statistics */ vnic_stats(&state, interval); + ofmt_close(ofmt); return; } @@ -4455,10 +4193,12 @@ do_show_vnic_common(int argc, char *argv[], const char *use, } else { (void) show_vnic(handle, linkid, &state); if (state.vs_status != DLADM_STATUS_OK) { + ofmt_close(ofmt); die_dlerr(state.vs_status, "failed to show vnic '%s'", state.vs_vnic); } } + ofmt_close(ofmt); } static void @@ -4535,18 +4275,15 @@ static void link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, show_state_t *state) { - print_field_t **fields; - uint_t nfields; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; - fields = parse_output_fields(fields_str, link_s_fields, - LINK_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - - state->ls_print.ps_fields = fields; - state->ls_print.ps_nfields = nfields; + if (state->ls_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, link_s_fields, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state->ls_parsable, ofmt); + state->ls_ofmt = ofmt; /* * If an interval is specified, continuously show the stats @@ -4554,8 +4291,6 @@ link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, */ state->ls_firstonly = (interval != 0); - if (!state->ls_parseable) - print_header(&state->ls_print); for (;;) { state->ls_donefirst = B_FALSE; if (linkid == DATALINK_ALL_LINKID) { @@ -4571,6 +4306,7 @@ link_stats(datalink_id_t linkid, uint_t interval, char *fields_str, (void) sleep(interval); } + ofmt_close(ofmt); } static void @@ -4819,129 +4555,50 @@ get_linkduplex(const char *name, boolean_t islink, char *buf) return (dladm_linkduplex2str(linkduplex, buf)); } -typedef struct { - char *s_buf; - char **s_fields; /* array of pointer to the fields in s_buf */ - uint_t s_nfields; /* the number of fields in s_buf */ -} split_t; - -/* - * Free the split_t structure pointed to by `sp'. - */ -static void -splitfree(split_t *sp) -{ - free(sp->s_buf); - free(sp->s_fields); - free(sp); -} - -/* - * Split `str' into at most `maxfields' fields, each field at most `maxlen' in - * length. Return a pointer to a split_t containing the split fields, or NULL - * on failure. - */ -static split_t * -split(const char *str, uint_t maxfields, uint_t maxlen) -{ - char *field, *token, *lasts = NULL; - split_t *sp; - - if (*str == '\0' || maxfields == 0 || maxlen == 0) - return (NULL); - - sp = calloc(sizeof (split_t), 1); - if (sp == NULL) - return (NULL); - - sp->s_buf = strdup(str); - sp->s_fields = malloc(sizeof (char *) * maxfields); - if (sp->s_buf == NULL || sp->s_fields == NULL) - goto fail; - - token = sp->s_buf; - while ((field = strtok_r(token, ",", &lasts)) != NULL) { - if (sp->s_nfields == maxfields || strlen(field) > maxlen) - goto fail; - token = NULL; - sp->s_fields[sp->s_nfields++] = field; - } - return (sp); -fail: - splitfree(sp); - return (NULL); -} - static int -parse_wifi_fields(char *str, print_field_t ***fields, uint_t *countp, - uint_t cmdtype) +parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype, + boolean_t parsable) { + ofmt_field_t *template, *of; + ofmt_cb_t *fn; + ofmt_status_t oferr; if (cmdtype == WIFI_CMD_SCAN) { + template = wifi_common_fields; if (str == NULL) str = def_scan_wifi_fields; if (strcasecmp(str, "all") == 0) str = all_scan_wifi_fields; + fn = print_wlan_attr_cb; } else if (cmdtype == WIFI_CMD_SHOW) { + bcopy(wifi_common_fields, &wifi_show_fields[2], + sizeof (wifi_common_fields)); + template = wifi_show_fields; if (str == NULL) str = def_show_wifi_fields; if (strcasecmp(str, "all") == 0) str = all_show_wifi_fields; + fn = print_link_attr_cb; } else { return (-1); } - *fields = parse_output_fields(str, wifi_fields, WIFI_MAX_FIELDS, - cmdtype, countp); - if (*fields != NULL) - return (0); - return (-1); -} -static print_field_t ** -parse_output_fields(char *str, print_field_t *template, int max_fields, - uint_t cmdtype, uint_t *countp) -{ - split_t *sp; - boolean_t good_match = B_FALSE; - uint_t i, j; - print_field_t **pf = NULL; - sp = split(str, max_fields, MAX_FIELD_LEN); - - if (sp == NULL) - return (NULL); - - pf = malloc(sp->s_nfields * sizeof (print_field_t *)); - if (pf == NULL) - goto fail; - - for (i = 0; i < sp->s_nfields; i++) { - for (j = 0; j < max_fields; j++) { - if (strcasecmp(sp->s_fields[i], - template[j].pf_name) == 0) { - good_match = template[j]. pf_cmdtype & cmdtype; - break; - } - } - if (!good_match) - goto fail; - - good_match = B_FALSE; - pf[i] = &template[j]; + for (of = template; of->of_name != NULL; of++) { + if (of->of_cb == NULL) + of->of_cb = fn; } - *countp = i; - splitfree(sp); - return (pf); -fail: - free(pf); - splitfree(sp); - return (NULL); + + oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0), + 0, ofmt); + dladm_ofmt_check(oferr, parsable, *ofmt); + return (0); } typedef struct print_wifi_state { char *ws_link; - boolean_t ws_parseable; + boolean_t ws_parsable; boolean_t ws_header; - print_state_t ws_print_state; + ofmt_handle_t ws_ofmt; } print_wifi_state_t; typedef struct wlan_scan_args_s { @@ -4949,102 +4606,52 @@ typedef struct wlan_scan_args_s { void *ws_attr; } wlan_scan_args_t; -static void -print_field(print_state_t *statep, print_field_t *pfp, const char *value, - boolean_t parseable) -{ - uint_t width = pfp->pf_width; - uint_t valwidth; - uint_t compress; - - /* - * Parsable fields are separated by ':'. If such a field contains - * a ':' or '\', this character is prefixed by a '\'. - */ - if (parseable) { - char c; - - if (statep->ps_nfields == 1) { - (void) printf("%s", value); - return; - } - while ((c = *value++) != '\0') { - if (c == ':' || c == '\\') - (void) putchar('\\'); - (void) putchar(c); - } - if (!statep->ps_lastfield) - (void) putchar(':'); - return; - } else { - if (value[0] == '\0') - value = STR_UNDEF_VAL; - if (statep->ps_lastfield) { - (void) printf("%s", value); - statep->ps_overflow = 0; - return; - } - - valwidth = strlen(value); - if (valwidth > width) { - statep->ps_overflow += valwidth - width; - } else if (valwidth < width && statep->ps_overflow > 0) { - compress = min(statep->ps_overflow, width - valwidth); - statep->ps_overflow -= compress; - width -= compress; - } - (void) printf("%-*s", width, value); - } - - if (!statep->ps_lastfield) - (void) putchar(' '); -} - -static char * -print_wlan_attr(print_field_t *wfp, void *warg) +static boolean_t +print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - static char buf[DLADM_STRSIZE]; - wlan_scan_args_t *w = warg; + wlan_scan_args_t *w = ofarg->ofmt_cbarg; print_wifi_state_t *statep = w->ws_state; dladm_wlan_attr_t *attrp = w->ws_attr; + char tmpbuf[DLADM_STRSIZE]; - if (wfp->pf_index == 0) { - return ((char *)statep->ws_link); + if (ofarg->ofmt_id == 0) { + (void) strlcpy(buf, (char *)statep->ws_link, bufsize); + return (B_TRUE); } - if ((wfp->pf_index & attrp->wa_valid) == 0) { - return (""); - } + if ((ofarg->ofmt_id & attrp->wa_valid) == 0) + return (B_TRUE); - switch (wfp->pf_index) { + switch (ofarg->ofmt_id) { case DLADM_WLAN_ATTR_ESSID: - (void) dladm_wlan_essid2str(&attrp->wa_essid, buf); + (void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf); break; case DLADM_WLAN_ATTR_BSSID: - (void) dladm_wlan_bssid2str(&attrp->wa_bssid, buf); + (void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf); break; case DLADM_WLAN_ATTR_SECMODE: - (void) dladm_wlan_secmode2str(&attrp->wa_secmode, buf); + (void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf); break; case DLADM_WLAN_ATTR_STRENGTH: - (void) dladm_wlan_strength2str(&attrp->wa_strength, buf); + (void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf); break; case DLADM_WLAN_ATTR_MODE: - (void) dladm_wlan_mode2str(&attrp->wa_mode, buf); + (void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf); break; case DLADM_WLAN_ATTR_SPEED: - (void) dladm_wlan_speed2str(&attrp->wa_speed, buf); - (void) strlcat(buf, "Mb", sizeof (buf)); + (void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf); + (void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf)); break; case DLADM_WLAN_ATTR_AUTH: - (void) dladm_wlan_auth2str(&attrp->wa_auth, buf); + (void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf); break; case DLADM_WLAN_ATTR_BSSTYPE: - (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, buf); + (void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf); break; } + (void) strlcpy(buf, tmpbuf, bufsize); - return (buf); + return (B_TRUE); } static boolean_t @@ -5053,18 +4660,10 @@ print_scan_results(void *arg, dladm_wlan_attr_t *attrp) print_wifi_state_t *statep = arg; wlan_scan_args_t warg; - if (statep->ws_header) { - statep->ws_header = B_FALSE; - if (!statep->ws_parseable) - print_header(&statep->ws_print_state); - } - - statep->ws_print_state.ps_overflow = 0; bzero(&warg, sizeof (warg)); warg.ws_state = statep; warg.ws_attr = attrp; - dladm_print_output(&statep->ws_print_state, statep->ws_parseable, - print_wlan_attr, &warg); + ofmt_print(statep->ws_ofmt, &warg); return (B_TRUE); } @@ -5088,27 +4687,32 @@ scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } -static char * -print_link_attr(print_field_t *wfp, void *warg) +static boolean_t +print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - static char buf[DLADM_STRSIZE]; - char *ptr; - wlan_scan_args_t *w = warg, w1; - print_wifi_state_t *statep = w->ws_state; + static char tmpbuf[DLADM_STRSIZE]; + wlan_scan_args_t *w = ofarg->ofmt_cbarg; dladm_wlan_linkattr_t *attrp = w->ws_attr; - if (strcmp(wfp->pf_name, "status") == 0) { - if ((wfp->pf_index & attrp->la_valid) != 0) - (void) dladm_wlan_linkstatus2str( - &attrp->la_status, buf); - return (buf); + if ((ofarg->ofmt_id & attrp->la_valid) != 0) { + (void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf); + (void) strlcpy(buf, tmpbuf, bufsize); } - statep->ws_print_state.ps_overflow = 0; + return (B_TRUE); +} + +static boolean_t +print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) +{ + wlan_scan_args_t *w = ofarg->ofmt_cbarg, w1; + print_wifi_state_t *statep = w->ws_state; + dladm_wlan_linkattr_t *attrp = w->ws_attr; + bzero(&w1, sizeof (w1)); w1.ws_state = statep; w1.ws_attr = &attrp->la_wlan_attr; - ptr = print_wlan_attr(wfp, &w1); - return (ptr); + ofarg->ofmt_cbarg = &w1; + return (print_wlan_attr_cb(ofarg, buf, bufsize)); } static int @@ -5132,18 +4736,10 @@ show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg) statep->ws_link = link; - if (statep->ws_header) { - statep->ws_header = B_FALSE; - if (!statep->ws_parseable) - print_header(&statep->ws_print_state); - } - - statep->ws_print_state.ps_overflow = 0; bzero(&warg, sizeof (warg)); warg.ws_state = statep; warg.ws_attr = &attr; - dladm_print_output(&statep->ws_print_state, statep->ws_parseable, - print_link_attr, &warg); + ofmt_print(statep->ws_ofmt, &warg); return (DLADM_WALK_CONTINUE); } @@ -5152,9 +4748,7 @@ do_display_wifi(int argc, char **argv, int cmd, const char *use) { int option; char *fields_str = NULL; - print_field_t **fields; int (*callback)(dladm_handle_t, datalink_id_t, void *); - uint_t nfields; print_wifi_state_t state; datalink_id_t linkid = DATALINK_ALL_LINKID; dladm_status_t status; @@ -5166,7 +4760,7 @@ do_display_wifi(int argc, char **argv, int cmd, const char *use) else return; - state.ws_parseable = B_FALSE; + state.ws_parsable = B_FALSE; state.ws_header = B_TRUE; opterr = 0; while ((option = getopt_long(argc, argv, ":o:p", @@ -5176,17 +4770,17 @@ do_display_wifi(int argc, char **argv, int cmd, const char *use) fields_str = optarg; break; case 'p': - state.ws_parseable = B_TRUE; + state.ws_parsable = B_TRUE; break; default: die_opterr(optopt, option, use); } } - if (state.ws_parseable && fields_str == NULL) + if (state.ws_parsable && fields_str == NULL) die("-p requires -o"); - if (state.ws_parseable && strcasecmp(fields_str, "all") == 0) + if (state.ws_parsable && strcasecmp(fields_str, "all") == 0) die("\"-o all\" is invalid with -p"); if (optind == (argc - 1)) { @@ -5198,20 +4792,17 @@ do_display_wifi(int argc, char **argv, int cmd, const char *use) usage(); } - if (parse_wifi_fields(fields_str, &fields, &nfields, cmd) < 0) + if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd, + state.ws_parsable) < 0) die("invalid field(s) specified"); - bzero(&state.ws_print_state, sizeof (state.ws_print_state)); - state.ws_print_state.ps_fields = fields; - state.ws_print_state.ps_nfields = nfields; - if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(callback, handle, &state, DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_ACTIVE); } else { (void) (*callback)(handle, linkid, &state); } - free(fields); + ofmt_close(state.ws_ofmt); } static void @@ -5247,23 +4838,33 @@ static int parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) { uint_t i; - split_t *sp; dladm_wlan_key_t *wk; + int nfields = 1; + char *field, *token, *lasts = NULL, c; - sp = split(str, DLADM_WLAN_MAX_WEPKEYS, DLADM_WLAN_MAX_KEYNAME_LEN); - if (sp == NULL) + token = str; + while ((c = *token++) != NULL) { + if (c == ',') + nfields++; + } + token = strdup(str); + if (token == NULL) return (-1); - wk = malloc(sp->s_nfields * sizeof (dladm_wlan_key_t)); + wk = malloc(nfields * sizeof (dladm_wlan_key_t)); if (wk == NULL) goto fail; - for (i = 0; i < sp->s_nfields; i++) { + token = str; + for (i = 0; i < nfields; i++) { char *s; dladm_secobj_class_t class; dladm_status_t status; - (void) strlcpy(wk[i].wk_name, sp->s_fields[i], + field = strtok_r(token, ",", &lasts); + token = NULL; + + (void) strlcpy(wk[i].wk_name, field, DLADM_WLAN_MAX_KEYNAME_LEN); wk[i].wk_idx = 1; @@ -5291,11 +4892,11 @@ parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp) } *keys = wk; *key_countp = i; - splitfree(sp); + free(token); return (0); fail: free(wk); - splitfree(sp); + free(token); return (-1); } @@ -5579,8 +5180,8 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, ptr = buf; lim = buf + DLADM_STRSIZE; for (i = 0; i < valcnt; i++) { - if (propvals[i][0] == '\0' && !statep->ls_parseable) - ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); + if (propvals[i][0] == '\0' && !statep->ls_parsable) + ptr += snprintf(ptr, lim - ptr, "--,"); else ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); if (ptr >= lim) @@ -5590,7 +5191,7 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, buf[strlen(buf) - 1] = '\0'; lim = statep->ls_line + MAX_PROP_LINE; - if (statep->ls_parseable) { + if (statep->ls_parsable) { *pptr += snprintf(*pptr, lim - *pptr, "%s", buf); } else { @@ -5598,17 +5199,17 @@ print_linkprop(datalink_id_t linkid, show_linkprop_state_t *statep, } } -static char * -linkprop_callback(print_field_t *pf, void *ls_arg) +static boolean_t +print_linkprop_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) { - linkprop_args_t *arg = ls_arg; + linkprop_args_t *arg = ofarg->ofmt_cbarg; char *propname = arg->ls_propname; show_linkprop_state_t *statep = arg->ls_state; char *ptr = statep->ls_line; char *lim = ptr + MAX_PROP_LINE; datalink_id_t linkid = arg->ls_linkid; - switch (pf->pf_index) { + switch (ofarg->ofmt_id) { case LINKPROP_LINK: (void) snprintf(ptr, lim - ptr, "%s", statep->ls_link); break; @@ -5653,12 +5254,11 @@ linkprop_callback(print_field_t *pf, void *ls_arg) die("invalid input"); break; } - return (ptr); + (void) strlcpy(buf, ptr, bufsize); + return (B_TRUE); skip: - if (statep->ls_status != DLADM_STATUS_OK) - return (NULL); - else - return (""); + return ((statep->ls_status == DLADM_STATUS_OK) ? + B_TRUE : B_FALSE); } static boolean_t @@ -5701,11 +5301,6 @@ show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, ls_arg.ls_propname = (char *)propname; ls_arg.ls_linkid = linkid; - if (statep->ls_header) { - statep->ls_header = B_FALSE; - if (!statep->ls_parseable) - print_header(&statep->ls_print); - } /* * This will need to be fixed when kernel interfaces are added * to enable walking of all known private properties. For now, @@ -5714,12 +5309,11 @@ show_linkprop(dladm_handle_t dh, datalink_id_t linkid, const char *propname, if ((propname[0] == '_') && !statep->ls_persist && (statep->ls_proplist == NULL)) return (DLADM_WALK_CONTINUE); - if (!statep->ls_parseable && + if (!statep->ls_parsable && !linkprop_is_supported(linkid, propname, statep)) return (DLADM_WALK_CONTINUE); - dladm_print_output(&statep->ls_print, statep->ls_parseable, - linkprop_callback, (void *)&ls_arg); + ofmt_print(statep->ls_ofmt, &ls_arg); return (DLADM_WALK_CONTINUE); } @@ -5735,19 +5329,15 @@ do_show_linkprop(int argc, char **argv, const char *use) uint32_t flags = DLADM_OPT_ACTIVE; dladm_status_t status; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; - boolean_t o_arg = B_FALSE; - char *all_fields = - "link,property,perm,value,default,possible"; - - fields_str = all_fields; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(propstr, DLADM_STRSIZE); opterr = 0; state.ls_propvals = NULL; state.ls_line = NULL; - state.ls_parseable = B_FALSE; + state.ls_parsable = B_FALSE; state.ls_persist = B_FALSE; state.ls_header = B_TRUE; state.ls_retstatus = DLADM_STATUS_OK; @@ -5762,18 +5352,14 @@ do_show_linkprop(int argc, char **argv, const char *use) die("property list too long '%s'", propstr); break; case 'c': - state.ls_parseable = B_TRUE; + state.ls_parsable = B_TRUE; break; case 'P': state.ls_persist = B_TRUE; flags = DLADM_OPT_PERSIST; break; case 'o': - o_arg = B_TRUE; - if (strcasecmp(optarg, "all") == 0) - fields_str = all_fields; - else - fields_str = optarg; + fields_str = optarg; break; default: die_opterr(optopt, option, use); @@ -5781,12 +5367,6 @@ do_show_linkprop(int argc, char **argv, const char *use) } } - if (state.ls_parseable && !o_arg) - die("-c requires -o"); - - if (state.ls_parseable && fields_str == all_fields) - die("\"-o all\" is invalid with -c"); - if (optind == (argc - 1)) { if ((status = dladm_name2info(handle, argv[optind], &linkid, NULL, NULL, NULL)) != DLADM_STATUS_OK) { @@ -5799,27 +5379,22 @@ do_show_linkprop(int argc, char **argv, const char *use) if (dladm_parse_link_props(propstr, &proplist, B_TRUE) != DLADM_STATUS_OK) die("invalid link properties specified"); - - bzero(&state.ls_print, sizeof (print_state_t)); state.ls_proplist = proplist; state.ls_status = DLADM_STATUS_OK; - fields = parse_output_fields(fields_str, linkprop_fields, - LINKPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } + if (state.ls_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.ls_parsable, ofmt); + state.ls_ofmt = ofmt; - state.ls_print.ps_fields = fields; - state.ls_print.ps_nfields = nfields; if (linkid == DATALINK_ALL_LINKID) { (void) dladm_walk_datalink_id(show_linkprop_onelink, handle, &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, flags); } else { (void) show_linkprop_onelink(handle, linkid, &state); } + ofmt_close(ofmt); dladm_free_props(proplist); if (state.ls_retstatus != DLADM_STATUS_OK) { @@ -6442,9 +6017,10 @@ do_delete_secobj(int argc, char **argv, const char *use) { int i, option; boolean_t temp = B_FALSE; - split_t *sp = NULL; boolean_t success; dladm_status_t status, pstatus; + int nfields = 1; + char *field, *token, *lasts = NULL, c; opterr = 0; status = pstatus = DLADM_STATUS_OK; @@ -6468,27 +6044,31 @@ do_delete_secobj(int argc, char **argv, const char *use) } if (optind == (argc - 1)) { - sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); - if (sp == NULL) { - die("invalid secure object name(s): '%s'", - argv[optind]); + token = argv[optind]; + if (token == NULL) + die("secure object name required"); + while ((c = *token++) != NULL) { + if (c == ',') + nfields++; } + token = strdup(argv[optind]); + if (token == NULL) + die("no memory"); } else if (optind != argc) usage(); - if (sp == NULL || sp->s_nfields < 1) - die("secure object name required"); - success = check_auth(LINK_SEC_AUTH); audit_secobj(LINK_SEC_AUTH, "unknown", argv[optind], success, B_FALSE); if (!success) die("authorization '%s' is required", LINK_SEC_AUTH); - for (i = 0; i < sp->s_nfields; i++) { - status = dladm_unset_secobj(handle, sp->s_fields[i], - DLADM_OPT_ACTIVE); + for (i = 0; i < nfields; i++) { + + field = strtok_r(token, ",", &lasts); + token = NULL; + status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE); if (!temp) { - pstatus = dladm_unset_secobj(handle, sp->s_fields[i], + pstatus = dladm_unset_secobj(handle, field, DLADM_OPT_PERSIST); } else { pstatus = DLADM_STATUS_OK; @@ -6496,13 +6076,14 @@ do_delete_secobj(int argc, char **argv, const char *use) if (status != DLADM_STATUS_OK) { warn_dlerr(status, "could not delete secure object " - "'%s'", sp->s_fields[i]); + "'%s'", field); } if (pstatus != DLADM_STATUS_OK) { warn_dlerr(pstatus, "could not persistently delete " - "secure object '%s'", sp->s_fields[i]); + "secure object '%s'", field); } } + free(token); if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) { dladm_close(handle); @@ -6512,9 +6093,9 @@ do_delete_secobj(int argc, char **argv, const char *use) typedef struct show_secobj_state { boolean_t ss_persist; - boolean_t ss_parseable; + boolean_t ss_parsable; boolean_t ss_header; - print_state_t ss_print; + ofmt_handle_t ss_ofmt; } show_secobj_state_t; @@ -6539,12 +6120,6 @@ show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) if (status != DLADM_STATUS_OK) die_dlerr(status, "cannot get secure object '%s'", obj_name); - if (statep->ss_header) { - statep->ss_header = B_FALSE; - if (!statep->ss_parseable) - print_header(&statep->ss_print); - } - (void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name), obj_name); (void) dladm_secobjclass2str(class, buf); @@ -6557,8 +6132,7 @@ show_secobj(dladm_handle_t dh, void *arg, const char *obj_name) (void) snprintf(sbuf.ss_val, sizeof (sbuf.ss_val), "%s", val); } - dladm_print_output(&statep->ss_print, statep->ss_parseable, - dladm_print_field, (void *)&sbuf); + ofmt_print(statep->ss_ofmt, &sbuf); return (B_TRUE); } @@ -6570,26 +6144,27 @@ do_show_secobj(int argc, char **argv, const char *use) dladm_status_t status; boolean_t o_arg = B_FALSE; uint_t i; - split_t *sp; uint_t flags; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; char *def_fields = "object,class"; char *all_fields = "object,class,value"; + char *field, *token, *lasts = NULL, c; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; opterr = 0; bzero(&state, sizeof (state)); - state.ss_parseable = B_FALSE; + state.ss_parsable = B_FALSE; fields_str = def_fields; state.ss_persist = B_FALSE; - state.ss_parseable = B_FALSE; + state.ss_parsable = B_FALSE; state.ss_header = B_TRUE; while ((option = getopt_long(argc, argv, ":pPo:", wifi_longopts, NULL)) != -1) { switch (option) { case 'p': - state.ss_parseable = B_TRUE; + state.ss_parsable = B_TRUE; break; case 'P': state.ss_persist = B_TRUE; @@ -6607,35 +6182,41 @@ do_show_secobj(int argc, char **argv, const char *use) } } - if (state.ss_parseable && !o_arg) + if (state.ss_parsable && !o_arg) die("option -c requires -o"); - if (state.ss_parseable && fields_str == all_fields) + if (state.ss_parsable && fields_str == all_fields) die("\"-o all\" is invalid with -p"); - fields = parse_output_fields(fields_str, secobj_fields, - DEV_SOBJ_FIELDS, CMD_TYPE_ANY, &nfields); - - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - state.ss_print.ps_fields = fields; - state.ss_print.ps_nfields = nfields; + if (state.ss_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, secobj_fields, ofmtflags, 0, &ofmt); + dladm_ofmt_check(oferr, state.ss_parsable, ofmt); + state.ss_ofmt = ofmt; flags = state.ss_persist ? DLADM_OPT_PERSIST : 0; if (optind == (argc - 1)) { - sp = split(argv[optind], MAX_SECOBJS, MAX_SECOBJ_NAMELEN); - if (sp == NULL) { - die("invalid secure object name(s): '%s'", - argv[optind]); + uint_t obj_fields = 1; + + token = argv[optind]; + if (token == NULL) + die("secure object name required"); + while ((c = *token++) != NULL) { + if (c == ',') + obj_fields++; } - for (i = 0; i < sp->s_nfields; i++) { - if (!show_secobj(handle, &state, sp->s_fields[i])) + token = strdup(argv[optind]); + if (token == NULL) + die("no memory"); + for (i = 0; i < obj_fields; i++) { + field = strtok_r(token, ",", &lasts); + token = NULL; + if (!show_secobj(handle, &state, field)) break; } - splitfree(sp); + free(token); + ofmt_close(ofmt); return; } else if (optind != argc) usage(); @@ -6644,6 +6225,7 @@ do_show_secobj(int argc, char **argv, const char *use) if (status != DLADM_STATUS_OK) die_dlerr(status, "show-secobj"); + ofmt_close(ofmt); } /*ARGSUSED*/ @@ -6707,19 +6289,14 @@ do_show_ether(int argc, char **argv, const char *use) int option; datalink_id_t linkid; print_ether_state_t state; - print_field_t **fields; - boolean_t o_arg = B_FALSE; - char *fields_str; - uint_t nfields; - char *all_fields = - "link,ptype,state,auto,speed-duplex,pause,rem_fault"; - char *default_fields = - "link,ptype,state,auto,speed-duplex,pause"; + char *fields_str = NULL; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; - fields_str = default_fields; bzero(&state, sizeof (state)); state.es_link = NULL; - state.es_parseable = B_FALSE; + state.es_parsable = B_FALSE; while ((option = getopt_long(argc, argv, "o:px", showeth_lopts, NULL)) != -1) { @@ -6728,14 +6305,10 @@ do_show_ether(int argc, char **argv, const char *use) state.es_extended = B_TRUE; break; case 'p': - state.es_parseable = B_TRUE; + state.es_parsable = B_TRUE; break; case 'o': - o_arg = B_TRUE; - if (strcasecmp(optarg, "all") == 0) - fields_str = all_fields; - else - fields_str = optarg; + fields_str = optarg; break; default: die_opterr(optopt, option, use); @@ -6743,24 +6316,15 @@ do_show_ether(int argc, char **argv, const char *use) } } - if (state.es_parseable && !o_arg) - die("-p requires -o"); - - if (state.es_parseable && fields_str == all_fields) - die("\"-o all\" is invalid with -p"); - if (optind == (argc - 1)) state.es_link = argv[optind]; - fields = parse_output_fields(fields_str, ether_fields, - ETHER_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - - if (fields == NULL) - die("invalid field(s) specified"); - - state.es_print.ps_fields = fields; - state.es_print.ps_nfields = nfields; - + if (state.es_parsable) + ofmtflags |= OFMT_PARSABLE; + oferr = ofmt_open(fields_str, ether_fields, ofmtflags, + DLADM_DEFAULT_COL, &ofmt); + dladm_ofmt_check(oferr, state.es_parsable, ofmt); + state.es_ofmt = ofmt; if (state.es_link == NULL) { (void) dladm_walk_datalink_id(show_etherprop, handle, &state, @@ -6771,15 +6335,7 @@ do_show_ether(int argc, char **argv, const char *use) die("invalid link specified"); (void) show_etherprop(handle, linkid, &state); } -} - -static char * -dladm_print_field(print_field_t *pf, void *arg) -{ - char *value; - - value = (char *)arg + pf->pf_offset; - return (value); + ofmt_close(ofmt); } static int @@ -6796,11 +6352,6 @@ show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) return (DLADM_WALK_CONTINUE); } - if (!statep->es_header && !statep->es_parseable) { - print_header(&statep->es_print); - statep->es_header = B_TRUE; - } - status = dladm_ether_info(dh, linkid, &eattr); if (status != DLADM_STATUS_OK) goto cleanup; @@ -6820,8 +6371,7 @@ show_etherprop(dladm_handle_t dh, datalink_id_t linkid, void *arg) (eattr.lei_attr[CURRENT].le_fault ? "fault" : "none"), sizeof (ebuf.eth_rem_fault)); - dladm_print_output(&statep->es_print, statep->es_parseable, - dladm_print_field, &ebuf); + ofmt_print(statep->es_ofmt, &ebuf); if (statep->es_extended) show_ether_xprop(arg, &eattr); @@ -7043,44 +6593,11 @@ show_ether_xprop(void *arg, dladm_ether_info_t *eattr) (void) strlcpy(ebuf.eth_rem_fault, (eattr->lei_attr[i].le_fault ? "fault" : "none"), sizeof (ebuf.eth_rem_fault)); - dladm_print_output(&statep->es_print, statep->es_parseable, - dladm_print_field, &ebuf); + ofmt_print(statep->es_ofmt, &ebuf); } } -static void -dladm_print_output(print_state_t *statep, boolean_t parseable, - print_callback_t fn, void *arg) -{ - int i; - char *value; - print_field_t **pf; - - pf = statep->ps_fields; - for (i = 0; i < statep->ps_nfields; i++) { - statep->ps_lastfield = (i + 1 == statep->ps_nfields); - value = (*fn)(pf[i], arg); - if (value != NULL) - print_field(statep, pf[i], value, parseable); - } - (void) putchar('\n'); -} - -static void -print_header(print_state_t *ps) -{ - int i; - print_field_t **pf; - - pf = ps->ps_fields; - for (i = 0; i < ps->ps_nfields; i++) { - ps->ps_lastfield = (i + 1 == ps->ps_nfields); - print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); - } - (void) putchar('\n'); -} - static boolean_t link_is_ether(const char *link, datalink_id_t *linkid) { @@ -7094,3 +6611,40 @@ link_is_ether(const char *link, datalink_id_t *linkid) } return (B_FALSE); } + +/* + * default output callback function that, when invoked, + * prints string which is offset by ofmt_arg->ofmt_id within buf. + */ +static boolean_t +print_default_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize) +{ + char *value; + + value = (char *)ofarg->ofmt_cbarg + ofarg->ofmt_id; + (void) strlcpy(buf, value, bufsize); + return (B_TRUE); +} + +static void +dladm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, + ofmt_handle_t ofmt) +{ + char buf[OFMT_BUFSIZE]; + + if (oferr == OFMT_SUCCESS) + return; + (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); + /* + * All errors are considered fatal in parsable mode. + * NOMEM errors are always fatal, regardless of mode. + * For other errors, we print diagnostics in human-readable + * mode and processs what we can. + */ + if (parsable || oferr == OFMT_ENOFIELDS) { + ofmt_close(ofmt); + die(buf); + } else { + warn(buf); + } +} diff --git a/usr/src/cmd/dladm/dladm.xcl b/usr/src/cmd/dladm/dladm.xcl index 09192c7f4d..2c74c5fbf4 100644 --- a/usr/src/cmd/dladm/dladm.xcl +++ b/usr/src/cmd/dladm/dladm.xcl @@ -18,7 +18,7 @@ # # CDDL HEADER END # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -27,6 +27,8 @@ msgid "" msgid "\t%-10llu" msgid "\t%-6.1f" msgid "\t-" +msgid "--" +msgid "--," msgid "\tipackets rbytes opackets obytes " msgid "\n" msgid " " @@ -300,6 +302,7 @@ msgid "opktdist" msgid "output" msgid "over" msgid "parseable" +msgid "parsable" msgid "pause" msgid "pd:si:" msgid "peeradv" diff --git a/usr/src/cmd/flowadm/Makefile b/usr/src/cmd/flowadm/Makefile index b6af8b2b79..2230ed1623 100644 --- a/usr/src/cmd/flowadm/Makefile +++ b/usr/src/cmd/flowadm/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -34,7 +34,7 @@ include ../Makefile.cmd XGETFLAGS += -a -x $(PROG).xcl LDLIBS += -L$(ROOT)/lib -LDLIBS += -ldladm -lkstat +LDLIBS += -ldladm -lkstat -linetutil ROOTCFGDIR= $(ROOTETC)/dladm ROOTCFGFILES= $(CONFIGFILES:%=$(ROOTCFGDIR)/%) diff --git a/usr/src/cmd/flowadm/flowadm.c b/usr/src/cmd/flowadm/flowadm.c index dfa718ff68..886c233fca 100644 --- a/usr/src/cmd/flowadm/flowadm.c +++ b/usr/src/cmd/flowadm/flowadm.c @@ -49,74 +49,27 @@ #include <inet/ip.h> #include <inet/ip6.h> #include <stddef.h> - -#define CMD_TYPE_ANY 0xffffffff -#define STR_UNDEF_VAL "--" - - -/* - * data structures and routines for printing output. - */ - -typedef struct print_field_s { - const char *pf_name; - const char *pf_header; - uint_t pf_width; - union { - uint_t _pf_index; - size_t _pf_offset; - }_pf_un; -#define pf_index _pf_un._pf_index -#define pf_offset _pf_un._pf_offset; - uint_t pf_cmdtype; -} print_field_t; - -typedef struct print_state_s { - print_field_t **ps_fields; - uint_t ps_nfields; - boolean_t ps_lastfield; - uint_t ps_overflow; -} print_state_t; +#include <ofmt.h> typedef struct show_usage_state_s { boolean_t us_plot; - boolean_t us_parseable; + boolean_t us_parsable; boolean_t us_printheader; boolean_t us_first; boolean_t us_showall; - print_state_t us_print; + ofmt_handle_t us_ofmt; } show_usage_state_t; -typedef char *(*print_callback_t)(print_field_t *, void *); -static print_field_t **parse_output_fields(char *, print_field_t *, int, - uint_t, uint_t *); - -static void print_header(print_state_t *); -static void print_field(print_state_t *, print_field_t *, const char *, - boolean_t); - -static void flowadm_print_output(print_state_t *, boolean_t, - print_callback_t, void *); - -/* - * helper function that, when invoked as flowadm(print_field(pf, buf) - * prints string which is offset by pf->pf_offset within buf. - */ -static char *flowadm_print_field(print_field_t *, void *); - -#define MAX_FIELD_LEN 32 - typedef struct show_flow_state { boolean_t fs_firstonly; boolean_t fs_donefirst; pktsum_t fs_prevstats; uint32_t fs_flags; dladm_status_t fs_status; - print_state_t fs_print; + ofmt_handle_t fs_ofmt; const char *fs_flow; const char *fs_link; - boolean_t fs_parseable; - boolean_t fs_printheader; + boolean_t fs_parsable; boolean_t fs_persist; boolean_t fs_stats; uint64_t fs_mask; @@ -150,6 +103,10 @@ static void die_dlerr(dladm_status_t, const char *, ...); static void warn(const char *, ...); static void warn_dlerr(dladm_status_t, const char *, ...); +/* callback functions for printing output */ +static ofmt_cb_t print_flowprop_cb, print_default_cb, print_flow_stats_cb; +static void flowadm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t); + typedef struct cmd { char *c_name; void (*c_fn)(int, char **); @@ -168,6 +125,7 @@ static cmd_t cmds[] = { static const struct option longopts[] = { {"link", required_argument, 0, 'l'}, + {"parsable", no_argument, 0, 'p'}, {"parseable", no_argument, 0, 'p'}, {"statistics", no_argument, 0, 's'}, {"interval", required_argument, 0, 'i'}, @@ -188,7 +146,6 @@ static const struct option prop_longopts[] = { /* * structures for 'flowadm remove-flow' */ - typedef struct remove_flow_state { boolean_t fs_tempop; const char *fs_altroot; @@ -198,6 +155,7 @@ typedef struct remove_flow_state { #define PROTO_MAXSTR_LEN 7 #define PORT_MAXSTR_LEN 6 #define DSFIELD_MAXSTR_LEN 10 +#define NULL_OFMT {NULL, 0, 0, NULL} typedef struct flow_fields_buf_s { @@ -209,24 +167,23 @@ typedef struct flow_fields_buf_s char flow_dsfield[DSFIELD_MAXSTR_LEN]; } flow_fields_buf_t; -static print_field_t flow_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "flow", "FLOW", 11, - offsetof(flow_fields_buf_t, flow_name), CMD_TYPE_ANY}, -{ "link", "LINK", 11, - offsetof(flow_fields_buf_t, flow_link), CMD_TYPE_ANY}, -{ "ipaddr", "IPADDR", 30, - offsetof(flow_fields_buf_t, flow_ipaddr), CMD_TYPE_ANY}, -{ "proto", "PROTO", 6, - offsetof(flow_fields_buf_t, flow_proto), CMD_TYPE_ANY}, -{ "port", "PORT", 7, - offsetof(flow_fields_buf_t, flow_port), CMD_TYPE_ANY}, -{ "dsfld", "DSFLD", 9, - offsetof(flow_fields_buf_t, flow_dsfield), CMD_TYPE_ANY}} +static ofmt_field_t flow_fields[] = { +/* name, field width, index */ +{ "FLOW", 12, + offsetof(flow_fields_buf_t, flow_name), print_default_cb}, +{ "LINK", 12, + offsetof(flow_fields_buf_t, flow_link), print_default_cb}, +{ "IPADDR", 31, + offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb}, +{ "PROTO", 7, + offsetof(flow_fields_buf_t, flow_proto), print_default_cb}, +{ "PORT", 8, + offsetof(flow_fields_buf_t, flow_port), print_default_cb}, +{ "DSFLD", 10, + offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb}, +NULL_OFMT} ; -#define FLOW_MAX_FIELDS (sizeof (flow_fields) / sizeof (print_field_t)) - /* * structures for 'flowadm show-flowprop' */ @@ -238,16 +195,15 @@ typedef enum { FLOWPROP_POSSIBLE } flowprop_field_index_t; -static print_field_t flowprop_fields[] = { -/* name, header, fieldwidth, index, cmdtype */ -{ "flow", "FLOW", 12, FLOWPROP_FLOW, CMD_TYPE_ANY}, -{ "property", "PROPERTY", 15, FLOWPROP_PROPERTY, CMD_TYPE_ANY}, -{ "value", "VALUE", 14, FLOWPROP_VALUE, CMD_TYPE_ANY}, -{ "default", "DEFAULT", 14, FLOWPROP_DEFAULT, CMD_TYPE_ANY}, -{ "possible", "POSSIBLE", 20, FLOWPROP_POSSIBLE, CMD_TYPE_ANY}} +static ofmt_field_t flowprop_fields[] = { +/* name, fieldwidth, index, callback */ +{ "FLOW", 13, FLOWPROP_FLOW, print_flowprop_cb}, +{ "PROPERTY", 16, FLOWPROP_PROPERTY, print_flowprop_cb}, +{ "VALUE", 15, FLOWPROP_VALUE, print_flowprop_cb}, +{ "DEFAULT", 15, FLOWPROP_DEFAULT, print_flowprop_cb}, +{ "POSSIBLE", 21, FLOWPROP_POSSIBLE, print_flowprop_cb}, +NULL_OFMT} ; -#define FLOWPROP_MAX_FIELDS \ - (sizeof (flowprop_fields) / sizeof (print_field_t)) #define MAX_PROP_LINE 512 @@ -257,12 +213,12 @@ typedef struct show_flowprop_state { char *fs_line; char **fs_propvals; dladm_arg_list_t *fs_proplist; - boolean_t fs_parseable; + boolean_t fs_parsable; boolean_t fs_persist; boolean_t fs_header; dladm_status_t fs_status; dladm_status_t fs_retstatus; - print_state_t fs_print; + ofmt_handle_t fs_ofmt; } show_flowprop_state_t; typedef struct set_flowprop_state { @@ -290,29 +246,26 @@ typedef enum { FLOW_S_OERRORS } flow_s_field_index_t; -static print_field_t flow_s_fields[] = { -/* name, header, field width, index, cmdtype */ -{ "flow", "FLOW", 15, FLOW_S_FLOW, CMD_TYPE_ANY}, -{ "ipackets", "IPACKETS", 10, FLOW_S_IPKTS, CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 8, FLOW_S_RBYTES, CMD_TYPE_ANY}, -{ "ierrors", "IERRORS", 10, FLOW_S_IERRORS, CMD_TYPE_ANY}, -{ "opackets", "OPACKETS", 12, FLOW_S_OPKTS, CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 12, FLOW_S_OBYTES, CMD_TYPE_ANY}, -{ "oerrors", "OERRORS", 8, FLOW_S_OERRORS, CMD_TYPE_ANY}} +static ofmt_field_t flow_s_fields[] = { +/* name, field width, index, callback */ +{ "FLOW", 15, FLOW_S_FLOW, print_flow_stats_cb}, +{ "IPACKETS", 10, FLOW_S_IPKTS, print_flow_stats_cb}, +{ "RBYTES", 8, FLOW_S_RBYTES, print_flow_stats_cb}, +{ "IERRORS", 10, FLOW_S_IERRORS, print_flow_stats_cb}, +{ "OPACKETS", 12, FLOW_S_OPKTS, print_flow_stats_cb}, +{ "OBYTES", 12, FLOW_S_OBYTES, print_flow_stats_cb}, +{ "OERRORS", 8, FLOW_S_OERRORS, print_flow_stats_cb}, +NULL_OFMT} ; -#define FLOW_S_MAX_FIELDS \ - (sizeof (flow_s_fields) / sizeof (print_field_t)) typedef struct flow_args_s { char *flow_s_flow; pktsum_t *flow_s_psum; } flow_args_t; -static char *print_flow_stats(print_field_t *, void *); /* * structures for 'flowadm show-usage' */ - typedef struct usage_fields_buf_s { char usage_flow[12]; char usage_duration[10]; @@ -323,26 +276,25 @@ typedef struct usage_fields_buf_s { char usage_bandwidth[14]; } usage_fields_buf_t; -static print_field_t usage_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "flow", "FLOW", 12, - offsetof(usage_fields_buf_t, usage_flow), CMD_TYPE_ANY}, -{ "duration", "DURATION", 10, - offsetof(usage_fields_buf_t, usage_duration), CMD_TYPE_ANY}, -{ "ipackets", "IPACKETS", 9, - offsetof(usage_fields_buf_t, usage_ipackets), CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 10, - offsetof(usage_fields_buf_t, usage_rbytes), CMD_TYPE_ANY}, -{ "opackets", "OPACKETS", 9, - offsetof(usage_fields_buf_t, usage_opackets), CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 10, - offsetof(usage_fields_buf_t, usage_obytes), CMD_TYPE_ANY}, -{ "bandwidth", "BANDWIDTH", 14, - offsetof(usage_fields_buf_t, usage_bandwidth), CMD_TYPE_ANY}} +static ofmt_field_t usage_fields[] = { +/* name, field width, offset */ +{ "FLOW", 13, + offsetof(usage_fields_buf_t, usage_flow), print_default_cb}, +{ "DURATION", 11, + offsetof(usage_fields_buf_t, usage_duration), print_default_cb}, +{ "IPACKETS", 10, + offsetof(usage_fields_buf_t, usage_ipackets), print_default_cb}, +{ "RBYTES", 11, + offsetof(usage_fields_buf_t, usage_rbytes), print_default_cb}, +{ "OPACKETS", 10, + offsetof(usage_fields_buf_t, usage_opackets), print_default_cb}, +{ "OBYTES", 11, + offsetof(usage_fields_buf_t, usage_obytes), print_default_cb}, +{ "BANDWIDTH", 15, + offsetof(usage_fields_buf_t, usage_bandwidth), print_default_cb}, +NULL_OFMT} ; -#define USAGE_MAX_FIELDS (sizeof (usage_fields) / sizeof (print_field_t)) - /* * structures for 'dladm show-usage link' */ @@ -356,25 +308,23 @@ typedef struct usage_l_fields_buf_s { char usage_l_bandwidth[14]; } usage_l_fields_buf_t; -static print_field_t usage_l_fields[] = { -/* name, header, field width, offset, cmdtype */ -{ "flow", "FLOW", 12, - offsetof(usage_l_fields_buf_t, usage_l_flow), CMD_TYPE_ANY}, -{ "start", "START", 13, - offsetof(usage_l_fields_buf_t, usage_l_stime), CMD_TYPE_ANY}, -{ "end", "END", 13, - offsetof(usage_l_fields_buf_t, usage_l_etime), CMD_TYPE_ANY}, -{ "rbytes", "RBYTES", 8, - offsetof(usage_l_fields_buf_t, usage_l_rbytes), CMD_TYPE_ANY}, -{ "obytes", "OBYTES", 8, - offsetof(usage_l_fields_buf_t, usage_l_obytes), CMD_TYPE_ANY}, -{ "bandwidth", "BANDWIDTH", 14, - offsetof(usage_l_fields_buf_t, usage_l_bandwidth), CMD_TYPE_ANY}} +static ofmt_field_t usage_l_fields[] = { +/* name, field width, offset */ +{ "FLOW", 13, + offsetof(usage_l_fields_buf_t, usage_l_flow), print_default_cb}, +{ "START", 14, + offsetof(usage_l_fields_buf_t, usage_l_stime), print_default_cb}, +{ "END", 14, + offsetof(usage_l_fields_buf_t, usage_l_etime), print_default_cb}, +{ "RBYTES", 9, + offsetof(usage_l_fields_buf_t, usage_l_rbytes), print_default_cb}, +{ "OBYTES", 9, + offsetof(usage_l_fields_buf_t, usage_l_obytes), print_default_cb}, +{ "BANDWIDTH", 15, + offsetof(usage_l_fields_buf_t, usage_l_bandwidth), print_default_cb}, +NULL_OFMT} ; -#define USAGE_L_MAX_FIELDS \ - (sizeof (usage_l_fields) /sizeof (print_field_t)) - #define PRI_HI 100 #define PRI_LO 10 #define PRI_NORM 50 @@ -588,14 +538,7 @@ show_usage_time(dladm_usage_t *usage, void *arg) (void) snprintf(ubuf.usage_l_bandwidth, sizeof (ubuf.usage_l_bandwidth), "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); - if (!state->us_parseable && !state->us_printheader) { - print_header(&state->us_print); - state->us_printheader = B_TRUE; - } - - flowadm_print_output(&state->us_print, state->us_parseable, - flowadm_print_field, (void *)&ubuf); - + ofmt_print(state->us_ofmt, (void *)&ubuf); return (DLADM_STATUS_OK); } @@ -634,13 +577,7 @@ show_usage_res(dladm_usage_t *usage, void *arg) (void) snprintf(ubuf.usage_bandwidth, sizeof (ubuf.usage_bandwidth), "%s Mbps", dladm_bw2str(usage->du_bandwidth, buf)); - if (!state->us_parseable && !state->us_printheader) { - print_header(&state->us_print); - state->us_printheader = B_TRUE; - } - - flowadm_print_output(&state->us_print, state->us_parseable, - flowadm_print_field, (void *)&ubuf); + ofmt_print(state->us_ofmt, (void *)&ubuf); return (DLADM_STATUS_OK); } @@ -669,15 +606,16 @@ do_show_usage(int argc, char *argv[]) boolean_t F_arg = B_FALSE; char *fields_str = NULL; char *formatspec_str = NULL; - print_field_t **fields; - uint_t nfields; char *all_fields = "flow,duration,ipackets,rbytes,opackets,obytes,bandwidth"; char *all_l_fields = "flow,start,end,rbytes,obytes,bandwidth"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (show_usage_state_t)); - state.us_parseable = B_FALSE; + state.us_parsable = B_FALSE; state.us_printheader = B_FALSE; state.us_plot = B_FALSE; state.us_first = B_TRUE; @@ -726,24 +664,22 @@ do_show_usage(int argc, char *argv[]) resource = argv[optind]; } + if (state.us_parsable) + ofmtflags |= OFMT_PARSABLE; if (resource == NULL && stime == NULL && etime == NULL) { if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) fields_str = all_fields; - fields = parse_output_fields(fields_str, usage_fields, - USAGE_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + oferr = ofmt_open(fields_str, usage_fields, ofmtflags, + 0, &ofmt); } else { if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) fields_str = all_l_fields; - fields = parse_output_fields(fields_str, usage_l_fields, - USAGE_L_MAX_FIELDS, CMD_TYPE_ANY, &nfields); + oferr = ofmt_open(fields_str, usage_l_fields, ofmtflags, + 0, &ofmt); } - if (fields == NULL) { - die("invalid fields(s) specified"); - return; - } - state.us_print.ps_fields = fields; - state.us_print.ps_nfields = nfields; + flowadm_ofmt_check(oferr, state.us_parsable, ofmt); + state.us_ofmt = ofmt; if (F_arg && d_arg) die("incompatible -d and -F options"); @@ -770,6 +706,7 @@ do_show_usage(int argc, char *argv[]) DLADM_LOGTYPE_FLOW, file, stime, etime, &state); } + ofmt_close(ofmt); if (status != DLADM_STATUS_OK) die_dlerr(status, "show-usage"); } @@ -949,15 +886,6 @@ remove_flow(dladm_flow_attr_t *attr, void *arg) return (DLADM_WALK_TERMINATE); } -static char * -flowadm_print_field(print_field_t *pf, void *arg) -{ - char *value; - - value = (char *)arg + pf->pf_offset; - return (value); -} - /*ARGSUSED*/ static dladm_status_t print_flow(show_flow_state_t *state, dladm_flow_attr_t *attr, @@ -1007,13 +935,7 @@ show_flow(dladm_flow_attr_t *attr, void *arg) if (status != DLADM_STATUS_OK) goto done; - if (!statep->fs_parseable && !statep->fs_printheader) { - print_header(&statep->fs_print); - statep->fs_printheader = B_TRUE; - } - - flowadm_print_output(&statep->fs_print, statep->fs_parseable, - flowadm_print_field, (void *)&fbuf); + ofmt_print(statep->fs_ofmt, (void *)&fbuf); done: statep->fs_status = status; @@ -1067,48 +989,47 @@ get_flow_stats(const char *flowname, pktsum_t *stats) (void) kstat_close(kcp); } - -static char * -print_flow_stats(print_field_t *pf, void *arg) +static boolean_t +print_flow_stats_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) { - flow_args_t *fargs = arg; + flow_args_t *fargs = of_arg->ofmt_cbarg; pktsum_t *diff_stats = fargs->flow_s_psum; - static char buf[DLADM_STRSIZE]; - switch (pf->pf_index) { + switch (of_arg->ofmt_id) { case FLOW_S_FLOW: - (void) snprintf(buf, sizeof (buf), "%s", fargs->flow_s_flow); + (void) snprintf(buf, bufsize, "%s", fargs->flow_s_flow); break; case FLOW_S_IPKTS: - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats->ipackets); break; case FLOW_S_RBYTES: - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats->rbytes); break; case FLOW_S_IERRORS: - (void) snprintf(buf, sizeof (buf), "%u", + (void) snprintf(buf, bufsize, "%u", diff_stats->ierrors); break; case FLOW_S_OPKTS: - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats->opackets); break; case FLOW_S_OBYTES: - (void) snprintf(buf, sizeof (buf), "%llu", + (void) snprintf(buf, bufsize, "%llu", diff_stats->obytes); break; case FLOW_S_OERRORS: - (void) snprintf(buf, sizeof (buf), "%u", + (void) snprintf(buf, bufsize, "%u", diff_stats->oerrors); break; default: die("invalid input"); break; } - return (buf); + return (B_TRUE); } + /* ARGSUSED */ static int show_flow_stats(dladm_flow_attr_t *attr, void *arg) @@ -1131,9 +1052,7 @@ show_flow_stats(dladm_flow_attr_t *attr, void *arg) fargs.flow_s_flow = name; fargs.flow_s_psum = &diff_stats; - flowadm_print_output(&state->fs_print, state->fs_parseable, - print_flow_stats, &fargs); - + ofmt_print(state->fs_ofmt, (void *)&fargs); state->fs_prevstats = stats; return (DLADM_WALK_CONTINUE); @@ -1160,18 +1079,13 @@ flow_stats(const char *flow, datalink_id_t linkid, uint_t interval, char *fields_str, show_flow_state_t *state) { dladm_flow_attr_t attr; - print_field_t **fields; - uint_t nfields; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; - fields = parse_output_fields(fields_str, flow_s_fields, - FLOW_S_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - - state->fs_print.ps_fields = fields; - state->fs_print.ps_nfields = nfields; + oferr = ofmt_open(fields_str, flow_s_fields, ofmtflags, 0, &ofmt); + flowadm_ofmt_check(oferr, state->fs_parsable, ofmt); + state->fs_ofmt = ofmt; if (flow != NULL && dladm_flow_info(handle, flow, &attr) != DLADM_STATUS_OK) @@ -1183,8 +1097,6 @@ flow_stats(const char *flow, datalink_id_t linkid, uint_t interval, */ state->fs_firstonly = (interval != 0); - if (!state->fs_parseable) - print_header(&state->fs_print); for (;;) { state->fs_donefirst = B_FALSE; @@ -1210,6 +1122,7 @@ flow_stats(const char *flow, datalink_id_t linkid, uint_t interval, (void) sleep(interval); } + ofmt_close(ofmt); } static void @@ -1227,12 +1140,9 @@ do_show_flow(int argc, char *argv[]) uint32_t interval = 0; show_flow_state_t state; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; - char *all_fields = - "flow,link,ipaddr,proto,port,dsfld"; - char *allstat_fields = - "flow,ipackets,rbytes,ierrors,opackets,obytes,oerrors"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; bzero(&state, sizeof (state)); @@ -1241,7 +1151,8 @@ do_show_flow(int argc, char *argv[]) longopts, NULL)) != -1) { switch (option) { case 'p': - state.fs_parseable = B_TRUE; + state.fs_parsable = B_TRUE; + ofmtflags |= OFMT_PARSABLE; break; case 'P': state.fs_persist = B_TRUE; @@ -1288,7 +1199,6 @@ do_show_flow(int argc, char *argv[]) break; } } - if (i_arg && !(s_arg || S_arg)) die("the -i option can be used only with -s or -S"); @@ -1309,28 +1219,14 @@ do_show_flow(int argc, char *argv[]) return; } - if (!o_arg || (o_arg && strcasecmp(fields_str, "all") == 0)) { - if (s_arg) - fields_str = allstat_fields; - else - fields_str = all_fields; - } - if (s_arg) { flow_stats(state.fs_flow, linkid, interval, fields_str, &state); return; } - fields = parse_output_fields(fields_str, flow_fields, FLOW_MAX_FIELDS, - CMD_TYPE_ANY, &nfields); - - if (fields == NULL) { - die("invalid fields(s) specified"); - return; - } - - state.fs_print.ps_fields = fields; - state.fs_print.ps_nfields = nfields; + oferr = ofmt_open(fields_str, flow_fields, ofmtflags, 0, &ofmt); + flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); + state.fs_ofmt = ofmt; /* Show attributes of one flow */ if (state.fs_flow != NULL) { @@ -1346,6 +1242,7 @@ do_show_flow(int argc, char *argv[]) &state, DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE); } + ofmt_close(ofmt); } static dladm_status_t @@ -1693,8 +1590,8 @@ print_flowprop(const char *flowname, show_flowprop_state_t *statep, ptr = buf; lim = buf + DLADM_STRSIZE; for (i = 0; i < valcnt; i++) { - if (propvals[i][0] == '\0' && !statep->fs_parseable) - ptr += snprintf(ptr, lim - ptr, STR_UNDEF_VAL","); + if (propvals[i][0] == '\0' && !statep->fs_parsable) + ptr += snprintf(ptr, lim - ptr, "--,"); else ptr += snprintf(ptr, lim - ptr, "%s,", propvals[i]); if (ptr >= lim) @@ -1704,7 +1601,7 @@ print_flowprop(const char *flowname, show_flowprop_state_t *statep, buf[strlen(buf) - 1] = '\0'; lim = statep->fs_line + MAX_PROP_LINE; - if (statep->fs_parseable) { + if (statep->fs_parsable) { *pptr += snprintf(*pptr, lim - *pptr, "%s", buf); } else { @@ -1712,17 +1609,17 @@ print_flowprop(const char *flowname, show_flowprop_state_t *statep, } } -static char * -flowprop_callback(print_field_t *pf, void *fs_arg) +static boolean_t +print_flowprop_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) { - flowprop_args_t *arg = fs_arg; + flowprop_args_t *arg = of_arg->ofmt_cbarg; char *propname = arg->fs_propname; show_flowprop_state_t *statep = arg->fs_state; char *ptr = statep->fs_line; char *lim = ptr + MAX_PROP_LINE; char *flowname = arg->fs_flowname; - switch (pf->pf_index) { + switch (of_arg->ofmt_id) { case FLOWPROP_FLOW: (void) snprintf(ptr, lim - ptr, "%s", statep->fs_flow); break; @@ -1760,12 +1657,12 @@ flowprop_callback(print_field_t *pf, void *fs_arg) die("invalid input"); break; } - return (ptr); + (void) strlcpy(buf, ptr, bufsize); + return (B_TRUE); skip: - if (statep->fs_status != DLADM_STATUS_OK) - return (NULL); - else - return (""); + buf[0] = '\0'; + return ((statep->fs_status == DLADM_STATUS_OK) ? + B_TRUE : B_FALSE); } static int @@ -1779,13 +1676,7 @@ show_one_flowprop(void *arg, const char *propname) fs_arg.fs_propname = (char *)propname; fs_arg.fs_flowname = (char *)statep->fs_flow; - if (statep->fs_header) { - statep->fs_header = B_FALSE; - if (!statep ->fs_parseable) - print_header(&statep->fs_print); - } - flowadm_print_output(&statep->fs_print, statep->fs_parseable, - flowprop_callback, (void *)&fs_arg); + ofmt_print(statep->fs_ofmt, (void *)&fs_arg); return (DLADM_WALK_CONTINUE); } @@ -1820,20 +1711,17 @@ static void do_show_flowprop(int argc, char **argv) { int option; - boolean_t o_arg = B_FALSE; dladm_arg_list_t *proplist = NULL; show_flowprop_state_t state; char *fields_str = NULL; - print_field_t **fields; - uint_t nfields; - char *all_fields = - "flow,property,value,default,possible"; + ofmt_handle_t ofmt; + ofmt_status_t oferr; + uint_t ofmtflags = 0; - fields_str = all_fields; opterr = 0; state.fs_propvals = NULL; state.fs_line = NULL; - state.fs_parseable = B_FALSE; + state.fs_parsable = B_FALSE; state.fs_persist = B_FALSE; state.fs_header = B_TRUE; state.fs_retstatus = DLADM_STATUS_OK; @@ -1849,7 +1737,8 @@ do_show_flowprop(int argc, char **argv) die("invalid flow properties specified"); break; case 'c': - state.fs_parseable = B_TRUE; + state.fs_parsable = B_TRUE; + ofmtflags |= OFMT_PARSABLE; break; case 'P': state.fs_persist = B_TRUE; @@ -1860,11 +1749,7 @@ do_show_flowprop(int argc, char **argv) die("invalid link '%s'", optarg); break; case 'o': - o_arg = B_TRUE; - if (strcasecmp(optarg, "all") == 0) - fields_str = all_fields; - else - fields_str = optarg; + fields_str = optarg; break; default: die_opterr(optopt, option); @@ -1872,12 +1757,6 @@ do_show_flowprop(int argc, char **argv) } } - if (state.fs_parseable && !o_arg) - die("-p requires -o"); - - if (state.fs_parseable && strcasecmp(fields_str, "all") == 0) - die("\"-o all\" is invalid with -p"); - if (optind == (argc - 1)) { if (strlen(argv[optind]) >= MAXFLOWNAMELEN) die("flow name too long"); @@ -1885,20 +1764,12 @@ do_show_flowprop(int argc, char **argv) } else if (optind != argc) { usage(); } - bzero(&state.fs_print, sizeof (print_state_t)); state.fs_proplist = proplist; state.fs_status = DLADM_STATUS_OK; - fields = parse_output_fields(fields_str, flowprop_fields, - FLOWPROP_MAX_FIELDS, CMD_TYPE_ANY, &nfields); - - if (fields == NULL) { - die("invalid field(s) specified"); - return; - } - - state.fs_print.ps_fields = fields; - state.fs_print.ps_nfields = nfields; + oferr = ofmt_open(fields_str, flowprop_fields, ofmtflags, 0, &ofmt); + flowadm_ofmt_check(oferr, state.fs_parsable, ofmt); + state.fs_ofmt = ofmt; /* Show properties for one flow */ if (state.fs_flow != NULL) { @@ -1916,6 +1787,7 @@ do_show_flowprop(int argc, char **argv) } dladm_free_props(proplist); + ofmt_close(ofmt); } static void @@ -1974,179 +1846,39 @@ show_flowprop_one_flow(void *arg, const char *flow) statep->fs_flow = savep; } -typedef struct { - char *s_buf; - char **s_fields; /* array of pointer to the fields in s_buf */ - uint_t s_nfields; /* the number of fields in s_buf */ -} split_t; - -/* - * Free the split_t structure pointed to by `sp'. - */ -static void -splitfree(split_t *sp) -{ - free(sp->s_buf); - free(sp->s_fields); - free(sp); -} - /* - * Split `str' into at most `maxfields' fields, each field at most `maxlen' in - * length. Return a pointer to a split_t containing the split fields, or NULL - * on failure. + * default output callback function that, when invoked from dladm_print_output, + * prints string which is offset by of_arg->ofmt_id within buf. */ -static split_t * -split(const char *str, uint_t maxfields, uint_t maxlen) -{ - char *field, *token, *lasts = NULL; - split_t *sp; - - if (*str == '\0' || maxfields == 0 || maxlen == 0) - return (NULL); - - sp = calloc(sizeof (split_t), 1); - if (sp == NULL) - return (NULL); - - sp->s_buf = strdup(str); - sp->s_fields = malloc(sizeof (char *) * maxfields); - if (sp->s_buf == NULL || sp->s_fields == NULL) - goto fail; - - token = sp->s_buf; - while ((field = strtok_r(token, ",", &lasts)) != NULL) { - if (sp->s_nfields == maxfields || strlen(field) > maxlen) - goto fail; - token = NULL; - sp->s_fields[sp->s_nfields++] = field; - } - return (sp); -fail: - splitfree(sp); - return (NULL); -} - -static print_field_t ** -parse_output_fields(char *str, print_field_t *template, int max_fields, - uint_t cmdtype, uint_t *countp) -{ - split_t *sp; - boolean_t good_match = B_FALSE; - uint_t i, j; - print_field_t **pf = NULL; - - sp = split(str, max_fields, MAX_FIELD_LEN); - - if (sp == NULL) - return (NULL); - - pf = malloc(sp->s_nfields * sizeof (print_field_t *)); - if (pf == NULL) - goto fail; - - for (i = 0; i < sp->s_nfields; i++) { - for (j = 0; j < max_fields; j++) { - if (strcasecmp(sp->s_fields[i], - template[j].pf_name) == 0) { - good_match = template[j]. pf_cmdtype & cmdtype; - break; - } - } - if (!good_match) - goto fail; - - good_match = B_FALSE; - pf[i] = &template[j]; - } - *countp = i; - splitfree(sp); - return (pf); -fail: - free(pf); - splitfree(sp); - return (NULL); -} - -static void -flowadm_print_output(print_state_t *statep, boolean_t parseable, - print_callback_t fn, void *arg) +static boolean_t +print_default_cb(ofmt_arg_t *of_arg, char *buf, uint_t bufsize) { - int i; char *value; - print_field_t **pf; - - pf = statep->ps_fields; - for (i = 0; i < statep->ps_nfields; i++) { - statep->ps_lastfield = (i + 1 == statep->ps_nfields); - value = (*fn)(pf[i], arg); - if (value != NULL) - print_field(statep, pf[i], value, parseable); - } - (void) putchar('\n'); -} - -static void -print_header(print_state_t *ps) -{ - int i; - print_field_t **pf; - pf = ps->ps_fields; - for (i = 0; i < ps->ps_nfields; i++) { - ps->ps_lastfield = (i + 1 == ps->ps_nfields); - print_field(ps, pf[i], pf[i]->pf_header, B_FALSE); - } - (void) putchar('\n'); + value = (char *)of_arg->ofmt_cbarg + of_arg->ofmt_id; + (void) strlcpy(buf, value, bufsize); + return (B_TRUE); } static void -print_field(print_state_t *statep, print_field_t *pfp, const char *value, - boolean_t parseable) +flowadm_ofmt_check(ofmt_status_t oferr, boolean_t parsable, + ofmt_handle_t ofmt) { - uint_t width = pfp->pf_width; - uint_t valwidth; - uint_t compress; + char buf[OFMT_BUFSIZE]; + if (oferr == OFMT_SUCCESS) + return; + (void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf)); /* - * Parsable fields are separated by ':'. If such a field contains - * a ':' or '\', this character is prefixed by a '\'. + * All errors are considered fatal in parsable mode. + * NOMEM errors are always fatal, regardless of mode. + * For other errors, we print diagnostics in human-readable + * mode and processs what we can. */ - if (parseable) { - char c; - - if (statep->ps_nfields == 1) { - (void) printf("%s", value); - return; - } - while ((c = *value++) != '\0') { - if (c == ':' || c == '\\') - (void) putchar('\\'); - (void) putchar(c); - } - if (!statep->ps_lastfield) - (void) putchar(':'); - return; + if (parsable || oferr == OFMT_ENOFIELDS) { + ofmt_close(ofmt); + die(buf); } else { - if (value[0] == '\0') - value = STR_UNDEF_VAL; - if (statep->ps_lastfield) { - (void) printf("%s", value); - statep->ps_overflow = 0; - return; - } - - valwidth = strlen(value); - if (valwidth > width) { - statep->ps_overflow += valwidth - width; - } else if (valwidth < width && statep->ps_overflow > 0) { - compress = min(statep->ps_overflow, width - valwidth); - statep->ps_overflow -= compress; - width -= compress; - } - (void) printf("%-*s", width, value); + warn(buf); } - - if (!statep->ps_lastfield) - (void) putchar(' '); } diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index bd432a268e..2ec74c85d6 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -314,6 +314,7 @@ MSGSUBDIRS= \ libidmap \ libinetcfg \ libipmp \ + libinetutil \ libnsl \ libpam \ libpicl \ diff --git a/usr/src/lib/libinetutil/Makefile b/usr/src/lib/libinetutil/Makefile index 980894ba78..0bc13a5c87 100644 --- a/usr/src/lib/libinetutil/Makefile +++ b/usr/src/lib/libinetutil/Makefile @@ -19,19 +19,22 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" # include ../Makefile.lib -HDRS = libinetutil.h +HDRS = libinetutil.h ofmt.h HDRDIR = common SUBDIRS = $(MACH) $(BUILD64)SUBDIRS += $(MACH64) +POFILE = libinetutil.po +MSGFILES = common/ofmt.c +XGETFLAGS = -a + all := TARGET = all clean := TARGET = clean clobber := TARGET = clobber @@ -46,9 +49,15 @@ install_h: $(ROOTHDRS) check: $(CHECKHDRS) +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +_msg: $(MSGDOMAINPOFILE) + $(SUBDIRS): FRC @cd $@; pwd; $(MAKE) $(TARGET) FRC: +include $(SRC)/Makefile.msg.targ include ../Makefile.targ diff --git a/usr/src/lib/libinetutil/Makefile.com b/usr/src/lib/libinetutil/Makefile.com index cd3a0d6e33..231dadfb58 100644 --- a/usr/src/lib/libinetutil/Makefile.com +++ b/usr/src/lib/libinetutil/Makefile.com @@ -25,7 +25,8 @@ LIBRARY = libinetutil.a VERS = .1 -OBJECTS = octet.o inetutil.o ifspec.o ifaddrlist.o ifaddrlistx.o eh.o tq.o +OBJECTS = octet.o inetutil.o ifspec.o ifaddrlist.o ifaddrlistx.o eh.o tq.o \ + ofmt.o include ../../Makefile.lib @@ -38,7 +39,8 @@ SRCDIR = ../common COMDIR = $(SRC)/common/net/dhcp SRCS = $(COMDIR)/octet.c $(SRCDIR)/inetutil.c \ $(SRCDIR)/ifspec.c $(SRCDIR)/eh.c $(SRCDIR)/tq.c \ - $(SRCDIR)/ifaddrlist.c $(SRCDIR)/ifaddrlistx.c + $(SRCDIR)/ifaddrlist.c $(SRCDIR)/ifaddrlistx.c \ + $(SRCDIR)/ofmt.c $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) LDLIBS += -lsocket -lc diff --git a/usr/src/lib/libinetutil/common/llib-linetutil b/usr/src/lib/libinetutil/common/llib-linetutil index 5e87f60dea..9dd868fa9f 100644 --- a/usr/src/lib/libinetutil/common/llib-linetutil +++ b/usr/src/lib/libinetutil/common/llib-linetutil @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,13 +19,12 @@ * CDDL HEADER END */ /* - * Copyright (c) 2001 by Sun Microsystems, Inc. - * All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* LINTLIBRARY */ /* PROTOLIB1 */ #include <libinetutil.h> +#include <ofmt.h> diff --git a/usr/src/lib/libinetutil/common/mapfile-vers b/usr/src/lib/libinetutil/common/mapfile-vers index cd0d88de08..8bc79dd4cb 100644 --- a/usr/src/lib/libinetutil/common/mapfile-vers +++ b/usr/src/lib/libinetutil/common/mapfile-vers @@ -63,6 +63,11 @@ SUNWprivate_1.1 { iu_unregister_event; octet_to_hexascii; sockaddrcmp; + ofmt_open; + ofmt_close; + ofmt_print; + ofmt_update_winsize; + ofmt_strerror; local: *; }; diff --git a/usr/src/lib/libinetutil/common/ofmt.c b/usr/src/lib/libinetutil/common/ofmt.c new file mode 100644 index 0000000000..2f9fe3f91d --- /dev/null +++ b/usr/src/lib/libinetutil/common/ofmt.c @@ -0,0 +1,480 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#include <errno.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <stdio.h> +#include <ofmt.h> +#include <sys/termios.h> +#include <unistd.h> +#include <sys/sysmacros.h> +#include <libintl.h> + +/* + * functions and structures to internally process a comma-separated string + * of fields selected for output. + */ +typedef struct { + char *s_buf; + const char **s_fields; /* array of pointers to the fields in s_buf */ + uint_t s_nfields; /* the number of fields in s_buf */ +} split_t; +static void splitfree(split_t *); +static split_t *split_str(const char *, uint_t); +static split_t *split_fields(const ofmt_field_t *, uint_t, uint_t); + +/* + * The state of the output is tracked in a ofmt_state_t structure. + * Each os_fields[i] entry points at an ofmt_field_t array for + * the sub-command whose contents are provided by the caller, with + * os_nfields set to the number of requested fields. + */ +typedef struct ofmt_state_s { + ofmt_field_t *os_fields; + uint_t os_nfields; + boolean_t os_lastfield; + uint_t os_overflow; + struct winsize os_winsize; + int os_nrow; + boolean_t os_parsable; + int os_nbad; + char **os_badfields; +} ofmt_state_t; +/* + * A B_TRUE return value from the callback function will print out the contents + * of the output buffer, except when the buffer is returned with the empty + * string "", in which case the OFMT_VAL_UNDEF will be printed. + * + * If the callback function returns B_FALSE, the "?" string will be emitted. + */ +#define OFMT_VAL_UNDEF "--" +#define OFMT_VAL_UNKNOWN "?" +static void ofmt_print_header(ofmt_state_t *); +static void ofmt_print_field(ofmt_state_t *, ofmt_field_t *, const char *, + boolean_t); + +/* + * Split `str' into at most `maxfields' fields, Return a pointer to a + * split_t containing the split fields, or NULL on failure. + */ +static split_t * +split_str(const char *str, uint_t maxfields) +{ + char *field, *token, *lasts = NULL; + split_t *sp; + + if (*str == '\0' || maxfields == 0) + return (NULL); + + sp = calloc(sizeof (split_t), 1); + if (sp == NULL) + return (NULL); + + sp->s_buf = strdup(str); + sp->s_fields = malloc(sizeof (char *) * maxfields); + if (sp->s_buf == NULL || sp->s_fields == NULL) + goto fail; + + token = sp->s_buf; + while ((field = strtok_r(token, ",", &lasts)) != NULL) { + if (sp->s_nfields == maxfields) + goto fail; + token = NULL; + sp->s_fields[sp->s_nfields++] = field; + } + return (sp); +fail: + splitfree(sp); + return (NULL); +} + +/* + * Split `fields' into at most `maxfields' fields. Return a pointer to + * a split_t containing the split fields, or NULL on failure. Invoked + * when all fields are implicitly selected at handle creation by + * passing in a NULL fields_str + */ +static split_t * +split_fields(const ofmt_field_t *template, uint_t maxfields, uint_t maxcols) +{ + split_t *sp; + int i, cols; + + sp = calloc(sizeof (split_t), 1); + if (sp == NULL) + return (NULL); + + sp->s_fields = malloc(sizeof (char *) * maxfields); + if (sp->s_fields == NULL) + goto fail; + cols = 0; + for (i = 0; i < maxfields; i++) { + cols += template[i].of_width; + /* + * If all fields are implied without explicitly passing + * in a fields_str, build a list of field names, stopping + * when we run out of columns. + */ + if (maxcols > 0 && cols > maxcols) + break; + sp->s_fields[sp->s_nfields++] = template[i].of_name; + } + return (sp); +fail: + splitfree(sp); + return (NULL); +} + +/* + * Free the split_t structure pointed to by `sp'. + */ +static void +splitfree(split_t *sp) +{ + if (sp == NULL) + return; + free(sp->s_buf); + free(sp->s_fields); + free(sp); +} + +/* + * Open a handle to be used for printing formatted output. + */ +ofmt_status_t +ofmt_open(const char *str, ofmt_field_t *template, uint_t flags, + uint_t maxcols, ofmt_handle_t *ofmt) +{ + split_t *sp; + uint_t i, j, of_index; + ofmt_field_t *of; + ofmt_state_t *os; + int nfields = 0; + ofmt_status_t err = OFMT_SUCCESS; + boolean_t parsable = (flags & OFMT_PARSABLE); + + *ofmt = NULL; + if (parsable) { + /* + * For parsable output mode, the caller always needs + * to specify precisely which fields are to be selected, + * since the set of fields may change over time. + */ + if (str == NULL || str[0] == '\0') + return (OFMT_EPARSENONE); + if (strcmp(str, "all") == 0) + return (OFMT_EPARSEALL); + } + if (template == NULL) + return (OFMT_ENOTEMPLATE); + for (of = template; of->of_name != NULL; of++) + nfields++; + /* + * split str into the columns selected, or construct the + * full set of columns (equivalent to -o all). + */ + if (str != NULL && strcmp(str, "all") != 0) { + sp = split_str(str, nfields); + } else { + if (parsable || (str != NULL && strcmp(str, "all") == 0)) + maxcols = 0; + sp = split_fields(template, nfields, maxcols); + } + if (sp == NULL) + goto nomem; + + os = calloc(sizeof (ofmt_state_t) + + sp->s_nfields * sizeof (ofmt_field_t), 1); + if (os == NULL) + goto nomem; + *ofmt = os; + os->os_fields = (ofmt_field_t *)&os[1]; + os->os_parsable = parsable; + of = os->os_fields; + of_index = 0; + /* + * sp->s_nfields is the number of fields requested in fields_str. + * nfields is the number of fields in template. + */ + for (i = 0; i < sp->s_nfields; i++) { + for (j = 0; j < nfields; j++) { + if (strcasecmp(sp->s_fields[i], + template[j].of_name) == 0) { + break; + } + } + if (j == nfields) { + int nbad = os->os_nbad++; + + err = OFMT_EBADFIELDS; + if (os->os_badfields == NULL) { + os->os_badfields = malloc(sp->s_nfields * + sizeof (char *)); + if (os->os_badfields == NULL) + goto nomem; + } + os->os_badfields[nbad] = strdup(sp->s_fields[i]); + if (os->os_badfields[nbad] == NULL) + goto nomem; + continue; + } + of[of_index].of_name = strdup(template[j].of_name); + if (of[of_index].of_name == NULL) + goto nomem; + of[of_index].of_width = template[j].of_width; + of[of_index].of_id = template[j].of_id; + of[of_index].of_cb = template[j].of_cb; + of_index++; + } + splitfree(sp); + if (of_index == 0) /* all values in str are bogus */ + return (OFMT_ENOFIELDS); + os->os_nfields = of_index; /* actual number of fields printed */ + ofmt_update_winsize(*ofmt); + return (err); +nomem: + err = OFMT_ENOMEM; + if (os != NULL) + ofmt_close(os); + *ofmt = NULL; + splitfree(sp); + return (err); +} + +/* + * free resources associated with the ofmt_handle_t + */ +void +ofmt_close(ofmt_handle_t ofmt) +{ + ofmt_state_t *os = ofmt; + int i; + + if (os == NULL) + return; + for (i = 0; i < os->os_nfields; i++) + free(os->os_fields[i].of_name); + for (i = 0; i < os->os_nbad; i++) + free(os->os_badfields[i]); + free(os->os_badfields); + free(os); +} + +/* + * Print the value for the selected field by calling the callback-function + * registered for the field. + */ +static void +ofmt_print_field(ofmt_state_t *os, ofmt_field_t *ofp, const char *value, + boolean_t escsep) +{ + uint_t width = ofp->of_width; + uint_t valwidth; + uint_t compress; + boolean_t parsable = os->os_parsable; + char c; + + /* + * Parsable fields are separated by ':'. If such a field contains + * a ':' or '\', this character is prefixed by a '\'. + */ + if (parsable) { + if (os->os_nfields == 1) { + (void) printf("%s", value); + return; + } + while ((c = *value++) != '\0') { + if (escsep && ((c == ':' || c == '\\'))) + (void) putchar('\\'); + (void) putchar(c); + } + if (!os->os_lastfield) + (void) putchar(':'); + return; + } else { + if (value[0] == '\0') + value = OFMT_VAL_UNDEF; + if (os->os_lastfield) { + (void) printf("%s", value); + os->os_overflow = 0; + return; + } + + valwidth = strlen(value); + if (valwidth + os->os_overflow >= width) { + os->os_overflow += valwidth - width + 1; + (void) printf("%s ", value); + return; + } + + if (os->os_overflow > 0) { + compress = MIN(os->os_overflow, width - valwidth); + os->os_overflow -= compress; + width -= compress; + } + (void) printf("%-*s", width, value); + } +} + +/* + * print one row of output values for the selected columns. + */ +void +ofmt_print(ofmt_handle_t ofmt, void *arg) +{ + ofmt_state_t *os = ofmt; + int i; + char value[1024]; + ofmt_field_t *of; + boolean_t escsep; + ofmt_arg_t ofarg; + + if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 && !os->os_parsable) { + ofmt_print_header(os); + os->os_nrow++; + } + + of = os->os_fields; + escsep = (os->os_nfields > 1); + for (i = 0; i < os->os_nfields; i++) { + os->os_lastfield = (i + 1 == os->os_nfields); + value[0] = '\0'; + ofarg.ofmt_id = of[i].of_id; + ofarg.ofmt_cbarg = arg; + if ((*of[i].of_cb)(&ofarg, value, sizeof (value))) + ofmt_print_field(os, &of[i], value, escsep); + else + ofmt_print_field(os, &of[i], OFMT_VAL_UNKNOWN, escsep); + } + (void) putchar('\n'); + (void) fflush(stdout); +} + +/* + * Print the field headers + */ +static void +ofmt_print_header(ofmt_state_t *os) +{ + int i; + ofmt_field_t *of = os->os_fields; + boolean_t escsep = (os->os_nfields > 1); + + for (i = 0; i < os->os_nfields; i++) { + os->os_lastfield = (i + 1 == os->os_nfields); + ofmt_print_field(os, &of[i], of[i].of_name, escsep); + } + (void) putchar('\n'); +} + +/* + * Update the current window size. + */ +void +ofmt_update_winsize(ofmt_handle_t ofmt) +{ + ofmt_state_t *os = ofmt; + struct winsize *winsize = &os->os_winsize; + + if (ioctl(1, TIOCGWINSZ, winsize) == -1 || + winsize->ws_col == 0 || winsize->ws_row == 0) { + winsize->ws_col = 80; + winsize->ws_row = 24; + } +} + +/* + * Return error diagnostics using the information in the ofmt_handle_t + */ +char * +ofmt_strerror(ofmt_handle_t ofmt, ofmt_status_t err, char *buf, uint_t bufsize) +{ + ofmt_state_t *os = ofmt; + int i; + const char *s; + char ebuf[OFMT_BUFSIZE]; + + /* + * ebuf is intended for optional error-specific data to be appended + * after the internationalized error string for an error code. + */ + ebuf[0] = '\0'; + + switch (err) { + case OFMT_SUCCESS: + s = "success"; + break; + case OFMT_EBADFIELDS: + /* + * Enumerate the singular/plural version of the warning + * and error to simplify and improve localization. + */ + if (!os->os_parsable) { + if (os->os_nbad > 1) + s = "ignoring unknown output fields:"; + else + s = "ignoring unknown output field:"; + } else { + if (os->os_nbad > 1) + s = "unknown output fields:"; + else + s = "unknown output field:"; + } + /* set up the bad fields in ebuf */ + for (i = 0; i < os->os_nbad; i++) { + (void) strlcat(ebuf, " `", sizeof (ebuf)); + (void) strlcat(ebuf, os->os_badfields[i], + sizeof (ebuf)); + (void) strlcat(ebuf, "'", sizeof (ebuf)); + } + break; + case OFMT_ENOFIELDS: + s = "no valid output fields"; + break; + case OFMT_EPARSEALL: + s = "output field `all' invalid in parsable mode"; + break; + case OFMT_EPARSENONE: + s = "output fields must be specified in parsable mode"; + break; + case OFMT_ENOTEMPLATE: + s = "no template provided for fields"; + break; + case OFMT_ENOMEM: + s = strerror(ENOMEM); + break; + default: + (void) snprintf(buf, bufsize, + dgettext(TEXT_DOMAIN, "unknown ofmt error (%d)"), + err); + return (buf); + } + (void) snprintf(buf, bufsize, dgettext(TEXT_DOMAIN, s)); + (void) strlcat(buf, ebuf, bufsize); + return (buf); +} diff --git a/usr/src/lib/libinetutil/common/ofmt.h b/usr/src/lib/libinetutil/common/ofmt.h new file mode 100644 index 0000000000..ff03b80ae0 --- /dev/null +++ b/usr/src/lib/libinetutil/common/ofmt.h @@ -0,0 +1,198 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _OFMT_H +#define _OFMT_H + +/* + * Data structures and routines for printing output. + * + * All output is assumed to be in a columnar format, where each column + * represents a field to be printed out. Multiple fields in parsable output + * are separated by ':', with the ':' character itself escaped by a \ + * (e.g., IPv6 addresses may be printed as "fe80\:\:1"); single field output + * is printed as-is. + * + * The caller must open a handle for each set of fields to be printed by + * invoking ofmt_open(). The invocation to ofmt_open must provide the list of + * supported fields, along with formatting information (e.g., field width), and + * a pointer to a callback function that can provide a string representation of + * the value to be printed out. The set of supported fields must be a NULL + * terminated array of type ofmt_field_t *ofields[]. The contents of the + * ofmt_field_t structure are used to construct the string that is emitted by + * ofmt_print(), and the interpretation of these contents is described with the + * semantics of ofmt_print() below. + * + * In addition, the call to ofmt_open() should provide a comma-separated + * list of the fields, char *fields_str, that have been selected for output + * (typically the string passed to -o in the command-line). The caller may + * also specify machine-parsable mode by specifying OFMT_PARSABLE in the oflags + * argument. Specifying a null or empty fields_str in the machine-parsable mode + * will result in a returned error value of OFMT_EPARSENONE. An attempt to + * create a handle in machine-parsable mode with the fields_str set to "all" + * will result in a returned error value of OFMT_EPARSEALL. In human-friendly + * (non machine-parsable) mode, a NULL fields_str, or a value of "all" for + * fields_str, is treated as a request to print all allowable fields that fit + * other applicable constraints. + * + * Thus a typical invocation to open the ofmt_handle would be: + * + * ofmt_handle_t ofmt; + * ofmt_status_t ofmt_err; + * + * ofmt_err = ofmt_open(fields_str, ofields, oflags, maxcols, &ofmt); + * + * where ofields is an array of the form: + * + * static ofmt_field_t ofields[] = { + * {<name>, <field width>, <id>, <callback> }, + * : + * {<name>, <field width>, <id>, <callback> }, + * {NULL, 0, 0, NULL}} + * + * <callback> is the application-specified function that provides a string + * representation of the value to be printed for the field. The calling + * application may provide unique values of <id> that will be passed back to + * <callback>, allowing a single <callback> to be shared between multiple + * fields in ofields[] with the value of <id> identifying the field that + * triggers the callback. + * + * If successful, ofmt_open() will return OFMT_SUCCESS, with a non-null + * ofmt_handle. The function returns a failure code otherwise, and more + * information about the type of failure can be obtained by calling + * ofmt_strerror() + * + * In order to print a row of output, the calling application should invoke + * + * ofmt_print(ofmt_handle, cbarg); + * + * where 'cbarg' points at the arguments to be passed to the <callback> + * function for each column in the row. The call to ofmt_print() will then + * result in the <callback> function of each selected field from ofields[] + * invoked with cbarg embedded in the ofmt_arg as + * + * (*callback)(ofmt_arg_t *ofmt_arg, char *buf, uint_t bufsize) + * + * Columns selected for output are identified by a match between the of_name + * value in the ofmt_field_t and the fields_str requested. For each selected + * column, the callback function (*of_cb)() is invoked, and is passed the of_id + * value from the ofmt_field_t structure for the field. + * + * The interpretation of the of_id field is completely private to the caller, + * and can be optionally used by the callback function as a cookie + * to identify the field being printed when a single callback function is + * shared between multiple ofmt_field_t entries. + * + * The callback function should fill `buf' with the string to be printed for + * the field using the data in cbarg. + * + * The calling application should invoke ofmt_close(ofmt_handle) to free up any + * resources allocated for the handle after all printing is completed. + * + * The printing library computes the current size of the output window when the + * handle is first created. If the caller wishes to adjust the window size + * after the handle has been created (e.g., on the reception of SIGWINCH by the + * caller), the function ofmt_update_winsize(handle) may be called. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Recommended buffer size for buffers passed, for example, to ofmt_strerror(). + */ +#define OFMT_BUFSIZE 256 + +typedef enum { + OFMT_SUCCESS = 0, + OFMT_ENOMEM, /* out of memory */ + OFMT_EBADFIELDS, /* one or more bad fields with good fields */ + OFMT_ENOFIELDS, /* no valid output fields */ + OFMT_EPARSEALL, /* 'all' invalid in parsable mode */ + OFMT_EPARSENONE, /* output fields missing in parsable mode */ + OFMT_ENOTEMPLATE /* no template provided for fields */ +} ofmt_status_t; + +/* + * The callback function for each field is invoked with a pointer to the + * ofmt_arg_t structure that contains the <id> registered by the application + * for that field, and the cbarg used by the application when invoking + * ofmt_output(). + */ +typedef struct ofmt_arg_s { + uint_t ofmt_id; + void *ofmt_cbarg; +} ofmt_arg_t; + +/* + * ofmt callback function that provides a string representation of the value to + * be printed for the field. + */ +typedef boolean_t ofmt_cb_t(ofmt_arg_t *, char *, uint_t); +typedef struct ofmt_field_s { + char *of_name; /* column name */ + uint_t of_width; /* output column width */ + uint_t of_id; /* implementation specific cookie */ + ofmt_cb_t *of_cb; /* callback function defined by caller */ +} ofmt_field_t; + +/* + * ofmt_open() must be called to create the ofmt_handle_t; Resources allocated + * for the handle are freed by ofmt_close(); + */ +typedef struct ofmt_state_s *ofmt_handle_t; +extern ofmt_status_t ofmt_open(const char *, ofmt_field_t *, uint_t, + uint_t, ofmt_handle_t *); + +#define OFMT_PARSABLE 0x00000001 /* machine parsable mode */ + +/* + * ofmt_close() must be called to free resources associated + * with the ofmt_handle_t + */ +extern void ofmt_close(ofmt_handle_t); + +/* + * ofmt_print() emits one row of output + */ +extern void ofmt_print(ofmt_handle_t, void *); + +/* + * ofmt_update_winsize() updates the window size information for ofmt_handle_t + */ +extern void ofmt_update_winsize(ofmt_handle_t); + +/* + * ofmt_strerror() provides error diagnostics in the buffer that it is passed. + */ +extern char *ofmt_strerror(ofmt_handle_t, ofmt_status_t, char *, uint_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _OFMT_H */ diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index a81a4443ad..7804bef6db 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -508,6 +508,7 @@ usr/lib/libinetsvc.so i386 # the shared object is shipped. # usr/include/libinetutil.h i386 +usr/include/ofmt.h i386 usr/include/netinet/inetutil.h i386 usr/lib/llib-linetutil i386 usr/lib/llib-linetutil.ln i386 diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 834b4c05b6..41261c76ff 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -511,6 +511,7 @@ usr/lib/libinetsvc.so sparc # the shared object is shipped. # usr/include/libinetutil.h sparc +usr/include/ofmt.h sparc usr/include/netinet/inetutil.h sparc usr/lib/llib-linetutil sparc usr/lib/llib-linetutil.ln sparc |
