From e96f841955c0305f457b111a667cc536d1eba3d0 Mon Sep 17 00:00:00 2001 From: Yuri Pankov Date: Wed, 31 May 2017 04:42:39 +0300 Subject: 8306 provide ofmt routines in public libofmt library and document them Reviewed by: Andy Stormont Reviewed by: Toomas Soome Reviewed by: Hans Rosenfeld Reviewed by: Jason King Reviewed by: Robert Mustacchi Approved by: Gordon Ross --- usr/src/cmd/cmd-inet/usr.sbin/ilbadm/Makefile | 2 +- usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile | 4 +- usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile | 2 +- usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile | 2 +- usr/src/cmd/dladm/Makefile | 2 +- usr/src/cmd/dlstat/Makefile | 4 +- usr/src/cmd/flowadm/Makefile | 6 +- usr/src/cmd/flowstat/Makefile | 6 +- usr/src/cmd/mandoc/lib.in | 1 + usr/src/cmd/mandoc/msec.in | 1 + usr/src/cmd/vrrpadm/Makefile | 4 +- usr/src/lib/Makefile | 4 +- usr/src/lib/libinetutil/Makefile | 12 +- usr/src/lib/libinetutil/Makefile.com | 7 +- usr/src/lib/libinetutil/common/llib-linetutil | 1 - usr/src/lib/libinetutil/common/mapfile-vers | 10 +- usr/src/lib/libinetutil/common/ofmt.c | 613 --------------------- usr/src/lib/libinetutil/common/ofmt.h | 210 -------- usr/src/lib/libofmt/Makefile | 52 ++ usr/src/lib/libofmt/Makefile.com | 37 ++ usr/src/lib/libofmt/amd64/Makefile | 19 + usr/src/lib/libofmt/common/llib-lofmt | 19 + usr/src/lib/libofmt/common/mapfile-vers | 42 ++ usr/src/lib/libofmt/common/ofmt.c | 614 ++++++++++++++++++++++ usr/src/lib/libofmt/common/ofmt.h | 210 ++++++++ usr/src/lib/libofmt/i386/Makefile | 18 + usr/src/lib/libofmt/sparc/Makefile | 18 + usr/src/lib/libofmt/sparcv9/Makefile | 19 + usr/src/man/Makefile | 1 + usr/src/man/man3ofmt/Makefile | 38 ++ usr/src/man/man3ofmt/ofmt.3ofmt | 305 +++++++++++ usr/src/pkg/manifests/developer-library-lint.mf | 3 + usr/src/pkg/manifests/system-library.man3ofmt.inc | 21 + usr/src/pkg/manifests/system-library.mf | 8 +- 34 files changed, 1452 insertions(+), 863 deletions(-) delete mode 100644 usr/src/lib/libinetutil/common/ofmt.c delete mode 100644 usr/src/lib/libinetutil/common/ofmt.h create mode 100644 usr/src/lib/libofmt/Makefile create mode 100644 usr/src/lib/libofmt/Makefile.com create mode 100644 usr/src/lib/libofmt/amd64/Makefile create mode 100644 usr/src/lib/libofmt/common/llib-lofmt create mode 100644 usr/src/lib/libofmt/common/mapfile-vers create mode 100644 usr/src/lib/libofmt/common/ofmt.c create mode 100644 usr/src/lib/libofmt/common/ofmt.h create mode 100644 usr/src/lib/libofmt/i386/Makefile create mode 100644 usr/src/lib/libofmt/sparc/Makefile create mode 100644 usr/src/lib/libofmt/sparcv9/Makefile create mode 100644 usr/src/man/man3ofmt/Makefile create mode 100644 usr/src/man/man3ofmt/ofmt.3ofmt create mode 100644 usr/src/pkg/manifests/system-library.man3ofmt.inc diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ilbadm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ilbadm/Makefile index a3afee1f15..b9307b48cc 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ilbadm/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/ilbadm/Makefile @@ -32,7 +32,7 @@ include ../../../Makefile.cmd include ../../../Makefile.ctf include ../../Makefile.cmd-inet -LDLIBS += -lcmdutils -lsocket -lnsl -lilb -linetutil -lkstat +LDLIBS += -lcmdutils -lsocket -lnsl -lilb -lkstat -lofmt CPPFLAGS += -I$(SRC)/lib/libilb/common -I$(SRC)/uts/common CERRWARN += -_gcc=-Wno-switch diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile index 57ae86b9e6..2a44c5b6aa 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipadm/Makefile @@ -27,7 +27,7 @@ PROG = ipadm ROOTFS_PROG = $(PROG) LOCALOBJS= ipadm.o -COMMONOBJS= +COMMONOBJS= OBJS= $(LOCALOBJS) $(COMMONOBJS) include ../../../Makefile.cmd @@ -41,7 +41,7 @@ SRCS= $(LOCALSRCS) $(COMMONSRCS) CPPFLAGS += -I$(CMDINETCOMMONDIR) CERRWARN += -_gcc=-Wno-unused-label CERRWARN += -_gcc=-Wno-uninitialized -LDLIBS += -linetutil -lipadm -lnvpair +LDLIBS += -lofmt -linetutil -lipadm -lnvpair LINTFLAGS += -m ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%) diff --git a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile index f070273015..a15c3fce80 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/ipmpstat/Makefile @@ -30,7 +30,7 @@ include $(SRC)/cmd/Makefile.cmd C99MODE = $(C99_ENABLE) CERRWARN += -_gcc=-Wno-uninitialized -LDLIBS += -lipmp -lsocket -lsysevent -lnvpair -linetutil +LDLIBS += -lipmp -lsocket -lsysevent -lnvpair -lofmt XGETFLAGS += -a -x $(PROG).xcl .KEEP_STATE: diff --git a/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile b/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile index 87c91b39eb..00c4998b2b 100644 --- a/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile +++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile @@ -31,7 +31,7 @@ PROG= nwamadm include ../../../Makefile.cmd XGETFLAGS += -a -x $(PROG).xcl -LDLIBS += -linetutil -lnsl -lnwam -lumem -lscf +LDLIBS += -lofmt -linetutil -lnsl -lnwam -lumem -lscf CERRWARN += -_gcc=-Wno-switch CERRWARN += -_gcc=-Wno-uninitialized diff --git a/usr/src/cmd/dladm/Makefile b/usr/src/cmd/dladm/Makefile index 43f24b484f..1eeede7152 100644 --- a/usr/src/cmd/dladm/Makefile +++ b/usr/src/cmd/dladm/Makefile @@ -38,7 +38,7 @@ include $(SRC)/cmd/Makefile.ctf XGETFLAGS += -a -x $(PROG).xcl LDLIBS += -L$(ROOT)/lib -lsocket -LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -linetutil -ldevinfo +LDLIBS += -ldladm -ldlpi -lkstat -lsecdb -lbsm -lofmt -linetutil -ldevinfo LDLIBS += $(ZLAZYLOAD) -lrstp $(ZNOLAZYLOAD) CERRWARN += -_gcc=-Wno-switch diff --git a/usr/src/cmd/dlstat/Makefile b/usr/src/cmd/dlstat/Makefile index c37982a686..c24ce1a62d 100644 --- a/usr/src/cmd/dlstat/Makefile +++ b/usr/src/cmd/dlstat/Makefile @@ -37,11 +37,11 @@ CERRWARN += -_gcc=-Wno-uninitialized XGETFLAGS += -a -x $(PROG).xcl LDLIBS += -L$(ROOT)/lib -LDLIBS += -ldladm -linetutil +LDLIBS += -ldladm -lofmt .KEEP_STATE: -all: $(ROOTFS_PROG) +all: $(ROOTFS_PROG) install: all $(ROOTSBINPROG) $(RM) $(ROOTUSRSBINPROG) diff --git a/usr/src/cmd/flowadm/Makefile b/usr/src/cmd/flowadm/Makefile index 19a15a1b47..24362b698a 100644 --- a/usr/src/cmd/flowadm/Makefile +++ b/usr/src/cmd/flowadm/Makefile @@ -23,7 +23,7 @@ # Use is subject to license terms. # -PROG=flowadm +PROG=flowadm ROOTFS_PROG= $(PROG) @@ -34,7 +34,7 @@ include ../Makefile.cmd XGETFLAGS += -a -x $(PROG).xcl LDLIBS += -L$(ROOT)/lib -LDLIBS += -ldladm -linetutil +LDLIBS += -ldladm -lofmt ROOTCFGDIR= $(ROOTETC)/dladm ROOTCFGFILES= $(CONFIGFILES:%=$(ROOTCFGDIR)/%) @@ -43,7 +43,7 @@ $(ROOTCFGFILES):= FILEMODE= 644 .KEEP_STATE: -all: $(ROOTFS_PROG) +all: $(ROOTFS_PROG) # # Message catalog diff --git a/usr/src/cmd/flowstat/Makefile b/usr/src/cmd/flowstat/Makefile index 7e0ee8bfb2..e9efa364e0 100644 --- a/usr/src/cmd/flowstat/Makefile +++ b/usr/src/cmd/flowstat/Makefile @@ -23,7 +23,7 @@ # Use is subject to license terms. # -PROG=flowstat +PROG=flowstat ROOTFS_PROG= $(PROG) @@ -33,7 +33,7 @@ include ../Makefile.cmd XGETFLAGS += -a -x $(PROG).xcl LDLIBS += -L$(ROOT)/lib -LDLIBS += -ldladm -linetutil +LDLIBS += -ldladm -lofmt CERRWARN += -_gcc=-Wno-implicit-function-declaration CERRWARN += -_gcc=-Wno-uninitialized @@ -42,7 +42,7 @@ ROOTCFGDIR= $(ROOTETC)/dladm .KEEP_STATE: -all: $(ROOTFS_PROG) +all: $(ROOTFS_PROG) # # Message catalog diff --git a/usr/src/cmd/mandoc/lib.in b/usr/src/cmd/mandoc/lib.in index b083172c2d..79f249fb5f 100644 --- a/usr/src/cmd/mandoc/lib.in +++ b/usr/src/cmd/mandoc/lib.in @@ -53,6 +53,7 @@ LINE("libmp", "Multiple Precision Library (libmp, -lmp)") LINE("libmpapi", "Common Multipath Management Library (libmpapi, -lMPAPI)") LINE("libnsl", "Network Services Library (libnsl, \\-lnsl)") LINE("libnvpair", "Name-Value Pair Library (libnvpair, \\-lnvpair)") +LINE("libofmt", "Formatted output library (libofmt, \\-lofmt)") LINE("libpam", "PAM (Pluggable Authentication Module) Library (libpam, \\-lpam)") LINE("libpicl", "PICL Library (libpicl, \\-lpicl)") LINE("libpicltree", "PICL Plug-In Library (libpicltree, \\-lpicltree)") diff --git a/usr/src/cmd/mandoc/msec.in b/usr/src/cmd/mandoc/msec.in index c47dff6112..10861ddd07 100644 --- a/usr/src/cmd/mandoc/msec.in +++ b/usr/src/cmd/mandoc/msec.in @@ -62,6 +62,7 @@ LINE("3MP", "Multiple Precision Library Functions") LINE("3MPAPI", "Common Multipath Management Library Functions") LINE("3NSL", "Networking Services Library Functions") LINE("3NVPAIR", "Name-value Pair Library Functions") +LINE("3OFMT", "Formatted Output Functions") LINE("3PAM", "PAM Library Functions") LINE("3PAPI", "PAPI Library Functions") LINE("3PERL", "Perl Library Functions") diff --git a/usr/src/cmd/vrrpadm/Makefile b/usr/src/cmd/vrrpadm/Makefile index c63a09589d..61167ab1cb 100644 --- a/usr/src/cmd/vrrpadm/Makefile +++ b/usr/src/cmd/vrrpadm/Makefile @@ -28,13 +28,13 @@ PROG= vrrpadm include ../Makefile.cmd XGETFLAGS += -a -x $(PROG).xcl -LDLIBS += -lvrrpadm -lnsl -linetutil +LDLIBS += -lvrrpadm -lnsl -lofmt CERRWARN += -_gcc=-Wno-unused-label .KEEP_STATE: -all: $(PROG) +all: $(PROG) install: all $(ROOTUSRSBINPROG) diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index 05de71f42d..36367793ac 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -168,6 +168,7 @@ SUBDIRS += \ libnls \ libnsctl \ libnwam \ + libofmt \ libpam \ libpcidb \ libpctx \ @@ -316,7 +317,6 @@ MSGSUBDIRS= \ libgss \ libidmap \ libilb \ - libinetutil \ libinstzones \ libipadm \ libipmp \ @@ -324,6 +324,7 @@ MSGSUBDIRS= \ libldap5 \ libnsl \ libnwam \ + libofmt \ libpam \ libpicl \ libpkg \ @@ -427,6 +428,7 @@ HDRSUBDIRS= \ libnsl \ libnvpair \ libnwam \ + libofmt \ libpam \ libpcidb \ libpctx \ diff --git a/usr/src/lib/libinetutil/Makefile b/usr/src/lib/libinetutil/Makefile index 0bc13a5c87..1d1ed69ccd 100644 --- a/usr/src/lib/libinetutil/Makefile +++ b/usr/src/lib/libinetutil/Makefile @@ -26,15 +26,11 @@ include ../Makefile.lib -HDRS = libinetutil.h ofmt.h +HDRS = libinetutil.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 @@ -49,15 +45,9 @@ 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 e866d1c434..d22ab84726 100644 --- a/usr/src/lib/libinetutil/Makefile.com +++ b/usr/src/lib/libinetutil/Makefile.com @@ -25,8 +25,7 @@ LIBRARY = libinetutil.a VERS = .1 -OBJECTS = octet.o inetutil.o ifspec.o ifaddrlist.o ifaddrlistx.o eh.o tq.o \ - ofmt.o +OBJECTS = octet.o inetutil.o ifspec.o ifaddrlist.o ifaddrlistx.o eh.o tq.o include ../../Makefile.lib @@ -39,8 +38,7 @@ 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)/ofmt.c + $(SRCDIR)/ifaddrlist.c $(SRCDIR)/ifaddrlistx.c $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) LDLIBS += -lsocket -lc @@ -48,7 +46,6 @@ LDLIBS += -lsocket -lc CFLAGS += $(CCVERBOSE) CPPFLAGS += -I$(SRCDIR) -CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-parentheses .KEEP_STATE: diff --git a/usr/src/lib/libinetutil/common/llib-linetutil b/usr/src/lib/libinetutil/common/llib-linetutil index 9dd868fa9f..03504ac752 100644 --- a/usr/src/lib/libinetutil/common/llib-linetutil +++ b/usr/src/lib/libinetutil/common/llib-linetutil @@ -27,4 +27,3 @@ /* PROTOLIB1 */ #include -#include diff --git a/usr/src/lib/libinetutil/common/mapfile-vers b/usr/src/lib/libinetutil/common/mapfile-vers index f47657c56e..a26d988990 100644 --- a/usr/src/lib/libinetutil/common/mapfile-vers +++ b/usr/src/lib/libinetutil/common/mapfile-vers @@ -63,11 +63,11 @@ SYMBOL_VERSION SUNWprivate_1.1 { iu_tq_destroy; iu_unregister_event; octet_to_hexascii; - ofmt_open; - ofmt_close; - ofmt_print; - ofmt_update_winsize; - ofmt_strerror; + ofmt_open { TYPE = FUNCTION; FILTER = libofmt.so.1 }; + ofmt_close { TYPE = FUNCTION; FILTER = libofmt.so.1 }; + ofmt_print { TYPE = FUNCTION; FILTER = libofmt.so.1 }; + ofmt_update_winsize { TYPE = FUNCTION; FILTER = libofmt.so.1 }; + ofmt_strerror { TYPE = FUNCTION; FILTER = libofmt.so.1 }; mask2plen; plen2mask; sockaddrcmp; diff --git a/usr/src/lib/libinetutil/common/ofmt.c b/usr/src/lib/libinetutil/common/ofmt.c deleted file mode 100644 index 63d744cdc9..0000000000 --- a/usr/src/lib/libinetutil/common/ofmt.c +++ /dev/null @@ -1,613 +0,0 @@ -/* - * 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 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * 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 */ - uint_t s_currfield; /* the current field being processed */ -} 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; - uint_t os_flags; - int os_nbad; - char **os_badfields; - int os_maxnamelen; /* longest name (f. multiline) */ -} 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 "?" - -/* - * The maximum number of rows supported by the OFMT_WRAP option. - */ -#define OFMT_MAX_ROWS 128 - -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, const ofmt_field_t *template, uint_t flags, - uint_t maxcols, ofmt_handle_t *ofmt) -{ - split_t *sp; - uint_t i, j, of_index; - const ofmt_field_t *ofp; - ofmt_field_t *of; - ofmt_state_t *os; - int nfields = 0; - ofmt_status_t err = OFMT_SUCCESS; - boolean_t parsable = (flags & OFMT_PARSABLE); - boolean_t wrap = (flags & OFMT_WRAP); - boolean_t multiline = (flags & OFMT_MULTILINE); - - *ofmt = NULL; - if (parsable) { - if (multiline) - return (OFMT_EPARSEMULTI); - /* - * 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 (strcasecmp(str, "all") == 0) - return (OFMT_EPARSEALL); - if (wrap) - return (OFMT_EPARSEWRAP); - } - if (template == NULL) - return (OFMT_ENOTEMPLATE); - for (ofp = template; ofp->of_name != NULL; ofp++) - nfields++; - /* - * split str into the columns selected, or construct the - * full set of columns (equivalent to -o all). - */ - if (str != NULL && strcasecmp(str, "all") != 0) { - sp = split_str(str, nfields); - } else { - if (parsable || (str != NULL && strcasecmp(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_flags = flags; - - 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; - if (multiline) { - int n = strlen(of[of_index].of_name); - - os->os_maxnamelen = MAX(n, os->os_maxnamelen); - } - 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_flags & OFMT_PARSABLE); - boolean_t multiline = (os->os_flags & OFMT_MULTILINE); - boolean_t rightjust = (os->os_flags & OFMT_RIGHTJUST); - 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(':'); - } else if (multiline) { - if (value[0] == '\0') - value = OFMT_VAL_UNDEF; - (void) printf("%*.*s: %s", os->os_maxnamelen, - os->os_maxnamelen, ofp->of_name, value); - if (!os->os_lastfield) - (void) putchar('\n'); - } else { - if (os->os_lastfield) { - if (rightjust) - (void) printf("%*s", width, value); - else - (void) printf("%s", value); - os->os_overflow = 0; - return; - } - - valwidth = strlen(value); - if (valwidth + os->os_overflow >= width) { - os->os_overflow += valwidth - width + 1; - if (rightjust) - (void) printf("%*s ", width, value); - else - (void) printf("%s ", value); - return; - } - - if (os->os_overflow > 0) { - compress = MIN(os->os_overflow, width - valwidth); - os->os_overflow -= compress; - width -= compress; - } - if (rightjust) - (void) printf("%*s ", width, value); - else - (void) printf("%-*s", width, value); - } -} - -/* - * Print enough to fit the field width. - */ -static void -ofmt_fit_width(split_t **spp, uint_t width, char *value, uint_t bufsize) -{ - split_t *sp = *spp; - char *ptr = value, *lim = ptr + bufsize; - int i, nextlen; - - if (sp == NULL) { - sp = split_str(value, OFMT_MAX_ROWS); - if (sp == NULL) - return; - - *spp = sp; - } - for (i = sp->s_currfield; i < sp->s_nfields; i++) { - ptr += snprintf(ptr, lim - ptr, "%s,", sp->s_fields[i]); - if (i + 1 == sp->s_nfields) { - nextlen = 0; - if (ptr > value) - ptr[-1] = '\0'; - } else { - nextlen = strlen(sp->s_fields[i + 1]); - } - - if (strlen(value) + nextlen > width || ptr >= lim) { - i++; - break; - } - } - sp->s_currfield = i; -} - -/* - * Print one or more rows 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, more_rows; - ofmt_arg_t ofarg; - split_t **sp = NULL; - boolean_t parsable = (os->os_flags & OFMT_PARSABLE); - boolean_t multiline = (os->os_flags & OFMT_MULTILINE); - boolean_t wrap = (os->os_flags & OFMT_WRAP); - - if (wrap) { - sp = calloc(sizeof (split_t *), os->os_nfields); - if (sp == NULL) - return; - } - - if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 && - !parsable && !multiline) { - ofmt_print_header(os); - os->os_nrow++; - } - - if (multiline && os->os_nrow > 1) - (void) putchar('\n'); - - of = os->os_fields; - escsep = (os->os_nfields > 1); - more_rows = B_FALSE; - 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))) { - if (wrap) { - /* - * 'value' will be split at comma boundaries - * and stored into sp[i]. - */ - ofmt_fit_width(&sp[i], of[i].of_width, value, - sizeof (value)); - if (sp[i] != NULL && - sp[i]->s_currfield < sp[i]->s_nfields) - more_rows = B_TRUE; - } - - ofmt_print_field(os, &of[i], - (*value == '\0' && !parsable) ? - OFMT_VAL_UNDEF : value, escsep); - } else { - ofmt_print_field(os, &of[i], OFMT_VAL_UNKNOWN, escsep); - } - } - (void) putchar('\n'); - - while (more_rows) { - more_rows = B_FALSE; - for (i = 0; i < os->os_nfields; i++) { - os->os_lastfield = (i + 1 == os->os_nfields); - value[0] = '\0'; - - ofmt_fit_width(&sp[i], of[i].of_width, - value, sizeof (value)); - if (sp[i] != NULL && - sp[i]->s_currfield < sp[i]->s_nfields) - more_rows = B_TRUE; - - ofmt_print_field(os, &of[i], value, escsep); - } - (void) putchar('\n'); - } - (void) fflush(stdout); - - if (sp != NULL) { - for (i = 0; i < os->os_nfields; i++) - splitfree(sp[i]); - free(sp); - } -} - -/* - * 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]; - boolean_t parsable; - - /* - * 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. - */ - parsable = (os->os_flags & OFMT_PARSABLE); - if (!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_EPARSEMULTI: - s = "multiline mode incompatible with parsable mode"; - 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_EPARSEWRAP: - s = "parsable mode is incompatible with wrap 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 deleted file mode 100644 index e69d43e20a..0000000000 --- a/usr/src/lib/libinetutil/common/ofmt.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * 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 2010 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. - * In multiline mode, every [field,value] pair is printed in a line of - * its own, thus: "field: value". - * - * 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. - * To achieve multiline mode, OFMT_MULTILINE needs to be specified in oflags. - * Specifying both OFMT_MULTILINE and OFMT_PARSABLE will result in - * OFMT_EPARSEMULTI. - * - * 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[] = { - * {, , , }, - * : - * {, , , }, - * {NULL, 0, 0, NULL}} - * - * 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 that will be passed back to - * , allowing a single to be shared between multiple - * fields in ofields[] with the value of 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 - * function for each column in the row. The call to ofmt_print() will then - * result in the 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_EPARSEWRAP, /* parsable mode incompatible with wrap mode */ - OFMT_ENOTEMPLATE, /* no template provided for fields */ - OFMT_EPARSEMULTI /* parsable and multiline don't mix */ -} ofmt_status_t; - -/* - * The callback function for each field is invoked with a pointer to the - * ofmt_arg_t structure that contains the 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; - uint_t ofmt_width; - uint_t ofmt_index; - 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 *, const ofmt_field_t *, uint_t, - uint_t, ofmt_handle_t *); - -#define OFMT_PARSABLE 0x00000001 /* machine parsable mode */ -#define OFMT_WRAP 0x00000002 /* wrap output if field width is exceeded */ -#define OFMT_MULTILINE 0x00000004 /* "long" output: "name: value" lines */ -#define OFMT_RIGHTJUST 0x00000008 /* right justified output */ - -/* - * 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/lib/libofmt/Makefile b/usr/src/lib/libofmt/Makefile new file mode 100644 index 0000000000..21bb7cdea8 --- /dev/null +++ b/usr/src/lib/libofmt/Makefile @@ -0,0 +1,52 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include $(SRC)/lib/Makefile.lib + +SUBDIRS= $(MACH) $(BUILD64) $(MACH64) + +HDRS= ofmt.h +HDRDIR= common + +POFILE= libofmt.po +MSGFILES= common/ofmt.c +XGETFLAGS= -a + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(POFILE): $(MSGFILES) + $(BUILDPO.msgfiles) + +_msg: $(MSGDOMAINPOFILE) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include $(SRC)/Makefile.msg.targ +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libofmt/Makefile.com b/usr/src/lib/libofmt/Makefile.com new file mode 100644 index 0000000000..1d27b92411 --- /dev/null +++ b/usr/src/lib/libofmt/Makefile.com @@ -0,0 +1,37 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +LIBRARY= libofmt.a +VERS= .1 + +OBJECTS= ofmt.o + +include $(SRC)/lib/Makefile.lib +include $(SRC)/lib/Makefile.rootfs + +SRCDIR= ../common + +LIBS= $(DYNLIB) $(LINTLIB) +SRCS= $(SRCDIR)/ofmt.c + +LDLIBS += -lc + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include $(SRC)/lib/Makefile.targ diff --git a/usr/src/lib/libofmt/amd64/Makefile b/usr/src/lib/libofmt/amd64/Makefile new file mode 100644 index 0000000000..ea4e1ac4f2 --- /dev/null +++ b/usr/src/lib/libofmt/amd64/Makefile @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libofmt/common/llib-lofmt b/usr/src/lib/libofmt/common/llib-lofmt new file mode 100644 index 0000000000..3abbb9f946 --- /dev/null +++ b/usr/src/lib/libofmt/common/llib-lofmt @@ -0,0 +1,19 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Nexenta Systems, Inc. + */ + +/* LINTLIBRARY */ +/* PROTOLIB1 */ + +#include diff --git a/usr/src/lib/libofmt/common/mapfile-vers b/usr/src/lib/libofmt/common/mapfile-vers new file mode 100644 index 0000000000..b2a87b3ecc --- /dev/null +++ b/usr/src/lib/libofmt/common/mapfile-vers @@ -0,0 +1,42 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +# +# MAPFILE HEADER START +# +# WARNING: STOP NOW. DO NOT MODIFY THIS FILE. +# Object versioning must comply with the rules detailed in +# +# usr/src/lib/README.mapfiles +# +# You should not be making modifications here until you've read the most current +# copy of that file. If you need help, contact a gatekeeper for guidance. +# +# MAPFILE HEADER END +# + +$mapfile_version 2 + +SYMBOL_VERSION ILLUMOSprivate { + global: + ofmt_close; + ofmt_open; + ofmt_print; + ofmt_strerror; + ofmt_update_winsize; + + local: + *; +}; diff --git a/usr/src/lib/libofmt/common/ofmt.c b/usr/src/lib/libofmt/common/ofmt.c new file mode 100644 index 0000000000..bab3da7311 --- /dev/null +++ b/usr/src/lib/libofmt/common/ofmt.c @@ -0,0 +1,614 @@ +/* + * 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 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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 */ + uint_t s_currfield; /* the current field being processed */ +} 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; + uint_t os_flags; + int os_nbad; + char **os_badfields; + int os_maxnamelen; /* longest name (f. multiline) */ +} 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 "?" + +/* + * The maximum number of rows supported by the OFMT_WRAP option. + */ +#define OFMT_MAX_ROWS 128 + +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, const ofmt_field_t *template, uint_t flags, + uint_t maxcols, ofmt_handle_t *ofmt) +{ + split_t *sp; + uint_t i, j, of_index; + const ofmt_field_t *ofp; + ofmt_field_t *of; + ofmt_state_t *os = NULL; + int nfields = 0; + ofmt_status_t error = OFMT_SUCCESS; + boolean_t parsable = (flags & OFMT_PARSABLE); + boolean_t wrap = (flags & OFMT_WRAP); + boolean_t multiline = (flags & OFMT_MULTILINE); + + *ofmt = NULL; + if (parsable) { + if (multiline) + return (OFMT_EPARSEMULTI); + /* + * 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 (strcasecmp(str, "all") == 0) + return (OFMT_EPARSEALL); + if (wrap) + return (OFMT_EPARSEWRAP); + } + if (template == NULL) + return (OFMT_ENOTEMPLATE); + for (ofp = template; ofp->of_name != NULL; ofp++) + nfields++; + /* + * split str into the columns selected, or construct the + * full set of columns (equivalent to -o all). + */ + if (str != NULL && strcasecmp(str, "all") != 0) { + sp = split_str(str, nfields); + } else { + if (parsable || (str != NULL && strcasecmp(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_flags = flags; + + 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++; + + error = 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; + if (multiline) { + int n = strlen(of[of_index].of_name); + + os->os_maxnamelen = MAX(n, os->os_maxnamelen); + } + 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 (error); +nomem: + error = OFMT_ENOMEM; + if (os != NULL) + ofmt_close(os); + *ofmt = NULL; + splitfree(sp); + return (error); +} + +/* + * 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_flags & OFMT_PARSABLE); + boolean_t multiline = (os->os_flags & OFMT_MULTILINE); + boolean_t rightjust = (os->os_flags & OFMT_RIGHTJUST); + 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(':'); + } else if (multiline) { + if (value[0] == '\0') + value = OFMT_VAL_UNDEF; + (void) printf("%*.*s: %s", os->os_maxnamelen, + os->os_maxnamelen, ofp->of_name, value); + if (!os->os_lastfield) + (void) putchar('\n'); + } else { + if (os->os_lastfield) { + if (rightjust) + (void) printf("%*s", width, value); + else + (void) printf("%s", value); + os->os_overflow = 0; + return; + } + + valwidth = strlen(value); + if (valwidth + os->os_overflow >= width) { + os->os_overflow += valwidth - width + 1; + if (rightjust) + (void) printf("%*s ", width, value); + else + (void) printf("%s ", value); + return; + } + + if (os->os_overflow > 0) { + compress = MIN(os->os_overflow, width - valwidth); + os->os_overflow -= compress; + width -= compress; + } + if (rightjust) + (void) printf("%*s ", width, value); + else + (void) printf("%-*s", width, value); + } +} + +/* + * Print enough to fit the field width. + */ +static void +ofmt_fit_width(split_t **spp, uint_t width, char *value, uint_t bufsize) +{ + split_t *sp = *spp; + char *ptr = value, *lim = ptr + bufsize; + int i, nextlen; + + if (sp == NULL) { + sp = split_str(value, OFMT_MAX_ROWS); + if (sp == NULL) + return; + + *spp = sp; + } + for (i = sp->s_currfield; i < sp->s_nfields; i++) { + ptr += snprintf(ptr, lim - ptr, "%s,", sp->s_fields[i]); + if (i + 1 == sp->s_nfields) { + nextlen = 0; + if (ptr > value) + ptr[-1] = '\0'; + } else { + nextlen = strlen(sp->s_fields[i + 1]); + } + + if (strlen(value) + nextlen > width || ptr >= lim) { + i++; + break; + } + } + sp->s_currfield = i; +} + +/* + * Print one or more rows 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, more_rows; + ofmt_arg_t ofarg; + split_t **sp = NULL; + boolean_t parsable = (os->os_flags & OFMT_PARSABLE); + boolean_t multiline = (os->os_flags & OFMT_MULTILINE); + boolean_t wrap = (os->os_flags & OFMT_WRAP); + + if (wrap) { + sp = calloc(sizeof (split_t *), os->os_nfields); + if (sp == NULL) + return; + } + + if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 && + !parsable && !multiline) { + ofmt_print_header(os); + os->os_nrow++; + } + + if (multiline && os->os_nrow > 1) + (void) putchar('\n'); + + of = os->os_fields; + escsep = (os->os_nfields > 1); + more_rows = B_FALSE; + 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))) { + if (wrap) { + /* + * 'value' will be split at comma boundaries + * and stored into sp[i]. + */ + ofmt_fit_width(&sp[i], of[i].of_width, value, + sizeof (value)); + if (sp[i] != NULL && + sp[i]->s_currfield < sp[i]->s_nfields) + more_rows = B_TRUE; + } + + ofmt_print_field(os, &of[i], + (*value == '\0' && !parsable) ? + OFMT_VAL_UNDEF : value, escsep); + } else { + ofmt_print_field(os, &of[i], OFMT_VAL_UNKNOWN, escsep); + } + } + (void) putchar('\n'); + + while (more_rows) { + more_rows = B_FALSE; + for (i = 0; i < os->os_nfields; i++) { + os->os_lastfield = (i + 1 == os->os_nfields); + value[0] = '\0'; + + ofmt_fit_width(&sp[i], of[i].of_width, + value, sizeof (value)); + if (sp[i] != NULL && + sp[i]->s_currfield < sp[i]->s_nfields) + more_rows = B_TRUE; + + ofmt_print_field(os, &of[i], value, escsep); + } + (void) putchar('\n'); + } + (void) fflush(stdout); + + if (sp != NULL) { + for (i = 0; i < os->os_nfields; i++) + splitfree(sp[i]); + free(sp); + } +} + +/* + * 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 error, char *buf, + uint_t bufsize) +{ + ofmt_state_t *os = ofmt; + int i; + const char *s; + char ebuf[OFMT_BUFSIZE]; + boolean_t parsable; + + /* + * ebuf is intended for optional error-specific data to be appended + * after the internationalized error string for an error code. + */ + ebuf[0] = '\0'; + + switch (error) { + case OFMT_SUCCESS: + s = "success"; + break; + case OFMT_EBADFIELDS: + /* + * Enumerate the singular/plural version of the warning + * and error to simplify and improve localization. + */ + parsable = (os->os_flags & OFMT_PARSABLE); + if (!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_EPARSEMULTI: + s = "multiline mode incompatible with parsable mode"; + 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_EPARSEWRAP: + s = "parsable mode is incompatible with wrap 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)"), + error); + return (buf); + } + (void) snprintf(buf, bufsize, dgettext(TEXT_DOMAIN, s)); + (void) strlcat(buf, ebuf, bufsize); + return (buf); +} diff --git a/usr/src/lib/libofmt/common/ofmt.h b/usr/src/lib/libofmt/common/ofmt.h new file mode 100644 index 0000000000..e69d43e20a --- /dev/null +++ b/usr/src/lib/libofmt/common/ofmt.h @@ -0,0 +1,210 @@ +/* + * 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 2010 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. + * In multiline mode, every [field,value] pair is printed in a line of + * its own, thus: "field: value". + * + * 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. + * To achieve multiline mode, OFMT_MULTILINE needs to be specified in oflags. + * Specifying both OFMT_MULTILINE and OFMT_PARSABLE will result in + * OFMT_EPARSEMULTI. + * + * 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[] = { + * {, , , }, + * : + * {, , , }, + * {NULL, 0, 0, NULL}} + * + * 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 that will be passed back to + * , allowing a single to be shared between multiple + * fields in ofields[] with the value of 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 + * function for each column in the row. The call to ofmt_print() will then + * result in the 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_EPARSEWRAP, /* parsable mode incompatible with wrap mode */ + OFMT_ENOTEMPLATE, /* no template provided for fields */ + OFMT_EPARSEMULTI /* parsable and multiline don't mix */ +} ofmt_status_t; + +/* + * The callback function for each field is invoked with a pointer to the + * ofmt_arg_t structure that contains the 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; + uint_t ofmt_width; + uint_t ofmt_index; + 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 *, const ofmt_field_t *, uint_t, + uint_t, ofmt_handle_t *); + +#define OFMT_PARSABLE 0x00000001 /* machine parsable mode */ +#define OFMT_WRAP 0x00000002 /* wrap output if field width is exceeded */ +#define OFMT_MULTILINE 0x00000004 /* "long" output: "name: value" lines */ +#define OFMT_RIGHTJUST 0x00000008 /* right justified output */ + +/* + * 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/lib/libofmt/i386/Makefile b/usr/src/lib/libofmt/i386/Makefile new file mode 100644 index 0000000000..d00779a2ee --- /dev/null +++ b/usr/src/lib/libofmt/i386/Makefile @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libofmt/sparc/Makefile b/usr/src/lib/libofmt/sparc/Makefile new file mode 100644 index 0000000000..d00779a2ee --- /dev/null +++ b/usr/src/lib/libofmt/sparc/Makefile @@ -0,0 +1,18 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libofmt/sparcv9/Makefile b/usr/src/lib/libofmt/sparcv9/Makefile new file mode 100644 index 0000000000..ea4e1ac4f2 --- /dev/null +++ b/usr/src/lib/libofmt/sparcv9/Makefile @@ -0,0 +1,19 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include ../Makefile.com +include $(SRC)/lib/Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/man/Makefile b/usr/src/man/Makefile index 74d27fb221..7bfd356b32 100644 --- a/usr/src/man/Makefile +++ b/usr/src/man/Makefile @@ -60,6 +60,7 @@ SUBDIRS= man1 \ man3nsl \ man3nvpair \ man3pam \ + man3ofmt \ man3papi \ man3perl \ man3picl \ diff --git a/usr/src/man/man3ofmt/Makefile b/usr/src/man/man3ofmt/Makefile new file mode 100644 index 0000000000..b89d88fb35 --- /dev/null +++ b/usr/src/man/man3ofmt/Makefile @@ -0,0 +1,38 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet +# at http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +include $(SRC)/Makefile.master + +MANSECT= 3ofmt + +MANFILES= ofmt.3ofmt + +MANLINKS= ofmt_close.3ofmt \ + ofmt_open.3ofmt \ + ofmt_print.3ofmt \ + ofmt_strerror.3ofmt \ + ofmt_update_winsize.3ofmt + +ofmt_close.3ofmt := LINKSRC = ofmt.3ofmt +ofmt_open.3ofmt := LINKSRC = ofmt.3ofmt +ofmt_print.3ofmt := LINKSRC = ofmt.3ofmt +ofmt_strerror.3ofmt := LINKSRC = ofmt.3ofmt +ofmt_update_winsize.3ofmt := LINKSRC = ofmt.3ofmt + +.KEEP_STATE: + +include $(SRC)/man/Makefile.man + +install: $(ROOTMANFILES) $(ROOTMANLINKS) diff --git a/usr/src/man/man3ofmt/ofmt.3ofmt b/usr/src/man/man3ofmt/ofmt.3ofmt new file mode 100644 index 0000000000..99b431f014 --- /dev/null +++ b/usr/src/man/man3ofmt/ofmt.3ofmt @@ -0,0 +1,305 @@ +.\" +.\" This file and its contents are supplied under the terms of the +.\" Common Development and Distribution License ("CDDL"), version 1.0. +.\" You may only use this file in accordance with the terms of version +.\" 1.0 of the CDDL. +.\" +.\" A full copy of the text of the CDDL should have accompanied this +.\" source. A copy of the CDDL is also available via the Internet at +.\" http://www.illumos.org/license/CDDL. +.\" +.\" +.\" Copyright 2010 Sun Microsystems, Inc. All rights reserved. +.\" Copyright 2017 Nexenta Systems, Inc. +.\" +.Dd June 1, 2017 +.Dt OFMT 3OFMT +.Os +.Sh NAME +.Nm ofmt_open , +.Nm ofmt_print , +.Nm ofmt_update_winsize , +.Nm ofmt_strerror , +.Nm ofmt_close +.Nd data structures and routines for printing output +.Sh LIBRARY +.Lb libofmt +.Sh SYNOPSIS +.In ofmt.h +.Ft ofmt_status_t +.Fo ofmt_open +.Fa "const char *fields" +.Fa "const ofmt_field_t *template" +.Fa "uint_t flags" +.Fa "uint_t maxcols" +.Fa "ofmt_handle_t *ofmt" +.Fc +.Ft void +.Fo ofmt_print +.Fa "ofmt_handle_t ofmt" +.Fa "void *cbarg" +.Fc +.Ft void +.Fo ofmt_update_winsize +.Fa "ofmt_handle_t ofmt" +.Fc +.Ft "char *" +.Fo ofmt_strerror +.Fa "ofmt_handle_t ofmt" +.Fa "ofmt_status_t error" +.Fa "char *buf" +.Fa "uint_t bufsize" +.Fc +.Ft void +.Fo ofmt_close +.Fa "ofmt_handle_t ofmt" +.Fc +.Sh DESCRIPTION +The +.Nm libofmt +library provides data structures and routines for printing output. +.Pp +Currently this is an internal interface. +The interface can and will change without notice as the project needs, at any +time. +.Pp +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 +.Sq \&: , +with the +.Sq \&: +character itself escaped by a +.Sq \e +.Po e.g., IPv6 addresses may be printed as +.Qq fe80\e:\e:1 +.Pc ; +single field output is printed as-is. +In multiline mode, every +.Bq field,value +pair is printed in a line of its own, thus: +.Qq field: value . +.Ss Data Structures +The +.Vt ofmt_field_t +data structure used in +.Sx ofmt_open +is defined as follows: +.Bd -literal +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; +.Ed +.Pp +The +.Vt ofmt_arg_t +data structure which is passed to callback function is defined as follows: +.Bd -literal +typedef struct ofmt_arg_s { + uint_t ofmt_id; /* implementation specific cookie */ + uint_t ofmt_width; /* output column width */ + uint_t ofmt_index; /* unused */ + void *ofmt_cbarg; /* argument passed to ofmt_print() */ +} ofmt_arg_t; +.Ed +.Ss Fn ofmt_open +The +.Fn ofmt_open +function opens a handle returned in +.Fa ofmt +for each set of fields to be printed. +.Pp +.Fa fields +is a comma-separated list of the fields that have been selected for output +.Po typically the string passed to +.Fl o +in the command-line +.Pc . +Columns selected for output are identified by a match between the +.Va of_name +value in the +.Fa template +and the +.Fa fields +requested. +In human-friendly +.Pq non machine-parsable +mode, +.Dv NULL +.Fa fields , +or a value of +.Qq all +is treated as a request to print all allowable fields that fit other applicable +constraints. +.Pp +.Fa template +specifies the list of supported fields, along with formatting information +.Pq 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 +.Dv NULL +terminated array of type +.Vt ofmt_field_t , +described in +.Sx Data Structures , +as follows: +.Bd -literal -offset indent +{, , , }, +\&.\&.\&. +{, , , }, +{NULL, 0, 0, NULL} +.Ed +.Pp +.Va of_cb +is the application-specified callback function with the following prototype that +provides a string representation of the value to be printed for the field: +.Bd -literal -offset indent +(*of_cb)(ofmt_arg_t *ofmt_arg, char *buf, uint_t bufsize) +.Ed +.Pp +The interpretation of the +.Va 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 +.Fa template +entries. +.Pp +The +.Fa flags +can be any valid combination of the following: +.Pp +.Bl -tag -width "OFMT_MULTILINE" -compact +.It Dv OFMT_PARSABLE +Machine-parsable mode. +Specifying a null or empty +.Va fields +in the machine-parsable mode will result in a returned error value of +.Dv OFMT_EPARSENONE . +An attempt to create a handle in machine-parsable mode with the +.Fa fields +set to +.Qq all +will result in a returned error value of +.Dv OFMT_EPARSEALL . +.It Dv OFMT_WRAP +Wrap output if field width is exceeded. +Currently output is wrapped at whitespace or comma characters. +.It Dv OFMT_MULTILINE +Multiline mode. +Specifying both +.Dv OFMT_MULTILINE +and +.Dv OFMT_PARSABLE +will result in +.Dv OFMT_EPARSEMULTI . +.It Dv OFMT_RIGHTJUST +Right justified output. +.El +.Pp +The non-zero +.Fa maxcols +limits the number of output columns. +.Ss Fn ofmt_print +The +.Fn ofmt_print +function prints a row of output. +.Pp +.Fa cbarg +points at the arguments to be passed to the callback function for each column in +the row. +The call to +.Fn ofmt_print +will result in the callback function of each selected field invoked with +.Va of_id , +.Va of_width +and +.Fa cbarg +embedded in +.Fa ofmt_arg , +described in +.Sx Data Structures . +.Pp +The callback function should fill +.Fa buf +with the string to be printed for the field using the data in +.Fa cbarg . +.Ss Fn ofmt_update_winsize +The +.Fn ofmt_update_winsize +function updates the window size information +.Pq which is initially computed when the handle is created +in the +.Fa ofmt . +If the +.Dv TIOCGWINSZ +ioctl fails, the window size is set to 80x24. +.Ss Fn ofmt_strerror +The +.Fn ofmt_strerror +function returns error diagnostics in +.Fa buf +using the information in the +.Fa ofmt +and +.Fa error . +.Pp +Using a +.Fa buf +size of +.Dv OFMT_BUFSIZE +is recommended. +.Ss Fn ofmt_close +The +.Fn ofmt_close +function frees any resources allocated for the handle after printing is +completed. +.Sh RETURN VALUES +If successful, the +.Fn ofmt_open +function will return +.Dv OFMT_SUCCESS , +with a non-null +.Fa ofmt_handle . +The function returns one of the failure codes +.Po enumerated in +.Vt ofmt_status_t +.Pc +listed below otherwise: +.Pp +.Bl -tag -width "OFMT_ENOTEMPLATE" -compact +.It Dv OFMT_ENOMEM +out of memory +.It Dv OFMT_EBADFIELDS +one or more bad fields with good fields +.It Dv OFMT_ENOFIELDS +no valid output fields +.It Dv OFMT_EPARSEALL +"all" is invalid in parsable mode +.It Dv OFMT_EPARSENONE +output fields missing in parsable mode +.It Dv OFMT_EPARSEWRAP +parsable mode incompatible with wrap mode +.It Dv OFMT_ENOTEMPLATE +no template provided for fields +.It Dv OFMT_EPARSEMULTI +parsable and multiline don't mix +.El +.Pp +More information about the type of failure can be obtained by calling +.Fn ofmt_strerror . +.Pp +The +.Fn ofmt_strerror +function returns the +.Fa buf . +.Sh INTERFACE STABILITY +.Sy Private . +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr strerror 3C , +.Xr attributes 5 diff --git a/usr/src/pkg/manifests/developer-library-lint.mf b/usr/src/pkg/manifests/developer-library-lint.mf index 452abff215..c77e0ff388 100644 --- a/usr/src/pkg/manifests/developer-library-lint.mf +++ b/usr/src/pkg/manifests/developer-library-lint.mf @@ -73,6 +73,7 @@ file path=lib/$(ARCH64)/llib-lmd.ln file path=lib/$(ARCH64)/llib-lmd5.ln file path=lib/$(ARCH64)/llib-lnsl.ln file path=lib/$(ARCH64)/llib-lnvpair.ln +file path=lib/$(ARCH64)/llib-lofmt.ln file path=lib/$(ARCH64)/llib-lpam.ln file path=lib/$(ARCH64)/llib-lproc.ln file path=lib/$(ARCH64)/llib-lpthread.ln @@ -155,6 +156,8 @@ file path=lib/llib-lnvpair file path=lib/llib-lnvpair.ln file path=lib/llib-lnwam file path=lib/llib-lnwam.ln +file path=lib/llib-lofmt +file path=lib/llib-lofmt.ln file path=lib/llib-lpam file path=lib/llib-lpam.ln file path=lib/llib-lproc diff --git a/usr/src/pkg/manifests/system-library.man3ofmt.inc b/usr/src/pkg/manifests/system-library.man3ofmt.inc new file mode 100644 index 0000000000..f9e49c3c26 --- /dev/null +++ b/usr/src/pkg/manifests/system-library.man3ofmt.inc @@ -0,0 +1,21 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet +# at http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2017 Nexenta Systems, Inc. +# + +file path=usr/share/man/man3ofmt/ofmt.3ofmt +link path=usr/share/man/man3ofmt/ofmt_close.3ofmt target=ofmt.3ofmt +link path=usr/share/man/man3ofmt/ofmt_open.3ofmt target=ofmt.3ofmt +link path=usr/share/man/man3ofmt/ofmt_print.3ofmt target=ofmt.3ofmt +link path=usr/share/man/man3ofmt/ofmt_strerror.3ofmt target=ofmt.3ofmt +link path=usr/share/man/man3ofmt/ofmt_update_winsize.3ofmt target=ofmt.3ofmt diff --git a/usr/src/pkg/manifests/system-library.mf b/usr/src/pkg/manifests/system-library.mf index 06a7e9bab4..0ca8d3a587 100644 --- a/usr/src/pkg/manifests/system-library.mf +++ b/usr/src/pkg/manifests/system-library.mf @@ -23,7 +23,7 @@ # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2012 OmniTI Computer Consulting, Inc. All rights reserved. # Copyright (c) 2013 Gary Mills -# Copyright 2014 Nexenta Systems, Inc. All rights reserved. +# Copyright 2017 Nexenta Systems, Inc. # @@ -53,6 +53,7 @@ + @@ -154,6 +155,7 @@ dir path=usr/share/man/man3malloc dir path=usr/share/man/man3mp dir path=usr/share/man/man3nsl dir path=usr/share/man/man3nvpair +dir path=usr/share/man/man3ofmt dir path=usr/share/man/man3pam dir path=usr/share/man/man3pool dir path=usr/share/man/man3proc @@ -214,6 +216,7 @@ file path=lib/$(ARCH64)/libmd5.so.1 file path=lib/$(ARCH64)/libmp.so.2 file path=lib/$(ARCH64)/libnsl.so.1 file path=lib/$(ARCH64)/libnvpair.so.1 +file path=lib/$(ARCH64)/libofmt.so.1 file path=lib/$(ARCH64)/libpam.so.1 file path=lib/$(ARCH64)/libproc.so.1 file path=lib/$(ARCH64)/libpthread.so.1 @@ -296,6 +299,7 @@ file path=lib/libmp.so.2 file path=lib/libnsl.so.1 file path=lib/libnvpair.so.1 file path=lib/libnwam.so.1 +file path=lib/libofmt.so.1 file path=lib/libpam.so.1 file path=lib/libproc.so.1 file path=lib/libpthread.so.1 @@ -639,6 +643,7 @@ link path=lib/$(ARCH64)/libmd5.so target=libmd5.so.1 link path=lib/$(ARCH64)/libmp.so target=libmp.so.2 link path=lib/$(ARCH64)/libnsl.so target=libnsl.so.1 link path=lib/$(ARCH64)/libnvpair.so target=libnvpair.so.1 +link path=lib/$(ARCH64)/libofmt.so target=libofmt.so.1 link path=lib/$(ARCH64)/libpam.so target=libpam.so.1 link path=lib/$(ARCH64)/libposix4.so target=libposix4.so.1 link path=lib/$(ARCH64)/libposix4.so.1 target=librt.so.1 @@ -706,6 +711,7 @@ link path=lib/libmp.so target=libmp.so.2 link path=lib/libnsl.so target=libnsl.so.1 link path=lib/libnvpair.so target=libnvpair.so.1 link path=lib/libnwam.so target=libnwam.so.1 +link path=lib/libofmt.so target=libofmt.so.1 link path=lib/libpam.so target=libpam.so.1 link path=lib/libposix4.so target=libposix4.so.1 link path=lib/libposix4.so.1 target=librt.so.1 -- cgit v1.2.3 From 2a6fb28d0877f35efb94c09cc03e8088426d0c30 Mon Sep 17 00:00:00 2001 From: Marcel Telka Date: Fri, 19 May 2017 12:59:57 +0200 Subject: 8250 libnsl: Raw RPC client sends unlimited data Reviewed by: Yuri Pankov Reviewed by: Jason King Approved by: Dan McDonald --- usr/src/lib/libnsl/common/mapfile-vers | 1 - usr/src/lib/libnsl/rpc/clnt_raw.c | 196 +++++++++++++++++---------------- usr/src/lib/libnsl/rpc/svc_raw.c | 116 +++++++++++-------- usr/src/pkg/manifests/system-header.mf | 1 - usr/src/uts/common/rpc/Makefile | 2 +- usr/src/uts/common/rpc/raw.h | 54 --------- 6 files changed, 171 insertions(+), 199 deletions(-) delete mode 100644 usr/src/uts/common/rpc/raw.h diff --git a/usr/src/lib/libnsl/common/mapfile-vers b/usr/src/lib/libnsl/common/mapfile-vers index c8fa67b625..3f31af2f5e 100644 --- a/usr/src/lib/libnsl/common/mapfile-vers +++ b/usr/src/lib/libnsl/common/mapfile-vers @@ -633,7 +633,6 @@ SYMBOL_VERSION SUNWprivate_1.1 { pagf; passwd2des; passwd2des_g; - _rawcombuf; __rpcbind_is_up; __rpc_bindresvport; rpcb_taddr2uaddr; diff --git a/usr/src/lib/libnsl/rpc/clnt_raw.c b/usr/src/lib/libnsl/rpc/clnt_raw.c index 8f1766cd73..805e41c361 100644 --- a/usr/src/lib/libnsl/rpc/clnt_raw.c +++ b/usr/src/lib/libnsl/rpc/clnt_raw.c @@ -32,45 +32,42 @@ * California. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * clnt_raw.c * * Memory based rpc for simple testing and timing. * Interface to create an rpc client and server in the same process. - * This lets us similate rpc and get round trip overhead, without + * This lets us simulate rpc and get round trip overhead, without * any interference from the kernel. */ #include "mt.h" #include "rpc_mt.h" #include #include -#include #include extern mutex_t clntraw_lock; #define MCALL_MSG_SIZE 24 -#ifndef UDPMSGSIZE -#define UDPMSGSIZE 8800 -#endif /* * This is the "network" we will be moving stuff over. */ static struct clnt_raw_private { CLIENT client_object; - XDR xdr_stream; - char *raw_buf; /* should be shared with server handle */ + struct netbuf *raw_netbuf; char mashl_callmsg[MCALL_MSG_SIZE]; uint_t mcnt; } *clnt_raw_private; static struct clnt_ops *clnt_raw_ops(); -extern void svc_getreq_common(int); extern bool_t xdr_opaque_auth(); +/* + * This netbuf is shared with the raw server. + */ +extern struct netbuf _rawcomnetbuf; + /* * Create a client handle for memory based rpc. */ @@ -79,35 +76,26 @@ clnt_raw_create(const rpcprog_t prog, const rpcvers_t vers) { struct clnt_raw_private *clp; struct rpc_msg call_msg; - XDR *xdrs; + XDR xdrs; CLIENT *client; + uint_t start; /* VARIABLES PROTECTED BY clntraw_lock: clp */ (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; + if (clp != NULL) { + (void) mutex_unlock(&clntraw_lock); + return (&clp->client_object); + } + + clp = calloc(1, sizeof (*clp)); if (clp == NULL) { - clp = calloc(1, sizeof (*clp)); - if (clp == NULL) { - (void) mutex_unlock(&clntraw_lock); - return (NULL); - } - if (_rawcombuf == NULL) { - _rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); - if (_rawcombuf == NULL) { - syslog(LOG_ERR, "clnt_raw_create: " - "out of memory."); - if (clp) - free(clp); - (void) mutex_unlock(&clntraw_lock); - return (NULL); - } - } - clp->raw_buf = _rawcombuf; /* Share it with the server */ - clnt_raw_private = clp; + (void) mutex_unlock(&clntraw_lock); + return (NULL); } - xdrs = &clp->xdr_stream; - client = &clp->client_object; + + clp->raw_netbuf = &_rawcomnetbuf; /* * pre-serialize the static part of the call msg and stash it away @@ -116,25 +104,30 @@ clnt_raw_create(const rpcprog_t prog, const rpcvers_t vers) call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; call_msg.rm_call.cb_prog = prog; call_msg.rm_call.cb_vers = vers; - xdrmem_create(xdrs, clp->mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE); - if (!xdr_callhdr(xdrs, &call_msg)) - (void) syslog(LOG_ERR, - (const char *) "clnt_raw_create : \ - Fatal header serialization error."); - clp->mcnt = XDR_GETPOS(xdrs); - XDR_DESTROY(xdrs); + xdrmem_create(&xdrs, clp->mashl_callmsg, sizeof (clp->mashl_callmsg), + XDR_ENCODE); + start = XDR_GETPOS(&xdrs); + if (!xdr_callhdr(&xdrs, &call_msg)) { + free(clp); + (void) syslog(LOG_ERR, + "clnt_raw_create: Fatal header serialization error"); - /* - * Set xdrmem for client/server shared buffer - */ - xdrmem_create(xdrs, clp->raw_buf, UDPMSGSIZE, XDR_FREE); + (void) mutex_unlock(&clntraw_lock); + return (NULL); + } + clp->mcnt = XDR_GETPOS(&xdrs) - start; + XDR_DESTROY(&xdrs); /* * create client handle */ + client = &clp->client_object; client->cl_ops = clnt_raw_ops(); client->cl_auth = authnone_create(); + + clnt_raw_private = clp; + (void) mutex_unlock(&clntraw_lock); return (client); } @@ -142,20 +135,21 @@ clnt_raw_create(const rpcprog_t prog, const rpcvers_t vers) /*ARGSUSED*/ static enum clnt_stat clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, - xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) + xdrproc_t xresults, caddr_t resultsp, struct timeval timeout) { struct clnt_raw_private *clp; - XDR *xdrs; + XDR xdrs; struct rpc_msg msg; - enum clnt_stat status; - struct rpc_err error; + uint_t start; + + rpc_callerr.re_errno = 0; + rpc_callerr.re_terrno = 0; (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; - xdrs = &clp->xdr_stream; if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); - return (RPC_FAILED); + return (rpc_callerr.re_status = RPC_FAILED); } (void) mutex_unlock(&clntraw_lock); @@ -163,45 +157,55 @@ call_again: /* * send request */ - xdrs->x_op = XDR_ENCODE; - XDR_SETPOS(xdrs, 0); + xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen, + XDR_ENCODE); + start = XDR_GETPOS(&xdrs); /* LINTED pointer alignment */ ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; - if ((!XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || - (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || - (!AUTH_MARSHALL(h->cl_auth, xdrs)) || - (!(*xargs)(xdrs, argsp))) - return (RPC_CANTENCODEARGS); - (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ + if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) || + (!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || + (!AUTH_MARSHALL(h->cl_auth, &xdrs)) || + (!(*xargs)(&xdrs, argsp))) { + XDR_DESTROY(&xdrs); + return (rpc_callerr.re_status = RPC_CANTENCODEARGS); + } + clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start; + XDR_DESTROY(&xdrs); /* * We have to call server input routine here because this is * all going on in one process. - * By convention using FD_SETSIZE as the psuedo file descriptor. + * By convention using FD_SETSIZE as the pseudo file descriptor. */ svc_getreq_common(FD_SETSIZE); /* * get results */ - xdrs->x_op = XDR_DECODE; - XDR_SETPOS(xdrs, 0); + xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->len, + XDR_DECODE); msg.acpted_rply.ar_verf = _null_auth; msg.acpted_rply.ar_results.where = resultsp; msg.acpted_rply.ar_results.proc = xresults; - if (!xdr_replymsg(xdrs, &msg)) - return (RPC_CANTDECODERES); - if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && - (msg.acpted_rply.ar_stat == SUCCESS)) - status = RPC_SUCCESS; - else { - __seterr_reply(&msg, &error); - status = error.re_status; + if (!xdr_replymsg(&xdrs, &msg)) { + XDR_DESTROY(&xdrs); + return (rpc_callerr.re_status = RPC_CANTDECODERES); } + XDR_DESTROY(&xdrs); + if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) && + (msg.acpted_rply.ar_stat == SUCCESS)) + rpc_callerr.re_status = RPC_SUCCESS; + else + __seterr_reply(&msg, &rpc_callerr); - if (status == RPC_SUCCESS) { + if (rpc_callerr.re_status == RPC_SUCCESS) { if (!AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { - status = RPC_AUTHERROR; + rpc_callerr.re_status = RPC_AUTHERROR; + rpc_callerr.re_why = AUTH_INVALIDRESP; + } + if (msg.acpted_rply.ar_verf.oa_base != NULL) { + xdr_free(xdr_opaque_auth, + (char *)&(msg.acpted_rply.ar_verf)); } /* end successful completion */ } else { @@ -210,17 +214,7 @@ call_again: /* end of unsuccessful completion */ } - if (status == RPC_SUCCESS) { - if (!AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) { - status = RPC_AUTHERROR; - } - if (msg.acpted_rply.ar_verf.oa_base != NULL) { - xdrs->x_op = XDR_FREE; - (void) xdr_opaque_auth(xdrs, - &(msg.acpted_rply.ar_verf)); - } - } - return (status); + return (rpc_callerr.re_status); } /*ARGSUSED*/ @@ -228,45 +222,53 @@ static enum clnt_stat clnt_raw_send(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) { struct clnt_raw_private *clp; - XDR *xdrs; + XDR xdrs; + uint_t start; + + rpc_callerr.re_errno = 0; + rpc_callerr.re_terrno = 0; (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; - xdrs = &clp->xdr_stream; if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); - return (RPC_FAILED); + return (rpc_callerr.re_status = RPC_FAILED); } (void) mutex_unlock(&clntraw_lock); /* * send request */ - xdrs->x_op = XDR_ENCODE; - XDR_SETPOS(xdrs, 0); + xdrmem_create(&xdrs, clp->raw_netbuf->buf, clp->raw_netbuf->maxlen, + XDR_ENCODE); + start = XDR_GETPOS(&xdrs); /* LINTED pointer alignment */ ((struct rpc_msg *)clp->mashl_callmsg)->rm_xid++; - if ((!XDR_PUTBYTES(xdrs, clp->mashl_callmsg, clp->mcnt)) || - (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || - (!AUTH_MARSHALL(h->cl_auth, xdrs)) || - (!(*xargs)(xdrs, argsp))) - return (RPC_CANTENCODEARGS); - (void) XDR_GETPOS(xdrs); /* called just to cause overhead */ + if ((!XDR_PUTBYTES(&xdrs, clp->mashl_callmsg, clp->mcnt)) || + (!XDR_PUTINT32(&xdrs, (int32_t *)&proc)) || + (!AUTH_MARSHALL(h->cl_auth, &xdrs)) || + (!(*xargs)(&xdrs, argsp))) { + XDR_DESTROY(&xdrs); + return (rpc_callerr.re_status = RPC_CANTENCODEARGS); + } + clp->raw_netbuf->len = XDR_GETPOS(&xdrs) - start; + XDR_DESTROY(&xdrs); /* * We have to call server input routine here because this is * all going on in one process. - * By convention using FD_SETSIZE as the psuedo file descriptor. + * By convention using FD_SETSIZE as the pseudo file descriptor. */ svc_getreq_common(FD_SETSIZE); - return (RPC_SUCCESS); + return (rpc_callerr.re_status = RPC_SUCCESS); } /*ARGSUSED*/ static void clnt_raw_geterr(CLIENT *cl, struct rpc_err *errp) { + *errp = rpc_callerr; } /*ARGSUSED*/ @@ -274,18 +276,18 @@ static bool_t clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) { struct clnt_raw_private *clp; - XDR *xdrs; (void) mutex_lock(&clntraw_lock); clp = clnt_raw_private; - xdrs = &clp->xdr_stream; if (clp == NULL) { (void) mutex_unlock(&clntraw_lock); return (FALSE); } (void) mutex_unlock(&clntraw_lock); - xdrs->x_op = XDR_FREE; - return ((*xdr_res)(xdrs, res_ptr)); + + xdr_free(xdr_res, res_ptr); + + return (TRUE); } /*ARGSUSED*/ diff --git a/usr/src/lib/libnsl/rpc/svc_raw.c b/usr/src/lib/libnsl/rpc/svc_raw.c index a3e9e9c7c6..1fe2ad7c6a 100644 --- a/usr/src/lib/libnsl/rpc/svc_raw.c +++ b/usr/src/lib/libnsl/rpc/svc_raw.c @@ -32,14 +32,11 @@ * California. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* - * svc_raw.c, This a toy for simple testing and timing. + * svc_raw.c, This is a toy for simple testing and timing. * Interface to create an rpc client and server in the same UNIX process. - * This lets us similate rpc and get rpc (round trip) overhead, without + * This lets us simulate rpc and get rpc (round trip) overhead, without * any interference from the kernal. - * */ #include "mt.h" @@ -47,7 +44,6 @@ #include #include #include -#include #include #ifndef UDPMSGSIZE @@ -58,7 +54,7 @@ * This is the "network" that we will be moving data over */ static struct svc_raw_private { - char *raw_buf; /* should be shared with the cl handle */ + struct netbuf *raw_netbuf; SVCXPRT *server; XDR xdr_stream; char verf_body[MAX_AUTH_BYTES]; @@ -67,56 +63,66 @@ static struct svc_raw_private { static struct xp_ops *svc_raw_ops(); extern mutex_t svcraw_lock; - +/* + * This netbuf is shared with the raw client. + */ +struct netbuf _rawcomnetbuf; SVCXPRT * svc_raw_create(void) { struct svc_raw_private *srp; - bool_t flag1 = FALSE, flag2 = FALSE; /* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */ (void) mutex_lock(&svcraw_lock); srp = svc_raw_private; + if (srp != NULL) { + (void) mutex_unlock(&svcraw_lock); + return (srp->server); + } + + srp = calloc(1, sizeof (*srp)); if (srp == NULL) { - srp = calloc(1, sizeof (*srp)); - if (srp == NULL) { - syslog(LOG_ERR, "svc_raw_create: out of memory"); - (void) mutex_unlock(&svcraw_lock); - return (NULL); - } - flag1 = TRUE; - if (_rawcombuf == NULL) { - _rawcombuf = calloc(UDPMSGSIZE, sizeof (char)); - if (_rawcombuf == NULL) { - free(srp); - syslog(LOG_ERR, "svc_raw_create: " - "out of memory"); - (void) mutex_unlock(&svcraw_lock); - return (NULL); - } - flag2 = TRUE; - } - srp->raw_buf = _rawcombuf; /* Share it with the client */ - svc_raw_private = srp; + syslog(LOG_ERR, "svc_raw_create: out of memory"); + + (void) mutex_unlock(&svcraw_lock); + return (NULL); } + + srp->raw_netbuf = &_rawcomnetbuf; + srp->raw_netbuf->buf = malloc(UDPMSGSIZE); + if (srp->raw_netbuf->buf == NULL) { + free(srp); + syslog(LOG_ERR, "svc_raw_create: out of memory"); + + (void) mutex_unlock(&svcraw_lock); + return (NULL); + } + srp->raw_netbuf->maxlen = UDPMSGSIZE; + srp->raw_netbuf->len = 0; + if ((srp->server = svc_xprt_alloc()) == NULL) { - if (flag2) - free(svc_raw_private->raw_buf); - if (flag1) - free(svc_raw_private); + free(srp->raw_netbuf->buf); + srp->raw_netbuf->buf = NULL; + srp->raw_netbuf->maxlen = 0; + + free(srp); + (void) mutex_unlock(&svcraw_lock); return (NULL); } + /* - * By convention, using FD_SETSIZE as the psuedo file descriptor + * By convention, using FD_SETSIZE as the pseudo file descriptor */ srp->server->xp_fd = FD_SETSIZE; srp->server->xp_port = 0; srp->server->xp_ops = svc_raw_ops(); srp->server->xp_verf.oa_base = srp->verf_body; - xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE); xprt_register(srp->server); + + svc_raw_private = srp; + (void) mutex_unlock(&svcraw_lock); return (srp->server); } @@ -144,9 +150,16 @@ svc_raw_recv(SVCXPRT *xprt, struct rpc_msg *msg) (void) mutex_unlock(&svcraw_lock); xdrs = &srp->xdr_stream; - xdrs->x_op = XDR_DECODE; - (void) XDR_SETPOS(xdrs, 0); - return (xdr_callmsg(xdrs, msg)); + + xdrmem_create(xdrs, srp->raw_netbuf->buf, srp->raw_netbuf->len, + XDR_DECODE); + + if (!xdr_callmsg(xdrs, msg)) { + XDR_DESTROY(xdrs); + return (FALSE); + } + + return (TRUE); } /*ARGSUSED*/ @@ -155,6 +168,7 @@ svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg) { struct svc_raw_private *srp; XDR *xdrs; + uint_t start; (void) mutex_lock(&svcraw_lock); srp = svc_raw_private; @@ -165,9 +179,19 @@ svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg) (void) mutex_unlock(&svcraw_lock); xdrs = &srp->xdr_stream; - xdrs->x_op = XDR_ENCODE; - (void) XDR_SETPOS(xdrs, 0); - return (xdr_replymsg(xdrs, msg)); + + XDR_DESTROY(xdrs); + xdrmem_create(xdrs, srp->raw_netbuf->buf, srp->raw_netbuf->maxlen, + XDR_ENCODE); + + start = XDR_GETPOS(xdrs); + if (!xdr_replymsg(xdrs, msg)) { + XDR_DESTROY(xdrs); + return (FALSE); + } + srp->raw_netbuf->len = XDR_GETPOS(xdrs) - start; + + return (TRUE); } /*ARGSUSED*/ @@ -183,6 +207,7 @@ svc_raw_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) return (FALSE); } (void) mutex_unlock(&svcraw_lock); + return ((*xdr_args)(&srp->xdr_stream, args_ptr)); } @@ -191,7 +216,6 @@ static bool_t svc_raw_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) { struct svc_raw_private *srp; - XDR *xdrs; (void) mutex_lock(&svcraw_lock); srp = svc_raw_private; @@ -201,9 +225,11 @@ svc_raw_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr) } (void) mutex_unlock(&svcraw_lock); - xdrs = &srp->xdr_stream; - xdrs->x_op = XDR_FREE; - return ((*xdr_args)(xdrs, args_ptr)); + XDR_DESTROY(&srp->xdr_stream); + + xdr_free(xdr_args, args_ptr); + + return (TRUE); } /*ARGSUSED*/ diff --git a/usr/src/pkg/manifests/system-header.mf b/usr/src/pkg/manifests/system-header.mf index 4e135e7751..9082061fd1 100644 --- a/usr/src/pkg/manifests/system-header.mf +++ b/usr/src/pkg/manifests/system-header.mf @@ -657,7 +657,6 @@ file path=usr/include/rpc/pmap_clnt.h file path=usr/include/rpc/pmap_prot.h file path=usr/include/rpc/pmap_prot.x file path=usr/include/rpc/pmap_rmt.h -file path=usr/include/rpc/raw.h file path=usr/include/rpc/rpc.h file path=usr/include/rpc/rpc_com.h file path=usr/include/rpc/rpc_msg.h diff --git a/usr/src/uts/common/rpc/Makefile b/usr/src/uts/common/rpc/Makefile index c300261b69..f0c54d24f2 100644 --- a/usr/src/uts/common/rpc/Makefile +++ b/usr/src/uts/common/rpc/Makefile @@ -41,7 +41,7 @@ COMMHDRS= \ auth.h auth_des.h auth_sys.h auth_unix.h \ bootparam.h clnt.h clnt_soc.h clnt_stat.h des_crypt.h \ nettype.h pmap_clnt.h pmap_rmt.h \ -raw.h rpc.h rpc_com.h rpc_msg.h \ +rpc.h rpc_com.h rpc_msg.h \ rpcb_clnt.h rpcent.h svc.h svc_auth.h svc_soc.h \ types.h xdr.h rpcsec_gss.h svc_mt.h \ rpcsys.h rpc_rdma.h diff --git a/usr/src/uts/common/rpc/raw.h b/usr/src/uts/common/rpc/raw.h deleted file mode 100644 index d58396b2b6..0000000000 --- a/usr/src/uts/common/rpc/raw.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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. - * - * 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 1991 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ -/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ -/* - * Portions of this source code were derived from Berkeley - * 4.3 BSD under license from the Regents of the University of - * California. - */ - -#ifndef _RPC_RAW_H -#define _RPC_RAW_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * raw.h - * - * Raw interface - * The common memory area over which they will communicate - */ -char *_rawcombuf; - -#ifdef __cplusplus -} -#endif - -#endif /* _RPC_RAW_H */ -- cgit v1.2.3