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