print-nfs.c revision 111729
117680Spst/*
239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2075118Sfenner *
2175118Sfenner * $FreeBSD: head/contrib/tcpdump/print-nfs.c 111729 2003-03-02 08:25:48Z fenner $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
2526183Sfennerstatic const char rcsid[] =
26111729Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.89.4.2 2002/06/01 23:51:14 guy Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2975118Sfenner#ifdef HAVE_CONFIG_H
3075118Sfenner#include "config.h"
3175118Sfenner#endif
3275118Sfenner
3317680Spst#include <sys/param.h>
3417680Spst#include <sys/time.h>
3517680Spst#include <sys/socket.h>
3617680Spst
3717680Spst#include <netinet/in.h>
3817680Spst
3917680Spst#include <rpc/rpc.h>
4017680Spst
4117680Spst#include <ctype.h>
4226183Sfenner#include <pcap.h>
4317680Spst#include <stdio.h>
4417680Spst#include <string.h>
4517680Spst
4617680Spst#include "interface.h"
4717680Spst#include "addrtoname.h"
4817680Spst
4918976Sdfr#include "nfs.h"
5017680Spst#include "nfsfh.h"
5117680Spst
5275118Sfenner#include "ip.h"
5375118Sfenner#ifdef INET6
5475118Sfenner#include "ip6.h"
5575118Sfenner#endif
5675118Sfenner
5775118Sfennerstatic void nfs_printfh(const u_int32_t *, const u_int);
5875118Sfennerstatic void xid_map_enter(const struct rpc_msg *, const u_char *);
5975118Sfennerstatic int32_t xid_map_find(const struct rpc_msg *, const u_char *,
6075118Sfenner			    u_int32_t *, u_int32_t *);
6118976Sdfrstatic void interp_reply(const struct rpc_msg *, u_int32_t, u_int32_t, int);
6218976Sdfrstatic const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
6375118Sfennerstatic void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
6475118Sfennerstatic int print_int64(const u_int32_t *dp, int how);
6575118Sfennerstatic void print_nfsaddr(const u_char *, const char *, const char *);
6617680Spst
6718976Sdfr/*
6818976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
6918976Sdfr */
7018976Sdfru_int32_t nfsv3_procid[NFS_NPROCS] = {
7118976Sdfr	NFSPROC_NULL,
7218976Sdfr	NFSPROC_GETATTR,
7318976Sdfr	NFSPROC_SETATTR,
7418976Sdfr	NFSPROC_NOOP,
7518976Sdfr	NFSPROC_LOOKUP,
7618976Sdfr	NFSPROC_READLINK,
7718976Sdfr	NFSPROC_READ,
7818976Sdfr	NFSPROC_NOOP,
7918976Sdfr	NFSPROC_WRITE,
8018976Sdfr	NFSPROC_CREATE,
8118976Sdfr	NFSPROC_REMOVE,
8218976Sdfr	NFSPROC_RENAME,
8318976Sdfr	NFSPROC_LINK,
8418976Sdfr	NFSPROC_SYMLINK,
8518976Sdfr	NFSPROC_MKDIR,
8618976Sdfr	NFSPROC_RMDIR,
8718976Sdfr	NFSPROC_READDIR,
8818976Sdfr	NFSPROC_FSSTAT,
8918976Sdfr	NFSPROC_NOOP,
9018976Sdfr	NFSPROC_NOOP,
9118976Sdfr	NFSPROC_NOOP,
9218976Sdfr	NFSPROC_NOOP,
9318976Sdfr	NFSPROC_NOOP,
9418976Sdfr	NFSPROC_NOOP,
9518976Sdfr	NFSPROC_NOOP,
9618976Sdfr	NFSPROC_NOOP
9718976Sdfr};
9818976Sdfr
9975118Sfenner/*
10075118Sfenner * NFS V2 and V3 status values.
10175118Sfenner *
10275118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message
10375118Sfenner * strings taken from the FreeBSD C library "errlst.c".
10475118Sfenner *
10575118Sfenner * Others are errors that are not in the RFC but that I suspect some
10675118Sfenner * NFS servers could return; the values are FreeBSD errno values, as
10775118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
10875118Sfenner * was primarily BSD-derived.
10975118Sfenner */
11075118Sfennerstatic struct tok status2str[] = {
11175118Sfenner	{ 1,     "Operation not permitted" },	/* EPERM */
11275118Sfenner	{ 2,     "No such file or directory" },	/* ENOENT */
11375118Sfenner	{ 5,     "Input/output error" },	/* EIO */
11475118Sfenner	{ 6,     "Device not configured" },	/* ENXIO */
11575118Sfenner	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
11675118Sfenner	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
11775118Sfenner	{ 13,    "Permission denied" },		/* EACCES */
11875118Sfenner	{ 17,    "File exists" },		/* EEXIST */
11975118Sfenner	{ 18,    "Cross-device link" },		/* EXDEV */
12075118Sfenner	{ 19,    "Operation not supported by device" }, /* ENODEV */
12175118Sfenner	{ 20,    "Not a directory" },		/* ENOTDIR */
12275118Sfenner	{ 21,    "Is a directory" },		/* EISDIR */
12375118Sfenner	{ 22,    "Invalid argument" },		/* EINVAL */
12475118Sfenner	{ 26,    "Text file busy" },		/* ETXTBSY */
12575118Sfenner	{ 27,    "File too large" },		/* EFBIG */
12675118Sfenner	{ 28,    "No space left on device" },	/* ENOSPC */
12775118Sfenner	{ 30,    "Read-only file system" },	/* EROFS */
12875118Sfenner	{ 31,    "Too many links" },		/* EMLINK */
12975118Sfenner	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
13075118Sfenner	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
13175118Sfenner	{ 63,    "File name too long" },	/* ENAMETOOLONG */
13275118Sfenner	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
13375118Sfenner	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
13475118Sfenner	{ 70,    "Stale NFS file handle" },	/* ESTALE */
13575118Sfenner	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
13675118Sfenner	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
13775118Sfenner	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
13875118Sfenner	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
13975118Sfenner	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
14075118Sfenner	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
14175118Sfenner	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
14275118Sfenner	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
14375118Sfenner	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
14475118Sfenner	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
14575118Sfenner	{ 0,     NULL }
14618976Sdfr};
14718976Sdfr
14875118Sfennerstatic struct tok nfsv3_writemodes[] = {
14975118Sfenner	{ 0,		"unstable" },
15075118Sfenner	{ 1,		"datasync" },
15175118Sfenner	{ 2,		"filesync" },
15275118Sfenner	{ 0,		NULL }
15375118Sfenner};
15475118Sfenner
15518976Sdfrstatic struct tok type2str[] = {
15618976Sdfr	{ NFNON,	"NON" },
15718976Sdfr	{ NFREG,	"REG" },
15818976Sdfr	{ NFDIR,	"DIR" },
15918976Sdfr	{ NFBLK,	"BLK" },
16018976Sdfr	{ NFCHR,	"CHR" },
16118976Sdfr	{ NFLNK,	"LNK" },
16218976Sdfr	{ NFFIFO,	"FIFO" },
16318976Sdfr	{ 0,		NULL }
16418976Sdfr};
16518976Sdfr
16618976Sdfr/*
16718976Sdfr * Print out a 64-bit integer. This appears to be different on each system,
16818976Sdfr * try to make the best of it. The integer stored as 2 consecutive XDR
16918976Sdfr * encoded 32-bit integers, to which a pointer is passed.
17018976Sdfr *
17118976Sdfr * Assume that a system that has INT64_FORMAT defined, has a 64-bit
17218976Sdfr * integer datatype and can print it.
17318976Sdfr */
17418976Sdfr
17518976Sdfr#define UNSIGNED 0
17618976Sdfr#define SIGNED   1
17718976Sdfr#define HEX      2
17818976Sdfr
17975118Sfennerstatic int print_int64(const u_int32_t *dp, int how)
18018976Sdfr{
18118976Sdfr#ifdef INT64_FORMAT
18218976Sdfr	u_int64_t res;
18318976Sdfr
18418976Sdfr	res = ((u_int64_t)ntohl(dp[0]) << 32) | (u_int64_t)ntohl(dp[1]);
18518976Sdfr	switch (how) {
18618976Sdfr	case SIGNED:
18718976Sdfr		printf(INT64_FORMAT, res);
18818976Sdfr		break;
18918976Sdfr	case UNSIGNED:
19018976Sdfr		printf(U_INT64_FORMAT, res);
19118976Sdfr		break;
19218976Sdfr	case HEX:
19318976Sdfr		printf(HEX_INT64_FORMAT, res);
19418976Sdfr		break;
19518976Sdfr	default:
19618976Sdfr		return (0);
19718976Sdfr	}
19818976Sdfr#else
19975118Sfenner	switch (how) {
20075118Sfenner	case SIGNED:
20175118Sfenner	case UNSIGNED:
20275118Sfenner	case HEX:
20375118Sfenner		printf("0x%x%08x", (u_int32_t)ntohl(dp[0]),
20475118Sfenner		    (u_int32_t)ntohl(dp[1]));
20575118Sfenner		break;
20675118Sfenner	default:
20775118Sfenner		return (0);
20875118Sfenner	}
20918976Sdfr#endif
21018976Sdfr	return 1;
21118976Sdfr}
21218976Sdfr
21375118Sfennerstatic void
21475118Sfennerprint_nfsaddr(const u_char *bp, const char *s, const char *d)
21575118Sfenner{
21675118Sfenner	struct ip *ip;
21775118Sfenner#ifdef INET6
21875118Sfenner	struct ip6_hdr *ip6;
21975118Sfenner	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
22075118Sfenner#else
22175118Sfenner#ifndef INET_ADDRSTRLEN
22275118Sfenner#define INET_ADDRSTRLEN	16
22375118Sfenner#endif
22475118Sfenner	char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
22575118Sfenner#endif
22675118Sfenner
22775118Sfenner	srcaddr[0] = dstaddr[0] = '\0';
22875118Sfenner	switch (IP_V((struct ip *)bp)) {
22975118Sfenner	case 4:
23075118Sfenner		ip = (struct ip *)bp;
23175118Sfenner		strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
23275118Sfenner		strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
23375118Sfenner		break;
23475118Sfenner#ifdef INET6
23575118Sfenner	case 6:
23675118Sfenner		ip6 = (struct ip6_hdr *)bp;
23775118Sfenner		strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
23875118Sfenner		    sizeof(srcaddr));
23975118Sfenner		strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
24075118Sfenner		    sizeof(dstaddr));
24175118Sfenner		break;
24275118Sfenner#endif
24375118Sfenner	default:
24475118Sfenner		strlcpy(srcaddr, "?", sizeof(srcaddr));
24575118Sfenner		strlcpy(dstaddr, "?", sizeof(dstaddr));
24675118Sfenner		break;
24775118Sfenner	}
24875118Sfenner
24975118Sfenner	(void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
25075118Sfenner}
25175118Sfenner
25218976Sdfrstatic const u_int32_t *
25318976Sdfrparse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
25418976Sdfr{
25575118Sfenner	TCHECK(dp[0]);
25618976Sdfr	if ((sa3->sa_modeset = ntohl(*dp++))) {
25775118Sfenner		TCHECK(dp[0]);
25818976Sdfr		sa3->sa_mode = ntohl(*dp++);
25918976Sdfr	}
26018976Sdfr
26175118Sfenner	TCHECK(dp[0]);
26218976Sdfr	if ((sa3->sa_uidset = ntohl(*dp++))) {
26375118Sfenner		TCHECK(dp[0]);
26418976Sdfr		sa3->sa_uid = ntohl(*dp++);
26518976Sdfr	}
26618976Sdfr
26775118Sfenner	TCHECK(dp[0]);
26818976Sdfr	if ((sa3->sa_gidset = ntohl(*dp++))) {
26975118Sfenner		TCHECK(dp[0]);
27018976Sdfr		sa3->sa_gid = ntohl(*dp++);
27118976Sdfr	}
27218976Sdfr
27375118Sfenner	TCHECK(dp[0]);
27418976Sdfr	if ((sa3->sa_sizeset = ntohl(*dp++))) {
27575118Sfenner		TCHECK(dp[0]);
27618976Sdfr		sa3->sa_size = ntohl(*dp++);
27718976Sdfr	}
27818976Sdfr
27975118Sfenner	TCHECK(dp[0]);
28018976Sdfr	if ((sa3->sa_atimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
28175118Sfenner		TCHECK(dp[1]);
28218976Sdfr		sa3->sa_atime.nfsv3_sec = ntohl(*dp++);
28318976Sdfr		sa3->sa_atime.nfsv3_nsec = ntohl(*dp++);
28418976Sdfr	}
28518976Sdfr
28675118Sfenner	TCHECK(dp[0]);
28718976Sdfr	if ((sa3->sa_mtimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
28875118Sfenner		TCHECK(dp[1]);
28918976Sdfr		sa3->sa_mtime.nfsv3_sec = ntohl(*dp++);
29018976Sdfr		sa3->sa_mtime.nfsv3_nsec = ntohl(*dp++);
29118976Sdfr	}
29218976Sdfr
29318976Sdfr	return dp;
29475118Sfennertrunc:
29575118Sfenner	return NULL;
29618976Sdfr}
29718976Sdfr
29875118Sfennerstatic int nfserr;		/* true if we error rather than trunc */
29975118Sfenner
30075118Sfennerstatic void
30118976Sdfrprint_sattr3(const struct nfsv3_sattr *sa3, int verbose)
30218976Sdfr{
30318976Sdfr	if (sa3->sa_modeset)
30418976Sdfr		printf(" mode %o", sa3->sa_mode);
30518976Sdfr	if (sa3->sa_uidset)
30618976Sdfr		printf(" uid %u", sa3->sa_uid);
30718976Sdfr	if (sa3->sa_gidset)
30818976Sdfr		printf(" gid %u", sa3->sa_gid);
30918976Sdfr	if (verbose > 1) {
31018976Sdfr		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
31118976Sdfr			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
31218976Sdfr			       sa3->sa_atime.nfsv3_nsec);
31318976Sdfr		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
31418976Sdfr			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
31518976Sdfr			       sa3->sa_mtime.nfsv3_nsec);
31618976Sdfr	}
31718976Sdfr}
31818976Sdfr
31918976Sdfrvoid
32017680Spstnfsreply_print(register const u_char *bp, u_int length,
32117680Spst	       register const u_char *bp2)
32217680Spst{
32317680Spst	register const struct rpc_msg *rp;
32418976Sdfr	u_int32_t proc, vers;
32575118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
32617680Spst
32726183Sfenner	nfserr = 0;		/* assume no error */
32817680Spst	rp = (const struct rpc_msg *)bp;
32917680Spst
33075118Sfenner	if (!nflag) {
33175118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
33275118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
33375118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
33475118Sfenner	} else {
33575118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
33675118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
33775118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
33875118Sfenner	}
33975118Sfenner	print_nfsaddr(bp2, srcid, dstid);
34075118Sfenner	(void)printf("reply %s %d",
34175118Sfenner		     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
34275118Sfenner			     "ok":"ERR",
34317680Spst			     length);
34417680Spst
34575118Sfenner	if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
34618976Sdfr		interp_reply(rp, proc, vers, length);
34717680Spst}
34817680Spst
34917680Spst/*
35017680Spst * Return a pointer to the first file handle in the packet.
35175118Sfenner * If the packet was truncated, return 0.
35217680Spst */
35317680Spststatic const u_int32_t *
35475118Sfennerparsereq(register const struct rpc_msg *rp, register u_int length)
35517680Spst{
35626183Sfenner	register const u_int32_t *dp;
35717680Spst	register u_int len;
35817680Spst
35917680Spst	/*
36017680Spst	 * find the start of the req data (if we captured it)
36117680Spst	 */
36226183Sfenner	dp = (u_int32_t *)&rp->rm_call.cb_cred;
36326183Sfenner	TCHECK(dp[1]);
36426183Sfenner	len = ntohl(dp[1]);
36526183Sfenner	if (len < length) {
36626183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
36726183Sfenner		TCHECK(dp[1]);
36817680Spst		len = ntohl(dp[1]);
36926183Sfenner		if (len < length) {
37026183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
37126183Sfenner			TCHECK2(dp[0], 0);
37226183Sfenner			return (dp);
37317680Spst		}
37417680Spst	}
37526183Sfennertrunc:
37626183Sfenner	return (NULL);
37717680Spst}
37817680Spst
37917680Spst/*
38017680Spst * Print out an NFS file handle and return a pointer to following word.
38175118Sfenner * If packet was truncated, return 0.
38217680Spst */
38317680Spststatic const u_int32_t *
38418976Sdfrparsefh(register const u_int32_t *dp, int v3)
38517680Spst{
38618976Sdfr	int len;
38718976Sdfr
38818976Sdfr	if (v3) {
38926183Sfenner		TCHECK(dp[0]);
39018976Sdfr		len = (int)ntohl(*dp) / 4;
39118976Sdfr		dp++;
39218976Sdfr	} else
39318976Sdfr		len = NFSX_V2FH / 4;
39418976Sdfr
39526183Sfenner	if (TTEST2(*dp, len * sizeof(*dp))) {
39618976Sdfr		nfs_printfh(dp, len);
39718976Sdfr		return (dp + len);
39817680Spst	}
39926183Sfennertrunc:
40026183Sfenner	return (NULL);
40117680Spst}
40217680Spst
40317680Spst/*
40417680Spst * Print out a file name and return pointer to 32-bit word past it.
40575118Sfenner * If packet was truncated, return 0.
40617680Spst */
40717680Spststatic const u_int32_t *
40817680Spstparsefn(register const u_int32_t *dp)
40917680Spst{
41017680Spst	register u_int32_t len;
41117680Spst	register const u_char *cp;
41217680Spst
41317680Spst	/* Bail if we don't have the string length */
41475118Sfenner	TCHECK(*dp);
41517680Spst
41617680Spst	/* Fetch string length; convert to host order */
41717680Spst	len = *dp++;
41817680Spst	NTOHL(len);
41917680Spst
42075118Sfenner	TCHECK2(*dp, ((len + 3) & ~3));
42175118Sfenner
42217680Spst	cp = (u_char *)dp;
42317680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
42417680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
42517680Spst	/* XXX seems like we should be checking the length */
42626183Sfenner	putchar('"');
42717680Spst	(void) fn_printn(cp, len, NULL);
42826183Sfenner	putchar('"');
42917680Spst
43017680Spst	return (dp);
43175118Sfennertrunc:
43275118Sfenner	return NULL;
43317680Spst}
43417680Spst
43517680Spst/*
43617680Spst * Print out file handle and file name.
43717680Spst * Return pointer to 32-bit word past file name.
43875118Sfenner * If packet was truncated (or there was some other error), return 0.
43917680Spst */
44017680Spststatic const u_int32_t *
44118976Sdfrparsefhn(register const u_int32_t *dp, int v3)
44217680Spst{
44318976Sdfr	dp = parsefh(dp, v3);
44426183Sfenner	if (dp == NULL)
44526183Sfenner		return (NULL);
44617680Spst	putchar(' ');
44717680Spst	return (parsefn(dp));
44817680Spst}
44917680Spst
45017680Spstvoid
45117680Spstnfsreq_print(register const u_char *bp, u_int length,
45217680Spst    register const u_char *bp2)
45317680Spst{
45417680Spst	register const struct rpc_msg *rp;
45517680Spst	register const u_int32_t *dp;
45675118Sfenner	nfs_type type;
45775118Sfenner	int v3;
45875118Sfenner	u_int32_t proc;
45918976Sdfr	struct nfsv3_sattr sa3;
46075118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
46117680Spst
46226183Sfenner	nfserr = 0;		/* assume no error */
46317680Spst	rp = (const struct rpc_msg *)bp;
46475118Sfenner	if (!nflag) {
46575118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
46675118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
46775118Sfenner		strlcpy(dstid, "nfs", sizeof(dstid));
46875118Sfenner	} else {
46975118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
47075118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
47175118Sfenner		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
47275118Sfenner	}
47375118Sfenner	print_nfsaddr(bp2, srcid, dstid);
47475118Sfenner	(void)printf("%d", length);
47517680Spst
47675118Sfenner	xid_map_enter(rp, bp2);	/* record proc number for later on */
47717680Spst
47818976Sdfr	v3 = (ntohl(rp->rm_call.cb_vers) == NFS_VER3);
47918976Sdfr	proc = ntohl(rp->rm_call.cb_proc);
48018976Sdfr
48118976Sdfr	if (!v3 && proc < NFS_NPROCS)
48218976Sdfr		proc =  nfsv3_procid[proc];
48318976Sdfr
48418976Sdfr	switch (proc) {
48517680Spst	case NFSPROC_NOOP:
48617680Spst		printf(" nop");
48717680Spst		return;
48817680Spst	case NFSPROC_NULL:
48917680Spst		printf(" null");
49017680Spst		return;
49117680Spst
49217680Spst	case NFSPROC_GETATTR:
49317680Spst		printf(" getattr");
49475118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
49575118Sfenner		    parsefh(dp, v3) != NULL)
49617680Spst			return;
49717680Spst		break;
49817680Spst
49917680Spst	case NFSPROC_SETATTR:
50017680Spst		printf(" setattr");
50175118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
50275118Sfenner		    parsefh(dp, v3) != NULL)
50317680Spst			return;
50417680Spst		break;
50517680Spst
50617680Spst	case NFSPROC_LOOKUP:
50717680Spst		printf(" lookup");
50875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
50975118Sfenner		    parsefhn(dp, v3) != NULL)
51017680Spst			return;
51117680Spst		break;
51217680Spst
51318976Sdfr	case NFSPROC_ACCESS:
51418976Sdfr		printf(" access");
51526183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
51626183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
51775118Sfenner			TCHECK(dp[0]);
51875118Sfenner			printf(" %04x", (u_int32_t)ntohl(dp[0]));
51918976Sdfr			return;
52018976Sdfr		}
52118976Sdfr		break;
52218976Sdfr
52317680Spst	case NFSPROC_READLINK:
52417680Spst		printf(" readlink");
52575118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
52675118Sfenner		    parsefh(dp, v3) != NULL)
52717680Spst			return;
52817680Spst		break;
52917680Spst
53017680Spst	case NFSPROC_READ:
53117680Spst		printf(" read");
53226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
53326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
53418976Sdfr			if (v3) {
53575118Sfenner				TCHECK(dp[2]);
53675118Sfenner				printf(" %u bytes @ ",
53775118Sfenner				       (u_int32_t) ntohl(dp[2]));
53818976Sdfr				print_int64(dp, UNSIGNED);
53918976Sdfr			} else {
54075118Sfenner				TCHECK(dp[1]);
54175118Sfenner				printf(" %u bytes @ %u",
54275118Sfenner				    (u_int32_t)ntohl(dp[1]),
54375118Sfenner				    (u_int32_t)ntohl(dp[0]));
54418976Sdfr			}
54517680Spst			return;
54617680Spst		}
54717680Spst		break;
54817680Spst
54917680Spst	case NFSPROC_WRITE:
55017680Spst		printf(" write");
55126183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55226183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
55318976Sdfr			if (v3) {
55475118Sfenner				TCHECK(dp[4]);
55575118Sfenner				printf(" %u bytes @ ",
55675118Sfenner						(u_int32_t) ntohl(dp[4]));
55718976Sdfr				print_int64(dp, UNSIGNED);
55818976Sdfr				if (vflag) {
55918976Sdfr					dp += 3;
56075118Sfenner					TCHECK(dp[0]);
56118976Sdfr					printf(" <%s>",
56275118Sfenner						tok2str(nfsv3_writemodes,
56375118Sfenner							NULL, ntohl(*dp)));
56418976Sdfr				}
56518976Sdfr			} else {
56675118Sfenner				TCHECK(dp[3]);
56775118Sfenner				printf(" %u (%u) bytes @ %u (%u)",
56875118Sfenner						(u_int32_t)ntohl(dp[3]),
56975118Sfenner						(u_int32_t)ntohl(dp[2]),
57075118Sfenner						(u_int32_t)ntohl(dp[1]),
57175118Sfenner						(u_int32_t)ntohl(dp[0]));
57218976Sdfr			}
57317680Spst			return;
57417680Spst		}
57517680Spst		break;
57617680Spst
57717680Spst	case NFSPROC_CREATE:
57817680Spst		printf(" create");
57975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
58075118Sfenner		    parsefhn(dp, v3) != NULL)
58117680Spst			return;
58217680Spst		break;
58317680Spst
58418976Sdfr	case NFSPROC_MKDIR:
58518976Sdfr		printf(" mkdir");
58675118Sfenner		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
58718976Sdfr			return;
58818976Sdfr		break;
58918976Sdfr
59018976Sdfr	case NFSPROC_SYMLINK:
59118976Sdfr		printf(" symlink");
59275118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
59375118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
59475118Sfenner			fputs(" ->", stdout);
59575118Sfenner			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
59618976Sdfr				break;
59775118Sfenner			if (parsefn(dp) == 0)
59818976Sdfr				break;
59918976Sdfr			if (v3 && vflag)
60018976Sdfr				print_sattr3(&sa3, vflag);
60118976Sdfr			return;
60218976Sdfr		}
60318976Sdfr		break;
60418976Sdfr
60518976Sdfr	case NFSPROC_MKNOD:
60618976Sdfr		printf(" mknod");
60775118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
60875118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
60975118Sfenner			TCHECK(*dp);
61075118Sfenner			type = (nfs_type)ntohl(*dp++);
61175118Sfenner			if ((dp = parse_sattr3(dp, &sa3)) == 0)
61218976Sdfr				break;
61318976Sdfr			printf(" %s", tok2str(type2str, "unk-ft %d", type));
61418976Sdfr			if (vflag && (type == NFCHR || type == NFBLK)) {
61575118Sfenner				TCHECK(dp[1]);
61675118Sfenner				printf(" %u/%u",
61775118Sfenner				       (u_int32_t)ntohl(dp[0]),
61875118Sfenner				       (u_int32_t)ntohl(dp[1]));
61918976Sdfr				dp += 2;
62018976Sdfr			}
62118976Sdfr			if (vflag)
62218976Sdfr				print_sattr3(&sa3, vflag);
62318976Sdfr			return;
62418976Sdfr		}
62518976Sdfr		break;
62618976Sdfr
62717680Spst	case NFSPROC_REMOVE:
62817680Spst		printf(" remove");
62975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
63075118Sfenner		    parsefhn(dp, v3) != NULL)
63117680Spst			return;
63217680Spst		break;
63317680Spst
63418976Sdfr	case NFSPROC_RMDIR:
63518976Sdfr		printf(" rmdir");
63675118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
63775118Sfenner		    parsefhn(dp, v3) != NULL)
63818976Sdfr			return;
63918976Sdfr		break;
64018976Sdfr
64117680Spst	case NFSPROC_RENAME:
64217680Spst		printf(" rename");
64326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
64426183Sfenner		    (dp = parsefhn(dp, v3)) != NULL) {
64517680Spst			fputs(" ->", stdout);
64626183Sfenner			if (parsefhn(dp, v3) != NULL)
64717680Spst				return;
64817680Spst		}
64917680Spst		break;
65017680Spst
65117680Spst	case NFSPROC_LINK:
65217680Spst		printf(" link");
65326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
65426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
65517680Spst			fputs(" ->", stdout);
65626183Sfenner			if (parsefhn(dp, v3) != NULL)
65717680Spst				return;
65817680Spst		}
65917680Spst		break;
66017680Spst
66118976Sdfr	case NFSPROC_READDIR:
66218976Sdfr		printf(" readdir");
66326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
66426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
66518976Sdfr			if (v3) {
66675118Sfenner				TCHECK(dp[4]);
66718976Sdfr				/*
66818976Sdfr				 * We shouldn't really try to interpret the
66918976Sdfr				 * offset cookie here.
67018976Sdfr				 */
67175118Sfenner				printf(" %u bytes @ ",
67275118Sfenner				    (u_int32_t) ntohl(dp[4]));
67318976Sdfr				print_int64(dp, SIGNED);
67418976Sdfr				if (vflag)
67526183Sfenner					printf(" verf %08x%08x", dp[2],
67618976Sdfr					       dp[3]);
67718976Sdfr			} else {
67875118Sfenner				TCHECK(dp[1]);
67918976Sdfr				/*
68018976Sdfr				 * Print the offset as signed, since -1 is
68118976Sdfr				 * common, but offsets > 2^31 aren't.
68218976Sdfr				 */
68375118Sfenner				printf(" %u bytes @ %d",
68475118Sfenner				    (u_int32_t)ntohl(dp[1]),
68575118Sfenner				    (u_int32_t)ntohl(dp[0]));
68618976Sdfr			}
68718976Sdfr			return;
68817680Spst		}
68917680Spst		break;
69017680Spst
69118976Sdfr	case NFSPROC_READDIRPLUS:
69218976Sdfr		printf(" readdirplus");
69326183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
69426183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
69575118Sfenner			TCHECK(dp[4]);
69618976Sdfr			/*
69718976Sdfr			 * We don't try to interpret the offset
69818976Sdfr			 * cookie here.
69918976Sdfr			 */
70075118Sfenner			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[4]));
70118976Sdfr			print_int64(dp, SIGNED);
70218976Sdfr			if (vflag)
70375118Sfenner				printf(" max %u verf %08x%08x",
70475118Sfenner				       (u_int32_t) ntohl(dp[5]), dp[2], dp[3]);
70517680Spst			return;
70618976Sdfr		}
70717680Spst		break;
70817680Spst
70918976Sdfr	case NFSPROC_FSSTAT:
71018976Sdfr		printf(" fsstat");
71175118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
71275118Sfenner		    parsefh(dp, v3) != NULL)
71317680Spst			return;
71417680Spst		break;
71517680Spst
71618976Sdfr	case NFSPROC_FSINFO:
71718976Sdfr		printf(" fsinfo");
718111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
719111729Sfenner		    parsefh(dp, v3) != NULL)
720111729Sfenner			return;
72118976Sdfr		break;
72218976Sdfr
72318976Sdfr	case NFSPROC_PATHCONF:
72418976Sdfr		printf(" pathconf");
725111729Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
726111729Sfenner		    parsefh(dp, v3) != NULL)
727111729Sfenner			return;
72818976Sdfr		break;
72918976Sdfr
73018976Sdfr	case NFSPROC_COMMIT:
73118976Sdfr		printf(" commit");
73226183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
73326183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
73475118Sfenner			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[2]));
73518976Sdfr			print_int64(dp, UNSIGNED);
73617680Spst			return;
73717680Spst		}
73817680Spst		break;
73917680Spst
74017680Spst	default:
74175118Sfenner		printf(" proc-%u", (u_int32_t)ntohl(rp->rm_call.cb_proc));
74217680Spst		return;
74317680Spst	}
74475118Sfenner
74517680Spsttrunc:
74626183Sfenner	if (!nfserr)
74726183Sfenner		fputs(" [|nfs]", stdout);
74817680Spst}
74917680Spst
75017680Spst/*
75117680Spst * Print out an NFS file handle.
75217680Spst * We assume packet was not truncated before the end of the
75317680Spst * file handle pointed to by dp.
75417680Spst *
75517680Spst * Note: new version (using portable file-handle parser) doesn't produce
75617680Spst * generation number.  It probably could be made to do that, with some
75717680Spst * additional hacking on the parser code.
75817680Spst */
75917680Spststatic void
76075118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len)
76117680Spst{
76217680Spst	my_fsid fsid;
76317680Spst	ino_t ino;
76417680Spst	char *sfsname = NULL;
76517680Spst
76675118Sfenner	Parse_fh((caddr_t*)dp, len, &fsid, &ino, NULL, &sfsname, 0);
76717680Spst
76817680Spst	if (sfsname) {
76926183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
77026183Sfenner		static char temp[NFSX_V3FHMAX+1];
77117680Spst
77226183Sfenner		/* Make sure string is null-terminated */
77326183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
77475118Sfenner		temp[sizeof(temp) - 1] = '\0';
77526183Sfenner		/* Remove trailing spaces */
77626183Sfenner		sfsname = strchr(temp, ' ');
77726183Sfenner		if (sfsname)
77826183Sfenner			*sfsname = 0;
77917680Spst
78075118Sfenner		(void)printf(" fh %s/", temp);
78126183Sfenner	} else {
78275118Sfenner		(void)printf(" fh %d,%d/",
78375118Sfenner			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
78417680Spst	}
78575118Sfenner
78675118Sfenner	if(fsid.Fsid_dev.Minor == 257 && uflag)
78775118Sfenner		/* Print the undecoded handle */
78875118Sfenner		(void)printf("%s", fsid.Opaque_Handle);
78975118Sfenner	else
79075118Sfenner		(void)printf("%ld", (long) ino);
79117680Spst}
79217680Spst
79317680Spst/*
79417680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
79517680Spst * us to match up replies with requests and thus to know how to parse
79617680Spst * the reply.
79717680Spst */
79817680Spst
79917680Spststruct xid_map_entry {
80075118Sfenner	u_int32_t	xid;		/* transaction ID (net order) */
80175118Sfenner	int ipver;			/* IP version (4 or 6) */
80275118Sfenner#ifdef INET6
80375118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
80475118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
80575118Sfenner#else
80617680Spst	struct in_addr	client;		/* client IP address (net order) */
80717680Spst	struct in_addr	server;		/* server IP address (net order) */
80875118Sfenner#endif
80975118Sfenner	u_int32_t	proc;		/* call proc number (host order) */
81075118Sfenner	u_int32_t	vers;		/* program version (host order) */
81117680Spst};
81217680Spst
81317680Spst/*
81417680Spst * Map entries are kept in an array that we manage as a ring;
81517680Spst * new entries are always added at the tail of the ring.  Initially,
81617680Spst * all the entries are zero and hence don't match anything.
81717680Spst */
81817680Spst
81917680Spst#define	XIDMAPSIZE	64
82017680Spst
82117680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
82217680Spst
82317680Spstint	xid_map_next = 0;
82417680Spstint	xid_map_hint = 0;
82517680Spst
82617680Spststatic void
82775118Sfennerxid_map_enter(const struct rpc_msg *rp, const u_char *bp)
82817680Spst{
82975118Sfenner	struct ip *ip = NULL;
83075118Sfenner#ifdef INET6
83175118Sfenner	struct ip6_hdr *ip6 = NULL;
83275118Sfenner#endif
83317680Spst	struct xid_map_entry *xmep;
83417680Spst
83575118Sfenner	switch (IP_V((struct ip *)bp)) {
83675118Sfenner	case 4:
83775118Sfenner		ip = (struct ip *)bp;
83875118Sfenner		break;
83975118Sfenner#ifdef INET6
84075118Sfenner	case 6:
84175118Sfenner		ip6 = (struct ip6_hdr *)bp;
84275118Sfenner		break;
84375118Sfenner#endif
84475118Sfenner	default:
84575118Sfenner		return;
84675118Sfenner	}
84775118Sfenner
84817680Spst	xmep = &xid_map[xid_map_next];
84917680Spst
85017680Spst	if (++xid_map_next >= XIDMAPSIZE)
85117680Spst		xid_map_next = 0;
85217680Spst
85317680Spst	xmep->xid = rp->rm_xid;
85475118Sfenner	if (ip) {
85575118Sfenner		xmep->ipver = 4;
85675118Sfenner		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
85775118Sfenner		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
85875118Sfenner	}
85975118Sfenner#ifdef INET6
86075118Sfenner	else if (ip6) {
86175118Sfenner		xmep->ipver = 6;
86275118Sfenner		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
86375118Sfenner		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
86475118Sfenner	}
86575118Sfenner#endif
86617680Spst	xmep->proc = ntohl(rp->rm_call.cb_proc);
86718976Sdfr	xmep->vers = ntohl(rp->rm_call.cb_vers);
86817680Spst}
86917680Spst
87026183Sfenner/*
87126183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
87226183Sfenner * version in vers return, or returns -1 on failure
87326183Sfenner */
87418976Sdfrstatic int
87575118Sfennerxid_map_find(const struct rpc_msg *rp, const u_char *bp, u_int32_t *proc,
87618976Sdfr	     u_int32_t *vers)
87717680Spst{
87817680Spst	int i;
87917680Spst	struct xid_map_entry *xmep;
88017680Spst	u_int32_t xid = rp->rm_xid;
88175118Sfenner	struct ip *ip = (struct ip *)bp;
88275118Sfenner#ifdef INET6
88375118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
88475118Sfenner#endif
88575118Sfenner	int cmp;
88617680Spst
88717680Spst	/* Start searching from where we last left off */
88875118Sfenner	i = xid_map_hint;
88917680Spst	do {
89017680Spst		xmep = &xid_map[i];
89175118Sfenner		cmp = 1;
89275118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
89375118Sfenner			goto nextitem;
89475118Sfenner		switch (xmep->ipver) {
89575118Sfenner		case 4:
89675118Sfenner			if (memcmp(&ip->ip_src, &xmep->server,
89775118Sfenner				   sizeof(ip->ip_src)) != 0 ||
89875118Sfenner			    memcmp(&ip->ip_dst, &xmep->client,
89975118Sfenner				   sizeof(ip->ip_dst)) != 0) {
90075118Sfenner				cmp = 0;
90175118Sfenner			}
90275118Sfenner			break;
90375118Sfenner#ifdef INET6
90475118Sfenner		case 6:
90575118Sfenner			if (memcmp(&ip6->ip6_src, &xmep->server,
90675118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
90775118Sfenner			    memcmp(&ip6->ip6_dst, &xmep->client,
90875118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
90975118Sfenner				cmp = 0;
91075118Sfenner			}
91175118Sfenner			break;
91275118Sfenner#endif
91375118Sfenner		default:
91475118Sfenner			cmp = 0;
91575118Sfenner			break;
91675118Sfenner		}
91775118Sfenner		if (cmp) {
91817680Spst			/* match */
91917680Spst			xid_map_hint = i;
92018976Sdfr			*proc = xmep->proc;
92118976Sdfr			*vers = xmep->vers;
92218976Sdfr			return 0;
92317680Spst		}
92475118Sfenner	nextitem:
92517680Spst		if (++i >= XIDMAPSIZE)
92617680Spst			i = 0;
92717680Spst	} while (i != xid_map_hint);
92817680Spst
92917680Spst	/* search failed */
93075118Sfenner	return (-1);
93117680Spst}
93217680Spst
93317680Spst/*
93417680Spst * Routines for parsing reply packets
93517680Spst */
93617680Spst
93717680Spst/*
93817680Spst * Return a pointer to the beginning of the actual results.
93975118Sfenner * If the packet was truncated, return 0.
94017680Spst */
94117680Spststatic const u_int32_t *
94275118Sfennerparserep(register const struct rpc_msg *rp, register u_int length)
94317680Spst{
94417680Spst	register const u_int32_t *dp;
94575118Sfenner	u_int len;
94617680Spst	enum accept_stat astat;
94717680Spst
94817680Spst	/*
94917680Spst	 * Portability note:
95017680Spst	 * Here we find the address of the ar_verf credentials.
95117680Spst	 * Originally, this calculation was
95217680Spst	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
95317680Spst	 * On the wire, the rp_acpt field starts immediately after
95417680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
95517680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
95617680Spst	 * whose internal representation contains a pointer, so on a
95717680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
95817680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
95917680Spst	 * the internal representation to parse the on-the-wire
96017680Spst	 * representation.  Instead, we skip past the rp_stat field,
96117680Spst	 * which is an "enum" and so occupies one 32-bit word.
96217680Spst	 */
96317680Spst	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
96475118Sfenner	TCHECK(dp[1]);
96517680Spst	len = ntohl(dp[1]);
96617680Spst	if (len >= length)
96726183Sfenner		return (NULL);
96817680Spst	/*
96917680Spst	 * skip past the ar_verf credentials.
97017680Spst	 */
97117680Spst	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
97226183Sfenner	TCHECK2(dp[0], 0);
97317680Spst
97417680Spst	/*
97517680Spst	 * now we can check the ar_stat field
97617680Spst	 */
97717680Spst	astat = ntohl(*(enum accept_stat *)dp);
97817680Spst	switch (astat) {
97917680Spst
98017680Spst	case SUCCESS:
98117680Spst		break;
98217680Spst
98317680Spst	case PROG_UNAVAIL:
98417680Spst		printf(" PROG_UNAVAIL");
98526183Sfenner		nfserr = 1;		/* suppress trunc string */
98626183Sfenner		return (NULL);
98717680Spst
98817680Spst	case PROG_MISMATCH:
98917680Spst		printf(" PROG_MISMATCH");
99026183Sfenner		nfserr = 1;		/* suppress trunc string */
99126183Sfenner		return (NULL);
99217680Spst
99317680Spst	case PROC_UNAVAIL:
99417680Spst		printf(" PROC_UNAVAIL");
99526183Sfenner		nfserr = 1;		/* suppress trunc string */
99626183Sfenner		return (NULL);
99717680Spst
99817680Spst	case GARBAGE_ARGS:
99917680Spst		printf(" GARBAGE_ARGS");
100026183Sfenner		nfserr = 1;		/* suppress trunc string */
100126183Sfenner		return (NULL);
100217680Spst
100317680Spst	case SYSTEM_ERR:
100417680Spst		printf(" SYSTEM_ERR");
100526183Sfenner		nfserr = 1;		/* suppress trunc string */
100626183Sfenner		return (NULL);
100717680Spst
100817680Spst	default:
100917680Spst		printf(" ar_stat %d", astat);
101026183Sfenner		nfserr = 1;		/* suppress trunc string */
101126183Sfenner		return (NULL);
101217680Spst	}
101317680Spst	/* successful return */
101475118Sfenner	TCHECK2(*dp, sizeof(astat));
101575118Sfenner	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
101626183Sfennertrunc:
101775118Sfenner	return (0);
101817680Spst}
101917680Spst
102017680Spststatic const u_int32_t *
102118976Sdfrparsestatus(const u_int32_t *dp, int *er)
102217680Spst{
102375118Sfenner	int errnum;
102417680Spst
102526183Sfenner	TCHECK(dp[0]);
102675118Sfenner
102726183Sfenner	errnum = ntohl(dp[0]);
102818976Sdfr	if (er)
102926183Sfenner		*er = errnum;
103026183Sfenner	if (errnum != 0) {
103126183Sfenner		if (!qflag)
103275118Sfenner			printf(" ERROR: %s",
103375118Sfenner			    tok2str(status2str, "unk %d", errnum));
103426183Sfenner		nfserr = 1;
103517680Spst	}
103617680Spst	return (dp + 1);
103726183Sfennertrunc:
103875118Sfenner	return NULL;
103917680Spst}
104017680Spst
104117680Spststatic const u_int32_t *
104218976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3)
104317680Spst{
104418976Sdfr	const struct nfs_fattr *fap;
104517680Spst
104618976Sdfr	fap = (const struct nfs_fattr *)dp;
104726184Sfenner	TCHECK(fap->fa_gid);
104817680Spst	if (verbose) {
104975118Sfenner		printf(" %s %o ids %d/%d",
105075118Sfenner		    tok2str(type2str, "unk-ft %d ",
105175118Sfenner		    (u_int32_t)ntohl(fap->fa_type)),
105275118Sfenner		    (u_int32_t)ntohl(fap->fa_mode),
105375118Sfenner		    (u_int32_t)ntohl(fap->fa_uid),
105475118Sfenner		    (u_int32_t) ntohl(fap->fa_gid));
105518976Sdfr		if (v3) {
105626184Sfenner			TCHECK(fap->fa3_size);
105718976Sdfr			printf(" sz ");
105818976Sdfr			print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED);
105918976Sdfr			putchar(' ');
106026184Sfenner		} else {
106126184Sfenner			TCHECK(fap->fa2_size);
106275118Sfenner			printf(" sz %d ", (u_int32_t) ntohl(fap->fa2_size));
106318976Sdfr		}
106417680Spst	}
106517680Spst	/* print lots more stuff */
106617680Spst	if (verbose > 1) {
106718976Sdfr		if (v3) {
106826184Sfenner			TCHECK(fap->fa3_ctime);
106975118Sfenner			printf("nlink %d rdev %d/%d ",
107075118Sfenner			       (u_int32_t)ntohl(fap->fa_nlink),
107175118Sfenner			       (u_int32_t) ntohl(fap->fa3_rdev.specdata1),
107275118Sfenner			       (u_int32_t) ntohl(fap->fa3_rdev.specdata2));
107318976Sdfr			printf("fsid ");
107418976Sdfr			print_int64((u_int32_t *)&fap->fa2_fsid, HEX);
107518976Sdfr			printf(" nodeid ");
107618976Sdfr			print_int64((u_int32_t *)&fap->fa2_fileid, HEX);
107775118Sfenner			printf(" a/m/ctime %u.%06u ",
107875118Sfenner			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_sec),
107975118Sfenner			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_nsec));
108075118Sfenner			printf("%u.%06u ",
108175118Sfenner			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_sec),
108275118Sfenner			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_nsec));
108375118Sfenner			printf("%u.%06u ",
108475118Sfenner			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_sec),
108575118Sfenner			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_nsec));
108618976Sdfr		} else {
108726184Sfenner			TCHECK(fap->fa2_ctime);
108875118Sfenner			printf("nlink %d rdev %x fsid %x nodeid %x a/m/ctime ",
108975118Sfenner			       (u_int32_t) ntohl(fap->fa_nlink),
109075118Sfenner			       (u_int32_t) ntohl(fap->fa2_rdev),
109175118Sfenner			       (u_int32_t) ntohl(fap->fa2_fsid),
109275118Sfenner			       (u_int32_t) ntohl(fap->fa2_fileid));
109375118Sfenner			printf("%u.%06u ",
109475118Sfenner			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_sec),
109575118Sfenner			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_usec));
109675118Sfenner			printf("%u.%06u ",
109775118Sfenner			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_sec),
109875118Sfenner			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_usec));
109975118Sfenner			printf("%u.%06u ",
110075118Sfenner			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_sec),
110175118Sfenner			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_usec));
110218976Sdfr		}
110317680Spst	}
110418976Sdfr	return ((const u_int32_t *)((unsigned char *)dp +
110518976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
110626184Sfennertrunc:
110726184Sfenner	return (NULL);
110817680Spst}
110917680Spst
111017680Spststatic int
111118976Sdfrparseattrstat(const u_int32_t *dp, int verbose, int v3)
111217680Spst{
111318976Sdfr	int er;
111418976Sdfr
111518976Sdfr	dp = parsestatus(dp, &er);
1116111729Sfenner	if (dp == NULL)
111717680Spst		return (0);
1118111729Sfenner	if (er)
1119111729Sfenner		return (1);
112017680Spst
112126183Sfenner	return (parsefattr(dp, verbose, v3) != NULL);
112217680Spst}
112317680Spst
112417680Spststatic int
112517680Spstparsediropres(const u_int32_t *dp)
112617680Spst{
112718976Sdfr	int er;
112818976Sdfr
1129111729Sfenner	if (!(dp = parsestatus(dp, &er)))
113017680Spst		return (0);
1131111729Sfenner	if (er)
1132111729Sfenner		return (1);
113317680Spst
113418976Sdfr	dp = parsefh(dp, 0);
113517680Spst	if (dp == NULL)
113617680Spst		return (0);
113717680Spst
113818976Sdfr	return (parsefattr(dp, vflag, 0) != NULL);
113917680Spst}
114017680Spst
114117680Spststatic int
114218976Sdfrparselinkres(const u_int32_t *dp, int v3)
114317680Spst{
114418976Sdfr	int er;
114518976Sdfr
114618976Sdfr	dp = parsestatus(dp, &er);
1147111729Sfenner	if (dp == NULL)
114817680Spst		return(0);
1149111729Sfenner	if (er)
1150111729Sfenner		return(1);
115175118Sfenner	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
115218976Sdfr		return (0);
115317680Spst	putchar(' ');
115417680Spst	return (parsefn(dp) != NULL);
115517680Spst}
115617680Spst
115717680Spststatic int
115818976Sdfrparsestatfs(const u_int32_t *dp, int v3)
115917680Spst{
116018976Sdfr	const struct nfs_statfs *sfsp;
116118976Sdfr	int er;
116217680Spst
116318976Sdfr	dp = parsestatus(dp, &er);
1164111729Sfenner	if (dp == NULL)
116575118Sfenner		return (0);
1166111729Sfenner	if (!v3 && er)
1167111729Sfenner		return (1);
116817680Spst
116918976Sdfr	if (qflag)
117018976Sdfr		return(1);
117118976Sdfr
117218976Sdfr	if (v3) {
117318976Sdfr		if (vflag)
117418976Sdfr			printf(" POST:");
117575118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
117618976Sdfr			return (0);
117717680Spst	}
117817680Spst
1179111729Sfenner	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
118018976Sdfr
118118976Sdfr	sfsp = (const struct nfs_statfs *)dp;
118218976Sdfr
118318976Sdfr	if (v3) {
118418976Sdfr		printf(" tbytes ");
118518976Sdfr		print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED);
118618976Sdfr		printf(" fbytes ");
118718976Sdfr		print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED);
118818976Sdfr		printf(" abytes ");
118918976Sdfr		print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED);
119018976Sdfr		if (vflag) {
119118976Sdfr			printf(" tfiles ");
119218976Sdfr			print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED);
119318976Sdfr			printf(" ffiles ");
119418976Sdfr			print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED);
119518976Sdfr			printf(" afiles ");
119618976Sdfr			print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED);
119775118Sfenner			printf(" invar %u",
119875118Sfenner			       (u_int32_t) ntohl(sfsp->sf_invarsec));
119918976Sdfr		}
120018976Sdfr	} else {
120175118Sfenner		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
120275118Sfenner			(u_int32_t)ntohl(sfsp->sf_tsize),
120375118Sfenner			(u_int32_t)ntohl(sfsp->sf_bsize),
120475118Sfenner			(u_int32_t)ntohl(sfsp->sf_blocks),
120575118Sfenner			(u_int32_t)ntohl(sfsp->sf_bfree),
120675118Sfenner			(u_int32_t)ntohl(sfsp->sf_bavail));
120718976Sdfr	}
120818976Sdfr
120917680Spst	return (1);
121026184Sfennertrunc:
121126184Sfenner	return (0);
121217680Spst}
121317680Spst
121417680Spststatic int
121517680Spstparserddires(const u_int32_t *dp)
121617680Spst{
121718976Sdfr	int er;
121818976Sdfr
121918976Sdfr	dp = parsestatus(dp, &er);
1220111729Sfenner	if (dp == NULL)
122117680Spst		return (0);
1222111729Sfenner	if (er)
1223111729Sfenner		return (1);
122418976Sdfr	if (qflag)
122518976Sdfr		return (1);
122618976Sdfr
122726184Sfenner	TCHECK(dp[2]);
122875118Sfenner	printf(" offset %x size %d ",
122975118Sfenner	       (u_int32_t)ntohl(dp[0]), (u_int32_t)ntohl(dp[1]));
123018976Sdfr	if (dp[2] != 0)
123175118Sfenner		printf(" eof");
123218976Sdfr
123318976Sdfr	return (1);
123426184Sfennertrunc:
123526184Sfenner	return (0);
123618976Sdfr}
123718976Sdfr
123818976Sdfrstatic const u_int32_t *
123918976Sdfrparse_wcc_attr(const u_int32_t *dp)
124018976Sdfr{
124118976Sdfr	printf(" sz ");
124218976Sdfr	print_int64(dp, UNSIGNED);
124375118Sfenner	printf(" mtime %u.%06u ctime %u.%06u",
124475118Sfenner	       (u_int32_t)ntohl(dp[2]), (u_int32_t)ntohl(dp[3]),
124575118Sfenner	       (u_int32_t)ntohl(dp[4]), (u_int32_t)ntohl(dp[5]));
124618976Sdfr	return (dp + 6);
124718976Sdfr}
124818976Sdfr
124918976Sdfr/*
125018976Sdfr * Pre operation attributes. Print only if vflag > 1.
125118976Sdfr */
125218976Sdfrstatic const u_int32_t *
125318976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose)
125418976Sdfr{
125526184Sfenner	TCHECK(dp[0]);
125618976Sdfr	if (!ntohl(dp[0]))
125718976Sdfr		return (dp + 1);
125818976Sdfr	dp++;
1259111729Sfenner	TCHECK2(*dp, 24);
126018976Sdfr	if (verbose > 1) {
126118976Sdfr		return parse_wcc_attr(dp);
126218976Sdfr	} else {
126318976Sdfr		/* If not verbose enough, just skip over wcc_attr */
126418976Sdfr		return (dp + 6);
126517680Spst	}
126626184Sfennertrunc:
126726184Sfenner	return (NULL);
126818976Sdfr}
126917680Spst
127018976Sdfr/*
127118976Sdfr * Post operation attributes are printed if vflag >= 1
127218976Sdfr */
127318976Sdfrstatic const u_int32_t *
127418976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose)
127518976Sdfr{
127626184Sfenner	TCHECK(dp[0]);
127718976Sdfr	if (!ntohl(dp[0]))
127818976Sdfr		return (dp + 1);
127918976Sdfr	dp++;
128018976Sdfr	if (verbose) {
128118976Sdfr		return parsefattr(dp, verbose, 1);
128218976Sdfr	} else
128318976Sdfr		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
128426184Sfennertrunc:
128526184Sfenner	return (NULL);
128618976Sdfr}
128718976Sdfr
128818976Sdfrstatic const u_int32_t *
128918976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose)
129018976Sdfr{
129118976Sdfr	if (verbose > 1)
129218976Sdfr		printf(" PRE:");
129375118Sfenner	if (!(dp = parse_pre_op_attr(dp, verbose)))
129475118Sfenner		return (0);
129518976Sdfr
129618976Sdfr	if (verbose)
129718976Sdfr		printf(" POST:");
129818976Sdfr	return parse_post_op_attr(dp, verbose);
129918976Sdfr}
130018976Sdfr
130118976Sdfrstatic const u_int32_t *
130218976Sdfrparsecreateopres(const u_int32_t *dp, int verbose)
130318976Sdfr{
130418976Sdfr	int er;
130518976Sdfr
130675118Sfenner	if (!(dp = parsestatus(dp, &er)))
130775118Sfenner		return (0);
130818976Sdfr	if (er)
130918976Sdfr		dp = parse_wcc_data(dp, verbose);
131018976Sdfr	else {
131126184Sfenner		TCHECK(dp[0]);
131218976Sdfr		if (!ntohl(dp[0]))
131318976Sdfr			return (dp + 1);
131418976Sdfr		dp++;
131575118Sfenner		if (!(dp = parsefh(dp, 1)))
131675118Sfenner			return (0);
131718976Sdfr		if (verbose) {
131875118Sfenner			if (!(dp = parse_post_op_attr(dp, verbose)))
131975118Sfenner				return (0);
132018976Sdfr			if (vflag > 1) {
132118976Sdfr				printf("dir attr:");
132218976Sdfr				dp = parse_wcc_data(dp, verbose);
132318976Sdfr			}
132418976Sdfr		}
132518976Sdfr	}
132618976Sdfr	return (dp);
132726184Sfennertrunc:
132826184Sfenner	return (NULL);
132918976Sdfr}
133018976Sdfr
133118976Sdfrstatic int
133218976Sdfrparsewccres(const u_int32_t *dp, int verbose)
133318976Sdfr{
133418976Sdfr	int er;
133518976Sdfr
133675118Sfenner	if (!(dp = parsestatus(dp, &er)))
133718976Sdfr		return (0);
133875118Sfenner	return parse_wcc_data(dp, verbose) != 0;
133918976Sdfr}
134018976Sdfr
134118976Sdfrstatic const u_int32_t *
134218976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose)
134318976Sdfr{
134418976Sdfr	int er;
134518976Sdfr
134675118Sfenner	if (!(dp = parsestatus(dp, &er)))
134775118Sfenner		return (0);
134818976Sdfr	if (vflag)
134918976Sdfr		printf(" POST:");
135075118Sfenner	if (!(dp = parse_post_op_attr(dp, verbose)))
135175118Sfenner		return (0);
135218976Sdfr	if (er)
135318976Sdfr		return dp;
135418976Sdfr	if (vflag) {
135526184Sfenner		TCHECK(dp[1]);
135626183Sfenner		printf(" verf %08x%08x", dp[0], dp[1]);
135718976Sdfr		dp += 2;
135818976Sdfr	}
135918976Sdfr	return dp;
136026184Sfennertrunc:
136126184Sfenner	return (NULL);
136218976Sdfr}
136318976Sdfr
136418976Sdfrstatic int
136518976Sdfrparsefsinfo(const u_int32_t *dp)
136618976Sdfr{
136718976Sdfr	struct nfsv3_fsinfo *sfp;
136818976Sdfr	int er;
136918976Sdfr
137075118Sfenner	if (!(dp = parsestatus(dp, &er)))
137118976Sdfr		return (0);
137218976Sdfr	if (vflag)
137318976Sdfr		printf(" POST:");
137475118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
137518976Sdfr		return (0);
137618976Sdfr	if (er)
137718976Sdfr		return (1);
137818976Sdfr
137918976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
138026184Sfenner	TCHECK(*sfp);
138175118Sfenner	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
138275118Sfenner	       (u_int32_t) ntohl(sfp->fs_rtmax),
138375118Sfenner	       (u_int32_t) ntohl(sfp->fs_rtpref),
138475118Sfenner	       (u_int32_t) ntohl(sfp->fs_wtmax),
138575118Sfenner	       (u_int32_t) ntohl(sfp->fs_wtpref),
138675118Sfenner	       (u_int32_t) ntohl(sfp->fs_dtpref));
138718976Sdfr	if (vflag) {
138875118Sfenner		printf(" rtmult %u wtmult %u maxfsz ",
138975118Sfenner		       (u_int32_t) ntohl(sfp->fs_rtmult),
139075118Sfenner		       (u_int32_t) ntohl(sfp->fs_wtmult));
139118976Sdfr		print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED);
139275118Sfenner		printf(" delta %u.%06u ",
139375118Sfenner		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_sec),
139475118Sfenner		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_nsec));
139518976Sdfr	}
1396111729Sfenner	return (1);
1397111729Sfennertrunc:
139875118Sfenner	return (0);
139918976Sdfr}
140018976Sdfr
140118976Sdfrstatic int
140218976Sdfrparsepathconf(const u_int32_t *dp)
140318976Sdfr{
140418976Sdfr	int er;
140518976Sdfr	struct nfsv3_pathconf *spp;
140618976Sdfr
140775118Sfenner	if (!(dp = parsestatus(dp, &er)))
140818976Sdfr		return (0);
140918976Sdfr	if (vflag)
141018976Sdfr		printf(" POST:");
141175118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
141218976Sdfr		return (0);
141318976Sdfr	if (er)
141418976Sdfr		return (1);
141518976Sdfr
141618976Sdfr	spp = (struct nfsv3_pathconf *)dp;
141726184Sfenner	TCHECK(*spp);
141818976Sdfr
141975118Sfenner	printf(" linkmax %u namemax %u %s %s %s %s",
142075118Sfenner	       (u_int32_t) ntohl(spp->pc_linkmax),
142175118Sfenner	       (u_int32_t) ntohl(spp->pc_namemax),
142218976Sdfr	       ntohl(spp->pc_notrunc) ? "notrunc" : "",
142318976Sdfr	       ntohl(spp->pc_chownrestricted) ? "chownres" : "",
142418976Sdfr	       ntohl(spp->pc_caseinsensitive) ? "igncase" : "",
142518976Sdfr	       ntohl(spp->pc_casepreserving) ? "keepcase" : "");
1426111729Sfenner	return (1);
1427111729Sfennertrunc:
142875118Sfenner	return (0);
142917680Spst}
143075118Sfenner
143117680Spststatic void
143218976Sdfrinterp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
143317680Spst{
143417680Spst	register const u_int32_t *dp;
143518976Sdfr	register int v3;
143618976Sdfr	int er;
143717680Spst
143818976Sdfr	v3 = (vers == NFS_VER3);
143918976Sdfr
144018976Sdfr	if (!v3 && proc < NFS_NPROCS)
144118976Sdfr		proc = nfsv3_procid[proc];
144218976Sdfr
144317680Spst	switch (proc) {
144417680Spst
144517680Spst	case NFSPROC_NOOP:
144617680Spst		printf(" nop");
144717680Spst		return;
144818976Sdfr
144917680Spst	case NFSPROC_NULL:
145017680Spst		printf(" null");
145117680Spst		return;
145217680Spst
145317680Spst	case NFSPROC_GETATTR:
145417680Spst		printf(" getattr");
145517680Spst		dp = parserep(rp, length);
145626183Sfenner		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
145717680Spst			return;
145817680Spst		break;
145917680Spst
146017680Spst	case NFSPROC_SETATTR:
146117680Spst		printf(" setattr");
146275118Sfenner		if (!(dp = parserep(rp, length)))
146317680Spst			return;
146418976Sdfr		if (v3) {
146575118Sfenner			if (parsewccres(dp, vflag))
146618976Sdfr				return;
146718976Sdfr		} else {
146818976Sdfr			if (parseattrstat(dp, !qflag, 0) != 0)
146918976Sdfr				return;
147018976Sdfr		}
147117680Spst		break;
147217680Spst
147317680Spst	case NFSPROC_LOOKUP:
147417680Spst		printf(" lookup");
147575118Sfenner		if (!(dp = parserep(rp, length)))
147618976Sdfr			break;
147718976Sdfr		if (v3) {
147875118Sfenner			if (!(dp = parsestatus(dp, &er)))
147918976Sdfr				break;
148018976Sdfr			if (er) {
148118976Sdfr				if (vflag > 1) {
148218976Sdfr					printf(" post dattr:");
148318976Sdfr					dp = parse_post_op_attr(dp, vflag);
148418976Sdfr				}
148518976Sdfr			} else {
148675118Sfenner				if (!(dp = parsefh(dp, v3)))
148718976Sdfr					break;
148875118Sfenner				if ((dp = parse_post_op_attr(dp, vflag)) &&
148975118Sfenner				    vflag > 1) {
149018976Sdfr					printf(" post dattr:");
149118976Sdfr					dp = parse_post_op_attr(dp, vflag);
149218976Sdfr				}
149318976Sdfr			}
149475118Sfenner			if (dp)
149518976Sdfr				return;
149618976Sdfr		} else {
149718976Sdfr			if (parsediropres(dp) != 0)
149818976Sdfr				return;
149918976Sdfr		}
150017680Spst		break;
150117680Spst
150218976Sdfr	case NFSPROC_ACCESS:
150318976Sdfr		printf(" access");
150498527Sfenner		if (!(dp = parserep(rp, length)))
150598527Sfenner			break;
150675118Sfenner		if (!(dp = parsestatus(dp, &er)))
150718976Sdfr			break;
150818976Sdfr		if (vflag)
150918976Sdfr			printf(" attr:");
151075118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
151118976Sdfr			break;
151218976Sdfr		if (!er)
151375118Sfenner			printf(" c %04x", (u_int32_t)ntohl(dp[0]));
151418976Sdfr		return;
151518976Sdfr
151617680Spst	case NFSPROC_READLINK:
151717680Spst		printf(" readlink");
151817680Spst		dp = parserep(rp, length);
151926183Sfenner		if (dp != NULL && parselinkres(dp, v3) != 0)
152017680Spst			return;
152117680Spst		break;
152217680Spst
152317680Spst	case NFSPROC_READ:
152417680Spst		printf(" read");
152575118Sfenner		if (!(dp = parserep(rp, length)))
152618976Sdfr			break;
152718976Sdfr		if (v3) {
152875118Sfenner			if (!(dp = parsestatus(dp, &er)))
152918976Sdfr				break;
153075118Sfenner			if (!(dp = parse_post_op_attr(dp, vflag)))
153118976Sdfr				break;
153218976Sdfr			if (er)
153318976Sdfr				return;
153418976Sdfr			if (vflag) {
153575118Sfenner				TCHECK(dp[1]);
153675118Sfenner				printf("%u bytes", (u_int32_t) ntohl(dp[0]));
153718976Sdfr				if (ntohl(dp[1]))
153818976Sdfr					printf(" EOF");
153918976Sdfr			}
154017680Spst			return;
154118976Sdfr		} else {
154218976Sdfr			if (parseattrstat(dp, vflag, 0) != 0)
154318976Sdfr				return;
154418976Sdfr		}
154517680Spst		break;
154617680Spst
154717680Spst	case NFSPROC_WRITE:
154817680Spst		printf(" write");
154975118Sfenner		if (!(dp = parserep(rp, length)))
155018976Sdfr			break;
155118976Sdfr		if (v3) {
155275118Sfenner			if (!(dp = parsestatus(dp, &er)))
155318976Sdfr				break;
155475118Sfenner			if (!(dp = parse_wcc_data(dp, vflag)))
155518976Sdfr				break;
155618976Sdfr			if (er)
155718976Sdfr				return;
155818976Sdfr			if (vflag) {
155975118Sfenner				TCHECK(dp[0]);
156075118Sfenner				printf("%u bytes", (u_int32_t) ntohl(dp[0]));
156118976Sdfr				if (vflag > 1) {
156275118Sfenner					TCHECK(dp[1]);
156318976Sdfr					printf(" <%s>",
156475118Sfenner						tok2str(nfsv3_writemodes,
156575118Sfenner							NULL, ntohl(dp[1])));
156618976Sdfr				}
156718976Sdfr				return;
156818976Sdfr			}
156918976Sdfr		} else {
157018976Sdfr			if (parseattrstat(dp, vflag, v3) != 0)
157118976Sdfr				return;
157218976Sdfr		}
157317680Spst		break;
157417680Spst
157517680Spst	case NFSPROC_CREATE:
157617680Spst		printf(" create");
157775118Sfenner		if (!(dp = parserep(rp, length)))
157818976Sdfr			break;
157918976Sdfr		if (v3) {
158075118Sfenner			if (parsecreateopres(dp, vflag) != 0)
158118976Sdfr				return;
158218976Sdfr		} else {
158318976Sdfr			if (parsediropres(dp) != 0)
158418976Sdfr				return;
158518976Sdfr		}
158618976Sdfr		break;
158718976Sdfr
158818976Sdfr	case NFSPROC_MKDIR:
158918976Sdfr		printf(" mkdir");
159075118Sfenner		if (!(dp = parserep(rp, length)))
159118976Sdfr			break;
159218976Sdfr		if (v3) {
159375118Sfenner			if (parsecreateopres(dp, vflag) != 0)
159418976Sdfr				return;
159518976Sdfr		} else {
159618976Sdfr			if (parsediropres(dp) != 0)
159718976Sdfr				return;
159818976Sdfr		}
159918976Sdfr		break;
160018976Sdfr
160118976Sdfr	case NFSPROC_SYMLINK:
160218976Sdfr		printf(" symlink");
160375118Sfenner		if (!(dp = parserep(rp, length)))
160418976Sdfr			break;
160518976Sdfr		if (v3) {
160675118Sfenner			if (parsecreateopres(dp, vflag) != 0)
160718976Sdfr				return;
160818976Sdfr		} else {
160975118Sfenner			if (parsestatus(dp, &er) != 0)
161018976Sdfr				return;
161118976Sdfr		}
161218976Sdfr		break;
161318976Sdfr
161418976Sdfr	case NFSPROC_MKNOD:
161518976Sdfr		printf(" mknod");
161675118Sfenner		if (!(dp = parserep(rp, length)))
161718976Sdfr			break;
161875118Sfenner		if (parsecreateopres(dp, vflag) != 0)
161917680Spst			return;
162017680Spst		break;
162117680Spst
162217680Spst	case NFSPROC_REMOVE:
162317680Spst		printf(" remove");
162475118Sfenner		if (!(dp = parserep(rp, length)))
162518976Sdfr			break;
162618976Sdfr		if (v3) {
162775118Sfenner			if (parsewccres(dp, vflag))
162818976Sdfr				return;
162918976Sdfr		} else {
163075118Sfenner			if (parsestatus(dp, &er) != 0)
163118976Sdfr				return;
163218976Sdfr		}
163317680Spst		break;
163417680Spst
163518976Sdfr	case NFSPROC_RMDIR:
163618976Sdfr		printf(" rmdir");
163775118Sfenner		if (!(dp = parserep(rp, length)))
163818976Sdfr			break;
163918976Sdfr		if (v3) {
164075118Sfenner			if (parsewccres(dp, vflag))
164118976Sdfr				return;
164218976Sdfr		} else {
164375118Sfenner			if (parsestatus(dp, &er) != 0)
164418976Sdfr				return;
164518976Sdfr		}
164618976Sdfr		break;
164718976Sdfr
164817680Spst	case NFSPROC_RENAME:
164917680Spst		printf(" rename");
165075118Sfenner		if (!(dp = parserep(rp, length)))
165118976Sdfr			break;
165218976Sdfr		if (v3) {
165375118Sfenner			if (!(dp = parsestatus(dp, &er)))
165418976Sdfr				break;
165518976Sdfr			if (vflag) {
165618976Sdfr				printf(" from:");
165775118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
165818976Sdfr					break;
165918976Sdfr				printf(" to:");
166075118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
166118976Sdfr					break;
166218976Sdfr			}
166317680Spst			return;
166418976Sdfr		} else {
166575118Sfenner			if (parsestatus(dp, &er) != 0)
166618976Sdfr				return;
166718976Sdfr		}
166817680Spst		break;
166917680Spst
167017680Spst	case NFSPROC_LINK:
167117680Spst		printf(" link");
167275118Sfenner		if (!(dp = parserep(rp, length)))
167318976Sdfr			break;
167418976Sdfr		if (v3) {
167575118Sfenner			if (!(dp = parsestatus(dp, &er)))
167618976Sdfr				break;
167718976Sdfr			if (vflag) {
167818976Sdfr				printf(" file POST:");
167975118Sfenner				if (!(dp = parse_post_op_attr(dp, vflag)))
168018976Sdfr					break;
168118976Sdfr				printf(" dir:");
168275118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
168318976Sdfr					break;
168418976Sdfr				return;
168518976Sdfr			}
168618976Sdfr		} else {
168775118Sfenner			if (parsestatus(dp, &er) != 0)
168818976Sdfr				return;
168918976Sdfr		}
169017680Spst		break;
169117680Spst
169218976Sdfr	case NFSPROC_READDIR:
169318976Sdfr		printf(" readdir");
169475118Sfenner		if (!(dp = parserep(rp, length)))
169518976Sdfr			break;
169618976Sdfr		if (v3) {
169775118Sfenner			if (parsev3rddirres(dp, vflag))
169818976Sdfr				return;
169918976Sdfr		} else {
170018976Sdfr			if (parserddires(dp) != 0)
170118976Sdfr				return;
170218976Sdfr		}
170318976Sdfr		break;
170418976Sdfr
170518976Sdfr	case NFSPROC_READDIRPLUS:
170618976Sdfr		printf(" readdirplus");
170775118Sfenner		if (!(dp = parserep(rp, length)))
170818976Sdfr			break;
170975118Sfenner		if (parsev3rddirres(dp, vflag))
171017680Spst			return;
171117680Spst		break;
171217680Spst
171318976Sdfr	case NFSPROC_FSSTAT:
171418976Sdfr		printf(" fsstat");
171517680Spst		dp = parserep(rp, length);
171675118Sfenner		if (dp != NULL && parsestatfs(dp, v3) != 0)
171717680Spst			return;
171817680Spst		break;
171917680Spst
172018976Sdfr	case NFSPROC_FSINFO:
172118976Sdfr		printf(" fsinfo");
172217680Spst		dp = parserep(rp, length);
172375118Sfenner		if (dp != NULL && parsefsinfo(dp) != 0)
172417680Spst			return;
172517680Spst		break;
172617680Spst
172718976Sdfr	case NFSPROC_PATHCONF:
172818976Sdfr		printf(" pathconf");
172917680Spst		dp = parserep(rp, length);
173026183Sfenner		if (dp != NULL && parsepathconf(dp) != 0)
173117680Spst			return;
173217680Spst		break;
173317680Spst
173418976Sdfr	case NFSPROC_COMMIT:
173518976Sdfr		printf(" commit");
173617680Spst		dp = parserep(rp, length);
173726183Sfenner		if (dp != NULL && parsewccres(dp, vflag) != 0)
173817680Spst			return;
173917680Spst		break;
174017680Spst
174117680Spst	default:
174226183Sfenner		printf(" proc-%u", proc);
174317680Spst		return;
174417680Spst	}
174518976Sdfrtrunc:
174626183Sfenner	if (!nfserr)
174726183Sfenner		fputs(" [|nfs]", stdout);
174817680Spst}
1749