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