Home | History | Annotate | Download | only in snoop
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 
     29 #include <ctype.h>
     30 #include <string.h>
     31 #include <strings.h>
     32 #include <stdlib.h>
     33 #include <sys/types.h>
     34 #include <sys/errno.h>
     35 #include <sys/tiuser.h>
     36 #include <setjmp.h>
     37 
     38 #include <rpc/types.h>
     39 #include <rpc/xdr.h>
     40 #include <rpc/auth.h>
     41 #include <rpc/clnt.h>
     42 #include <rpc/rpc_msg.h>
     43 #include "snoop.h"
     44 
     45 #include <sys/stat.h>
     46 #include <sys/param.h>
     47 #include <rpcsvc/nfs_prot.h>
     48 /* use the same nfs4_prot.h as the xdr code */
     49 #include "rpcsvc/nfs4_prot.h"
     50 
     51 /*
     52  * XXX With NFS v2 and v3, we only need to xdr the pieces that we care
     53  * about.  Anything else we can ignore and just skip to the next packet.
     54  * So all the stuff that deals directly with XDR lives in snoop_display.c
     55  * With v4, we need to XDR entire structures so that we can skip over
     56  * uninteresting bits in a compound array, so we call XDR directly from
     57  * here.  We need to rethink how we're going to structure XDR access.  Do
     58  * we continue to hide it all in snoop_display.c, or do we expose it to all
     59  * the protocol modules?
     60  */
     61 extern XDR xdrm;
     62 
     63 #ifndef MIN
     64 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
     65 #endif
     66 
     67 /*
     68  * Maximum number of characters to display in compound4 summary line.
     69  */
     70 #define	SUM_COMPND_MAX	100
     71 
     72 /*
     73  * Maximum number of recognized attributes.
     74  */
     75 #define	MAX_ATTRIBUTES	56
     76 
     77 /*
     78  * This data structure provides a more convenient way to access an
     79  * attribute bitmask.  map[N] = value of bit N in a bitmap4.
     80  * It's defined as a struct so as to step around all the weird rules in C
     81  * about arrays, pointers, passing them as arguments, etc.
     82  */
     83 
     84 typedef struct {
     85 	char map[MAX_ATTRIBUTES];
     86 } unpkd_attrmap_t;
     87 
     88 
     89 static void sumarg_cb_getattr(char *buf, size_t buflen, void *obj);
     90 static void dtlarg_cb_getattr(void *obj);
     91 static void sumarg_cb_recall(char *buf, size_t buflen, void *obj);
     92 static void dtlarg_cb_recall(void *obj);
     93 
     94 
     95 static void sumarg_access(char *buf, size_t buflen, void *obj);
     96 static void dtlarg_access(void *obj);
     97 static void sumarg_close(char *buf, size_t buflen, void *obj);
     98 static void dtlarg_close(void *obj);
     99 static void sumarg_commit(char *buf, size_t buflen, void *obj);
    100 static void dtlarg_commit(void *obj);
    101 static void sumarg_compnt(char *buf, size_t buflen, void *obj);
    102 static void dtlarg_compnt(void *obj);
    103 static void sumarg_create(char *buf, size_t buflen, void *obj);
    104 static void dtlarg_create(void *obj);
    105 static void sumarg_delprge(char *buf, size_t buflen, void *obj);
    106 static void dtlarg_delprge(void *obj);
    107 static void sumarg_delret(char *buf, size_t buflen, void *obj);
    108 static void dtlarg_delret(void *obj);
    109 static void sumarg_getattr(char *buf, size_t buflen, void *obj);
    110 static void dtlarg_getattr(void *obj);
    111 static void sumarg_link(char *buf, size_t buflen, void *obj);
    112 static void dtlarg_link(void *obj);
    113 static void sum_open_to_lock_owner(char *buf, int buflen,
    114 					open_to_lock_owner4 *own);
    115 static void sum_exist_lock_owner(char *buf, int buflen,
    116 					exist_lock_owner4 *own);
    117 static void sum_locker(char *buf, size_t buflen, locker4 *lk);
    118 static void sumarg_lock(char *buf, size_t buflen, void *obj);
    119 static void detail_open_to_lock_owner(open_to_lock_owner4 *own);
    120 static void detail_exist_lock_owner(exist_lock_owner4 *own);
    121 static void detail_locker(locker4 *lk);
    122 static void dtlarg_lock(void *obj);
    123 static void sumarg_lockt(char *buf, size_t buflen, void *obj);
    124 static void dtlarg_lockt(void *obj);
    125 static void sumarg_locku(char *buf, size_t buflen, void *obj);
    126 static void dtlarg_locku(void *obj);
    127 static void sumarg_lookup(char *buf, size_t buflen, void *obj);
    128 static void dtlarg_lookup(void *obj);
    129 static void sumarg_open(char *buf, size_t buflen, void *obj);
    130 static void dtlarg_open(void *obj);
    131 static void sumarg_openattr(char *buf, size_t buflen, void *obj);
    132 static void dtlarg_openattr(void *obj);
    133 static void sumarg_open_confirm(char *buf, size_t buflen, void *obj);
    134 static void dtlarg_open_confirm(void *obj);
    135 static void sumarg_open_downgrd(char *buf, size_t buflen, void *obj);
    136 static void dtlarg_open_downgrd(void *obj);
    137 static void sumarg_putfh(char *buf, size_t buflen, void *obj);
    138 static void dtlarg_putfh(void *obj);
    139 static void sumarg_read(char *buf, size_t buflen, void *obj);
    140 static void dtlarg_read(void *obj);
    141 static void sumarg_readdir(char *buf, size_t buflen, void *obj);
    142 static void dtlarg_readdir(void *obj);
    143 static void sumarg_release_lkown(char *buf, size_t buflen, void *obj);
    144 static void dtlarg_release_lkown(void *obj);
    145 static void sumarg_rename(char *buf, size_t buflen, void *obj);
    146 static void dtlarg_rename(void *obj);
    147 static void sumarg_renew(char *buf, size_t buflen, void *obj);
    148 static void dtlarg_renew(void *buf);
    149 static void sumarg_secinfo(char *buf, size_t buflen, void *obj);
    150 static void dtlarg_secinfo(void *obj);
    151 static void sumarg_setattr(char *buf, size_t buflen, void *obj);
    152 static void dtlarg_setattr(void *obj);
    153 static void sumarg_setclid(char *buf, size_t buflen, void *obj);
    154 static void dtlarg_setclid(void *obj);
    155 static void sumarg_setclid_cfm(char *buf, size_t buflen, void *obj);
    156 static void dtlarg_setclid_cfm(void *obj);
    157 static void dtlarg_verify(void *obj);
    158 static void sumarg_write(char *buf, size_t buflen, void *obj);
    159 static void dtlarg_write(void *obj);
    160 
    161 static void sumres_cb_getattr(char *buf, size_t buflen, void *obj);
    162 static void dtlres_cb_getattr(void *obj);
    163 
    164 static void sumres_access(char *buf, size_t buflen, void *obj);
    165 static void dtlres_access(void *obj);
    166 static void sumres_close(char *buf, size_t buflen, void *obj);
    167 static void dtlres_close(void *obj);
    168 static void sumres_commit(char *buf, size_t buflen, void *obj);
    169 static void dtlres_commit(void *obj);
    170 static void dtlres_create(void *obj);
    171 static void sumres_getattr(char *buf, size_t buflen, void *obj);
    172 static void dtlres_getattr(void *obj);
    173 static void sumres_getfh(char *buf, size_t buflen, void *obj);
    174 static void dtlres_getfh(void *obj);
    175 static void dtlres_link(void *obj);
    176 static void sumres_lock(char *buf, size_t buflen, void *obj);
    177 static void dtlres_lock(void *obj);
    178 static void sumres_lockt(char *buf, size_t buflen, void *obj);
    179 static void dtlres_lockt(void *obj);
    180 static void sumres_locku(char *buf, size_t buflen, void *obj);
    181 static void dtlres_locku(void *obj);
    182 static void sumres_open(char *buf, size_t buflen, void *obj);
    183 static void dtlres_open(void *obj);
    184 static void sumres_open_confirm(char *buf, size_t buflen, void *obj);
    185 static void dtlres_open_confirm(void *obj);
    186 static void sumres_open_downgrd(char *buf, size_t buflen, void *obj);
    187 static void dtlres_open_downgrd(void *obj);
    188 static void sumres_read(char *buf, size_t buflen, void *obj);
    189 static void dtlres_read(void *obj);
    190 static void sumres_readdir(char *buf, size_t buflen, void *obj);
    191 static void dtlres_readdir(void *obj);
    192 static void sumres_readlnk(char *buf, size_t buflen, void *obj);
    193 static void dtlres_readlnk(void *obj);
    194 static void dtlres_remove(void *obj);
    195 static void dtlres_rename(void *obj);
    196 static void sumres_secinfo(char *buf, size_t buflen, void *obj);
    197 static void dtlres_secinfo(void *obj);
    198 static void sumres_setattr(char *buf, size_t buflen, void *obj);
    199 static void dtlres_setattr(void *obj);
    200 static void sumres_setclid(char *buf, size_t buflen, void *obj);
    201 static void dtlres_setclid(void *obj);
    202 static void sumres_write(char *buf, size_t buflen, void *obj);
    203 static void dtlres_write(void *obj);
    204 static void sum_nfsstat4(char *buf, size_t buflen, void *obj);
    205 static void dtl_nfsstat4(void *obj);
    206 static uint32_t adler16(void *, int);
    207 static void nfs4_xdr_skip(int nbytes);
    208 static char *sum_lock_type_name(enum nfs_lock_type4 type);
    209 
    210 int nfs4_pkt_start;
    211 int nfs4_pkt_len;
    212 int nfs4_skip_bytes;
    213 int nfs4_fragged_rpc;
    214 char *nfs4err_fragrpc = "<Fragmented RPC>";
    215 char *nfs4err_xdrfrag = "<XDR Error or Fragmented RPC>";
    216 
    217 /*
    218  * need a way to enable this if current testcases are parsing snoop
    219  * error text. -- maybe an env var would do as temp workaround until
    220  * testcases changed to grep for new error text.
    221  */
    222 int nfs4_use_old_error_text = 0;
    223 
    224 /*
    225  * Information about each operation that can appear in a compound call.
    226  * The function pointers are to formatting functions for summary arguments
    227  * and results, and detail arguments & results.
    228  */
    229 
    230 typedef struct {
    231 	char	*name;
    232 	void	(*sumarg)(char *, size_t, void *);
    233 	void	(*sumres)(char *, size_t, void *);
    234 	void	(*dtlarg)(void *);
    235 	void	(*dtlres)(void *);
    236 } op_info_t;
    237 
    238 static op_info_t cb_opcode_info[] = {
    239 	{"OP_ZERO",	NULL,	NULL,	NULL,	NULL},	/* 0 */
    240 	{"OP_ONE",	NULL,	NULL,	NULL,	NULL},
    241 	{"OP_TWO",	NULL,	NULL,	NULL,	NULL},  /* minor vers */
    242 	{"CB_GETATTR",
    243 		sumarg_cb_getattr,	sumres_cb_getattr,
    244 		dtlarg_cb_getattr,	dtlres_cb_getattr},
    245 	{"CB_RECALL",
    246 		sumarg_cb_recall,	sum_nfsstat4,
    247 		dtlarg_cb_recall,	dtl_nfsstat4},
    248 };
    249 static uint_t cb_num_opcodes = sizeof (cb_opcode_info) / sizeof (op_info_t *);
    250 
    251 static op_info_t opcode_info[] = {
    252 	{"OP_ZERO",	NULL,	NULL,	NULL,	NULL},	/* 0 */
    253 	{"OP_ONE",	NULL,	NULL,	NULL,	NULL},
    254 	{"OP_TWO",	NULL,	NULL,	NULL,	NULL},  /* minor vers */
    255 	{"ACCESS",
    256 	sumarg_access,	sumres_access,	dtlarg_access,	dtlres_access},
    257 	{"CLOSE",
    258 	sumarg_close,	sumres_close,	dtlarg_close,	dtlres_close},
    259 	{"COMMIT",
    260 	sumarg_commit,	sumres_commit,	dtlarg_commit,	dtlres_commit},
    261 	{"CREATE",					/* 5 */
    262 	sumarg_create,	sum_nfsstat4,	dtlarg_create,	dtlres_create},
    263 	{"DELEGPURGE",
    264 	sumarg_delprge,	sum_nfsstat4,	dtlarg_delprge,	dtl_nfsstat4},
    265 	{"DELEGRETURN",
    266 	sumarg_delret,	sum_nfsstat4,	dtlarg_delret,	dtl_nfsstat4},
    267 	{"GETATTR",
    268 	sumarg_getattr,	sumres_getattr,	dtlarg_getattr,	dtlres_getattr},
    269 	{"GETFH",
    270 	NULL,		sumres_getfh,	NULL,	dtlres_getfh},
    271 	{"LINK",					/* 10 */
    272 	sumarg_link,	sum_nfsstat4,	dtlarg_link,	dtlres_link},
    273 	{"LOCK",
    274 	sumarg_lock,	sumres_lock,	dtlarg_lock,	dtlres_lock},
    275 	{"LOCKT",
    276 	sumarg_lockt,	sumres_lockt,	dtlarg_lockt,	dtlres_lockt},
    277 	{"LOCKU",
    278 	sumarg_locku,	sumres_locku,	dtlarg_locku,	dtlres_locku},
    279 	{"LOOKUP",
    280 	sumarg_lookup,	sum_nfsstat4,	dtlarg_lookup,	dtl_nfsstat4},
    281 	{"LOOKUPP",					/* 15 */
    282 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
    283 	{"NVERIFY",
    284 	NULL,		sum_nfsstat4,	dtlarg_verify,	dtl_nfsstat4},
    285 	{"OPEN",
    286 	sumarg_open,	sumres_open,	dtlarg_open,	dtlres_open},
    287 	{"OPENATTR",
    288 	sumarg_openattr, sum_nfsstat4, dtlarg_openattr, dtl_nfsstat4},
    289 	{"OPEN_CONFIRM",
    290 	sumarg_open_confirm,
    291 	sumres_open_confirm,
    292 	dtlarg_open_confirm,
    293 	dtlres_open_confirm},
    294 	{"OPEN_DOWNGRADE",
    295 	sumarg_open_downgrd,
    296 	sumres_open_downgrd,
    297 	dtlarg_open_downgrd,
    298 	dtlres_open_downgrd},
    299 	{"PUTFH",
    300 	sumarg_putfh,	sum_nfsstat4,	dtlarg_putfh,	dtl_nfsstat4},
    301 	{"PUTPUBFH",					/* 20 */
    302 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
    303 	{"PUTROOTFH",
    304 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
    305 	{"READ",
    306 	sumarg_read,	sumres_read,	dtlarg_read,	dtlres_read},
    307 	{"READDIR",
    308 	sumarg_readdir,	sumres_readdir,	dtlarg_readdir,	dtlres_readdir},
    309 	{"READLINK",
    310 	NULL,		sumres_readlnk,	NULL,		dtlres_readlnk},
    311 	{"REMOVE",					/* 25 */
    312 	sumarg_compnt,	sum_nfsstat4,	dtlarg_compnt,	dtlres_remove},
    313 	{"RENAME",
    314 	sumarg_rename,	sum_nfsstat4,	dtlarg_rename,	dtlres_rename},
    315 	{"RENEW",
    316 	sumarg_renew,	sum_nfsstat4,	dtlarg_renew,	dtl_nfsstat4},
    317 	{"RESTOREFH",
    318 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
    319 	{"SAVEFH",
    320 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
    321 	{"SECINFO",					/* 30 */
    322 	sumarg_secinfo,	sumres_secinfo,	dtlarg_secinfo,	dtlres_secinfo},
    323 	{"SETATTR",
    324 	sumarg_setattr,	sumres_setattr,	dtlarg_setattr,	dtlres_setattr},
    325 	{"SETCLIENTID",
    326 	sumarg_setclid,	sumres_setclid,	dtlarg_setclid,	dtlres_setclid},
    327 	{"SETCLIENTID_CONFIRM",
    328 	sumarg_setclid_cfm,
    329 	sum_nfsstat4,
    330 	dtlarg_setclid_cfm,
    331 	dtl_nfsstat4},
    332 	{"VERIFY",
    333 	NULL,		sum_nfsstat4,	dtlarg_verify,	dtl_nfsstat4},
    334 	{"WRITE",
    335 	sumarg_write,	sumres_write,	dtlarg_write,	dtlres_write},
    336 	{"RELEASE_LOCKOWNER",
    337 	sumarg_release_lkown, sum_nfsstat4,
    338 	dtlarg_release_lkown, dtl_nfsstat4},
    339 };
    340 static uint_t num_opcodes = sizeof (opcode_info) / sizeof (op_info_t *);
    341 
    342 /*
    343  * File types.
    344  */
    345 
    346 typedef struct {
    347 	char *short_name;		/* for summary output */
    348 	char *long_name;		/* for detail output */
    349 } ftype_names_t;
    350 
    351 static ftype_names_t ftype_names[] = {
    352 	{"Type 0",	"Type 0"},
    353 	{"REG",		"Regular File"},
    354 	{"DIR",		"Directory"},
    355 	{"BLK",		"Block Device"},
    356 	{"CHR",		"Character Device"},
    357 	{"LNK",		"Symbolic Link"},	/* 5 */
    358 	{"SOCK",	"Socket"},
    359 	{"FIFO",	"FIFO"},
    360 	{"ATTRDIR",	"Attribute Directory"},
    361 	{"NAMEDATTR",	"Named Attribute"},
    362 };
    363 static uint_t num_ftypes = sizeof (ftype_names) / sizeof (ftype_names_t);
    364 
    365 static ftype_names_t	open_rflags[] = {
    366 	{"?",	"UNKNOWN"},	/* 0 */
    367 	{"CF",	"CONFIRM"},	/* 1 */
    368 	{"PL",	"POSIX LOCK"},	/* 2 */
    369 	{"?",	"UNKNOWN"},
    370 };
    371 static uint_t num_open_rflags =
    372 	sizeof (open_rflags) / sizeof (ftype_names_t) - 1;
    373 
    374 static char *get_flags(uint_t, ftype_names_t *, uint_t, int, char *);
    375 
    376 #define	sum_open_rflags(flag) \
    377 	get_flags((flag), open_rflags, num_open_rflags, 1, " RF=")
    378 
    379 #define	detail_open_rflags(flag) \
    380 	get_flags((flag), open_rflags, num_open_rflags, 0, NULL)
    381 
    382 static void prt_supported_attrs(XDR *);
    383 static void prt_type(XDR *);
    384 static void prt_fh_expire_type(XDR *);
    385 static void prt_change(XDR *);
    386 static void prt_size(XDR *);
    387 static void prt_link_support(XDR *);
    388 static void prt_symlink_support(XDR *);
    389 static void prt_named_attr(XDR *);
    390 static void prt_fsid(XDR *);
    391 static void prt_unique_handles(XDR *);
    392 static void prt_lease_time(XDR *);
    393 static void prt_rdattr_error(XDR *);
    394 static void prt_acl(XDR *);
    395 static void prt_aclsupport(XDR *);
    396 static void prt_archive(XDR *);
    397 static void prt_cansettime(XDR *);
    398 static void prt_case_insensitive(XDR *);
    399 static void prt_case_preserving(XDR *);
    400 static void prt_chown_restricted(XDR *);
    401 static void prt_filehandle(XDR *);
    402 static void prt_fileid(XDR *);
    403 static void prt_mounted_on_fileid(XDR *);
    404 static void prt_files_avail(XDR *);
    405 static void prt_files_free(XDR *);
    406 static void prt_files_total(XDR *);
    407 static void prt_fs_locations(XDR *);
    408 static void prt_hidden(XDR *);
    409 static void prt_homogeneous(XDR *);
    410 static void prt_maxfilesize(XDR *);
    411 static void prt_maxlink(XDR *);
    412 static void prt_maxname(XDR *);
    413 static void prt_maxread(XDR *);
    414 static void prt_maxwrite(XDR *);
    415 static void prt_mimetype(XDR *);
    416 static void prt_mode(XDR *);
    417 static void prt_no_trunc(XDR *);
    418 static void prt_numlinks(XDR *);
    419 static void prt_owner(XDR *);
    420 static void prt_owner_group(XDR *);
    421 static void prt_quota_avail_hard(XDR *);
    422 static void prt_quota_avail_soft(XDR *);
    423 static void prt_quota_used(XDR *);
    424 static void prt_rawdev(XDR *);
    425 static void prt_space_avail(XDR *);
    426 static void prt_space_free(XDR *);
    427 static void prt_space_total(XDR *);
    428 static void prt_space_used(XDR *);
    429 static void prt_system(XDR *);
    430 static void prt_time_access(XDR *);
    431 static void prt_time_access_set(XDR *);
    432 static void prt_time_backup(XDR *);
    433 static void prt_time_create(XDR *);
    434 static void prt_time_delta(XDR *);
    435 static void prt_time_metadata(XDR *);
    436 static void prt_time_modify(XDR *);
    437 static void prt_time_modify_set(XDR *);
    438 
    439 
    440 
    441 /*
    442  * Information for attributes.
    443  * name		name of the attribute.
    444  * prt_details	function to XDR decode the attribute and print it.
    445  *
    446  * XXX If this table ever gets extensively changed (including
    447  * reorganization to track changes to the spec), it would probably be a
    448  * good idea to change to a scheme where the table is mechanically
    449  * generated.  Look at $SRC/uts/common/rpcsvc for how this is done in the
    450  * kernel.
    451  */
    452 
    453 typedef struct {
    454 	char	*name;
    455 	void	(*prt_details)(XDR *);
    456 } attr_info_t;
    457 
    458 static attr_info_t attr_info[MAX_ATTRIBUTES] = {
    459 	{"SUPPORTED_ATTRS",	prt_supported_attrs},
    460 	{"TYPE",		prt_type},
    461 	{"FH_EXPIRE_TYPE",	prt_fh_expire_type},
    462 	{"CHANGE",		prt_change},
    463 	{"SIZE",		prt_size},
    464 	{"LINK_SUPPORT",	prt_link_support},	/* 5 */
    465 	{"SYMLINK_SUPPORT",	prt_symlink_support},
    466 	{"NAMED_ATTR",		prt_named_attr},
    467 	{"FSID",		prt_fsid},
    468 	{"UNIQUE_HANDLES",	prt_unique_handles},
    469 	{"LEASE_TIME",		prt_lease_time},	/* 10 */
    470 	{"RDATTR_ERROR",	prt_rdattr_error},
    471 	{"ACL",			prt_acl},
    472 	{"ACLSUPPORT",		prt_aclsupport},
    473 	{"ARCHIVE",		prt_archive},
    474 	{"CANSETTIME",		prt_cansettime},	/* 15 */
    475 	{"CASE_INSENSITIVE",	prt_case_insensitive},
    476 	{"CASE_PRESERVING",	prt_case_preserving},
    477 	{"CHOWN_RESTRICTED",	prt_chown_restricted},
    478 	{"FILEHANDLE",		prt_filehandle},
    479 	{"FILEID",		prt_fileid},		/* 20 */
    480 	{"FILES_AVAIL",		prt_files_avail},
    481 	{"FILES_FREE",		prt_files_free},
    482 	{"FILES_TOTAL",		prt_files_total},
    483 	{"FS_LOCATIONS",	prt_fs_locations},
    484 	{"HIDDEN",		prt_hidden},		/* 25 */
    485 	{"HOMOGENEOUS",		prt_homogeneous},
    486 	{"MAXFILESIZE",		prt_maxfilesize},
    487 	{"MAXLINK",		prt_maxlink},
    488 	{"MAXNAME",		prt_maxname},
    489 	{"MAXREAD",		prt_maxread},		/* 30 */
    490 	{"MAXWRITE",		prt_maxwrite},
    491 	{"MIMETYPE",		prt_mimetype},
    492 	{"MODE",		prt_mode},
    493 	{"NO_TRUNC",		prt_no_trunc},
    494 	{"NUMLINKS",		prt_numlinks},		/* 35 */
    495 	{"OWNER",		prt_owner},
    496 	{"OWNER_GROUP",		prt_owner_group},
    497 	{"QUOTA_AVAIL_HARD",	prt_quota_avail_hard},
    498 	{"QUOTA_AVAIL_SOFT",	prt_quota_avail_soft},
    499 	{"QUOTA_USED",		prt_quota_used},	/* 40 */
    500 	{"RAWDEV",		prt_rawdev},
    501 	{"SPACE_AVAIL",		prt_space_avail},
    502 	{"SPACE_FREE",		prt_space_free},
    503 	{"SPACE_TOTAL",		prt_space_total},
    504 	{"SPACE_USED",		prt_space_used},	/* 45 */
    505 	{"SYSTEM",		prt_system},
    506 	{"TIME_ACCESS",		prt_time_access},
    507 	{"TIME_ACCESS_SET",	prt_time_access_set},
    508 	{"TIME_BACKUP",		prt_time_backup},
    509 	{"TIME_CREATE",		prt_time_create},	/* 50 */
    510 	{"TIME_DELTA",		prt_time_delta},
    511 	{"TIME_METADATA",	prt_time_metadata},
    512 	{"TIME_MODIFY",		prt_time_modify},
    513 	{"TIME_MODIFY_SET",	prt_time_modify_set},
    514 	{"MOUNTED_ON_FILEID",	prt_mounted_on_fileid},
    515 };
    516 
    517 extern char *get_sum_line();
    518 
    519 extern jmp_buf xdr_err;
    520 
    521 static void sum_comp4res(char *, char *(*)(void));
    522 static char *sum_compound4args(void);
    523 static char *sum_compound4res(void);
    524 static char *sum_operand(nfs_argop4 *opp);
    525 static char *sum_result(nfs_resop4 *resp);
    526 
    527 static char *sum_cb_compound4args(void);
    528 static char *sum_cb_compound4res(void);
    529 static char *sum_cb_operand(nfs_cb_argop4 *opp);
    530 static char *sum_cb_result(nfs_cb_resop4 *resp);
    531 
    532 static void detail_acetype4(acetype4);
    533 static void detail_uint32_bitmap(uint32_t, char *[], int);
    534 static void detail_aceflag4(aceflag4);
    535 static void detail_acemask4(acemask4);
    536 static void detail_nfs_argop4(void);
    537 static void detail_nfs_resop4(void);
    538 static void detail_cb_argop4(void);
    539 static void detail_cb_resop4(void);
    540 
    541 static char *attr_name(uint_t);
    542 static char *claim_name(enum open_claim_type4 claim_type);
    543 static char *delegation_type_name(enum open_delegation_type4 type);
    544 static char *flavor_name(uint_t flavor);
    545 static char *gss_svc_name(rpc_gss_svc_t svc);
    546 static char *limitby_name(enum limit_by4 limitby);
    547 static char *lock_type_name(enum nfs_lock_type4);
    548 static char *opcode_name(uint_t);
    549 static char *cb_opcode_name(uint_t opnum);
    550 static char *status_name(int);
    551 static char *status_name_compat(int);
    552 static char *status_name_pcol(int);
    553 static char *sum_type_name(nfs_ftype4);
    554 static void sum_access4(char *buf, size_t buflen, uint32_t bits);
    555 static void detail_access4(char *, uint32_t);
    556 static void sum_claim(char *buf, size_t buflen, open_claim4 *claim);
    557 static void detail_claim(open_claim4 *claim);
    558 static char *sum_clientid(clientid4 client);
    559 static void detail_clientid(clientid4 client);
    560 static char *_sum_stateid(stateid4 *, char *prefix);
    561 static void sum_delegation(char *buf, size_t buflen, open_delegation4 *delp);
    562 static void detail_delegation(open_delegation4 *delp);
    563 static void detail_lock_owner(lock_owner4 *owner);
    564 static void detail_open_owner(open_owner4 *owner);
    565 static void sum_openflag(char *bufp, int buflen, openflag4 *flagp);
    566 static char *get_deleg_typestr(open_delegation_type4 dt);
    567 static void detail_openflag(openflag4 *flagp);
    568 static void sum_name(char *buf, size_t buflen, open_claim4 *claim);
    569 static void detail_rpcsec_gss(rpcsec_gss_info *);
    570 static void detail_secinfo4(secinfo4 *infop);
    571 static char *sum_space_limit(nfs_space_limit4 *limitp);
    572 static void detail_space_limit(nfs_space_limit4 *limitp);
    573 static char *detail_type_name(nfs_ftype4);
    574 static char *createhow4_name(createhow4 *crtp);
    575 
    576 
    577 static void showxdr_utf8string(char *);
    578 static char *utf8localize(utf8string *);
    579 static void utf8free(void);
    580 static void sum_pathname4(char *, size_t, pathname4 *);
    581 static void detail_pathname4(pathname4 *pathp);
    582 static void sum_compname4(char *buf, size_t buflen, component4 *comp);
    583 static void detail_compname4(component4 *comp);
    584 
    585 static void detail_fattr4(fattr4 *attrp);
    586 static void detail_attr_bitmap(char *, bitmap4 *, unpkd_attrmap_t *);
    587 static void sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp);
    588 static void detail_fattr4_change(char *msg, fattr4_change chg);
    589 static char *sum_fh4(nfs_fh4 *fhp);
    590 static void detail_fh4(nfs_fh4 *fh);
    591 
    592 #define	fh4_hash(fh) adler16((fh)->nfs_fh4_val, (fh)->nfs_fh4_len)
    593 #define	stateid_hash(st) adler16((st)->other, sizeof ((st)->other))
    594 #define	owner_hash(own) adler16((own)->owner_val, (own)->owner_len)
    595 
    596 #define	sum_deleg_stateid(st)	_sum_stateid((st), "DST=")
    597 #define	sum_open_stateid(st)	_sum_stateid((st), "OST=")
    598 #define	sum_lock_stateid(st)	_sum_stateid((st), "LST=")
    599 #define	sum_stateid(st)		_sum_stateid((st), "ST=")
    600 
    601 #define	detail_deleg_stateid(st)	_detail_stateid((st), "Delegation ")
    602 #define	detail_open_stateid(st)		_detail_stateid((st), "Open ")
    603 #define	detail_lock_stateid(st)		_detail_stateid((st), "Lock ")
    604 #define	detail_stateid(st)		_detail_stateid((st), "")
    605 
    606 #define	SPECIAL_STATEID0	"SPC0"
    607 #define	SPECIAL_STATEID1	"SPC1"
    608 
    609 #define	DONT_CHANGE		0
    610 #define	SET_TO_SERVER_TIME	1
    611 #define	SET_TO_CLIENT_TIME	2
    612 
    613 static stateid4 spec_stateid_0 =
    614 	{0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
    615 static stateid4 spec_stateid_1 =
    616 	{0xFFFFFFFF, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
    617 
    618 static char *procnames_short[] = {
    619 	"NULL4",	/*  0 */
    620 	"COMPOUND4"	/*  1 */
    621 };
    622 
    623 static char *procnames_long[] = {
    624 	"Null procedure",		/*  0 */
    625 	"Compound",			/*  1 */
    626 };
    627 
    628 static char *cb_procnames_short[] = {
    629 	"CB_NULL",	/*  0 */
    630 	"CB_COMPOUND"	/*  1 */
    631 };
    632 
    633 static char *cb_procnames_long[] = {
    634 	"Null CallBack procedure",	/*  0 */
    635 	"CallBack compound",		/*  1 */
    636 };
    637 
    638 static char *acetype4_names[] = {
    639 	"ACE4_ACCESS_ALLOWED_ACE_TYPE",
    640 	"ACE4_ACCESS_DENIED_ACE_TYPE",
    641 	"ACE4_SYSTEM_AUDIT_ACE_TYPE",
    642 	"ACE4_SYSTEM_ALARM_ACE_TYPE"
    643 };
    644 #define	ACETYPE4_NAMES_MAX (sizeof (acetype4_names) / sizeof (char *))
    645 
    646 static char *aceflag4_names[] = {
    647 	"ACE4_FILE_INHERIT_ACE",
    648 	"ACE4_DIRECTORY_INHERIT_ACE",
    649 	"ACE4_NO_PROPAGATE_INHERIT_ACE",
    650 	"ACE4_INHERIT_ONLY_ACE",
    651 	"ACE4_SUCCESSFUL_ACCESS_ACE_FLAG",
    652 	"ACE4_FAILED_ACCESS_ACE_FLAG",
    653 	"ACE4_IDENTIFIER_GROUP"
    654 };
    655 #define	ACEFLAG4_NAMES_MAX (sizeof (aceflag4_names) / sizeof (char *))
    656 
    657 static char *acemask4_names[] = {
    658 	"ACE4_READ_DATA/ACE4_LIST_DIRECTORY",
    659 	"ACE4_WRITE_DATA/ACE4_ADD_FILE",
    660 	"ACE4_APPEND_DATA/ACE4_ADD_SUBDIRECTORY",
    661 	"ACE4_READ_NAMED_ATTRS",
    662 	"ACE4_WRITE_NAMED_ATTRS",
    663 	"ACE4_EXECUTE",
    664 	"ACE4_DELETE_CHILD",
    665 	"ACE4_READ_ATTRIBUTES",
    666 	"ACE4_WRITE_ATTRIBUTES",
    667 	"UNDEFINED",	/* 0x00000200 */
    668 	"UNDEFINED",	/* 0x00000400 */
    669 	"UNDEFINED",	/* 0x00000800 */
    670 	"UNDEFINED",	/* 0x00001000 */
    671 	"UNDEFINED",	/* 0x00002000 */
    672 	"UNDEFINED",	/* 0x00004000 */
    673 	"UNDEFINED",	/* 0x00008000 */
    674 	"ACE4_DELETE",
    675 	"ACE4_READ_ACL",
    676 	"ACE4_WRITE_ACL",
    677 	"ACE4_WRITE_OWNER",
    678 	"ACE4_SYNCHRONIZE"
    679 };
    680 #define	ACEMASK4_NAMES_MAX (sizeof (acemask4_names) / sizeof (char *))
    681 
    682 #define	MAXPROC	1
    683 
    684 /*ARGSUSED*/
    685 void
    686 interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
    687 		char *data, int len)
    688 {
    689 	char *line = NULL;
    690 
    691 	if (proc < 0 || proc > MAXPROC)
    692 		return;
    693 
    694 	if (flags & F_SUM) {
    695 		line = get_sum_line();
    696 
    697 		if (type == CALL) {
    698 			(void) sprintf(line, "NFS C %s",
    699 				    proc == CB_COMPOUND ? "CB4" :
    700 					    cb_procnames_short[proc]);
    701 			line += strlen(line);
    702 
    703 			if (proc == CB_COMPOUND) {
    704 				static utf8string tag;
    705 
    706 				if (!xdr_utf8string(&xdrm, &tag))
    707 					longjmp(xdr_err, 1);
    708 				sprintf(line, " (%.20s) %s",
    709 					utf8localize(&tag),
    710 					sum_cb_compound4args());
    711 				xdr_free(xdr_utf8string, (char *)&tag);
    712 			}
    713 			check_retransmit(line, xid);
    714 		} else {
    715 			(void) sprintf(line, "NFS R %s ",
    716 				    proc == CB_COMPOUND ? "CB4" :
    717 					    cb_procnames_short[proc]);
    718 			line += strlen(line);
    719 			if (proc == CB_COMPOUND)
    720 				sum_comp4res(line, sum_cb_compound4res);
    721 		}
    722 	}
    723 
    724 	if (flags & F_DTAIL) {
    725 		show_header("NFS:  ", "Sun NFS4 CallBack", len);
    726 		show_space();
    727 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    728 			proc, cb_procnames_long[proc]);
    729 		if (proc == CB_COMPOUND) {
    730 			if (type == CALL) {
    731 				showxdr_utf8string("Tag = %s");
    732 				detail_cb_argop4();
    733 			} else {
    734 				nfsstat4 status;
    735 
    736 				status = getxdr_long();
    737 				showxdr_utf8string("Tag = %s");
    738 				sprintf(get_line(0, 0), "Status = %d (%s)",
    739 					status, status_name(status));
    740 				detail_cb_resop4();
    741 			}
    742 		}
    743 		show_trailer();
    744 	}
    745 
    746 	utf8free();			/* cf. utf8localize() */
    747 }
    748 
    749 
    750 /*ARGSUSED*/
    751 void
    752 interpret_nfs4(int flags, int type, int xid, int vers, int proc,
    753 		char *data, int len)
    754 {
    755 	char *line = NULL;
    756 
    757 	if (proc < 0 || proc > MAXPROC)
    758 		return;
    759 
    760 	nfs4_fragged_rpc = 0;
    761 	nfs4_pkt_len = len;
    762 	nfs4_pkt_start = xdr_getpos(&xdrm);
    763 
    764 	if (flags & F_SUM) {
    765 		line = get_sum_line();
    766 
    767 		if (type == CALL) {
    768 			(void) sprintf(line, "NFS C %s",
    769 				    proc == NFSPROC4_COMPOUND ? "4" :
    770 					    procnames_short[proc]);
    771 			line += strlen(line);
    772 
    773 			if (proc == NFSPROC4_COMPOUND) {
    774 				static utf8string tag;
    775 
    776 				if (!xdr_utf8string(&xdrm, &tag))
    777 					longjmp(xdr_err, 1);
    778 				sprintf(line, " (%.20s) %s",
    779 					utf8localize(&tag),
    780 					sum_compound4args());
    781 				xdr_free(xdr_utf8string, (char *)&tag);
    782 			}
    783 			check_retransmit(line, xid);
    784 		} else {
    785 			(void) sprintf(line, "NFS R %s ",
    786 				    proc == NFSPROC4_COMPOUND ? "4" :
    787 					    procnames_short[proc]);
    788 			line += strlen(line);
    789 
    790 			if (proc == NFSPROC4_COMPOUND)
    791 				sum_comp4res(line, sum_compound4res);
    792 		}
    793 	}
    794 
    795 	if (flags & F_DTAIL) {
    796 		show_header("NFS:  ", "Sun NFS", len);
    797 		show_space();
    798 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    799 			proc, procnames_long[proc]);
    800 		if (proc == NFSPROC4_COMPOUND) {
    801 			if (type == CALL) {
    802 				showxdr_utf8string("Tag = %s");
    803 				detail_nfs_argop4();
    804 			} else {
    805 				nfsstat4 status;
    806 
    807 				status = getxdr_long();
    808 				showxdr_utf8string("Tag = %s");
    809 				sprintf(get_line(0, 0), "Status = %d (%s)",
    810 					status, status_name(status));
    811 				detail_nfs_resop4();
    812 			}
    813 		}
    814 		show_trailer();
    815 	}
    816 
    817 	utf8free();			/* cf. utf8localize() */
    818 }
    819 
    820 
    821 
    822 /*
    823  * Return the names and arguments of the oplist elements, up to
    824  * SUM_COMPND_MAX characters.  If the elements don't fit, include a "..."
    825  * at the end of the string.
    826  */
    827 
    828 static char *
    829 sum_compound4args(void)
    830 {
    831 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
    832 	int numops;
    833 	const size_t buflen = sizeof (buf);
    834 	char *bp;
    835 	nfs_argop4 one_op;
    836 	uint32_t minor_version;
    837 
    838 	buf[0] = '\0';
    839 
    840 	if (setjmp(xdr_err)) {
    841 		bp = buf + strlen(buf);
    842 		snprintf(bp, buflen - (bp - buf),
    843 			nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
    844 		return (buf);
    845 	}
    846 
    847 	/*
    848 	 * might be nice to print minor version, but doesn't
    849 	 * seem like very useful info for summary mode
    850 	 */
    851 	if (!xdr_uint32_t(&xdrm, &minor_version))
    852 		longjmp(xdr_err, 1);
    853 
    854 	numops = getxdr_long();
    855 	bp = buf;
    856 	while (numops-- > 0) {
    857 		char *operand;
    858 
    859 		bzero(&one_op, sizeof (one_op));
    860 
    861 		if (!xdr_nfs_argop4(&xdrm, &one_op)) {
    862 			xdr_free(xdr_nfs_argop4, (char *)&one_op);
    863 			longjmp(xdr_err, 1);
    864 		}
    865 		snprintf(bp, buflen - (bp - buf), "%s ",
    866 			opcode_name(one_op.argop));
    867 		bp += strlen(bp);
    868 
    869 		operand = sum_operand(&one_op);
    870 		if (strlen(operand) > 0) {
    871 			snprintf(bp, buflen - (bp - buf), "%s ", operand);
    872 			bp += strlen(bp);
    873 		}
    874 
    875 		/* nfs4_skip_bytes set by xdr_nfs4_argop4 */
    876 		if (nfs4_skip_bytes != 0)
    877 			nfs4_xdr_skip(nfs4_skip_bytes);
    878 
    879 		xdr_free(xdr_nfs_argop4, (char *)&one_op);
    880 
    881 		/* add "..." if past the "end" of the buffer */
    882 		if (bp - buf > SUM_COMPND_MAX) {
    883 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
    884 			    "...");
    885 			break;
    886 		}
    887 	}
    888 
    889 	return (buf);
    890 }
    891 
    892 static void
    893 nfs4_xdr_skip(int nbytes)
    894 {
    895 	int resid, off, len, cur_pos, new_pos;
    896 
    897 	len = RNDUP(nbytes);
    898 	cur_pos = xdr_getpos(&xdrm);
    899 
    900 	/*
    901 	 * Time to skip over the rd/wr data.  If the
    902 	 * rd/wr data is completely contained in the first
    903 	 * frag, we must skip over it to process the rest of
    904 	 * the packet.
    905 	 *
    906 	 * nfs4_pkt_start: XDR position of start of NFS4 compound
    907 	 * nfs4_pkt_len: number of bytes in pkt relative to
    908 	 *		 nfs4_pkt_start
    909 	 *
    910 	 * cur_pos: current XDR position
    911 	 * off: current XDR position relative to nfs4_pkt_start
    912 	 * resid: number of unprocessed bytes in current pkt
    913 	 *	  (relative to cur_pos/off)
    914 	 *
    915 	 * If nbytes <= resid, then we must skip over the rd/wr
    916 	 * bytes so we can read the next op/compound in this
    917 	 * packet.  Otherwise, set the fragged flag so we can
    918 	 * display the fragged_rpc message.
    919 	 */
    920 	off = cur_pos - nfs4_pkt_start;
    921 	resid = nfs4_pkt_len - off;
    922 
    923 	/*
    924 	 * set nfs4_fragged_rpc if the requested number of "skip"
    925 	 * bytes is larger than the bytes remaining in the XDR
    926 	 * stream/current packet.  The global is reset to 0 at
    927 	 * start of interpret_nfs4.
    928 	 */
    929 	new_pos = cur_pos + ((nfs4_fragged_rpc = len > resid) ? resid : len);
    930 
    931 	/* there's nothing to do for error case (if it fails pkt is doomed) */
    932 	xdr_setpos(&xdrm, new_pos);
    933 }
    934 
    935 
    936 /*
    937  * Return the names and arguments of the oplist elements, up to
    938  * SUM_COMPND_MAX characters.  If the elements don't fit, include a "..."
    939  * at the end of the string.
    940  */
    941 static char *
    942 sum_cb_compound4args(void)
    943 {
    944 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
    945 	int numops;
    946 	const size_t buflen = sizeof (buf);
    947 	char *bp;
    948 	nfs_cb_argop4 one_op;
    949 	uint32_t minor_version, callback_ident;
    950 
    951 	buf[0] = '\0';
    952 	if (setjmp(xdr_err)) {
    953 		bp = buf + strlen(buf);
    954 		snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
    955 			" RPC>");
    956 		return (buf);
    957 	}
    958 
    959 	/*
    960 	 * might be nice to print minor version, but doesn't
    961 	 * seem like very useful info for summary mode
    962 	 */
    963 	if (!xdr_uint32_t(&xdrm, &minor_version))
    964 		longjmp(xdr_err, 1);
    965 
    966 	/* print callback_ident */
    967 	if (!xdr_uint32_t(&xdrm, &callback_ident))
    968 		longjmp(xdr_err, 1);
    969 	snprintf(buf, buflen, "CBID=%u ", callback_ident);
    970 
    971 	bp = buf + strlen(buf);
    972 	numops = getxdr_long();
    973 
    974 	while (numops-- > 0) {
    975 		char *operand;
    976 
    977 		bzero(&one_op, sizeof (one_op));
    978 		if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) {
    979 			xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
    980 			longjmp(xdr_err, 1);
    981 		}
    982 
    983 		snprintf(bp, buflen - (bp - buf), "%s ",
    984 			cb_opcode_name(one_op.argop));
    985 		bp += strlen(bp);
    986 		operand = sum_cb_operand(&one_op);
    987 		if (strlen(operand) > 0) {
    988 			snprintf(bp, buflen - (bp - buf), "%s ", operand);
    989 			bp += strlen(bp);
    990 		}
    991 
    992 		xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
    993 
    994 		/* add "..." if past the "end" of the buffer */
    995 		if (bp - buf > SUM_COMPND_MAX) {
    996 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
    997 			    "...");
    998 			break;
    999 		}
   1000 	}
   1001 
   1002 	return (buf);
   1003 }
   1004 
   1005 /*
   1006  * Return the summarized argument list for the given nfs_argop4.
   1007  */
   1008 
   1009 static char *
   1010 sum_operand(nfs_argop4 *opp)
   1011 {
   1012 	static char buf[1024];
   1013 	void (*fmtproc)(char *, size_t, void *);
   1014 
   1015 	buf[0] = '\0';
   1016 	if (opp->argop < num_opcodes) {
   1017 		fmtproc = opcode_info[opp->argop].sumarg;
   1018 		if (fmtproc != NULL)
   1019 			fmtproc(buf, sizeof (buf), &opp->nfs_argop4_u);
   1020 	}
   1021 
   1022 	return (buf);
   1023 }
   1024 
   1025 /*
   1026  * Return the summarized argument list for the given nfs_argop4.
   1027  */
   1028 
   1029 static char *
   1030 sum_cb_operand(nfs_cb_argop4 *opp)
   1031 {
   1032 	static char buf[1024];
   1033 	void (*fmtproc)(char *, size_t, void *);
   1034 
   1035 	buf[0] = '\0';
   1036 	if (opp->argop < cb_num_opcodes) {
   1037 		fmtproc = cb_opcode_info[opp->argop].sumarg;
   1038 		if (fmtproc != NULL)
   1039 			fmtproc(buf, sizeof (buf), &opp->nfs_cb_argop4_u);
   1040 	}
   1041 
   1042 	return (buf);
   1043 }
   1044 
   1045 /*
   1046  * Print details about the nfs_argop4 that is next in the XDR stream.
   1047  */
   1048 
   1049 static void
   1050 detail_nfs_argop4(void)
   1051 {
   1052 	int numops;
   1053 	nfs_argop4 one_op;
   1054 	void (*fmtproc)(void *);
   1055 	uint32_t minor_version;
   1056 
   1057 	if (!xdr_uint32_t(&xdrm, &minor_version))
   1058 		longjmp(xdr_err, 1);
   1059 
   1060 	(void) sprintf(get_line(0, 0), "Minor version = %u",
   1061 		minor_version);
   1062 
   1063 	numops = getxdr_long();
   1064 	(void) sprintf(get_line(0, 0), "Number of operations = %d",
   1065 		    numops);
   1066 
   1067 	while (numops-- > 0) {
   1068 		bzero(&one_op, sizeof (one_op));
   1069 
   1070 		if (!xdr_nfs_argop4(&xdrm, &one_op)) {
   1071 			xdr_free(xdr_nfs_argop4, (char *)&one_op);
   1072 			longjmp(xdr_err, 1);
   1073 		}
   1074 
   1075 		get_line(0, 0);		/* blank line to separate ops */
   1076 		sprintf(get_line(0, 0), "Op = %d (%s)",
   1077 			one_op.argop, opcode_name(one_op.argop));
   1078 		if (one_op.argop < num_opcodes) {
   1079 			fmtproc = opcode_info[one_op.argop].dtlarg;
   1080 			if (fmtproc != NULL)
   1081 				fmtproc(&one_op.nfs_argop4_u);
   1082 		}
   1083 
   1084 		/* nfs4_skip_bytes set by xdr_nfs_argop4() */
   1085 		if (nfs4_skip_bytes)
   1086 			nfs4_xdr_skip(nfs4_skip_bytes);
   1087 
   1088 		xdr_free(xdr_nfs_argop4, (char *)&one_op);
   1089 	}
   1090 }
   1091 
   1092 
   1093 /*
   1094  * Print details about the nfs_argop4 that is next in the XDR stream.
   1095  */
   1096 static void
   1097 detail_cb_argop4(void)
   1098 {
   1099 	int numops;
   1100 	nfs_cb_argop4 one_op;
   1101 	void (*fmtproc)(void *);
   1102 	uint32_t minor_version, callback_ident;
   1103 
   1104 	if (!xdr_uint32_t(&xdrm, &minor_version))
   1105 		longjmp(xdr_err, 1);
   1106 	(void) sprintf(get_line(0, 0), "Minor version = %u",
   1107 		minor_version);
   1108 
   1109 	if (!xdr_uint32_t(&xdrm, &callback_ident))
   1110 		longjmp(xdr_err, 1);
   1111 	(void) sprintf(get_line(0, 0), "Callback Ident = %u",
   1112 		callback_ident);
   1113 
   1114 	numops = getxdr_long();
   1115 	(void) sprintf(get_line(0, 0), "Number of operations = %d",
   1116 		    numops);
   1117 
   1118 	while (numops-- > 0) {
   1119 		bzero(&one_op, sizeof (one_op));
   1120 		if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) {
   1121 			xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
   1122 			longjmp(xdr_err, 1);
   1123 		}
   1124 
   1125 		get_line(0, 0);		/* blank line to separate ops */
   1126 		sprintf(get_line(0, 0), "Op = %d (%s)",
   1127 			one_op.argop, cb_opcode_name(one_op.argop));
   1128 		if (one_op.argop < cb_num_opcodes) {
   1129 			fmtproc = cb_opcode_info[one_op.argop].dtlarg;
   1130 			if (fmtproc != NULL)
   1131 				fmtproc(&one_op.nfs_cb_argop4_u);
   1132 		}
   1133 
   1134 		xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
   1135 	}
   1136 }
   1137 
   1138 /*
   1139  * component_name: return a printable string for the given component4.  I'm
   1140  * leaving this as a separate function (as opposed to having the callers
   1141  * call utf8localize() directly) in case the definition of component4
   1142  * changes.
   1143  */
   1144 
   1145 static char *
   1146 component_name(component4 *cp)
   1147 {
   1148 	return (utf8localize(cp));
   1149 }
   1150 
   1151 /*
   1152  * linktext_name.  cf. component_name().
   1153  */
   1154 
   1155 static char *
   1156 linktext_name(linktext4 *lp)
   1157 {
   1158 	return (utf8localize(lp));
   1159 }
   1160 
   1161 /*
   1162  * stable_how4_name: return a string for "how".
   1163  */
   1164 
   1165 static char *
   1166 stable_how4_name(stable_how4 how)
   1167 {
   1168 	char *result;
   1169 
   1170 	switch (how) {
   1171 	case UNSTABLE4:
   1172 		result = "ASYNC";
   1173 		break;
   1174 	case DATA_SYNC4:
   1175 		result = "DSYNC";
   1176 		break;
   1177 	case FILE_SYNC4:
   1178 		result = "FSYNC";
   1179 		break;
   1180 	default:
   1181 		result = "?";
   1182 		break;
   1183 	}
   1184 
   1185 	return (result);
   1186 }
   1187 
   1188 /*
   1189  * sum_open_share_access: return a string corresponding to the
   1190  * given OPEN share access bitmask.
   1191  */
   1192 
   1193 static char *
   1194 sum_open_share_access(int32_t mask)
   1195 {
   1196 	char *result;
   1197 
   1198 	switch (mask) {
   1199 	case 0:
   1200 		result = "N";
   1201 		break;
   1202 	case OPEN4_SHARE_ACCESS_READ:
   1203 		result = "R";
   1204 		break;
   1205 	case OPEN4_SHARE_ACCESS_WRITE:
   1206 		result = "W";
   1207 		break;
   1208 	case OPEN4_SHARE_ACCESS_BOTH:
   1209 		result = "RW";
   1210 		break;
   1211 	default:
   1212 		result = "?";
   1213 		break;
   1214 	}
   1215 
   1216 	return (result);
   1217 }
   1218 
   1219 /*
   1220  * sum_open_share_deny: return a string corresponding to the
   1221  * given OPEN share deny bitmask.
   1222  */
   1223 
   1224 static char *
   1225 sum_open_share_deny(int32_t mask)
   1226 {
   1227 	char *result;
   1228 
   1229 	switch (mask) {
   1230 	case OPEN4_SHARE_DENY_NONE:
   1231 		result = "N";
   1232 		break;
   1233 	case OPEN4_SHARE_DENY_READ:
   1234 		result = "R";
   1235 		break;
   1236 	case OPEN4_SHARE_DENY_WRITE:
   1237 		result = "W";
   1238 		break;
   1239 	case OPEN4_SHARE_DENY_BOTH:
   1240 		result = "RW";
   1241 		break;
   1242 	default:
   1243 		result = "?";
   1244 		break;
   1245 	}
   1246 
   1247 	return (result);
   1248 }
   1249 
   1250 static int
   1251 special_stateid(stateid4 *stateid)
   1252 {
   1253 
   1254 	if (! memcmp(stateid, &spec_stateid_0, sizeof (*stateid)))
   1255 		return (0);
   1256 
   1257 	if (! memcmp(stateid, &spec_stateid_1, sizeof (*stateid)))
   1258 		return (1);
   1259 
   1260 	return (-1);
   1261 }
   1262 
   1263 static char *
   1264 _sum_stateid(stateid4 *stateid, char *prefix)
   1265 {
   1266 	static char buf[32];
   1267 	int spec;
   1268 
   1269 	if ((spec = special_stateid(stateid)) < 0)
   1270 		snprintf(buf, sizeof (buf), "%s%04X:%u", prefix,
   1271 			stateid_hash(stateid), stateid->seqid);
   1272 	else
   1273 		snprintf(buf, sizeof (buf), "%s%s", prefix,
   1274 			spec == 0 ? "SPC0" : (spec == 1 ? "SPC1" : "SPC?"));
   1275 	return (buf);
   1276 }
   1277 
   1278 static void
   1279 _detail_stateid(stateid4 *stateid, char *prefix)
   1280 {
   1281 	int spec;
   1282 	char seqstr[32] = {0};
   1283 
   1284 	spec = special_stateid(stateid);
   1285 
   1286 	if (spec < 0)
   1287 		sprintf(get_line(0, 0), "%sState ID hash = %04X",
   1288 			prefix, stateid_hash(stateid));
   1289 	else
   1290 		sprintf(get_line(0, 0), "%sState ID hash = %s",	prefix,
   1291 			spec == 0 ? "SPECIAL_0" :
   1292 				(spec == 1 ? "SPECIAL_1" : "SPECIAL_?"));
   1293 
   1294 	sprintf(get_line(0, 0), "    len = %u    val = %s",
   1295 		sizeof (stateid->other),
   1296 		tohex(stateid->other, sizeof (stateid->other)));
   1297 
   1298 	/*
   1299 	 * If spec 0/1 stateid, print seqid in hex; otherwise,
   1300 	 * use decimal.  This makes it more clear how spec stateids
   1301 	 * are constructed [obvious that either all bits are 0, or all
   1302 	 * bits are 1].
   1303 	 */
   1304 	if (spec == -1)
   1305 		sprintf(seqstr, "%d", stateid->seqid);
   1306 	else
   1307 		sprintf(seqstr, "%08X", stateid->seqid);
   1308 
   1309 	sprintf(get_line(0, 0), "    %sState ID Sequence ID = %s",
   1310 		prefix, seqstr);
   1311 }
   1312 
   1313 
   1314 static char *
   1315 sum_lock_denied(LOCK4denied *denied)
   1316 {
   1317 	static char buf[64];
   1318 
   1319 	sprintf(buf, "%s %llu %llu LO=%04X",
   1320 		sum_lock_type_name(denied->locktype),
   1321 		denied->offset, denied->length,
   1322 		owner_hash(&denied->owner.owner));
   1323 
   1324 	return (buf);
   1325 }
   1326 
   1327 static void
   1328 detail_lock_denied(LOCK4denied *denied)
   1329 {
   1330 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(denied->locktype));
   1331 	detail_lock_owner(&denied->owner);
   1332 	sprintf(get_line(0, 0), "Offset = %llu", denied->offset);
   1333 	sprintf(get_line(0, 0), "Length = %llu", denied->length);
   1334 }
   1335 
   1336 /*
   1337  * sum_createhow4: return the string name of "how".
   1338  */
   1339 
   1340 static char *
   1341 createhow4_name(createhow4 *crtp)
   1342 {
   1343 	char *result;
   1344 
   1345 	switch (crtp->mode) {
   1346 	case UNCHECKED4:
   1347 		result = "UNCHECKED";
   1348 		break;
   1349 	case GUARDED4:
   1350 		result = "GUARDED";
   1351 		break;
   1352 	case EXCLUSIVE4:
   1353 		result = "EXCLUSIVE";
   1354 		break;
   1355 	default:
   1356 		result = "?";
   1357 		break;
   1358 	}
   1359 
   1360 	return (result);
   1361 }
   1362 
   1363 /*
   1364  * detail_createhow4: print detail information about "how".
   1365  */
   1366 
   1367 static void
   1368 detail_createhow4(createhow4 *crtp)
   1369 {
   1370 	sprintf(get_line(0, 0), "Method = %s",
   1371 		createhow4_name(crtp));
   1372 
   1373 	switch (crtp->mode) {
   1374 	case UNCHECKED4:
   1375 	case GUARDED4:
   1376 		detail_fattr4(&crtp->createhow4_u.createattrs);
   1377 		break;
   1378 	case EXCLUSIVE4:
   1379 		sprintf(get_line(0, 0), "  Verifier = %s",
   1380 			tohex(crtp->createhow4_u.createverf,
   1381 				NFS4_VERIFIER_SIZE));
   1382 		break;
   1383 	}
   1384 }
   1385 
   1386 static void
   1387 detail_createtype4(createtype4 *crtp)
   1388 {
   1389 	sprintf(get_line(0, 0), "Type = %s",
   1390 		detail_type_name(crtp->type));
   1391 	switch (crtp->type) {
   1392 	case NF4LNK:
   1393 		sprintf(get_line(0, 0), "Linkdata = %s",
   1394 			utf8localize(&crtp->createtype4_u.linkdata));
   1395 		break;
   1396 	case NF4BLK:
   1397 	case NF4CHR:
   1398 		sprintf(get_line(0, 0), "Specdata1 = %04x Specdata2 = %04x",
   1399 			crtp->createtype4_u.devdata.specdata1,
   1400 			crtp->createtype4_u.devdata.specdata2);
   1401 		break;
   1402 	default:
   1403 		break;
   1404 	}
   1405 }
   1406 
   1407 static void
   1408 sumarg_access(char *buf, size_t buflen, void *obj)
   1409 {
   1410 	ACCESS4args *args = (ACCESS4args *)obj;
   1411 
   1412 	sum_access4(buf, buflen, args->access);
   1413 }
   1414 
   1415 static void
   1416 dtlarg_access(void *obj)
   1417 {
   1418 	ACCESS4args *args = (ACCESS4args *)obj;
   1419 
   1420 	detail_access4("Access bits", args->access);
   1421 }
   1422 
   1423 static void
   1424 sumarg_close(char *buf, size_t buflen, void *obj)
   1425 {
   1426 	CLOSE4args *args = (CLOSE4args *)obj;
   1427 
   1428 	snprintf(buf, buflen, "SQ=%u %s",
   1429 		args->seqid, sum_open_stateid(&args->open_stateid));
   1430 }
   1431 
   1432 static void
   1433 dtlarg_close(void *obj)
   1434 {
   1435 	CLOSE4args *args = (CLOSE4args *)obj;
   1436 
   1437 	detail_open_stateid(&args->open_stateid);
   1438 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
   1439 }
   1440 
   1441 static void
   1442 sumarg_commit(char *buf, size_t buflen, void *obj)
   1443 {
   1444 	COMMIT4args *args = (COMMIT4args *)obj;
   1445 
   1446 	snprintf(buf, buflen, "at %llu for %u ", args->offset,
   1447 		args->count);
   1448 }
   1449 
   1450 static void
   1451 dtlarg_commit(void *obj)
   1452 {
   1453 	COMMIT4args *args = (COMMIT4args *)obj;
   1454 
   1455 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   1456 	sprintf(get_line(0, 0), "Count = %u", args->count);
   1457 }
   1458 
   1459 static void
   1460 sumarg_compnt(char *buf, size_t buflen, void *obj)
   1461 {
   1462 	component4 *comp = (component4 *)obj;
   1463 
   1464 	snprintf(buf, buflen, "%s", component_name(comp));
   1465 }
   1466 
   1467 static void
   1468 dtlarg_compnt(void *obj)
   1469 {
   1470 	component4 *comp = (component4 *)obj;
   1471 
   1472 	sprintf(get_line(0, 0), "Name = %s", component_name(comp));
   1473 }
   1474 
   1475 static void
   1476 sumarg_create(char *buf, size_t buflen, void *obj)
   1477 {
   1478 	CREATE4args *args = (CREATE4args *)obj;
   1479 
   1480 	snprintf(buf, buflen, "%s %s ", component_name(&args->objname),
   1481 		sum_type_name(args->objtype.type));
   1482 }
   1483 
   1484 static void
   1485 dtlarg_create(void *obj)
   1486 {
   1487 	CREATE4args *args = (CREATE4args *)obj;
   1488 
   1489 	sprintf(get_line(0, 0), "Name = %s", component_name(&args->objname));
   1490 	detail_createtype4(&args->objtype);
   1491 	detail_fattr4(&args->createattrs);
   1492 }
   1493 
   1494 static void
   1495 sumarg_delprge(char *buf, size_t buflen, void *obj)
   1496 {
   1497 	DELEGPURGE4args *args = (DELEGPURGE4args *)obj;
   1498 
   1499 	snprintf(buf, buflen, "%s", sum_clientid(args->clientid));
   1500 }
   1501 
   1502 static void
   1503 dtlarg_delprge(void *obj)
   1504 {
   1505 	DELEGPURGE4args *args = (DELEGPURGE4args *)obj;
   1506 
   1507 	detail_clientid(args->clientid);
   1508 }
   1509 
   1510 static void
   1511 sumarg_delret(char *buf, size_t buflen, void *obj)
   1512 {
   1513 	DELEGRETURN4args *args = (DELEGRETURN4args *)obj;
   1514 
   1515 	snprintf(buf, buflen, "%s", sum_deleg_stateid(&args->deleg_stateid));
   1516 }
   1517 
   1518 static void
   1519 dtlarg_delret(void *obj)
   1520 {
   1521 	DELEGRETURN4args *args = (DELEGRETURN4args *)obj;
   1522 
   1523 	detail_deleg_stateid(&args->deleg_stateid);
   1524 }
   1525 
   1526 static void
   1527 sumarg_getattr(char *buf, size_t buflen, void *obj)
   1528 {
   1529 	GETATTR4args *args = (GETATTR4args *)obj;
   1530 
   1531 	sum_attr_bitmap(buf, buflen, &args->attr_request);
   1532 }
   1533 
   1534 static void
   1535 dtlarg_getattr(void *obj)
   1536 {
   1537 	GETATTR4args *args = (GETATTR4args *)obj;
   1538 
   1539 	detail_attr_bitmap("", &args->attr_request, NULL);
   1540 }
   1541 
   1542 static void
   1543 sumarg_cb_getattr(char *buf, size_t buflen, void *obj)
   1544 {
   1545 	CB_GETATTR4args *args = (CB_GETATTR4args *)obj;
   1546 	char *bp = buf;
   1547 
   1548 	snprintf(bp, buflen, "%s ", sum_fh4(&args->fh));
   1549 	bp += strlen(bp);
   1550 	sum_attr_bitmap(bp, buflen - (bp - buf), &args->attr_request);
   1551 }
   1552 
   1553 static void
   1554 dtlarg_cb_getattr(void *obj)
   1555 {
   1556 	CB_GETATTR4args *args = (CB_GETATTR4args *)obj;
   1557 
   1558 	detail_fh4(&args->fh);
   1559 	detail_attr_bitmap("", &args->attr_request, NULL);
   1560 }
   1561 
   1562 static void
   1563 sumarg_cb_recall(char *buf, size_t buflen, void *obj)
   1564 {
   1565 	CB_RECALL4args *args = (CB_RECALL4args *)obj;
   1566 	char *bp = buf;
   1567 
   1568 	snprintf(bp, buflen, "%s %s TR=%s", sum_fh4(&args->fh),
   1569 		sum_stateid(&args->stateid), args->truncate ? "T" : "F");
   1570 }
   1571 
   1572 static void
   1573 dtlarg_cb_recall(void *obj)
   1574 {
   1575 	CB_RECALL4args *args = (CB_RECALL4args *)obj;
   1576 
   1577 	detail_fh4(&args->fh);
   1578 	detail_stateid(&args->stateid);
   1579 	sprintf(get_line(0, 0), "Truncate = %s",
   1580 		args->truncate ? "True" : "False");
   1581 }
   1582 
   1583 
   1584 /*
   1585  * name openhow seqid claim access deny owner
   1586  */
   1587 static void
   1588 sumarg_open(char *buf, size_t buflen, void *obj)
   1589 {
   1590 	OPEN4args *args = (OPEN4args *)obj;
   1591 	char *bp = buf;
   1592 	int blen = buflen, len;
   1593 
   1594 	sum_name(bp, buflen, &args->claim);
   1595 	bp += (len = strlen(bp));
   1596 	blen -= len;
   1597 
   1598 	sum_openflag(bp, blen, &args->openhow);
   1599 	bp += (len = strlen(bp));
   1600 	blen -= len;
   1601 
   1602 	snprintf(bp, blen, " SQ=%u", args->seqid);
   1603 	bp += (len = strlen(bp));
   1604 	blen -= len;
   1605 
   1606 	sum_claim(bp, blen, &args->claim);
   1607 	bp += (len = strlen(bp));
   1608 	blen -= len;
   1609 
   1610 	snprintf(bp, blen, " AC=%s DN=%s OO=%04X",
   1611 		sum_open_share_access(args->share_access),
   1612 		sum_open_share_deny(args->share_deny),
   1613 				owner_hash(&args->owner.owner));
   1614 }
   1615 
   1616 static void
   1617 dtlarg_open(void *obj)
   1618 {
   1619 	OPEN4args *args = (OPEN4args *)obj;
   1620 
   1621 	detail_claim(&args->claim);
   1622 	detail_openflag(&args->openhow);
   1623 	detail_open_owner(&args->owner);
   1624 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
   1625 	sprintf(get_line(0, 0), "Access = 0x%x (%s)",
   1626 		args->share_access, sum_open_share_access(args->share_access));
   1627 	sprintf(get_line(0, 0), "Deny   = 0x%x (%s)",
   1628 		args->share_deny, sum_open_share_access(args->share_deny));
   1629 }
   1630 
   1631 static void
   1632 sumarg_openattr(char *buf, size_t buflen, void *obj)
   1633 {
   1634 	OPENATTR4args *args = (OPENATTR4args *)obj;
   1635 
   1636 	snprintf(buf, buflen, "CD=%s",
   1637 		args->createdir ? "T" : "F");
   1638 }
   1639 
   1640 static void
   1641 dtlarg_openattr(void *obj)
   1642 {
   1643 	OPENATTR4args *args = (OPENATTR4args *)obj;
   1644 
   1645 	sprintf(get_line(0, 0), "CreateDir = %s",
   1646 		args->createdir ? "True" : "False");
   1647 }
   1648 
   1649 static void
   1650 sumarg_open_confirm(char *buf, size_t buflen, void *obj)
   1651 {
   1652 	char *bp = buf;
   1653 	OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj;
   1654 
   1655 	snprintf(bp, buflen, "SQ=%u %s", args->seqid,
   1656 		sum_open_stateid(&args->open_stateid));
   1657 }
   1658 
   1659 static void
   1660 dtlarg_open_confirm(void *obj)
   1661 {
   1662 	OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj;
   1663 
   1664 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
   1665 	detail_open_stateid(&args->open_stateid);
   1666 }
   1667 
   1668 static void
   1669 sumarg_open_downgrd(char *buf, size_t buflen, void *obj)
   1670 {
   1671 	OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj;
   1672 
   1673 	snprintf(buf, buflen, "SQ=%u %s AC=%s DN=%s",
   1674 		args->seqid, sum_open_stateid(&args->open_stateid),
   1675 		sum_open_share_access(args->share_access),
   1676 		sum_open_share_deny(args->share_deny));
   1677 }
   1678 
   1679 static void
   1680 dtlarg_open_downgrd(void *obj)
   1681 {
   1682 	OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj;
   1683 
   1684 	sprintf(get_line(0, 0), "Open Sequence ID = %u", args->seqid);
   1685 	detail_open_stateid(&args->open_stateid);
   1686 	sprintf(get_line(0, 0), "Access = 0x%x (%s)",
   1687 		args->share_access, sum_open_share_access(args->share_access));
   1688 	sprintf(get_line(0, 0), "Deny   = 0x%x (%s)",
   1689 		args->share_deny, sum_open_share_access(args->share_deny));
   1690 }
   1691 
   1692 static void
   1693 sumarg_putfh(char *buf, size_t buflen, void *obj)
   1694 {
   1695 	PUTFH4args *args = (PUTFH4args *)obj;
   1696 
   1697 	snprintf(buf, buflen, "%s", sum_fh4(&args->object));
   1698 }
   1699 
   1700 static void
   1701 dtlarg_putfh(void *obj)
   1702 {
   1703 	PUTFH4args *args = (PUTFH4args *)obj;
   1704 
   1705 	detail_fh4(&args->object);
   1706 }
   1707 
   1708 static void
   1709 sumarg_link(char *buf, size_t buflen, void *obj)
   1710 {
   1711 	LINK4args *args = (LINK4args *)obj;
   1712 
   1713 	snprintf(buf, buflen, "%s", component_name(&args->newname));
   1714 }
   1715 
   1716 static void
   1717 dtlarg_link(void *obj)
   1718 {
   1719 	LINK4args *args = (LINK4args *)obj;
   1720 
   1721 	sprintf(get_line(0, 0), "New name = %s",
   1722 		component_name(&args->newname));
   1723 }
   1724 
   1725 static void
   1726 sum_open_to_lock_owner(char *buf, int buflen, open_to_lock_owner4 *own)
   1727 {
   1728 	snprintf(buf, buflen, " OSQ=%u %s LSQ=%u LO=%04X", own->open_seqid,
   1729 		sum_open_stateid(&own->open_stateid), own->lock_seqid,
   1730 		owner_hash(&own->lock_owner.owner));
   1731 }
   1732 
   1733 static void
   1734 sum_exist_lock_owner(char *buf, int buflen, exist_lock_owner4 *own)
   1735 {
   1736 	snprintf(buf, buflen, " LSQ=%u %s", own->lock_seqid,
   1737 		sum_lock_stateid(&own->lock_stateid));
   1738 }
   1739 
   1740 static void
   1741 sum_locker(char *buf, size_t len, locker4 *lk)
   1742 {
   1743 	if (lk->new_lock_owner == TRUE)
   1744 		sum_open_to_lock_owner(buf, len, &lk->locker4_u.open_owner);
   1745 	else
   1746 		sum_exist_lock_owner(buf, len, &lk->locker4_u.lock_owner);
   1747 }
   1748 
   1749 static char *
   1750 sum_lock_type_name(enum nfs_lock_type4 type)
   1751 {
   1752 	char *result;
   1753 
   1754 	switch (type) {
   1755 	case READ_LT:
   1756 		result = "RD";
   1757 		break;
   1758 	case WRITE_LT:
   1759 		result = "WR";
   1760 		break;
   1761 	case READW_LT:
   1762 		result = "RDW";
   1763 		break;
   1764 	case WRITEW_LT:
   1765 		result = "WRW";
   1766 		break;
   1767 	default:
   1768 		result = "?";
   1769 		break;
   1770 	}
   1771 
   1772 	return (result);
   1773 }
   1774 
   1775 static void
   1776 sumarg_lock(char *buf, size_t buflen, void *obj)
   1777 {
   1778 	LOCK4args *args = (LOCK4args *)obj;
   1779 	char *bp = buf;
   1780 
   1781 	snprintf(buf, buflen, "%s%s%llu:%llu",
   1782 		sum_lock_type_name(args->locktype),
   1783 		args->reclaim ? " reclaim " : " ",
   1784 		args->offset, args->length);
   1785 
   1786 	bp += strlen(buf);
   1787 	sum_locker(bp, buflen - (bp - buf), &args->locker);
   1788 }
   1789 
   1790 static void
   1791 detail_open_to_lock_owner(open_to_lock_owner4 *own)
   1792 {
   1793 	sprintf(get_line(0, 0), "Open Sequence ID = %u", own->open_seqid);
   1794 	detail_open_stateid(&own->open_stateid);
   1795 	sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid);
   1796 	detail_lock_owner(&own->lock_owner);
   1797 }
   1798 
   1799 static void
   1800 detail_exist_lock_owner(exist_lock_owner4 *own)
   1801 {
   1802 	detail_lock_stateid(&own->lock_stateid);
   1803 	sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid);
   1804 }
   1805 
   1806 static void
   1807 detail_locker(locker4 *lk)
   1808 {
   1809 	if (lk->new_lock_owner == TRUE)
   1810 		detail_open_to_lock_owner(&lk->locker4_u.open_owner);
   1811 	else
   1812 		detail_exist_lock_owner(&lk->locker4_u.lock_owner);
   1813 }
   1814 
   1815 static void
   1816 dtlarg_lock(void *obj)
   1817 {
   1818 	LOCK4args *args = (LOCK4args *)obj;
   1819 
   1820 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
   1821 	sprintf(get_line(0, 0), "Reclaim = %s",
   1822 		args->reclaim ? "TRUE" : "FALSE");
   1823 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   1824 	sprintf(get_line(0, 0), "Length = %llu", args->length);
   1825 	detail_locker(&args->locker);
   1826 }
   1827 
   1828 static void
   1829 sumarg_lockt(char *buf, size_t buflen, void *obj)
   1830 {
   1831 	LOCKT4args *args = (LOCKT4args *)obj;
   1832 
   1833 	snprintf(buf, buflen, "R=%llu:%llu",
   1834 		args->offset, args->length);
   1835 }
   1836 
   1837 static void
   1838 dtlarg_lockt(void *obj)
   1839 {
   1840 	LOCKT4args *args = (LOCKT4args *)obj;
   1841 
   1842 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
   1843 	detail_lock_owner(&args->owner);
   1844 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   1845 	sprintf(get_line(0, 0), "Length = %llu", args->length);
   1846 }
   1847 
   1848 static void
   1849 sumarg_locku(char *buf, size_t buflen, void *obj)
   1850 {
   1851 	LOCKU4args *args = (LOCKU4args *)obj;
   1852 
   1853 	snprintf(buf, buflen, "R=%llu:%llu LSQ=%u %s",
   1854 		args->offset, args->length, args->seqid,
   1855 		sum_lock_stateid(&args->lock_stateid));
   1856 }
   1857 
   1858 
   1859 static void
   1860 dtlarg_locku(void *obj)
   1861 {
   1862 	LOCKU4args *args = (LOCKU4args *)obj;
   1863 
   1864 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
   1865 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
   1866 	detail_lock_stateid(&args->lock_stateid);
   1867 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   1868 	sprintf(get_line(0, 0), "Length = %llu", args->length);
   1869 }
   1870 
   1871 static void
   1872 sumarg_lookup(char *buf, size_t buflen, void *obj)
   1873 {
   1874 	LOOKUP4args *args = (LOOKUP4args *)obj;
   1875 
   1876 	sum_compname4(buf, buflen, &args->objname);
   1877 }
   1878 
   1879 static void
   1880 dtlarg_lookup(void *obj)
   1881 {
   1882 	LOOKUP4args *args = (LOOKUP4args *)obj;
   1883 
   1884 	detail_compname4(&args->objname);
   1885 }
   1886 
   1887 static void
   1888 sumarg_read(char *buf, size_t buflen, void *obj)
   1889 {
   1890 	READ4args *args = (READ4args *)obj;
   1891 
   1892 	snprintf(buf, buflen, "%s at %llu for %u",
   1893 		sum_stateid(&args->stateid), args->offset, args->count);
   1894 }
   1895 
   1896 static void
   1897 dtlarg_read(void *obj)
   1898 {
   1899 	READ4args *args = (READ4args *)obj;
   1900 
   1901 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   1902 	sprintf(get_line(0, 0), "Count = %u", args->count);
   1903 	detail_stateid(&args->stateid);
   1904 }
   1905 
   1906 static void
   1907 sumarg_readdir(char *buf, size_t buflen, void *obj)
   1908 {
   1909 	READDIR4args *args = (READDIR4args *)obj;
   1910 
   1911 	snprintf(buf, buflen, "Cookie=%llu (%s) for %u/%u",
   1912 		args->cookie, tohex(args->cookieverf, NFS4_VERIFIER_SIZE),
   1913 		args->dircount, args->maxcount);
   1914 }
   1915 
   1916 static void
   1917 dtlarg_readdir(void *obj)
   1918 {
   1919 	READDIR4args *args = (READDIR4args *)obj;
   1920 
   1921 	sprintf(get_line(0, 0), "Cookie = %llu", args->cookie);
   1922 	sprintf(get_line(0, 0), "Verifier = %s",
   1923 		tohex(args->cookieverf, NFS4_VERIFIER_SIZE));
   1924 	sprintf(get_line(0, 0), "Dircount = %u", args->dircount);
   1925 	sprintf(get_line(0, 0), "Maxcount = %u", args->maxcount);
   1926 	detail_attr_bitmap("", &args->attr_request, NULL);
   1927 }
   1928 
   1929 static void
   1930 dtlarg_release_lkown(void *obj)
   1931 {
   1932 	RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj;
   1933 
   1934 	detail_lock_owner(&args->lock_owner);
   1935 }
   1936 
   1937 static void
   1938 sumarg_release_lkown(char *buf, size_t buflen, void *obj)
   1939 
   1940 {
   1941 	RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj;
   1942 
   1943 	snprintf(buf, buflen, "LO=%04X", owner_hash(&args->lock_owner.owner));
   1944 }
   1945 
   1946 static void
   1947 sumarg_rename(char *buf, size_t buflen, void *obj)
   1948 {
   1949 	RENAME4args *args = (RENAME4args *)obj;
   1950 
   1951 	snprintf(buf, buflen, "%s to %s",
   1952 		component_name(&args->oldname),
   1953 		component_name(&args->newname));
   1954 }
   1955 
   1956 static void
   1957 dtlarg_rename(void *obj)
   1958 {
   1959 	RENAME4args *args = (RENAME4args *)obj;
   1960 
   1961 	sprintf(get_line(0, 0), "Old name = %s",
   1962 		component_name(&args->oldname));
   1963 	sprintf(get_line(0, 0), "New name = %s",
   1964 		component_name(&args->newname));
   1965 }
   1966 
   1967 static void
   1968 sumarg_renew(char *buf, size_t buflen, void *obj)
   1969 {
   1970 	RENEW4args *args = (RENEW4args *)obj;
   1971 
   1972 	snprintf(buf, buflen, "%s", sum_clientid(args->clientid));
   1973 }
   1974 static void
   1975 dtlarg_renew(void *obj)
   1976 {
   1977 	RENEW4args *args = (RENEW4args *)obj;
   1978 
   1979 	detail_clientid(args->clientid);
   1980 }
   1981 
   1982 static void
   1983 sumarg_secinfo(char *buf, size_t buflen, void *obj)
   1984 {
   1985 	SECINFO4args *args = (SECINFO4args *)obj;
   1986 
   1987 	snprintf(buf, buflen, "%s",
   1988 		component_name(&args->name));
   1989 }
   1990 
   1991 static void
   1992 dtlarg_secinfo(void *obj)
   1993 {
   1994 	SECINFO4args *args = (SECINFO4args *)obj;
   1995 
   1996 	sprintf(get_line(0, 0), "Name = %s",
   1997 		component_name(&args->name));
   1998 }
   1999 
   2000 static void
   2001 sumarg_setattr(char *buf, size_t buflen, void *obj)
   2002 {
   2003 	SETATTR4args *args = (SETATTR4args *)obj;
   2004 
   2005 	snprintf(buf, buflen, "%s", sum_stateid(&args->stateid));
   2006 }
   2007 
   2008 static void
   2009 dtlarg_setattr(void *obj)
   2010 {
   2011 	SETATTR4args *args = (SETATTR4args *)obj;
   2012 
   2013 	detail_stateid(&args->stateid);
   2014 	detail_fattr4(&args->obj_attributes);
   2015 }
   2016 
   2017 static void
   2018 sumarg_setclid(char *buf, size_t buflen, void *obj)
   2019 {
   2020 	SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
   2021 
   2022 	snprintf(buf, buflen, "Prog=%u ID=%s Addr=%s CBID=%u",
   2023 		args->callback.cb_program,
   2024 		args->callback.cb_location.r_netid,
   2025 		args->callback.cb_location.r_addr, args->callback_ident);
   2026 }
   2027 
   2028 static void
   2029 dtlarg_setclid(void *obj)
   2030 {
   2031 	SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
   2032 
   2033 	sprintf(get_line(0, 0), "Verifier=%s",
   2034 		tohex(args->client.verifier, NFS4_VERIFIER_SIZE));
   2035 	sprintf(get_line(0, 0), "ID = (%d) %s",
   2036 		args->client.id.id_len,
   2037 		tohex(args->client.id.id_val, args->client.id.id_len));
   2038 
   2039 	sprintf(get_line(0, 0), "Callback Program = %u",
   2040 		args->callback.cb_program);
   2041 	sprintf(get_line(0, 0), "Callback Net ID = %s",
   2042 		args->callback.cb_location.r_netid);
   2043 	sprintf(get_line(0, 0), "Callback Addr = %s",
   2044 		args->callback.cb_location.r_addr);
   2045 	sprintf(get_line(0, 0), "Callback Ident = %u", args->callback_ident);
   2046 }
   2047 
   2048 static void
   2049 sumarg_setclid_cfm(char *buf, size_t buflen, void *obj)
   2050 {
   2051 	SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj;
   2052 
   2053 	snprintf(buf, buflen, "%s CFV=%s", sum_clientid(args->clientid),
   2054 		tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
   2055 }
   2056 
   2057 static void
   2058 dtlarg_setclid_cfm(void *obj)
   2059 {
   2060 	SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj;
   2061 
   2062 	detail_clientid(args->clientid);
   2063 	sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
   2064 		tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
   2065 }
   2066 
   2067 
   2068 static void
   2069 dtlarg_verify(void *obj)
   2070 {
   2071 	NVERIFY4args *args = (NVERIFY4args *)obj;
   2072 
   2073 	detail_fattr4(&args->obj_attributes);
   2074 }
   2075 
   2076 static void
   2077 sumarg_write(char *buf, size_t buflen, void *obj)
   2078 {
   2079 	WRITE4args *args = (WRITE4args *)obj;
   2080 
   2081 	snprintf(buf, buflen, "%s at %llu for %u",
   2082 		sum_stateid(&args->stateid), args->offset, args->data.data_len);
   2083 }
   2084 
   2085 static void
   2086 dtlarg_write(void *obj)
   2087 {
   2088 	WRITE4args *args = (WRITE4args *)obj;
   2089 
   2090 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
   2091 	sprintf(get_line(0, 0), "Count = %u", args->data.data_len);
   2092 	sprintf(get_line(0, 0), "Stable = %s", stable_how4_name(args->stable));
   2093 	detail_stateid(&args->stateid);
   2094 }
   2095 
   2096 static char *
   2097 sum_fh4(nfs_fh4 *fh)
   2098 {
   2099 	static char buf[20];
   2100 
   2101 	sprintf(buf, "FH=%04X", fh4_hash(fh));
   2102 
   2103 	return (buf);
   2104 }
   2105 
   2106 static void
   2107 detail_fh4(nfs_fh4 *fh)
   2108 {
   2109 	int i;
   2110 	uchar_t *cp;
   2111 	char *bufp;
   2112 
   2113 	sprintf(get_line(0, 0), "File handle = [%04X]", fh4_hash(fh));
   2114 	bufp = get_line(0, 0);
   2115 	sprintf(bufp, "(%d) ", fh->nfs_fh4_len);
   2116 	bufp += strlen(bufp);
   2117 	/* XXX use tohex()? */
   2118 	for (i = 0, cp = (uchar_t *)fh->nfs_fh4_val;
   2119 	    i < fh->nfs_fh4_len;
   2120 	    i++, cp++) {
   2121 		if (i != 0 && i % 32 == 0)
   2122 			bufp = get_line(0, 0);
   2123 		sprintf(bufp, "%02x", *cp);
   2124 		bufp += strlen(bufp);
   2125 	}
   2126 }
   2127 
   2128 static void
   2129 detail_fattr4(fattr4 *attrp)
   2130 {
   2131 	unpkd_attrmap_t provided;
   2132 	uint_t attrnum;
   2133 	XDR attrxdr;
   2134 	jmp_buf old_errbuf;
   2135 
   2136 	xdrmem_create(&attrxdr, attrp->attr_vals.attrlist4_val,
   2137 		    attrp->attr_vals.attrlist4_len, XDR_DECODE);
   2138 
   2139 	bcopy(xdr_err, old_errbuf, sizeof (old_errbuf));
   2140 	if (setjmp(xdr_err)) {
   2141 		sprintf(get_line(0, 0), "<attr_vals too short>");
   2142 		goto done;
   2143 	}
   2144 
   2145 	detail_attr_bitmap("", &attrp->attrmask, &provided);
   2146 	for (attrnum = 0; attrnum < MAX_ATTRIBUTES; attrnum++) {
   2147 		if (provided.map[attrnum]) {
   2148 			attr_info[attrnum].prt_details(&attrxdr);
   2149 		}
   2150 	}
   2151 
   2152 done:
   2153 	bcopy(old_errbuf, xdr_err, sizeof (old_errbuf));
   2154 }
   2155 
   2156 static void
   2157 sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp)
   2158 {
   2159 	uint_t num_words;
   2160 	char *bp;
   2161 	size_t curlen, remaining;
   2162 
   2163 	buf[0] = '\0';
   2164 	for (num_words = 0; num_words < mapp->bitmap4_len; num_words++) {
   2165 		curlen = strlen(buf);
   2166 		if (curlen + sizeof ("<Too Long>") >= buflen) {
   2167 			strcpy(buf + buflen - sizeof ("<Too Long>"),
   2168 			    "<Too Long>");
   2169 			return;
   2170 		}
   2171 		bp = buf + curlen;
   2172 		remaining = buflen - curlen;
   2173 		snprintf(bp, remaining,
   2174 			num_words == 0 ? "%x" : " %x",
   2175 			mapp->bitmap4_val[num_words]);
   2176 	}
   2177 }
   2178 
   2179 /*
   2180  * Print detail information for the given attribute bitmap, and fill in the
   2181  * unpacked version of the map if "unpacked" is non-null.  Returns the
   2182  * number of bytes in the bitmap.  "prefix" is an initial string that is
   2183  * printed at the front of each line.
   2184  */
   2185 
   2186 static void
   2187 detail_attr_bitmap(char *prefix, bitmap4 *bitp, unpkd_attrmap_t *unpacked)
   2188 {
   2189 	uint_t num_words;
   2190 	uint32_t *wp;
   2191 	uint_t byte_num;
   2192 
   2193 	if (unpacked != NULL)
   2194 		memset(unpacked, 0, sizeof (unpkd_attrmap_t));
   2195 
   2196 	/*
   2197 	 * Break the bitmap into octets, then print in hex and
   2198 	 * symbolically.
   2199 	 */
   2200 
   2201 	for (num_words = 0, wp = bitp->bitmap4_val;
   2202 	    num_words < bitp->bitmap4_len;
   2203 	    num_words++, wp++) {
   2204 		for (byte_num = 0; byte_num < 4; byte_num++) {
   2205 			uchar_t val = (*wp) >> (byte_num * 8);
   2206 			char *buf = get_line(0, 0);
   2207 			uint_t attrnum;
   2208 			int bit;
   2209 
   2210 			sprintf(buf, "%s  0x%02x  ", prefix, val);
   2211 			attrnum = num_words * 32 + byte_num * 8;
   2212 			for (bit = 7; bit >= 0; bit--) {
   2213 				if (val & (1 << bit)) {
   2214 					strcat(buf, " ");
   2215 					strcat(buf,
   2216 					    attr_name(attrnum + bit));
   2217 					if (unpacked != NULL)
   2218 						unpacked->map[attrnum + bit] =
   2219 							1;
   2220 				}
   2221 			}
   2222 		}
   2223 	}
   2224 }
   2225 
   2226 /*
   2227  * Format the summary line results from a COMPOUND4 call.
   2228  */
   2229 
   2230 static void
   2231 sum_comp4res(char *line, char *(*sumres_fn)(void))
   2232 {
   2233 	nfsstat4 status;
   2234 	static utf8string tag;
   2235 
   2236 	status = getxdr_long();
   2237 	if (!xdr_utf8string(&xdrm, &tag))
   2238 		longjmp(xdr_err, 1);
   2239 
   2240 	sprintf(line, "(%.20s) %s %s", utf8localize(&tag),
   2241 		status_name(status), sumres_fn());
   2242 
   2243 	xdr_free(xdr_utf8string, (char *)&tag);
   2244 }
   2245 
   2246 
   2247 /*
   2248  * Return a set of summary strings for the result data that's next in the
   2249  * XDR stream, up to SUM_COMPND_MAX characters.  If the strings don't fit,
   2250  * include a "..." at the end of the string.
   2251  */
   2252 
   2253 static char *
   2254 sum_compound4res(void)
   2255 {
   2256 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
   2257 	int numres;
   2258 	const size_t buflen = sizeof (buf);
   2259 	char *bp;
   2260 	nfs_resop4 one_res;
   2261 
   2262 	buf[0] = '\0';
   2263 	if (setjmp(xdr_err)) {
   2264 		bp = buf + strlen(buf);
   2265 		snprintf(bp, buflen - (bp - buf),
   2266 			nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
   2267 		return (buf);
   2268 	}
   2269 
   2270 	numres = getxdr_long();
   2271 	bp = buf;
   2272 	while (numres-- > 0) {
   2273 		char *result;
   2274 
   2275 		bzero(&one_res, sizeof (one_res));
   2276 
   2277 		if (!xdr_nfs_resop4(&xdrm, &one_res)) {
   2278 			xdr_free(xdr_nfs_resop4, (char *)&one_res);
   2279 			longjmp(xdr_err, 1);
   2280 		}
   2281 
   2282 		snprintf(bp, buflen - (bp - buf), "%s ",
   2283 			opcode_name(one_res.resop));
   2284 		bp += strlen(bp);
   2285 
   2286 		result = sum_result(&one_res);
   2287 		if (strlen(result) > 0) {
   2288 			snprintf(bp, buflen - (bp - buf), "%s ", result);
   2289 			bp += strlen(bp);
   2290 		}
   2291 
   2292 		/* nfs4_skip_bytes set by xdr_nfs4_argop4() */
   2293 		if (nfs4_skip_bytes != 0)
   2294 			nfs4_xdr_skip(nfs4_skip_bytes);
   2295 
   2296 		xdr_free(xdr_nfs_resop4, (char *)&one_res);
   2297 		/* add "..." if past the "end" of the buffer */
   2298 		if (bp - buf > SUM_COMPND_MAX) {
   2299 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
   2300 			    "...");
   2301 			break;
   2302 		}
   2303 	}
   2304 
   2305 	return (buf);
   2306 }
   2307 
   2308 
   2309 /*
   2310  * Return a set of summary strings for the result data that's next in the
   2311  * XDR stream, up to SUM_COMPND_MAX characters.  If the strings don't fit,
   2312  * include a "..." at the end of the string.
   2313  */
   2314 
   2315 static char *
   2316 sum_cb_compound4res(void)
   2317 {
   2318 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
   2319 	int numres;
   2320 	const size_t buflen = sizeof (buf);
   2321 	char *bp;
   2322 	nfs_cb_resop4 one_res;
   2323 
   2324 	buf[0] = '\0';
   2325 	if (setjmp(xdr_err)) {
   2326 		bp = buf + strlen(buf);
   2327 		snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
   2328 			" RPC>");
   2329 		return (buf);
   2330 	}
   2331 
   2332 	numres = getxdr_long();
   2333 	bp = buf;
   2334 	while (numres-- > 0) {
   2335 		bzero(&one_res, sizeof (one_res));
   2336 		if (!xdr_nfs_cb_resop4(&xdrm, &one_res)) {
   2337 			xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
   2338 			longjmp(xdr_err, 1);
   2339 		}
   2340 		snprintf(bp, buflen - (bp - buf), "%s %s ",
   2341 					cb_opcode_name(one_res.resop),
   2342 					sum_cb_result(&one_res));
   2343 		bp += strlen(bp);
   2344 
   2345 		xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
   2346 
   2347 		/* add "..." if past the "end" of the buffer */
   2348 		if (bp - buf > SUM_COMPND_MAX) {
   2349 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
   2350 			    "...");
   2351 			break;
   2352 		}
   2353 	}
   2354 
   2355 	return (buf);
   2356 }
   2357 
   2358 
   2359 /*
   2360  * Return the summarized results for the given resultdata.
   2361  */
   2362 
   2363 static char *
   2364 sum_result(nfs_resop4 *resp)
   2365 {
   2366 	static char buf[1024];
   2367 	void (*fmtproc)(char *, size_t, void *);
   2368 
   2369 	buf[0] = '\0';
   2370 	if (resp->resop < num_opcodes)
   2371 		fmtproc = opcode_info[resp->resop].sumres;
   2372 	else if (resp->resop == OP_ILLEGAL)
   2373 		fmtproc = sum_nfsstat4;
   2374 	else
   2375 		fmtproc = NULL;
   2376 
   2377 	if (fmtproc != NULL)
   2378 		fmtproc(buf, sizeof (buf), &resp->nfs_resop4_u);
   2379 
   2380 	return (buf);
   2381 }
   2382 
   2383 /*
   2384  * Return the summarized results for the given resultdata.
   2385  */
   2386 
   2387 static char *
   2388 sum_cb_result(nfs_cb_resop4 *resp)
   2389 {
   2390 	static char buf[1024];
   2391 	void (*fmtproc)(char *, size_t, void *);
   2392 
   2393 	buf[0] = '\0';
   2394 	if (resp->resop < cb_num_opcodes)
   2395 		fmtproc = cb_opcode_info[resp->resop].sumres;
   2396 	else if (resp->resop == OP_CB_ILLEGAL)
   2397 		fmtproc = sum_nfsstat4;
   2398 	else
   2399 		fmtproc = NULL;
   2400 
   2401 	if (fmtproc != NULL)
   2402 		fmtproc(buf, sizeof (buf), &resp->nfs_cb_resop4_u);
   2403 
   2404 	return (buf);
   2405 }
   2406 
   2407 
   2408 static void
   2409 dtl_change_info(char *msg, change_info4 *infop)
   2410 {
   2411 	sprintf(get_line(0, 0), "%s:", msg);
   2412 	sprintf(get_line(0, 0), "  Atomic = %s",
   2413 		infop->atomic ? "TRUE" : "FALSE");
   2414 	detail_fattr4_change("  Before", infop->before);
   2415 	detail_fattr4_change("  After", infop->after);
   2416 }
   2417 
   2418 static void
   2419 detail_fattr4_change(char *msg, fattr4_change chg)
   2420 {
   2421 	sprintf(get_line(0, 0), "%s: 0x%llx", msg, chg);
   2422 					/* XXX print as time_t, too? */
   2423 }
   2424 
   2425 static void
   2426 sum_nfsstat4(char *buf, size_t buflen, void *obj)
   2427 {
   2428 	nfsstat4 status = *(nfsstat4 *)obj;
   2429 
   2430 	strncpy(buf, status_name(status), buflen);
   2431 }
   2432 
   2433 static void
   2434 dtl_nfsstat4(void *obj)
   2435 {
   2436 	nfsstat4 status = *(nfsstat4 *)obj;
   2437 
   2438 	sprintf(get_line(0, 0), "Status = %d (%s)", status,
   2439 		status_name(status));
   2440 }
   2441 
   2442 static void
   2443 sumres_access(char *buf, size_t buflen, void *obj)
   2444 {
   2445 	ACCESS4res *res = (ACCESS4res *)obj;
   2446 	char *bp = buf;
   2447 	int len, blen = buflen;
   2448 
   2449 	strcpy(bp, status_name(res->status));
   2450 	if (res->status == NFS4_OK) {
   2451 		bp += (len = strlen(bp));
   2452 		blen -= len;
   2453 
   2454 		snprintf(bp, blen, " Supp=");
   2455 		bp += (len = strlen(bp));
   2456 		blen -= len;
   2457 
   2458 		sum_access4(bp, blen, res->ACCESS4res_u.resok4.supported);
   2459 		bp += (len = strlen(bp));
   2460 		blen -= len;
   2461 
   2462 		snprintf(bp, blen, " Allow=");
   2463 		bp += (len = strlen(bp));
   2464 		blen -= len;
   2465 
   2466 		sum_access4(bp, blen, res->ACCESS4res_u.resok4.access);
   2467 	}
   2468 }
   2469 
   2470 static void
   2471 dtlres_access(void *obj)
   2472 {
   2473 	ACCESS4res *res = (ACCESS4res *)obj;
   2474 
   2475 	dtl_nfsstat4(obj);
   2476 	if (res->status == NFS4_OK) {
   2477 		detail_access4("Supported Attributes",
   2478 			    res->ACCESS4res_u.resok4.supported);
   2479 		detail_access4("Allowed Attributes",
   2480 			    res->ACCESS4res_u.resok4.access);
   2481 	}
   2482 }
   2483 
   2484 static void
   2485 sumres_close(char *buf, size_t buflen, void *obj)
   2486 {
   2487 	CLOSE4res *res = (CLOSE4res *)obj;
   2488 
   2489 	if (res->status == NFS4_OK)
   2490 		snprintf(buf, buflen, "%s",
   2491 			sum_open_stateid(&res->CLOSE4res_u.open_stateid));
   2492 }
   2493 
   2494 static void
   2495 dtlres_close(void *obj)
   2496 {
   2497 	CLOSE4res *res = (CLOSE4res *)obj;
   2498 
   2499 	dtl_nfsstat4(obj);
   2500 	if (res->status == NFS4_OK) {
   2501 		detail_open_stateid(&res->CLOSE4res_u.open_stateid);
   2502 	}
   2503 }
   2504 
   2505 static void
   2506 sumres_commit(char *buf, size_t buflen, void *obj)
   2507 {
   2508 	COMMIT4res *res = (COMMIT4res *)obj;
   2509 
   2510 	if (res->status == NFS4_OK)
   2511 		snprintf(buf, buflen, "Verf=%s",
   2512 			tohex(res->COMMIT4res_u.resok4.writeverf,
   2513 				NFS4_VERIFIER_SIZE));
   2514 }
   2515 
   2516 static void
   2517 dtlres_commit(void *obj)
   2518 {
   2519 	COMMIT4res *res = (COMMIT4res *)obj;
   2520 
   2521 	dtl_nfsstat4(obj);
   2522 	if (res->status == NFS4_OK) {
   2523 		sprintf(get_line(0, 0), "Verifier = %s",
   2524 			tohex(res->COMMIT4res_u.resok4.writeverf,
   2525 				NFS4_VERIFIER_SIZE));
   2526 	}
   2527 }
   2528 
   2529 static void
   2530 dtlres_create(void *obj)
   2531 {
   2532 	CREATE4res *res = (CREATE4res *)obj;
   2533 
   2534 	dtl_nfsstat4(obj);
   2535 	if (res->status == NFS4_OK) {
   2536 		dtl_change_info("Change Information",
   2537 				&res->CREATE4res_u.resok4.cinfo);
   2538 		detail_attr_bitmap("", &res->CREATE4res_u.resok4.attrset,
   2539 				NULL);
   2540 	}
   2541 }
   2542 
   2543 static void
   2544 sumres_getattr(char *buf, size_t buflen, void *obj)
   2545 {
   2546 	GETATTR4res *res = (GETATTR4res *)obj;
   2547 
   2548 	strncpy(buf, status_name(res->status), buflen);
   2549 }
   2550 
   2551 static void
   2552 dtlres_getattr(void *obj)
   2553 {
   2554 	GETATTR4res *res = (GETATTR4res *)obj;
   2555 
   2556 	dtl_nfsstat4(obj);
   2557 	if (res->status == NFS4_OK) {
   2558 		detail_fattr4(&res->GETATTR4res_u.resok4.obj_attributes);
   2559 	}
   2560 }
   2561 
   2562 static void
   2563 sumres_cb_getattr(char *buf, size_t buflen, void *obj)
   2564 {
   2565 	CB_GETATTR4res *res = (CB_GETATTR4res *)obj;
   2566 
   2567 	strncpy(buf, status_name(res->status), buflen);
   2568 }
   2569 
   2570 static void
   2571 dtlres_cb_getattr(void *obj)
   2572 {
   2573 	CB_GETATTR4res *res = (CB_GETATTR4res *)obj;
   2574 
   2575 	dtl_nfsstat4(obj);
   2576 	if (res->status == NFS4_OK) {
   2577 		detail_fattr4(&res->CB_GETATTR4res_u.resok4.obj_attributes);
   2578 	}
   2579 }
   2580 
   2581 
   2582 static void
   2583 sumres_getfh(char *buf, size_t buflen, void *obj)
   2584 {
   2585 	char *bp;
   2586 	GETFH4res *res = (GETFH4res *)obj;
   2587 
   2588 	strncpy(buf, status_name(res->status), buflen);
   2589 	if (res->status == NFS4_OK) {
   2590 		bp = buf + strlen(buf);
   2591 		snprintf(bp, buflen - (bp - buf), " %s",
   2592 			sum_fh4(&res->GETFH4res_u.resok4.object));
   2593 	}
   2594 }
   2595 
   2596 static void
   2597 dtlres_getfh(void *obj)
   2598 {
   2599 	GETFH4res *res = (GETFH4res *)obj;
   2600 
   2601 	dtl_nfsstat4(obj);
   2602 	if (res->status == NFS4_OK) {
   2603 		detail_fh4(&res->GETFH4res_u.resok4.object);
   2604 	}
   2605 }
   2606 
   2607 static void
   2608 dtlres_link(void *obj)
   2609 {
   2610 	LINK4res *res = (LINK4res *)obj;
   2611 
   2612 	dtl_nfsstat4(obj);
   2613 	if (res->status == NFS4_OK) {
   2614 		dtl_change_info("Change Information",
   2615 				&res->LINK4res_u.resok4.cinfo);
   2616 	}
   2617 }
   2618 
   2619 static void
   2620 sumres_lock(char *buf, size_t buflen, void *obj)
   2621 {
   2622 	char *bp;
   2623 	LOCK4res *res = (LOCK4res *)obj;
   2624 
   2625 	strncpy(buf, status_name(res->status), buflen);
   2626 	if (res->status == NFS4_OK) {
   2627 		bp = buf + strlen(buf);
   2628 		snprintf(bp, buflen - (bp - buf), " %s",
   2629 			sum_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid));
   2630 	}
   2631 	if (res->status == NFS4ERR_DENIED) {
   2632 		bp = buf + strlen(buf);
   2633 		snprintf(bp, buflen - (bp - buf), " %s",
   2634 			sum_lock_denied(&res->LOCK4res_u.denied));
   2635 	}
   2636 }
   2637 
   2638 static void
   2639 dtlres_lock(void *obj)
   2640 {
   2641 	LOCK4res *res = (LOCK4res *)obj;
   2642 
   2643 	dtl_nfsstat4(obj);
   2644 	if (res->status == NFS4_OK) {
   2645 		detail_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid);
   2646 	}
   2647 	if (res->status == NFS4ERR_DENIED) {
   2648 		detail_lock_denied(&res->LOCK4res_u.denied);
   2649 	}
   2650 }
   2651 
   2652 static void
   2653 sumres_lockt(char *buf, size_t buflen, void *obj)
   2654 {
   2655 	char *bp;
   2656 	LOCKT4res *res = (LOCKT4res *)obj;
   2657 
   2658 	strcpy(buf, status_name(res->status));
   2659 	if (res->status == NFS4ERR_DENIED) {
   2660 		bp = buf + strlen(buf);
   2661 		snprintf(bp, buflen - (bp - buf), " %s",
   2662 			sum_lock_denied(&res->LOCKT4res_u.denied));
   2663 	}
   2664 }
   2665 
   2666 static void
   2667 dtlres_lockt(void *obj)
   2668 {
   2669 	LOCKT4res *res = (LOCKT4res *)obj;
   2670 
   2671 	dtl_nfsstat4(obj);
   2672 	if (res->status == NFS4ERR_DENIED) {
   2673 		detail_lock_denied(&res->LOCKT4res_u.denied);
   2674 	}
   2675 }
   2676 
   2677 static void
   2678 sumres_locku(char *buf, size_t buflen, void *obj)
   2679 {
   2680 	char *bp;
   2681 	LOCKU4res *res = (LOCKU4res *)obj;
   2682 
   2683 	strncpy(buf, status_name(res->status), buflen);
   2684 	bp = buf + strlen(buf);
   2685 	if (res->status == NFS4_OK)
   2686 		snprintf(bp, buflen - (bp - buf), " %s",
   2687 			sum_lock_stateid(&res->LOCKU4res_u.lock_stateid));
   2688 }
   2689 
   2690 static void
   2691 dtlres_locku(void *obj)
   2692 {
   2693 	LOCKU4res *res = (LOCKU4res *)obj;
   2694 
   2695 	dtl_nfsstat4(obj);
   2696 	if (res->status == NFS4_OK)
   2697 		detail_lock_stateid(&res->LOCKU4res_u.lock_stateid);
   2698 }
   2699 
   2700 static void
   2701 sumres_open(char *buf, size_t buflen, void *obj)
   2702 {
   2703 	char *bp = buf;
   2704 	OPEN4res *res = (OPEN4res *)obj;
   2705 	uint_t rflags;
   2706 	int len, blen = buflen;
   2707 
   2708 	strncpy(bp, status_name(res->status), blen);
   2709 
   2710 	if (res->status == NFS4_OK) {
   2711 		bp += (len = strlen(bp));
   2712 		blen -= len;
   2713 
   2714 		snprintf(bp, blen, " %s",
   2715 			sum_stateid(&res->OPEN4res_u.resok4.stateid));
   2716 		bp += (len = strlen(bp));
   2717 		blen -= len;
   2718 
   2719 		if ((rflags = res->OPEN4res_u.resok4.rflags) != 0) {
   2720 			snprintf(bp, blen, "%s", sum_open_rflags(rflags));
   2721 			bp += (len = strlen(bp));
   2722 			blen -= len;
   2723 		}
   2724 
   2725 		sum_delegation(bp, blen, &res->OPEN4res_u.resok4.delegation);
   2726 	}
   2727 }
   2728 
   2729 static void
   2730 dtlres_open(void *obj)
   2731 {
   2732 	OPEN4res *res = (OPEN4res *)obj;
   2733 
   2734 	dtl_nfsstat4(obj);
   2735 	if (res->status == NFS4_OK) {
   2736 		detail_stateid(&res->OPEN4res_u.resok4.stateid);
   2737 		dtl_change_info("Change Information",
   2738 			&res->OPEN4res_u.resok4.cinfo);
   2739 		sprintf(get_line(0, 0), "Flags = 0x%x (%s)",
   2740 			res->OPEN4res_u.resok4.rflags,
   2741 			detail_open_rflags(res->OPEN4res_u.resok4.rflags));
   2742 		detail_attr_bitmap("", &res->OPEN4res_u.resok4.attrset,
   2743 				NULL);
   2744 		detail_delegation(&res->OPEN4res_u.resok4.delegation);
   2745 	}
   2746 }
   2747 
   2748 static void
   2749 sumres_open_confirm(char *buf, size_t buflen, void *obj)
   2750 {
   2751 	char *bp;
   2752 	OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj;
   2753 
   2754 	strncpy(buf, status_name(res->status), buflen);
   2755 	if (res->status == NFS4_OK) {
   2756 		bp = buf + strlen(buf);
   2757 		snprintf(bp, buflen - (bp - buf), " %s",
   2758 			sum_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
   2759 					open_stateid));
   2760 	}
   2761 }
   2762 
   2763 static void
   2764 dtlres_open_confirm(void *obj)
   2765 {
   2766 	OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj;
   2767 
   2768 	dtl_nfsstat4(obj);
   2769 	if (res->status == NFS4_OK) {
   2770 		detail_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
   2771 				    open_stateid);
   2772 	}
   2773 }
   2774 
   2775 static void
   2776 sumres_open_downgrd(char *buf, size_t buflen, void *obj)
   2777 {
   2778 	char *bp;
   2779 	OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj;
   2780 
   2781 	strncpy(buf, status_name(res->status), buflen);
   2782 	if (res->status == NFS4_OK) {
   2783 		bp = buf + strlen(buf);
   2784 		snprintf(bp, buflen - (bp - buf), " %s",
   2785 			sum_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
   2786 					open_stateid));
   2787 	}
   2788 }
   2789 
   2790 static void
   2791 dtlres_open_downgrd(void *obj)
   2792 {
   2793 	OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj;
   2794 
   2795 	dtl_nfsstat4(obj);
   2796 	if (res->status == NFS4_OK) {
   2797 		detail_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
   2798 				    open_stateid);
   2799 	}
   2800 }
   2801 
   2802 static void
   2803 sumres_read(char *buf, size_t buflen, void *obj)
   2804 {
   2805 	char *bp;
   2806 	READ4res *res = (READ4res *)obj;
   2807 
   2808 	strncpy(buf, status_name(res->status), buflen);
   2809 	if (res->status == NFS4_OK) {
   2810 		bp = buf + strlen(buf);
   2811 		snprintf(bp, buflen - (bp - buf), " (%u bytes) %s",
   2812 			res->READ4res_u.resok4.data.data_len,
   2813 			res->READ4res_u.resok4.eof ? "EOF" : "");
   2814 	}
   2815 }
   2816 
   2817 static void
   2818 dtlres_read(void *obj)
   2819 {
   2820 	READ4res *res = (READ4res *)obj;
   2821 
   2822 	dtl_nfsstat4(obj);
   2823 	if (res->status == NFS4_OK) {
   2824 		sprintf(get_line(0, 0), "Count = %u bytes read",
   2825 			res->READ4res_u.resok4.data.data_len);
   2826 		sprintf(get_line(0, 0), "End of file = %s",
   2827 			res->READ4res_u.resok4.eof ? "TRUE" : "FALSE");
   2828 	}
   2829 }
   2830 
   2831 static void
   2832 sumres_readdir(char *buf, size_t buflen, void *obj)
   2833 {
   2834 	char *bp;
   2835 	READDIR4res *res = (READDIR4res *)obj;
   2836 	int num_entries = 0;
   2837 	entry4 *ep;
   2838 
   2839 	strncpy(buf, status_name(res->status), buflen);
   2840 	if (res->status == NFS4_OK) {
   2841 		for (ep = res->READDIR4res_u.resok4.reply.entries;
   2842 		    ep != NULL;
   2843 		    ep = ep->nextentry)
   2844 			num_entries++;
   2845 		bp = buf + strlen(buf);
   2846 		snprintf(bp, buflen - (bp - buf), " %d entries (%s)",
   2847 			num_entries,
   2848 			res->READDIR4res_u.resok4.reply.eof
   2849 			? "No more" : "More");
   2850 	}
   2851 }
   2852 
   2853 static void
   2854 dtlres_readdir(void *obj)
   2855 {
   2856 	READDIR4res *res = (READDIR4res *)obj;
   2857 	int num_entries = 0;
   2858 	entry4 *ep;
   2859 
   2860 	dtl_nfsstat4(obj);
   2861 	if (res->status == NFS4_OK) {
   2862 		for (ep = res->READDIR4res_u.resok4.reply.entries;
   2863 		    ep != NULL;
   2864 		    ep = ep->nextentry) {
   2865 			num_entries++;
   2866 			sprintf(get_line(0, 0),
   2867 				"------------------ entry #%d",
   2868 				num_entries);
   2869 			sprintf(get_line(0, 0), "Cookie = %llu",
   2870 				ep->cookie);
   2871 			sprintf(get_line(0, 0), "Name = %s",
   2872 				component_name(&ep->name));
   2873 			detail_fattr4(&ep->attrs);
   2874 		}
   2875 		if (num_entries == 0)
   2876 			sprintf(get_line(0, 0), "(No entries)");
   2877 		sprintf(get_line(0, 0), "EOF = %s",
   2878 		    res->READDIR4res_u.resok4.reply.eof ? "TRUE" : "FALSE");
   2879 		sprintf(get_line(0, 0), "Verifer = %s",
   2880 			tohex(res->READDIR4res_u.resok4.cookieverf,
   2881 				NFS4_VERIFIER_SIZE));
   2882 	}
   2883 }
   2884 
   2885 static void
   2886 sumres_readlnk(char *buf, size_t buflen, void *obj)
   2887 {
   2888 	char *bp;
   2889 	READLINK4res *res = (READLINK4res *)obj;
   2890 
   2891 	strncpy(buf, status_name(res->status), buflen);
   2892 	if (res->status == NFS4_OK) {
   2893 		bp = buf + strlen(buf);
   2894 		snprintf(bp, buflen - (bp - buf), " %s",
   2895 			linktext_name(&res->READLINK4res_u.resok4.link));
   2896 	}
   2897 }
   2898 
   2899 static void
   2900 dtlres_readlnk(void *obj)
   2901 {
   2902 	READLINK4res *res = (READLINK4res *)obj;
   2903 
   2904 	dtl_nfsstat4(obj);
   2905 	if (res->status == NFS4_OK) {
   2906 		sprintf(get_line(0, 0), "Link = %s",
   2907 			linktext_name(&res->READLINK4res_u.resok4.link));
   2908 	}
   2909 }
   2910 
   2911 static void
   2912 dtlres_remove(void *obj)
   2913 {
   2914 	REMOVE4res *res = (REMOVE4res *)obj;
   2915 
   2916 	dtl_nfsstat4(obj);
   2917 	if (res->status == NFS4_OK) {
   2918 		dtl_change_info("Change Information",
   2919 				&res->REMOVE4res_u.resok4.cinfo);
   2920 	}
   2921 }
   2922 
   2923 static void
   2924 dtlres_rename(void *obj)
   2925 {
   2926 	RENAME4res *res = (RENAME4res *)obj;
   2927 
   2928 	dtl_nfsstat4(obj);
   2929 	if (res->status == NFS4_OK) {
   2930 		dtl_change_info("Source Change Information",
   2931 				&res->RENAME4res_u.resok4.source_cinfo);
   2932 		dtl_change_info("Target Change Information",
   2933 				&res->RENAME4res_u.resok4.target_cinfo);
   2934 	}
   2935 }
   2936 
   2937 static void
   2938 sumres_secinfo(char *buf, size_t buflen, void *obj)
   2939 {
   2940 	char *bp;
   2941 	SECINFO4res *res = (SECINFO4res *)obj;
   2942 
   2943 	strncpy(buf, status_name(res->status), buflen);
   2944 	bp = buf + strlen(buf);
   2945 	if (res->status == NFS4_OK) {
   2946 		uint_t numinfo = res->SECINFO4res_u.resok4.SECINFO4resok_len;
   2947 		secinfo4 *infop;
   2948 
   2949 		for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val;
   2950 		    numinfo != 0;
   2951 		    infop++, numinfo--) {
   2952 			snprintf(bp, buflen - (bp - buf), " %s",
   2953 				flavor_name(infop->flavor));
   2954 			bp += strlen(bp);
   2955 		}
   2956 	}
   2957 }
   2958 
   2959 static void
   2960 dtlres_secinfo(void *obj)
   2961 {
   2962 	SECINFO4res *res = (SECINFO4res *)obj;
   2963 
   2964 	dtl_nfsstat4(obj);
   2965 	if (res->status == NFS4_OK) {
   2966 		uint_t numinfo =
   2967 			res->SECINFO4res_u.resok4.SECINFO4resok_len;
   2968 		secinfo4 *infop;
   2969 
   2970 		for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val;
   2971 		    numinfo != 0;
   2972 		    infop++, numinfo--) {
   2973 			detail_secinfo4(infop);
   2974 		}
   2975 	}
   2976 }
   2977 
   2978 static void
   2979 sumres_setattr(char *buf, size_t buflen, void *obj)
   2980 {
   2981 	SETATTR4res *res = (SETATTR4res *)obj;
   2982 
   2983 	strncpy(buf, status_name(res->status), buflen);
   2984 	sum_attr_bitmap(buf, buflen, &res->attrsset);
   2985 }
   2986 
   2987 static void
   2988 dtlres_setattr(void *obj)
   2989 {
   2990 	SETATTR4res *res = (SETATTR4res *)obj;
   2991 
   2992 	dtl_nfsstat4(obj);
   2993 	detail_attr_bitmap("", &res->attrsset, NULL);
   2994 }
   2995 
   2996 static void
   2997 sumres_setclid(char *buf, size_t buflen, void *obj)
   2998 {
   2999 	char *bp;
   3000 	SETCLIENTID4res *res = (SETCLIENTID4res *)obj;
   3001 
   3002 	strncpy(buf, status_name(res->status), buflen);
   3003 	switch (res->status) {
   3004 	case NFS_OK:
   3005 		bp = buf + strlen(buf);
   3006 		snprintf(bp, buflen - (bp - buf), " %s CFV=%s",
   3007 			sum_clientid(res->SETCLIENTID4res_u.resok4.clientid),
   3008 			tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
   3009 				NFS4_VERIFIER_SIZE));
   3010 		break;
   3011 	case NFS4ERR_CLID_INUSE:
   3012 		bp = buf + strlen(buf);
   3013 		snprintf(bp, buflen - (bp - buf), " ID=%s Addr=%s",
   3014 			res->SETCLIENTID4res_u.client_using.r_netid,
   3015 			res->SETCLIENTID4res_u.client_using.r_addr);
   3016 		break;
   3017 	}
   3018 }
   3019 
   3020 static void
   3021 dtlres_setclid(void *obj)
   3022 {
   3023 	SETCLIENTID4res *res = (SETCLIENTID4res *)obj;
   3024 
   3025 	dtl_nfsstat4(obj);
   3026 	switch (res->status) {
   3027 	case NFS_OK:
   3028 		detail_clientid(res->SETCLIENTID4res_u.resok4.clientid);
   3029 		sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
   3030 			tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
   3031 				NFS4_VERIFIER_SIZE));
   3032 		break;
   3033 	case NFS4ERR_CLID_INUSE:
   3034 		sprintf(get_line(0, 0), "Used by Net ID = %s",
   3035 			res->SETCLIENTID4res_u.client_using.r_netid);
   3036 		sprintf(get_line(0, 0), "Used by Addr = %s",
   3037 			res->SETCLIENTID4res_u.client_using.r_addr);
   3038 		break;
   3039 	}
   3040 }
   3041 
   3042 static void
   3043 sumres_write(char *buf, size_t buflen, void *obj)
   3044 {
   3045 	char *bp;
   3046 	WRITE4res *res = (WRITE4res *)obj;
   3047 
   3048 	strncpy(buf, status_name(res->status), buflen);
   3049 	if (res->status == NFS4_OK) {
   3050 		bp = buf + strlen(buf);
   3051 		snprintf(bp, buflen - (bp - buf), " %u (%s)",
   3052 			res->WRITE4res_u.resok4.count,
   3053 			stable_how4_name(res->WRITE4res_u.resok4.committed));
   3054 	}
   3055 }
   3056 
   3057 static void
   3058 dtlres_write(void *obj)
   3059 {
   3060 	WRITE4res *res = (WRITE4res *)obj;
   3061 
   3062 	dtl_nfsstat4(obj);
   3063 	if (res->status == NFS4_OK) {
   3064 		sprintf(get_line(0, 0), "Count = %u bytes written",
   3065 			res->WRITE4res_u.resok4.count);
   3066 		sprintf(get_line(0, 0), "Stable = %s",
   3067 			stable_how4_name(res->WRITE4res_u.resok4.committed));
   3068 		sprintf(get_line(0, 0), "Verifier = %s",
   3069 			tohex(res->WRITE4res_u.resok4.writeverf,
   3070 				NFS4_VERIFIER_SIZE));
   3071 	}
   3072 }
   3073 
   3074 /*
   3075  * Print details about the nfs_resop4 that is next in the XDR stream.
   3076  */
   3077 
   3078 static void
   3079 detail_nfs_resop4(void)
   3080 {
   3081 	int numres;
   3082 	nfs_resop4 one_res;
   3083 	void (*fmtproc)(void *);
   3084 
   3085 	numres = getxdr_long();
   3086 	(void) sprintf(get_line(0, 0), "Number of results = %d",
   3087 		    numres);
   3088 
   3089 	while (numres-- > 0) {
   3090 		bzero(&one_res, sizeof (one_res));
   3091 
   3092 		if (!xdr_nfs_resop4(&xdrm, &one_res)) {
   3093 			xdr_free(xdr_nfs_resop4, (char *)&one_res);
   3094 			longjmp(xdr_err, 1);
   3095 		}
   3096 
   3097 		get_line(0, 0);		/* blank line to separate ops */
   3098 		sprintf(get_line(0, 0), "Op = %d (%s)",
   3099 			one_res.resop, opcode_name(one_res.resop));
   3100 		if (one_res.resop < num_opcodes)
   3101 			fmtproc = opcode_info[one_res.resop].dtlres;
   3102 		else if (one_res.resop == OP_ILLEGAL)
   3103 			fmtproc = dtl_nfsstat4;
   3104 		else
   3105 			fmtproc = NULL;
   3106 
   3107 		if (fmtproc != NULL)
   3108 			fmtproc(&one_res.nfs_resop4_u);
   3109 
   3110 		/* nfs4_skip_bytes set by xdr_nfs_resop4()() */
   3111 		if (nfs4_skip_bytes)
   3112 			nfs4_xdr_skip(nfs4_skip_bytes);
   3113 
   3114 		xdr_free(xdr_nfs_resop4, (char *)&one_res);
   3115 	}
   3116 }
   3117 
   3118 
   3119 /*
   3120  * Print details about the nfs_cb_resop4 that is next in the XDR stream.
   3121  */
   3122 
   3123 static void
   3124 detail_cb_resop4(void)
   3125 {
   3126 	int numres;
   3127 	nfs_cb_resop4 one_res;
   3128 	void (*fmtproc)(void *);
   3129 
   3130 	numres = getxdr_long();
   3131 	(void) sprintf(get_line(0, 0), "Number of results = %d",
   3132 		    numres);
   3133 
   3134 	while (numres-- > 0) {
   3135 		bzero(&one_res, sizeof (one_res));
   3136 		if (!xdr_nfs_cb_resop4(&xdrm, &one_res))
   3137 			longjmp(xdr_err, 1);
   3138 
   3139 		get_line(0, 0);		/* blank line to separate ops */
   3140 		sprintf(get_line(0, 0), "Op = %d (%s)",
   3141 			one_res.resop, cb_opcode_name(one_res.resop));
   3142 		if (one_res.resop < cb_num_opcodes)
   3143 			fmtproc = cb_opcode_info[one_res.resop].dtlres;
   3144 		else if (one_res.resop == OP_CB_ILLEGAL)
   3145 			fmtproc = dtl_nfsstat4;
   3146 		else
   3147 			fmtproc = NULL;
   3148 
   3149 		if (fmtproc != NULL)
   3150 			fmtproc(&one_res.nfs_cb_resop4_u);
   3151 
   3152 		xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
   3153 	}
   3154 }
   3155 
   3156 
   3157 /*
   3158  * Return the name of a lock type.
   3159  */
   3160 static char *
   3161 lock_type_name(enum nfs_lock_type4 type)
   3162 {
   3163 	char *result;
   3164 
   3165 	switch (type) {
   3166 	case READ_LT:
   3167 		result = "READ";
   3168 		break;
   3169 	case WRITE_LT:
   3170 		result = "WRITE";
   3171 		break;
   3172 	case READW_LT:
   3173 		result = "READW";
   3174 		break;
   3175 	case WRITEW_LT:
   3176 		result = "WRITEW";
   3177 		break;
   3178 	default:
   3179 		result = "?";
   3180 		break;
   3181 	}
   3182 
   3183 	return (result);
   3184 }
   3185 
   3186 /*
   3187  * Return the name of an opcode.
   3188  */
   3189 
   3190 static char *
   3191 opcode_name(uint_t opnum)
   3192 {
   3193 	static char buf[20];
   3194 
   3195 	if (opnum < num_opcodes)
   3196 		return (opcode_info[opnum].name);
   3197 
   3198 	if (opnum == OP_ILLEGAL)
   3199 		return ("ILLEGAL");
   3200 
   3201 	sprintf(buf, "op %d", opnum);
   3202 	return (buf);
   3203 }
   3204 
   3205 /*
   3206  * Return the name of an opcode.
   3207  */
   3208 static char *
   3209 cb_opcode_name(uint_t opnum)
   3210 {
   3211 	static char buf[20];
   3212 
   3213 	if (opnum < cb_num_opcodes)
   3214 		return (cb_opcode_info[opnum].name);
   3215 
   3216 	if (opnum == OP_CB_ILLEGAL)
   3217 		return ("CB_ILLEGAL");
   3218 
   3219 	sprintf(buf, "op %d", opnum);
   3220 	return (buf);
   3221 }
   3222 
   3223 
   3224 /*
   3225  * Fill in a summary string for the given access bitmask.
   3226  */
   3227 
   3228 static void
   3229 sum_access4(char *buf, size_t buflen, uint32_t bits)
   3230 {
   3231 	buf[0] = '\0';
   3232 
   3233 	if (bits & ACCESS4_READ)
   3234 		(void) strncat(buf, "rd,", buflen);
   3235 	if (bits & ACCESS4_LOOKUP)
   3236 		(void) strncat(buf, "lk,", buflen);
   3237 	if (bits & ACCESS4_MODIFY)
   3238 		(void) strncat(buf, "mo,", buflen);
   3239 	if (bits & ACCESS4_EXTEND)
   3240 		(void) strncat(buf, "ext,", buflen);
   3241 	if (bits & ACCESS4_DELETE)
   3242 		(void) strncat(buf, "dl,", buflen);
   3243 	if (bits & ACCESS4_EXECUTE)
   3244 		(void) strncat(buf, "exc,", buflen);
   3245 	if (buf[0] != '\0')
   3246 		buf[strlen(buf) - 1] = '\0';
   3247 }
   3248 
   3249 /*
   3250  * Print detail information about the given access bitmask.
   3251  */
   3252 
   3253 static void
   3254 detail_access4(char *descrip, uint32_t bits)
   3255 {
   3256 	sprintf(get_line(0, 0), "%s = 0x%08x", descrip, bits);
   3257 
   3258 	(void) sprintf(get_line(0, 0), "	%s",
   3259 		getflag(bits, ACCESS4_READ, "Read", "(no read)"));
   3260 	(void) sprintf(get_line(0, 0), "	%s",
   3261 		getflag(bits, ACCESS4_LOOKUP, "Lookup", "(no lookup)"));
   3262 	(void) sprintf(get_line(0, 0), "	%s",
   3263 		getflag(bits, ACCESS4_MODIFY, "Modify", "(no modify)"));
   3264 	(void) sprintf(get_line(0, 0), "	%s",
   3265 		getflag(bits, ACCESS4_EXTEND, "Extend", "(no extend)"));
   3266 	(void) sprintf(get_line(0, 0), "	%s",
   3267 		getflag(bits, ACCESS4_DELETE, "Delete", "(no delete)"));
   3268 	(void) sprintf(get_line(0, 0), "	%s",
   3269 		getflag(bits, ACCESS4_EXECUTE, "Execute", "(no execute)"));
   3270 }
   3271 
   3272 
   3273 /*
   3274  * Fill in a summary string for the given open_claim4.
   3275  */
   3276 static void
   3277 sum_name(char *buf, size_t buflen, open_claim4 *claim)
   3278 {
   3279 	char *bp = buf;
   3280 
   3281 	switch (claim->claim) {
   3282 	case CLAIM_NULL:
   3283 		snprintf(bp, buflen, "%s ",
   3284 			component_name(&claim->open_claim4_u.file));
   3285 		break;
   3286 	case CLAIM_PREVIOUS:
   3287 		break;
   3288 	case CLAIM_DELEGATE_CUR:
   3289 		snprintf(bp, buflen, "%s ",
   3290 			component_name(&claim->open_claim4_u.
   3291 					delegate_cur_info.file));
   3292 		break;
   3293 	case CLAIM_DELEGATE_PREV:
   3294 		snprintf(bp, buflen, "%s ",
   3295 			component_name(&claim->open_claim4_u.
   3296 					file_delegate_prev));
   3297 		break;
   3298 	}
   3299 }
   3300 
   3301 /*
   3302  * Fill in a summary string for the given open_claim4.
   3303  */
   3304 static void
   3305 sum_claim(char *buf, size_t buflen, open_claim4 *claim)
   3306 {
   3307 	char *bp = buf;
   3308 
   3309 	switch (claim->claim) {
   3310 	case CLAIM_NULL:
   3311 		snprintf(bp, buflen, " CT=N");
   3312 		break;
   3313 	case CLAIM_PREVIOUS:
   3314 		snprintf(bp, buflen, " CT=P DT=%s",
   3315 			get_deleg_typestr(claim->open_claim4_u.delegate_type));
   3316 		break;
   3317 	case CLAIM_DELEGATE_CUR:
   3318 		snprintf(bp, buflen, " CT=DC %s",
   3319 			sum_deleg_stateid(&claim->open_claim4_u.
   3320 				delegate_cur_info.delegate_stateid));
   3321 		break;
   3322 	case CLAIM_DELEGATE_PREV:
   3323 		snprintf(bp, buflen, " CT=DP");
   3324 		break;
   3325 	default:
   3326 		snprintf(bp, buflen, " CT=?");
   3327 		break;
   3328 	}
   3329 }
   3330 
   3331 static char *
   3332 get_deleg_typestr(open_delegation_type4 dt)
   3333 {
   3334 	char *str = "";
   3335 
   3336 	switch (dt) {
   3337 	case OPEN_DELEGATE_NONE:
   3338 		str = "N";
   3339 		break;
   3340 	case OPEN_DELEGATE_READ:
   3341 		str = "R";
   3342 		break;
   3343 	case OPEN_DELEGATE_WRITE:
   3344 		str = "W";
   3345 		break;
   3346 	default:
   3347 		str = "?";
   3348 	}
   3349 
   3350 	return (str);
   3351 }
   3352 
   3353 /*
   3354  * Print detail information for the given open_claim4.
   3355  */
   3356 
   3357 static void
   3358 detail_claim(open_claim4 *claim)
   3359 {
   3360 	sprintf(get_line(0, 0), "Claim Type = %d (%s)",
   3361 		claim->claim, claim_name(claim->claim));
   3362 
   3363 	switch (claim->claim) {
   3364 	case CLAIM_NULL:
   3365 		detail_compname4(&claim->open_claim4_u.file);
   3366 		break;
   3367 	case CLAIM_PREVIOUS:
   3368 		sprintf(get_line(0, 0), "Delegate Type = %s (val = %d)",
   3369 			get_deleg_typestr(claim->open_claim4_u.delegate_type),
   3370 			claim->open_claim4_u.delegate_type);
   3371 		break;
   3372 	case CLAIM_DELEGATE_CUR:
   3373 		detail_compname4(&claim->open_claim4_u.delegate_cur_info.file);
   3374 		detail_deleg_stateid(&claim->open_claim4_u.delegate_cur_info.
   3375 				    delegate_stateid);
   3376 		break;
   3377 	case CLAIM_DELEGATE_PREV:
   3378 		detail_compname4(&claim->open_claim4_u.file_delegate_prev);
   3379 		break;
   3380 	}
   3381 }
   3382 
   3383 /*
   3384  * Return a summary string for the given clientid4.
   3385  */
   3386 static char *
   3387 sum_clientid(clientid4 client)
   3388 {
   3389 	static char buf[50];
   3390 
   3391 	snprintf(buf, sizeof (buf), "CL=%llx", client);
   3392 
   3393 	return (buf);
   3394 }
   3395 
   3396 /*
   3397  * Print a detail string for the given clientid4.
   3398  */
   3399 static void
   3400 detail_clientid(clientid4 client)
   3401 {
   3402 	sprintf(get_line(0, 0), "Client ID = %llx", client);
   3403 }
   3404 
   3405 /*
   3406  * Write a summary string for the given delegation into buf.
   3407  */
   3408 
   3409 static void
   3410 sum_delegation(char *buf, size_t buflen, open_delegation4 *delp)
   3411 {
   3412 	switch (delp->delegation_type) {
   3413 	case OPEN_DELEGATE_NONE:
   3414 		snprintf(buf, buflen, " DT=N");
   3415 		break;
   3416 	case OPEN_DELEGATE_READ:
   3417 		snprintf(buf, buflen, " DT=R %s",
   3418 			sum_deleg_stateid(&delp->open_delegation4_u.write.
   3419 					stateid));
   3420 		break;
   3421 	case OPEN_DELEGATE_WRITE:
   3422 		snprintf(buf, buflen, " DT=W %s %s",
   3423 			sum_deleg_stateid(&delp->open_delegation4_u.write.
   3424 					stateid),
   3425 			sum_space_limit(&delp->open_delegation4_u.write.
   3426 					space_limit));
   3427 		break;
   3428 	default:
   3429 		snprintf(buf, buflen, " DT=?");
   3430 		break;
   3431 	}
   3432 }
   3433 
   3434 static void
   3435 detail_delegation(open_delegation4 *delp)
   3436 {
   3437 	sprintf(get_line(0, 0), "Delegation Type = %d (%s)",
   3438 		delp->delegation_type,
   3439 		delegation_type_name(delp->delegation_type));
   3440 
   3441 	switch (delp->delegation_type) {
   3442 	case OPEN_DELEGATE_NONE:
   3443 		/* no-op */
   3444 		break;
   3445 	case OPEN_DELEGATE_READ:
   3446 		detail_deleg_stateid(&delp->open_delegation4_u.read.stateid);
   3447 		sprintf(get_line(0, 0), "Recall = %s",
   3448 			delp->open_delegation4_u.read.recall ?
   3449 			"TRUE" : "FALSE");
   3450 		sprintf(get_line(0, 0), "[nfsacl4]");
   3451 		break;
   3452 	case OPEN_DELEGATE_WRITE:
   3453 		detail_deleg_stateid(&delp->open_delegation4_u.write.stateid);
   3454 		sprintf(get_line(0, 0), "Recall = %s",
   3455 			delp->open_delegation4_u.write.recall ?
   3456 			"TRUE" : "FALSE");
   3457 		detail_space_limit(&delp->open_delegation4_u.write.
   3458 				space_limit);
   3459 		sprintf(get_line(0, 0), "[nfsacl4]");
   3460 		break;
   3461 	}
   3462 }
   3463 
   3464 
   3465 static void
   3466 detail_open_owner(open_owner4 *owner)
   3467 {
   3468 	sprintf(get_line(0, 0), "Open Owner hash = [%04X] ",
   3469 		owner_hash(&owner->owner));
   3470 	sprintf(get_line(0, 0), "    len = %u   val = %s ",
   3471 		owner->owner.owner_len,
   3472 		tohex(owner->owner.owner_val, owner->owner.owner_len));
   3473 	detail_clientid(owner->clientid);
   3474 }
   3475 
   3476 static void
   3477 detail_lock_owner(lock_owner4 *owner)
   3478 {
   3479 	sprintf(get_line(0, 0), "Lock Owner hash = [%04X] ",
   3480 		owner_hash(&owner->owner));
   3481 	sprintf(get_line(0, 0), "    len = %u   val = %s ",
   3482 		owner->owner.owner_len,
   3483 		tohex(owner->owner.owner_val, owner->owner.owner_len));
   3484 	detail_clientid(owner->clientid);
   3485 }
   3486 
   3487 static void
   3488 sum_openflag(char *bufp, int buflen, openflag4 *flagp)
   3489 {
   3490 	if (flagp->opentype == OPEN4_CREATE) {
   3491 		switch (flagp->openflag4_u.how.mode) {
   3492 		case UNCHECKED4:
   3493 			snprintf(bufp, buflen, "OT=CR(U)");
   3494 			break;
   3495 		case GUARDED4:
   3496 			snprintf(bufp, buflen, "OT=CR(G)");
   3497 			break;
   3498 		case EXCLUSIVE4:
   3499 			snprintf(bufp, buflen, "OT=CR(E)");
   3500 			break;
   3501 		default:
   3502 			snprintf(bufp, buflen, "OT=CR(?:%d)",
   3503 				flagp->openflag4_u.how.mode);
   3504 			break;
   3505 		}
   3506 	} else
   3507 		snprintf(bufp, buflen, "OT=NC");
   3508 }
   3509 
   3510 static void
   3511 detail_openflag(openflag4 *flagp)
   3512 {
   3513 	sprintf(get_line(0, 0), "Open Type = %s",
   3514 		flagp->opentype == OPEN4_CREATE ? "CREATE" : "NOCREATE");
   3515 	if (flagp->opentype == OPEN4_CREATE)
   3516 		detail_createhow4(&flagp->openflag4_u.how);
   3517 }
   3518 
   3519 /*
   3520  * Fill in buf with the given path.
   3521  */
   3522 static void
   3523 sum_pathname4(char *buf, size_t buflen, pathname4 *pathp)
   3524 {
   3525 	char *bp = buf;
   3526 	uint_t component;
   3527 
   3528 	for (component = 0; component < pathp->pathname4_len;
   3529 	    component++) {
   3530 		snprintf(bp, buflen - (bp - buf),
   3531 			component == 0 ? "%s" : "/%s",
   3532 			component_name(&pathp->pathname4_val[component]));
   3533 		bp += strlen(bp);
   3534 	}
   3535 }
   3536 
   3537 static void
   3538 sum_compname4(char *buf, size_t buflen, component4 *comp)
   3539 {
   3540 	snprintf(buf, buflen, "%s", component_name(comp));
   3541 }
   3542 
   3543 static void
   3544 detail_compname4(component4 *comp)
   3545 {
   3546 	sprintf(get_line(0, 0), "%s", component_name(comp));
   3547 }
   3548 
   3549 static void
   3550 detail_pathname4(pathname4 *pathp)
   3551 {
   3552 	char *bp = get_line(0, 0);
   3553 	uint_t component;
   3554 
   3555 	sprintf(bp, "File name = ");
   3556 	bp += strlen(bp);
   3557 
   3558 	for (component = 0; component < pathp->pathname4_len; component++) {
   3559 		sprintf(bp, component == 0 ? "%s" : "/%s",
   3560 			component_name(&pathp->pathname4_val[component]));
   3561 		bp += strlen(bp);
   3562 	}
   3563 }
   3564 
   3565 /*
   3566  * Print detail information about the rpcsec_gss_info that is XDR-encoded
   3567  * at mem.
   3568  */
   3569 
   3570 static void
   3571 detail_rpcsec_gss(rpcsec_gss_info *info)
   3572 {
   3573 	sprintf(get_line(0, 0), "OID = %s",
   3574 		tohex(info->oid.sec_oid4_val, info->oid.sec_oid4_len));
   3575 	sprintf(get_line(0, 0), "QOP = %u", info->qop);
   3576 	sprintf(get_line(0, 0), "Service = %d (%s)",
   3577 		info->service, gss_svc_name(info->service));
   3578 }
   3579 
   3580 /*
   3581  * Print detail information about the given secinfo4.
   3582  */
   3583 
   3584 static void
   3585 detail_secinfo4(secinfo4 *infop)
   3586 {
   3587 	sprintf(get_line(0, 0), "Flavor = %d (%s)",
   3588 		infop->flavor, flavor_name(infop->flavor));
   3589 	switch (infop->flavor) {
   3590 	case RPCSEC_GSS:
   3591 		detail_rpcsec_gss(&infop->secinfo4_u.flavor_info);
   3592 		break;
   3593 	}
   3594 }
   3595 
   3596 
   3597 /*
   3598  * Return a summary string corresponding to the given nfs_space_limit4.
   3599  */
   3600 
   3601 static char *
   3602 sum_space_limit(nfs_space_limit4 *limitp)
   3603 {
   3604 	static char buf[64];
   3605 	int buflen = sizeof (buf);
   3606 
   3607 	buf[0] = '\0';
   3608 	switch (limitp->limitby) {
   3609 	case NFS_LIMIT_SIZE:
   3610 		snprintf(buf, buflen, "LB=SZ(%llu)",
   3611 			limitp->nfs_space_limit4_u.filesize);
   3612 		break;
   3613 	case NFS_LIMIT_BLOCKS:
   3614 		snprintf(buf, buflen, "LB=BL(%u*%u)",
   3615 			limitp->nfs_space_limit4_u.mod_blocks.num_blocks,
   3616 			limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
   3617 		break;
   3618 	default:
   3619 		snprintf(buf, buflen, "LB=?(%d)", limitp->limitby);
   3620 		break;
   3621 	}
   3622 
   3623 	return (buf);
   3624 }
   3625 
   3626 /*
   3627  * Print detail information about the given nfs_space_limit4.
   3628  */
   3629 
   3630 static void
   3631 detail_space_limit(nfs_space_limit4 *limitp)
   3632 {
   3633 	sprintf(get_line(0, 0), "LimitBy = %d (%s)",
   3634 		limitp->limitby,
   3635 		limitby_name(limitp->limitby));
   3636 
   3637 	switch (limitp->limitby) {
   3638 	case NFS_LIMIT_SIZE:
   3639 		sprintf(get_line(0, 0), "Bytes = %llu",
   3640 			limitp->nfs_space_limit4_u.filesize);
   3641 		break;
   3642 	case NFS_LIMIT_BLOCKS:
   3643 		sprintf(get_line(0, 0), "Blocks = %u",
   3644 			limitp->nfs_space_limit4_u.mod_blocks.num_blocks);
   3645 		sprintf(get_line(0, 0), "Bytes Per Block = %u",
   3646 			limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block);
   3647 		break;
   3648 	}
   3649 }
   3650 
   3651 
   3652 /*
   3653  * Return the short name of a file type.
   3654  */
   3655 
   3656 static char *
   3657 sum_type_name(nfs_ftype4 type)
   3658 {
   3659 	static char buf[20];
   3660 
   3661 	if (type < num_ftypes)
   3662 		return (ftype_names[type].short_name);
   3663 	else {
   3664 		sprintf(buf, "type %d", type);
   3665 		return (buf);
   3666 	}
   3667 }
   3668 
   3669 
   3670 /*
   3671  * Return string with long/short flag names
   3672  */
   3673 
   3674 static char *
   3675 get_flags(uint_t flag, ftype_names_t *names, uint_t num_flags, int shortname,
   3676 	char *prefix)
   3677 {
   3678 	static char buf[200];
   3679 	char *bp = buf, *str;
   3680 	int i, len, blen = sizeof (buf);
   3681 	ftype_names_t *fn = NULL;
   3682 
   3683 	*bp = '\0';
   3684 
   3685 	if (prefix) {
   3686 		snprintf(bp, blen, "%s", prefix);
   3687 		bp += (len = sizeof (bp));
   3688 		blen -= len;
   3689 	}
   3690 
   3691 	for (i = 0; i < 32; i++)
   3692 		if (flag & (1 << i)) {
   3693 			fn = names + (i < num_flags ? i : num_flags);
   3694 			str = (shortname ? fn->short_name : fn->long_name);
   3695 
   3696 			snprintf(bp, blen, "%s,", str);
   3697 			bp += (len = strlen(bp));
   3698 			blen -= len;
   3699 		}
   3700 
   3701 	if (fn)
   3702 		*(bp - 1) = '\0';
   3703 	else
   3704 		*buf = '\0';
   3705 
   3706 	return (buf);
   3707 }
   3708 
   3709 
   3710 /*
   3711  * Return the long name of a file type.
   3712  */
   3713 
   3714 static char *
   3715 detail_type_name(nfs_ftype4 type)
   3716 {
   3717 	static char buf[20];
   3718 
   3719 	if (type < num_ftypes)
   3720 		return (ftype_names[type].long_name);
   3721 	else {
   3722 		sprintf(buf, "type %d", type);
   3723 		return (buf);
   3724 	}
   3725 }
   3726 
   3727 /*
   3728  * Return the name of an attribute.
   3729  */
   3730 
   3731 static char *
   3732 attr_name(uint_t attrnum)
   3733 {
   3734 	static char buf[20];
   3735 
   3736 	if (attrnum < MAX_ATTRIBUTES)
   3737 		return (attr_info[attrnum].name);
   3738 	else {
   3739 		sprintf(buf, "attr #%d", attrnum);
   3740 		return (buf);
   3741 	}
   3742 }
   3743 
   3744 /*
   3745  * Return the name of the given open_claim_type4.
   3746  */
   3747 
   3748 static char *
   3749 claim_name(enum open_claim_type4 claim_type)
   3750 {
   3751 	char *result;
   3752 
   3753 	switch (claim_type) {
   3754 	case CLAIM_NULL:
   3755 		result = "NULL";
   3756 		break;
   3757 	case CLAIM_PREVIOUS:
   3758 		result = "PREVIOUS";
   3759 		break;
   3760 	case CLAIM_DELEGATE_CUR:
   3761 		result = "DELEGATE CURRENT";
   3762 		break;
   3763 	case CLAIM_DELEGATE_PREV:
   3764 		result = "DELEGATE PREVIOUS";
   3765 		break;
   3766 	default:
   3767 		result = "?";
   3768 		break;
   3769 	}
   3770 
   3771 	return (result);
   3772 }
   3773 
   3774 /*
   3775  * Return a string naming the given delegation.
   3776  */
   3777 
   3778 static char *
   3779 delegation_type_name(enum open_delegation_type4 type)
   3780 {
   3781 	char *result;
   3782 
   3783 	switch (type) {
   3784 	case OPEN_DELEGATE_NONE:
   3785 		result = "NONE";
   3786 		break;
   3787 	case OPEN_DELEGATE_READ:
   3788 		result = "READ";
   3789 		break;
   3790 	case OPEN_DELEGATE_WRITE:
   3791 		result = "WRITE";
   3792 		break;
   3793 	default:
   3794 		result = "?";
   3795 		break;
   3796 	}
   3797 
   3798 	return (result);
   3799 }
   3800 
   3801 /*
   3802  * Return the name of the given authentication flavor.
   3803  */
   3804 
   3805 static char *
   3806 flavor_name(uint_t flavor)
   3807 {
   3808 	char *result;
   3809 	static char buf[50];
   3810 
   3811 	switch (flavor) {
   3812 	case AUTH_SYS:
   3813 		result = "AUTH_SYS";
   3814 		break;
   3815 	case AUTH_NONE:
   3816 		result = "AUTH_NONE";
   3817 		break;
   3818 	case AUTH_DH:
   3819 		result = "AUTH_DH";
   3820 		break;
   3821 	case RPCSEC_GSS:
   3822 		result = "RPCSEC_GSS";
   3823 		break;
   3824 	default:
   3825 		sprintf(buf, "[flavor %d]", flavor);
   3826 		result = buf;
   3827 		break;
   3828 	}
   3829 
   3830 	return (result);
   3831 }
   3832 
   3833 /*
   3834  * Return the name of the given rpc_gss_svc_t.
   3835  */
   3836 
   3837 static char *
   3838 gss_svc_name(rpc_gss_svc_t svc)
   3839 {
   3840 	char *result;
   3841 	static char buf[50];
   3842 
   3843 	switch (svc) {
   3844 	case RPC_GSS_SVC_NONE:
   3845 		result = "NONE";
   3846 		break;
   3847 	case RPC_GSS_SVC_INTEGRITY:
   3848 		result = "INTEGRITY";
   3849 		break;
   3850 	case RPC_GSS_SVC_PRIVACY:
   3851 		result = "PRIVACY";
   3852 		break;
   3853 	default:
   3854 		sprintf(buf, "Service %d", svc);
   3855 		result = buf;
   3856 		break;
   3857 	}
   3858 
   3859 	return (result);
   3860 }
   3861 
   3862 /*
   3863  * Return a string name for the given limit_by4.
   3864  */
   3865 
   3866 static char *
   3867 limitby_name(enum limit_by4 limitby)
   3868 {
   3869 	char *result;
   3870 
   3871 	switch (limitby) {
   3872 	case NFS_LIMIT_SIZE:
   3873 		result = "SIZE";
   3874 		break;
   3875 	case NFS_LIMIT_BLOCKS:
   3876 		result = "BLOCKS";
   3877 		break;
   3878 	default:
   3879 		result = "?";
   3880 		break;
   3881 	}
   3882 
   3883 	return (result);
   3884 }
   3885 
   3886 static char *
   3887 status_name(int status)
   3888 {
   3889 	char *p;
   3890 
   3891 	switch (status) {
   3892 	case NFS4_OK:		p = "NFS4_OK"; break;
   3893 	case NFS4ERR_PERM:	p = "NFS4ERR_PERM"; break;
   3894 	case NFS4ERR_NOENT:	p = "NFS4ERR_NOENT"; break;
   3895 	case NFS4ERR_IO:	p = "NFS4ERR_IO"; break;
   3896 	case NFS4ERR_NXIO:	p = "NFS4ERR_NXIO"; break;
   3897 	case NFS4ERR_ACCESS:	p = "NFS4ERR_ACCESS"; break;
   3898 	case NFS4ERR_EXIST:	p = "NFS4ERR_EXIST"; break;
   3899 	case NFS4ERR_XDEV:	p = "NFS4ERR_XDEV"; break;
   3900 	case NFS4ERR_NOTDIR:	p = "NFS4ERR_NOTDIR"; break;
   3901 	case NFS4ERR_ISDIR:	p = "NFS4ERR_ISDIR"; break;
   3902 	case NFS4ERR_INVAL:	p = "NFS4ERR_INVAL"; break;
   3903 	case NFS4ERR_FBIG:	p = "NFS4ERR_FBIG"; break;
   3904 	case NFS4ERR_NOSPC:	p = "NFS4ERR_NOSPC"; break;
   3905 	case NFS4ERR_ROFS:	p = "NFS4ERR_ROFS"; break;
   3906 	case NFS4ERR_MLINK:	p = "NFS4ERR_MLINK"; break;
   3907 	case NFS4ERR_NAMETOOLONG:p = "NFS4ERR_NAMETOOLONG"; break;
   3908 	case NFS4ERR_NOTEMPTY:	p = "NFS4ERR_NOTEMPTY"; break;
   3909 	case NFS4ERR_DQUOT:	p = "NFS4ERR_DQUOT"; break;
   3910 	case NFS4ERR_STALE:	p = "NFS4ERR_STALE"; break;
   3911 	case NFS4ERR_BADHANDLE:	p = "NFS4ERR_BADHANDLE"; break;
   3912 	case NFS4ERR_BAD_COOKIE:p = "NFS4ERR_BAD_COOKIE"; break;
   3913 	case NFS4ERR_NOTSUPP:	p = "NFS4ERR_NOTSUPP"; break;
   3914 	case NFS4ERR_TOOSMALL:	p = "NFS4ERR_TOOSMALL"; break;
   3915 	case NFS4ERR_SERVERFAULT:p = "NFS4ERR_SERVERFAULT"; break;
   3916 	case NFS4ERR_BADTYPE:	p = "NFS4ERR_BADTYPE"; break;
   3917 	case NFS4ERR_DELAY:	p = "NFS4ERR_DELAY"; break;
   3918 	case NFS4ERR_SAME:	p = "NFS4ERR_SAME"; break;
   3919 	case NFS4ERR_DENIED:	p = "NFS4ERR_DENIED"; break;
   3920 	case NFS4ERR_EXPIRED:	p = "NFS4ERR_EXPIRED"; break;
   3921 	case NFS4ERR_LOCKED:	p = "NFS4ERR_LOCKED"; break;
   3922 	case NFS4ERR_GRACE:	p = "NFS4ERR_GRACE"; break;
   3923 	case NFS4ERR_FHEXPIRED:	p = "NFS4ERR_FHEXPIRED"; break;
   3924 	case NFS4ERR_SHARE_DENIED: p = "NFS4ERR_SHARE_DENIED"; break;
   3925 	case NFS4ERR_WRONGSEC:	p = "NFS4ERR_WRONGSEC"; break;
   3926 	case NFS4ERR_CLID_INUSE: p = "NFS4ERR_CLID_INUSE"; break;
   3927 	case NFS4ERR_RESOURCE:	p = "NFS4ERR_RESOURCE"; break;
   3928 	case NFS4ERR_MOVED:	p = "NFS4ERR_MOVED"; break;
   3929 	case NFS4ERR_NOFILEHANDLE: p = "NFS4ERR_NOFILEHANDLE"; break;
   3930 	case NFS4ERR_MINOR_VERS_MISMATCH: p =
   3931 				"NFS4ERR_MINOR_VERS_MISMATCH"; break;
   3932 	case NFS4ERR_STALE_CLIENTID: p = "NFS4ERR_STALE_CLIENTID"; break;
   3933 	case NFS4ERR_STALE_STATEID: p = "NFS4ERR_STALE_STATEID"; break;
   3934 	case NFS4ERR_OLD_STATEID: p = "NFS4ERR_OLD_STATEID"; break;
   3935 	case NFS4ERR_BAD_STATEID: p = "NFS4ERR_BAD_STATEID"; break;
   3936 	case NFS4ERR_BAD_SEQID: p = "NFS4ERR_BAD_SEQID"; break;
   3937 	case NFS4ERR_NOT_SAME: p = "NFS4ERR_NOT_SAME"; break;
   3938 	case NFS4ERR_LOCK_RANGE: p = "NFS4ERR_LOCK_RANGE"; break;
   3939 	case NFS4ERR_SYMLINK: p = "NFS4ERR_SYMLINK"; break;
   3940 	case NFS4ERR_RESTOREFH: p = "NFS4ERR_RESTOREFH"; break;
   3941 	case NFS4ERR_LEASE_MOVED: p = "NFS4ERR_LEASE_MOVED"; break;
   3942 	case NFS4ERR_ATTRNOTSUPP: p = "NFS4ERR_ATTRNOTSUPP"; break;
   3943 	case NFS4ERR_NO_GRACE: p = "NFS4ERR_NO_GRACE"; break;
   3944 	case NFS4ERR_RECLAIM_BAD: p = "NFS4ERR_RECLAIM_BAD"; break;
   3945 	case NFS4ERR_RECLAIM_CONFLICT: p = "NFS4ERR_RECLAIM_CONFLICT"; break;
   3946 	case NFS4ERR_BADXDR: p = "NFS4ERR_BADXDR"; break;
   3947 	case NFS4ERR_LOCKS_HELD: p = "NFS4ERR_LOCKS_HELD"; break;
   3948 	case NFS4ERR_OPENMODE: p = "NFS4ERR_OPENMODE"; break;
   3949 	case NFS4ERR_BADOWNER: p = "NFS4ERR_BADOWNER"; break;
   3950 	case NFS4ERR_BADCHAR: p = "NFS4ERR_BADCHAR"; break;
   3951 	case NFS4ERR_BADNAME: p = "NFS4ERR_BADNAME"; break;
   3952 	case NFS4ERR_BAD_RANGE: p = "NFS4ERR_BAD_RANGE"; break;
   3953 	case NFS4ERR_LOCK_NOTSUPP: p = "NFS4ERR_LOCK_NOTSUPP"; break;
   3954 	case NFS4ERR_OP_ILLEGAL: p = "NFS4ERR_OP_ILLEGAL"; break;
   3955 	case NFS4ERR_DEADLOCK: p = "NFS4ERR_DEADLOCK"; break;
   3956 	case NFS4ERR_FILE_OPEN: p = "NFS4ERR_FILE_OPEN"; break;
   3957 	case NFS4ERR_ADMIN_REVOKED: p = "NFS4ERR_ADMIN_REVOKED"; break;
   3958 	case NFS4ERR_CB_PATH_DOWN: p = "NFS4ERR_CB_PATH_DOWN"; break;
   3959 	default:		p = "(unknown error)"; break;
   3960 	}
   3961 
   3962 	return (p);
   3963 }
   3964 
   3965 char *
   3966 nfsstat4_to_name(int status)
   3967 {
   3968 	return (status_name(status));
   3969 }
   3970 
   3971 /*
   3972  * Attribute print functions.  See attr_info_t.
   3973  */
   3974 
   3975 static void
   3976 prt_supported_attrs(XDR *xdr)
   3977 {
   3978 	static bitmap4 val;
   3979 
   3980 	if (!xdr_bitmap4(xdr, &val))
   3981 		longjmp(xdr_err, 1);
   3982 	sprintf(get_line(0, 0), "Supported Attributes:");
   3983 	detail_attr_bitmap("\t", &val, NULL);
   3984 	xdr_free(xdr_bitmap4, (char *)&val);
   3985 }
   3986 
   3987 static void
   3988 prt_type(XDR *xdr)
   3989 {
   3990 	nfs_ftype4 val;
   3991 
   3992 	if (!xdr_nfs_ftype4(xdr, &val))
   3993 		longjmp(xdr_err, 1);
   3994 	sprintf(get_line(0, 0), "Type = %s", sum_type_name(val));
   3995 }
   3996 
   3997 static void
   3998 prt_fh_expire_type(XDR *xdr)
   3999 {
   4000 	fattr4_fh_expire_type val;
   4001 	char *buf;
   4002 	bool_t first = TRUE;
   4003 
   4004 	if (!xdr_fattr4_fh_expire_type(xdr, &val))
   4005 		longjmp(xdr_err, 1);
   4006 	buf = get_line(0, 0);
   4007 
   4008 	sprintf(buf, "Filehandle expire type = ");
   4009 	if ((val & (FH4_NOEXPIRE_WITH_OPEN | FH4_VOLATILE_ANY |
   4010 			FH4_VOL_MIGRATION | FH4_VOL_RENAME)) == 0) {
   4011 		strcat(buf, "Persistent");
   4012 		return;
   4013 	}
   4014 	if (val & FH4_NOEXPIRE_WITH_OPEN) {
   4015 		strcat(buf, "No Expire With OPEN");
   4016 		first = FALSE;
   4017 	}
   4018 	if (val & FH4_VOLATILE_ANY) {
   4019 		if (first)
   4020 			first = FALSE;
   4021 		else
   4022 			strcat(buf, ", ");
   4023 		strcat(buf, "Volatile at any time");
   4024 	}
   4025 	if (val & FH4_VOL_MIGRATION) {
   4026 		if (first)
   4027 			first = FALSE;
   4028 		else
   4029 			strcat(buf, ", ");
   4030 		strcat(buf, "Volatile at Migration");
   4031 	}
   4032 	if (val & FH4_VOL_RENAME) {
   4033 		if (first)
   4034 			first = FALSE;
   4035 		else
   4036 			strcat(buf, ", ");
   4037 		strcat(buf, "Volatile at Rename");
   4038 	}
   4039 }
   4040 
   4041 static void
   4042 prt_change(XDR *xdr)
   4043 {
   4044 	changeid4 val;
   4045 
   4046 	if (!xdr_changeid4(xdr, &val))
   4047 		longjmp(xdr_err, 1);
   4048 	sprintf(get_line(0, 0), "Change ID = 0x%llx", val);
   4049 					/* XXX print as time_t, too? */
   4050 }
   4051 
   4052 static void
   4053 prt_size(XDR *xdr)
   4054 {
   4055 	uint64_t val;
   4056 
   4057 	if (!xdr_uint64_t(xdr, &val))
   4058 		longjmp(xdr_err, 1);
   4059 	sprintf(get_line(0, 0), "Size = %llu", val);
   4060 }
   4061 
   4062 static void
   4063 prt_link_support(XDR *xdr)
   4064 {
   4065 	bool_t val;
   4066 
   4067 	if (!xdr_bool(xdr, &val))
   4068 		longjmp(xdr_err, 1);
   4069 	sprintf(get_line(0, 0), "Link Support = %s",
   4070 		val ? "TRUE" : "FALSE");
   4071 }
   4072 
   4073 static void
   4074 prt_symlink_support(XDR *xdr)
   4075 {
   4076 	bool_t val;
   4077 
   4078 	if (!xdr_bool(xdr, &val))
   4079 		longjmp(xdr_err, 1);
   4080 	sprintf(get_line(0, 0), "Symlink Support = %s",
   4081 		val ? "TRUE" : "FALSE");
   4082 }
   4083 
   4084 static void
   4085 prt_named_attr(XDR *xdr)
   4086 {
   4087 	bool_t val;
   4088 
   4089 	if (!xdr_bool(xdr, &val))
   4090 		longjmp(xdr_err, 1);
   4091 	sprintf(get_line(0, 0), "Has Named Attributes = %s",
   4092 		val ? "TRUE" : "FALSE");
   4093 }
   4094 
   4095 static void
   4096 prt_fsid(XDR *xdr)
   4097 {
   4098 	fsid4 val;
   4099 
   4100 	if (!xdr_fsid4(xdr, &val))
   4101 		longjmp(xdr_err, 1);
   4102 	sprintf(get_line(0, 0), "FS ID: Major = %llx, Minor = %llx",
   4103 		val.major, val.minor);
   4104 }
   4105 
   4106 static void
   4107 prt_unique_handles(XDR *xdr)
   4108 {
   4109 	bool_t val;
   4110 
   4111 	if (!xdr_bool(xdr, &val))
   4112 		longjmp(xdr_err, 1);
   4113 	sprintf(get_line(0, 0), "Unique Handles = %s",
   4114 		val ? "TRUE" : "FALSE");
   4115 }
   4116 
   4117 static void
   4118 prt_lease_time(XDR *xdr)
   4119 {
   4120 	uint32_t val;
   4121 
   4122 	if (!xdr_uint32_t(xdr, &val))
   4123 		longjmp(xdr_err, 1);
   4124 	sprintf(get_line(0, 0), "Lease Time = %u", val);
   4125 }
   4126 
   4127 static void
   4128 prt_rdattr_error(XDR *xdr)
   4129 {
   4130 	nfsstat4 val;
   4131 
   4132 	if (!xdr_nfsstat4(xdr, &val))
   4133 		longjmp(xdr_err, 1);
   4134 	sprintf(get_line(0, 0), "Rdattr Error = %u (%s)",
   4135 		val, status_name(val));
   4136 }
   4137 
   4138 static void
   4139 prt_acl(XDR *xdr)
   4140 {
   4141 	static fattr4_acl val;
   4142 	char buffy[NFS4_OPAQUE_LIMIT];
   4143 	int i, len;
   4144 
   4145 	if (!xdr_fattr4_acl(xdr, &val))
   4146 		longjmp(xdr_err, 1);
   4147 	sprintf(get_line(0, 0), "ACL of %d entries", val.fattr4_acl_len);
   4148 	for (i = 0; i < val.fattr4_acl_len; i++) {
   4149 		sprintf(get_line(0, 0), "nfsace4[%d]", i);
   4150 
   4151 		sprintf(get_line(0, 0), "  type = %x",
   4152 		    val.fattr4_acl_val[i].type);
   4153 		detail_acetype4(val.fattr4_acl_val[i].type);
   4154 
   4155 		sprintf(get_line(0, 0), "  flags = %x",
   4156 		    val.fattr4_acl_val[i].flag);
   4157 		detail_aceflag4(val.fattr4_acl_val[i].flag);
   4158 
   4159 		sprintf(get_line(0, 0), "  mask = %x",
   4160 		    val.fattr4_acl_val[i].access_mask);
   4161 		detail_acemask4(val.fattr4_acl_val[i].access_mask);
   4162 
   4163 		len = val.fattr4_acl_val[i].who.utf8string_len;
   4164 		if (len >= NFS4_OPAQUE_LIMIT)
   4165 			len = NFS4_OPAQUE_LIMIT - 1;
   4166 		(void) strncpy(buffy, val.fattr4_acl_val[i].who.utf8string_val,
   4167 		    len);
   4168 		buffy[len] = '\0';
   4169 		sprintf(get_line(0, 0), "  who = %s", buffy);
   4170 	}
   4171 	xdr_free(xdr_fattr4_acl, (char *)&val);
   4172 }
   4173 
   4174 static void
   4175 detail_acetype4(acetype4 type)
   4176 {
   4177 	if (type >= ACETYPE4_NAMES_MAX) {
   4178 		sprintf(get_line(0, 0), "     unknown type");
   4179 	} else {
   4180 		sprintf(get_line(0, 0), "     %s", acetype4_names[type]);
   4181 	}
   4182 }
   4183 
   4184 static void
   4185 detail_uint32_bitmap(uint32_t mask, char *mask_names[], int names_max)
   4186 {
   4187 	char buffy[BUFSIZ], *name;
   4188 	char *indent = "     ";
   4189 	char *spacer = "  ";
   4190 	int pending = 0;
   4191 	int bit;
   4192 	int len, namelen, spacelen;
   4193 
   4194 	strcpy(buffy, indent);
   4195 	len = strlen(buffy);
   4196 	spacelen = strlen(spacer);
   4197 
   4198 	for (bit = 0; bit < names_max; bit++) {
   4199 		if (mask & (1 << bit)) {
   4200 			name = mask_names[bit];
   4201 			namelen = strlen(name);
   4202 			/* 80 - 6 for "NFS:  " = 74 */
   4203 			if ((len + spacelen + namelen) >= 74) {
   4204 				sprintf(get_line(0, 0), "%s", buffy);
   4205 				strcpy(buffy, indent);
   4206 				len = strlen(buffy);
   4207 				pending = 0;
   4208 			}
   4209 			(void) strlcat(buffy, spacer, sizeof (buffy));
   4210 			(void) strlcat(buffy, name, sizeof (buffy));
   4211 			pending = 1;
   4212 			len += spacelen + namelen;
   4213 		}
   4214 	}
   4215 	if (pending)
   4216 		sprintf(get_line(0, 0), "%s", buffy);
   4217 }
   4218 
   4219 static void
   4220 detail_aceflag4(aceflag4 flag)
   4221 {
   4222 	detail_uint32_bitmap(flag, aceflag4_names, ACEFLAG4_NAMES_MAX);
   4223 }
   4224 
   4225 static void
   4226 detail_acemask4(acemask4 mask)
   4227 {
   4228 	detail_uint32_bitmap(mask, acemask4_names, ACEMASK4_NAMES_MAX);
   4229 }
   4230 
   4231 static void
   4232 prt_aclsupport(XDR *xdr)
   4233 {
   4234 	fattr4_aclsupport val;
   4235 
   4236 	if (!xdr_fattr4_aclsupport(xdr, &val))
   4237 		longjmp(xdr_err, 1);
   4238 	if (val & ACL4_SUPPORT_ALLOW_ACL)
   4239 		sprintf(get_line(0, 0), "ALLOW ACL Supported");
   4240 	if (val & ACL4_SUPPORT_DENY_ACL)
   4241 		sprintf(get_line(0, 0), "DENY ACL Supported");
   4242 	if (val & ACL4_SUPPORT_AUDIT_ACL)
   4243 		sprintf(get_line(0, 0), "AUDIT ACL Supported");
   4244 	if (val & ACL4_SUPPORT_ALARM_ACL)
   4245 		sprintf(get_line(0, 0), "ALARM ACL Supported");
   4246 }
   4247 
   4248 static void
   4249 prt_archive(XDR *xdr)
   4250 {
   4251 	bool_t val;
   4252 
   4253 	if (!xdr_bool(xdr, &val))
   4254 		longjmp(xdr_err, 1);
   4255 	sprintf(get_line(0, 0), "Archived = %s",
   4256 		val ? "TRUE" : "FALSE");
   4257 }
   4258 
   4259 static void
   4260 prt_cansettime(XDR *xdr)
   4261 {
   4262 	bool_t val;
   4263 
   4264 	if (!xdr_bool(xdr, &val))
   4265 		longjmp(xdr_err, 1);
   4266 	sprintf(get_line(0, 0), "Server Can Set Time = %s",
   4267 		val ? "TRUE" : "FALSE");
   4268 }
   4269 
   4270 static void
   4271 prt_case_insensitive(XDR *xdr)
   4272 {
   4273 	bool_t val;
   4274 
   4275 	if (!xdr_bool(xdr, &val))
   4276 		longjmp(xdr_err, 1);
   4277 	sprintf(get_line(0, 0), "Case Insensitive Lookups = %s",
   4278 		val ? "TRUE" : "FALSE");
   4279 }
   4280 
   4281 static void
   4282 prt_case_preserving(XDR *xdr)
   4283 {
   4284 	bool_t val;
   4285 
   4286 	if (!xdr_bool(xdr, &val))
   4287 		longjmp(xdr_err, 1);
   4288 	sprintf(get_line(0, 0), "Case Preserving = %s",
   4289 		val ? "TRUE" : "FALSE");
   4290 }
   4291 
   4292 static void
   4293 prt_chown_restricted(XDR *xdr)
   4294 {
   4295 	bool_t val;
   4296 
   4297 	if (!xdr_bool(xdr, &val))
   4298 		longjmp(xdr_err, 1);
   4299 	sprintf(get_line(0, 0), "Chown Is Restricted = %s",
   4300 		val ? "TRUE" : "FALSE");
   4301 }
   4302 
   4303 static void
   4304 prt_filehandle(XDR *xdr)
   4305 {
   4306 	static nfs_fh4 val;
   4307 
   4308 	if (!xdr_nfs_fh4(xdr, &val))
   4309 		longjmp(xdr_err, 1);
   4310 	detail_fh4(&val);
   4311 	xdr_free(xdr_nfs_fh4, (char *)&val);
   4312 }
   4313 
   4314 static void
   4315 prt_fileid(XDR *xdr)
   4316 {
   4317 	uint64_t val;
   4318 
   4319 	if (!xdr_uint64_t(xdr, &val))
   4320 		longjmp(xdr_err, 1);
   4321 	sprintf(get_line(0, 0), "File ID = %llu", val);
   4322 }
   4323 
   4324 static void
   4325 prt_mounted_on_fileid(XDR *xdr)
   4326 {
   4327 	uint64_t val;
   4328 
   4329 	if (!xdr_uint64_t(xdr, &val))
   4330 		longjmp(xdr_err, 1);
   4331 	sprintf(get_line(0, 0), "Mounted On File ID = %llu", val);
   4332 }
   4333 
   4334 static void
   4335 prt_files_avail(XDR *xdr)
   4336 {
   4337 	uint64_t val;
   4338 
   4339 	if (!xdr_uint64_t(xdr, &val))
   4340 		longjmp(xdr_err, 1);
   4341 	sprintf(get_line(0, 0), "Files Available = %llu", val);
   4342 }
   4343 
   4344 static void
   4345 prt_files_free(XDR *xdr)
   4346 {
   4347 	uint64_t val;
   4348 
   4349 	if (!xdr_uint64_t(xdr, &val))
   4350 		longjmp(xdr_err, 1);
   4351 	sprintf(get_line(0, 0), "Files Free = %llu", val);
   4352 }
   4353 
   4354 static void
   4355 prt_files_total(XDR *xdr)
   4356 {
   4357 	uint64_t val;
   4358 
   4359 	if (!xdr_uint64_t(xdr, &val))
   4360 		longjmp(xdr_err, 1);
   4361 	sprintf(get_line(0, 0), "Files Total = %llu", val);
   4362 }
   4363 
   4364 static void
   4365 prt_fs_locations(XDR *xdr)
   4366 {
   4367 	static fs_locations4 val;
   4368 
   4369 	if (!xdr_fs_locations4(xdr, &val))
   4370 		longjmp(xdr_err, 1);
   4371 	sprintf(get_line(0, 0), "[fs_locations]"); /* XXX */
   4372 	detail_pathname4(&val.fs_root);
   4373 	xdr_free(xdr_fs_locations4, (char *)&val);
   4374 }
   4375 
   4376 static void
   4377 prt_hidden(XDR *xdr)
   4378 {
   4379 	bool_t val;
   4380 
   4381 	if (!xdr_bool(xdr, &val))
   4382 		longjmp(xdr_err, 1);
   4383 	sprintf(get_line(0, 0), "Hidden = %s",
   4384 		val ? "TRUE" : "FALSE");
   4385 }
   4386 
   4387 static void
   4388 prt_homogeneous(XDR *xdr)
   4389 {
   4390 	bool_t val;
   4391 
   4392 	if (!xdr_bool(xdr, &val))
   4393 		longjmp(xdr_err, 1);
   4394 	sprintf(get_line(0, 0), "FS Is Homogeneous = %s",
   4395 		val ? "TRUE" : "FALSE");
   4396 }
   4397 
   4398 static void
   4399 prt_maxfilesize(XDR *xdr)
   4400 {
   4401 	uint64_t val;
   4402 
   4403 	if (!xdr_uint64_t(xdr, &val))
   4404 		longjmp(xdr_err, 1);
   4405 	sprintf(get_line(0, 0), "Maximum File Size = %llu", val);
   4406 }
   4407 
   4408 static void
   4409 prt_maxlink(XDR *xdr)
   4410 {
   4411 	uint32_t val;
   4412 
   4413 	if (!xdr_uint32_t(xdr, &val))
   4414 		longjmp(xdr_err, 1);
   4415 	sprintf(get_line(0, 0), "Maximum Number of Links = %u", val);
   4416 }
   4417 
   4418 static void
   4419 prt_maxname(XDR *xdr)
   4420 {
   4421 	uint32_t val;
   4422 
   4423 	if (!xdr_uint32_t(xdr, &val))
   4424 		longjmp(xdr_err, 1);
   4425 	sprintf(get_line(0, 0), "Maximum File Name Length = %u", val);
   4426 }
   4427 
   4428 static void
   4429 prt_maxread(XDR *xdr)
   4430 {
   4431 	uint64_t val;
   4432 
   4433 	if (!xdr_uint64_t(xdr, &val))
   4434 		longjmp(xdr_err, 1);
   4435 	sprintf(get_line(0, 0), "Maximum Read Size = %llu", val);
   4436 }
   4437 
   4438 static void
   4439 prt_maxwrite(XDR *xdr)
   4440 {
   4441 	uint64_t val;
   4442 
   4443 	if (!xdr_uint64_t(xdr, &val))
   4444 		longjmp(xdr_err, 1);
   4445 
   4446 	sprintf(get_line(0, 0), "Maximum Write Size = %llu", val);
   4447 }
   4448 
   4449 static void
   4450 prt_mimetype(XDR *xdr)
   4451 {
   4452 	static utf8string val;
   4453 
   4454 	if (!xdr_utf8string(xdr, &val))
   4455 		longjmp(xdr_err, 1);
   4456 	sprintf(get_line(0, 0), "MIME Type = %s", utf8localize(&val));
   4457 	xdr_free(xdr_utf8string, (char *)&val);
   4458 }
   4459 
   4460 static void
   4461 prt_mode(XDR *xdr)
   4462 {
   4463 	mode4 val;
   4464 
   4465 	if (!xdr_mode4(xdr, &val))
   4466 		longjmp(xdr_err, 1);
   4467 	sprintf(get_line(0, 0), "Mode = 0%03o", val);
   4468 }
   4469 
   4470 static void
   4471 prt_no_trunc(XDR *xdr)
   4472 {
   4473 	bool_t val;
   4474 
   4475 	if (!xdr_bool(xdr, &val))
   4476 		longjmp(xdr_err, 1);
   4477 	sprintf(get_line(0, 0), "Long Names Are Error (no_trunc) = %s",
   4478 		val ? "TRUE" : "FALSE");
   4479 }
   4480 
   4481 static void
   4482 prt_numlinks(XDR *xdr)
   4483 {
   4484 	uint32_t val;
   4485 
   4486 	if (!xdr_uint32_t(xdr, &val))
   4487 		longjmp(xdr_err, 1);
   4488 	sprintf(get_line(0, 0), "Number of Links = %u", val);
   4489 }
   4490 
   4491 static void
   4492 prt_owner(XDR *xdr)
   4493 {
   4494 	static utf8string val;
   4495 
   4496 	if (!xdr_utf8string(xdr, &val))
   4497 		longjmp(xdr_err, 1);
   4498 	sprintf(get_line(0, 0), "Owner = %s", utf8localize(&val));
   4499 	xdr_free(xdr_utf8string, (char *)&val);
   4500 }
   4501 
   4502 static void
   4503 prt_owner_group(XDR *xdr)
   4504 {
   4505 	static utf8string val;
   4506 
   4507 	if (!xdr_utf8string(xdr, &val))
   4508 		longjmp(xdr_err, 1);
   4509 	sprintf(get_line(0, 0), "Group = %s", utf8localize(&val));
   4510 	xdr_free(xdr_utf8string, (char *)&val);
   4511 }
   4512 
   4513 static void
   4514 prt_quota_avail_hard(XDR *xdr)
   4515 {
   4516 	uint64_t val;
   4517 
   4518 	if (!xdr_uint64_t(xdr, &val))
   4519 		longjmp(xdr_err, 1);
   4520 	sprintf(get_line(0, 0), "Quota Hard Limit = %llu", val);
   4521 }
   4522 
   4523 static void
   4524 prt_quota_avail_soft(XDR *xdr)
   4525 {
   4526 	uint64_t val;
   4527 
   4528 	if (!xdr_uint64_t(xdr, &val))
   4529 		longjmp(xdr_err, 1);
   4530 	sprintf(get_line(0, 0), "Quota Soft Limit = %llu", val);
   4531 }
   4532 
   4533 static void
   4534 prt_quota_used(XDR *xdr)
   4535 {
   4536 	uint64_t val;
   4537 
   4538 	if (!xdr_uint64_t(xdr, &val))
   4539 		longjmp(xdr_err, 1);
   4540 	sprintf(get_line(0, 0), "Quota Used = %llu", val);
   4541 }
   4542 
   4543 static void
   4544 prt_rawdev(XDR *xdr)
   4545 {
   4546 	specdata4 val;
   4547 
   4548 	if (!xdr_specdata4(xdr, &val))
   4549 		longjmp(xdr_err, 1);
   4550 	sprintf(get_line(0, 0), "Raw Device ID = %u, %u",
   4551 		val.specdata1, val.specdata2);
   4552 }
   4553 
   4554 static void
   4555 prt_space_avail(XDR *xdr)
   4556 {
   4557 	uint64_t val;
   4558 
   4559 	if (!xdr_uint64_t(xdr, &val))
   4560 		longjmp(xdr_err, 1);
   4561 	sprintf(get_line(0, 0), "Space Available = %llu", val);
   4562 }
   4563 
   4564 static void
   4565 prt_space_free(XDR *xdr)
   4566 {
   4567 	uint64_t val;
   4568 
   4569 	if (!xdr_uint64_t(xdr, &val))
   4570 		longjmp(xdr_err, 1);
   4571 	sprintf(get_line(0, 0), "Space Free = %llu", val);
   4572 }
   4573 
   4574 static void
   4575 prt_space_total(XDR *xdr)
   4576 {
   4577 	uint64_t val;
   4578 
   4579 	if (!xdr_uint64_t(xdr, &val))
   4580 		longjmp(xdr_err, 1);
   4581 	sprintf(get_line(0, 0), "Total Disk Space = %llu", val);
   4582 }
   4583 
   4584 static void
   4585 prt_space_used(XDR *xdr)
   4586 {
   4587 	uint64_t val;
   4588 
   4589 	if (!xdr_uint64_t(xdr, &val))
   4590 		longjmp(xdr_err, 1);
   4591 	sprintf(get_line(0, 0), "Space Used (this object) = %llu", val);
   4592 }
   4593 
   4594 static void
   4595 prt_system(XDR *xdr)
   4596 {
   4597 	bool_t val;
   4598 
   4599 	if (!xdr_bool(xdr, &val))
   4600 		longjmp(xdr_err, 1);
   4601 	sprintf(get_line(0, 0), "System File = %s",
   4602 		val ? "TRUE" : "FALSE");
   4603 }
   4604 
   4605 static void
   4606 prt_time_access(XDR *xdr)
   4607 {
   4608 	nfstime4 val;
   4609 
   4610 	if (!xdr_nfstime4(xdr, &val))
   4611 		longjmp(xdr_err, 1);
   4612 	sprintf(get_line(0, 0), "Last Access Time = %s",
   4613 		format_time(val.seconds, val.nseconds));
   4614 }
   4615 
   4616 static void
   4617 prt_time_access_set(XDR *xdr)
   4618 {
   4619 	settime4 val;
   4620 
   4621 	if (!xdr_settime4(xdr, &val))
   4622 		longjmp(xdr_err, 1);
   4623 	if (val.set_it == SET_TO_CLIENT_TIME4) {
   4624 		sprintf(get_line(0, 0), "Access Time = %s (set to client time)",
   4625 			format_time(val.settime4_u.time.seconds,
   4626 			val.settime4_u.time.nseconds));
   4627 	} else if (val.set_it == SET_TO_SERVER_TIME4) {
   4628 		sprintf(get_line(0, 0), "Access Time (set to server time)");
   4629 	} else
   4630 		longjmp(xdr_err, 1);
   4631 }
   4632 
   4633 static void
   4634 prt_time_backup(XDR *xdr)
   4635 {
   4636 	nfstime4 val;
   4637 
   4638 	if (!xdr_nfstime4(xdr, &val))
   4639 		longjmp(xdr_err, 1);
   4640 	sprintf(get_line(0, 0), "Last Backup Time = %s",
   4641 		format_time(val.seconds, val.nseconds));
   4642 }
   4643 
   4644 static void
   4645 prt_time_create(XDR *xdr)
   4646 {
   4647 	nfstime4 val;
   4648 
   4649 	if (!xdr_nfstime4(xdr, &val))
   4650 		longjmp(xdr_err, 1);
   4651 	sprintf(get_line(0, 0), "Creation Time = %s",
   4652 		format_time(val.seconds, val.nseconds));
   4653 }
   4654 
   4655 static void
   4656 prt_time_delta(XDR *xdr)
   4657 {
   4658 	nfstime4 val;
   4659 
   4660 	if (!xdr_nfstime4(xdr, &val))
   4661 		longjmp(xdr_err, 1);
   4662 	sprintf(get_line(0, 0), "Server Time Granularity = %lld.%09d sec",
   4663 		val.seconds, val.nseconds);
   4664 }
   4665 
   4666 static void
   4667 prt_time_metadata(XDR *xdr)
   4668 {
   4669 	nfstime4 val;
   4670 
   4671 	if (!xdr_nfstime4(xdr, &val))
   4672 		longjmp(xdr_err, 1);
   4673 	sprintf(get_line(0, 0), "Last Metadata Change Time = %s",
   4674 		format_time(val.seconds, val.nseconds));
   4675 }
   4676 
   4677 static void
   4678 prt_time_modify(XDR *xdr)
   4679 {
   4680 	nfstime4 val;
   4681 
   4682 	if (!xdr_nfstime4(xdr, &val))
   4683 		longjmp(xdr_err, 1);
   4684 	sprintf(get_line(0, 0), "Last Modification Time = %s",
   4685 		format_time(val.seconds, val.nseconds));
   4686 }
   4687 
   4688 static void
   4689 prt_time_modify_set(XDR *xdr)
   4690 {
   4691 	settime4 val;
   4692 
   4693 	if (!xdr_settime4(xdr, &val))
   4694 		longjmp(xdr_err, 1);
   4695 	if (val.set_it == SET_TO_CLIENT_TIME4) {
   4696 		sprintf(get_line(0, 0),
   4697 			"Modification Time = %s (set to client time)",
   4698 			format_time(val.settime4_u.time.seconds,
   4699 			val.settime4_u.time.nseconds));
   4700 	} else if (val.set_it == SET_TO_SERVER_TIME4) {
   4701 		sprintf(get_line(0, 0),
   4702 			"Modification Time (set to server time)");
   4703 	} else
   4704 		longjmp(xdr_err, 1);
   4705 }
   4706 
   4707 /*
   4708  * Display the UTF8 string that is next in the XDR stream.
   4709  */
   4710 
   4711 static void
   4712 showxdr_utf8string(char *fmt)
   4713 {
   4714 	static utf8string string;
   4715 
   4716 	if (!xdr_utf8string(&xdrm, &string))
   4717 		longjmp(xdr_err, 1);
   4718 	sprintf(get_line(0, 0), fmt, utf8localize(&string));
   4719 	xdr_free(xdr_utf8string, (char *)&string);
   4720 }
   4721 
   4722 /*
   4723  * utf8string is defined in nfs4_prot.x as an opaque array, which means
   4724  * when it is decoded into a string, the string might not have a trailing
   4725  * null.  Also, the string will still be encoded in UTF-8, rather than
   4726  * whatever character encoding is associated with the current locale.  This
   4727  * routine converts a utf8string into a (null-terminated) C string.  One day
   4728  * it will convert into the current character encoding, too.  To avoid
   4729  * dealing with storage management issues, it allocates storage for each
   4730  * new string, then this storage is "freed" when the packet has been
   4731  * processed.
   4732  */
   4733 
   4734 #define	MAX_UTF8_STRINGS	512
   4735 
   4736 static char *utf_buf[MAX_UTF8_STRINGS];
   4737 static size_t utf_buflen[MAX_UTF8_STRINGS];
   4738 static uint_t cur_utf_buf = 0;
   4739 
   4740 static char *
   4741 utf8localize(utf8string *utf8str)
   4742 {
   4743 	size_t newsize, oldsize, len;
   4744 	char *result, *cp;
   4745 
   4746 	len = utf8str->utf8string_len;
   4747 	if (len == 0)
   4748 		return ("");
   4749 	if (cur_utf_buf >= MAX_UTF8_STRINGS)
   4750 		return ("[Too Many UTF-8 Strings]");
   4751 
   4752 	newsize = oldsize = utf_buflen[cur_utf_buf];
   4753 
   4754 
   4755 	if (oldsize < len + 1) {
   4756 		/* truncate opaques at NFS4_OPAQUE_LIMIT */
   4757 		if (len > NFS4_OPAQUE_LIMIT)
   4758 			len = NFS4_OPAQUE_LIMIT;
   4759 		newsize = len + 1;
   4760 	}
   4761 	if (newsize != oldsize) {
   4762 		utf_buf[cur_utf_buf] = realloc(utf_buf[cur_utf_buf],
   4763 					    newsize);
   4764 		if (utf_buf[cur_utf_buf] == NULL) {
   4765 			pr_err("out of memory\n");
   4766 			utf_buflen[cur_utf_buf] = 0;
   4767 			return ("");
   4768 		}
   4769 		utf_buflen[cur_utf_buf] = newsize;
   4770 	}
   4771 
   4772 	result = utf_buf[cur_utf_buf];
   4773 	strncpy(result, utf8str->utf8string_val, len);
   4774 	result[len] = '\0';
   4775 	for (cp = result; cp < result + len; cp++) {
   4776 		if (!isprint(*cp)) {
   4777 			*cp = '.';
   4778 		}
   4779 	}
   4780 
   4781 	cur_utf_buf++;
   4782 
   4783 	return (result);
   4784 }
   4785 
   4786 static void
   4787 utf8free()
   4788 {
   4789 	cur_utf_buf = 0;
   4790 }
   4791 
   4792 
   4793 /*
   4794  * adler16(): adler32 hash code shamelessly copied and mutiliated from
   4795  * usr/src/uts/common/io/ppp/spppcomp/zlib.[ch]
   4796  *
   4797  * The alg was originally created to provide a running
   4798  * checksum, but we don't need that -- we just want to
   4799  * chksum data described by buf,len; therefore, the first
   4800  * parameter was removed (held the running checksum),
   4801  * and s1/s2 are always set to their required initial
   4802  * values (1 and 0).  I also ripped out code which only
   4803  * applied to large data sets (bufs larger than 5k).  All
   4804  * I wanted was their core checksum alg (which is supposed
   4805  * to do really well).  The v2/v3 hash alg didn't work well
   4806  * at all for v4 stuff -- it produced too many collisions.
   4807  *
   4808  * The copyright info from uts/common/io/ppp/spppcomp/zlib.[ch]
   4809  * is included below.
   4810  */
   4811 
   4812 /* -----zlib.c copyright info below */
   4813 /*
   4814  * Copyright 2000 Sun Microsystems, Inc.
   4815  * All rights reserved.
   4816  *
   4817  * Updated from zlib-1.0.4 to zlib-1.1.3 by James Carlson.
   4818  *
   4819  * This file is derived from various .h and .c files from the zlib-1.0.4
   4820  * distribution by Jean-loup Gailly and Mark Adler, with some additions
   4821  * by Paul Mackerras to aid in implementing Deflate compression and
   4822  * decompression for PPP packets.  See zlib.h for conditions of
   4823  * distribution and use.
   4824  *
   4825  * Changes that have been made include:
   4826  * - added Z_PACKET_FLUSH (see zlib.h for details)
   4827  * - added inflateIncomp and deflateOutputPending
   4828  * - allow strm->next_out to be NULL, meaning discard the output
   4829  *
   4830  * $Id: zlib.c,v 1.11 1998/09/13 23:37:12 paulus Exp $
   4831  */
   4832 /* +++ adler32.c */
   4833 /*
   4834  * adler32.c -- compute the Adler-32 checksum of a data stream
   4835  * Copyright (C) 1995-1998 Mark Adler
   4836  * For conditions of distribution and use, see copyright notice in zlib.h
   4837  */
   4838 /* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
   4839 /* -----zlib.c copyright info above */
   4840 
   4841 /* -----zlib.h copyright info below */
   4842 /*
   4843  * Copyright 2000 Sun Microsystems, Inc.
   4844  * All rights reserved.
   4845  *
   4846  * Permission to use, copy, modify, and distribute this software and
   4847  * its documentation is hereby granted, provided that the above
   4848  * copyright notice appears in all copies.
   4849  *
   4850  * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF
   4851  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
   4852  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
   4853  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT.  SUN SHALL NOT BE LIABLE
   4854  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
   4855  * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES
   4856  *
   4857  * This file has been altered from its original by Sun Microsystems to
   4858  * fit local coding style.
   4859  */
   4860 /* -----zlib.h copyright info above */
   4861 
   4862 #define	DO1(buf, i)  {s1 += buf[i]; s2 += s1; }
   4863 #define	DO2(buf, i)  DO1(buf, i); DO1(buf, i+1);
   4864 #define	DO4(buf, i)  DO2(buf, i); DO2(buf, i+2);
   4865 #define	DO8(buf, i)  DO4(buf, i); DO4(buf, i+4);
   4866 #define	DO16(buf)   DO8(buf, 0); DO8(buf, 8);
   4867 
   4868 static uint32_t
   4869 adler16(void *p, int len)
   4870 {
   4871 	uint32_t s1 = 1;
   4872 	uint32_t s2 = 0;
   4873 	uchar_t *buf = p;
   4874 
   4875 	while (len >= 16) {
   4876 		DO16(buf);
   4877 		buf += 16;
   4878 		len -= 16;
   4879 	}
   4880 
   4881 	while (len > 0) {
   4882 		s1 += *buf++;
   4883 		s2 += s1;
   4884 		len--;
   4885 	}
   4886 
   4887 	return ((uint32_t)(s2 ^ s1) & 0xFFFFU);
   4888 }
   4889