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 /*
23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 /*
27  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #include <ctype.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/errno.h>
37 #include <sys/tiuser.h>
38 #include <setjmp.h>
39 
40 #include <rpc/types.h>
41 #include <rpc/xdr.h>
42 #include <rpc/auth.h>
43 #include <rpc/clnt.h>
44 #include <rpc/rpc_msg.h>
45 #include "snoop.h"
46 
47 #include <sys/stat.h>
48 #include <sys/param.h>
49 #include <sys/sysmacros.h>
50 #include <rpcsvc/nfs_prot.h>
51 /* use the same nfs4_prot.h as the xdr code */
52 #include "rpcsvc/nfs4_prot.h"
53 
54 /*
55  * XXX With NFS v2 and v3, we only need to xdr the pieces that we care
56  * about.  Anything else we can ignore and just skip to the next packet.
57  * So all the stuff that deals directly with XDR lives in snoop_display.c
58  * With v4, we need to XDR entire structures so that we can skip over
59  * uninteresting bits in a compound array, so we call XDR directly from
60  * here.  We need to rethink how we're going to structure XDR access.  Do
61  * we continue to hide it all in snoop_display.c, or do we expose it to all
62  * the protocol modules?
63  */
64 extern XDR xdrm;
65 
66 #ifndef MIN
67 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
68 #endif
69 
70 /*
71  * Maximum number of characters to display in compound4 summary line.
72  */
73 #define	SUM_COMPND_MAX	100
74 
75 /*
76  * Maximum number of recognized attributes.
77  */
78 #define	MAX_ATTRIBUTES	56
79 
80 /*
81  * This data structure provides a more convenient way to access an
82  * attribute bitmask.  map[N] = value of bit N in a bitmap4.
83  * It's defined as a struct so as to step around all the weird rules in C
84  * about arrays, pointers, passing them as arguments, etc.
85  */
86 
87 typedef struct {
88 	char map[MAX_ATTRIBUTES];
89 } unpkd_attrmap_t;
90 
91 
92 static void sumarg_cb_getattr(char *buf, size_t buflen, void *obj);
93 static void dtlarg_cb_getattr(void *obj);
94 static void sumarg_cb_recall(char *buf, size_t buflen, void *obj);
95 static void dtlarg_cb_recall(void *obj);
96 
97 
98 static void sumarg_access(char *buf, size_t buflen, void *obj);
99 static void dtlarg_access(void *obj);
100 static void sumarg_close(char *buf, size_t buflen, void *obj);
101 static void dtlarg_close(void *obj);
102 static void sumarg_commit(char *buf, size_t buflen, void *obj);
103 static void dtlarg_commit(void *obj);
104 static void sumarg_compnt(char *buf, size_t buflen, void *obj);
105 static void dtlarg_compnt(void *obj);
106 static void sumarg_create(char *buf, size_t buflen, void *obj);
107 static void dtlarg_create(void *obj);
108 static void sumarg_delprge(char *buf, size_t buflen, void *obj);
109 static void dtlarg_delprge(void *obj);
110 static void sumarg_delret(char *buf, size_t buflen, void *obj);
111 static void dtlarg_delret(void *obj);
112 static void sumarg_getattr(char *buf, size_t buflen, void *obj);
113 static void dtlarg_getattr(void *obj);
114 static void sumarg_link(char *buf, size_t buflen, void *obj);
115 static void dtlarg_link(void *obj);
116 static void sum_open_to_lock_owner(char *buf, int buflen,
117 					open_to_lock_owner4 *own);
118 static void sum_exist_lock_owner(char *buf, int buflen,
119 					exist_lock_owner4 *own);
120 static void sum_locker(char *buf, size_t buflen, locker4 *lk);
121 static void sumarg_lock(char *buf, size_t buflen, void *obj);
122 static void detail_open_to_lock_owner(open_to_lock_owner4 *own);
123 static void detail_exist_lock_owner(exist_lock_owner4 *own);
124 static void detail_locker(locker4 *lk);
125 static void dtlarg_lock(void *obj);
126 static void sumarg_lockt(char *buf, size_t buflen, void *obj);
127 static void dtlarg_lockt(void *obj);
128 static void sumarg_locku(char *buf, size_t buflen, void *obj);
129 static void dtlarg_locku(void *obj);
130 static void sumarg_lookup(char *buf, size_t buflen, void *obj);
131 static void dtlarg_lookup(void *obj);
132 static void sumarg_open(char *buf, size_t buflen, void *obj);
133 static void dtlarg_open(void *obj);
134 static void sumarg_openattr(char *buf, size_t buflen, void *obj);
135 static void dtlarg_openattr(void *obj);
136 static void sumarg_open_confirm(char *buf, size_t buflen, void *obj);
137 static void dtlarg_open_confirm(void *obj);
138 static void sumarg_open_downgrd(char *buf, size_t buflen, void *obj);
139 static void dtlarg_open_downgrd(void *obj);
140 static void sumarg_putfh(char *buf, size_t buflen, void *obj);
141 static void dtlarg_putfh(void *obj);
142 static void sumarg_read(char *buf, size_t buflen, void *obj);
143 static void dtlarg_read(void *obj);
144 static void sumarg_readdir(char *buf, size_t buflen, void *obj);
145 static void dtlarg_readdir(void *obj);
146 static void sumarg_release_lkown(char *buf, size_t buflen, void *obj);
147 static void dtlarg_release_lkown(void *obj);
148 static void sumarg_rename(char *buf, size_t buflen, void *obj);
149 static void dtlarg_rename(void *obj);
150 static void sumarg_renew(char *buf, size_t buflen, void *obj);
151 static void dtlarg_renew(void *buf);
152 static void sumarg_secinfo(char *buf, size_t buflen, void *obj);
153 static void dtlarg_secinfo(void *obj);
154 static void sumarg_setattr(char *buf, size_t buflen, void *obj);
155 static void dtlarg_setattr(void *obj);
156 static void sumarg_setclid(char *buf, size_t buflen, void *obj);
157 static void dtlarg_setclid(void *obj);
158 static void sumarg_setclid_cfm(char *buf, size_t buflen, void *obj);
159 static void dtlarg_setclid_cfm(void *obj);
160 static void dtlarg_verify(void *obj);
161 static void sumarg_write(char *buf, size_t buflen, void *obj);
162 static void dtlarg_write(void *obj);
163 
164 static void sumres_cb_getattr(char *buf, size_t buflen, void *obj);
165 static void dtlres_cb_getattr(void *obj);
166 
167 static void sumres_access(char *buf, size_t buflen, void *obj);
168 static void dtlres_access(void *obj);
169 static void sumres_close(char *buf, size_t buflen, void *obj);
170 static void dtlres_close(void *obj);
171 static void sumres_commit(char *buf, size_t buflen, void *obj);
172 static void dtlres_commit(void *obj);
173 static void dtlres_create(void *obj);
174 static void sumres_getattr(char *buf, size_t buflen, void *obj);
175 static void dtlres_getattr(void *obj);
176 static void sumres_getfh(char *buf, size_t buflen, void *obj);
177 static void dtlres_getfh(void *obj);
178 static void dtlres_link(void *obj);
179 static void sumres_lock(char *buf, size_t buflen, void *obj);
180 static void dtlres_lock(void *obj);
181 static void sumres_lockt(char *buf, size_t buflen, void *obj);
182 static void dtlres_lockt(void *obj);
183 static void sumres_locku(char *buf, size_t buflen, void *obj);
184 static void dtlres_locku(void *obj);
185 static void sumres_open(char *buf, size_t buflen, void *obj);
186 static void dtlres_open(void *obj);
187 static void sumres_open_confirm(char *buf, size_t buflen, void *obj);
188 static void dtlres_open_confirm(void *obj);
189 static void sumres_open_downgrd(char *buf, size_t buflen, void *obj);
190 static void dtlres_open_downgrd(void *obj);
191 static void sumres_read(char *buf, size_t buflen, void *obj);
192 static void dtlres_read(void *obj);
193 static void sumres_readdir(char *buf, size_t buflen, void *obj);
194 static void dtlres_readdir(void *obj);
195 static void sumres_readlnk(char *buf, size_t buflen, void *obj);
196 static void dtlres_readlnk(void *obj);
197 static void dtlres_remove(void *obj);
198 static void dtlres_rename(void *obj);
199 static void sumres_secinfo(char *buf, size_t buflen, void *obj);
200 static void dtlres_secinfo(void *obj);
201 static void sumres_setattr(char *buf, size_t buflen, void *obj);
202 static void dtlres_setattr(void *obj);
203 static void sumres_setclid(char *buf, size_t buflen, void *obj);
204 static void dtlres_setclid(void *obj);
205 static void sumres_write(char *buf, size_t buflen, void *obj);
206 static void dtlres_write(void *obj);
207 static void sum_nfsstat4(char *buf, size_t buflen, void *obj);
208 static void dtl_nfsstat4(void *obj);
209 static uint32_t adler16(void *, int);
210 static void nfs4_xdr_skip(int nbytes);
211 static char *sum_lock_type_name(enum nfs_lock_type4 type);
212 
213 int nfs4_pkt_start;
214 int nfs4_pkt_len;
215 int nfs4_skip_bytes;
216 int nfs4_fragged_rpc;
217 char *nfs4err_fragrpc = "<Fragmented RPC>";
218 char *nfs4err_xdrfrag = "<XDR Error or Fragmented RPC>";
219 
220 /*
221  * need a way to enable this if current testcases are parsing snoop
222  * error text. -- maybe an env var would do as temp workaround until
223  * testcases changed to grep for new error text.
224  */
225 int nfs4_use_old_error_text = 0;
226 
227 /*
228  * Information about each operation that can appear in a compound call.
229  * The function pointers are to formatting functions for summary arguments
230  * and results, and detail arguments & results.
231  */
232 
233 typedef struct {
234 	char	*name;
235 	void	(*sumarg)(char *, size_t, void *);
236 	void	(*sumres)(char *, size_t, void *);
237 	void	(*dtlarg)(void *);
238 	void	(*dtlres)(void *);
239 } op_info_t;
240 
241 static op_info_t cb_opcode_info[] = {
242 	{"OP_ZERO",	NULL,	NULL,	NULL,	NULL},	/* 0 */
243 	{"OP_ONE",	NULL,	NULL,	NULL,	NULL},
244 	{"OP_TWO",	NULL,	NULL,	NULL,	NULL},  /* minor vers */
245 	{"CB_GETATTR",
246 		sumarg_cb_getattr,	sumres_cb_getattr,
247 		dtlarg_cb_getattr,	dtlres_cb_getattr},
248 	{"CB_RECALL",
249 		sumarg_cb_recall,	sum_nfsstat4,
250 		dtlarg_cb_recall,	dtl_nfsstat4},
251 };
252 static uint_t cb_num_opcodes = ARRAY_SIZE(cb_opcode_info);
253 
254 static op_info_t opcode_info[] = {
255 	{"OP_ZERO",	NULL,	NULL,	NULL,	NULL},	/* 0 */
256 	{"OP_ONE",	NULL,	NULL,	NULL,	NULL},
257 	{"OP_TWO",	NULL,	NULL,	NULL,	NULL},  /* minor vers */
258 	{"ACCESS",
259 	sumarg_access,	sumres_access,	dtlarg_access,	dtlres_access},
260 	{"CLOSE",
261 	sumarg_close,	sumres_close,	dtlarg_close,	dtlres_close},
262 	{"COMMIT",
263 	sumarg_commit,	sumres_commit,	dtlarg_commit,	dtlres_commit},
264 	{"CREATE",					/* 5 */
265 	sumarg_create,	sum_nfsstat4,	dtlarg_create,	dtlres_create},
266 	{"DELEGPURGE",
267 	sumarg_delprge,	sum_nfsstat4,	dtlarg_delprge,	dtl_nfsstat4},
268 	{"DELEGRETURN",
269 	sumarg_delret,	sum_nfsstat4,	dtlarg_delret,	dtl_nfsstat4},
270 	{"GETATTR",
271 	sumarg_getattr,	sumres_getattr,	dtlarg_getattr,	dtlres_getattr},
272 	{"GETFH",
273 	NULL,		sumres_getfh,	NULL,	dtlres_getfh},
274 	{"LINK",					/* 10 */
275 	sumarg_link,	sum_nfsstat4,	dtlarg_link,	dtlres_link},
276 	{"LOCK",
277 	sumarg_lock,	sumres_lock,	dtlarg_lock,	dtlres_lock},
278 	{"LOCKT",
279 	sumarg_lockt,	sumres_lockt,	dtlarg_lockt,	dtlres_lockt},
280 	{"LOCKU",
281 	sumarg_locku,	sumres_locku,	dtlarg_locku,	dtlres_locku},
282 	{"LOOKUP",
283 	sumarg_lookup,	sum_nfsstat4,	dtlarg_lookup,	dtl_nfsstat4},
284 	{"LOOKUPP",					/* 15 */
285 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
286 	{"NVERIFY",
287 	NULL,		sum_nfsstat4,	dtlarg_verify,	dtl_nfsstat4},
288 	{"OPEN",
289 	sumarg_open,	sumres_open,	dtlarg_open,	dtlres_open},
290 	{"OPENATTR",
291 	sumarg_openattr, sum_nfsstat4, dtlarg_openattr, dtl_nfsstat4},
292 	{"OPEN_CONFIRM",
293 	sumarg_open_confirm,
294 	sumres_open_confirm,
295 	dtlarg_open_confirm,
296 	dtlres_open_confirm},
297 	{"OPEN_DOWNGRADE",
298 	sumarg_open_downgrd,
299 	sumres_open_downgrd,
300 	dtlarg_open_downgrd,
301 	dtlres_open_downgrd},
302 	{"PUTFH",
303 	sumarg_putfh,	sum_nfsstat4,	dtlarg_putfh,	dtl_nfsstat4},
304 	{"PUTPUBFH",					/* 20 */
305 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
306 	{"PUTROOTFH",
307 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
308 	{"READ",
309 	sumarg_read,	sumres_read,	dtlarg_read,	dtlres_read},
310 	{"READDIR",
311 	sumarg_readdir,	sumres_readdir,	dtlarg_readdir,	dtlres_readdir},
312 	{"READLINK",
313 	NULL,		sumres_readlnk,	NULL,		dtlres_readlnk},
314 	{"REMOVE",					/* 25 */
315 	sumarg_compnt,	sum_nfsstat4,	dtlarg_compnt,	dtlres_remove},
316 	{"RENAME",
317 	sumarg_rename,	sum_nfsstat4,	dtlarg_rename,	dtlres_rename},
318 	{"RENEW",
319 	sumarg_renew,	sum_nfsstat4,	dtlarg_renew,	dtl_nfsstat4},
320 	{"RESTOREFH",
321 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
322 	{"SAVEFH",
323 	NULL,		sum_nfsstat4,	NULL,		dtl_nfsstat4},
324 	{"SECINFO",					/* 30 */
325 	sumarg_secinfo,	sumres_secinfo,	dtlarg_secinfo,	dtlres_secinfo},
326 	{"SETATTR",
327 	sumarg_setattr,	sumres_setattr,	dtlarg_setattr,	dtlres_setattr},
328 	{"SETCLIENTID",
329 	sumarg_setclid,	sumres_setclid,	dtlarg_setclid,	dtlres_setclid},
330 	{"SETCLIENTID_CONFIRM",
331 	sumarg_setclid_cfm,
332 	sum_nfsstat4,
333 	dtlarg_setclid_cfm,
334 	dtl_nfsstat4},
335 	{"VERIFY",
336 	NULL,		sum_nfsstat4,	dtlarg_verify,	dtl_nfsstat4},
337 	{"WRITE",
338 	sumarg_write,	sumres_write,	dtlarg_write,	dtlres_write},
339 	{"RELEASE_LOCKOWNER",
340 	sumarg_release_lkown, sum_nfsstat4,
341 	dtlarg_release_lkown, dtl_nfsstat4},
342 };
343 static uint_t num_opcodes = ARRAY_SIZE(opcode_info);
344 
345 /*
346  * File types.
347  */
348 
349 typedef struct {
350 	char *short_name;		/* for summary output */
351 	char *long_name;		/* for detail output */
352 } ftype_names_t;
353 
354 static ftype_names_t ftype_names[] = {
355 	{"Type 0",	"Type 0"},
356 	{"REG",		"Regular File"},
357 	{"DIR",		"Directory"},
358 	{"BLK",		"Block Device"},
359 	{"CHR",		"Character Device"},
360 	{"LNK",		"Symbolic Link"},	/* 5 */
361 	{"SOCK",	"Socket"},
362 	{"FIFO",	"FIFO"},
363 	{"ATTRDIR",	"Attribute Directory"},
364 	{"NAMEDATTR",	"Named Attribute"},
365 };
366 static uint_t num_ftypes = sizeof (ftype_names) / sizeof (ftype_names_t);
367 
368 static ftype_names_t	open_rflags[] = {
369 	{"?",	"UNKNOWN"},	/* 0 */
370 	{"CF",	"CONFIRM"},	/* 1 */
371 	{"PL",	"POSIX LOCK"},	/* 2 */
372 	{"?",	"UNKNOWN"},
373 };
374 static uint_t num_open_rflags =
375 	sizeof (open_rflags) / sizeof (ftype_names_t) - 1;
376 
377 static char *get_flags(uint_t, ftype_names_t *, uint_t, int, char *);
378 
379 #define	sum_open_rflags(flag) \
380 	get_flags((flag), open_rflags, num_open_rflags, 1, " RF=")
381 
382 #define	detail_open_rflags(flag) \
383 	get_flags((flag), open_rflags, num_open_rflags, 0, NULL)
384 
385 static void prt_supported_attrs(XDR *);
386 static void prt_type(XDR *);
387 static void prt_fh_expire_type(XDR *);
388 static void prt_change(XDR *);
389 static void prt_size(XDR *);
390 static void prt_link_support(XDR *);
391 static void prt_symlink_support(XDR *);
392 static void prt_named_attr(XDR *);
393 static void prt_fsid(XDR *);
394 static void prt_unique_handles(XDR *);
395 static void prt_lease_time(XDR *);
396 static void prt_rdattr_error(XDR *);
397 static void prt_acl(XDR *);
398 static void prt_aclsupport(XDR *);
399 static void prt_archive(XDR *);
400 static void prt_cansettime(XDR *);
401 static void prt_case_insensitive(XDR *);
402 static void prt_case_preserving(XDR *);
403 static void prt_chown_restricted(XDR *);
404 static void prt_filehandle(XDR *);
405 static void prt_fileid(XDR *);
406 static void prt_mounted_on_fileid(XDR *);
407 static void prt_files_avail(XDR *);
408 static void prt_files_free(XDR *);
409 static void prt_files_total(XDR *);
410 static void prt_fs_locations(XDR *);
411 static void prt_hidden(XDR *);
412 static void prt_homogeneous(XDR *);
413 static void prt_maxfilesize(XDR *);
414 static void prt_maxlink(XDR *);
415 static void prt_maxname(XDR *);
416 static void prt_maxread(XDR *);
417 static void prt_maxwrite(XDR *);
418 static void prt_mimetype(XDR *);
419 static void prt_mode(XDR *);
420 static void prt_no_trunc(XDR *);
421 static void prt_numlinks(XDR *);
422 static void prt_owner(XDR *);
423 static void prt_owner_group(XDR *);
424 static void prt_quota_avail_hard(XDR *);
425 static void prt_quota_avail_soft(XDR *);
426 static void prt_quota_used(XDR *);
427 static void prt_rawdev(XDR *);
428 static void prt_space_avail(XDR *);
429 static void prt_space_free(XDR *);
430 static void prt_space_total(XDR *);
431 static void prt_space_used(XDR *);
432 static void prt_system(XDR *);
433 static void prt_time_access(XDR *);
434 static void prt_time_access_set(XDR *);
435 static void prt_time_backup(XDR *);
436 static void prt_time_create(XDR *);
437 static void prt_time_delta(XDR *);
438 static void prt_time_metadata(XDR *);
439 static void prt_time_modify(XDR *);
440 static void prt_time_modify_set(XDR *);
441 
442 
443 
444 /*
445  * Information for attributes.
446  * name		name of the attribute.
447  * prt_details	function to XDR decode the attribute and print it.
448  *
449  * XXX If this table ever gets extensively changed (including
450  * reorganization to track changes to the spec), it would probably be a
451  * good idea to change to a scheme where the table is mechanically
452  * generated.  Look at $SRC/uts/common/rpcsvc for how this is done in the
453  * kernel.
454  */
455 
456 typedef struct {
457 	char	*name;
458 	void	(*prt_details)(XDR *);
459 } attr_info_t;
460 
461 static attr_info_t attr_info[MAX_ATTRIBUTES] = {
462 	{"SUPPORTED_ATTRS",	prt_supported_attrs},
463 	{"TYPE",		prt_type},
464 	{"FH_EXPIRE_TYPE",	prt_fh_expire_type},
465 	{"CHANGE",		prt_change},
466 	{"SIZE",		prt_size},
467 	{"LINK_SUPPORT",	prt_link_support},	/* 5 */
468 	{"SYMLINK_SUPPORT",	prt_symlink_support},
469 	{"NAMED_ATTR",		prt_named_attr},
470 	{"FSID",		prt_fsid},
471 	{"UNIQUE_HANDLES",	prt_unique_handles},
472 	{"LEASE_TIME",		prt_lease_time},	/* 10 */
473 	{"RDATTR_ERROR",	prt_rdattr_error},
474 	{"ACL",			prt_acl},
475 	{"ACLSUPPORT",		prt_aclsupport},
476 	{"ARCHIVE",		prt_archive},
477 	{"CANSETTIME",		prt_cansettime},	/* 15 */
478 	{"CASE_INSENSITIVE",	prt_case_insensitive},
479 	{"CASE_PRESERVING",	prt_case_preserving},
480 	{"CHOWN_RESTRICTED",	prt_chown_restricted},
481 	{"FILEHANDLE",		prt_filehandle},
482 	{"FILEID",		prt_fileid},		/* 20 */
483 	{"FILES_AVAIL",		prt_files_avail},
484 	{"FILES_FREE",		prt_files_free},
485 	{"FILES_TOTAL",		prt_files_total},
486 	{"FS_LOCATIONS",	prt_fs_locations},
487 	{"HIDDEN",		prt_hidden},		/* 25 */
488 	{"HOMOGENEOUS",		prt_homogeneous},
489 	{"MAXFILESIZE",		prt_maxfilesize},
490 	{"MAXLINK",		prt_maxlink},
491 	{"MAXNAME",		prt_maxname},
492 	{"MAXREAD",		prt_maxread},		/* 30 */
493 	{"MAXWRITE",		prt_maxwrite},
494 	{"MIMETYPE",		prt_mimetype},
495 	{"MODE",		prt_mode},
496 	{"NO_TRUNC",		prt_no_trunc},
497 	{"NUMLINKS",		prt_numlinks},		/* 35 */
498 	{"OWNER",		prt_owner},
499 	{"OWNER_GROUP",		prt_owner_group},
500 	{"QUOTA_AVAIL_HARD",	prt_quota_avail_hard},
501 	{"QUOTA_AVAIL_SOFT",	prt_quota_avail_soft},
502 	{"QUOTA_USED",		prt_quota_used},	/* 40 */
503 	{"RAWDEV",		prt_rawdev},
504 	{"SPACE_AVAIL",		prt_space_avail},
505 	{"SPACE_FREE",		prt_space_free},
506 	{"SPACE_TOTAL",		prt_space_total},
507 	{"SPACE_USED",		prt_space_used},	/* 45 */
508 	{"SYSTEM",		prt_system},
509 	{"TIME_ACCESS",		prt_time_access},
510 	{"TIME_ACCESS_SET",	prt_time_access_set},
511 	{"TIME_BACKUP",		prt_time_backup},
512 	{"TIME_CREATE",		prt_time_create},	/* 50 */
513 	{"TIME_DELTA",		prt_time_delta},
514 	{"TIME_METADATA",	prt_time_metadata},
515 	{"TIME_MODIFY",		prt_time_modify},
516 	{"TIME_MODIFY_SET",	prt_time_modify_set},
517 	{"MOUNTED_ON_FILEID",	prt_mounted_on_fileid},
518 };
519 
520 extern char *get_sum_line();
521 
522 extern jmp_buf xdr_err;
523 
524 static void sum_comp4res(char *, char *(*)(void));
525 static char *sum_compound4args(void);
526 static char *sum_compound4res(void);
527 static char *sum_operand(nfs_argop4 *opp);
528 static char *sum_result(nfs_resop4 *resp);
529 
530 static char *sum_cb_compound4args(void);
531 static char *sum_cb_compound4res(void);
532 static char *sum_cb_operand(nfs_cb_argop4 *opp);
533 static char *sum_cb_result(nfs_cb_resop4 *resp);
534 
535 static void detail_acetype4(acetype4);
536 static void detail_uint32_bitmap(uint32_t, char *[], int);
537 static void detail_aceflag4(aceflag4);
538 static void detail_acemask4(acemask4);
539 static void detail_nfs_argop4(void);
540 static void detail_nfs_resop4(void);
541 static void detail_cb_argop4(void);
542 static void detail_cb_resop4(void);
543 
544 static char *attr_name(uint_t);
545 static char *claim_name(enum open_claim_type4 claim_type);
546 static char *delegation_type_name(enum open_delegation_type4 type);
547 static char *flavor_name(uint_t flavor);
548 static char *gss_svc_name(rpc_gss_svc_t svc);
549 static char *limitby_name(enum limit_by4 limitby);
550 static char *lock_type_name(enum nfs_lock_type4);
551 static char *opcode_name(uint_t);
552 static char *cb_opcode_name(uint_t opnum);
553 static char *status_name(int);
554 static char *status_name_compat(int);
555 static char *status_name_pcol(int);
556 static char *sum_type_name(nfs_ftype4);
557 static void sum_access4(char *buf, size_t buflen, uint32_t bits);
558 static void detail_access4(char *, uint32_t);
559 static void sum_claim(char *buf, size_t buflen, open_claim4 *claim);
560 static void detail_claim(open_claim4 *claim);
561 static char *sum_clientid(clientid4 client);
562 static void detail_clientid(clientid4 client);
563 static char *_sum_stateid(stateid4 *, char *prefix);
564 static void sum_delegation(char *buf, size_t buflen, open_delegation4 *delp);
565 static void detail_delegation(open_delegation4 *delp);
566 static void detail_lock_owner(lock_owner4 *owner);
567 static void detail_open_owner(open_owner4 *owner);
568 static void sum_openflag(char *bufp, int buflen, openflag4 *flagp);
569 static char *get_deleg_typestr(open_delegation_type4 dt);
570 static void detail_openflag(openflag4 *flagp);
571 static void sum_name(char *buf, size_t buflen, open_claim4 *claim);
572 static void detail_rpcsec_gss(rpcsec_gss_info *);
573 static void detail_secinfo4(secinfo4 *infop);
574 static char *sum_space_limit(nfs_space_limit4 *limitp);
575 static void detail_space_limit(nfs_space_limit4 *limitp);
576 static char *detail_type_name(nfs_ftype4);
577 static char *createhow4_name(createhow4 *crtp);
578 
579 
580 static void showxdr_utf8string(char *);
581 static char *utf8localize(utf8string *);
582 static void utf8free(void);
583 static void sum_pathname4(char *, size_t, pathname4 *);
584 static void detail_pathname4(pathname4 *pathp, char *);
585 static void sum_compname4(char *buf, size_t buflen, component4 *comp);
586 static void detail_compname4(component4 *comp);
587 
588 static void detail_fattr4(fattr4 *attrp);
589 static void detail_attr_bitmap(char *, bitmap4 *, unpkd_attrmap_t *);
590 static void sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp);
591 static void detail_fattr4_change(char *msg, fattr4_change chg);
592 static char *sum_fh4(nfs_fh4 *fhp);
593 static void detail_fh4(nfs_fh4 *fh);
594 
595 #define	fh4_hash(fh) adler16((fh)->nfs_fh4_val, (fh)->nfs_fh4_len)
596 #define	stateid_hash(st) adler16((st)->other, sizeof ((st)->other))
597 #define	owner_hash(own) adler16((own)->owner_val, (own)->owner_len)
598 
599 #define	sum_deleg_stateid(st)	_sum_stateid((st), "DST=")
600 #define	sum_open_stateid(st)	_sum_stateid((st), "OST=")
601 #define	sum_lock_stateid(st)	_sum_stateid((st), "LST=")
602 #define	sum_stateid(st)		_sum_stateid((st), "ST=")
603 
604 #define	detail_deleg_stateid(st)	_detail_stateid((st), "Delegation ")
605 #define	detail_open_stateid(st)		_detail_stateid((st), "Open ")
606 #define	detail_lock_stateid(st)		_detail_stateid((st), "Lock ")
607 #define	detail_stateid(st)		_detail_stateid((st), "")
608 
609 #define	SPECIAL_STATEID0	"SPC0"
610 #define	SPECIAL_STATEID1	"SPC1"
611 
612 #define	DONT_CHANGE		0
613 #define	SET_TO_SERVER_TIME	1
614 #define	SET_TO_CLIENT_TIME	2
615 
616 static stateid4 spec_stateid_0 =
617 	{0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
618 static stateid4 spec_stateid_1 =
619 	{0xFFFFFFFF, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
620 
621 static char *procnames_short[] = {
622 	"NULL4",	/*  0 */
623 	"COMPOUND4"	/*  1 */
624 };
625 
626 static char *procnames_long[] = {
627 	"Null procedure",		/*  0 */
628 	"Compound",			/*  1 */
629 };
630 
631 static char *cb_procnames_short[] = {
632 	"CB_NULL",	/*  0 */
633 	"CB_COMPOUND"	/*  1 */
634 };
635 
636 static char *cb_procnames_long[] = {
637 	"Null CallBack procedure",	/*  0 */
638 	"CallBack compound",		/*  1 */
639 };
640 
641 static char *acetype4_names[] = {
642 	"ACE4_ACCESS_ALLOWED_ACE_TYPE",
643 	"ACE4_ACCESS_DENIED_ACE_TYPE",
644 	"ACE4_SYSTEM_AUDIT_ACE_TYPE",
645 	"ACE4_SYSTEM_ALARM_ACE_TYPE"
646 };
647 #define	ACETYPE4_NAMES_MAX (sizeof (acetype4_names) / sizeof (char *))
648 
649 static char *aceflag4_names[] = {
650 	"ACE4_FILE_INHERIT_ACE",
651 	"ACE4_DIRECTORY_INHERIT_ACE",
652 	"ACE4_NO_PROPAGATE_INHERIT_ACE",
653 	"ACE4_INHERIT_ONLY_ACE",
654 	"ACE4_SUCCESSFUL_ACCESS_ACE_FLAG",
655 	"ACE4_FAILED_ACCESS_ACE_FLAG",
656 	"ACE4_IDENTIFIER_GROUP"
657 };
658 #define	ACEFLAG4_NAMES_MAX (sizeof (aceflag4_names) / sizeof (char *))
659 
660 static char *acemask4_names[] = {
661 	"ACE4_READ_DATA/ACE4_LIST_DIRECTORY",
662 	"ACE4_WRITE_DATA/ACE4_ADD_FILE",
663 	"ACE4_APPEND_DATA/ACE4_ADD_SUBDIRECTORY",
664 	"ACE4_READ_NAMED_ATTRS",
665 	"ACE4_WRITE_NAMED_ATTRS",
666 	"ACE4_EXECUTE",
667 	"ACE4_DELETE_CHILD",
668 	"ACE4_READ_ATTRIBUTES",
669 	"ACE4_WRITE_ATTRIBUTES",
670 	"UNDEFINED",	/* 0x00000200 */
671 	"UNDEFINED",	/* 0x00000400 */
672 	"UNDEFINED",	/* 0x00000800 */
673 	"UNDEFINED",	/* 0x00001000 */
674 	"UNDEFINED",	/* 0x00002000 */
675 	"UNDEFINED",	/* 0x00004000 */
676 	"UNDEFINED",	/* 0x00008000 */
677 	"ACE4_DELETE",
678 	"ACE4_READ_ACL",
679 	"ACE4_WRITE_ACL",
680 	"ACE4_WRITE_OWNER",
681 	"ACE4_SYNCHRONIZE"
682 };
683 #define	ACEMASK4_NAMES_MAX (sizeof (acemask4_names) / sizeof (char *))
684 
685 #define	MAXPROC	1
686 
687 /*ARGSUSED*/
688 void
interpret_nfs4_cb(int flags,int type,int xid,int vers,int proc,char * data,int len)689 interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc,
690     char *data, int len)
691 {
692 	char *line = NULL;
693 
694 	if (proc < 0 || proc > MAXPROC)
695 		return;
696 
697 	if (flags & F_SUM) {
698 		line = get_sum_line();
699 
700 		if (type == CALL) {
701 			(void) sprintf(line, "NFS C %s",
702 			    proc == CB_COMPOUND ? "CB4" :
703 			    cb_procnames_short[proc]);
704 			line += strlen(line);
705 
706 			if (proc == CB_COMPOUND) {
707 				static utf8string tag;
708 
709 				if (!xdr_utf8string(&xdrm, &tag))
710 					longjmp(xdr_err, 1);
711 				sprintf(line, " (%.20s) %s",
712 				    utf8localize(&tag),
713 				    sum_cb_compound4args());
714 				xdr_free(xdr_utf8string, (char *)&tag);
715 			}
716 			check_retransmit(line, xid);
717 		} else {
718 			(void) sprintf(line, "NFS R %s ",
719 			    proc == CB_COMPOUND ? "CB4" :
720 			    cb_procnames_short[proc]);
721 			line += strlen(line);
722 			if (proc == CB_COMPOUND)
723 				sum_comp4res(line, sum_cb_compound4res);
724 		}
725 	}
726 
727 	if (flags & F_DTAIL) {
728 		show_header("NFS:  ", "Sun NFS4 CallBack", len);
729 		show_space();
730 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
731 		    proc, cb_procnames_long[proc]);
732 		if (proc == CB_COMPOUND) {
733 			if (type == CALL) {
734 				showxdr_utf8string("Tag = %s");
735 				detail_cb_argop4();
736 			} else {
737 				nfsstat4 status;
738 
739 				status = getxdr_long();
740 				showxdr_utf8string("Tag = %s");
741 				sprintf(get_line(0, 0), "Status = %d (%s)",
742 				    status, status_name(status));
743 				detail_cb_resop4();
744 			}
745 		}
746 		show_trailer();
747 	}
748 
749 	utf8free();			/* cf. utf8localize() */
750 }
751 
752 
753 /*ARGSUSED*/
754 void
interpret_nfs4(int flags,int type,int xid,int vers,int proc,char * data,int len)755 interpret_nfs4(int flags, int type, int xid, int vers, int proc,
756     char *data, int len)
757 {
758 	char *line = NULL;
759 
760 	if (proc < 0 || proc > MAXPROC)
761 		return;
762 
763 	nfs4_fragged_rpc = 0;
764 	nfs4_pkt_len = len;
765 	nfs4_pkt_start = xdr_getpos(&xdrm);
766 
767 	if (flags & F_SUM) {
768 		line = get_sum_line();
769 
770 		if (type == CALL) {
771 			(void) sprintf(line, "NFS C %s",
772 			    proc == NFSPROC4_COMPOUND ? "4" :
773 			    procnames_short[proc]);
774 			line += strlen(line);
775 
776 			if (proc == NFSPROC4_COMPOUND) {
777 				static utf8string tag;
778 
779 				if (!xdr_utf8string(&xdrm, &tag))
780 					longjmp(xdr_err, 1);
781 				sprintf(line, " (%.20s) %s",
782 				    utf8localize(&tag),
783 				    sum_compound4args());
784 				xdr_free(xdr_utf8string, (char *)&tag);
785 			}
786 			check_retransmit(line, xid);
787 		} else {
788 			(void) sprintf(line, "NFS R %s ",
789 			    proc == NFSPROC4_COMPOUND ? "4" :
790 			    procnames_short[proc]);
791 			line += strlen(line);
792 
793 			if (proc == NFSPROC4_COMPOUND)
794 				sum_comp4res(line, sum_compound4res);
795 		}
796 	}
797 
798 	if (flags & F_DTAIL) {
799 		show_header("NFS:  ", "Sun NFS", len);
800 		show_space();
801 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
802 		    proc, procnames_long[proc]);
803 		if (proc == NFSPROC4_COMPOUND) {
804 			if (type == CALL) {
805 				showxdr_utf8string("Tag = %s");
806 				detail_nfs_argop4();
807 			} else {
808 				nfsstat4 status;
809 
810 				status = getxdr_long();
811 				showxdr_utf8string("Tag = %s");
812 				sprintf(get_line(0, 0), "Status = %d (%s)",
813 				    status, status_name(status));
814 				detail_nfs_resop4();
815 			}
816 		}
817 		show_trailer();
818 	}
819 
820 	utf8free();			/* cf. utf8localize() */
821 }
822 
823 
824 
825 /*
826  * Return the names and arguments of the oplist elements, up to
827  * SUM_COMPND_MAX characters.  If the elements don't fit, include a "..."
828  * at the end of the string.
829  */
830 
831 static char *
sum_compound4args(void)832 sum_compound4args(void)
833 {
834 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
835 	int numops;
836 	const size_t buflen = sizeof (buf);
837 	char *bp;
838 	nfs_argop4 one_op;
839 	uint32_t minor_version;
840 
841 	buf[0] = '\0';
842 
843 	if (setjmp(xdr_err)) {
844 		bp = buf + strlen(buf);
845 		snprintf(bp, buflen - (bp - buf),
846 		    nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
847 		return (buf);
848 	}
849 
850 	/*
851 	 * might be nice to print minor version, but doesn't
852 	 * seem like very useful info for summary mode
853 	 */
854 	if (!xdr_uint32_t(&xdrm, &minor_version))
855 		longjmp(xdr_err, 1);
856 
857 	numops = getxdr_long();
858 	bp = buf;
859 	while (numops-- > 0) {
860 		char *operand;
861 
862 		bzero(&one_op, sizeof (one_op));
863 
864 		if (!xdr_nfs_argop4(&xdrm, &one_op)) {
865 			xdr_free(xdr_nfs_argop4, (char *)&one_op);
866 			longjmp(xdr_err, 1);
867 		}
868 		snprintf(bp, buflen - (bp - buf), "%s ",
869 		    opcode_name(one_op.argop));
870 		bp += strlen(bp);
871 
872 		operand = sum_operand(&one_op);
873 		if (strlen(operand) > 0) {
874 			snprintf(bp, buflen - (bp - buf), "%s ", operand);
875 			bp += strlen(bp);
876 		}
877 
878 		/* nfs4_skip_bytes set by xdr_nfs4_argop4 */
879 		if (nfs4_skip_bytes != 0)
880 			nfs4_xdr_skip(nfs4_skip_bytes);
881 
882 		xdr_free(xdr_nfs_argop4, (char *)&one_op);
883 
884 		/* add "..." if past the "end" of the buffer */
885 		if (bp - buf > SUM_COMPND_MAX) {
886 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
887 			    "...");
888 			break;
889 		}
890 	}
891 
892 	return (buf);
893 }
894 
895 static void
nfs4_xdr_skip(int nbytes)896 nfs4_xdr_skip(int nbytes)
897 {
898 	int resid, off, len, cur_pos, new_pos;
899 
900 	len = RNDUP(nbytes);
901 	cur_pos = xdr_getpos(&xdrm);
902 
903 	/*
904 	 * Time to skip over the rd/wr data.  If the
905 	 * rd/wr data is completely contained in the first
906 	 * frag, we must skip over it to process the rest of
907 	 * the packet.
908 	 *
909 	 * nfs4_pkt_start: XDR position of start of NFS4 compound
910 	 * nfs4_pkt_len: number of bytes in pkt relative to
911 	 *		 nfs4_pkt_start
912 	 *
913 	 * cur_pos: current XDR position
914 	 * off: current XDR position relative to nfs4_pkt_start
915 	 * resid: number of unprocessed bytes in current pkt
916 	 *	  (relative to cur_pos/off)
917 	 *
918 	 * If nbytes <= resid, then we must skip over the rd/wr
919 	 * bytes so we can read the next op/compound in this
920 	 * packet.  Otherwise, set the fragged flag so we can
921 	 * display the fragged_rpc message.
922 	 */
923 	off = cur_pos - nfs4_pkt_start;
924 	resid = nfs4_pkt_len - off;
925 
926 	/*
927 	 * set nfs4_fragged_rpc if the requested number of "skip"
928 	 * bytes is larger than the bytes remaining in the XDR
929 	 * stream/current packet.  The global is reset to 0 at
930 	 * start of interpret_nfs4.
931 	 */
932 	new_pos = cur_pos + ((nfs4_fragged_rpc = len > resid) ? resid : len);
933 
934 	/* there's nothing to do for error case (if it fails pkt is doomed) */
935 	xdr_setpos(&xdrm, new_pos);
936 }
937 
938 
939 /*
940  * Return the names and arguments of the oplist elements, up to
941  * SUM_COMPND_MAX characters.  If the elements don't fit, include a "..."
942  * at the end of the string.
943  */
944 static char *
sum_cb_compound4args(void)945 sum_cb_compound4args(void)
946 {
947 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
948 	int numops;
949 	const size_t buflen = sizeof (buf);
950 	char *bp;
951 	nfs_cb_argop4 one_op;
952 	uint32_t minor_version, callback_ident;
953 
954 	buf[0] = '\0';
955 	if (setjmp(xdr_err)) {
956 		bp = buf + strlen(buf);
957 		snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
958 		    " RPC>");
959 		return (buf);
960 	}
961 
962 	/*
963 	 * might be nice to print minor version, but doesn't
964 	 * seem like very useful info for summary mode
965 	 */
966 	if (!xdr_uint32_t(&xdrm, &minor_version))
967 		longjmp(xdr_err, 1);
968 
969 	/* print callback_ident */
970 	if (!xdr_uint32_t(&xdrm, &callback_ident))
971 		longjmp(xdr_err, 1);
972 	snprintf(buf, buflen, "CBID=%u ", callback_ident);
973 
974 	bp = buf + strlen(buf);
975 	numops = getxdr_long();
976 
977 	while (numops-- > 0) {
978 		char *operand;
979 
980 		bzero(&one_op, sizeof (one_op));
981 		if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) {
982 			xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
983 			longjmp(xdr_err, 1);
984 		}
985 
986 		snprintf(bp, buflen - (bp - buf), "%s ",
987 		    cb_opcode_name(one_op.argop));
988 		bp += strlen(bp);
989 		operand = sum_cb_operand(&one_op);
990 		if (strlen(operand) > 0) {
991 			snprintf(bp, buflen - (bp - buf), "%s ", operand);
992 			bp += strlen(bp);
993 		}
994 
995 		xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
996 
997 		/* add "..." if past the "end" of the buffer */
998 		if (bp - buf > SUM_COMPND_MAX) {
999 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
1000 			    "...");
1001 			break;
1002 		}
1003 	}
1004 
1005 	return (buf);
1006 }
1007 
1008 /*
1009  * Return the summarized argument list for the given nfs_argop4.
1010  */
1011 
1012 static char *
sum_operand(nfs_argop4 * opp)1013 sum_operand(nfs_argop4 *opp)
1014 {
1015 	static char buf[1024];
1016 	void (*fmtproc)(char *, size_t, void *);
1017 
1018 	buf[0] = '\0';
1019 	if (opp->argop < num_opcodes) {
1020 		fmtproc = opcode_info[opp->argop].sumarg;
1021 		if (fmtproc != NULL)
1022 			fmtproc(buf, sizeof (buf), &opp->nfs_argop4_u);
1023 	}
1024 
1025 	return (buf);
1026 }
1027 
1028 /*
1029  * Return the summarized argument list for the given nfs_argop4.
1030  */
1031 
1032 static char *
sum_cb_operand(nfs_cb_argop4 * opp)1033 sum_cb_operand(nfs_cb_argop4 *opp)
1034 {
1035 	static char buf[1024];
1036 	void (*fmtproc)(char *, size_t, void *);
1037 
1038 	buf[0] = '\0';
1039 	if (opp->argop < cb_num_opcodes) {
1040 		fmtproc = cb_opcode_info[opp->argop].sumarg;
1041 		if (fmtproc != NULL)
1042 			fmtproc(buf, sizeof (buf), &opp->nfs_cb_argop4_u);
1043 	}
1044 
1045 	return (buf);
1046 }
1047 
1048 /*
1049  * Print details about the nfs_argop4 that is next in the XDR stream.
1050  */
1051 
1052 static void
detail_nfs_argop4(void)1053 detail_nfs_argop4(void)
1054 {
1055 	int numops;
1056 	nfs_argop4 one_op;
1057 	void (*fmtproc)(void *);
1058 	uint32_t minor_version;
1059 
1060 	if (!xdr_uint32_t(&xdrm, &minor_version))
1061 		longjmp(xdr_err, 1);
1062 
1063 	(void) sprintf(get_line(0, 0), "Minor version = %u",
1064 	    minor_version);
1065 
1066 	numops = getxdr_long();
1067 	(void) sprintf(get_line(0, 0), "Number of operations = %d",
1068 	    numops);
1069 
1070 	while (numops-- > 0) {
1071 		bzero(&one_op, sizeof (one_op));
1072 
1073 		if (!xdr_nfs_argop4(&xdrm, &one_op)) {
1074 			xdr_free(xdr_nfs_argop4, (char *)&one_op);
1075 			longjmp(xdr_err, 1);
1076 		}
1077 
1078 		get_line(0, 0);		/* blank line to separate ops */
1079 		sprintf(get_line(0, 0), "Op = %d (%s)",
1080 		    one_op.argop, opcode_name(one_op.argop));
1081 		if (one_op.argop < num_opcodes) {
1082 			fmtproc = opcode_info[one_op.argop].dtlarg;
1083 			if (fmtproc != NULL)
1084 				fmtproc(&one_op.nfs_argop4_u);
1085 		}
1086 
1087 		/* nfs4_skip_bytes set by xdr_nfs_argop4() */
1088 		if (nfs4_skip_bytes)
1089 			nfs4_xdr_skip(nfs4_skip_bytes);
1090 
1091 		xdr_free(xdr_nfs_argop4, (char *)&one_op);
1092 	}
1093 }
1094 
1095 
1096 /*
1097  * Print details about the nfs_argop4 that is next in the XDR stream.
1098  */
1099 static void
detail_cb_argop4(void)1100 detail_cb_argop4(void)
1101 {
1102 	int numops;
1103 	nfs_cb_argop4 one_op;
1104 	void (*fmtproc)(void *);
1105 	uint32_t minor_version, callback_ident;
1106 
1107 	if (!xdr_uint32_t(&xdrm, &minor_version))
1108 		longjmp(xdr_err, 1);
1109 	(void) sprintf(get_line(0, 0), "Minor version = %u",
1110 	    minor_version);
1111 
1112 	if (!xdr_uint32_t(&xdrm, &callback_ident))
1113 		longjmp(xdr_err, 1);
1114 	(void) sprintf(get_line(0, 0), "Callback Ident = %u",
1115 	    callback_ident);
1116 
1117 	numops = getxdr_long();
1118 	(void) sprintf(get_line(0, 0), "Number of operations = %d",
1119 	    numops);
1120 
1121 	while (numops-- > 0) {
1122 		bzero(&one_op, sizeof (one_op));
1123 		if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) {
1124 			xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
1125 			longjmp(xdr_err, 1);
1126 		}
1127 
1128 		get_line(0, 0);		/* blank line to separate ops */
1129 		sprintf(get_line(0, 0), "Op = %d (%s)",
1130 		    one_op.argop, cb_opcode_name(one_op.argop));
1131 		if (one_op.argop < cb_num_opcodes) {
1132 			fmtproc = cb_opcode_info[one_op.argop].dtlarg;
1133 			if (fmtproc != NULL)
1134 				fmtproc(&one_op.nfs_cb_argop4_u);
1135 		}
1136 
1137 		xdr_free(xdr_nfs_cb_argop4, (char *)&one_op);
1138 	}
1139 }
1140 
1141 /*
1142  * component_name: return a printable string for the given component4.  I'm
1143  * leaving this as a separate function (as opposed to having the callers
1144  * call utf8localize() directly) in case the definition of component4
1145  * changes.
1146  */
1147 
1148 static char *
component_name(component4 * cp)1149 component_name(component4 *cp)
1150 {
1151 	return (utf8localize(cp));
1152 }
1153 
1154 /*
1155  * linktext_name.  cf. component_name().
1156  */
1157 
1158 static char *
linktext_name(linktext4 * lp)1159 linktext_name(linktext4 *lp)
1160 {
1161 	return (utf8localize((utf8string *)lp));
1162 }
1163 
1164 /*
1165  * stable_how4_name: return a string for "how".
1166  */
1167 
1168 static char *
stable_how4_name(stable_how4 how)1169 stable_how4_name(stable_how4 how)
1170 {
1171 	char *result;
1172 
1173 	switch (how) {
1174 	case UNSTABLE4:
1175 		result = "ASYNC";
1176 		break;
1177 	case DATA_SYNC4:
1178 		result = "DSYNC";
1179 		break;
1180 	case FILE_SYNC4:
1181 		result = "FSYNC";
1182 		break;
1183 	default:
1184 		result = "?";
1185 		break;
1186 	}
1187 
1188 	return (result);
1189 }
1190 
1191 /*
1192  * sum_open_share_access: return a string corresponding to the
1193  * given OPEN share access bitmask.
1194  */
1195 
1196 static char *
sum_open_share_access(int32_t mask)1197 sum_open_share_access(int32_t mask)
1198 {
1199 	char *result;
1200 
1201 	switch (mask) {
1202 	case 0:
1203 		result = "N";
1204 		break;
1205 	case OPEN4_SHARE_ACCESS_READ:
1206 		result = "R";
1207 		break;
1208 	case OPEN4_SHARE_ACCESS_WRITE:
1209 		result = "W";
1210 		break;
1211 	case OPEN4_SHARE_ACCESS_BOTH:
1212 		result = "RW";
1213 		break;
1214 	default:
1215 		result = "?";
1216 		break;
1217 	}
1218 
1219 	return (result);
1220 }
1221 
1222 /*
1223  * sum_open_share_deny: return a string corresponding to the
1224  * given OPEN share deny bitmask.
1225  */
1226 
1227 static char *
sum_open_share_deny(int32_t mask)1228 sum_open_share_deny(int32_t mask)
1229 {
1230 	char *result;
1231 
1232 	switch (mask) {
1233 	case OPEN4_SHARE_DENY_NONE:
1234 		result = "N";
1235 		break;
1236 	case OPEN4_SHARE_DENY_READ:
1237 		result = "R";
1238 		break;
1239 	case OPEN4_SHARE_DENY_WRITE:
1240 		result = "W";
1241 		break;
1242 	case OPEN4_SHARE_DENY_BOTH:
1243 		result = "RW";
1244 		break;
1245 	default:
1246 		result = "?";
1247 		break;
1248 	}
1249 
1250 	return (result);
1251 }
1252 
1253 static int
special_stateid(stateid4 * stateid)1254 special_stateid(stateid4 *stateid)
1255 {
1256 
1257 	if (! memcmp(stateid, &spec_stateid_0, sizeof (*stateid)))
1258 		return (0);
1259 
1260 	if (! memcmp(stateid, &spec_stateid_1, sizeof (*stateid)))
1261 		return (1);
1262 
1263 	return (-1);
1264 }
1265 
1266 static char *
_sum_stateid(stateid4 * stateid,char * prefix)1267 _sum_stateid(stateid4 *stateid, char *prefix)
1268 {
1269 	static char buf[32];
1270 	int spec;
1271 
1272 	if ((spec = special_stateid(stateid)) < 0)
1273 		snprintf(buf, sizeof (buf), "%s%04X:%u", prefix,
1274 		    stateid_hash(stateid), stateid->seqid);
1275 	else
1276 		snprintf(buf, sizeof (buf), "%s%s", prefix,
1277 		    spec == 0 ? "SPC0" : (spec == 1 ? "SPC1" : "SPC?"));
1278 	return (buf);
1279 }
1280 
1281 static void
_detail_stateid(stateid4 * stateid,char * prefix)1282 _detail_stateid(stateid4 *stateid, char *prefix)
1283 {
1284 	int spec;
1285 	char seqstr[32] = {0};
1286 
1287 	spec = special_stateid(stateid);
1288 
1289 	if (spec < 0)
1290 		sprintf(get_line(0, 0), "%sState ID hash = %04X",
1291 		    prefix, stateid_hash(stateid));
1292 	else
1293 		sprintf(get_line(0, 0), "%sState ID hash = %s",	prefix,
1294 		    spec == 0 ? "SPECIAL_0" :
1295 		    (spec == 1 ? "SPECIAL_1" : "SPECIAL_?"));
1296 
1297 	sprintf(get_line(0, 0), "    len = %u    val = %s",
1298 	    sizeof (stateid->other),
1299 	    tohex(stateid->other, sizeof (stateid->other)));
1300 
1301 	/*
1302 	 * If spec 0/1 stateid, print seqid in hex; otherwise,
1303 	 * use decimal.  This makes it more clear how spec stateids
1304 	 * are constructed [obvious that either all bits are 0, or all
1305 	 * bits are 1].
1306 	 */
1307 	if (spec == -1)
1308 		sprintf(seqstr, "%d", stateid->seqid);
1309 	else
1310 		sprintf(seqstr, "%08X", stateid->seqid);
1311 
1312 	sprintf(get_line(0, 0), "    %sState ID Sequence ID = %s",
1313 	    prefix, seqstr);
1314 }
1315 
1316 
1317 static char *
sum_lock_denied(LOCK4denied * denied)1318 sum_lock_denied(LOCK4denied *denied)
1319 {
1320 	static char buf[64];
1321 
1322 	sprintf(buf, "%s %llu:%llu LO=%04X",
1323 	    sum_lock_type_name(denied->locktype),
1324 	    denied->offset, denied->length,
1325 	    owner_hash(&denied->owner.owner));
1326 
1327 	return (buf);
1328 }
1329 
1330 static void
detail_lock_denied(LOCK4denied * denied)1331 detail_lock_denied(LOCK4denied *denied)
1332 {
1333 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(denied->locktype));
1334 	detail_lock_owner(&denied->owner);
1335 	sprintf(get_line(0, 0), "Offset = %llu", denied->offset);
1336 	sprintf(get_line(0, 0), "Length = %llu", denied->length);
1337 }
1338 
1339 /*
1340  * sum_createhow4: return the string name of "how".
1341  */
1342 
1343 static char *
createhow4_name(createhow4 * crtp)1344 createhow4_name(createhow4 *crtp)
1345 {
1346 	char *result;
1347 
1348 	switch (crtp->mode) {
1349 	case UNCHECKED4:
1350 		result = "UNCHECKED";
1351 		break;
1352 	case GUARDED4:
1353 		result = "GUARDED";
1354 		break;
1355 	case EXCLUSIVE4:
1356 		result = "EXCLUSIVE";
1357 		break;
1358 	default:
1359 		result = "?";
1360 		break;
1361 	}
1362 
1363 	return (result);
1364 }
1365 
1366 /*
1367  * detail_createhow4: print detail information about "how".
1368  */
1369 
1370 static void
detail_createhow4(createhow4 * crtp)1371 detail_createhow4(createhow4 *crtp)
1372 {
1373 	sprintf(get_line(0, 0), "Method = %s",
1374 	    createhow4_name(crtp));
1375 
1376 	switch (crtp->mode) {
1377 	case UNCHECKED4:
1378 	case GUARDED4:
1379 		detail_fattr4(&crtp->createhow4_u.createattrs);
1380 		break;
1381 	case EXCLUSIVE4:
1382 		sprintf(get_line(0, 0), "  Verifier = %s",
1383 		    tohex(crtp->createhow4_u.createverf,
1384 		    NFS4_VERIFIER_SIZE));
1385 		break;
1386 	}
1387 }
1388 
1389 static void
detail_createtype4(createtype4 * crtp)1390 detail_createtype4(createtype4 *crtp)
1391 {
1392 	sprintf(get_line(0, 0), "Type = %s",
1393 	    detail_type_name(crtp->type));
1394 	switch (crtp->type) {
1395 	case NF4LNK:
1396 		sprintf(get_line(0, 0), "Linkdata = %s",
1397 		    utf8localize((utf8string *)&crtp->createtype4_u.linkdata));
1398 		break;
1399 	case NF4BLK:
1400 	case NF4CHR:
1401 		sprintf(get_line(0, 0), "Specdata1 = %04x Specdata2 = %04x",
1402 		    crtp->createtype4_u.devdata.specdata1,
1403 		    crtp->createtype4_u.devdata.specdata2);
1404 		break;
1405 	default:
1406 		break;
1407 	}
1408 }
1409 
1410 static void
sumarg_access(char * buf,size_t buflen,void * obj)1411 sumarg_access(char *buf, size_t buflen, void *obj)
1412 {
1413 	ACCESS4args *args = (ACCESS4args *)obj;
1414 
1415 	sum_access4(buf, buflen, args->access);
1416 }
1417 
1418 static void
dtlarg_access(void * obj)1419 dtlarg_access(void *obj)
1420 {
1421 	ACCESS4args *args = (ACCESS4args *)obj;
1422 
1423 	detail_access4("Access bits", args->access);
1424 }
1425 
1426 static void
sumarg_close(char * buf,size_t buflen,void * obj)1427 sumarg_close(char *buf, size_t buflen, void *obj)
1428 {
1429 	CLOSE4args *args = (CLOSE4args *)obj;
1430 
1431 	snprintf(buf, buflen, "SQ=%u %s",
1432 	    args->seqid, sum_open_stateid(&args->open_stateid));
1433 }
1434 
1435 static void
dtlarg_close(void * obj)1436 dtlarg_close(void *obj)
1437 {
1438 	CLOSE4args *args = (CLOSE4args *)obj;
1439 
1440 	detail_open_stateid(&args->open_stateid);
1441 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
1442 }
1443 
1444 static void
sumarg_commit(char * buf,size_t buflen,void * obj)1445 sumarg_commit(char *buf, size_t buflen, void *obj)
1446 {
1447 	COMMIT4args *args = (COMMIT4args *)obj;
1448 
1449 	snprintf(buf, buflen, "at %llu for %u ", args->offset,
1450 	    args->count);
1451 }
1452 
1453 static void
dtlarg_commit(void * obj)1454 dtlarg_commit(void *obj)
1455 {
1456 	COMMIT4args *args = (COMMIT4args *)obj;
1457 
1458 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
1459 	sprintf(get_line(0, 0), "Count = %u", args->count);
1460 }
1461 
1462 static void
sumarg_compnt(char * buf,size_t buflen,void * obj)1463 sumarg_compnt(char *buf, size_t buflen, void *obj)
1464 {
1465 	component4 *comp = (component4 *)obj;
1466 
1467 	snprintf(buf, buflen, "%s", component_name(comp));
1468 }
1469 
1470 static void
dtlarg_compnt(void * obj)1471 dtlarg_compnt(void *obj)
1472 {
1473 	component4 *comp = (component4 *)obj;
1474 
1475 	sprintf(get_line(0, 0), "Name = %s", component_name(comp));
1476 }
1477 
1478 static void
sumarg_create(char * buf,size_t buflen,void * obj)1479 sumarg_create(char *buf, size_t buflen, void *obj)
1480 {
1481 	CREATE4args *args = (CREATE4args *)obj;
1482 
1483 	snprintf(buf, buflen, "%s %s ", component_name(&args->objname),
1484 	    sum_type_name(args->objtype.type));
1485 }
1486 
1487 static void
dtlarg_create(void * obj)1488 dtlarg_create(void *obj)
1489 {
1490 	CREATE4args *args = (CREATE4args *)obj;
1491 
1492 	sprintf(get_line(0, 0), "Name = %s", component_name(&args->objname));
1493 	detail_createtype4(&args->objtype);
1494 	detail_fattr4(&args->createattrs);
1495 }
1496 
1497 static void
sumarg_delprge(char * buf,size_t buflen,void * obj)1498 sumarg_delprge(char *buf, size_t buflen, void *obj)
1499 {
1500 	DELEGPURGE4args *args = (DELEGPURGE4args *)obj;
1501 
1502 	snprintf(buf, buflen, "%s", sum_clientid(args->clientid));
1503 }
1504 
1505 static void
dtlarg_delprge(void * obj)1506 dtlarg_delprge(void *obj)
1507 {
1508 	DELEGPURGE4args *args = (DELEGPURGE4args *)obj;
1509 
1510 	detail_clientid(args->clientid);
1511 }
1512 
1513 static void
sumarg_delret(char * buf,size_t buflen,void * obj)1514 sumarg_delret(char *buf, size_t buflen, void *obj)
1515 {
1516 	DELEGRETURN4args *args = (DELEGRETURN4args *)obj;
1517 
1518 	snprintf(buf, buflen, "%s", sum_deleg_stateid(&args->deleg_stateid));
1519 }
1520 
1521 static void
dtlarg_delret(void * obj)1522 dtlarg_delret(void *obj)
1523 {
1524 	DELEGRETURN4args *args = (DELEGRETURN4args *)obj;
1525 
1526 	detail_deleg_stateid(&args->deleg_stateid);
1527 }
1528 
1529 static void
sumarg_getattr(char * buf,size_t buflen,void * obj)1530 sumarg_getattr(char *buf, size_t buflen, void *obj)
1531 {
1532 	GETATTR4args *args = (GETATTR4args *)obj;
1533 
1534 	sum_attr_bitmap(buf, buflen, &args->attr_request);
1535 }
1536 
1537 static void
dtlarg_getattr(void * obj)1538 dtlarg_getattr(void *obj)
1539 {
1540 	GETATTR4args *args = (GETATTR4args *)obj;
1541 
1542 	detail_attr_bitmap("", &args->attr_request, NULL);
1543 }
1544 
1545 static void
sumarg_cb_getattr(char * buf,size_t buflen,void * obj)1546 sumarg_cb_getattr(char *buf, size_t buflen, void *obj)
1547 {
1548 	CB_GETATTR4args *args = (CB_GETATTR4args *)obj;
1549 	char *bp = buf;
1550 
1551 	snprintf(bp, buflen, "%s ", sum_fh4(&args->fh));
1552 	bp += strlen(bp);
1553 	sum_attr_bitmap(bp, buflen - (bp - buf), &args->attr_request);
1554 }
1555 
1556 static void
dtlarg_cb_getattr(void * obj)1557 dtlarg_cb_getattr(void *obj)
1558 {
1559 	CB_GETATTR4args *args = (CB_GETATTR4args *)obj;
1560 
1561 	detail_fh4(&args->fh);
1562 	detail_attr_bitmap("", &args->attr_request, NULL);
1563 }
1564 
1565 static void
sumarg_cb_recall(char * buf,size_t buflen,void * obj)1566 sumarg_cb_recall(char *buf, size_t buflen, void *obj)
1567 {
1568 	CB_RECALL4args *args = (CB_RECALL4args *)obj;
1569 	char *bp = buf;
1570 
1571 	snprintf(bp, buflen, "%s %s TR=%s", sum_fh4(&args->fh),
1572 	    sum_stateid(&args->stateid), args->truncate ? "T" : "F");
1573 }
1574 
1575 static void
dtlarg_cb_recall(void * obj)1576 dtlarg_cb_recall(void *obj)
1577 {
1578 	CB_RECALL4args *args = (CB_RECALL4args *)obj;
1579 
1580 	detail_fh4(&args->fh);
1581 	detail_stateid(&args->stateid);
1582 	sprintf(get_line(0, 0), "Truncate = %s",
1583 	    args->truncate ? "True" : "False");
1584 }
1585 
1586 
1587 /*
1588  * name openhow seqid claim access deny owner
1589  */
1590 static void
sumarg_open(char * buf,size_t buflen,void * obj)1591 sumarg_open(char *buf, size_t buflen, void *obj)
1592 {
1593 	OPEN4args *args = (OPEN4args *)obj;
1594 	char *bp = buf;
1595 	int blen = buflen, len;
1596 
1597 	sum_name(bp, buflen, &args->claim);
1598 	bp += (len = strlen(bp));
1599 	blen -= len;
1600 
1601 	sum_openflag(bp, blen, &args->openhow);
1602 	bp += (len = strlen(bp));
1603 	blen -= len;
1604 
1605 	snprintf(bp, blen, " SQ=%u", args->seqid);
1606 	bp += (len = strlen(bp));
1607 	blen -= len;
1608 
1609 	sum_claim(bp, blen, &args->claim);
1610 	bp += (len = strlen(bp));
1611 	blen -= len;
1612 
1613 	snprintf(bp, blen, " AC=%s DN=%s OO=%04X",
1614 	    sum_open_share_access(args->share_access),
1615 	    sum_open_share_deny(args->share_deny),
1616 	    owner_hash(&args->owner.owner));
1617 }
1618 
1619 static void
dtlarg_open(void * obj)1620 dtlarg_open(void *obj)
1621 {
1622 	OPEN4args *args = (OPEN4args *)obj;
1623 
1624 	detail_claim(&args->claim);
1625 	detail_openflag(&args->openhow);
1626 	detail_open_owner(&args->owner);
1627 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
1628 	sprintf(get_line(0, 0), "Access = 0x%x (%s)",
1629 	    args->share_access, sum_open_share_access(args->share_access));
1630 	sprintf(get_line(0, 0), "Deny   = 0x%x (%s)",
1631 	    args->share_deny, sum_open_share_access(args->share_deny));
1632 }
1633 
1634 static void
sumarg_openattr(char * buf,size_t buflen,void * obj)1635 sumarg_openattr(char *buf, size_t buflen, void *obj)
1636 {
1637 	OPENATTR4args *args = (OPENATTR4args *)obj;
1638 
1639 	snprintf(buf, buflen, "CD=%s",
1640 	    args->createdir ? "T" : "F");
1641 }
1642 
1643 static void
dtlarg_openattr(void * obj)1644 dtlarg_openattr(void *obj)
1645 {
1646 	OPENATTR4args *args = (OPENATTR4args *)obj;
1647 
1648 	sprintf(get_line(0, 0), "CreateDir = %s",
1649 	    args->createdir ? "True" : "False");
1650 }
1651 
1652 static void
sumarg_open_confirm(char * buf,size_t buflen,void * obj)1653 sumarg_open_confirm(char *buf, size_t buflen, void *obj)
1654 {
1655 	char *bp = buf;
1656 	OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj;
1657 
1658 	snprintf(bp, buflen, "SQ=%u %s", args->seqid,
1659 	    sum_open_stateid(&args->open_stateid));
1660 }
1661 
1662 static void
dtlarg_open_confirm(void * obj)1663 dtlarg_open_confirm(void *obj)
1664 {
1665 	OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj;
1666 
1667 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
1668 	detail_open_stateid(&args->open_stateid);
1669 }
1670 
1671 static void
sumarg_open_downgrd(char * buf,size_t buflen,void * obj)1672 sumarg_open_downgrd(char *buf, size_t buflen, void *obj)
1673 {
1674 	OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj;
1675 
1676 	snprintf(buf, buflen, "SQ=%u %s AC=%s DN=%s",
1677 	    args->seqid, sum_open_stateid(&args->open_stateid),
1678 	    sum_open_share_access(args->share_access),
1679 	    sum_open_share_deny(args->share_deny));
1680 }
1681 
1682 static void
dtlarg_open_downgrd(void * obj)1683 dtlarg_open_downgrd(void *obj)
1684 {
1685 	OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj;
1686 
1687 	sprintf(get_line(0, 0), "Open Sequence ID = %u", args->seqid);
1688 	detail_open_stateid(&args->open_stateid);
1689 	sprintf(get_line(0, 0), "Access = 0x%x (%s)",
1690 	    args->share_access, sum_open_share_access(args->share_access));
1691 	sprintf(get_line(0, 0), "Deny   = 0x%x (%s)",
1692 	    args->share_deny, sum_open_share_access(args->share_deny));
1693 }
1694 
1695 static void
sumarg_putfh(char * buf,size_t buflen,void * obj)1696 sumarg_putfh(char *buf, size_t buflen, void *obj)
1697 {
1698 	PUTFH4args *args = (PUTFH4args *)obj;
1699 
1700 	snprintf(buf, buflen, "%s", sum_fh4(&args->object));
1701 }
1702 
1703 static void
dtlarg_putfh(void * obj)1704 dtlarg_putfh(void *obj)
1705 {
1706 	PUTFH4args *args = (PUTFH4args *)obj;
1707 
1708 	detail_fh4(&args->object);
1709 }
1710 
1711 static void
sumarg_link(char * buf,size_t buflen,void * obj)1712 sumarg_link(char *buf, size_t buflen, void *obj)
1713 {
1714 	LINK4args *args = (LINK4args *)obj;
1715 
1716 	snprintf(buf, buflen, "%s", component_name(&args->newname));
1717 }
1718 
1719 static void
dtlarg_link(void * obj)1720 dtlarg_link(void *obj)
1721 {
1722 	LINK4args *args = (LINK4args *)obj;
1723 
1724 	sprintf(get_line(0, 0), "New name = %s",
1725 	    component_name(&args->newname));
1726 }
1727 
1728 static void
sum_open_to_lock_owner(char * buf,int buflen,open_to_lock_owner4 * own)1729 sum_open_to_lock_owner(char *buf, int buflen, open_to_lock_owner4 *own)
1730 {
1731 	snprintf(buf, buflen, " OSQ=%u %s LSQ=%u LO=%04X", own->open_seqid,
1732 	    sum_open_stateid(&own->open_stateid), own->lock_seqid,
1733 	    owner_hash(&own->lock_owner.owner));
1734 }
1735 
1736 static void
sum_exist_lock_owner(char * buf,int buflen,exist_lock_owner4 * own)1737 sum_exist_lock_owner(char *buf, int buflen, exist_lock_owner4 *own)
1738 {
1739 	snprintf(buf, buflen, " LSQ=%u %s", own->lock_seqid,
1740 	    sum_lock_stateid(&own->lock_stateid));
1741 }
1742 
1743 static void
sum_locker(char * buf,size_t len,locker4 * lk)1744 sum_locker(char *buf, size_t len, locker4 *lk)
1745 {
1746 	if (lk->new_lock_owner == TRUE)
1747 		sum_open_to_lock_owner(buf, len, &lk->locker4_u.open_owner);
1748 	else
1749 		sum_exist_lock_owner(buf, len, &lk->locker4_u.lock_owner);
1750 }
1751 
1752 static char *
sum_lock_type_name(enum nfs_lock_type4 type)1753 sum_lock_type_name(enum nfs_lock_type4 type)
1754 {
1755 	char *result;
1756 
1757 	switch (type) {
1758 	case READ_LT:
1759 		result = "RD";
1760 		break;
1761 	case WRITE_LT:
1762 		result = "WR";
1763 		break;
1764 	case READW_LT:
1765 		result = "RDW";
1766 		break;
1767 	case WRITEW_LT:
1768 		result = "WRW";
1769 		break;
1770 	default:
1771 		result = "?";
1772 		break;
1773 	}
1774 
1775 	return (result);
1776 }
1777 
1778 static void
sumarg_lock(char * buf,size_t buflen,void * obj)1779 sumarg_lock(char *buf, size_t buflen, void *obj)
1780 {
1781 	LOCK4args *args = (LOCK4args *)obj;
1782 	char *bp = buf;
1783 
1784 	snprintf(buf, buflen, "%s%s%llu:%llu",
1785 	    sum_lock_type_name(args->locktype),
1786 	    args->reclaim ? " reclaim " : " ",
1787 	    args->offset, args->length);
1788 
1789 	bp += strlen(buf);
1790 	sum_locker(bp, buflen - (bp - buf), &args->locker);
1791 }
1792 
1793 static void
detail_open_to_lock_owner(open_to_lock_owner4 * own)1794 detail_open_to_lock_owner(open_to_lock_owner4 *own)
1795 {
1796 	sprintf(get_line(0, 0), "Open Sequence ID = %u", own->open_seqid);
1797 	detail_open_stateid(&own->open_stateid);
1798 	sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid);
1799 	detail_lock_owner(&own->lock_owner);
1800 }
1801 
1802 static void
detail_exist_lock_owner(exist_lock_owner4 * own)1803 detail_exist_lock_owner(exist_lock_owner4 *own)
1804 {
1805 	detail_lock_stateid(&own->lock_stateid);
1806 	sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid);
1807 }
1808 
1809 static void
detail_locker(locker4 * lk)1810 detail_locker(locker4 *lk)
1811 {
1812 	if (lk->new_lock_owner == TRUE)
1813 		detail_open_to_lock_owner(&lk->locker4_u.open_owner);
1814 	else
1815 		detail_exist_lock_owner(&lk->locker4_u.lock_owner);
1816 }
1817 
1818 static void
dtlarg_lock(void * obj)1819 dtlarg_lock(void *obj)
1820 {
1821 	LOCK4args *args = (LOCK4args *)obj;
1822 
1823 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
1824 	sprintf(get_line(0, 0), "Reclaim = %s",
1825 	    args->reclaim ? "TRUE" : "FALSE");
1826 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
1827 	sprintf(get_line(0, 0), "Length = %llu", args->length);
1828 	detail_locker(&args->locker);
1829 }
1830 
1831 static void
sumarg_lockt(char * buf,size_t buflen,void * obj)1832 sumarg_lockt(char *buf, size_t buflen, void *obj)
1833 {
1834 	LOCKT4args *args = (LOCKT4args *)obj;
1835 
1836 	snprintf(buf, buflen, "%s %llu:%llu",
1837 	    sum_lock_type_name(args->locktype),
1838 	    args->offset, args->length);
1839 }
1840 
1841 static void
dtlarg_lockt(void * obj)1842 dtlarg_lockt(void *obj)
1843 {
1844 	LOCKT4args *args = (LOCKT4args *)obj;
1845 
1846 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
1847 	detail_lock_owner(&args->owner);
1848 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
1849 	sprintf(get_line(0, 0), "Length = %llu", args->length);
1850 }
1851 
1852 static void
sumarg_locku(char * buf,size_t buflen,void * obj)1853 sumarg_locku(char *buf, size_t buflen, void *obj)
1854 {
1855 	LOCKU4args *args = (LOCKU4args *)obj;
1856 
1857 	snprintf(buf, buflen, "%llu:%llu LSQ=%u %s",
1858 	    args->offset, args->length, args->seqid,
1859 	    sum_lock_stateid(&args->lock_stateid));
1860 }
1861 
1862 
1863 static void
dtlarg_locku(void * obj)1864 dtlarg_locku(void *obj)
1865 {
1866 	LOCKU4args *args = (LOCKU4args *)obj;
1867 
1868 	sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype));
1869 	sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid);
1870 	detail_lock_stateid(&args->lock_stateid);
1871 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
1872 	sprintf(get_line(0, 0), "Length = %llu", args->length);
1873 }
1874 
1875 static void
sumarg_lookup(char * buf,size_t buflen,void * obj)1876 sumarg_lookup(char *buf, size_t buflen, void *obj)
1877 {
1878 	LOOKUP4args *args = (LOOKUP4args *)obj;
1879 
1880 	sum_compname4(buf, buflen, &args->objname);
1881 }
1882 
1883 static void
dtlarg_lookup(void * obj)1884 dtlarg_lookup(void *obj)
1885 {
1886 	LOOKUP4args *args = (LOOKUP4args *)obj;
1887 
1888 	detail_compname4(&args->objname);
1889 }
1890 
1891 static void
sumarg_read(char * buf,size_t buflen,void * obj)1892 sumarg_read(char *buf, size_t buflen, void *obj)
1893 {
1894 	READ4args *args = (READ4args *)obj;
1895 
1896 	snprintf(buf, buflen, "%s at %llu for %u",
1897 	    sum_stateid(&args->stateid), args->offset, args->count);
1898 }
1899 
1900 static void
dtlarg_read(void * obj)1901 dtlarg_read(void *obj)
1902 {
1903 	READ4args *args = (READ4args *)obj;
1904 
1905 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
1906 	sprintf(get_line(0, 0), "Count = %u", args->count);
1907 	detail_stateid(&args->stateid);
1908 }
1909 
1910 static void
sumarg_readdir(char * buf,size_t buflen,void * obj)1911 sumarg_readdir(char *buf, size_t buflen, void *obj)
1912 {
1913 	READDIR4args *args = (READDIR4args *)obj;
1914 
1915 	snprintf(buf, buflen, "Cookie=%llu (%s) for %u/%u",
1916 	    args->cookie, tohex(args->cookieverf, NFS4_VERIFIER_SIZE),
1917 	    args->dircount, args->maxcount);
1918 }
1919 
1920 static void
dtlarg_readdir(void * obj)1921 dtlarg_readdir(void *obj)
1922 {
1923 	READDIR4args *args = (READDIR4args *)obj;
1924 
1925 	sprintf(get_line(0, 0), "Cookie = %llu", args->cookie);
1926 	sprintf(get_line(0, 0), "Verifier = %s",
1927 	    tohex(args->cookieverf, NFS4_VERIFIER_SIZE));
1928 	sprintf(get_line(0, 0), "Dircount = %u", args->dircount);
1929 	sprintf(get_line(0, 0), "Maxcount = %u", args->maxcount);
1930 	detail_attr_bitmap("", &args->attr_request, NULL);
1931 }
1932 
1933 static void
dtlarg_release_lkown(void * obj)1934 dtlarg_release_lkown(void *obj)
1935 {
1936 	RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj;
1937 
1938 	detail_lock_owner(&args->lock_owner);
1939 }
1940 
1941 static void
sumarg_release_lkown(char * buf,size_t buflen,void * obj)1942 sumarg_release_lkown(char *buf, size_t buflen, void *obj)
1943 {
1944 	RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj;
1945 
1946 	snprintf(buf, buflen, "LO=%04X", owner_hash(&args->lock_owner.owner));
1947 }
1948 
1949 static void
sumarg_rename(char * buf,size_t buflen,void * obj)1950 sumarg_rename(char *buf, size_t buflen, void *obj)
1951 {
1952 	RENAME4args *args = (RENAME4args *)obj;
1953 
1954 	snprintf(buf, buflen, "%s to %s",
1955 	    component_name(&args->oldname),
1956 	    component_name(&args->newname));
1957 }
1958 
1959 static void
dtlarg_rename(void * obj)1960 dtlarg_rename(void *obj)
1961 {
1962 	RENAME4args *args = (RENAME4args *)obj;
1963 
1964 	sprintf(get_line(0, 0), "Old name = %s",
1965 	    component_name(&args->oldname));
1966 	sprintf(get_line(0, 0), "New name = %s",
1967 	    component_name(&args->newname));
1968 }
1969 
1970 static void
sumarg_renew(char * buf,size_t buflen,void * obj)1971 sumarg_renew(char *buf, size_t buflen, void *obj)
1972 {
1973 	RENEW4args *args = (RENEW4args *)obj;
1974 
1975 	snprintf(buf, buflen, "%s", sum_clientid(args->clientid));
1976 }
1977 static void
dtlarg_renew(void * obj)1978 dtlarg_renew(void *obj)
1979 {
1980 	RENEW4args *args = (RENEW4args *)obj;
1981 
1982 	detail_clientid(args->clientid);
1983 }
1984 
1985 static void
sumarg_secinfo(char * buf,size_t buflen,void * obj)1986 sumarg_secinfo(char *buf, size_t buflen, void *obj)
1987 {
1988 	SECINFO4args *args = (SECINFO4args *)obj;
1989 
1990 	snprintf(buf, buflen, "%s",
1991 	    component_name(&args->name));
1992 }
1993 
1994 static void
dtlarg_secinfo(void * obj)1995 dtlarg_secinfo(void *obj)
1996 {
1997 	SECINFO4args *args = (SECINFO4args *)obj;
1998 
1999 	sprintf(get_line(0, 0), "Name = %s",
2000 	    component_name(&args->name));
2001 }
2002 
2003 static void
sumarg_setattr(char * buf,size_t buflen,void * obj)2004 sumarg_setattr(char *buf, size_t buflen, void *obj)
2005 {
2006 	SETATTR4args *args = (SETATTR4args *)obj;
2007 
2008 	snprintf(buf, buflen, "%s", sum_stateid(&args->stateid));
2009 }
2010 
2011 static void
dtlarg_setattr(void * obj)2012 dtlarg_setattr(void *obj)
2013 {
2014 	SETATTR4args *args = (SETATTR4args *)obj;
2015 
2016 	detail_stateid(&args->stateid);
2017 	detail_fattr4(&args->obj_attributes);
2018 }
2019 
2020 static void
sumarg_setclid(char * buf,size_t buflen,void * obj)2021 sumarg_setclid(char *buf, size_t buflen, void *obj)
2022 {
2023 	SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
2024 
2025 	snprintf(buf, buflen, "Prog=%u ID=%s Addr=%s CBID=%u",
2026 	    args->callback.cb_program,
2027 	    args->callback.cb_location.r_netid,
2028 	    args->callback.cb_location.r_addr, args->callback_ident);
2029 }
2030 
2031 static void
dtlarg_setclid(void * obj)2032 dtlarg_setclid(void *obj)
2033 {
2034 	SETCLIENTID4args *args = (SETCLIENTID4args *)obj;
2035 
2036 	sprintf(get_line(0, 0), "Verifier=%s",
2037 	    tohex(args->client.verifier, NFS4_VERIFIER_SIZE));
2038 	sprintf(get_line(0, 0), "ID = (%d) %s",
2039 	    args->client.id.id_len,
2040 	    tohex(args->client.id.id_val, args->client.id.id_len));
2041 
2042 	sprintf(get_line(0, 0), "Callback Program = %u",
2043 	    args->callback.cb_program);
2044 	sprintf(get_line(0, 0), "Callback Net ID = %s",
2045 	    args->callback.cb_location.r_netid);
2046 	sprintf(get_line(0, 0), "Callback Addr = %s",
2047 	    args->callback.cb_location.r_addr);
2048 	sprintf(get_line(0, 0), "Callback Ident = %u", args->callback_ident);
2049 }
2050 
2051 static void
sumarg_setclid_cfm(char * buf,size_t buflen,void * obj)2052 sumarg_setclid_cfm(char *buf, size_t buflen, void *obj)
2053 {
2054 	SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj;
2055 
2056 	snprintf(buf, buflen, "%s CFV=%s", sum_clientid(args->clientid),
2057 	    tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
2058 }
2059 
2060 static void
dtlarg_setclid_cfm(void * obj)2061 dtlarg_setclid_cfm(void *obj)
2062 {
2063 	SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj;
2064 
2065 	detail_clientid(args->clientid);
2066 	sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
2067 	    tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE));
2068 }
2069 
2070 
2071 static void
dtlarg_verify(void * obj)2072 dtlarg_verify(void *obj)
2073 {
2074 	NVERIFY4args *args = (NVERIFY4args *)obj;
2075 
2076 	detail_fattr4(&args->obj_attributes);
2077 }
2078 
2079 static void
sumarg_write(char * buf,size_t buflen,void * obj)2080 sumarg_write(char *buf, size_t buflen, void *obj)
2081 {
2082 	WRITE4args *args = (WRITE4args *)obj;
2083 
2084 	snprintf(buf, buflen, "%s at %llu for %u",
2085 	    sum_stateid(&args->stateid), args->offset, args->data.data_len);
2086 }
2087 
2088 static void
dtlarg_write(void * obj)2089 dtlarg_write(void *obj)
2090 {
2091 	WRITE4args *args = (WRITE4args *)obj;
2092 
2093 	sprintf(get_line(0, 0), "Offset = %llu", args->offset);
2094 	sprintf(get_line(0, 0), "Count = %u", args->data.data_len);
2095 	sprintf(get_line(0, 0), "Stable = %s", stable_how4_name(args->stable));
2096 	detail_stateid(&args->stateid);
2097 }
2098 
2099 static char *
sum_fh4(nfs_fh4 * fh)2100 sum_fh4(nfs_fh4 *fh)
2101 {
2102 	static char buf[20];
2103 
2104 	sprintf(buf, "FH=%04X", fh4_hash(fh));
2105 
2106 	return (buf);
2107 }
2108 
2109 static void
detail_fh4(nfs_fh4 * fh)2110 detail_fh4(nfs_fh4 *fh)
2111 {
2112 	int i;
2113 	uchar_t *cp;
2114 	char *bufp;
2115 
2116 	sprintf(get_line(0, 0), "File handle = [%04X]", fh4_hash(fh));
2117 	bufp = get_line(0, 0);
2118 	sprintf(bufp, "(%d) ", fh->nfs_fh4_len);
2119 	bufp += strlen(bufp);
2120 	/* XXX use tohex()? */
2121 	for (i = 0, cp = (uchar_t *)fh->nfs_fh4_val;
2122 	    i < fh->nfs_fh4_len;
2123 	    i++, cp++) {
2124 		if (i != 0 && i % 32 == 0)
2125 			bufp = get_line(0, 0);
2126 		sprintf(bufp, "%02x", *cp);
2127 		bufp += strlen(bufp);
2128 	}
2129 }
2130 
2131 static void
detail_fattr4(fattr4 * attrp)2132 detail_fattr4(fattr4 *attrp)
2133 {
2134 	unpkd_attrmap_t provided;
2135 	uint_t attrnum;
2136 	XDR attrxdr;
2137 	jmp_buf old_errbuf;
2138 
2139 	xdrmem_create(&attrxdr, attrp->attr_vals.attrlist4_val,
2140 	    attrp->attr_vals.attrlist4_len, XDR_DECODE);
2141 
2142 	bcopy(xdr_err, old_errbuf, sizeof (old_errbuf));
2143 	if (setjmp(xdr_err)) {
2144 		sprintf(get_line(0, 0), "<attr_vals too short>");
2145 		goto done;
2146 	}
2147 
2148 	detail_attr_bitmap("", &attrp->attrmask, &provided);
2149 	for (attrnum = 0; attrnum < MAX_ATTRIBUTES; attrnum++) {
2150 		if (provided.map[attrnum]) {
2151 			attr_info[attrnum].prt_details(&attrxdr);
2152 		}
2153 	}
2154 
2155 done:
2156 	bcopy(old_errbuf, xdr_err, sizeof (old_errbuf));
2157 }
2158 
2159 static void
sum_attr_bitmap(char * buf,size_t buflen,bitmap4 * mapp)2160 sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp)
2161 {
2162 	uint_t num_words;
2163 	char *bp;
2164 	size_t curlen, remaining;
2165 
2166 	buf[0] = '\0';
2167 	for (num_words = 0; num_words < mapp->bitmap4_len; num_words++) {
2168 		curlen = strlen(buf);
2169 		if (curlen + sizeof ("<Too Long>") >= buflen) {
2170 			strcpy(buf + buflen - sizeof ("<Too Long>"),
2171 			    "<Too Long>");
2172 			return;
2173 		}
2174 		bp = buf + curlen;
2175 		remaining = buflen - curlen;
2176 		snprintf(bp, remaining,
2177 		    num_words == 0 ? "%x" : " %x",
2178 		    mapp->bitmap4_val[num_words]);
2179 	}
2180 }
2181 
2182 /*
2183  * Print detail information for the given attribute bitmap, and fill in the
2184  * unpacked version of the map if "unpacked" is non-null.  Returns the
2185  * number of bytes in the bitmap.  "prefix" is an initial string that is
2186  * printed at the front of each line.
2187  */
2188 
2189 static void
detail_attr_bitmap(char * prefix,bitmap4 * bitp,unpkd_attrmap_t * unpacked)2190 detail_attr_bitmap(char *prefix, bitmap4 *bitp, unpkd_attrmap_t *unpacked)
2191 {
2192 	uint_t num_words;
2193 	uint32_t *wp;
2194 	uint_t byte_num;
2195 
2196 	if (unpacked != NULL)
2197 		memset(unpacked, 0, sizeof (unpkd_attrmap_t));
2198 
2199 	/*
2200 	 * Break the bitmap into octets, then print in hex and
2201 	 * symbolically.
2202 	 */
2203 
2204 	for (num_words = 0, wp = bitp->bitmap4_val;
2205 	    num_words < bitp->bitmap4_len;
2206 	    num_words++, wp++) {
2207 		for (byte_num = 0; byte_num < 4; byte_num++) {
2208 			uchar_t val = (*wp) >> (byte_num * 8);
2209 			char *buf = get_line(0, 0);
2210 			uint_t attrnum;
2211 			int bit;
2212 
2213 			sprintf(buf, "%s  0x%02x  ", prefix, val);
2214 			attrnum = num_words * 32 + byte_num * 8;
2215 			for (bit = 7; bit >= 0; bit--) {
2216 				if (val & (1 << bit)) {
2217 					strcat(buf, " ");
2218 					strcat(buf,
2219 					    attr_name(attrnum + bit));
2220 					if (unpacked != NULL)
2221 						unpacked->map[attrnum + bit] =
2222 						    1;
2223 				}
2224 			}
2225 		}
2226 	}
2227 }
2228 
2229 /*
2230  * Format the summary line results from a COMPOUND4 call.
2231  */
2232 
2233 static void
sum_comp4res(char * line,char * (* sumres_fn)(void))2234 sum_comp4res(char *line, char *(*sumres_fn)(void))
2235 {
2236 	nfsstat4 status;
2237 	static utf8string tag;
2238 
2239 	status = getxdr_long();
2240 	if (!xdr_utf8string(&xdrm, &tag))
2241 		longjmp(xdr_err, 1);
2242 
2243 	sprintf(line, "(%.20s) %s %s", utf8localize(&tag),
2244 	    status_name(status), sumres_fn());
2245 
2246 	xdr_free(xdr_utf8string, (char *)&tag);
2247 }
2248 
2249 
2250 /*
2251  * Return a set of summary strings for the result data that's next in the
2252  * XDR stream, up to SUM_COMPND_MAX characters.  If the strings don't fit,
2253  * include a "..." at the end of the string.
2254  */
2255 
2256 static char *
sum_compound4res(void)2257 sum_compound4res(void)
2258 {
2259 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
2260 	int numres;
2261 	const size_t buflen = sizeof (buf);
2262 	char *bp;
2263 	nfs_resop4 one_res;
2264 
2265 	buf[0] = '\0';
2266 	if (setjmp(xdr_err)) {
2267 		bp = buf + strlen(buf);
2268 		snprintf(bp, buflen - (bp - buf),
2269 		    nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag);
2270 		return (buf);
2271 	}
2272 
2273 	numres = getxdr_long();
2274 	bp = buf;
2275 	while (numres-- > 0) {
2276 		char *result;
2277 
2278 		bzero(&one_res, sizeof (one_res));
2279 
2280 		if (!xdr_nfs_resop4(&xdrm, &one_res)) {
2281 			xdr_free(xdr_nfs_resop4, (char *)&one_res);
2282 			longjmp(xdr_err, 1);
2283 		}
2284 
2285 		snprintf(bp, buflen - (bp - buf), "%s ",
2286 		    opcode_name(one_res.resop));
2287 		bp += strlen(bp);
2288 
2289 		result = sum_result(&one_res);
2290 		if (strlen(result) > 0) {
2291 			snprintf(bp, buflen - (bp - buf), "%s ", result);
2292 			bp += strlen(bp);
2293 		}
2294 
2295 		/* nfs4_skip_bytes set by xdr_nfs4_argop4() */
2296 		if (nfs4_skip_bytes != 0)
2297 			nfs4_xdr_skip(nfs4_skip_bytes);
2298 
2299 		xdr_free(xdr_nfs_resop4, (char *)&one_res);
2300 		/* add "..." if past the "end" of the buffer */
2301 		if (bp - buf > SUM_COMPND_MAX) {
2302 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
2303 			    "...");
2304 			break;
2305 		}
2306 	}
2307 
2308 	return (buf);
2309 }
2310 
2311 
2312 /*
2313  * Return a set of summary strings for the result data that's next in the
2314  * XDR stream, up to SUM_COMPND_MAX characters.  If the strings don't fit,
2315  * include a "..." at the end of the string.
2316  */
2317 
2318 static char *
sum_cb_compound4res(void)2319 sum_cb_compound4res(void)
2320 {
2321 	static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */
2322 	int numres;
2323 	const size_t buflen = sizeof (buf);
2324 	char *bp;
2325 	nfs_cb_resop4 one_res;
2326 
2327 	buf[0] = '\0';
2328 	if (setjmp(xdr_err)) {
2329 		bp = buf + strlen(buf);
2330 		snprintf(bp, buflen - (bp - buf), "<XDR Error or Fragmented"
2331 		    " RPC>");
2332 		return (buf);
2333 	}
2334 
2335 	numres = getxdr_long();
2336 	bp = buf;
2337 	while (numres-- > 0) {
2338 		bzero(&one_res, sizeof (one_res));
2339 		if (!xdr_nfs_cb_resop4(&xdrm, &one_res)) {
2340 			xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
2341 			longjmp(xdr_err, 1);
2342 		}
2343 		snprintf(bp, buflen - (bp - buf), "%s %s ",
2344 		    cb_opcode_name(one_res.resop),
2345 		    sum_cb_result(&one_res));
2346 		bp += strlen(bp);
2347 
2348 		xdr_free(xdr_nfs_cb_resop4, (char *)&one_res);
2349 
2350 		/* add "..." if past the "end" of the buffer */
2351 		if (bp - buf > SUM_COMPND_MAX) {
2352 			strcpy(buf + SUM_COMPND_MAX - strlen("..."),
2353 			    "...");
2354 			break;
2355 		}
2356 	}
2357 
2358 	return (buf);
2359 }
2360 
2361 
2362 /*
2363  * Return the summarized results for the given resultdata.
2364  */
2365 
2366 static char *
sum_result(nfs_resop4 * resp)2367 sum_result(nfs_resop4 *resp)
2368 {
2369 	static char buf[1024];
2370 	void (*fmtproc)(char *, size_t, void *);
2371 
2372 	buf[0] = '\0';
2373 	if (resp->resop < num_opcodes)
2374 		fmtproc = opcode_info[resp->resop].sumres;
2375 	else if (resp->resop == OP_ILLEGAL)
2376 		fmtproc = sum_nfsstat4;
2377 	else
2378 		fmtproc = NULL;
2379 
2380 	if (fmtproc != NULL)
2381 		fmtproc(buf, sizeof (buf), &resp->nfs_resop4_u);
2382 
2383 	return (buf);
2384 }
2385 
2386 /*
2387  * Return the summarized results for the given resultdata.
2388  */
2389 
2390 static char *
sum_cb_result(nfs_cb_resop4 * resp)2391 sum_cb_result(nfs_cb_resop4 *resp)
2392 {
2393 	static char buf[1024];
2394 	void (*fmtproc)(char *, size_t, void *);
2395 
2396 	buf[0] = '\0';
2397 	if (resp->resop < cb_num_opcodes)
2398 		fmtproc = cb_opcode_info[resp->resop].sumres;
2399 	else if (resp->resop == OP_CB_ILLEGAL)
2400 		fmtproc = sum_nfsstat4;
2401 	else
2402 		fmtproc = NULL;
2403 
2404 	if (fmtproc != NULL)
2405 		fmtproc(buf, sizeof (buf), &resp->nfs_cb_resop4_u);
2406 
2407 	return (buf);
2408 }
2409 
2410 
2411 static void
dtl_change_info(char * msg,change_info4 * infop)2412 dtl_change_info(char *msg, change_info4 *infop)
2413 {
2414 	sprintf(get_line(0, 0), "%s:", msg);
2415 	sprintf(get_line(0, 0), "  Atomic = %s",
2416 	    infop->atomic ? "TRUE" : "FALSE");
2417 	detail_fattr4_change("  Before", infop->before);
2418 	detail_fattr4_change("  After", infop->after);
2419 }
2420 
2421 static void
detail_fattr4_change(char * msg,fattr4_change chg)2422 detail_fattr4_change(char *msg, fattr4_change chg)
2423 {
2424 	sprintf(get_line(0, 0), "%s: 0x%llx", msg, chg);
2425 					/* XXX print as time_t, too? */
2426 }
2427 
2428 static void
sum_nfsstat4(char * buf,size_t buflen,void * obj)2429 sum_nfsstat4(char *buf, size_t buflen, void *obj)
2430 {
2431 	nfsstat4 status = *(nfsstat4 *)obj;
2432 
2433 	strncpy(buf, status_name(status), buflen);
2434 }
2435 
2436 static void
dtl_nfsstat4(void * obj)2437 dtl_nfsstat4(void *obj)
2438 {
2439 	nfsstat4 status = *(nfsstat4 *)obj;
2440 
2441 	sprintf(get_line(0, 0), "Status = %d (%s)", status,
2442 	    status_name(status));
2443 }
2444 
2445 static void
sumres_access(char * buf,size_t buflen,void * obj)2446 sumres_access(char *buf, size_t buflen, void *obj)
2447 {
2448 	ACCESS4res *res = (ACCESS4res *)obj;
2449 	char *bp = buf;
2450 	int len, blen = buflen;
2451 
2452 	strcpy(bp, status_name(res->status));
2453 	if (res->status == NFS4_OK) {
2454 		bp += (len = strlen(bp));
2455 		blen -= len;
2456 
2457 		snprintf(bp, blen, " Supp=");
2458 		bp += (len = strlen(bp));
2459 		blen -= len;
2460 
2461 		sum_access4(bp, blen, res->ACCESS4res_u.resok4.supported);
2462 		bp += (len = strlen(bp));
2463 		blen -= len;
2464 
2465 		snprintf(bp, blen, " Allow=");
2466 		bp += (len = strlen(bp));
2467 		blen -= len;
2468 
2469 		sum_access4(bp, blen, res->ACCESS4res_u.resok4.access);
2470 	}
2471 }
2472 
2473 static void
dtlres_access(void * obj)2474 dtlres_access(void *obj)
2475 {
2476 	ACCESS4res *res = (ACCESS4res *)obj;
2477 
2478 	dtl_nfsstat4(obj);
2479 	if (res->status == NFS4_OK) {
2480 		detail_access4("Supported Attributes",
2481 		    res->ACCESS4res_u.resok4.supported);
2482 		detail_access4("Allowed Attributes",
2483 		    res->ACCESS4res_u.resok4.access);
2484 	}
2485 }
2486 
2487 static void
sumres_close(char * buf,size_t buflen,void * obj)2488 sumres_close(char *buf, size_t buflen, void *obj)
2489 {
2490 	CLOSE4res *res = (CLOSE4res *)obj;
2491 
2492 	if (res->status == NFS4_OK)
2493 		snprintf(buf, buflen, "%s",
2494 		    sum_open_stateid(&res->CLOSE4res_u.open_stateid));
2495 }
2496 
2497 static void
dtlres_close(void * obj)2498 dtlres_close(void *obj)
2499 {
2500 	CLOSE4res *res = (CLOSE4res *)obj;
2501 
2502 	dtl_nfsstat4(obj);
2503 	if (res->status == NFS4_OK) {
2504 		detail_open_stateid(&res->CLOSE4res_u.open_stateid);
2505 	}
2506 }
2507 
2508 static void
sumres_commit(char * buf,size_t buflen,void * obj)2509 sumres_commit(char *buf, size_t buflen, void *obj)
2510 {
2511 	COMMIT4res *res = (COMMIT4res *)obj;
2512 
2513 	if (res->status == NFS4_OK)
2514 		snprintf(buf, buflen, "Verf=%s",
2515 		    tohex(res->COMMIT4res_u.resok4.writeverf,
2516 		    NFS4_VERIFIER_SIZE));
2517 }
2518 
2519 static void
dtlres_commit(void * obj)2520 dtlres_commit(void *obj)
2521 {
2522 	COMMIT4res *res = (COMMIT4res *)obj;
2523 
2524 	dtl_nfsstat4(obj);
2525 	if (res->status == NFS4_OK) {
2526 		sprintf(get_line(0, 0), "Verifier = %s",
2527 		    tohex(res->COMMIT4res_u.resok4.writeverf,
2528 		    NFS4_VERIFIER_SIZE));
2529 	}
2530 }
2531 
2532 static void
dtlres_create(void * obj)2533 dtlres_create(void *obj)
2534 {
2535 	CREATE4res *res = (CREATE4res *)obj;
2536 
2537 	dtl_nfsstat4(obj);
2538 	if (res->status == NFS4_OK) {
2539 		dtl_change_info("Change Information",
2540 		    &res->CREATE4res_u.resok4.cinfo);
2541 		detail_attr_bitmap("", &res->CREATE4res_u.resok4.attrset,
2542 		    NULL);
2543 	}
2544 }
2545 
2546 static void
sumres_getattr(char * buf,size_t buflen,void * obj)2547 sumres_getattr(char *buf, size_t buflen, void *obj)
2548 {
2549 	GETATTR4res *res = (GETATTR4res *)obj;
2550 
2551 	strncpy(buf, status_name(res->status), buflen);
2552 }
2553 
2554 static void
dtlres_getattr(void * obj)2555 dtlres_getattr(void *obj)
2556 {
2557 	GETATTR4res *res = (GETATTR4res *)obj;
2558 
2559 	dtl_nfsstat4(obj);
2560 	if (res->status == NFS4_OK) {
2561 		detail_fattr4(&res->GETATTR4res_u.resok4.obj_attributes);
2562 	}
2563 }
2564 
2565 static void
sumres_cb_getattr(char * buf,size_t buflen,void * obj)2566 sumres_cb_getattr(char *buf, size_t buflen, void *obj)
2567 {
2568 	CB_GETATTR4res *res = (CB_GETATTR4res *)obj;
2569 
2570 	strncpy(buf, status_name(res->status), buflen);
2571 }
2572 
2573 static void
dtlres_cb_getattr(void * obj)2574 dtlres_cb_getattr(void *obj)
2575 {
2576 	CB_GETATTR4res *res = (CB_GETATTR4res *)obj;
2577 
2578 	dtl_nfsstat4(obj);
2579 	if (res->status == NFS4_OK) {
2580 		detail_fattr4(&res->CB_GETATTR4res_u.resok4.obj_attributes);
2581 	}
2582 }
2583 
2584 
2585 static void
sumres_getfh(char * buf,size_t buflen,void * obj)2586 sumres_getfh(char *buf, size_t buflen, void *obj)
2587 {
2588 	char *bp;
2589 	GETFH4res *res = (GETFH4res *)obj;
2590 
2591 	strncpy(buf, status_name(res->status), buflen);
2592 	if (res->status == NFS4_OK) {
2593 		bp = buf + strlen(buf);
2594 		snprintf(bp, buflen - (bp - buf), " %s",
2595 		    sum_fh4(&res->GETFH4res_u.resok4.object));
2596 	}
2597 }
2598 
2599 static void
dtlres_getfh(void * obj)2600 dtlres_getfh(void *obj)
2601 {
2602 	GETFH4res *res = (GETFH4res *)obj;
2603 
2604 	dtl_nfsstat4(obj);
2605 	if (res->status == NFS4_OK) {
2606 		detail_fh4(&res->GETFH4res_u.resok4.object);
2607 	}
2608 }
2609 
2610 static void
dtlres_link(void * obj)2611 dtlres_link(void *obj)
2612 {
2613 	LINK4res *res = (LINK4res *)obj;
2614 
2615 	dtl_nfsstat4(obj);
2616 	if (res->status == NFS4_OK) {
2617 		dtl_change_info("Change Information",
2618 		    &res->LINK4res_u.resok4.cinfo);
2619 	}
2620 }
2621 
2622 static void
sumres_lock(char * buf,size_t buflen,void * obj)2623 sumres_lock(char *buf, size_t buflen, void *obj)
2624 {
2625 	char *bp;
2626 	LOCK4res *res = (LOCK4res *)obj;
2627 
2628 	strncpy(buf, status_name(res->status), buflen);
2629 	if (res->status == NFS4_OK) {
2630 		bp = buf + strlen(buf);
2631 		snprintf(bp, buflen - (bp - buf), " %s",
2632 		    sum_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid));
2633 	}
2634 	if (res->status == NFS4ERR_DENIED) {
2635 		bp = buf + strlen(buf);
2636 		snprintf(bp, buflen - (bp - buf), " %s",
2637 		    sum_lock_denied(&res->LOCK4res_u.denied));
2638 	}
2639 }
2640 
2641 static void
dtlres_lock(void * obj)2642 dtlres_lock(void *obj)
2643 {
2644 	LOCK4res *res = (LOCK4res *)obj;
2645 
2646 	dtl_nfsstat4(obj);
2647 	if (res->status == NFS4_OK) {
2648 		detail_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid);
2649 	}
2650 	if (res->status == NFS4ERR_DENIED) {
2651 		detail_lock_denied(&res->LOCK4res_u.denied);
2652 	}
2653 }
2654 
2655 static void
sumres_lockt(char * buf,size_t buflen,void * obj)2656 sumres_lockt(char *buf, size_t buflen, void *obj)
2657 {
2658 	char *bp;
2659 	LOCKT4res *res = (LOCKT4res *)obj;
2660 
2661 	strcpy(buf, status_name(res->status));
2662 	if (res->status == NFS4ERR_DENIED) {
2663 		bp = buf + strlen(buf);
2664 		snprintf(bp, buflen - (bp - buf), " %s",
2665 		    sum_lock_denied(&res->LOCKT4res_u.denied));
2666 	}
2667 }
2668 
2669 static void
dtlres_lockt(void * obj)2670 dtlres_lockt(void *obj)
2671 {
2672 	LOCKT4res *res = (LOCKT4res *)obj;
2673 
2674 	dtl_nfsstat4(obj);
2675 	if (res->status == NFS4ERR_DENIED) {
2676 		detail_lock_denied(&res->LOCKT4res_u.denied);
2677 	}
2678 }
2679 
2680 static void
sumres_locku(char * buf,size_t buflen,void * obj)2681 sumres_locku(char *buf, size_t buflen, void *obj)
2682 {
2683 	char *bp;
2684 	LOCKU4res *res = (LOCKU4res *)obj;
2685 
2686 	strncpy(buf, status_name(res->status), buflen);
2687 	bp = buf + strlen(buf);
2688 	if (res->status == NFS4_OK)
2689 		snprintf(bp, buflen - (bp - buf), " %s",
2690 		    sum_lock_stateid(&res->LOCKU4res_u.lock_stateid));
2691 }
2692 
2693 static void
dtlres_locku(void * obj)2694 dtlres_locku(void *obj)
2695 {
2696 	LOCKU4res *res = (LOCKU4res *)obj;
2697 
2698 	dtl_nfsstat4(obj);
2699 	if (res->status == NFS4_OK)
2700 		detail_lock_stateid(&res->LOCKU4res_u.lock_stateid);
2701 }
2702 
2703 static void
sumres_open(char * buf,size_t buflen,void * obj)2704 sumres_open(char *buf, size_t buflen, void *obj)
2705 {
2706 	char *bp = buf;
2707 	OPEN4res *res = (OPEN4res *)obj;
2708 	uint_t rflags;
2709 	int len, blen = buflen;
2710 
2711 	strncpy(bp, status_name(res->status), blen);
2712 
2713 	if (res->status == NFS4_OK) {
2714 		bp += (len = strlen(bp));
2715 		blen -= len;
2716 
2717 		snprintf(bp, blen, " %s",
2718 		    sum_stateid(&res->OPEN4res_u.resok4.stateid));
2719 		bp += (len = strlen(bp));
2720 		blen -= len;
2721 
2722 		if ((rflags = res->OPEN4res_u.resok4.rflags) != 0) {
2723 			snprintf(bp, blen, "%s", sum_open_rflags(rflags));
2724 			bp += (len = strlen(bp));
2725 			blen -= len;
2726 		}
2727 
2728 		sum_delegation(bp, blen, &res->OPEN4res_u.resok4.delegation);
2729 	}
2730 }
2731 
2732 static void
dtlres_open(void * obj)2733 dtlres_open(void *obj)
2734 {
2735 	OPEN4res *res = (OPEN4res *)obj;
2736 
2737 	dtl_nfsstat4(obj);
2738 	if (res->status == NFS4_OK) {
2739 		detail_stateid(&res->OPEN4res_u.resok4.stateid);
2740 		dtl_change_info("Change Information",
2741 		    &res->OPEN4res_u.resok4.cinfo);
2742 		sprintf(get_line(0, 0), "Flags = 0x%x (%s)",
2743 		    res->OPEN4res_u.resok4.rflags,
2744 		    detail_open_rflags(res->OPEN4res_u.resok4.rflags));
2745 		detail_attr_bitmap("", &res->OPEN4res_u.resok4.attrset,
2746 		    NULL);
2747 		detail_delegation(&res->OPEN4res_u.resok4.delegation);
2748 	}
2749 }
2750 
2751 static void
sumres_open_confirm(char * buf,size_t buflen,void * obj)2752 sumres_open_confirm(char *buf, size_t buflen, void *obj)
2753 {
2754 	char *bp;
2755 	OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj;
2756 
2757 	strncpy(buf, status_name(res->status), buflen);
2758 	if (res->status == NFS4_OK) {
2759 		bp = buf + strlen(buf);
2760 		snprintf(bp, buflen - (bp - buf), " %s",
2761 		    sum_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
2762 		    open_stateid));
2763 	}
2764 }
2765 
2766 static void
dtlres_open_confirm(void * obj)2767 dtlres_open_confirm(void *obj)
2768 {
2769 	OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj;
2770 
2771 	dtl_nfsstat4(obj);
2772 	if (res->status == NFS4_OK) {
2773 		detail_open_stateid(&res->OPEN_CONFIRM4res_u.resok4.
2774 		    open_stateid);
2775 	}
2776 }
2777 
2778 static void
sumres_open_downgrd(char * buf,size_t buflen,void * obj)2779 sumres_open_downgrd(char *buf, size_t buflen, void *obj)
2780 {
2781 	char *bp;
2782 	OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj;
2783 
2784 	strncpy(buf, status_name(res->status), buflen);
2785 	if (res->status == NFS4_OK) {
2786 		bp = buf + strlen(buf);
2787 		snprintf(bp, buflen - (bp - buf), " %s",
2788 		    sum_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
2789 		    open_stateid));
2790 	}
2791 }
2792 
2793 static void
dtlres_open_downgrd(void * obj)2794 dtlres_open_downgrd(void *obj)
2795 {
2796 	OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj;
2797 
2798 	dtl_nfsstat4(obj);
2799 	if (res->status == NFS4_OK) {
2800 		detail_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4.
2801 		    open_stateid);
2802 	}
2803 }
2804 
2805 static void
sumres_read(char * buf,size_t buflen,void * obj)2806 sumres_read(char *buf, size_t buflen, void *obj)
2807 {
2808 	char *bp;
2809 	READ4res *res = (READ4res *)obj;
2810 
2811 	strncpy(buf, status_name(res->status), buflen);
2812 	if (res->status == NFS4_OK) {
2813 		bp = buf + strlen(buf);
2814 		snprintf(bp, buflen - (bp - buf), " (%u bytes) %s",
2815 		    res->READ4res_u.resok4.data.data_len,
2816 		    res->READ4res_u.resok4.eof ? "EOF" : "");
2817 	}
2818 }
2819 
2820 static void
dtlres_read(void * obj)2821 dtlres_read(void *obj)
2822 {
2823 	READ4res *res = (READ4res *)obj;
2824 
2825 	dtl_nfsstat4(obj);
2826 	if (res->status == NFS4_OK) {
2827 		sprintf(get_line(0, 0), "Count = %u bytes read",
2828 		    res->READ4res_u.resok4.data.data_len);
2829 		sprintf(get_line(0, 0), "End of file = %s",
2830 		    res->READ4res_u.resok4.eof ? "TRUE" : "FALSE");
2831 	}
2832 }
2833 
2834 static void
sumres_readdir(char * buf,size_t buflen,void * obj)2835 sumres_readdir(char *buf, size_t buflen, void *obj)
2836 {
2837 	char *bp;
2838 	READDIR4res *res = (READDIR4res *)obj;
2839 	int num_entries = 0;
2840 	entry4 *ep;
2841 
2842 	strncpy(buf, status_name(res->status), buflen);
2843 	if (res->status == NFS4_OK) {
2844 		for (ep = res->READDIR4res_u.resok4.reply.entries;
2845 		    ep != NULL;
2846 		    ep = ep->nextentry)
2847 			num_entries++;
2848 		bp = buf + strlen(buf);
2849 		snprintf(bp, buflen - (bp - buf), " %d entries (%s)",
2850 		    num_entries,
2851 		    res->READDIR4res_u.resok4.reply.eof
2852 		    ? "No more" : "More");
2853 	}
2854 }
2855 
2856 static void
dtlres_readdir(void * obj)2857 dtlres_readdir(void *obj)
2858 {
2859 	READDIR4res *res = (READDIR4res *)obj;
2860 	int num_entries = 0;
2861 	entry4 *ep;
2862 
2863 	dtl_nfsstat4(obj);
2864 	if (res->status == NFS4_OK) {
2865 		for (ep = res->READDIR4res_u.resok4.reply.entries;
2866 		    ep != NULL;
2867 		    ep = ep->nextentry) {
2868 			num_entries++;
2869 			sprintf(get_line(0, 0),
2870 			    "------------------ entry #%d",
2871 			    num_entries);
2872 			sprintf(get_line(0, 0), "Cookie = %llu",
2873 			    ep->cookie);
2874 			sprintf(get_line(0, 0), "Name = %s",
2875 			    component_name(&ep->name));
2876 			detail_fattr4(&ep->attrs);
2877 		}
2878 		if (num_entries == 0)
2879 			sprintf(get_line(0, 0), "(No entries)");
2880 		sprintf(get_line(0, 0), "EOF = %s",
2881 		    res->READDIR4res_u.resok4.reply.eof ? "TRUE" : "FALSE");
2882 		sprintf(get_line(0, 0), "Verifer = %s",
2883 		    tohex(res->READDIR4res_u.resok4.cookieverf,
2884 		    NFS4_VERIFIER_SIZE));
2885 	}
2886 }
2887 
2888 static void
sumres_readlnk(char * buf,size_t buflen,void * obj)2889 sumres_readlnk(char *buf, size_t buflen, void *obj)
2890 {
2891 	char *bp;
2892 	READLINK4res *res = (READLINK4res *)obj;
2893 
2894 	strncpy(buf, status_name(res->status), buflen);
2895 	if (res->status == NFS4_OK) {
2896 		bp = buf + strlen(buf);
2897 		snprintf(bp, buflen - (bp - buf), " %s",
2898 		    linktext_name(&res->READLINK4res_u.resok4.link));
2899 	}
2900 }
2901 
2902 static void
dtlres_readlnk(void * obj)2903 dtlres_readlnk(void *obj)
2904 {
2905 	READLINK4res *res = (READLINK4res *)obj;
2906 
2907 	dtl_nfsstat4(obj);
2908 	if (res->status == NFS4_OK) {
2909 		sprintf(get_line(0, 0), "Link = %s",
2910 		    linktext_name(&res->READLINK4res_u.resok4.link));
2911 	}
2912 }
2913 
2914 static void
dtlres_remove(void * obj)2915 dtlres_remove(void *obj)
2916 {
2917 	REMOVE4res *res = (REMOVE4res *)obj;
2918 
2919 	dtl_nfsstat4(obj);
2920 	if (res->status == NFS4_OK) {
2921 		dtl_change_info("Change Information",
2922 		    &res->REMOVE4res_u.resok4.cinfo);
2923 	}
2924 }
2925 
2926 static void
dtlres_rename(void * obj)2927 dtlres_rename(void *obj)
2928 {
2929 	RENAME4res *res = (RENAME4res *)obj;
2930 
2931 	dtl_nfsstat4(obj);
2932 	if (res->status == NFS4_OK) {
2933 		dtl_change_info("Source Change Information",
2934 		    &res->RENAME4res_u.resok4.source_cinfo);
2935 		dtl_change_info("Target Change Information",
2936 		    &res->RENAME4res_u.resok4.target_cinfo);
2937 	}
2938 }
2939 
2940 static void
sumres_secinfo(char * buf,size_t buflen,void * obj)2941 sumres_secinfo(char *buf, size_t buflen, void *obj)
2942 {
2943 	char *bp;
2944 	SECINFO4res *res = (SECINFO4res *)obj;
2945 
2946 	strncpy(buf, status_name(res->status), buflen);
2947 	bp = buf + strlen(buf);
2948 	if (res->status == NFS4_OK) {
2949 		uint_t numinfo = res->SECINFO4res_u.resok4.SECINFO4resok_len;
2950 		secinfo4 *infop;
2951 
2952 		for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val;
2953 		    numinfo != 0;
2954 		    infop++, numinfo--) {
2955 			snprintf(bp, buflen - (bp - buf), " %s",
2956 			    flavor_name(infop->flavor));
2957 			bp += strlen(bp);
2958 		}
2959 	}
2960 }
2961 
2962 static void
dtlres_secinfo(void * obj)2963 dtlres_secinfo(void *obj)
2964 {
2965 	SECINFO4res *res = (SECINFO4res *)obj;
2966 
2967 	dtl_nfsstat4(obj);
2968 	if (res->status == NFS4_OK) {
2969 		uint_t numinfo =
2970 		    res->SECINFO4res_u.resok4.SECINFO4resok_len;
2971 		secinfo4 *infop;
2972 
2973 		for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val;
2974 		    numinfo != 0;
2975 		    infop++, numinfo--) {
2976 			detail_secinfo4(infop);
2977 		}
2978 	}
2979 }
2980 
2981 static void
sumres_setattr(char * buf,size_t buflen,void * obj)2982 sumres_setattr(char *buf, size_t buflen, void *obj)
2983 {
2984 	SETATTR4res *res = (SETATTR4res *)obj;
2985 	size_t len;
2986 
2987 	(void) snprintf(buf, buflen, "%s ", status_name(res->status));
2988 	len = strlen(buf);
2989 	sum_attr_bitmap(buf + len, buflen - len, &res->attrsset);
2990 }
2991 
2992 static void
dtlres_setattr(void * obj)2993 dtlres_setattr(void *obj)
2994 {
2995 	SETATTR4res *res = (SETATTR4res *)obj;
2996 
2997 	dtl_nfsstat4(obj);
2998 	detail_attr_bitmap("", &res->attrsset, NULL);
2999 }
3000 
3001 static void
sumres_setclid(char * buf,size_t buflen,void * obj)3002 sumres_setclid(char *buf, size_t buflen, void *obj)
3003 {
3004 	char *bp;
3005 	SETCLIENTID4res *res = (SETCLIENTID4res *)obj;
3006 
3007 	strncpy(buf, status_name(res->status), buflen);
3008 	switch (res->status) {
3009 	case NFS_OK:
3010 		bp = buf + strlen(buf);
3011 		snprintf(bp, buflen - (bp - buf), " %s CFV=%s",
3012 		    sum_clientid(res->SETCLIENTID4res_u.resok4.clientid),
3013 		    tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
3014 		    NFS4_VERIFIER_SIZE));
3015 		break;
3016 	case NFS4ERR_CLID_INUSE:
3017 		bp = buf + strlen(buf);
3018 		snprintf(bp, buflen - (bp - buf), " ID=%s Addr=%s",
3019 		    res->SETCLIENTID4res_u.client_using.r_netid,
3020 		    res->SETCLIENTID4res_u.client_using.r_addr);
3021 		break;
3022 	}
3023 }
3024 
3025 static void
dtlres_setclid(void * obj)3026 dtlres_setclid(void *obj)
3027 {
3028 	SETCLIENTID4res *res = (SETCLIENTID4res *)obj;
3029 
3030 	dtl_nfsstat4(obj);
3031 	switch (res->status) {
3032 	case NFS_OK:
3033 		detail_clientid(res->SETCLIENTID4res_u.resok4.clientid);
3034 		sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s",
3035 		    tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm,
3036 		    NFS4_VERIFIER_SIZE));
3037 		break;
3038 	case NFS4ERR_CLID_INUSE:
3039 		sprintf(get_line(0, 0), "Used by Net ID = %s",
3040 		    res->SETCLIENTID4res_u.client_using.r_netid);
3041 		sprintf(get_line(0, 0), "Used by Addr = %s",
3042 		    res->SETCLIENTID4res_u.client_using.r_addr);
3043 		break;
3044 	}
3045 }
3046 
3047 static void
sumres_write(char * buf,size_t buflen,void * obj)3048 sumres_write(char *buf, size_t buflen, void *obj)
3049 {
3050 	char *bp;
3051 	WRITE4res *res = (WRITE4res *)obj;
3052 
3053 	strncpy(buf, status_name(res->status), buflen);
3054 	if (res->status == NFS4_OK) {
3055 		bp = buf + strlen(buf);
3056 		snprintf(bp, buflen - (bp - buf), " %u (%s)",
3057 		    res->WRITE4res_u.resok4.count,
3058 		    stable_how4_name(res->WRITE4res_u.resok4.committed));
3059 	}
3060 }
3061 
3062 static void
dtlres_write(void * obj)3063 dtlres_write(void *obj)
3064 {
3065 	WRITE4res *res = (WRITE4res *)