xref: /freebsd/contrib/tcpdump/print-nfs.c (revision a5779b6e02d0404232959eede5a5d3a5c699adaf)
14edb46e9SPaul Traina /*
2699fc314SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20943ee2b1SBill Fenner  *
21943ee2b1SBill Fenner  * $FreeBSD$
224edb46e9SPaul Traina  */
234edb46e9SPaul Traina 
244edb46e9SPaul Traina #ifndef lint
25cc391cceSBruce M Simpson static const char rcsid[] _U_ =
26a5779b6eSRui Paulo     "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.110.2.1 2007-12-22 03:08:45 guy Exp $ (LBL)";
27943ee2b1SBill Fenner #endif
28943ee2b1SBill Fenner 
29943ee2b1SBill Fenner #ifdef HAVE_CONFIG_H
30943ee2b1SBill Fenner #include "config.h"
314edb46e9SPaul Traina #endif
324edb46e9SPaul Traina 
33cc391cceSBruce M Simpson #include <tcpdump-stdinc.h>
344edb46e9SPaul Traina 
352ebf6c05SBill Fenner #include <pcap.h>
364edb46e9SPaul Traina #include <stdio.h>
374edb46e9SPaul Traina #include <string.h>
384edb46e9SPaul Traina 
394edb46e9SPaul Traina #include "interface.h"
404edb46e9SPaul Traina #include "addrtoname.h"
41cc391cceSBruce M Simpson #include "extract.h"
424edb46e9SPaul Traina 
43647f50c3SDoug Rabson #include "nfs.h"
444edb46e9SPaul Traina #include "nfsfh.h"
454edb46e9SPaul Traina 
46943ee2b1SBill Fenner #include "ip.h"
47943ee2b1SBill Fenner #ifdef INET6
48943ee2b1SBill Fenner #include "ip6.h"
49943ee2b1SBill Fenner #endif
50c1ad1296SSam Leffler #include "rpc_auth.h"
51c1ad1296SSam Leffler #include "rpc_msg.h"
52943ee2b1SBill Fenner 
53943ee2b1SBill Fenner static void nfs_printfh(const u_int32_t *, const u_int);
54a5779b6eSRui Paulo static int xid_map_enter(const struct sunrpc_msg *, const u_char *);
55c1ad1296SSam Leffler static int32_t xid_map_find(const struct sunrpc_msg *, const u_char *,
56943ee2b1SBill Fenner 			    u_int32_t *, u_int32_t *);
57c1ad1296SSam Leffler static void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);
58647f50c3SDoug Rabson static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
59943ee2b1SBill Fenner static void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
60943ee2b1SBill Fenner static void print_nfsaddr(const u_char *, const char *, const char *);
612ebf6c05SBill Fenner 
62647f50c3SDoug Rabson /*
63647f50c3SDoug Rabson  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
64647f50c3SDoug Rabson  */
65647f50c3SDoug Rabson u_int32_t nfsv3_procid[NFS_NPROCS] = {
66647f50c3SDoug Rabson 	NFSPROC_NULL,
67647f50c3SDoug Rabson 	NFSPROC_GETATTR,
68647f50c3SDoug Rabson 	NFSPROC_SETATTR,
69647f50c3SDoug Rabson 	NFSPROC_NOOP,
70647f50c3SDoug Rabson 	NFSPROC_LOOKUP,
71647f50c3SDoug Rabson 	NFSPROC_READLINK,
72647f50c3SDoug Rabson 	NFSPROC_READ,
73647f50c3SDoug Rabson 	NFSPROC_NOOP,
74647f50c3SDoug Rabson 	NFSPROC_WRITE,
75647f50c3SDoug Rabson 	NFSPROC_CREATE,
76647f50c3SDoug Rabson 	NFSPROC_REMOVE,
77647f50c3SDoug Rabson 	NFSPROC_RENAME,
78647f50c3SDoug Rabson 	NFSPROC_LINK,
79647f50c3SDoug Rabson 	NFSPROC_SYMLINK,
80647f50c3SDoug Rabson 	NFSPROC_MKDIR,
81647f50c3SDoug Rabson 	NFSPROC_RMDIR,
82647f50c3SDoug Rabson 	NFSPROC_READDIR,
83647f50c3SDoug Rabson 	NFSPROC_FSSTAT,
84647f50c3SDoug Rabson 	NFSPROC_NOOP,
85647f50c3SDoug Rabson 	NFSPROC_NOOP,
86647f50c3SDoug Rabson 	NFSPROC_NOOP,
87647f50c3SDoug Rabson 	NFSPROC_NOOP,
88647f50c3SDoug Rabson 	NFSPROC_NOOP,
89647f50c3SDoug Rabson 	NFSPROC_NOOP,
90647f50c3SDoug Rabson 	NFSPROC_NOOP,
91647f50c3SDoug Rabson 	NFSPROC_NOOP
92647f50c3SDoug Rabson };
93647f50c3SDoug Rabson 
94943ee2b1SBill Fenner /*
95943ee2b1SBill Fenner  * NFS V2 and V3 status values.
96943ee2b1SBill Fenner  *
97943ee2b1SBill Fenner  * Some of these come from the RFCs for NFS V2 and V3, with the message
98943ee2b1SBill Fenner  * strings taken from the FreeBSD C library "errlst.c".
99943ee2b1SBill Fenner  *
100943ee2b1SBill Fenner  * Others are errors that are not in the RFC but that I suspect some
101943ee2b1SBill Fenner  * NFS servers could return; the values are FreeBSD errno values, as
102943ee2b1SBill Fenner  * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
103943ee2b1SBill Fenner  * was primarily BSD-derived.
104943ee2b1SBill Fenner  */
105943ee2b1SBill Fenner static struct tok status2str[] = {
106943ee2b1SBill Fenner 	{ 1,     "Operation not permitted" },	/* EPERM */
107943ee2b1SBill Fenner 	{ 2,     "No such file or directory" },	/* ENOENT */
108943ee2b1SBill Fenner 	{ 5,     "Input/output error" },	/* EIO */
109943ee2b1SBill Fenner 	{ 6,     "Device not configured" },	/* ENXIO */
110943ee2b1SBill Fenner 	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
111943ee2b1SBill Fenner 	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
112943ee2b1SBill Fenner 	{ 13,    "Permission denied" },		/* EACCES */
113943ee2b1SBill Fenner 	{ 17,    "File exists" },		/* EEXIST */
114943ee2b1SBill Fenner 	{ 18,    "Cross-device link" },		/* EXDEV */
115943ee2b1SBill Fenner 	{ 19,    "Operation not supported by device" }, /* ENODEV */
116943ee2b1SBill Fenner 	{ 20,    "Not a directory" },		/* ENOTDIR */
117943ee2b1SBill Fenner 	{ 21,    "Is a directory" },		/* EISDIR */
118943ee2b1SBill Fenner 	{ 22,    "Invalid argument" },		/* EINVAL */
119943ee2b1SBill Fenner 	{ 26,    "Text file busy" },		/* ETXTBSY */
120943ee2b1SBill Fenner 	{ 27,    "File too large" },		/* EFBIG */
121943ee2b1SBill Fenner 	{ 28,    "No space left on device" },	/* ENOSPC */
122943ee2b1SBill Fenner 	{ 30,    "Read-only file system" },	/* EROFS */
123943ee2b1SBill Fenner 	{ 31,    "Too many links" },		/* EMLINK */
124943ee2b1SBill Fenner 	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
125943ee2b1SBill Fenner 	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
126943ee2b1SBill Fenner 	{ 63,    "File name too long" },	/* ENAMETOOLONG */
127943ee2b1SBill Fenner 	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
128943ee2b1SBill Fenner 	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
129943ee2b1SBill Fenner 	{ 70,    "Stale NFS file handle" },	/* ESTALE */
130943ee2b1SBill Fenner 	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
131943ee2b1SBill Fenner 	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
132943ee2b1SBill Fenner 	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
133943ee2b1SBill Fenner 	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
134943ee2b1SBill Fenner 	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
135943ee2b1SBill Fenner 	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
136943ee2b1SBill Fenner 	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
137943ee2b1SBill Fenner 	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
138943ee2b1SBill Fenner 	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
139943ee2b1SBill Fenner 	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
140943ee2b1SBill Fenner 	{ 0,     NULL }
141943ee2b1SBill Fenner };
142943ee2b1SBill Fenner 
143943ee2b1SBill Fenner static struct tok nfsv3_writemodes[] = {
144943ee2b1SBill Fenner 	{ 0,		"unstable" },
145943ee2b1SBill Fenner 	{ 1,		"datasync" },
146943ee2b1SBill Fenner 	{ 2,		"filesync" },
147943ee2b1SBill Fenner 	{ 0,		NULL }
148647f50c3SDoug Rabson };
149647f50c3SDoug Rabson 
150647f50c3SDoug Rabson static struct tok type2str[] = {
151647f50c3SDoug Rabson 	{ NFNON,	"NON" },
152647f50c3SDoug Rabson 	{ NFREG,	"REG" },
153647f50c3SDoug Rabson 	{ NFDIR,	"DIR" },
154647f50c3SDoug Rabson 	{ NFBLK,	"BLK" },
155647f50c3SDoug Rabson 	{ NFCHR,	"CHR" },
156647f50c3SDoug Rabson 	{ NFLNK,	"LNK" },
157647f50c3SDoug Rabson 	{ NFFIFO,	"FIFO" },
158647f50c3SDoug Rabson 	{ 0,		NULL }
159647f50c3SDoug Rabson };
160647f50c3SDoug Rabson 
161943ee2b1SBill Fenner static void
162943ee2b1SBill Fenner print_nfsaddr(const u_char *bp, const char *s, const char *d)
163943ee2b1SBill Fenner {
164943ee2b1SBill Fenner 	struct ip *ip;
165943ee2b1SBill Fenner #ifdef INET6
166943ee2b1SBill Fenner 	struct ip6_hdr *ip6;
167943ee2b1SBill Fenner 	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
168943ee2b1SBill Fenner #else
169943ee2b1SBill Fenner #ifndef INET_ADDRSTRLEN
170943ee2b1SBill Fenner #define INET_ADDRSTRLEN	16
171943ee2b1SBill Fenner #endif
172943ee2b1SBill Fenner 	char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
173943ee2b1SBill Fenner #endif
174943ee2b1SBill Fenner 
175943ee2b1SBill Fenner 	srcaddr[0] = dstaddr[0] = '\0';
176943ee2b1SBill Fenner 	switch (IP_V((struct ip *)bp)) {
177943ee2b1SBill Fenner 	case 4:
178943ee2b1SBill Fenner 		ip = (struct ip *)bp;
179943ee2b1SBill Fenner 		strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
180943ee2b1SBill Fenner 		strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
181943ee2b1SBill Fenner 		break;
182943ee2b1SBill Fenner #ifdef INET6
183943ee2b1SBill Fenner 	case 6:
184943ee2b1SBill Fenner 		ip6 = (struct ip6_hdr *)bp;
185943ee2b1SBill Fenner 		strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
186943ee2b1SBill Fenner 		    sizeof(srcaddr));
187943ee2b1SBill Fenner 		strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
188943ee2b1SBill Fenner 		    sizeof(dstaddr));
189943ee2b1SBill Fenner 		break;
190943ee2b1SBill Fenner #endif
191943ee2b1SBill Fenner 	default:
192943ee2b1SBill Fenner 		strlcpy(srcaddr, "?", sizeof(srcaddr));
193943ee2b1SBill Fenner 		strlcpy(dstaddr, "?", sizeof(dstaddr));
194943ee2b1SBill Fenner 		break;
195943ee2b1SBill Fenner 	}
196943ee2b1SBill Fenner 
197943ee2b1SBill Fenner 	(void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
198943ee2b1SBill Fenner }
199943ee2b1SBill Fenner 
200647f50c3SDoug Rabson static const u_int32_t *
201647f50c3SDoug Rabson parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
202647f50c3SDoug Rabson {
203943ee2b1SBill Fenner 	TCHECK(dp[0]);
204cc391cceSBruce M Simpson 	sa3->sa_modeset = EXTRACT_32BITS(dp);
205cc391cceSBruce M Simpson 	dp++;
206cc391cceSBruce M Simpson 	if (sa3->sa_modeset) {
207943ee2b1SBill Fenner 		TCHECK(dp[0]);
208cc391cceSBruce M Simpson 		sa3->sa_mode = EXTRACT_32BITS(dp);
209cc391cceSBruce M Simpson 		dp++;
210647f50c3SDoug Rabson 	}
211647f50c3SDoug Rabson 
212943ee2b1SBill Fenner 	TCHECK(dp[0]);
213cc391cceSBruce M Simpson 	sa3->sa_uidset = EXTRACT_32BITS(dp);
214cc391cceSBruce M Simpson 	dp++;
215cc391cceSBruce M Simpson 	if (sa3->sa_uidset) {
216943ee2b1SBill Fenner 		TCHECK(dp[0]);
217cc391cceSBruce M Simpson 		sa3->sa_uid = EXTRACT_32BITS(dp);
218cc391cceSBruce M Simpson 		dp++;
219647f50c3SDoug Rabson 	}
220647f50c3SDoug Rabson 
221943ee2b1SBill Fenner 	TCHECK(dp[0]);
222cc391cceSBruce M Simpson 	sa3->sa_gidset = EXTRACT_32BITS(dp);
223cc391cceSBruce M Simpson 	dp++;
224cc391cceSBruce M Simpson 	if (sa3->sa_gidset) {
225943ee2b1SBill Fenner 		TCHECK(dp[0]);
226cc391cceSBruce M Simpson 		sa3->sa_gid = EXTRACT_32BITS(dp);
227cc391cceSBruce M Simpson 		dp++;
228647f50c3SDoug Rabson 	}
229647f50c3SDoug Rabson 
230943ee2b1SBill Fenner 	TCHECK(dp[0]);
231cc391cceSBruce M Simpson 	sa3->sa_sizeset = EXTRACT_32BITS(dp);
232cc391cceSBruce M Simpson 	dp++;
233cc391cceSBruce M Simpson 	if (sa3->sa_sizeset) {
234943ee2b1SBill Fenner 		TCHECK(dp[0]);
235cc391cceSBruce M Simpson 		sa3->sa_size = EXTRACT_32BITS(dp);
236cc391cceSBruce M Simpson 		dp++;
237647f50c3SDoug Rabson 	}
238647f50c3SDoug Rabson 
239943ee2b1SBill Fenner 	TCHECK(dp[0]);
240cc391cceSBruce M Simpson 	sa3->sa_atimetype = EXTRACT_32BITS(dp);
241cc391cceSBruce M Simpson 	dp++;
242cc391cceSBruce M Simpson 	if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
243943ee2b1SBill Fenner 		TCHECK(dp[1]);
244cc391cceSBruce M Simpson 		sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
245cc391cceSBruce M Simpson 		dp++;
246cc391cceSBruce M Simpson 		sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
247cc391cceSBruce M Simpson 		dp++;
248647f50c3SDoug Rabson 	}
249647f50c3SDoug Rabson 
250943ee2b1SBill Fenner 	TCHECK(dp[0]);
251cc391cceSBruce M Simpson 	sa3->sa_mtimetype = EXTRACT_32BITS(dp);
252cc391cceSBruce M Simpson 	dp++;
253cc391cceSBruce M Simpson 	if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
254943ee2b1SBill Fenner 		TCHECK(dp[1]);
255cc391cceSBruce M Simpson 		sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
256cc391cceSBruce M Simpson 		dp++;
257cc391cceSBruce M Simpson 		sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
258cc391cceSBruce M Simpson 		dp++;
259647f50c3SDoug Rabson 	}
260647f50c3SDoug Rabson 
261647f50c3SDoug Rabson 	return dp;
262943ee2b1SBill Fenner trunc:
263943ee2b1SBill Fenner 	return NULL;
264647f50c3SDoug Rabson }
265647f50c3SDoug Rabson 
266943ee2b1SBill Fenner static int nfserr;		/* true if we error rather than trunc */
267943ee2b1SBill Fenner 
268943ee2b1SBill Fenner static void
269647f50c3SDoug Rabson print_sattr3(const struct nfsv3_sattr *sa3, int verbose)
270647f50c3SDoug Rabson {
271647f50c3SDoug Rabson 	if (sa3->sa_modeset)
272647f50c3SDoug Rabson 		printf(" mode %o", sa3->sa_mode);
273647f50c3SDoug Rabson 	if (sa3->sa_uidset)
274647f50c3SDoug Rabson 		printf(" uid %u", sa3->sa_uid);
275647f50c3SDoug Rabson 	if (sa3->sa_gidset)
276647f50c3SDoug Rabson 		printf(" gid %u", sa3->sa_gid);
277647f50c3SDoug Rabson 	if (verbose > 1) {
278647f50c3SDoug Rabson 		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
279647f50c3SDoug Rabson 			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
280647f50c3SDoug Rabson 			       sa3->sa_atime.nfsv3_nsec);
281647f50c3SDoug Rabson 		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
282647f50c3SDoug Rabson 			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
283647f50c3SDoug Rabson 			       sa3->sa_mtime.nfsv3_nsec);
284647f50c3SDoug Rabson 	}
285647f50c3SDoug Rabson }
2864edb46e9SPaul Traina 
2874edb46e9SPaul Traina void
2884edb46e9SPaul Traina nfsreply_print(register const u_char *bp, u_int length,
2894edb46e9SPaul Traina 	       register const u_char *bp2)
2904edb46e9SPaul Traina {
291c1ad1296SSam Leffler 	register const struct sunrpc_msg *rp;
292abf25193SMax Laier 	u_int32_t proc, vers, reply_stat;
293943ee2b1SBill Fenner 	char srcid[20], dstid[20];	/*fits 32bit*/
294abf25193SMax Laier 	enum sunrpc_reject_stat rstat;
295abf25193SMax Laier 	u_int32_t rlow;
296abf25193SMax Laier 	u_int32_t rhigh;
297abf25193SMax Laier 	enum sunrpc_auth_stat rwhy;
2984edb46e9SPaul Traina 
2992ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
300c1ad1296SSam Leffler 	rp = (const struct sunrpc_msg *)bp;
3014edb46e9SPaul Traina 
302a5779b6eSRui Paulo 	TCHECK(rp->rm_xid);
303943ee2b1SBill Fenner 	if (!nflag) {
304943ee2b1SBill Fenner 		strlcpy(srcid, "nfs", sizeof(srcid));
305943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u",
306cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
307943ee2b1SBill Fenner 	} else {
308943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
309943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u",
310cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
311943ee2b1SBill Fenner 	}
312943ee2b1SBill Fenner 	print_nfsaddr(bp2, srcid, dstid);
313a5779b6eSRui Paulo 	TCHECK(rp->rm_reply.rp_stat);
314abf25193SMax Laier 	reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
315abf25193SMax Laier 	switch (reply_stat) {
3164edb46e9SPaul Traina 
317abf25193SMax Laier 	case SUNRPC_MSG_ACCEPTED:
318abf25193SMax Laier 		(void)printf("reply ok %u", length);
319943ee2b1SBill Fenner 		if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
320647f50c3SDoug Rabson 			interp_reply(rp, proc, vers, length);
321abf25193SMax Laier 		break;
322abf25193SMax Laier 
323abf25193SMax Laier 	case SUNRPC_MSG_DENIED:
324abf25193SMax Laier 		(void)printf("reply ERR %u: ", length);
325a5779b6eSRui Paulo 		TCHECK(rp->rm_reply.rp_reject.rj_stat);
326abf25193SMax Laier 		rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
327abf25193SMax Laier 		switch (rstat) {
328abf25193SMax Laier 
329abf25193SMax Laier 		case SUNRPC_RPC_MISMATCH:
330a5779b6eSRui Paulo 			TCHECK(rp->rm_reply.rp_reject.rj_vers.high);
331abf25193SMax Laier 			rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
332abf25193SMax Laier 			rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
333abf25193SMax Laier 			(void)printf("RPC Version mismatch (%u-%u)",
334abf25193SMax Laier 			    rlow, rhigh);
335abf25193SMax Laier 			break;
336abf25193SMax Laier 
337abf25193SMax Laier 		case SUNRPC_AUTH_ERROR:
338a5779b6eSRui Paulo 			TCHECK(rp->rm_reply.rp_reject.rj_why);
339abf25193SMax Laier 			rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
340abf25193SMax Laier 			(void)printf("Auth ");
341abf25193SMax Laier 			switch (rwhy) {
342abf25193SMax Laier 
343abf25193SMax Laier 			case SUNRPC_AUTH_OK:
344abf25193SMax Laier 				(void)printf("OK");
345abf25193SMax Laier 				break;
346abf25193SMax Laier 
347abf25193SMax Laier 			case SUNRPC_AUTH_BADCRED:
348abf25193SMax Laier 				(void)printf("Bogus Credentials (seal broken)");
349abf25193SMax Laier 				break;
350abf25193SMax Laier 
351abf25193SMax Laier 			case SUNRPC_AUTH_REJECTEDCRED:
352abf25193SMax Laier 				(void)printf("Rejected Credentials (client should begin new session)");
353abf25193SMax Laier 				break;
354abf25193SMax Laier 
355abf25193SMax Laier 			case SUNRPC_AUTH_BADVERF:
356abf25193SMax Laier 				(void)printf("Bogus Verifier (seal broken)");
357abf25193SMax Laier 				break;
358abf25193SMax Laier 
359abf25193SMax Laier 			case SUNRPC_AUTH_REJECTEDVERF:
360abf25193SMax Laier 				(void)printf("Verifier expired or was replayed");
361abf25193SMax Laier 				break;
362abf25193SMax Laier 
363abf25193SMax Laier 			case SUNRPC_AUTH_TOOWEAK:
364abf25193SMax Laier 				(void)printf("Credentials are too weak");
365abf25193SMax Laier 				break;
366abf25193SMax Laier 
367abf25193SMax Laier 			case SUNRPC_AUTH_INVALIDRESP:
368abf25193SMax Laier 				(void)printf("Bogus response verifier");
369abf25193SMax Laier 				break;
370abf25193SMax Laier 
371abf25193SMax Laier 			case SUNRPC_AUTH_FAILED:
372abf25193SMax Laier 				(void)printf("Unknown failure");
373abf25193SMax Laier 				break;
374abf25193SMax Laier 
375abf25193SMax Laier 			default:
376abf25193SMax Laier 				(void)printf("Invalid failure code %u",
377abf25193SMax Laier 				    (unsigned int)rwhy);
378abf25193SMax Laier 				break;
379abf25193SMax Laier 			}
380abf25193SMax Laier 			break;
381abf25193SMax Laier 
382abf25193SMax Laier 		default:
383abf25193SMax Laier 			(void)printf("Unknown reason for rejecting rpc message %u",
384abf25193SMax Laier 			    (unsigned int)rstat);
385abf25193SMax Laier 			break;
386abf25193SMax Laier 		}
387abf25193SMax Laier 		break;
388abf25193SMax Laier 
389abf25193SMax Laier 	default:
390abf25193SMax Laier 		(void)printf("reply Unknown rpc response code=%u %u",
391abf25193SMax Laier 		    reply_stat, length);
392abf25193SMax Laier 		break;
393abf25193SMax Laier 	}
394a5779b6eSRui Paulo 	return;
395a5779b6eSRui Paulo 
396a5779b6eSRui Paulo trunc:
397a5779b6eSRui Paulo 	if (!nfserr)
398a5779b6eSRui Paulo 		fputs(" [|nfs]", stdout);
3994edb46e9SPaul Traina }
4004edb46e9SPaul Traina 
4014edb46e9SPaul Traina /*
4024edb46e9SPaul Traina  * Return a pointer to the first file handle in the packet.
403943ee2b1SBill Fenner  * If the packet was truncated, return 0.
4044edb46e9SPaul Traina  */
4054edb46e9SPaul Traina static const u_int32_t *
406c1ad1296SSam Leffler parsereq(register const struct sunrpc_msg *rp, register u_int length)
4074edb46e9SPaul Traina {
4082ebf6c05SBill Fenner 	register const u_int32_t *dp;
4094edb46e9SPaul Traina 	register u_int len;
4104edb46e9SPaul Traina 
4114edb46e9SPaul Traina 	/*
4124edb46e9SPaul Traina 	 * find the start of the req data (if we captured it)
4134edb46e9SPaul Traina 	 */
4142ebf6c05SBill Fenner 	dp = (u_int32_t *)&rp->rm_call.cb_cred;
4152ebf6c05SBill Fenner 	TCHECK(dp[1]);
416cc391cceSBruce M Simpson 	len = EXTRACT_32BITS(&dp[1]);
4172ebf6c05SBill Fenner 	if (len < length) {
4182ebf6c05SBill Fenner 		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
4192ebf6c05SBill Fenner 		TCHECK(dp[1]);
420cc391cceSBruce M Simpson 		len = EXTRACT_32BITS(&dp[1]);
4212ebf6c05SBill Fenner 		if (len < length) {
4222ebf6c05SBill Fenner 			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
4232ebf6c05SBill Fenner 			TCHECK2(dp[0], 0);
4244edb46e9SPaul Traina 			return (dp);
4254edb46e9SPaul Traina 		}
4264edb46e9SPaul Traina 	}
4272ebf6c05SBill Fenner trunc:
4282ebf6c05SBill Fenner 	return (NULL);
4294edb46e9SPaul Traina }
4304edb46e9SPaul Traina 
4314edb46e9SPaul Traina /*
4324edb46e9SPaul Traina  * Print out an NFS file handle and return a pointer to following word.
433943ee2b1SBill Fenner  * If packet was truncated, return 0.
4344edb46e9SPaul Traina  */
4354edb46e9SPaul Traina static const u_int32_t *
436647f50c3SDoug Rabson parsefh(register const u_int32_t *dp, int v3)
4374edb46e9SPaul Traina {
438cc391cceSBruce M Simpson 	u_int len;
439647f50c3SDoug Rabson 
440647f50c3SDoug Rabson 	if (v3) {
4412ebf6c05SBill Fenner 		TCHECK(dp[0]);
442cc391cceSBruce M Simpson 		len = EXTRACT_32BITS(dp) / 4;
443647f50c3SDoug Rabson 		dp++;
444647f50c3SDoug Rabson 	} else
445647f50c3SDoug Rabson 		len = NFSX_V2FH / 4;
446647f50c3SDoug Rabson 
4472ebf6c05SBill Fenner 	if (TTEST2(*dp, len * sizeof(*dp))) {
448647f50c3SDoug Rabson 		nfs_printfh(dp, len);
449647f50c3SDoug Rabson 		return (dp + len);
4504edb46e9SPaul Traina 	}
4512ebf6c05SBill Fenner trunc:
4522ebf6c05SBill Fenner 	return (NULL);
4534edb46e9SPaul Traina }
4544edb46e9SPaul Traina 
4554edb46e9SPaul Traina /*
4564edb46e9SPaul Traina  * Print out a file name and return pointer to 32-bit word past it.
457943ee2b1SBill Fenner  * If packet was truncated, return 0.
4584edb46e9SPaul Traina  */
4594edb46e9SPaul Traina static const u_int32_t *
4604edb46e9SPaul Traina parsefn(register const u_int32_t *dp)
4614edb46e9SPaul Traina {
4624edb46e9SPaul Traina 	register u_int32_t len;
4634edb46e9SPaul Traina 	register const u_char *cp;
4644edb46e9SPaul Traina 
4654edb46e9SPaul Traina 	/* Bail if we don't have the string length */
466943ee2b1SBill Fenner 	TCHECK(*dp);
4674edb46e9SPaul Traina 
4684edb46e9SPaul Traina 	/* Fetch string length; convert to host order */
4694edb46e9SPaul Traina 	len = *dp++;
4704edb46e9SPaul Traina 	NTOHL(len);
4714edb46e9SPaul Traina 
472943ee2b1SBill Fenner 	TCHECK2(*dp, ((len + 3) & ~3));
473943ee2b1SBill Fenner 
4744edb46e9SPaul Traina 	cp = (u_char *)dp;
4754edb46e9SPaul Traina 	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
4764edb46e9SPaul Traina 	dp += ((len + 3) & ~3) / sizeof(*dp);
4772ebf6c05SBill Fenner 	putchar('"');
47829292c17SSam Leffler 	if (fn_printn(cp, len, snapend)) {
47929292c17SSam Leffler 		putchar('"');
48029292c17SSam Leffler 		goto trunc;
48129292c17SSam Leffler 	}
4822ebf6c05SBill Fenner 	putchar('"');
4834edb46e9SPaul Traina 
4844edb46e9SPaul Traina 	return (dp);
485943ee2b1SBill Fenner trunc:
486943ee2b1SBill Fenner 	return NULL;
4874edb46e9SPaul Traina }
4884edb46e9SPaul Traina 
4894edb46e9SPaul Traina /*
4904edb46e9SPaul Traina  * Print out file handle and file name.
4914edb46e9SPaul Traina  * Return pointer to 32-bit word past file name.
492943ee2b1SBill Fenner  * If packet was truncated (or there was some other error), return 0.
4934edb46e9SPaul Traina  */
4944edb46e9SPaul Traina static const u_int32_t *
495647f50c3SDoug Rabson parsefhn(register const u_int32_t *dp, int v3)
4964edb46e9SPaul Traina {
497647f50c3SDoug Rabson 	dp = parsefh(dp, v3);
4982ebf6c05SBill Fenner 	if (dp == NULL)
4992ebf6c05SBill Fenner 		return (NULL);
5004edb46e9SPaul Traina 	putchar(' ');
5014edb46e9SPaul Traina 	return (parsefn(dp));
5024edb46e9SPaul Traina }
5034edb46e9SPaul Traina 
5044edb46e9SPaul Traina void
5054edb46e9SPaul Traina nfsreq_print(register const u_char *bp, u_int length,
5064edb46e9SPaul Traina     register const u_char *bp2)
5074edb46e9SPaul Traina {
508c1ad1296SSam Leffler 	register const struct sunrpc_msg *rp;
5094edb46e9SPaul Traina 	register const u_int32_t *dp;
510943ee2b1SBill Fenner 	nfs_type type;
511943ee2b1SBill Fenner 	int v3;
512943ee2b1SBill Fenner 	u_int32_t proc;
513647f50c3SDoug Rabson 	struct nfsv3_sattr sa3;
514943ee2b1SBill Fenner 	char srcid[20], dstid[20];	/*fits 32bit*/
5154edb46e9SPaul Traina 
5162ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
517c1ad1296SSam Leffler 	rp = (const struct sunrpc_msg *)bp;
518a5779b6eSRui Paulo 
519a5779b6eSRui Paulo 	TCHECK(rp->rm_xid);
520943ee2b1SBill Fenner 	if (!nflag) {
521943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u",
522cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
523943ee2b1SBill Fenner 		strlcpy(dstid, "nfs", sizeof(dstid));
524943ee2b1SBill Fenner 	} else {
525943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u",
526cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
527943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
528943ee2b1SBill Fenner 	}
529943ee2b1SBill Fenner 	print_nfsaddr(bp2, srcid, dstid);
530943ee2b1SBill Fenner 	(void)printf("%d", length);
5314edb46e9SPaul Traina 
532a5779b6eSRui Paulo 	if (!xid_map_enter(rp, bp2))	/* record proc number for later on */
533a5779b6eSRui Paulo 		goto trunc;
5344edb46e9SPaul Traina 
535cc391cceSBruce M Simpson 	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
536cc391cceSBruce M Simpson 	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
537647f50c3SDoug Rabson 
538647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
539647f50c3SDoug Rabson 		proc =  nfsv3_procid[proc];
540647f50c3SDoug Rabson 
541647f50c3SDoug Rabson 	switch (proc) {
5424edb46e9SPaul Traina 	case NFSPROC_NOOP:
5434edb46e9SPaul Traina 		printf(" nop");
5444edb46e9SPaul Traina 		return;
5454edb46e9SPaul Traina 	case NFSPROC_NULL:
5464edb46e9SPaul Traina 		printf(" null");
5474edb46e9SPaul Traina 		return;
5484edb46e9SPaul Traina 
5494edb46e9SPaul Traina 	case NFSPROC_GETATTR:
5504edb46e9SPaul Traina 		printf(" getattr");
551943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
552943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
5534edb46e9SPaul Traina 			return;
5544edb46e9SPaul Traina 		break;
5554edb46e9SPaul Traina 
5564edb46e9SPaul Traina 	case NFSPROC_SETATTR:
5574edb46e9SPaul Traina 		printf(" setattr");
558943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
559943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
5604edb46e9SPaul Traina 			return;
5614edb46e9SPaul Traina 		break;
5624edb46e9SPaul Traina 
5634edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
5644edb46e9SPaul Traina 		printf(" lookup");
565943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
566943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
5674edb46e9SPaul Traina 			return;
5684edb46e9SPaul Traina 		break;
5694edb46e9SPaul Traina 
570647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
571647f50c3SDoug Rabson 		printf(" access");
5722ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5732ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
574943ee2b1SBill Fenner 			TCHECK(dp[0]);
575cc391cceSBruce M Simpson 			printf(" %04x", EXTRACT_32BITS(&dp[0]));
576647f50c3SDoug Rabson 			return;
577647f50c3SDoug Rabson 		}
578647f50c3SDoug Rabson 		break;
579647f50c3SDoug Rabson 
5804edb46e9SPaul Traina 	case NFSPROC_READLINK:
5814edb46e9SPaul Traina 		printf(" readlink");
582943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
583943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
5844edb46e9SPaul Traina 			return;
5854edb46e9SPaul Traina 		break;
5864edb46e9SPaul Traina 
5874edb46e9SPaul Traina 	case NFSPROC_READ:
5884edb46e9SPaul Traina 		printf(" read");
5892ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5902ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
591647f50c3SDoug Rabson 			if (v3) {
592943ee2b1SBill Fenner 				TCHECK(dp[2]);
593c1ad1296SSam Leffler 				printf(" %u bytes @ %" PRIu64,
594c1ad1296SSam Leffler 				       EXTRACT_32BITS(&dp[2]),
595c1ad1296SSam Leffler 				       EXTRACT_64BITS(&dp[0]));
596647f50c3SDoug Rabson 			} else {
597943ee2b1SBill Fenner 				TCHECK(dp[1]);
598943ee2b1SBill Fenner 				printf(" %u bytes @ %u",
599cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[1]),
600cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[0]));
601647f50c3SDoug Rabson 			}
6024edb46e9SPaul Traina 			return;
6034edb46e9SPaul Traina 		}
6044edb46e9SPaul Traina 		break;
6054edb46e9SPaul Traina 
6064edb46e9SPaul Traina 	case NFSPROC_WRITE:
6074edb46e9SPaul Traina 		printf(" write");
6082ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6092ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
610647f50c3SDoug Rabson 			if (v3) {
611c1ad1296SSam Leffler 				TCHECK(dp[2]);
612c1ad1296SSam Leffler 				printf(" %u (%u) bytes @ %" PRIu64,
613c1ad1296SSam Leffler 						EXTRACT_32BITS(&dp[4]),
614c1ad1296SSam Leffler 						EXTRACT_32BITS(&dp[2]),
615c1ad1296SSam Leffler 						EXTRACT_64BITS(&dp[0]));
616647f50c3SDoug Rabson 				if (vflag) {
617647f50c3SDoug Rabson 					dp += 3;
618943ee2b1SBill Fenner 					TCHECK(dp[0]);
619647f50c3SDoug Rabson 					printf(" <%s>",
620943ee2b1SBill Fenner 						tok2str(nfsv3_writemodes,
621cc391cceSBruce M Simpson 							NULL, EXTRACT_32BITS(dp)));
622647f50c3SDoug Rabson 				}
623647f50c3SDoug Rabson 			} else {
624943ee2b1SBill Fenner 				TCHECK(dp[3]);
625943ee2b1SBill Fenner 				printf(" %u (%u) bytes @ %u (%u)",
626cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[3]),
627cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[2]),
628cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[1]),
629cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[0]));
630647f50c3SDoug Rabson 			}
6314edb46e9SPaul Traina 			return;
6324edb46e9SPaul Traina 		}
6334edb46e9SPaul Traina 		break;
6344edb46e9SPaul Traina 
6354edb46e9SPaul Traina 	case NFSPROC_CREATE:
6364edb46e9SPaul Traina 		printf(" create");
637943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
638943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
6394edb46e9SPaul Traina 			return;
6404edb46e9SPaul Traina 		break;
6414edb46e9SPaul Traina 
642647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
643647f50c3SDoug Rabson 		printf(" mkdir");
644943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
645647f50c3SDoug Rabson 			return;
646647f50c3SDoug Rabson 		break;
647647f50c3SDoug Rabson 
648647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
649647f50c3SDoug Rabson 		printf(" symlink");
650943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 &&
651943ee2b1SBill Fenner 		    (dp = parsefhn(dp, v3)) != 0) {
652647f50c3SDoug Rabson 			fputs(" ->", stdout);
653943ee2b1SBill Fenner 			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
654647f50c3SDoug Rabson 				break;
655943ee2b1SBill Fenner 			if (parsefn(dp) == 0)
656647f50c3SDoug Rabson 				break;
657647f50c3SDoug Rabson 			if (v3 && vflag)
658647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
659647f50c3SDoug Rabson 			return;
660647f50c3SDoug Rabson 		}
661647f50c3SDoug Rabson 		break;
662647f50c3SDoug Rabson 
663647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
664647f50c3SDoug Rabson 		printf(" mknod");
665943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 &&
666943ee2b1SBill Fenner 		    (dp = parsefhn(dp, v3)) != 0) {
667943ee2b1SBill Fenner 			TCHECK(*dp);
668cc391cceSBruce M Simpson 			type = (nfs_type)EXTRACT_32BITS(dp);
669cc391cceSBruce M Simpson 			dp++;
670943ee2b1SBill Fenner 			if ((dp = parse_sattr3(dp, &sa3)) == 0)
671647f50c3SDoug Rabson 				break;
672647f50c3SDoug Rabson 			printf(" %s", tok2str(type2str, "unk-ft %d", type));
673647f50c3SDoug Rabson 			if (vflag && (type == NFCHR || type == NFBLK)) {
674943ee2b1SBill Fenner 				TCHECK(dp[1]);
675943ee2b1SBill Fenner 				printf(" %u/%u",
676cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[0]),
677cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[1]));
678647f50c3SDoug Rabson 				dp += 2;
679647f50c3SDoug Rabson 			}
680647f50c3SDoug Rabson 			if (vflag)
681647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
682647f50c3SDoug Rabson 			return;
683647f50c3SDoug Rabson 		}
684647f50c3SDoug Rabson 		break;
685647f50c3SDoug Rabson 
6864edb46e9SPaul Traina 	case NFSPROC_REMOVE:
6874edb46e9SPaul Traina 		printf(" remove");
688943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
689943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
690647f50c3SDoug Rabson 			return;
691647f50c3SDoug Rabson 		break;
692647f50c3SDoug Rabson 
693647f50c3SDoug Rabson 	case NFSPROC_RMDIR:
694647f50c3SDoug Rabson 		printf(" rmdir");
695943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
696943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
6974edb46e9SPaul Traina 			return;
6984edb46e9SPaul Traina 		break;
6994edb46e9SPaul Traina 
7004edb46e9SPaul Traina 	case NFSPROC_RENAME:
7014edb46e9SPaul Traina 		printf(" rename");
7022ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7032ebf6c05SBill Fenner 		    (dp = parsefhn(dp, v3)) != NULL) {
7044edb46e9SPaul Traina 			fputs(" ->", stdout);
7052ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
7064edb46e9SPaul Traina 				return;
7074edb46e9SPaul Traina 		}
7084edb46e9SPaul Traina 		break;
7094edb46e9SPaul Traina 
7104edb46e9SPaul Traina 	case NFSPROC_LINK:
7114edb46e9SPaul Traina 		printf(" link");
7122ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7132ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
7144edb46e9SPaul Traina 			fputs(" ->", stdout);
7152ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
7164edb46e9SPaul Traina 				return;
7174edb46e9SPaul Traina 		}
7184edb46e9SPaul Traina 		break;
7194edb46e9SPaul Traina 
7204edb46e9SPaul Traina 	case NFSPROC_READDIR:
7214edb46e9SPaul Traina 		printf(" readdir");
7222ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7232ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
724647f50c3SDoug Rabson 			if (v3) {
725943ee2b1SBill Fenner 				TCHECK(dp[4]);
7264edb46e9SPaul Traina 				/*
727647f50c3SDoug Rabson 				 * We shouldn't really try to interpret the
728647f50c3SDoug Rabson 				 * offset cookie here.
7294edb46e9SPaul Traina 				 */
730c1ad1296SSam Leffler 				printf(" %u bytes @ %" PRId64,
731c1ad1296SSam Leffler 				    EXTRACT_32BITS(&dp[4]),
732c1ad1296SSam Leffler 				    EXTRACT_64BITS(&dp[0]));
733647f50c3SDoug Rabson 				if (vflag)
7342ebf6c05SBill Fenner 					printf(" verf %08x%08x", dp[2],
735647f50c3SDoug Rabson 					       dp[3]);
736647f50c3SDoug Rabson 			} else {
737943ee2b1SBill Fenner 				TCHECK(dp[1]);
738647f50c3SDoug Rabson 				/*
739647f50c3SDoug Rabson 				 * Print the offset as signed, since -1 is
740647f50c3SDoug Rabson 				 * common, but offsets > 2^31 aren't.
741647f50c3SDoug Rabson 				 */
742943ee2b1SBill Fenner 				printf(" %u bytes @ %d",
743cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[1]),
744cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[0]));
745647f50c3SDoug Rabson 			}
7464edb46e9SPaul Traina 			return;
7474edb46e9SPaul Traina 		}
7484edb46e9SPaul Traina 		break;
7494edb46e9SPaul Traina 
750647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
751647f50c3SDoug Rabson 		printf(" readdirplus");
7522ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7532ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
754943ee2b1SBill Fenner 			TCHECK(dp[4]);
755647f50c3SDoug Rabson 			/*
756647f50c3SDoug Rabson 			 * We don't try to interpret the offset
757647f50c3SDoug Rabson 			 * cookie here.
758647f50c3SDoug Rabson 			 */
759c1ad1296SSam Leffler 			printf(" %u bytes @ %" PRId64,
760c1ad1296SSam Leffler 				EXTRACT_32BITS(&dp[4]),
761c1ad1296SSam Leffler 				EXTRACT_64BITS(&dp[0]));
762c1ad1296SSam Leffler 			if (vflag) {
763c1ad1296SSam Leffler 				TCHECK(dp[5]);
764943ee2b1SBill Fenner 				printf(" max %u verf %08x%08x",
765cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
766c1ad1296SSam Leffler 			}
767647f50c3SDoug Rabson 			return;
768647f50c3SDoug Rabson 		}
769647f50c3SDoug Rabson 		break;
770647f50c3SDoug Rabson 
771647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
772647f50c3SDoug Rabson 		printf(" fsstat");
773943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
774943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
7754edb46e9SPaul Traina 			return;
7764edb46e9SPaul Traina 		break;
7774edb46e9SPaul Traina 
778647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
779647f50c3SDoug Rabson 		printf(" fsinfo");
7800e0def19SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7810e0def19SBill Fenner 		    parsefh(dp, v3) != NULL)
7820e0def19SBill Fenner 			return;
783647f50c3SDoug Rabson 		break;
784647f50c3SDoug Rabson 
785647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
786647f50c3SDoug Rabson 		printf(" pathconf");
7870e0def19SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7880e0def19SBill Fenner 		    parsefh(dp, v3) != NULL)
7890e0def19SBill Fenner 			return;
790647f50c3SDoug Rabson 		break;
791647f50c3SDoug Rabson 
792647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
793647f50c3SDoug Rabson 		printf(" commit");
7942ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7952ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
796c1ad1296SSam Leffler 			TCHECK(dp[2]);
797c1ad1296SSam Leffler 			printf(" %u bytes @ %" PRIu64,
798c1ad1296SSam Leffler 				EXTRACT_32BITS(&dp[2]),
799c1ad1296SSam Leffler 				EXTRACT_64BITS(&dp[0]));
800647f50c3SDoug Rabson 			return;
801647f50c3SDoug Rabson 		}
802647f50c3SDoug Rabson 		break;
803647f50c3SDoug Rabson 
8044edb46e9SPaul Traina 	default:
805cc391cceSBruce M Simpson 		printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
8064edb46e9SPaul Traina 		return;
8074edb46e9SPaul Traina 	}
808943ee2b1SBill Fenner 
8094edb46e9SPaul Traina trunc:
8102ebf6c05SBill Fenner 	if (!nfserr)
8114edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
8124edb46e9SPaul Traina }
8134edb46e9SPaul Traina 
8144edb46e9SPaul Traina /*
8154edb46e9SPaul Traina  * Print out an NFS file handle.
8164edb46e9SPaul Traina  * We assume packet was not truncated before the end of the
8174edb46e9SPaul Traina  * file handle pointed to by dp.
8184edb46e9SPaul Traina  *
8194edb46e9SPaul Traina  * Note: new version (using portable file-handle parser) doesn't produce
8204edb46e9SPaul Traina  * generation number.  It probably could be made to do that, with some
8214edb46e9SPaul Traina  * additional hacking on the parser code.
8224edb46e9SPaul Traina  */
8234edb46e9SPaul Traina static void
824943ee2b1SBill Fenner nfs_printfh(register const u_int32_t *dp, const u_int len)
8254edb46e9SPaul Traina {
8264edb46e9SPaul Traina 	my_fsid fsid;
8274edb46e9SPaul Traina 	ino_t ino;
828cc391cceSBruce M Simpson 	const char *sfsname = NULL;
829cc391cceSBruce M Simpson 	char *spacep;
8304edb46e9SPaul Traina 
831cc391cceSBruce M Simpson 	if (uflag) {
832cc391cceSBruce M Simpson 		u_int i;
833cc391cceSBruce M Simpson 		char const *sep = "";
834cc391cceSBruce M Simpson 
835cc391cceSBruce M Simpson 		printf(" fh[");
836cc391cceSBruce M Simpson 		for (i=0; i<len; i++) {
837cc391cceSBruce M Simpson 			(void)printf("%s%x", sep, dp[i]);
838cc391cceSBruce M Simpson 			sep = ":";
839cc391cceSBruce M Simpson 		}
840cc391cceSBruce M Simpson 		printf("]");
841cc391cceSBruce M Simpson 		return;
842cc391cceSBruce M Simpson 	}
843cc391cceSBruce M Simpson 
844cc391cceSBruce M Simpson 	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
8454edb46e9SPaul Traina 
8464edb46e9SPaul Traina 	if (sfsname) {
8474edb46e9SPaul Traina 		/* file system ID is ASCII, not numeric, for this server OS */
848647f50c3SDoug Rabson 		static char temp[NFSX_V3FHMAX+1];
8494edb46e9SPaul Traina 
8504edb46e9SPaul Traina 		/* Make sure string is null-terminated */
851647f50c3SDoug Rabson 		strncpy(temp, sfsname, NFSX_V3FHMAX);
852943ee2b1SBill Fenner 		temp[sizeof(temp) - 1] = '\0';
8534edb46e9SPaul Traina 		/* Remove trailing spaces */
854cc391cceSBruce M Simpson 		spacep = strchr(temp, ' ');
855cc391cceSBruce M Simpson 		if (spacep)
856cc391cceSBruce M Simpson 			*spacep = '\0';
8574edb46e9SPaul Traina 
858943ee2b1SBill Fenner 		(void)printf(" fh %s/", temp);
8592ebf6c05SBill Fenner 	} else {
860943ee2b1SBill Fenner 		(void)printf(" fh %d,%d/",
861943ee2b1SBill Fenner 			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
8624edb46e9SPaul Traina 	}
863943ee2b1SBill Fenner 
864cc391cceSBruce M Simpson 	if(fsid.Fsid_dev.Minor == 257)
865943ee2b1SBill Fenner 		/* Print the undecoded handle */
866943ee2b1SBill Fenner 		(void)printf("%s", fsid.Opaque_Handle);
867943ee2b1SBill Fenner 	else
868943ee2b1SBill Fenner 		(void)printf("%ld", (long) ino);
8694edb46e9SPaul Traina }
8704edb46e9SPaul Traina 
8714edb46e9SPaul Traina /*
8724edb46e9SPaul Traina  * Maintain a small cache of recent client.XID.server/proc pairs, to allow
8734edb46e9SPaul Traina  * us to match up replies with requests and thus to know how to parse
8744edb46e9SPaul Traina  * the reply.
8754edb46e9SPaul Traina  */
8764edb46e9SPaul Traina 
8774edb46e9SPaul Traina struct xid_map_entry {
8784edb46e9SPaul Traina 	u_int32_t	xid;		/* transaction ID (net order) */
879943ee2b1SBill Fenner 	int ipver;			/* IP version (4 or 6) */
880943ee2b1SBill Fenner #ifdef INET6
881943ee2b1SBill Fenner 	struct in6_addr	client;		/* client IP address (net order) */
882943ee2b1SBill Fenner 	struct in6_addr	server;		/* server IP address (net order) */
883943ee2b1SBill Fenner #else
8844edb46e9SPaul Traina 	struct in_addr	client;		/* client IP address (net order) */
8854edb46e9SPaul Traina 	struct in_addr	server;		/* server IP address (net order) */
886943ee2b1SBill Fenner #endif
8874edb46e9SPaul Traina 	u_int32_t	proc;		/* call proc number (host order) */
888647f50c3SDoug Rabson 	u_int32_t	vers;		/* program version (host order) */
8894edb46e9SPaul Traina };
8904edb46e9SPaul Traina 
8914edb46e9SPaul Traina /*
8924edb46e9SPaul Traina  * Map entries are kept in an array that we manage as a ring;
8934edb46e9SPaul Traina  * new entries are always added at the tail of the ring.  Initially,
8944edb46e9SPaul Traina  * all the entries are zero and hence don't match anything.
8954edb46e9SPaul Traina  */
8964edb46e9SPaul Traina 
8974edb46e9SPaul Traina #define	XIDMAPSIZE	64
8984edb46e9SPaul Traina 
8994edb46e9SPaul Traina struct xid_map_entry xid_map[XIDMAPSIZE];
9004edb46e9SPaul Traina 
9014edb46e9SPaul Traina int	xid_map_next = 0;
9024edb46e9SPaul Traina int	xid_map_hint = 0;
9034edb46e9SPaul Traina 
904a5779b6eSRui Paulo static int
905c1ad1296SSam Leffler xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
9064edb46e9SPaul Traina {
907943ee2b1SBill Fenner 	struct ip *ip = NULL;
908943ee2b1SBill Fenner #ifdef INET6
909943ee2b1SBill Fenner 	struct ip6_hdr *ip6 = NULL;
910943ee2b1SBill Fenner #endif
9114edb46e9SPaul Traina 	struct xid_map_entry *xmep;
9124edb46e9SPaul Traina 
913a5779b6eSRui Paulo 	if (!TTEST(rp->rm_call.cb_vers))
914a5779b6eSRui Paulo 		return (0);
915943ee2b1SBill Fenner 	switch (IP_V((struct ip *)bp)) {
916943ee2b1SBill Fenner 	case 4:
917943ee2b1SBill Fenner 		ip = (struct ip *)bp;
918943ee2b1SBill Fenner 		break;
919943ee2b1SBill Fenner #ifdef INET6
920943ee2b1SBill Fenner 	case 6:
921943ee2b1SBill Fenner 		ip6 = (struct ip6_hdr *)bp;
922943ee2b1SBill Fenner 		break;
923943ee2b1SBill Fenner #endif
924943ee2b1SBill Fenner 	default:
925a5779b6eSRui Paulo 		return (1);
926943ee2b1SBill Fenner 	}
927943ee2b1SBill Fenner 
9284edb46e9SPaul Traina 	xmep = &xid_map[xid_map_next];
9294edb46e9SPaul Traina 
9304edb46e9SPaul Traina 	if (++xid_map_next >= XIDMAPSIZE)
9314edb46e9SPaul Traina 		xid_map_next = 0;
9324edb46e9SPaul Traina 
9334edb46e9SPaul Traina 	xmep->xid = rp->rm_xid;
934943ee2b1SBill Fenner 	if (ip) {
935943ee2b1SBill Fenner 		xmep->ipver = 4;
936943ee2b1SBill Fenner 		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
937943ee2b1SBill Fenner 		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
938943ee2b1SBill Fenner 	}
939943ee2b1SBill Fenner #ifdef INET6
940943ee2b1SBill Fenner 	else if (ip6) {
941943ee2b1SBill Fenner 		xmep->ipver = 6;
942943ee2b1SBill Fenner 		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
943943ee2b1SBill Fenner 		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
944943ee2b1SBill Fenner 	}
945943ee2b1SBill Fenner #endif
946cc391cceSBruce M Simpson 	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
947cc391cceSBruce M Simpson 	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
948a5779b6eSRui Paulo 	return (1);
9494edb46e9SPaul Traina }
9504edb46e9SPaul Traina 
9512ebf6c05SBill Fenner /*
9522ebf6c05SBill Fenner  * Returns 0 and puts NFSPROC_xxx in proc return and
9532ebf6c05SBill Fenner  * version in vers return, or returns -1 on failure
9542ebf6c05SBill Fenner  */
955647f50c3SDoug Rabson static int
956c1ad1296SSam Leffler xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
957647f50c3SDoug Rabson 	     u_int32_t *vers)
9584edb46e9SPaul Traina {
9594edb46e9SPaul Traina 	int i;
9604edb46e9SPaul Traina 	struct xid_map_entry *xmep;
9614edb46e9SPaul Traina 	u_int32_t xid = rp->rm_xid;
962943ee2b1SBill Fenner 	struct ip *ip = (struct ip *)bp;
963943ee2b1SBill Fenner #ifdef INET6
964943ee2b1SBill Fenner 	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
965943ee2b1SBill Fenner #endif
966943ee2b1SBill Fenner 	int cmp;
9674edb46e9SPaul Traina 
9684edb46e9SPaul Traina 	/* Start searching from where we last left off */
9694edb46e9SPaul Traina 	i = xid_map_hint;
9704edb46e9SPaul Traina 	do {
9714edb46e9SPaul Traina 		xmep = &xid_map[i];
972943ee2b1SBill Fenner 		cmp = 1;
973943ee2b1SBill Fenner 		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
974943ee2b1SBill Fenner 			goto nextitem;
975943ee2b1SBill Fenner 		switch (xmep->ipver) {
976943ee2b1SBill Fenner 		case 4:
977943ee2b1SBill Fenner 			if (memcmp(&ip->ip_src, &xmep->server,
978943ee2b1SBill Fenner 				   sizeof(ip->ip_src)) != 0 ||
979943ee2b1SBill Fenner 			    memcmp(&ip->ip_dst, &xmep->client,
980943ee2b1SBill Fenner 				   sizeof(ip->ip_dst)) != 0) {
981943ee2b1SBill Fenner 				cmp = 0;
982943ee2b1SBill Fenner 			}
983943ee2b1SBill Fenner 			break;
984943ee2b1SBill Fenner #ifdef INET6
985943ee2b1SBill Fenner 		case 6:
986943ee2b1SBill Fenner 			if (memcmp(&ip6->ip6_src, &xmep->server,
987943ee2b1SBill Fenner 				   sizeof(ip6->ip6_src)) != 0 ||
988943ee2b1SBill Fenner 			    memcmp(&ip6->ip6_dst, &xmep->client,
989943ee2b1SBill Fenner 				   sizeof(ip6->ip6_dst)) != 0) {
990943ee2b1SBill Fenner 				cmp = 0;
991943ee2b1SBill Fenner 			}
992943ee2b1SBill Fenner 			break;
993943ee2b1SBill Fenner #endif
994943ee2b1SBill Fenner 		default:
995943ee2b1SBill Fenner 			cmp = 0;
996943ee2b1SBill Fenner 			break;
997943ee2b1SBill Fenner 		}
998943ee2b1SBill Fenner 		if (cmp) {
9994edb46e9SPaul Traina 			/* match */
10004edb46e9SPaul Traina 			xid_map_hint = i;
1001647f50c3SDoug Rabson 			*proc = xmep->proc;
1002647f50c3SDoug Rabson 			*vers = xmep->vers;
1003647f50c3SDoug Rabson 			return 0;
10044edb46e9SPaul Traina 		}
1005943ee2b1SBill Fenner 	nextitem:
10064edb46e9SPaul Traina 		if (++i >= XIDMAPSIZE)
10074edb46e9SPaul Traina 			i = 0;
10084edb46e9SPaul Traina 	} while (i != xid_map_hint);
10094edb46e9SPaul Traina 
10104edb46e9SPaul Traina 	/* search failed */
1011943ee2b1SBill Fenner 	return (-1);
10124edb46e9SPaul Traina }
10134edb46e9SPaul Traina 
10144edb46e9SPaul Traina /*
10154edb46e9SPaul Traina  * Routines for parsing reply packets
10164edb46e9SPaul Traina  */
10174edb46e9SPaul Traina 
10184edb46e9SPaul Traina /*
10194edb46e9SPaul Traina  * Return a pointer to the beginning of the actual results.
1020943ee2b1SBill Fenner  * If the packet was truncated, return 0.
10214edb46e9SPaul Traina  */
10224edb46e9SPaul Traina static const u_int32_t *
1023c1ad1296SSam Leffler parserep(register const struct sunrpc_msg *rp, register u_int length)
10244edb46e9SPaul Traina {
10254edb46e9SPaul Traina 	register const u_int32_t *dp;
1026943ee2b1SBill Fenner 	u_int len;
1027c1ad1296SSam Leffler 	enum sunrpc_accept_stat astat;
10284edb46e9SPaul Traina 
10294edb46e9SPaul Traina 	/*
10304edb46e9SPaul Traina 	 * Portability note:
10314edb46e9SPaul Traina 	 * Here we find the address of the ar_verf credentials.
10324edb46e9SPaul Traina 	 * Originally, this calculation was
10334edb46e9SPaul Traina 	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
10344edb46e9SPaul Traina 	 * On the wire, the rp_acpt field starts immediately after
10354edb46e9SPaul Traina 	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
10364edb46e9SPaul Traina 	 * "struct accepted_reply") contains a "struct opaque_auth",
10374edb46e9SPaul Traina 	 * whose internal representation contains a pointer, so on a
10384edb46e9SPaul Traina 	 * 64-bit machine the compiler inserts 32 bits of padding
10394edb46e9SPaul Traina 	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
10404edb46e9SPaul Traina 	 * the internal representation to parse the on-the-wire
10414edb46e9SPaul Traina 	 * representation.  Instead, we skip past the rp_stat field,
10424edb46e9SPaul Traina 	 * which is an "enum" and so occupies one 32-bit word.
10434edb46e9SPaul Traina 	 */
10444edb46e9SPaul Traina 	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
1045943ee2b1SBill Fenner 	TCHECK(dp[1]);
1046cc391cceSBruce M Simpson 	len = EXTRACT_32BITS(&dp[1]);
10474edb46e9SPaul Traina 	if (len >= length)
10482ebf6c05SBill Fenner 		return (NULL);
10494edb46e9SPaul Traina 	/*
10504edb46e9SPaul Traina 	 * skip past the ar_verf credentials.
10514edb46e9SPaul Traina 	 */
10524edb46e9SPaul Traina 	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
10532ebf6c05SBill Fenner 	TCHECK2(dp[0], 0);
10544edb46e9SPaul Traina 
10554edb46e9SPaul Traina 	/*
10564edb46e9SPaul Traina 	 * now we can check the ar_stat field
10574edb46e9SPaul Traina 	 */
105829292c17SSam Leffler 	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
10594edb46e9SPaul Traina 	switch (astat) {
10604edb46e9SPaul Traina 
1061c1ad1296SSam Leffler 	case SUNRPC_SUCCESS:
10624edb46e9SPaul Traina 		break;
10634edb46e9SPaul Traina 
1064c1ad1296SSam Leffler 	case SUNRPC_PROG_UNAVAIL:
10654edb46e9SPaul Traina 		printf(" PROG_UNAVAIL");
10662ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10672ebf6c05SBill Fenner 		return (NULL);
10684edb46e9SPaul Traina 
1069c1ad1296SSam Leffler 	case SUNRPC_PROG_MISMATCH:
10704edb46e9SPaul Traina 		printf(" PROG_MISMATCH");
10712ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10722ebf6c05SBill Fenner 		return (NULL);
10734edb46e9SPaul Traina 
1074c1ad1296SSam Leffler 	case SUNRPC_PROC_UNAVAIL:
10754edb46e9SPaul Traina 		printf(" PROC_UNAVAIL");
10762ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10772ebf6c05SBill Fenner 		return (NULL);
10784edb46e9SPaul Traina 
1079c1ad1296SSam Leffler 	case SUNRPC_GARBAGE_ARGS:
10804edb46e9SPaul Traina 		printf(" GARBAGE_ARGS");
10812ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10822ebf6c05SBill Fenner 		return (NULL);
10834edb46e9SPaul Traina 
1084c1ad1296SSam Leffler 	case SUNRPC_SYSTEM_ERR:
10854edb46e9SPaul Traina 		printf(" SYSTEM_ERR");
10862ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10872ebf6c05SBill Fenner 		return (NULL);
10884edb46e9SPaul Traina 
10894edb46e9SPaul Traina 	default:
10904edb46e9SPaul Traina 		printf(" ar_stat %d", astat);
10912ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10922ebf6c05SBill Fenner 		return (NULL);
10934edb46e9SPaul Traina 	}
10944edb46e9SPaul Traina 	/* successful return */
1095943ee2b1SBill Fenner 	TCHECK2(*dp, sizeof(astat));
10964edb46e9SPaul Traina 	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
10972ebf6c05SBill Fenner trunc:
1098943ee2b1SBill Fenner 	return (0);
10994edb46e9SPaul Traina }
11004edb46e9SPaul Traina 
1101647f50c3SDoug Rabson static const u_int32_t *
1102647f50c3SDoug Rabson parsestatus(const u_int32_t *dp, int *er)
1103647f50c3SDoug Rabson {
1104943ee2b1SBill Fenner 	int errnum;
1105647f50c3SDoug Rabson 
11062ebf6c05SBill Fenner 	TCHECK(dp[0]);
1107943ee2b1SBill Fenner 
1108cc391cceSBruce M Simpson 	errnum = EXTRACT_32BITS(&dp[0]);
1109647f50c3SDoug Rabson 	if (er)
11102ebf6c05SBill Fenner 		*er = errnum;
11112ebf6c05SBill Fenner 	if (errnum != 0) {
11122ebf6c05SBill Fenner 		if (!qflag)
1113943ee2b1SBill Fenner 			printf(" ERROR: %s",
1114943ee2b1SBill Fenner 			    tok2str(status2str, "unk %d", errnum));
11152ebf6c05SBill Fenner 		nfserr = 1;
11164edb46e9SPaul Traina 	}
11174edb46e9SPaul Traina 	return (dp + 1);
11182ebf6c05SBill Fenner trunc:
1119943ee2b1SBill Fenner 	return NULL;
11204edb46e9SPaul Traina }
11214edb46e9SPaul Traina 
11224edb46e9SPaul Traina static const u_int32_t *
1123647f50c3SDoug Rabson parsefattr(const u_int32_t *dp, int verbose, int v3)
11244edb46e9SPaul Traina {
1125647f50c3SDoug Rabson 	const struct nfs_fattr *fap;
11264edb46e9SPaul Traina 
1127647f50c3SDoug Rabson 	fap = (const struct nfs_fattr *)dp;
1128685b49deSBill Fenner 	TCHECK(fap->fa_gid);
11294edb46e9SPaul Traina 	if (verbose) {
1130943ee2b1SBill Fenner 		printf(" %s %o ids %d/%d",
1131943ee2b1SBill Fenner 		    tok2str(type2str, "unk-ft %d ",
1132cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_type)),
1133cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_mode),
1134cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_uid),
1135cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_gid));
1136647f50c3SDoug Rabson 		if (v3) {
1137685b49deSBill Fenner 			TCHECK(fap->fa3_size);
1138c1ad1296SSam Leffler 			printf(" sz %" PRIu64,
1139c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
1140685b49deSBill Fenner 		} else {
1141685b49deSBill Fenner 			TCHECK(fap->fa2_size);
1142cc391cceSBruce M Simpson 			printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
1143647f50c3SDoug Rabson 		}
11444edb46e9SPaul Traina 	}
11454edb46e9SPaul Traina 	/* print lots more stuff */
11464edb46e9SPaul Traina 	if (verbose > 1) {
1147647f50c3SDoug Rabson 		if (v3) {
1148685b49deSBill Fenner 			TCHECK(fap->fa3_ctime);
1149943ee2b1SBill Fenner 			printf(" nlink %d rdev %d/%d",
1150cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa_nlink),
1151cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1152cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1153c1ad1296SSam Leffler 			printf(" fsid %" PRIx64,
1154c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1155c1ad1296SSam Leffler 			printf(" fileid %" PRIx64,
1156c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1157943ee2b1SBill Fenner 			printf(" a/m/ctime %u.%06u",
1158cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1159cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1160943ee2b1SBill Fenner 			printf(" %u.%06u",
1161cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1162cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1163943ee2b1SBill Fenner 			printf(" %u.%06u",
1164cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1165cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
1166647f50c3SDoug Rabson 		} else {
1167685b49deSBill Fenner 			TCHECK(fap->fa2_ctime);
1168943ee2b1SBill Fenner 			printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1169cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa_nlink),
1170cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_rdev),
1171cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_fsid),
1172cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_fileid));
1173943ee2b1SBill Fenner 			printf(" %u.%06u",
1174cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1175cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1176943ee2b1SBill Fenner 			printf(" %u.%06u",
1177cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1178cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1179943ee2b1SBill Fenner 			printf(" %u.%06u",
1180cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1181cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
11824edb46e9SPaul Traina 		}
1183647f50c3SDoug Rabson 	}
1184647f50c3SDoug Rabson 	return ((const u_int32_t *)((unsigned char *)dp +
1185647f50c3SDoug Rabson 		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
1186685b49deSBill Fenner trunc:
1187685b49deSBill Fenner 	return (NULL);
11884edb46e9SPaul Traina }
11894edb46e9SPaul Traina 
11904edb46e9SPaul Traina static int
1191647f50c3SDoug Rabson parseattrstat(const u_int32_t *dp, int verbose, int v3)
11924edb46e9SPaul Traina {
1193647f50c3SDoug Rabson 	int er;
1194647f50c3SDoug Rabson 
1195647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
11960e0def19SBill Fenner 	if (dp == NULL)
11974edb46e9SPaul Traina 		return (0);
11980e0def19SBill Fenner 	if (er)
11990e0def19SBill Fenner 		return (1);
12004edb46e9SPaul Traina 
12012ebf6c05SBill Fenner 	return (parsefattr(dp, verbose, v3) != NULL);
12024edb46e9SPaul Traina }
12034edb46e9SPaul Traina 
12044edb46e9SPaul Traina static int
12054edb46e9SPaul Traina parsediropres(const u_int32_t *dp)
12064edb46e9SPaul Traina {
1207647f50c3SDoug Rabson 	int er;
1208647f50c3SDoug Rabson 
12090e0def19SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1210647f50c3SDoug Rabson 		return (0);
12110e0def19SBill Fenner 	if (er)
12120e0def19SBill Fenner 		return (1);
1213647f50c3SDoug Rabson 
1214647f50c3SDoug Rabson 	dp = parsefh(dp, 0);
12154edb46e9SPaul Traina 	if (dp == NULL)
12164edb46e9SPaul Traina 		return (0);
12174edb46e9SPaul Traina 
1218647f50c3SDoug Rabson 	return (parsefattr(dp, vflag, 0) != NULL);
12194edb46e9SPaul Traina }
12204edb46e9SPaul Traina 
12214edb46e9SPaul Traina static int
1222647f50c3SDoug Rabson parselinkres(const u_int32_t *dp, int v3)
12234edb46e9SPaul Traina {
1224647f50c3SDoug Rabson 	int er;
12254edb46e9SPaul Traina 
1226647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
12270e0def19SBill Fenner 	if (dp == NULL)
1228647f50c3SDoug Rabson 		return(0);
12290e0def19SBill Fenner 	if (er)
12300e0def19SBill Fenner 		return(1);
1231943ee2b1SBill Fenner 	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
1232647f50c3SDoug Rabson 		return (0);
12334edb46e9SPaul Traina 	putchar(' ');
12344edb46e9SPaul Traina 	return (parsefn(dp) != NULL);
12354edb46e9SPaul Traina }
12364edb46e9SPaul Traina 
12374edb46e9SPaul Traina static int
1238647f50c3SDoug Rabson parsestatfs(const u_int32_t *dp, int v3)
12394edb46e9SPaul Traina {
1240647f50c3SDoug Rabson 	const struct nfs_statfs *sfsp;
1241647f50c3SDoug Rabson 	int er;
12424edb46e9SPaul Traina 
1243647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
12440e0def19SBill Fenner 	if (dp == NULL)
12454edb46e9SPaul Traina 		return (0);
12460e0def19SBill Fenner 	if (!v3 && er)
12470e0def19SBill Fenner 		return (1);
12484edb46e9SPaul Traina 
1249647f50c3SDoug Rabson 	if (qflag)
1250647f50c3SDoug Rabson 		return(1);
1251647f50c3SDoug Rabson 
1252647f50c3SDoug Rabson 	if (v3) {
1253647f50c3SDoug Rabson 		if (vflag)
1254647f50c3SDoug Rabson 			printf(" POST:");
1255943ee2b1SBill Fenner 		if (!(dp = parse_post_op_attr(dp, vflag)))
1256647f50c3SDoug Rabson 			return (0);
1257647f50c3SDoug Rabson 	}
1258647f50c3SDoug Rabson 
12590e0def19SBill Fenner 	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1260647f50c3SDoug Rabson 
1261647f50c3SDoug Rabson 	sfsp = (const struct nfs_statfs *)dp;
1262647f50c3SDoug Rabson 
1263647f50c3SDoug Rabson 	if (v3) {
1264c1ad1296SSam Leffler 		printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1265c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1266c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1267c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
1268647f50c3SDoug Rabson 		if (vflag) {
1269c1ad1296SSam Leffler 			printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1270c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1271c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1272c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1273cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&sfsp->sf_invarsec));
1274647f50c3SDoug Rabson 		}
1275647f50c3SDoug Rabson 	} else {
1276943ee2b1SBill Fenner 		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1277cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_tsize),
1278cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bsize),
1279cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_blocks),
1280cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bfree),
1281cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bavail));
12824edb46e9SPaul Traina 	}
12834edb46e9SPaul Traina 
12844edb46e9SPaul Traina 	return (1);
1285685b49deSBill Fenner trunc:
1286685b49deSBill Fenner 	return (0);
12874edb46e9SPaul Traina }
12884edb46e9SPaul Traina 
12894edb46e9SPaul Traina static int
12904edb46e9SPaul Traina parserddires(const u_int32_t *dp)
12914edb46e9SPaul Traina {
1292647f50c3SDoug Rabson 	int er;
1293647f50c3SDoug Rabson 
1294647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
12950e0def19SBill Fenner 	if (dp == NULL)
12964edb46e9SPaul Traina 		return (0);
12970e0def19SBill Fenner 	if (er)
12980e0def19SBill Fenner 		return (1);
1299647f50c3SDoug Rabson 	if (qflag)
1300647f50c3SDoug Rabson 		return (1);
1301647f50c3SDoug Rabson 
1302685b49deSBill Fenner 	TCHECK(dp[2]);
1303943ee2b1SBill Fenner 	printf(" offset %x size %d ",
1304cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
13054edb46e9SPaul Traina 	if (dp[2] != 0)
13064edb46e9SPaul Traina 		printf(" eof");
13074edb46e9SPaul Traina 
13084edb46e9SPaul Traina 	return (1);
1309685b49deSBill Fenner trunc:
1310685b49deSBill Fenner 	return (0);
1311647f50c3SDoug Rabson }
1312647f50c3SDoug Rabson 
1313647f50c3SDoug Rabson static const u_int32_t *
1314647f50c3SDoug Rabson parse_wcc_attr(const u_int32_t *dp)
1315647f50c3SDoug Rabson {
1316c1ad1296SSam Leffler 	printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
1317943ee2b1SBill Fenner 	printf(" mtime %u.%06u ctime %u.%06u",
1318cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1319cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
1320647f50c3SDoug Rabson 	return (dp + 6);
1321647f50c3SDoug Rabson }
1322647f50c3SDoug Rabson 
1323647f50c3SDoug Rabson /*
1324647f50c3SDoug Rabson  * Pre operation attributes. Print only if vflag > 1.
1325647f50c3SDoug Rabson  */
1326647f50c3SDoug Rabson static const u_int32_t *
1327647f50c3SDoug Rabson parse_pre_op_attr(const u_int32_t *dp, int verbose)
1328647f50c3SDoug Rabson {
1329685b49deSBill Fenner 	TCHECK(dp[0]);
1330cc391cceSBruce M Simpson 	if (!EXTRACT_32BITS(&dp[0]))
1331647f50c3SDoug Rabson 		return (dp + 1);
1332647f50c3SDoug Rabson 	dp++;
13330e0def19SBill Fenner 	TCHECK2(*dp, 24);
1334647f50c3SDoug Rabson 	if (verbose > 1) {
1335647f50c3SDoug Rabson 		return parse_wcc_attr(dp);
1336647f50c3SDoug Rabson 	} else {
1337647f50c3SDoug Rabson 		/* If not verbose enough, just skip over wcc_attr */
1338647f50c3SDoug Rabson 		return (dp + 6);
1339647f50c3SDoug Rabson 	}
1340685b49deSBill Fenner trunc:
1341685b49deSBill Fenner 	return (NULL);
1342647f50c3SDoug Rabson }
1343647f50c3SDoug Rabson 
1344647f50c3SDoug Rabson /*
1345647f50c3SDoug Rabson  * Post operation attributes are printed if vflag >= 1
1346647f50c3SDoug Rabson  */
1347647f50c3SDoug Rabson static const u_int32_t *
1348647f50c3SDoug Rabson parse_post_op_attr(const u_int32_t *dp, int verbose)
1349647f50c3SDoug Rabson {
1350685b49deSBill Fenner 	TCHECK(dp[0]);
1351cc391cceSBruce M Simpson 	if (!EXTRACT_32BITS(&dp[0]))
1352647f50c3SDoug Rabson 		return (dp + 1);
1353647f50c3SDoug Rabson 	dp++;
1354647f50c3SDoug Rabson 	if (verbose) {
1355647f50c3SDoug Rabson 		return parsefattr(dp, verbose, 1);
1356647f50c3SDoug Rabson 	} else
1357647f50c3SDoug Rabson 		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1358685b49deSBill Fenner trunc:
1359685b49deSBill Fenner 	return (NULL);
1360647f50c3SDoug Rabson }
1361647f50c3SDoug Rabson 
1362647f50c3SDoug Rabson static const u_int32_t *
1363647f50c3SDoug Rabson parse_wcc_data(const u_int32_t *dp, int verbose)
1364647f50c3SDoug Rabson {
1365647f50c3SDoug Rabson 	if (verbose > 1)
1366647f50c3SDoug Rabson 		printf(" PRE:");
1367943ee2b1SBill Fenner 	if (!(dp = parse_pre_op_attr(dp, verbose)))
1368943ee2b1SBill Fenner 		return (0);
1369647f50c3SDoug Rabson 
1370647f50c3SDoug Rabson 	if (verbose)
1371647f50c3SDoug Rabson 		printf(" POST:");
1372647f50c3SDoug Rabson 	return parse_post_op_attr(dp, verbose);
1373647f50c3SDoug Rabson }
1374647f50c3SDoug Rabson 
1375647f50c3SDoug Rabson static const u_int32_t *
1376647f50c3SDoug Rabson parsecreateopres(const u_int32_t *dp, int verbose)
1377647f50c3SDoug Rabson {
1378647f50c3SDoug Rabson 	int er;
1379647f50c3SDoug Rabson 
1380943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1381943ee2b1SBill Fenner 		return (0);
1382647f50c3SDoug Rabson 	if (er)
1383647f50c3SDoug Rabson 		dp = parse_wcc_data(dp, verbose);
1384647f50c3SDoug Rabson 	else {
1385685b49deSBill Fenner 		TCHECK(dp[0]);
1386cc391cceSBruce M Simpson 		if (!EXTRACT_32BITS(&dp[0]))
1387647f50c3SDoug Rabson 			return (dp + 1);
1388647f50c3SDoug Rabson 		dp++;
1389943ee2b1SBill Fenner 		if (!(dp = parsefh(dp, 1)))
1390943ee2b1SBill Fenner 			return (0);
1391647f50c3SDoug Rabson 		if (verbose) {
1392943ee2b1SBill Fenner 			if (!(dp = parse_post_op_attr(dp, verbose)))
1393943ee2b1SBill Fenner 				return (0);
1394647f50c3SDoug Rabson 			if (vflag > 1) {
1395647f50c3SDoug Rabson 				printf(" dir attr:");
1396647f50c3SDoug Rabson 				dp = parse_wcc_data(dp, verbose);
1397647f50c3SDoug Rabson 			}
1398647f50c3SDoug Rabson 		}
1399647f50c3SDoug Rabson 	}
1400647f50c3SDoug Rabson 	return (dp);
1401685b49deSBill Fenner trunc:
1402685b49deSBill Fenner 	return (NULL);
1403647f50c3SDoug Rabson }
1404647f50c3SDoug Rabson 
1405647f50c3SDoug Rabson static int
1406647f50c3SDoug Rabson parsewccres(const u_int32_t *dp, int verbose)
1407647f50c3SDoug Rabson {
1408647f50c3SDoug Rabson 	int er;
1409647f50c3SDoug Rabson 
1410943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1411647f50c3SDoug Rabson 		return (0);
1412943ee2b1SBill Fenner 	return parse_wcc_data(dp, verbose) != 0;
1413647f50c3SDoug Rabson }
1414647f50c3SDoug Rabson 
1415647f50c3SDoug Rabson static const u_int32_t *
1416647f50c3SDoug Rabson parsev3rddirres(const u_int32_t *dp, int verbose)
1417647f50c3SDoug Rabson {
1418647f50c3SDoug Rabson 	int er;
1419647f50c3SDoug Rabson 
1420943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1421943ee2b1SBill Fenner 		return (0);
1422647f50c3SDoug Rabson 	if (vflag)
1423647f50c3SDoug Rabson 		printf(" POST:");
1424943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, verbose)))
1425943ee2b1SBill Fenner 		return (0);
1426647f50c3SDoug Rabson 	if (er)
1427647f50c3SDoug Rabson 		return dp;
1428647f50c3SDoug Rabson 	if (vflag) {
1429685b49deSBill Fenner 		TCHECK(dp[1]);
14302ebf6c05SBill Fenner 		printf(" verf %08x%08x", dp[0], dp[1]);
1431647f50c3SDoug Rabson 		dp += 2;
1432647f50c3SDoug Rabson 	}
1433647f50c3SDoug Rabson 	return dp;
1434685b49deSBill Fenner trunc:
1435685b49deSBill Fenner 	return (NULL);
1436647f50c3SDoug Rabson }
1437647f50c3SDoug Rabson 
1438647f50c3SDoug Rabson static int
1439647f50c3SDoug Rabson parsefsinfo(const u_int32_t *dp)
1440647f50c3SDoug Rabson {
1441647f50c3SDoug Rabson 	struct nfsv3_fsinfo *sfp;
1442647f50c3SDoug Rabson 	int er;
1443647f50c3SDoug Rabson 
1444943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1445647f50c3SDoug Rabson 		return (0);
1446647f50c3SDoug Rabson 	if (vflag)
1447647f50c3SDoug Rabson 		printf(" POST:");
1448943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, vflag)))
1449647f50c3SDoug Rabson 		return (0);
1450647f50c3SDoug Rabson 	if (er)
1451647f50c3SDoug Rabson 		return (1);
1452647f50c3SDoug Rabson 
1453647f50c3SDoug Rabson 	sfp = (struct nfsv3_fsinfo *)dp;
1454685b49deSBill Fenner 	TCHECK(*sfp);
1455943ee2b1SBill Fenner 	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1456cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_rtmax),
1457cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_rtpref),
1458cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_wtmax),
1459cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_wtpref),
1460cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_dtpref));
1461647f50c3SDoug Rabson 	if (vflag) {
1462c1ad1296SSam Leffler 		printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1463cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_rtmult),
1464c1ad1296SSam Leffler 		       EXTRACT_32BITS(&sfp->fs_wtmult),
1465c1ad1296SSam Leffler 		       EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
1466943ee2b1SBill Fenner 		printf(" delta %u.%06u ",
1467cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1468cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
1469647f50c3SDoug Rabson 	}
1470943ee2b1SBill Fenner 	return (1);
14710e0def19SBill Fenner trunc:
14720e0def19SBill Fenner 	return (0);
1473647f50c3SDoug Rabson }
1474647f50c3SDoug Rabson 
1475647f50c3SDoug Rabson static int
1476647f50c3SDoug Rabson parsepathconf(const u_int32_t *dp)
1477647f50c3SDoug Rabson {
1478647f50c3SDoug Rabson 	int er;
1479647f50c3SDoug Rabson 	struct nfsv3_pathconf *spp;
1480647f50c3SDoug Rabson 
1481943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1482647f50c3SDoug Rabson 		return (0);
1483647f50c3SDoug Rabson 	if (vflag)
1484647f50c3SDoug Rabson 		printf(" POST:");
1485943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, vflag)))
1486647f50c3SDoug Rabson 		return (0);
1487647f50c3SDoug Rabson 	if (er)
1488647f50c3SDoug Rabson 		return (1);
1489647f50c3SDoug Rabson 
1490647f50c3SDoug Rabson 	spp = (struct nfsv3_pathconf *)dp;
1491685b49deSBill Fenner 	TCHECK(*spp);
1492647f50c3SDoug Rabson 
1493943ee2b1SBill Fenner 	printf(" linkmax %u namemax %u %s %s %s %s",
1494cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_linkmax),
1495cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_namemax),
1496cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1497cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1498cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1499cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1500943ee2b1SBill Fenner 	return (1);
15010e0def19SBill Fenner trunc:
15020e0def19SBill Fenner 	return (0);
15034edb46e9SPaul Traina }
15044edb46e9SPaul Traina 
15054edb46e9SPaul Traina static void
1506c1ad1296SSam Leffler interp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
15074edb46e9SPaul Traina {
15084edb46e9SPaul Traina 	register const u_int32_t *dp;
1509647f50c3SDoug Rabson 	register int v3;
1510647f50c3SDoug Rabson 	int er;
1511647f50c3SDoug Rabson 
1512647f50c3SDoug Rabson 	v3 = (vers == NFS_VER3);
1513647f50c3SDoug Rabson 
1514647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
1515647f50c3SDoug Rabson 		proc = nfsv3_procid[proc];
15164edb46e9SPaul Traina 
15174edb46e9SPaul Traina 	switch (proc) {
15184edb46e9SPaul Traina 
15194edb46e9SPaul Traina 	case NFSPROC_NOOP:
15204edb46e9SPaul Traina 		printf(" nop");
15214edb46e9SPaul Traina 		return;
1522647f50c3SDoug Rabson 
15234edb46e9SPaul Traina 	case NFSPROC_NULL:
15244edb46e9SPaul Traina 		printf(" null");
15254edb46e9SPaul Traina 		return;
15264edb46e9SPaul Traina 
15274edb46e9SPaul Traina 	case NFSPROC_GETATTR:
15284edb46e9SPaul Traina 		printf(" getattr");
15294edb46e9SPaul Traina 		dp = parserep(rp, length);
15302ebf6c05SBill Fenner 		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
15314edb46e9SPaul Traina 			return;
15324edb46e9SPaul Traina 		break;
15334edb46e9SPaul Traina 
15344edb46e9SPaul Traina 	case NFSPROC_SETATTR:
15354edb46e9SPaul Traina 		printf(" setattr");
1536943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
15374edb46e9SPaul Traina 			return;
1538647f50c3SDoug Rabson 		if (v3) {
1539943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
1540647f50c3SDoug Rabson 				return;
1541647f50c3SDoug Rabson 		} else {
1542647f50c3SDoug Rabson 			if (parseattrstat(dp, !qflag, 0) != 0)
1543647f50c3SDoug Rabson 				return;
1544647f50c3SDoug Rabson 		}
15454edb46e9SPaul Traina 		break;
15464edb46e9SPaul Traina 
15474edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
15484edb46e9SPaul Traina 		printf(" lookup");
1549943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
15504edb46e9SPaul Traina 			break;
1551647f50c3SDoug Rabson 		if (v3) {
1552943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1553647f50c3SDoug Rabson 				break;
1554647f50c3SDoug Rabson 			if (er) {
1555647f50c3SDoug Rabson 				if (vflag > 1) {
1556647f50c3SDoug Rabson 					printf(" post dattr:");
1557647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1558647f50c3SDoug Rabson 				}
1559647f50c3SDoug Rabson 			} else {
1560943ee2b1SBill Fenner 				if (!(dp = parsefh(dp, v3)))
1561647f50c3SDoug Rabson 					break;
1562943ee2b1SBill Fenner 				if ((dp = parse_post_op_attr(dp, vflag)) &&
1563943ee2b1SBill Fenner 				    vflag > 1) {
1564647f50c3SDoug Rabson 					printf(" post dattr:");
1565647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1566647f50c3SDoug Rabson 				}
1567647f50c3SDoug Rabson 			}
1568943ee2b1SBill Fenner 			if (dp)
1569647f50c3SDoug Rabson 				return;
1570647f50c3SDoug Rabson 		} else {
1571647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1572647f50c3SDoug Rabson 				return;
1573647f50c3SDoug Rabson 		}
1574647f50c3SDoug Rabson 		break;
1575647f50c3SDoug Rabson 
1576647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
1577647f50c3SDoug Rabson 		printf(" access");
1578a1c2090eSBill Fenner 		if (!(dp = parserep(rp, length)))
1579a1c2090eSBill Fenner 			break;
1580943ee2b1SBill Fenner 		if (!(dp = parsestatus(dp, &er)))
1581647f50c3SDoug Rabson 			break;
1582647f50c3SDoug Rabson 		if (vflag)
1583647f50c3SDoug Rabson 			printf(" attr:");
1584943ee2b1SBill Fenner 		if (!(dp = parse_post_op_attr(dp, vflag)))
1585647f50c3SDoug Rabson 			break;
1586647f50c3SDoug Rabson 		if (!er)
1587cc391cceSBruce M Simpson 			printf(" c %04x", EXTRACT_32BITS(&dp[0]));
1588647f50c3SDoug Rabson 		return;
15894edb46e9SPaul Traina 
15904edb46e9SPaul Traina 	case NFSPROC_READLINK:
15914edb46e9SPaul Traina 		printf(" readlink");
15924edb46e9SPaul Traina 		dp = parserep(rp, length);
15932ebf6c05SBill Fenner 		if (dp != NULL && parselinkres(dp, v3) != 0)
15944edb46e9SPaul Traina 			return;
15954edb46e9SPaul Traina 		break;
15964edb46e9SPaul Traina 
15974edb46e9SPaul Traina 	case NFSPROC_READ:
15984edb46e9SPaul Traina 		printf(" read");
1599943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1600647f50c3SDoug Rabson 			break;
1601647f50c3SDoug Rabson 		if (v3) {
1602943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1603647f50c3SDoug Rabson 				break;
1604943ee2b1SBill Fenner 			if (!(dp = parse_post_op_attr(dp, vflag)))
1605647f50c3SDoug Rabson 				break;
1606647f50c3SDoug Rabson 			if (er)
16074edb46e9SPaul Traina 				return;
1608647f50c3SDoug Rabson 			if (vflag) {
1609943ee2b1SBill Fenner 				TCHECK(dp[1]);
1610cc391cceSBruce M Simpson 				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1611cc391cceSBruce M Simpson 				if (EXTRACT_32BITS(&dp[1]))
1612647f50c3SDoug Rabson 					printf(" EOF");
1613647f50c3SDoug Rabson 			}
1614647f50c3SDoug Rabson 			return;
1615647f50c3SDoug Rabson 		} else {
1616647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, 0) != 0)
1617647f50c3SDoug Rabson 				return;
1618647f50c3SDoug Rabson 		}
16194edb46e9SPaul Traina 		break;
16204edb46e9SPaul Traina 
16214edb46e9SPaul Traina 	case NFSPROC_WRITE:
16224edb46e9SPaul Traina 		printf(" write");
1623943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1624647f50c3SDoug Rabson 			break;
1625647f50c3SDoug Rabson 		if (v3) {
1626943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1627647f50c3SDoug Rabson 				break;
1628943ee2b1SBill Fenner 			if (!(dp = parse_wcc_data(dp, vflag)))
1629647f50c3SDoug Rabson 				break;
1630647f50c3SDoug Rabson 			if (er)
16314edb46e9SPaul Traina 				return;
1632647f50c3SDoug Rabson 			if (vflag) {
1633943ee2b1SBill Fenner 				TCHECK(dp[0]);
1634cc391cceSBruce M Simpson 				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1635647f50c3SDoug Rabson 				if (vflag > 1) {
1636943ee2b1SBill Fenner 					TCHECK(dp[1]);
1637647f50c3SDoug Rabson 					printf(" <%s>",
1638943ee2b1SBill Fenner 						tok2str(nfsv3_writemodes,
1639cc391cceSBruce M Simpson 							NULL, EXTRACT_32BITS(&dp[1])));
1640647f50c3SDoug Rabson 				}
1641647f50c3SDoug Rabson 				return;
1642647f50c3SDoug Rabson 			}
1643647f50c3SDoug Rabson 		} else {
1644647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, v3) != 0)
1645647f50c3SDoug Rabson 				return;
1646647f50c3SDoug Rabson 		}
16474edb46e9SPaul Traina 		break;
16484edb46e9SPaul Traina 
16494edb46e9SPaul Traina 	case NFSPROC_CREATE:
16504edb46e9SPaul Traina 		printf(" create");
1651943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1652647f50c3SDoug Rabson 			break;
1653647f50c3SDoug Rabson 		if (v3) {
1654943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1655647f50c3SDoug Rabson 				return;
1656647f50c3SDoug Rabson 		} else {
1657647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1658647f50c3SDoug Rabson 				return;
1659647f50c3SDoug Rabson 		}
1660647f50c3SDoug Rabson 		break;
1661647f50c3SDoug Rabson 
1662647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
1663647f50c3SDoug Rabson 		printf(" mkdir");
1664943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1665647f50c3SDoug Rabson 			break;
1666647f50c3SDoug Rabson 		if (v3) {
1667943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1668647f50c3SDoug Rabson 				return;
1669647f50c3SDoug Rabson 		} else {
1670647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1671647f50c3SDoug Rabson 				return;
1672647f50c3SDoug Rabson 		}
1673647f50c3SDoug Rabson 		break;
1674647f50c3SDoug Rabson 
1675647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
1676647f50c3SDoug Rabson 		printf(" symlink");
1677943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1678647f50c3SDoug Rabson 			break;
1679647f50c3SDoug Rabson 		if (v3) {
1680943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1681647f50c3SDoug Rabson 				return;
1682647f50c3SDoug Rabson 		} else {
1683943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1684647f50c3SDoug Rabson 				return;
1685647f50c3SDoug Rabson 		}
1686647f50c3SDoug Rabson 		break;
1687647f50c3SDoug Rabson 
1688647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
1689647f50c3SDoug Rabson 		printf(" mknod");
1690943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1691647f50c3SDoug Rabson 			break;
1692943ee2b1SBill Fenner 		if (parsecreateopres(dp, vflag) != 0)
16934edb46e9SPaul Traina 			return;
16944edb46e9SPaul Traina 		break;
16954edb46e9SPaul Traina 
16964edb46e9SPaul Traina 	case NFSPROC_REMOVE:
16974edb46e9SPaul Traina 		printf(" remove");
1698943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
16994edb46e9SPaul Traina 			break;
1700647f50c3SDoug Rabson 		if (v3) {
1701943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
17024edb46e9SPaul Traina 				return;
1703647f50c3SDoug Rabson 		} else {
1704943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
17054edb46e9SPaul Traina 				return;
1706647f50c3SDoug Rabson 		}
17074edb46e9SPaul Traina 		break;
17084edb46e9SPaul Traina 
17094edb46e9SPaul Traina 	case NFSPROC_RMDIR:
17104edb46e9SPaul Traina 		printf(" rmdir");
1711943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1712647f50c3SDoug Rabson 			break;
1713647f50c3SDoug Rabson 		if (v3) {
1714943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
17154edb46e9SPaul Traina 				return;
1716647f50c3SDoug Rabson 		} else {
1717943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1718647f50c3SDoug Rabson 				return;
1719647f50c3SDoug Rabson 		}
1720647f50c3SDoug Rabson 		break;
1721647f50c3SDoug Rabson 
1722647f50c3SDoug Rabson 	case NFSPROC_RENAME:
1723647f50c3SDoug Rabson 		printf(" rename");
1724943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1725647f50c3SDoug Rabson 			break;
1726647f50c3SDoug Rabson 		if (v3) {
1727943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1728647f50c3SDoug Rabson 				break;
1729647f50c3SDoug Rabson 			if (vflag) {
1730647f50c3SDoug Rabson 				printf(" from:");
1731943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1732647f50c3SDoug Rabson 					break;
1733647f50c3SDoug Rabson 				printf(" to:");
1734943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1735647f50c3SDoug Rabson 					break;
1736647f50c3SDoug Rabson 			}
1737647f50c3SDoug Rabson 			return;
1738647f50c3SDoug Rabson 		} else {
1739943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1740647f50c3SDoug Rabson 				return;
1741647f50c3SDoug Rabson 		}
1742647f50c3SDoug Rabson 		break;
1743647f50c3SDoug Rabson 
1744647f50c3SDoug Rabson 	case NFSPROC_LINK:
1745647f50c3SDoug Rabson 		printf(" link");
1746943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1747647f50c3SDoug Rabson 			break;
1748647f50c3SDoug Rabson 		if (v3) {
1749943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1750647f50c3SDoug Rabson 				break;
1751647f50c3SDoug Rabson 			if (vflag) {
1752647f50c3SDoug Rabson 				printf(" file POST:");
1753943ee2b1SBill Fenner 				if (!(dp = parse_post_op_attr(dp, vflag)))
1754647f50c3SDoug Rabson 					break;
1755647f50c3SDoug Rabson 				printf(" dir:");
1756943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1757647f50c3SDoug Rabson 					break;
1758647f50c3SDoug Rabson 				return;
1759647f50c3SDoug Rabson 			}
1760647f50c3SDoug Rabson 		} else {
1761943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1762647f50c3SDoug Rabson 				return;
1763647f50c3SDoug Rabson 		}
17644edb46e9SPaul Traina 		break;
17654edb46e9SPaul Traina 
17664edb46e9SPaul Traina 	case NFSPROC_READDIR:
17674edb46e9SPaul Traina 		printf(" readdir");
1768943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1769647f50c3SDoug Rabson 			break;
1770647f50c3SDoug Rabson 		if (v3) {
1771943ee2b1SBill Fenner 			if (parsev3rddirres(dp, vflag))
1772647f50c3SDoug Rabson 				return;
1773647f50c3SDoug Rabson 		} else {
1774647f50c3SDoug Rabson 			if (parserddires(dp) != 0)
1775647f50c3SDoug Rabson 				return;
1776647f50c3SDoug Rabson 		}
1777647f50c3SDoug Rabson 		break;
1778647f50c3SDoug Rabson 
1779647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
1780647f50c3SDoug Rabson 		printf(" readdirplus");
1781943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1782647f50c3SDoug Rabson 			break;
1783943ee2b1SBill Fenner 		if (parsev3rddirres(dp, vflag))
17844edb46e9SPaul Traina 			return;
17854edb46e9SPaul Traina 		break;
17864edb46e9SPaul Traina 
1787647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
1788647f50c3SDoug Rabson 		printf(" fsstat");
17894edb46e9SPaul Traina 		dp = parserep(rp, length);
1790943ee2b1SBill Fenner 		if (dp != NULL && parsestatfs(dp, v3) != 0)
1791647f50c3SDoug Rabson 			return;
1792647f50c3SDoug Rabson 		break;
1793647f50c3SDoug Rabson 
1794647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
1795647f50c3SDoug Rabson 		printf(" fsinfo");
1796647f50c3SDoug Rabson 		dp = parserep(rp, length);
1797943ee2b1SBill Fenner 		if (dp != NULL && parsefsinfo(dp) != 0)
1798647f50c3SDoug Rabson 			return;
1799647f50c3SDoug Rabson 		break;
1800647f50c3SDoug Rabson 
1801647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
1802647f50c3SDoug Rabson 		printf(" pathconf");
1803647f50c3SDoug Rabson 		dp = parserep(rp, length);
18042ebf6c05SBill Fenner 		if (dp != NULL && parsepathconf(dp) != 0)
1805647f50c3SDoug Rabson 			return;
1806647f50c3SDoug Rabson 		break;
1807647f50c3SDoug Rabson 
1808647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
1809647f50c3SDoug Rabson 		printf(" commit");
1810647f50c3SDoug Rabson 		dp = parserep(rp, length);
18112ebf6c05SBill Fenner 		if (dp != NULL && parsewccres(dp, vflag) != 0)
18124edb46e9SPaul Traina 			return;
18134edb46e9SPaul Traina 		break;
18144edb46e9SPaul Traina 
18154edb46e9SPaul Traina 	default:
18162ebf6c05SBill Fenner 		printf(" proc-%u", proc);
18174edb46e9SPaul Traina 		return;
18184edb46e9SPaul Traina 	}
1819647f50c3SDoug Rabson trunc:
18202ebf6c05SBill Fenner 	if (!nfserr)
18214edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
18224edb46e9SPaul Traina }
1823