xref: /freebsd/contrib/tcpdump/print-nfs.c (revision 29292c17af721e5dabd42f1d89b511352ed945ed)
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_ =
2629292c17SSam Leffler     "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.106.2.2 2005/05/06 07:57:18 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);
54c1ad1296SSam Leffler static void 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;
292647f50c3SDoug Rabson 	u_int32_t proc, vers;
293943ee2b1SBill Fenner 	char srcid[20], dstid[20];	/*fits 32bit*/
2944edb46e9SPaul Traina 
2952ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
296c1ad1296SSam Leffler 	rp = (const struct sunrpc_msg *)bp;
2974edb46e9SPaul Traina 
298943ee2b1SBill Fenner 	if (!nflag) {
299943ee2b1SBill Fenner 		strlcpy(srcid, "nfs", sizeof(srcid));
300943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u",
301cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
302943ee2b1SBill Fenner 	} else {
303943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
304943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u",
305cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
306943ee2b1SBill Fenner 	}
307943ee2b1SBill Fenner 	print_nfsaddr(bp2, srcid, dstid);
308943ee2b1SBill Fenner 	(void)printf("reply %s %d",
309c1ad1296SSam Leffler 	     EXTRACT_32BITS(&rp->rm_reply.rp_stat) == SUNRPC_MSG_ACCEPTED?
3104edb46e9SPaul Traina 		     "ok":"ERR",
3114edb46e9SPaul Traina 	     length);
3124edb46e9SPaul Traina 
313943ee2b1SBill Fenner 	if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
314647f50c3SDoug Rabson 		interp_reply(rp, proc, vers, length);
3154edb46e9SPaul Traina }
3164edb46e9SPaul Traina 
3174edb46e9SPaul Traina /*
3184edb46e9SPaul Traina  * Return a pointer to the first file handle in the packet.
319943ee2b1SBill Fenner  * If the packet was truncated, return 0.
3204edb46e9SPaul Traina  */
3214edb46e9SPaul Traina static const u_int32_t *
322c1ad1296SSam Leffler parsereq(register const struct sunrpc_msg *rp, register u_int length)
3234edb46e9SPaul Traina {
3242ebf6c05SBill Fenner 	register const u_int32_t *dp;
3254edb46e9SPaul Traina 	register u_int len;
3264edb46e9SPaul Traina 
3274edb46e9SPaul Traina 	/*
3284edb46e9SPaul Traina 	 * find the start of the req data (if we captured it)
3294edb46e9SPaul Traina 	 */
3302ebf6c05SBill Fenner 	dp = (u_int32_t *)&rp->rm_call.cb_cred;
3312ebf6c05SBill Fenner 	TCHECK(dp[1]);
332cc391cceSBruce M Simpson 	len = EXTRACT_32BITS(&dp[1]);
3332ebf6c05SBill Fenner 	if (len < length) {
3342ebf6c05SBill Fenner 		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
3352ebf6c05SBill Fenner 		TCHECK(dp[1]);
336cc391cceSBruce M Simpson 		len = EXTRACT_32BITS(&dp[1]);
3372ebf6c05SBill Fenner 		if (len < length) {
3382ebf6c05SBill Fenner 			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
3392ebf6c05SBill Fenner 			TCHECK2(dp[0], 0);
3404edb46e9SPaul Traina 			return (dp);
3414edb46e9SPaul Traina 		}
3424edb46e9SPaul Traina 	}
3432ebf6c05SBill Fenner trunc:
3442ebf6c05SBill Fenner 	return (NULL);
3454edb46e9SPaul Traina }
3464edb46e9SPaul Traina 
3474edb46e9SPaul Traina /*
3484edb46e9SPaul Traina  * Print out an NFS file handle and return a pointer to following word.
349943ee2b1SBill Fenner  * If packet was truncated, return 0.
3504edb46e9SPaul Traina  */
3514edb46e9SPaul Traina static const u_int32_t *
352647f50c3SDoug Rabson parsefh(register const u_int32_t *dp, int v3)
3534edb46e9SPaul Traina {
354cc391cceSBruce M Simpson 	u_int len;
355647f50c3SDoug Rabson 
356647f50c3SDoug Rabson 	if (v3) {
3572ebf6c05SBill Fenner 		TCHECK(dp[0]);
358cc391cceSBruce M Simpson 		len = EXTRACT_32BITS(dp) / 4;
359647f50c3SDoug Rabson 		dp++;
360647f50c3SDoug Rabson 	} else
361647f50c3SDoug Rabson 		len = NFSX_V2FH / 4;
362647f50c3SDoug Rabson 
3632ebf6c05SBill Fenner 	if (TTEST2(*dp, len * sizeof(*dp))) {
364647f50c3SDoug Rabson 		nfs_printfh(dp, len);
365647f50c3SDoug Rabson 		return (dp + len);
3664edb46e9SPaul Traina 	}
3672ebf6c05SBill Fenner trunc:
3682ebf6c05SBill Fenner 	return (NULL);
3694edb46e9SPaul Traina }
3704edb46e9SPaul Traina 
3714edb46e9SPaul Traina /*
3724edb46e9SPaul Traina  * Print out a file name and return pointer to 32-bit word past it.
373943ee2b1SBill Fenner  * If packet was truncated, return 0.
3744edb46e9SPaul Traina  */
3754edb46e9SPaul Traina static const u_int32_t *
3764edb46e9SPaul Traina parsefn(register const u_int32_t *dp)
3774edb46e9SPaul Traina {
3784edb46e9SPaul Traina 	register u_int32_t len;
3794edb46e9SPaul Traina 	register const u_char *cp;
3804edb46e9SPaul Traina 
3814edb46e9SPaul Traina 	/* Bail if we don't have the string length */
382943ee2b1SBill Fenner 	TCHECK(*dp);
3834edb46e9SPaul Traina 
3844edb46e9SPaul Traina 	/* Fetch string length; convert to host order */
3854edb46e9SPaul Traina 	len = *dp++;
3864edb46e9SPaul Traina 	NTOHL(len);
3874edb46e9SPaul Traina 
388943ee2b1SBill Fenner 	TCHECK2(*dp, ((len + 3) & ~3));
389943ee2b1SBill Fenner 
3904edb46e9SPaul Traina 	cp = (u_char *)dp;
3914edb46e9SPaul Traina 	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
3924edb46e9SPaul Traina 	dp += ((len + 3) & ~3) / sizeof(*dp);
3932ebf6c05SBill Fenner 	putchar('"');
39429292c17SSam Leffler 	if (fn_printn(cp, len, snapend)) {
39529292c17SSam Leffler 		putchar('"');
39629292c17SSam Leffler 		goto trunc;
39729292c17SSam Leffler 	}
3982ebf6c05SBill Fenner 	putchar('"');
3994edb46e9SPaul Traina 
4004edb46e9SPaul Traina 	return (dp);
401943ee2b1SBill Fenner trunc:
402943ee2b1SBill Fenner 	return NULL;
4034edb46e9SPaul Traina }
4044edb46e9SPaul Traina 
4054edb46e9SPaul Traina /*
4064edb46e9SPaul Traina  * Print out file handle and file name.
4074edb46e9SPaul Traina  * Return pointer to 32-bit word past file name.
408943ee2b1SBill Fenner  * If packet was truncated (or there was some other error), return 0.
4094edb46e9SPaul Traina  */
4104edb46e9SPaul Traina static const u_int32_t *
411647f50c3SDoug Rabson parsefhn(register const u_int32_t *dp, int v3)
4124edb46e9SPaul Traina {
413647f50c3SDoug Rabson 	dp = parsefh(dp, v3);
4142ebf6c05SBill Fenner 	if (dp == NULL)
4152ebf6c05SBill Fenner 		return (NULL);
4164edb46e9SPaul Traina 	putchar(' ');
4174edb46e9SPaul Traina 	return (parsefn(dp));
4184edb46e9SPaul Traina }
4194edb46e9SPaul Traina 
4204edb46e9SPaul Traina void
4214edb46e9SPaul Traina nfsreq_print(register const u_char *bp, u_int length,
4224edb46e9SPaul Traina     register const u_char *bp2)
4234edb46e9SPaul Traina {
424c1ad1296SSam Leffler 	register const struct sunrpc_msg *rp;
4254edb46e9SPaul Traina 	register const u_int32_t *dp;
426943ee2b1SBill Fenner 	nfs_type type;
427943ee2b1SBill Fenner 	int v3;
428943ee2b1SBill Fenner 	u_int32_t proc;
429647f50c3SDoug Rabson 	struct nfsv3_sattr sa3;
430943ee2b1SBill Fenner 	char srcid[20], dstid[20];	/*fits 32bit*/
4314edb46e9SPaul Traina 
4322ebf6c05SBill Fenner 	nfserr = 0;		/* assume no error */
433c1ad1296SSam Leffler 	rp = (const struct sunrpc_msg *)bp;
434943ee2b1SBill Fenner 	if (!nflag) {
435943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u",
436cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
437943ee2b1SBill Fenner 		strlcpy(dstid, "nfs", sizeof(dstid));
438943ee2b1SBill Fenner 	} else {
439943ee2b1SBill Fenner 		snprintf(srcid, sizeof(srcid), "%u",
440cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&rp->rm_xid));
441943ee2b1SBill Fenner 		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
442943ee2b1SBill Fenner 	}
443943ee2b1SBill Fenner 	print_nfsaddr(bp2, srcid, dstid);
444943ee2b1SBill Fenner 	(void)printf("%d", length);
4454edb46e9SPaul Traina 
446943ee2b1SBill Fenner 	xid_map_enter(rp, bp2);	/* record proc number for later on */
4474edb46e9SPaul Traina 
448cc391cceSBruce M Simpson 	v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
449cc391cceSBruce M Simpson 	proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
450647f50c3SDoug Rabson 
451647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
452647f50c3SDoug Rabson 		proc =  nfsv3_procid[proc];
453647f50c3SDoug Rabson 
454647f50c3SDoug Rabson 	switch (proc) {
4554edb46e9SPaul Traina 	case NFSPROC_NOOP:
4564edb46e9SPaul Traina 		printf(" nop");
4574edb46e9SPaul Traina 		return;
4584edb46e9SPaul Traina 	case NFSPROC_NULL:
4594edb46e9SPaul Traina 		printf(" null");
4604edb46e9SPaul Traina 		return;
4614edb46e9SPaul Traina 
4624edb46e9SPaul Traina 	case NFSPROC_GETATTR:
4634edb46e9SPaul Traina 		printf(" getattr");
464943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
465943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
4664edb46e9SPaul Traina 			return;
4674edb46e9SPaul Traina 		break;
4684edb46e9SPaul Traina 
4694edb46e9SPaul Traina 	case NFSPROC_SETATTR:
4704edb46e9SPaul Traina 		printf(" setattr");
471943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
472943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
4734edb46e9SPaul Traina 			return;
4744edb46e9SPaul Traina 		break;
4754edb46e9SPaul Traina 
4764edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
4774edb46e9SPaul Traina 		printf(" lookup");
478943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
479943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
4804edb46e9SPaul Traina 			return;
4814edb46e9SPaul Traina 		break;
4824edb46e9SPaul Traina 
483647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
484647f50c3SDoug Rabson 		printf(" access");
4852ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
4862ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
487943ee2b1SBill Fenner 			TCHECK(dp[0]);
488cc391cceSBruce M Simpson 			printf(" %04x", EXTRACT_32BITS(&dp[0]));
489647f50c3SDoug Rabson 			return;
490647f50c3SDoug Rabson 		}
491647f50c3SDoug Rabson 		break;
492647f50c3SDoug Rabson 
4934edb46e9SPaul Traina 	case NFSPROC_READLINK:
4944edb46e9SPaul Traina 		printf(" readlink");
495943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
496943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
4974edb46e9SPaul Traina 			return;
4984edb46e9SPaul Traina 		break;
4994edb46e9SPaul Traina 
5004edb46e9SPaul Traina 	case NFSPROC_READ:
5014edb46e9SPaul Traina 		printf(" read");
5022ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5032ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
504647f50c3SDoug Rabson 			if (v3) {
505943ee2b1SBill Fenner 				TCHECK(dp[2]);
506c1ad1296SSam Leffler 				printf(" %u bytes @ %" PRIu64,
507c1ad1296SSam Leffler 				       EXTRACT_32BITS(&dp[2]),
508c1ad1296SSam Leffler 				       EXTRACT_64BITS(&dp[0]));
509647f50c3SDoug Rabson 			} else {
510943ee2b1SBill Fenner 				TCHECK(dp[1]);
511943ee2b1SBill Fenner 				printf(" %u bytes @ %u",
512cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[1]),
513cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[0]));
514647f50c3SDoug Rabson 			}
5154edb46e9SPaul Traina 			return;
5164edb46e9SPaul Traina 		}
5174edb46e9SPaul Traina 		break;
5184edb46e9SPaul Traina 
5194edb46e9SPaul Traina 	case NFSPROC_WRITE:
5204edb46e9SPaul Traina 		printf(" write");
5212ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
5222ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
523647f50c3SDoug Rabson 			if (v3) {
524c1ad1296SSam Leffler 				TCHECK(dp[2]);
525c1ad1296SSam Leffler 				printf(" %u (%u) bytes @ %" PRIu64,
526c1ad1296SSam Leffler 						EXTRACT_32BITS(&dp[4]),
527c1ad1296SSam Leffler 						EXTRACT_32BITS(&dp[2]),
528c1ad1296SSam Leffler 						EXTRACT_64BITS(&dp[0]));
529647f50c3SDoug Rabson 				if (vflag) {
530647f50c3SDoug Rabson 					dp += 3;
531943ee2b1SBill Fenner 					TCHECK(dp[0]);
532647f50c3SDoug Rabson 					printf(" <%s>",
533943ee2b1SBill Fenner 						tok2str(nfsv3_writemodes,
534cc391cceSBruce M Simpson 							NULL, EXTRACT_32BITS(dp)));
535647f50c3SDoug Rabson 				}
536647f50c3SDoug Rabson 			} else {
537943ee2b1SBill Fenner 				TCHECK(dp[3]);
538943ee2b1SBill Fenner 				printf(" %u (%u) bytes @ %u (%u)",
539cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[3]),
540cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[2]),
541cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[1]),
542cc391cceSBruce M Simpson 						EXTRACT_32BITS(&dp[0]));
543647f50c3SDoug Rabson 			}
5444edb46e9SPaul Traina 			return;
5454edb46e9SPaul Traina 		}
5464edb46e9SPaul Traina 		break;
5474edb46e9SPaul Traina 
5484edb46e9SPaul Traina 	case NFSPROC_CREATE:
5494edb46e9SPaul Traina 		printf(" create");
550943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
551943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
5524edb46e9SPaul Traina 			return;
5534edb46e9SPaul Traina 		break;
5544edb46e9SPaul Traina 
555647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
556647f50c3SDoug Rabson 		printf(" mkdir");
557943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
558647f50c3SDoug Rabson 			return;
559647f50c3SDoug Rabson 		break;
560647f50c3SDoug Rabson 
561647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
562647f50c3SDoug Rabson 		printf(" symlink");
563943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 &&
564943ee2b1SBill Fenner 		    (dp = parsefhn(dp, v3)) != 0) {
565647f50c3SDoug Rabson 			fputs(" ->", stdout);
566943ee2b1SBill Fenner 			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
567647f50c3SDoug Rabson 				break;
568943ee2b1SBill Fenner 			if (parsefn(dp) == 0)
569647f50c3SDoug Rabson 				break;
570647f50c3SDoug Rabson 			if (v3 && vflag)
571647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
572647f50c3SDoug Rabson 			return;
573647f50c3SDoug Rabson 		}
574647f50c3SDoug Rabson 		break;
575647f50c3SDoug Rabson 
576647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
577647f50c3SDoug Rabson 		printf(" mknod");
578943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != 0 &&
579943ee2b1SBill Fenner 		    (dp = parsefhn(dp, v3)) != 0) {
580943ee2b1SBill Fenner 			TCHECK(*dp);
581cc391cceSBruce M Simpson 			type = (nfs_type)EXTRACT_32BITS(dp);
582cc391cceSBruce M Simpson 			dp++;
583943ee2b1SBill Fenner 			if ((dp = parse_sattr3(dp, &sa3)) == 0)
584647f50c3SDoug Rabson 				break;
585647f50c3SDoug Rabson 			printf(" %s", tok2str(type2str, "unk-ft %d", type));
586647f50c3SDoug Rabson 			if (vflag && (type == NFCHR || type == NFBLK)) {
587943ee2b1SBill Fenner 				TCHECK(dp[1]);
588943ee2b1SBill Fenner 				printf(" %u/%u",
589cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[0]),
590cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[1]));
591647f50c3SDoug Rabson 				dp += 2;
592647f50c3SDoug Rabson 			}
593647f50c3SDoug Rabson 			if (vflag)
594647f50c3SDoug Rabson 				print_sattr3(&sa3, vflag);
595647f50c3SDoug Rabson 			return;
596647f50c3SDoug Rabson 		}
597647f50c3SDoug Rabson 		break;
598647f50c3SDoug Rabson 
5994edb46e9SPaul Traina 	case NFSPROC_REMOVE:
6004edb46e9SPaul Traina 		printf(" remove");
601943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
602943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
603647f50c3SDoug Rabson 			return;
604647f50c3SDoug Rabson 		break;
605647f50c3SDoug Rabson 
606647f50c3SDoug Rabson 	case NFSPROC_RMDIR:
607647f50c3SDoug Rabson 		printf(" rmdir");
608943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
609943ee2b1SBill Fenner 		    parsefhn(dp, v3) != NULL)
6104edb46e9SPaul Traina 			return;
6114edb46e9SPaul Traina 		break;
6124edb46e9SPaul Traina 
6134edb46e9SPaul Traina 	case NFSPROC_RENAME:
6144edb46e9SPaul Traina 		printf(" rename");
6152ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6162ebf6c05SBill Fenner 		    (dp = parsefhn(dp, v3)) != NULL) {
6174edb46e9SPaul Traina 			fputs(" ->", stdout);
6182ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
6194edb46e9SPaul Traina 				return;
6204edb46e9SPaul Traina 		}
6214edb46e9SPaul Traina 		break;
6224edb46e9SPaul Traina 
6234edb46e9SPaul Traina 	case NFSPROC_LINK:
6244edb46e9SPaul Traina 		printf(" link");
6252ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6262ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
6274edb46e9SPaul Traina 			fputs(" ->", stdout);
6282ebf6c05SBill Fenner 			if (parsefhn(dp, v3) != NULL)
6294edb46e9SPaul Traina 				return;
6304edb46e9SPaul Traina 		}
6314edb46e9SPaul Traina 		break;
6324edb46e9SPaul Traina 
6334edb46e9SPaul Traina 	case NFSPROC_READDIR:
6344edb46e9SPaul Traina 		printf(" readdir");
6352ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6362ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
637647f50c3SDoug Rabson 			if (v3) {
638943ee2b1SBill Fenner 				TCHECK(dp[4]);
6394edb46e9SPaul Traina 				/*
640647f50c3SDoug Rabson 				 * We shouldn't really try to interpret the
641647f50c3SDoug Rabson 				 * offset cookie here.
6424edb46e9SPaul Traina 				 */
643c1ad1296SSam Leffler 				printf(" %u bytes @ %" PRId64,
644c1ad1296SSam Leffler 				    EXTRACT_32BITS(&dp[4]),
645c1ad1296SSam Leffler 				    EXTRACT_64BITS(&dp[0]));
646647f50c3SDoug Rabson 				if (vflag)
6472ebf6c05SBill Fenner 					printf(" verf %08x%08x", dp[2],
648647f50c3SDoug Rabson 					       dp[3]);
649647f50c3SDoug Rabson 			} else {
650943ee2b1SBill Fenner 				TCHECK(dp[1]);
651647f50c3SDoug Rabson 				/*
652647f50c3SDoug Rabson 				 * Print the offset as signed, since -1 is
653647f50c3SDoug Rabson 				 * common, but offsets > 2^31 aren't.
654647f50c3SDoug Rabson 				 */
655943ee2b1SBill Fenner 				printf(" %u bytes @ %d",
656cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[1]),
657cc391cceSBruce M Simpson 				    EXTRACT_32BITS(&dp[0]));
658647f50c3SDoug Rabson 			}
6594edb46e9SPaul Traina 			return;
6604edb46e9SPaul Traina 		}
6614edb46e9SPaul Traina 		break;
6624edb46e9SPaul Traina 
663647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
664647f50c3SDoug Rabson 		printf(" readdirplus");
6652ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6662ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
667943ee2b1SBill Fenner 			TCHECK(dp[4]);
668647f50c3SDoug Rabson 			/*
669647f50c3SDoug Rabson 			 * We don't try to interpret the offset
670647f50c3SDoug Rabson 			 * cookie here.
671647f50c3SDoug Rabson 			 */
672c1ad1296SSam Leffler 			printf(" %u bytes @ %" PRId64,
673c1ad1296SSam Leffler 				EXTRACT_32BITS(&dp[4]),
674c1ad1296SSam Leffler 				EXTRACT_64BITS(&dp[0]));
675c1ad1296SSam Leffler 			if (vflag) {
676c1ad1296SSam Leffler 				TCHECK(dp[5]);
677943ee2b1SBill Fenner 				printf(" max %u verf %08x%08x",
678cc391cceSBruce M Simpson 				       EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
679c1ad1296SSam Leffler 			}
680647f50c3SDoug Rabson 			return;
681647f50c3SDoug Rabson 		}
682647f50c3SDoug Rabson 		break;
683647f50c3SDoug Rabson 
684647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
685647f50c3SDoug Rabson 		printf(" fsstat");
686943ee2b1SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
687943ee2b1SBill Fenner 		    parsefh(dp, v3) != NULL)
6884edb46e9SPaul Traina 			return;
6894edb46e9SPaul Traina 		break;
6904edb46e9SPaul Traina 
691647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
692647f50c3SDoug Rabson 		printf(" fsinfo");
6930e0def19SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
6940e0def19SBill Fenner 		    parsefh(dp, v3) != NULL)
6950e0def19SBill Fenner 			return;
696647f50c3SDoug Rabson 		break;
697647f50c3SDoug Rabson 
698647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
699647f50c3SDoug Rabson 		printf(" pathconf");
7000e0def19SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7010e0def19SBill Fenner 		    parsefh(dp, v3) != NULL)
7020e0def19SBill Fenner 			return;
703647f50c3SDoug Rabson 		break;
704647f50c3SDoug Rabson 
705647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
706647f50c3SDoug Rabson 		printf(" commit");
7072ebf6c05SBill Fenner 		if ((dp = parsereq(rp, length)) != NULL &&
7082ebf6c05SBill Fenner 		    (dp = parsefh(dp, v3)) != NULL) {
709c1ad1296SSam Leffler 			TCHECK(dp[2]);
710c1ad1296SSam Leffler 			printf(" %u bytes @ %" PRIu64,
711c1ad1296SSam Leffler 				EXTRACT_32BITS(&dp[2]),
712c1ad1296SSam Leffler 				EXTRACT_64BITS(&dp[0]));
713647f50c3SDoug Rabson 			return;
714647f50c3SDoug Rabson 		}
715647f50c3SDoug Rabson 		break;
716647f50c3SDoug Rabson 
7174edb46e9SPaul Traina 	default:
718cc391cceSBruce M Simpson 		printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
7194edb46e9SPaul Traina 		return;
7204edb46e9SPaul Traina 	}
721943ee2b1SBill Fenner 
7224edb46e9SPaul Traina trunc:
7232ebf6c05SBill Fenner 	if (!nfserr)
7244edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
7254edb46e9SPaul Traina }
7264edb46e9SPaul Traina 
7274edb46e9SPaul Traina /*
7284edb46e9SPaul Traina  * Print out an NFS file handle.
7294edb46e9SPaul Traina  * We assume packet was not truncated before the end of the
7304edb46e9SPaul Traina  * file handle pointed to by dp.
7314edb46e9SPaul Traina  *
7324edb46e9SPaul Traina  * Note: new version (using portable file-handle parser) doesn't produce
7334edb46e9SPaul Traina  * generation number.  It probably could be made to do that, with some
7344edb46e9SPaul Traina  * additional hacking on the parser code.
7354edb46e9SPaul Traina  */
7364edb46e9SPaul Traina static void
737943ee2b1SBill Fenner nfs_printfh(register const u_int32_t *dp, const u_int len)
7384edb46e9SPaul Traina {
7394edb46e9SPaul Traina 	my_fsid fsid;
7404edb46e9SPaul Traina 	ino_t ino;
741cc391cceSBruce M Simpson 	const char *sfsname = NULL;
742cc391cceSBruce M Simpson 	char *spacep;
7434edb46e9SPaul Traina 
744cc391cceSBruce M Simpson 	if (uflag) {
745cc391cceSBruce M Simpson 		u_int i;
746cc391cceSBruce M Simpson 		char const *sep = "";
747cc391cceSBruce M Simpson 
748cc391cceSBruce M Simpson 		printf(" fh[");
749cc391cceSBruce M Simpson 		for (i=0; i<len; i++) {
750cc391cceSBruce M Simpson 			(void)printf("%s%x", sep, dp[i]);
751cc391cceSBruce M Simpson 			sep = ":";
752cc391cceSBruce M Simpson 		}
753cc391cceSBruce M Simpson 		printf("]");
754cc391cceSBruce M Simpson 		return;
755cc391cceSBruce M Simpson 	}
756cc391cceSBruce M Simpson 
757cc391cceSBruce M Simpson 	Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
7584edb46e9SPaul Traina 
7594edb46e9SPaul Traina 	if (sfsname) {
7604edb46e9SPaul Traina 		/* file system ID is ASCII, not numeric, for this server OS */
761647f50c3SDoug Rabson 		static char temp[NFSX_V3FHMAX+1];
7624edb46e9SPaul Traina 
7634edb46e9SPaul Traina 		/* Make sure string is null-terminated */
764647f50c3SDoug Rabson 		strncpy(temp, sfsname, NFSX_V3FHMAX);
765943ee2b1SBill Fenner 		temp[sizeof(temp) - 1] = '\0';
7664edb46e9SPaul Traina 		/* Remove trailing spaces */
767cc391cceSBruce M Simpson 		spacep = strchr(temp, ' ');
768cc391cceSBruce M Simpson 		if (spacep)
769cc391cceSBruce M Simpson 			*spacep = '\0';
7704edb46e9SPaul Traina 
771943ee2b1SBill Fenner 		(void)printf(" fh %s/", temp);
7722ebf6c05SBill Fenner 	} else {
773943ee2b1SBill Fenner 		(void)printf(" fh %d,%d/",
774943ee2b1SBill Fenner 			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
7754edb46e9SPaul Traina 	}
776943ee2b1SBill Fenner 
777cc391cceSBruce M Simpson 	if(fsid.Fsid_dev.Minor == 257)
778943ee2b1SBill Fenner 		/* Print the undecoded handle */
779943ee2b1SBill Fenner 		(void)printf("%s", fsid.Opaque_Handle);
780943ee2b1SBill Fenner 	else
781943ee2b1SBill Fenner 		(void)printf("%ld", (long) ino);
7824edb46e9SPaul Traina }
7834edb46e9SPaul Traina 
7844edb46e9SPaul Traina /*
7854edb46e9SPaul Traina  * Maintain a small cache of recent client.XID.server/proc pairs, to allow
7864edb46e9SPaul Traina  * us to match up replies with requests and thus to know how to parse
7874edb46e9SPaul Traina  * the reply.
7884edb46e9SPaul Traina  */
7894edb46e9SPaul Traina 
7904edb46e9SPaul Traina struct xid_map_entry {
7914edb46e9SPaul Traina 	u_int32_t	xid;		/* transaction ID (net order) */
792943ee2b1SBill Fenner 	int ipver;			/* IP version (4 or 6) */
793943ee2b1SBill Fenner #ifdef INET6
794943ee2b1SBill Fenner 	struct in6_addr	client;		/* client IP address (net order) */
795943ee2b1SBill Fenner 	struct in6_addr	server;		/* server IP address (net order) */
796943ee2b1SBill Fenner #else
7974edb46e9SPaul Traina 	struct in_addr	client;		/* client IP address (net order) */
7984edb46e9SPaul Traina 	struct in_addr	server;		/* server IP address (net order) */
799943ee2b1SBill Fenner #endif
8004edb46e9SPaul Traina 	u_int32_t	proc;		/* call proc number (host order) */
801647f50c3SDoug Rabson 	u_int32_t	vers;		/* program version (host order) */
8024edb46e9SPaul Traina };
8034edb46e9SPaul Traina 
8044edb46e9SPaul Traina /*
8054edb46e9SPaul Traina  * Map entries are kept in an array that we manage as a ring;
8064edb46e9SPaul Traina  * new entries are always added at the tail of the ring.  Initially,
8074edb46e9SPaul Traina  * all the entries are zero and hence don't match anything.
8084edb46e9SPaul Traina  */
8094edb46e9SPaul Traina 
8104edb46e9SPaul Traina #define	XIDMAPSIZE	64
8114edb46e9SPaul Traina 
8124edb46e9SPaul Traina struct xid_map_entry xid_map[XIDMAPSIZE];
8134edb46e9SPaul Traina 
8144edb46e9SPaul Traina int	xid_map_next = 0;
8154edb46e9SPaul Traina int	xid_map_hint = 0;
8164edb46e9SPaul Traina 
8174edb46e9SPaul Traina static void
818c1ad1296SSam Leffler xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
8194edb46e9SPaul Traina {
820943ee2b1SBill Fenner 	struct ip *ip = NULL;
821943ee2b1SBill Fenner #ifdef INET6
822943ee2b1SBill Fenner 	struct ip6_hdr *ip6 = NULL;
823943ee2b1SBill Fenner #endif
8244edb46e9SPaul Traina 	struct xid_map_entry *xmep;
8254edb46e9SPaul Traina 
826943ee2b1SBill Fenner 	switch (IP_V((struct ip *)bp)) {
827943ee2b1SBill Fenner 	case 4:
828943ee2b1SBill Fenner 		ip = (struct ip *)bp;
829943ee2b1SBill Fenner 		break;
830943ee2b1SBill Fenner #ifdef INET6
831943ee2b1SBill Fenner 	case 6:
832943ee2b1SBill Fenner 		ip6 = (struct ip6_hdr *)bp;
833943ee2b1SBill Fenner 		break;
834943ee2b1SBill Fenner #endif
835943ee2b1SBill Fenner 	default:
836943ee2b1SBill Fenner 		return;
837943ee2b1SBill Fenner 	}
838943ee2b1SBill Fenner 
8394edb46e9SPaul Traina 	xmep = &xid_map[xid_map_next];
8404edb46e9SPaul Traina 
8414edb46e9SPaul Traina 	if (++xid_map_next >= XIDMAPSIZE)
8424edb46e9SPaul Traina 		xid_map_next = 0;
8434edb46e9SPaul Traina 
8444edb46e9SPaul Traina 	xmep->xid = rp->rm_xid;
845943ee2b1SBill Fenner 	if (ip) {
846943ee2b1SBill Fenner 		xmep->ipver = 4;
847943ee2b1SBill Fenner 		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
848943ee2b1SBill Fenner 		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
849943ee2b1SBill Fenner 	}
850943ee2b1SBill Fenner #ifdef INET6
851943ee2b1SBill Fenner 	else if (ip6) {
852943ee2b1SBill Fenner 		xmep->ipver = 6;
853943ee2b1SBill Fenner 		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
854943ee2b1SBill Fenner 		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
855943ee2b1SBill Fenner 	}
856943ee2b1SBill Fenner #endif
857cc391cceSBruce M Simpson 	xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
858cc391cceSBruce M Simpson 	xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
8594edb46e9SPaul Traina }
8604edb46e9SPaul Traina 
8612ebf6c05SBill Fenner /*
8622ebf6c05SBill Fenner  * Returns 0 and puts NFSPROC_xxx in proc return and
8632ebf6c05SBill Fenner  * version in vers return, or returns -1 on failure
8642ebf6c05SBill Fenner  */
865647f50c3SDoug Rabson static int
866c1ad1296SSam Leffler xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
867647f50c3SDoug Rabson 	     u_int32_t *vers)
8684edb46e9SPaul Traina {
8694edb46e9SPaul Traina 	int i;
8704edb46e9SPaul Traina 	struct xid_map_entry *xmep;
8714edb46e9SPaul Traina 	u_int32_t xid = rp->rm_xid;
872943ee2b1SBill Fenner 	struct ip *ip = (struct ip *)bp;
873943ee2b1SBill Fenner #ifdef INET6
874943ee2b1SBill Fenner 	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
875943ee2b1SBill Fenner #endif
876943ee2b1SBill Fenner 	int cmp;
8774edb46e9SPaul Traina 
8784edb46e9SPaul Traina 	/* Start searching from where we last left off */
8794edb46e9SPaul Traina 	i = xid_map_hint;
8804edb46e9SPaul Traina 	do {
8814edb46e9SPaul Traina 		xmep = &xid_map[i];
882943ee2b1SBill Fenner 		cmp = 1;
883943ee2b1SBill Fenner 		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
884943ee2b1SBill Fenner 			goto nextitem;
885943ee2b1SBill Fenner 		switch (xmep->ipver) {
886943ee2b1SBill Fenner 		case 4:
887943ee2b1SBill Fenner 			if (memcmp(&ip->ip_src, &xmep->server,
888943ee2b1SBill Fenner 				   sizeof(ip->ip_src)) != 0 ||
889943ee2b1SBill Fenner 			    memcmp(&ip->ip_dst, &xmep->client,
890943ee2b1SBill Fenner 				   sizeof(ip->ip_dst)) != 0) {
891943ee2b1SBill Fenner 				cmp = 0;
892943ee2b1SBill Fenner 			}
893943ee2b1SBill Fenner 			break;
894943ee2b1SBill Fenner #ifdef INET6
895943ee2b1SBill Fenner 		case 6:
896943ee2b1SBill Fenner 			if (memcmp(&ip6->ip6_src, &xmep->server,
897943ee2b1SBill Fenner 				   sizeof(ip6->ip6_src)) != 0 ||
898943ee2b1SBill Fenner 			    memcmp(&ip6->ip6_dst, &xmep->client,
899943ee2b1SBill Fenner 				   sizeof(ip6->ip6_dst)) != 0) {
900943ee2b1SBill Fenner 				cmp = 0;
901943ee2b1SBill Fenner 			}
902943ee2b1SBill Fenner 			break;
903943ee2b1SBill Fenner #endif
904943ee2b1SBill Fenner 		default:
905943ee2b1SBill Fenner 			cmp = 0;
906943ee2b1SBill Fenner 			break;
907943ee2b1SBill Fenner 		}
908943ee2b1SBill Fenner 		if (cmp) {
9094edb46e9SPaul Traina 			/* match */
9104edb46e9SPaul Traina 			xid_map_hint = i;
911647f50c3SDoug Rabson 			*proc = xmep->proc;
912647f50c3SDoug Rabson 			*vers = xmep->vers;
913647f50c3SDoug Rabson 			return 0;
9144edb46e9SPaul Traina 		}
915943ee2b1SBill Fenner 	nextitem:
9164edb46e9SPaul Traina 		if (++i >= XIDMAPSIZE)
9174edb46e9SPaul Traina 			i = 0;
9184edb46e9SPaul Traina 	} while (i != xid_map_hint);
9194edb46e9SPaul Traina 
9204edb46e9SPaul Traina 	/* search failed */
921943ee2b1SBill Fenner 	return (-1);
9224edb46e9SPaul Traina }
9234edb46e9SPaul Traina 
9244edb46e9SPaul Traina /*
9254edb46e9SPaul Traina  * Routines for parsing reply packets
9264edb46e9SPaul Traina  */
9274edb46e9SPaul Traina 
9284edb46e9SPaul Traina /*
9294edb46e9SPaul Traina  * Return a pointer to the beginning of the actual results.
930943ee2b1SBill Fenner  * If the packet was truncated, return 0.
9314edb46e9SPaul Traina  */
9324edb46e9SPaul Traina static const u_int32_t *
933c1ad1296SSam Leffler parserep(register const struct sunrpc_msg *rp, register u_int length)
9344edb46e9SPaul Traina {
9354edb46e9SPaul Traina 	register const u_int32_t *dp;
936943ee2b1SBill Fenner 	u_int len;
937c1ad1296SSam Leffler 	enum sunrpc_accept_stat astat;
9384edb46e9SPaul Traina 
9394edb46e9SPaul Traina 	/*
9404edb46e9SPaul Traina 	 * Portability note:
9414edb46e9SPaul Traina 	 * Here we find the address of the ar_verf credentials.
9424edb46e9SPaul Traina 	 * Originally, this calculation was
9434edb46e9SPaul Traina 	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
9444edb46e9SPaul Traina 	 * On the wire, the rp_acpt field starts immediately after
9454edb46e9SPaul Traina 	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
9464edb46e9SPaul Traina 	 * "struct accepted_reply") contains a "struct opaque_auth",
9474edb46e9SPaul Traina 	 * whose internal representation contains a pointer, so on a
9484edb46e9SPaul Traina 	 * 64-bit machine the compiler inserts 32 bits of padding
9494edb46e9SPaul Traina 	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
9504edb46e9SPaul Traina 	 * the internal representation to parse the on-the-wire
9514edb46e9SPaul Traina 	 * representation.  Instead, we skip past the rp_stat field,
9524edb46e9SPaul Traina 	 * which is an "enum" and so occupies one 32-bit word.
9534edb46e9SPaul Traina 	 */
9544edb46e9SPaul Traina 	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
955943ee2b1SBill Fenner 	TCHECK(dp[1]);
956cc391cceSBruce M Simpson 	len = EXTRACT_32BITS(&dp[1]);
9574edb46e9SPaul Traina 	if (len >= length)
9582ebf6c05SBill Fenner 		return (NULL);
9594edb46e9SPaul Traina 	/*
9604edb46e9SPaul Traina 	 * skip past the ar_verf credentials.
9614edb46e9SPaul Traina 	 */
9624edb46e9SPaul Traina 	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
9632ebf6c05SBill Fenner 	TCHECK2(dp[0], 0);
9644edb46e9SPaul Traina 
9654edb46e9SPaul Traina 	/*
9664edb46e9SPaul Traina 	 * now we can check the ar_stat field
9674edb46e9SPaul Traina 	 */
96829292c17SSam Leffler 	astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
9694edb46e9SPaul Traina 	switch (astat) {
9704edb46e9SPaul Traina 
971c1ad1296SSam Leffler 	case SUNRPC_SUCCESS:
9724edb46e9SPaul Traina 		break;
9734edb46e9SPaul Traina 
974c1ad1296SSam Leffler 	case SUNRPC_PROG_UNAVAIL:
9754edb46e9SPaul Traina 		printf(" PROG_UNAVAIL");
9762ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
9772ebf6c05SBill Fenner 		return (NULL);
9784edb46e9SPaul Traina 
979c1ad1296SSam Leffler 	case SUNRPC_PROG_MISMATCH:
9804edb46e9SPaul Traina 		printf(" PROG_MISMATCH");
9812ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
9822ebf6c05SBill Fenner 		return (NULL);
9834edb46e9SPaul Traina 
984c1ad1296SSam Leffler 	case SUNRPC_PROC_UNAVAIL:
9854edb46e9SPaul Traina 		printf(" PROC_UNAVAIL");
9862ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
9872ebf6c05SBill Fenner 		return (NULL);
9884edb46e9SPaul Traina 
989c1ad1296SSam Leffler 	case SUNRPC_GARBAGE_ARGS:
9904edb46e9SPaul Traina 		printf(" GARBAGE_ARGS");
9912ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
9922ebf6c05SBill Fenner 		return (NULL);
9934edb46e9SPaul Traina 
994c1ad1296SSam Leffler 	case SUNRPC_SYSTEM_ERR:
9954edb46e9SPaul Traina 		printf(" SYSTEM_ERR");
9962ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
9972ebf6c05SBill Fenner 		return (NULL);
9984edb46e9SPaul Traina 
9994edb46e9SPaul Traina 	default:
10004edb46e9SPaul Traina 		printf(" ar_stat %d", astat);
10012ebf6c05SBill Fenner 		nfserr = 1;		/* suppress trunc string */
10022ebf6c05SBill Fenner 		return (NULL);
10034edb46e9SPaul Traina 	}
10044edb46e9SPaul Traina 	/* successful return */
1005943ee2b1SBill Fenner 	TCHECK2(*dp, sizeof(astat));
10064edb46e9SPaul Traina 	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
10072ebf6c05SBill Fenner trunc:
1008943ee2b1SBill Fenner 	return (0);
10094edb46e9SPaul Traina }
10104edb46e9SPaul Traina 
1011647f50c3SDoug Rabson static const u_int32_t *
1012647f50c3SDoug Rabson parsestatus(const u_int32_t *dp, int *er)
1013647f50c3SDoug Rabson {
1014943ee2b1SBill Fenner 	int errnum;
1015647f50c3SDoug Rabson 
10162ebf6c05SBill Fenner 	TCHECK(dp[0]);
1017943ee2b1SBill Fenner 
1018cc391cceSBruce M Simpson 	errnum = EXTRACT_32BITS(&dp[0]);
1019647f50c3SDoug Rabson 	if (er)
10202ebf6c05SBill Fenner 		*er = errnum;
10212ebf6c05SBill Fenner 	if (errnum != 0) {
10222ebf6c05SBill Fenner 		if (!qflag)
1023943ee2b1SBill Fenner 			printf(" ERROR: %s",
1024943ee2b1SBill Fenner 			    tok2str(status2str, "unk %d", errnum));
10252ebf6c05SBill Fenner 		nfserr = 1;
10264edb46e9SPaul Traina 	}
10274edb46e9SPaul Traina 	return (dp + 1);
10282ebf6c05SBill Fenner trunc:
1029943ee2b1SBill Fenner 	return NULL;
10304edb46e9SPaul Traina }
10314edb46e9SPaul Traina 
10324edb46e9SPaul Traina static const u_int32_t *
1033647f50c3SDoug Rabson parsefattr(const u_int32_t *dp, int verbose, int v3)
10344edb46e9SPaul Traina {
1035647f50c3SDoug Rabson 	const struct nfs_fattr *fap;
10364edb46e9SPaul Traina 
1037647f50c3SDoug Rabson 	fap = (const struct nfs_fattr *)dp;
1038685b49deSBill Fenner 	TCHECK(fap->fa_gid);
10394edb46e9SPaul Traina 	if (verbose) {
1040943ee2b1SBill Fenner 		printf(" %s %o ids %d/%d",
1041943ee2b1SBill Fenner 		    tok2str(type2str, "unk-ft %d ",
1042cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_type)),
1043cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_mode),
1044cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_uid),
1045cc391cceSBruce M Simpson 		    EXTRACT_32BITS(&fap->fa_gid));
1046647f50c3SDoug Rabson 		if (v3) {
1047685b49deSBill Fenner 			TCHECK(fap->fa3_size);
1048c1ad1296SSam Leffler 			printf(" sz %" PRIu64,
1049c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
1050685b49deSBill Fenner 		} else {
1051685b49deSBill Fenner 			TCHECK(fap->fa2_size);
1052cc391cceSBruce M Simpson 			printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
1053647f50c3SDoug Rabson 		}
10544edb46e9SPaul Traina 	}
10554edb46e9SPaul Traina 	/* print lots more stuff */
10564edb46e9SPaul Traina 	if (verbose > 1) {
1057647f50c3SDoug Rabson 		if (v3) {
1058685b49deSBill Fenner 			TCHECK(fap->fa3_ctime);
1059943ee2b1SBill Fenner 			printf(" nlink %d rdev %d/%d",
1060cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa_nlink),
1061cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1062cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1063c1ad1296SSam Leffler 			printf(" fsid %" PRIx64,
1064c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1065c1ad1296SSam Leffler 			printf(" fileid %" PRIx64,
1066c1ad1296SSam Leffler 				EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1067943ee2b1SBill Fenner 			printf(" a/m/ctime %u.%06u",
1068cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1069cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1070943ee2b1SBill Fenner 			printf(" %u.%06u",
1071cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1072cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1073943ee2b1SBill Fenner 			printf(" %u.%06u",
1074cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1075cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
1076647f50c3SDoug Rabson 		} else {
1077685b49deSBill Fenner 			TCHECK(fap->fa2_ctime);
1078943ee2b1SBill Fenner 			printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1079cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa_nlink),
1080cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_rdev),
1081cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_fsid),
1082cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_fileid));
1083943ee2b1SBill Fenner 			printf(" %u.%06u",
1084cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1085cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1086943ee2b1SBill Fenner 			printf(" %u.%06u",
1087cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1088cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1089943ee2b1SBill Fenner 			printf(" %u.%06u",
1090cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1091cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
10924edb46e9SPaul Traina 		}
1093647f50c3SDoug Rabson 	}
1094647f50c3SDoug Rabson 	return ((const u_int32_t *)((unsigned char *)dp +
1095647f50c3SDoug Rabson 		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
1096685b49deSBill Fenner trunc:
1097685b49deSBill Fenner 	return (NULL);
10984edb46e9SPaul Traina }
10994edb46e9SPaul Traina 
11004edb46e9SPaul Traina static int
1101647f50c3SDoug Rabson parseattrstat(const u_int32_t *dp, int verbose, int v3)
11024edb46e9SPaul Traina {
1103647f50c3SDoug Rabson 	int er;
1104647f50c3SDoug Rabson 
1105647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
11060e0def19SBill Fenner 	if (dp == NULL)
11074edb46e9SPaul Traina 		return (0);
11080e0def19SBill Fenner 	if (er)
11090e0def19SBill Fenner 		return (1);
11104edb46e9SPaul Traina 
11112ebf6c05SBill Fenner 	return (parsefattr(dp, verbose, v3) != NULL);
11124edb46e9SPaul Traina }
11134edb46e9SPaul Traina 
11144edb46e9SPaul Traina static int
11154edb46e9SPaul Traina parsediropres(const u_int32_t *dp)
11164edb46e9SPaul Traina {
1117647f50c3SDoug Rabson 	int er;
1118647f50c3SDoug Rabson 
11190e0def19SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1120647f50c3SDoug Rabson 		return (0);
11210e0def19SBill Fenner 	if (er)
11220e0def19SBill Fenner 		return (1);
1123647f50c3SDoug Rabson 
1124647f50c3SDoug Rabson 	dp = parsefh(dp, 0);
11254edb46e9SPaul Traina 	if (dp == NULL)
11264edb46e9SPaul Traina 		return (0);
11274edb46e9SPaul Traina 
1128647f50c3SDoug Rabson 	return (parsefattr(dp, vflag, 0) != NULL);
11294edb46e9SPaul Traina }
11304edb46e9SPaul Traina 
11314edb46e9SPaul Traina static int
1132647f50c3SDoug Rabson parselinkres(const u_int32_t *dp, int v3)
11334edb46e9SPaul Traina {
1134647f50c3SDoug Rabson 	int er;
11354edb46e9SPaul Traina 
1136647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
11370e0def19SBill Fenner 	if (dp == NULL)
1138647f50c3SDoug Rabson 		return(0);
11390e0def19SBill Fenner 	if (er)
11400e0def19SBill Fenner 		return(1);
1141943ee2b1SBill Fenner 	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
1142647f50c3SDoug Rabson 		return (0);
11434edb46e9SPaul Traina 	putchar(' ');
11444edb46e9SPaul Traina 	return (parsefn(dp) != NULL);
11454edb46e9SPaul Traina }
11464edb46e9SPaul Traina 
11474edb46e9SPaul Traina static int
1148647f50c3SDoug Rabson parsestatfs(const u_int32_t *dp, int v3)
11494edb46e9SPaul Traina {
1150647f50c3SDoug Rabson 	const struct nfs_statfs *sfsp;
1151647f50c3SDoug Rabson 	int er;
11524edb46e9SPaul Traina 
1153647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
11540e0def19SBill Fenner 	if (dp == NULL)
11554edb46e9SPaul Traina 		return (0);
11560e0def19SBill Fenner 	if (!v3 && er)
11570e0def19SBill Fenner 		return (1);
11584edb46e9SPaul Traina 
1159647f50c3SDoug Rabson 	if (qflag)
1160647f50c3SDoug Rabson 		return(1);
1161647f50c3SDoug Rabson 
1162647f50c3SDoug Rabson 	if (v3) {
1163647f50c3SDoug Rabson 		if (vflag)
1164647f50c3SDoug Rabson 			printf(" POST:");
1165943ee2b1SBill Fenner 		if (!(dp = parse_post_op_attr(dp, vflag)))
1166647f50c3SDoug Rabson 			return (0);
1167647f50c3SDoug Rabson 	}
1168647f50c3SDoug Rabson 
11690e0def19SBill Fenner 	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1170647f50c3SDoug Rabson 
1171647f50c3SDoug Rabson 	sfsp = (const struct nfs_statfs *)dp;
1172647f50c3SDoug Rabson 
1173647f50c3SDoug Rabson 	if (v3) {
1174c1ad1296SSam Leffler 		printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1175c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1176c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1177c1ad1296SSam Leffler 			EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
1178647f50c3SDoug Rabson 		if (vflag) {
1179c1ad1296SSam Leffler 			printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1180c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1181c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1182c1ad1296SSam Leffler 			       EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1183cc391cceSBruce M Simpson 			       EXTRACT_32BITS(&sfsp->sf_invarsec));
1184647f50c3SDoug Rabson 		}
1185647f50c3SDoug Rabson 	} else {
1186943ee2b1SBill Fenner 		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1187cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_tsize),
1188cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bsize),
1189cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_blocks),
1190cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bfree),
1191cc391cceSBruce M Simpson 			EXTRACT_32BITS(&sfsp->sf_bavail));
11924edb46e9SPaul Traina 	}
11934edb46e9SPaul Traina 
11944edb46e9SPaul Traina 	return (1);
1195685b49deSBill Fenner trunc:
1196685b49deSBill Fenner 	return (0);
11974edb46e9SPaul Traina }
11984edb46e9SPaul Traina 
11994edb46e9SPaul Traina static int
12004edb46e9SPaul Traina parserddires(const u_int32_t *dp)
12014edb46e9SPaul Traina {
1202647f50c3SDoug Rabson 	int er;
1203647f50c3SDoug Rabson 
1204647f50c3SDoug Rabson 	dp = parsestatus(dp, &er);
12050e0def19SBill Fenner 	if (dp == NULL)
12064edb46e9SPaul Traina 		return (0);
12070e0def19SBill Fenner 	if (er)
12080e0def19SBill Fenner 		return (1);
1209647f50c3SDoug Rabson 	if (qflag)
1210647f50c3SDoug Rabson 		return (1);
1211647f50c3SDoug Rabson 
1212685b49deSBill Fenner 	TCHECK(dp[2]);
1213943ee2b1SBill Fenner 	printf(" offset %x size %d ",
1214cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
12154edb46e9SPaul Traina 	if (dp[2] != 0)
12164edb46e9SPaul Traina 		printf(" eof");
12174edb46e9SPaul Traina 
12184edb46e9SPaul Traina 	return (1);
1219685b49deSBill Fenner trunc:
1220685b49deSBill Fenner 	return (0);
1221647f50c3SDoug Rabson }
1222647f50c3SDoug Rabson 
1223647f50c3SDoug Rabson static const u_int32_t *
1224647f50c3SDoug Rabson parse_wcc_attr(const u_int32_t *dp)
1225647f50c3SDoug Rabson {
1226c1ad1296SSam Leffler 	printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
1227943ee2b1SBill Fenner 	printf(" mtime %u.%06u ctime %u.%06u",
1228cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1229cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
1230647f50c3SDoug Rabson 	return (dp + 6);
1231647f50c3SDoug Rabson }
1232647f50c3SDoug Rabson 
1233647f50c3SDoug Rabson /*
1234647f50c3SDoug Rabson  * Pre operation attributes. Print only if vflag > 1.
1235647f50c3SDoug Rabson  */
1236647f50c3SDoug Rabson static const u_int32_t *
1237647f50c3SDoug Rabson parse_pre_op_attr(const u_int32_t *dp, int verbose)
1238647f50c3SDoug Rabson {
1239685b49deSBill Fenner 	TCHECK(dp[0]);
1240cc391cceSBruce M Simpson 	if (!EXTRACT_32BITS(&dp[0]))
1241647f50c3SDoug Rabson 		return (dp + 1);
1242647f50c3SDoug Rabson 	dp++;
12430e0def19SBill Fenner 	TCHECK2(*dp, 24);
1244647f50c3SDoug Rabson 	if (verbose > 1) {
1245647f50c3SDoug Rabson 		return parse_wcc_attr(dp);
1246647f50c3SDoug Rabson 	} else {
1247647f50c3SDoug Rabson 		/* If not verbose enough, just skip over wcc_attr */
1248647f50c3SDoug Rabson 		return (dp + 6);
1249647f50c3SDoug Rabson 	}
1250685b49deSBill Fenner trunc:
1251685b49deSBill Fenner 	return (NULL);
1252647f50c3SDoug Rabson }
1253647f50c3SDoug Rabson 
1254647f50c3SDoug Rabson /*
1255647f50c3SDoug Rabson  * Post operation attributes are printed if vflag >= 1
1256647f50c3SDoug Rabson  */
1257647f50c3SDoug Rabson static const u_int32_t *
1258647f50c3SDoug Rabson parse_post_op_attr(const u_int32_t *dp, int verbose)
1259647f50c3SDoug Rabson {
1260685b49deSBill Fenner 	TCHECK(dp[0]);
1261cc391cceSBruce M Simpson 	if (!EXTRACT_32BITS(&dp[0]))
1262647f50c3SDoug Rabson 		return (dp + 1);
1263647f50c3SDoug Rabson 	dp++;
1264647f50c3SDoug Rabson 	if (verbose) {
1265647f50c3SDoug Rabson 		return parsefattr(dp, verbose, 1);
1266647f50c3SDoug Rabson 	} else
1267647f50c3SDoug Rabson 		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1268685b49deSBill Fenner trunc:
1269685b49deSBill Fenner 	return (NULL);
1270647f50c3SDoug Rabson }
1271647f50c3SDoug Rabson 
1272647f50c3SDoug Rabson static const u_int32_t *
1273647f50c3SDoug Rabson parse_wcc_data(const u_int32_t *dp, int verbose)
1274647f50c3SDoug Rabson {
1275647f50c3SDoug Rabson 	if (verbose > 1)
1276647f50c3SDoug Rabson 		printf(" PRE:");
1277943ee2b1SBill Fenner 	if (!(dp = parse_pre_op_attr(dp, verbose)))
1278943ee2b1SBill Fenner 		return (0);
1279647f50c3SDoug Rabson 
1280647f50c3SDoug Rabson 	if (verbose)
1281647f50c3SDoug Rabson 		printf(" POST:");
1282647f50c3SDoug Rabson 	return parse_post_op_attr(dp, verbose);
1283647f50c3SDoug Rabson }
1284647f50c3SDoug Rabson 
1285647f50c3SDoug Rabson static const u_int32_t *
1286647f50c3SDoug Rabson parsecreateopres(const u_int32_t *dp, int verbose)
1287647f50c3SDoug Rabson {
1288647f50c3SDoug Rabson 	int er;
1289647f50c3SDoug Rabson 
1290943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1291943ee2b1SBill Fenner 		return (0);
1292647f50c3SDoug Rabson 	if (er)
1293647f50c3SDoug Rabson 		dp = parse_wcc_data(dp, verbose);
1294647f50c3SDoug Rabson 	else {
1295685b49deSBill Fenner 		TCHECK(dp[0]);
1296cc391cceSBruce M Simpson 		if (!EXTRACT_32BITS(&dp[0]))
1297647f50c3SDoug Rabson 			return (dp + 1);
1298647f50c3SDoug Rabson 		dp++;
1299943ee2b1SBill Fenner 		if (!(dp = parsefh(dp, 1)))
1300943ee2b1SBill Fenner 			return (0);
1301647f50c3SDoug Rabson 		if (verbose) {
1302943ee2b1SBill Fenner 			if (!(dp = parse_post_op_attr(dp, verbose)))
1303943ee2b1SBill Fenner 				return (0);
1304647f50c3SDoug Rabson 			if (vflag > 1) {
1305647f50c3SDoug Rabson 				printf(" dir attr:");
1306647f50c3SDoug Rabson 				dp = parse_wcc_data(dp, verbose);
1307647f50c3SDoug Rabson 			}
1308647f50c3SDoug Rabson 		}
1309647f50c3SDoug Rabson 	}
1310647f50c3SDoug Rabson 	return (dp);
1311685b49deSBill Fenner trunc:
1312685b49deSBill Fenner 	return (NULL);
1313647f50c3SDoug Rabson }
1314647f50c3SDoug Rabson 
1315647f50c3SDoug Rabson static int
1316647f50c3SDoug Rabson parsewccres(const u_int32_t *dp, int verbose)
1317647f50c3SDoug Rabson {
1318647f50c3SDoug Rabson 	int er;
1319647f50c3SDoug Rabson 
1320943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1321647f50c3SDoug Rabson 		return (0);
1322943ee2b1SBill Fenner 	return parse_wcc_data(dp, verbose) != 0;
1323647f50c3SDoug Rabson }
1324647f50c3SDoug Rabson 
1325647f50c3SDoug Rabson static const u_int32_t *
1326647f50c3SDoug Rabson parsev3rddirres(const u_int32_t *dp, int verbose)
1327647f50c3SDoug Rabson {
1328647f50c3SDoug Rabson 	int er;
1329647f50c3SDoug Rabson 
1330943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1331943ee2b1SBill Fenner 		return (0);
1332647f50c3SDoug Rabson 	if (vflag)
1333647f50c3SDoug Rabson 		printf(" POST:");
1334943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, verbose)))
1335943ee2b1SBill Fenner 		return (0);
1336647f50c3SDoug Rabson 	if (er)
1337647f50c3SDoug Rabson 		return dp;
1338647f50c3SDoug Rabson 	if (vflag) {
1339685b49deSBill Fenner 		TCHECK(dp[1]);
13402ebf6c05SBill Fenner 		printf(" verf %08x%08x", dp[0], dp[1]);
1341647f50c3SDoug Rabson 		dp += 2;
1342647f50c3SDoug Rabson 	}
1343647f50c3SDoug Rabson 	return dp;
1344685b49deSBill Fenner trunc:
1345685b49deSBill Fenner 	return (NULL);
1346647f50c3SDoug Rabson }
1347647f50c3SDoug Rabson 
1348647f50c3SDoug Rabson static int
1349647f50c3SDoug Rabson parsefsinfo(const u_int32_t *dp)
1350647f50c3SDoug Rabson {
1351647f50c3SDoug Rabson 	struct nfsv3_fsinfo *sfp;
1352647f50c3SDoug Rabson 	int er;
1353647f50c3SDoug Rabson 
1354943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1355647f50c3SDoug Rabson 		return (0);
1356647f50c3SDoug Rabson 	if (vflag)
1357647f50c3SDoug Rabson 		printf(" POST:");
1358943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, vflag)))
1359647f50c3SDoug Rabson 		return (0);
1360647f50c3SDoug Rabson 	if (er)
1361647f50c3SDoug Rabson 		return (1);
1362647f50c3SDoug Rabson 
1363647f50c3SDoug Rabson 	sfp = (struct nfsv3_fsinfo *)dp;
1364685b49deSBill Fenner 	TCHECK(*sfp);
1365943ee2b1SBill Fenner 	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1366cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_rtmax),
1367cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_rtpref),
1368cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_wtmax),
1369cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_wtpref),
1370cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&sfp->fs_dtpref));
1371647f50c3SDoug Rabson 	if (vflag) {
1372c1ad1296SSam Leffler 		printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1373cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_rtmult),
1374c1ad1296SSam Leffler 		       EXTRACT_32BITS(&sfp->fs_wtmult),
1375c1ad1296SSam Leffler 		       EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
1376943ee2b1SBill Fenner 		printf(" delta %u.%06u ",
1377cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1378cc391cceSBruce M Simpson 		       EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
1379647f50c3SDoug Rabson 	}
1380943ee2b1SBill Fenner 	return (1);
13810e0def19SBill Fenner trunc:
13820e0def19SBill Fenner 	return (0);
1383647f50c3SDoug Rabson }
1384647f50c3SDoug Rabson 
1385647f50c3SDoug Rabson static int
1386647f50c3SDoug Rabson parsepathconf(const u_int32_t *dp)
1387647f50c3SDoug Rabson {
1388647f50c3SDoug Rabson 	int er;
1389647f50c3SDoug Rabson 	struct nfsv3_pathconf *spp;
1390647f50c3SDoug Rabson 
1391943ee2b1SBill Fenner 	if (!(dp = parsestatus(dp, &er)))
1392647f50c3SDoug Rabson 		return (0);
1393647f50c3SDoug Rabson 	if (vflag)
1394647f50c3SDoug Rabson 		printf(" POST:");
1395943ee2b1SBill Fenner 	if (!(dp = parse_post_op_attr(dp, vflag)))
1396647f50c3SDoug Rabson 		return (0);
1397647f50c3SDoug Rabson 	if (er)
1398647f50c3SDoug Rabson 		return (1);
1399647f50c3SDoug Rabson 
1400647f50c3SDoug Rabson 	spp = (struct nfsv3_pathconf *)dp;
1401685b49deSBill Fenner 	TCHECK(*spp);
1402647f50c3SDoug Rabson 
1403943ee2b1SBill Fenner 	printf(" linkmax %u namemax %u %s %s %s %s",
1404cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_linkmax),
1405cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_namemax),
1406cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1407cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1408cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1409cc391cceSBruce M Simpson 	       EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1410943ee2b1SBill Fenner 	return (1);
14110e0def19SBill Fenner trunc:
14120e0def19SBill Fenner 	return (0);
14134edb46e9SPaul Traina }
14144edb46e9SPaul Traina 
14154edb46e9SPaul Traina static void
1416c1ad1296SSam Leffler interp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
14174edb46e9SPaul Traina {
14184edb46e9SPaul Traina 	register const u_int32_t *dp;
1419647f50c3SDoug Rabson 	register int v3;
1420647f50c3SDoug Rabson 	int er;
1421647f50c3SDoug Rabson 
1422647f50c3SDoug Rabson 	v3 = (vers == NFS_VER3);
1423647f50c3SDoug Rabson 
1424647f50c3SDoug Rabson 	if (!v3 && proc < NFS_NPROCS)
1425647f50c3SDoug Rabson 		proc = nfsv3_procid[proc];
14264edb46e9SPaul Traina 
14274edb46e9SPaul Traina 	switch (proc) {
14284edb46e9SPaul Traina 
14294edb46e9SPaul Traina 	case NFSPROC_NOOP:
14304edb46e9SPaul Traina 		printf(" nop");
14314edb46e9SPaul Traina 		return;
1432647f50c3SDoug Rabson 
14334edb46e9SPaul Traina 	case NFSPROC_NULL:
14344edb46e9SPaul Traina 		printf(" null");
14354edb46e9SPaul Traina 		return;
14364edb46e9SPaul Traina 
14374edb46e9SPaul Traina 	case NFSPROC_GETATTR:
14384edb46e9SPaul Traina 		printf(" getattr");
14394edb46e9SPaul Traina 		dp = parserep(rp, length);
14402ebf6c05SBill Fenner 		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
14414edb46e9SPaul Traina 			return;
14424edb46e9SPaul Traina 		break;
14434edb46e9SPaul Traina 
14444edb46e9SPaul Traina 	case NFSPROC_SETATTR:
14454edb46e9SPaul Traina 		printf(" setattr");
1446943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
14474edb46e9SPaul Traina 			return;
1448647f50c3SDoug Rabson 		if (v3) {
1449943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
1450647f50c3SDoug Rabson 				return;
1451647f50c3SDoug Rabson 		} else {
1452647f50c3SDoug Rabson 			if (parseattrstat(dp, !qflag, 0) != 0)
1453647f50c3SDoug Rabson 				return;
1454647f50c3SDoug Rabson 		}
14554edb46e9SPaul Traina 		break;
14564edb46e9SPaul Traina 
14574edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
14584edb46e9SPaul Traina 		printf(" lookup");
1459943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
14604edb46e9SPaul Traina 			break;
1461647f50c3SDoug Rabson 		if (v3) {
1462943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1463647f50c3SDoug Rabson 				break;
1464647f50c3SDoug Rabson 			if (er) {
1465647f50c3SDoug Rabson 				if (vflag > 1) {
1466647f50c3SDoug Rabson 					printf(" post dattr:");
1467647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1468647f50c3SDoug Rabson 				}
1469647f50c3SDoug Rabson 			} else {
1470943ee2b1SBill Fenner 				if (!(dp = parsefh(dp, v3)))
1471647f50c3SDoug Rabson 					break;
1472943ee2b1SBill Fenner 				if ((dp = parse_post_op_attr(dp, vflag)) &&
1473943ee2b1SBill Fenner 				    vflag > 1) {
1474647f50c3SDoug Rabson 					printf(" post dattr:");
1475647f50c3SDoug Rabson 					dp = parse_post_op_attr(dp, vflag);
1476647f50c3SDoug Rabson 				}
1477647f50c3SDoug Rabson 			}
1478943ee2b1SBill Fenner 			if (dp)
1479647f50c3SDoug Rabson 				return;
1480647f50c3SDoug Rabson 		} else {
1481647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1482647f50c3SDoug Rabson 				return;
1483647f50c3SDoug Rabson 		}
1484647f50c3SDoug Rabson 		break;
1485647f50c3SDoug Rabson 
1486647f50c3SDoug Rabson 	case NFSPROC_ACCESS:
1487647f50c3SDoug Rabson 		printf(" access");
1488a1c2090eSBill Fenner 		if (!(dp = parserep(rp, length)))
1489a1c2090eSBill Fenner 			break;
1490943ee2b1SBill Fenner 		if (!(dp = parsestatus(dp, &er)))
1491647f50c3SDoug Rabson 			break;
1492647f50c3SDoug Rabson 		if (vflag)
1493647f50c3SDoug Rabson 			printf(" attr:");
1494943ee2b1SBill Fenner 		if (!(dp = parse_post_op_attr(dp, vflag)))
1495647f50c3SDoug Rabson 			break;
1496647f50c3SDoug Rabson 		if (!er)
1497cc391cceSBruce M Simpson 			printf(" c %04x", EXTRACT_32BITS(&dp[0]));
1498647f50c3SDoug Rabson 		return;
14994edb46e9SPaul Traina 
15004edb46e9SPaul Traina 	case NFSPROC_READLINK:
15014edb46e9SPaul Traina 		printf(" readlink");
15024edb46e9SPaul Traina 		dp = parserep(rp, length);
15032ebf6c05SBill Fenner 		if (dp != NULL && parselinkres(dp, v3) != 0)
15044edb46e9SPaul Traina 			return;
15054edb46e9SPaul Traina 		break;
15064edb46e9SPaul Traina 
15074edb46e9SPaul Traina 	case NFSPROC_READ:
15084edb46e9SPaul Traina 		printf(" read");
1509943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1510647f50c3SDoug Rabson 			break;
1511647f50c3SDoug Rabson 		if (v3) {
1512943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1513647f50c3SDoug Rabson 				break;
1514943ee2b1SBill Fenner 			if (!(dp = parse_post_op_attr(dp, vflag)))
1515647f50c3SDoug Rabson 				break;
1516647f50c3SDoug Rabson 			if (er)
15174edb46e9SPaul Traina 				return;
1518647f50c3SDoug Rabson 			if (vflag) {
1519943ee2b1SBill Fenner 				TCHECK(dp[1]);
1520cc391cceSBruce M Simpson 				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1521cc391cceSBruce M Simpson 				if (EXTRACT_32BITS(&dp[1]))
1522647f50c3SDoug Rabson 					printf(" EOF");
1523647f50c3SDoug Rabson 			}
1524647f50c3SDoug Rabson 			return;
1525647f50c3SDoug Rabson 		} else {
1526647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, 0) != 0)
1527647f50c3SDoug Rabson 				return;
1528647f50c3SDoug Rabson 		}
15294edb46e9SPaul Traina 		break;
15304edb46e9SPaul Traina 
15314edb46e9SPaul Traina 	case NFSPROC_WRITE:
15324edb46e9SPaul Traina 		printf(" write");
1533943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1534647f50c3SDoug Rabson 			break;
1535647f50c3SDoug Rabson 		if (v3) {
1536943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1537647f50c3SDoug Rabson 				break;
1538943ee2b1SBill Fenner 			if (!(dp = parse_wcc_data(dp, vflag)))
1539647f50c3SDoug Rabson 				break;
1540647f50c3SDoug Rabson 			if (er)
15414edb46e9SPaul Traina 				return;
1542647f50c3SDoug Rabson 			if (vflag) {
1543943ee2b1SBill Fenner 				TCHECK(dp[0]);
1544cc391cceSBruce M Simpson 				printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1545647f50c3SDoug Rabson 				if (vflag > 1) {
1546943ee2b1SBill Fenner 					TCHECK(dp[1]);
1547647f50c3SDoug Rabson 					printf(" <%s>",
1548943ee2b1SBill Fenner 						tok2str(nfsv3_writemodes,
1549cc391cceSBruce M Simpson 							NULL, EXTRACT_32BITS(&dp[1])));
1550647f50c3SDoug Rabson 				}
1551647f50c3SDoug Rabson 				return;
1552647f50c3SDoug Rabson 			}
1553647f50c3SDoug Rabson 		} else {
1554647f50c3SDoug Rabson 			if (parseattrstat(dp, vflag, v3) != 0)
1555647f50c3SDoug Rabson 				return;
1556647f50c3SDoug Rabson 		}
15574edb46e9SPaul Traina 		break;
15584edb46e9SPaul Traina 
15594edb46e9SPaul Traina 	case NFSPROC_CREATE:
15604edb46e9SPaul Traina 		printf(" create");
1561943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1562647f50c3SDoug Rabson 			break;
1563647f50c3SDoug Rabson 		if (v3) {
1564943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1565647f50c3SDoug Rabson 				return;
1566647f50c3SDoug Rabson 		} else {
1567647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1568647f50c3SDoug Rabson 				return;
1569647f50c3SDoug Rabson 		}
1570647f50c3SDoug Rabson 		break;
1571647f50c3SDoug Rabson 
1572647f50c3SDoug Rabson 	case NFSPROC_MKDIR:
1573647f50c3SDoug Rabson 		printf(" mkdir");
1574943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1575647f50c3SDoug Rabson 			break;
1576647f50c3SDoug Rabson 		if (v3) {
1577943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1578647f50c3SDoug Rabson 				return;
1579647f50c3SDoug Rabson 		} else {
1580647f50c3SDoug Rabson 			if (parsediropres(dp) != 0)
1581647f50c3SDoug Rabson 				return;
1582647f50c3SDoug Rabson 		}
1583647f50c3SDoug Rabson 		break;
1584647f50c3SDoug Rabson 
1585647f50c3SDoug Rabson 	case NFSPROC_SYMLINK:
1586647f50c3SDoug Rabson 		printf(" symlink");
1587943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1588647f50c3SDoug Rabson 			break;
1589647f50c3SDoug Rabson 		if (v3) {
1590943ee2b1SBill Fenner 			if (parsecreateopres(dp, vflag) != 0)
1591647f50c3SDoug Rabson 				return;
1592647f50c3SDoug Rabson 		} else {
1593943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1594647f50c3SDoug Rabson 				return;
1595647f50c3SDoug Rabson 		}
1596647f50c3SDoug Rabson 		break;
1597647f50c3SDoug Rabson 
1598647f50c3SDoug Rabson 	case NFSPROC_MKNOD:
1599647f50c3SDoug Rabson 		printf(" mknod");
1600943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1601647f50c3SDoug Rabson 			break;
1602943ee2b1SBill Fenner 		if (parsecreateopres(dp, vflag) != 0)
16034edb46e9SPaul Traina 			return;
16044edb46e9SPaul Traina 		break;
16054edb46e9SPaul Traina 
16064edb46e9SPaul Traina 	case NFSPROC_REMOVE:
16074edb46e9SPaul Traina 		printf(" remove");
1608943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
16094edb46e9SPaul Traina 			break;
1610647f50c3SDoug Rabson 		if (v3) {
1611943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
16124edb46e9SPaul Traina 				return;
1613647f50c3SDoug Rabson 		} else {
1614943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
16154edb46e9SPaul Traina 				return;
1616647f50c3SDoug Rabson 		}
16174edb46e9SPaul Traina 		break;
16184edb46e9SPaul Traina 
16194edb46e9SPaul Traina 	case NFSPROC_RMDIR:
16204edb46e9SPaul Traina 		printf(" rmdir");
1621943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1622647f50c3SDoug Rabson 			break;
1623647f50c3SDoug Rabson 		if (v3) {
1624943ee2b1SBill Fenner 			if (parsewccres(dp, vflag))
16254edb46e9SPaul Traina 				return;
1626647f50c3SDoug Rabson 		} else {
1627943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1628647f50c3SDoug Rabson 				return;
1629647f50c3SDoug Rabson 		}
1630647f50c3SDoug Rabson 		break;
1631647f50c3SDoug Rabson 
1632647f50c3SDoug Rabson 	case NFSPROC_RENAME:
1633647f50c3SDoug Rabson 		printf(" rename");
1634943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1635647f50c3SDoug Rabson 			break;
1636647f50c3SDoug Rabson 		if (v3) {
1637943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1638647f50c3SDoug Rabson 				break;
1639647f50c3SDoug Rabson 			if (vflag) {
1640647f50c3SDoug Rabson 				printf(" from:");
1641943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1642647f50c3SDoug Rabson 					break;
1643647f50c3SDoug Rabson 				printf(" to:");
1644943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1645647f50c3SDoug Rabson 					break;
1646647f50c3SDoug Rabson 			}
1647647f50c3SDoug Rabson 			return;
1648647f50c3SDoug Rabson 		} else {
1649943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1650647f50c3SDoug Rabson 				return;
1651647f50c3SDoug Rabson 		}
1652647f50c3SDoug Rabson 		break;
1653647f50c3SDoug Rabson 
1654647f50c3SDoug Rabson 	case NFSPROC_LINK:
1655647f50c3SDoug Rabson 		printf(" link");
1656943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1657647f50c3SDoug Rabson 			break;
1658647f50c3SDoug Rabson 		if (v3) {
1659943ee2b1SBill Fenner 			if (!(dp = parsestatus(dp, &er)))
1660647f50c3SDoug Rabson 				break;
1661647f50c3SDoug Rabson 			if (vflag) {
1662647f50c3SDoug Rabson 				printf(" file POST:");
1663943ee2b1SBill Fenner 				if (!(dp = parse_post_op_attr(dp, vflag)))
1664647f50c3SDoug Rabson 					break;
1665647f50c3SDoug Rabson 				printf(" dir:");
1666943ee2b1SBill Fenner 				if (!(dp = parse_wcc_data(dp, vflag)))
1667647f50c3SDoug Rabson 					break;
1668647f50c3SDoug Rabson 				return;
1669647f50c3SDoug Rabson 			}
1670647f50c3SDoug Rabson 		} else {
1671943ee2b1SBill Fenner 			if (parsestatus(dp, &er) != 0)
1672647f50c3SDoug Rabson 				return;
1673647f50c3SDoug Rabson 		}
16744edb46e9SPaul Traina 		break;
16754edb46e9SPaul Traina 
16764edb46e9SPaul Traina 	case NFSPROC_READDIR:
16774edb46e9SPaul Traina 		printf(" readdir");
1678943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1679647f50c3SDoug Rabson 			break;
1680647f50c3SDoug Rabson 		if (v3) {
1681943ee2b1SBill Fenner 			if (parsev3rddirres(dp, vflag))
1682647f50c3SDoug Rabson 				return;
1683647f50c3SDoug Rabson 		} else {
1684647f50c3SDoug Rabson 			if (parserddires(dp) != 0)
1685647f50c3SDoug Rabson 				return;
1686647f50c3SDoug Rabson 		}
1687647f50c3SDoug Rabson 		break;
1688647f50c3SDoug Rabson 
1689647f50c3SDoug Rabson 	case NFSPROC_READDIRPLUS:
1690647f50c3SDoug Rabson 		printf(" readdirplus");
1691943ee2b1SBill Fenner 		if (!(dp = parserep(rp, length)))
1692647f50c3SDoug Rabson 			break;
1693943ee2b1SBill Fenner 		if (parsev3rddirres(dp, vflag))
16944edb46e9SPaul Traina 			return;
16954edb46e9SPaul Traina 		break;
16964edb46e9SPaul Traina 
1697647f50c3SDoug Rabson 	case NFSPROC_FSSTAT:
1698647f50c3SDoug Rabson 		printf(" fsstat");
16994edb46e9SPaul Traina 		dp = parserep(rp, length);
1700943ee2b1SBill Fenner 		if (dp != NULL && parsestatfs(dp, v3) != 0)
1701647f50c3SDoug Rabson 			return;
1702647f50c3SDoug Rabson 		break;
1703647f50c3SDoug Rabson 
1704647f50c3SDoug Rabson 	case NFSPROC_FSINFO:
1705647f50c3SDoug Rabson 		printf(" fsinfo");
1706647f50c3SDoug Rabson 		dp = parserep(rp, length);
1707943ee2b1SBill Fenner 		if (dp != NULL && parsefsinfo(dp) != 0)
1708647f50c3SDoug Rabson 			return;
1709647f50c3SDoug Rabson 		break;
1710647f50c3SDoug Rabson 
1711647f50c3SDoug Rabson 	case NFSPROC_PATHCONF:
1712647f50c3SDoug Rabson 		printf(" pathconf");
1713647f50c3SDoug Rabson 		dp = parserep(rp, length);
17142ebf6c05SBill Fenner 		if (dp != NULL && parsepathconf(dp) != 0)
1715647f50c3SDoug Rabson 			return;
1716647f50c3SDoug Rabson 		break;
1717647f50c3SDoug Rabson 
1718647f50c3SDoug Rabson 	case NFSPROC_COMMIT:
1719647f50c3SDoug Rabson 		printf(" commit");
1720647f50c3SDoug Rabson 		dp = parserep(rp, length);
17212ebf6c05SBill Fenner 		if (dp != NULL && parsewccres(dp, vflag) != 0)
17224edb46e9SPaul Traina 			return;
17234edb46e9SPaul Traina 		break;
17244edb46e9SPaul Traina 
17254edb46e9SPaul Traina 	default:
17262ebf6c05SBill Fenner 		printf(" proc-%u", proc);
17274edb46e9SPaul Traina 		return;
17284edb46e9SPaul Traina 	}
1729647f50c3SDoug Rabson trunc:
17302ebf6c05SBill Fenner 	if (!nfserr)
17314edb46e9SPaul Traina 		fputs(" [|nfs]", stdout);
17324edb46e9SPaul Traina }
1733