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