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