print-nfs.c revision 75118
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 75118 2001-04-03 07:50:46Z fenner $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
2526183Sfennerstatic const char rcsid[] =
2675118Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.87 2000/10/07 05:53:12 itojun 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
3775118Sfennerstruct mbuf;
3875118Sfennerstruct rtentry;
3917680Spst
4017680Spst#include <netinet/in.h>
4117680Spst
4217680Spst#include <rpc/rpc.h>
4317680Spst
4417680Spst#include <ctype.h>
4526183Sfenner#include <pcap.h>
4617680Spst#include <stdio.h>
4717680Spst#include <string.h>
4817680Spst
4917680Spst#include "interface.h"
5017680Spst#include "addrtoname.h"
5117680Spst
5218976Sdfr#include "nfs.h"
5317680Spst#include "nfsfh.h"
5417680Spst
5575118Sfenner#include "ip.h"
5675118Sfenner#ifdef INET6
5775118Sfenner#include "ip6.h"
5875118Sfenner#endif
5975118Sfenner
6075118Sfennerstatic void nfs_printfh(const u_int32_t *, const u_int);
6175118Sfennerstatic void xid_map_enter(const struct rpc_msg *, const u_char *);
6275118Sfennerstatic int32_t xid_map_find(const struct rpc_msg *, const u_char *,
6375118Sfenner			    u_int32_t *, u_int32_t *);
6418976Sdfrstatic void interp_reply(const struct rpc_msg *, u_int32_t, u_int32_t, int);
6518976Sdfrstatic const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
6675118Sfennerstatic void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
6775118Sfennerstatic int print_int64(const u_int32_t *dp, int how);
6875118Sfennerstatic void print_nfsaddr(const u_char *, const char *, const char *);
6917680Spst
7018976Sdfr/*
7118976Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
7218976Sdfr */
7318976Sdfru_int32_t nfsv3_procid[NFS_NPROCS] = {
7418976Sdfr	NFSPROC_NULL,
7518976Sdfr	NFSPROC_GETATTR,
7618976Sdfr	NFSPROC_SETATTR,
7718976Sdfr	NFSPROC_NOOP,
7818976Sdfr	NFSPROC_LOOKUP,
7918976Sdfr	NFSPROC_READLINK,
8018976Sdfr	NFSPROC_READ,
8118976Sdfr	NFSPROC_NOOP,
8218976Sdfr	NFSPROC_WRITE,
8318976Sdfr	NFSPROC_CREATE,
8418976Sdfr	NFSPROC_REMOVE,
8518976Sdfr	NFSPROC_RENAME,
8618976Sdfr	NFSPROC_LINK,
8718976Sdfr	NFSPROC_SYMLINK,
8818976Sdfr	NFSPROC_MKDIR,
8918976Sdfr	NFSPROC_RMDIR,
9018976Sdfr	NFSPROC_READDIR,
9118976Sdfr	NFSPROC_FSSTAT,
9218976Sdfr	NFSPROC_NOOP,
9318976Sdfr	NFSPROC_NOOP,
9418976Sdfr	NFSPROC_NOOP,
9518976Sdfr	NFSPROC_NOOP,
9618976Sdfr	NFSPROC_NOOP,
9718976Sdfr	NFSPROC_NOOP,
9818976Sdfr	NFSPROC_NOOP,
9918976Sdfr	NFSPROC_NOOP
10018976Sdfr};
10118976Sdfr
10275118Sfenner/*
10375118Sfenner * NFS V2 and V3 status values.
10475118Sfenner *
10575118Sfenner * Some of these come from the RFCs for NFS V2 and V3, with the message
10675118Sfenner * strings taken from the FreeBSD C library "errlst.c".
10775118Sfenner *
10875118Sfenner * Others are errors that are not in the RFC but that I suspect some
10975118Sfenner * NFS servers could return; the values are FreeBSD errno values, as
11075118Sfenner * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
11175118Sfenner * was primarily BSD-derived.
11275118Sfenner */
11375118Sfennerstatic struct tok status2str[] = {
11475118Sfenner	{ 1,     "Operation not permitted" },	/* EPERM */
11575118Sfenner	{ 2,     "No such file or directory" },	/* ENOENT */
11675118Sfenner	{ 5,     "Input/output error" },	/* EIO */
11775118Sfenner	{ 6,     "Device not configured" },	/* ENXIO */
11875118Sfenner	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
11975118Sfenner	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
12075118Sfenner	{ 13,    "Permission denied" },		/* EACCES */
12175118Sfenner	{ 17,    "File exists" },		/* EEXIST */
12275118Sfenner	{ 18,    "Cross-device link" },		/* EXDEV */
12375118Sfenner	{ 19,    "Operation not supported by device" }, /* ENODEV */
12475118Sfenner	{ 20,    "Not a directory" },		/* ENOTDIR */
12575118Sfenner	{ 21,    "Is a directory" },		/* EISDIR */
12675118Sfenner	{ 22,    "Invalid argument" },		/* EINVAL */
12775118Sfenner	{ 26,    "Text file busy" },		/* ETXTBSY */
12875118Sfenner	{ 27,    "File too large" },		/* EFBIG */
12975118Sfenner	{ 28,    "No space left on device" },	/* ENOSPC */
13075118Sfenner	{ 30,    "Read-only file system" },	/* EROFS */
13175118Sfenner	{ 31,    "Too many links" },		/* EMLINK */
13275118Sfenner	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
13375118Sfenner	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
13475118Sfenner	{ 63,    "File name too long" },	/* ENAMETOOLONG */
13575118Sfenner	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
13675118Sfenner	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
13775118Sfenner	{ 70,    "Stale NFS file handle" },	/* ESTALE */
13875118Sfenner	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
13975118Sfenner	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
14075118Sfenner	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
14175118Sfenner	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
14275118Sfenner	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
14375118Sfenner	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
14475118Sfenner	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
14575118Sfenner	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
14675118Sfenner	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
14775118Sfenner	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
14875118Sfenner	{ 0,     NULL }
14918976Sdfr};
15018976Sdfr
15175118Sfennerstatic struct tok nfsv3_writemodes[] = {
15275118Sfenner	{ 0,		"unstable" },
15375118Sfenner	{ 1,		"datasync" },
15475118Sfenner	{ 2,		"filesync" },
15575118Sfenner	{ 0,		NULL }
15675118Sfenner};
15775118Sfenner
15818976Sdfrstatic struct tok type2str[] = {
15918976Sdfr	{ NFNON,	"NON" },
16018976Sdfr	{ NFREG,	"REG" },
16118976Sdfr	{ NFDIR,	"DIR" },
16218976Sdfr	{ NFBLK,	"BLK" },
16318976Sdfr	{ NFCHR,	"CHR" },
16418976Sdfr	{ NFLNK,	"LNK" },
16518976Sdfr	{ NFFIFO,	"FIFO" },
16618976Sdfr	{ 0,		NULL }
16718976Sdfr};
16818976Sdfr
16918976Sdfr/*
17018976Sdfr * Print out a 64-bit integer. This appears to be different on each system,
17118976Sdfr * try to make the best of it. The integer stored as 2 consecutive XDR
17218976Sdfr * encoded 32-bit integers, to which a pointer is passed.
17318976Sdfr *
17418976Sdfr * Assume that a system that has INT64_FORMAT defined, has a 64-bit
17518976Sdfr * integer datatype and can print it.
17618976Sdfr */
17718976Sdfr
17818976Sdfr#define UNSIGNED 0
17918976Sdfr#define SIGNED   1
18018976Sdfr#define HEX      2
18118976Sdfr
18275118Sfennerstatic int print_int64(const u_int32_t *dp, int how)
18318976Sdfr{
18418976Sdfr#ifdef INT64_FORMAT
18518976Sdfr	u_int64_t res;
18618976Sdfr
18718976Sdfr	res = ((u_int64_t)ntohl(dp[0]) << 32) | (u_int64_t)ntohl(dp[1]);
18818976Sdfr	switch (how) {
18918976Sdfr	case SIGNED:
19018976Sdfr		printf(INT64_FORMAT, res);
19118976Sdfr		break;
19218976Sdfr	case UNSIGNED:
19318976Sdfr		printf(U_INT64_FORMAT, res);
19418976Sdfr		break;
19518976Sdfr	case HEX:
19618976Sdfr		printf(HEX_INT64_FORMAT, res);
19718976Sdfr		break;
19818976Sdfr	default:
19918976Sdfr		return (0);
20018976Sdfr	}
20118976Sdfr#else
20275118Sfenner	switch (how) {
20375118Sfenner	case SIGNED:
20475118Sfenner	case UNSIGNED:
20575118Sfenner	case HEX:
20675118Sfenner		printf("0x%x%08x", (u_int32_t)ntohl(dp[0]),
20775118Sfenner		    (u_int32_t)ntohl(dp[1]));
20875118Sfenner		break;
20975118Sfenner	default:
21075118Sfenner		return (0);
21175118Sfenner	}
21218976Sdfr#endif
21318976Sdfr	return 1;
21418976Sdfr}
21518976Sdfr
21675118Sfennerstatic void
21775118Sfennerprint_nfsaddr(const u_char *bp, const char *s, const char *d)
21875118Sfenner{
21975118Sfenner	struct ip *ip;
22075118Sfenner#ifdef INET6
22175118Sfenner	struct ip6_hdr *ip6;
22275118Sfenner	char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
22375118Sfenner#else
22475118Sfenner#ifndef INET_ADDRSTRLEN
22575118Sfenner#define INET_ADDRSTRLEN	16
22675118Sfenner#endif
22775118Sfenner	char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
22875118Sfenner#endif
22975118Sfenner
23075118Sfenner	srcaddr[0] = dstaddr[0] = '\0';
23175118Sfenner	switch (IP_V((struct ip *)bp)) {
23275118Sfenner	case 4:
23375118Sfenner		ip = (struct ip *)bp;
23475118Sfenner		strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
23575118Sfenner		strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
23675118Sfenner		break;
23775118Sfenner#ifdef INET6
23875118Sfenner	case 6:
23975118Sfenner		ip6 = (struct ip6_hdr *)bp;
24075118Sfenner		strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
24175118Sfenner		    sizeof(srcaddr));
24275118Sfenner		strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
24375118Sfenner		    sizeof(dstaddr));
24475118Sfenner		break;
24575118Sfenner#endif
24675118Sfenner	default:
24775118Sfenner		strlcpy(srcaddr, "?", sizeof(srcaddr));
24875118Sfenner		strlcpy(dstaddr, "?", sizeof(dstaddr));
24975118Sfenner		break;
25075118Sfenner	}
25175118Sfenner
25275118Sfenner	(void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
25375118Sfenner}
25475118Sfenner
25518976Sdfrstatic const u_int32_t *
25618976Sdfrparse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
25718976Sdfr{
25875118Sfenner	TCHECK(dp[0]);
25918976Sdfr	if ((sa3->sa_modeset = ntohl(*dp++))) {
26075118Sfenner		TCHECK(dp[0]);
26118976Sdfr		sa3->sa_mode = ntohl(*dp++);
26218976Sdfr	}
26318976Sdfr
26475118Sfenner	TCHECK(dp[0]);
26518976Sdfr	if ((sa3->sa_uidset = ntohl(*dp++))) {
26675118Sfenner		TCHECK(dp[0]);
26718976Sdfr		sa3->sa_uid = ntohl(*dp++);
26818976Sdfr	}
26918976Sdfr
27075118Sfenner	TCHECK(dp[0]);
27118976Sdfr	if ((sa3->sa_gidset = ntohl(*dp++))) {
27275118Sfenner		TCHECK(dp[0]);
27318976Sdfr		sa3->sa_gid = ntohl(*dp++);
27418976Sdfr	}
27518976Sdfr
27675118Sfenner	TCHECK(dp[0]);
27718976Sdfr	if ((sa3->sa_sizeset = ntohl(*dp++))) {
27875118Sfenner		TCHECK(dp[0]);
27918976Sdfr		sa3->sa_size = ntohl(*dp++);
28018976Sdfr	}
28118976Sdfr
28275118Sfenner	TCHECK(dp[0]);
28318976Sdfr	if ((sa3->sa_atimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
28475118Sfenner		TCHECK(dp[1]);
28518976Sdfr		sa3->sa_atime.nfsv3_sec = ntohl(*dp++);
28618976Sdfr		sa3->sa_atime.nfsv3_nsec = ntohl(*dp++);
28718976Sdfr	}
28818976Sdfr
28975118Sfenner	TCHECK(dp[0]);
29018976Sdfr	if ((sa3->sa_mtimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
29175118Sfenner		TCHECK(dp[1]);
29218976Sdfr		sa3->sa_mtime.nfsv3_sec = ntohl(*dp++);
29318976Sdfr		sa3->sa_mtime.nfsv3_nsec = ntohl(*dp++);
29418976Sdfr	}
29518976Sdfr
29618976Sdfr	return dp;
29775118Sfennertrunc:
29875118Sfenner	return NULL;
29918976Sdfr}
30018976Sdfr
30175118Sfennerstatic int nfserr;		/* true if we error rather than trunc */
30275118Sfenner
30375118Sfennerstatic void
30418976Sdfrprint_sattr3(const struct nfsv3_sattr *sa3, int verbose)
30518976Sdfr{
30618976Sdfr	if (sa3->sa_modeset)
30718976Sdfr		printf(" mode %o", sa3->sa_mode);
30818976Sdfr	if (sa3->sa_uidset)
30918976Sdfr		printf(" uid %u", sa3->sa_uid);
31018976Sdfr	if (sa3->sa_gidset)
31118976Sdfr		printf(" gid %u", sa3->sa_gid);
31218976Sdfr	if (verbose > 1) {
31318976Sdfr		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
31418976Sdfr			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
31518976Sdfr			       sa3->sa_atime.nfsv3_nsec);
31618976Sdfr		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
31718976Sdfr			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
31818976Sdfr			       sa3->sa_mtime.nfsv3_nsec);
31918976Sdfr	}
32018976Sdfr}
32118976Sdfr
32218976Sdfrvoid
32317680Spstnfsreply_print(register const u_char *bp, u_int length,
32417680Spst	       register const u_char *bp2)
32517680Spst{
32617680Spst	register const struct rpc_msg *rp;
32718976Sdfr	u_int32_t proc, vers;
32875118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
32917680Spst
33026183Sfenner	nfserr = 0;		/* assume no error */
33117680Spst	rp = (const struct rpc_msg *)bp;
33217680Spst
33375118Sfenner	if (!nflag) {
33475118Sfenner		strlcpy(srcid, "nfs", sizeof(srcid));
33575118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
33675118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
33775118Sfenner	} else {
33875118Sfenner		snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
33975118Sfenner		snprintf(dstid, sizeof(dstid), "%u",
34075118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
34175118Sfenner	}
34275118Sfenner	print_nfsaddr(bp2, srcid, dstid);
34375118Sfenner	(void)printf("reply %s %d",
34475118Sfenner		     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
34575118Sfenner			     "ok":"ERR",
34617680Spst			     length);
34717680Spst
34875118Sfenner	if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
34918976Sdfr		interp_reply(rp, proc, vers, length);
35017680Spst}
35117680Spst
35217680Spst/*
35317680Spst * Return a pointer to the first file handle in the packet.
35475118Sfenner * If the packet was truncated, return 0.
35517680Spst */
35617680Spststatic const u_int32_t *
35775118Sfennerparsereq(register const struct rpc_msg *rp, register u_int length)
35817680Spst{
35926183Sfenner	register const u_int32_t *dp;
36017680Spst	register u_int len;
36117680Spst
36217680Spst	/*
36317680Spst	 * find the start of the req data (if we captured it)
36417680Spst	 */
36526183Sfenner	dp = (u_int32_t *)&rp->rm_call.cb_cred;
36626183Sfenner	TCHECK(dp[1]);
36726183Sfenner	len = ntohl(dp[1]);
36826183Sfenner	if (len < length) {
36926183Sfenner		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
37026183Sfenner		TCHECK(dp[1]);
37117680Spst		len = ntohl(dp[1]);
37226183Sfenner		if (len < length) {
37326183Sfenner			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
37426183Sfenner			TCHECK2(dp[0], 0);
37526183Sfenner			return (dp);
37617680Spst		}
37717680Spst	}
37826183Sfennertrunc:
37926183Sfenner	return (NULL);
38017680Spst}
38117680Spst
38217680Spst/*
38317680Spst * Print out an NFS file handle and return a pointer to following word.
38475118Sfenner * If packet was truncated, return 0.
38517680Spst */
38617680Spststatic const u_int32_t *
38718976Sdfrparsefh(register const u_int32_t *dp, int v3)
38817680Spst{
38918976Sdfr	int len;
39018976Sdfr
39118976Sdfr	if (v3) {
39226183Sfenner		TCHECK(dp[0]);
39318976Sdfr		len = (int)ntohl(*dp) / 4;
39418976Sdfr		dp++;
39518976Sdfr	} else
39618976Sdfr		len = NFSX_V2FH / 4;
39718976Sdfr
39826183Sfenner	if (TTEST2(*dp, len * sizeof(*dp))) {
39918976Sdfr		nfs_printfh(dp, len);
40018976Sdfr		return (dp + len);
40117680Spst	}
40226183Sfennertrunc:
40326183Sfenner	return (NULL);
40417680Spst}
40517680Spst
40617680Spst/*
40717680Spst * Print out a file name and return pointer to 32-bit word past it.
40875118Sfenner * If packet was truncated, return 0.
40917680Spst */
41017680Spststatic const u_int32_t *
41117680Spstparsefn(register const u_int32_t *dp)
41217680Spst{
41317680Spst	register u_int32_t len;
41417680Spst	register const u_char *cp;
41517680Spst
41617680Spst	/* Bail if we don't have the string length */
41775118Sfenner	TCHECK(*dp);
41817680Spst
41917680Spst	/* Fetch string length; convert to host order */
42017680Spst	len = *dp++;
42117680Spst	NTOHL(len);
42217680Spst
42375118Sfenner	TCHECK2(*dp, ((len + 3) & ~3));
42475118Sfenner
42517680Spst	cp = (u_char *)dp;
42617680Spst	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
42717680Spst	dp += ((len + 3) & ~3) / sizeof(*dp);
42817680Spst	/* XXX seems like we should be checking the length */
42926183Sfenner	putchar('"');
43017680Spst	(void) fn_printn(cp, len, NULL);
43126183Sfenner	putchar('"');
43217680Spst
43317680Spst	return (dp);
43475118Sfennertrunc:
43575118Sfenner	return NULL;
43617680Spst}
43717680Spst
43817680Spst/*
43917680Spst * Print out file handle and file name.
44017680Spst * Return pointer to 32-bit word past file name.
44175118Sfenner * If packet was truncated (or there was some other error), return 0.
44217680Spst */
44317680Spststatic const u_int32_t *
44418976Sdfrparsefhn(register const u_int32_t *dp, int v3)
44517680Spst{
44618976Sdfr	dp = parsefh(dp, v3);
44726183Sfenner	if (dp == NULL)
44826183Sfenner		return (NULL);
44917680Spst	putchar(' ');
45017680Spst	return (parsefn(dp));
45117680Spst}
45217680Spst
45317680Spstvoid
45417680Spstnfsreq_print(register const u_char *bp, u_int length,
45517680Spst    register const u_char *bp2)
45617680Spst{
45717680Spst	register const struct rpc_msg *rp;
45817680Spst	register const u_int32_t *dp;
45975118Sfenner	nfs_type type;
46075118Sfenner	int v3;
46175118Sfenner	u_int32_t proc;
46218976Sdfr	struct nfsv3_sattr sa3;
46375118Sfenner	char srcid[20], dstid[20];	/*fits 32bit*/
46417680Spst
46526183Sfenner	nfserr = 0;		/* assume no error */
46617680Spst	rp = (const struct rpc_msg *)bp;
46775118Sfenner	if (!nflag) {
46875118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
46975118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
47075118Sfenner		strlcpy(dstid, "nfs", sizeof(dstid));
47175118Sfenner	} else {
47275118Sfenner		snprintf(srcid, sizeof(srcid), "%u",
47375118Sfenner		    (u_int32_t)ntohl(rp->rm_xid));
47475118Sfenner		snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
47575118Sfenner	}
47675118Sfenner	print_nfsaddr(bp2, srcid, dstid);
47775118Sfenner	(void)printf("%d", length);
47817680Spst
47975118Sfenner	xid_map_enter(rp, bp2);	/* record proc number for later on */
48017680Spst
48118976Sdfr	v3 = (ntohl(rp->rm_call.cb_vers) == NFS_VER3);
48218976Sdfr	proc = ntohl(rp->rm_call.cb_proc);
48318976Sdfr
48418976Sdfr	if (!v3 && proc < NFS_NPROCS)
48518976Sdfr		proc =  nfsv3_procid[proc];
48618976Sdfr
48718976Sdfr	switch (proc) {
48817680Spst	case NFSPROC_NOOP:
48917680Spst		printf(" nop");
49017680Spst		return;
49117680Spst	case NFSPROC_NULL:
49217680Spst		printf(" null");
49317680Spst		return;
49417680Spst
49517680Spst	case NFSPROC_GETATTR:
49617680Spst		printf(" getattr");
49775118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
49875118Sfenner		    parsefh(dp, v3) != NULL)
49917680Spst			return;
50017680Spst		break;
50117680Spst
50217680Spst	case NFSPROC_SETATTR:
50317680Spst		printf(" setattr");
50475118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
50575118Sfenner		    parsefh(dp, v3) != NULL)
50617680Spst			return;
50717680Spst		break;
50817680Spst
50917680Spst	case NFSPROC_LOOKUP:
51017680Spst		printf(" lookup");
51175118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
51275118Sfenner		    parsefhn(dp, v3) != NULL)
51317680Spst			return;
51417680Spst		break;
51517680Spst
51618976Sdfr	case NFSPROC_ACCESS:
51718976Sdfr		printf(" access");
51826183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
51926183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
52075118Sfenner			TCHECK(dp[0]);
52175118Sfenner			printf(" %04x", (u_int32_t)ntohl(dp[0]));
52218976Sdfr			return;
52318976Sdfr		}
52418976Sdfr		break;
52518976Sdfr
52617680Spst	case NFSPROC_READLINK:
52717680Spst		printf(" readlink");
52875118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
52975118Sfenner		    parsefh(dp, v3) != NULL)
53017680Spst			return;
53117680Spst		break;
53217680Spst
53317680Spst	case NFSPROC_READ:
53417680Spst		printf(" read");
53526183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
53626183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
53718976Sdfr			if (v3) {
53875118Sfenner				TCHECK(dp[2]);
53975118Sfenner				printf(" %u bytes @ ",
54075118Sfenner				       (u_int32_t) ntohl(dp[2]));
54118976Sdfr				print_int64(dp, UNSIGNED);
54218976Sdfr			} else {
54375118Sfenner				TCHECK(dp[1]);
54475118Sfenner				printf(" %u bytes @ %u",
54575118Sfenner				    (u_int32_t)ntohl(dp[1]),
54675118Sfenner				    (u_int32_t)ntohl(dp[0]));
54718976Sdfr			}
54817680Spst			return;
54917680Spst		}
55017680Spst		break;
55117680Spst
55217680Spst	case NFSPROC_WRITE:
55317680Spst		printf(" write");
55426183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
55526183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
55618976Sdfr			if (v3) {
55775118Sfenner				TCHECK(dp[4]);
55875118Sfenner				printf(" %u bytes @ ",
55975118Sfenner						(u_int32_t) ntohl(dp[4]));
56018976Sdfr				print_int64(dp, UNSIGNED);
56118976Sdfr				if (vflag) {
56218976Sdfr					dp += 3;
56375118Sfenner					TCHECK(dp[0]);
56418976Sdfr					printf(" <%s>",
56575118Sfenner						tok2str(nfsv3_writemodes,
56675118Sfenner							NULL, ntohl(*dp)));
56718976Sdfr				}
56818976Sdfr			} else {
56975118Sfenner				TCHECK(dp[3]);
57075118Sfenner				printf(" %u (%u) bytes @ %u (%u)",
57175118Sfenner						(u_int32_t)ntohl(dp[3]),
57275118Sfenner						(u_int32_t)ntohl(dp[2]),
57375118Sfenner						(u_int32_t)ntohl(dp[1]),
57475118Sfenner						(u_int32_t)ntohl(dp[0]));
57518976Sdfr			}
57617680Spst			return;
57717680Spst		}
57817680Spst		break;
57917680Spst
58017680Spst	case NFSPROC_CREATE:
58117680Spst		printf(" create");
58275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
58375118Sfenner		    parsefhn(dp, v3) != NULL)
58417680Spst			return;
58517680Spst		break;
58617680Spst
58718976Sdfr	case NFSPROC_MKDIR:
58818976Sdfr		printf(" mkdir");
58975118Sfenner		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
59018976Sdfr			return;
59118976Sdfr		break;
59218976Sdfr
59318976Sdfr	case NFSPROC_SYMLINK:
59418976Sdfr		printf(" symlink");
59575118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
59675118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
59775118Sfenner			fputs(" ->", stdout);
59875118Sfenner			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
59918976Sdfr				break;
60075118Sfenner			if (parsefn(dp) == 0)
60118976Sdfr				break;
60218976Sdfr			if (v3 && vflag)
60318976Sdfr				print_sattr3(&sa3, vflag);
60418976Sdfr			return;
60518976Sdfr		}
60618976Sdfr		break;
60718976Sdfr
60818976Sdfr	case NFSPROC_MKNOD:
60918976Sdfr		printf(" mknod");
61075118Sfenner		if ((dp = parsereq(rp, length)) != 0 &&
61175118Sfenner		    (dp = parsefhn(dp, v3)) != 0) {
61275118Sfenner			TCHECK(*dp);
61375118Sfenner			type = (nfs_type)ntohl(*dp++);
61475118Sfenner			if ((dp = parse_sattr3(dp, &sa3)) == 0)
61518976Sdfr				break;
61618976Sdfr			printf(" %s", tok2str(type2str, "unk-ft %d", type));
61718976Sdfr			if (vflag && (type == NFCHR || type == NFBLK)) {
61875118Sfenner				TCHECK(dp[1]);
61975118Sfenner				printf(" %u/%u",
62075118Sfenner				       (u_int32_t)ntohl(dp[0]),
62175118Sfenner				       (u_int32_t)ntohl(dp[1]));
62218976Sdfr				dp += 2;
62318976Sdfr			}
62418976Sdfr			if (vflag)
62518976Sdfr				print_sattr3(&sa3, vflag);
62618976Sdfr			return;
62718976Sdfr		}
62818976Sdfr		break;
62918976Sdfr
63017680Spst	case NFSPROC_REMOVE:
63117680Spst		printf(" remove");
63275118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
63375118Sfenner		    parsefhn(dp, v3) != NULL)
63417680Spst			return;
63517680Spst		break;
63617680Spst
63718976Sdfr	case NFSPROC_RMDIR:
63818976Sdfr		printf(" rmdir");
63975118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
64075118Sfenner		    parsefhn(dp, v3) != NULL)
64118976Sdfr			return;
64218976Sdfr		break;
64318976Sdfr
64417680Spst	case NFSPROC_RENAME:
64517680Spst		printf(" rename");
64626183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
64726183Sfenner		    (dp = parsefhn(dp, v3)) != NULL) {
64817680Spst			fputs(" ->", stdout);
64926183Sfenner			if (parsefhn(dp, v3) != NULL)
65017680Spst				return;
65117680Spst		}
65217680Spst		break;
65317680Spst
65417680Spst	case NFSPROC_LINK:
65517680Spst		printf(" link");
65626183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
65726183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
65817680Spst			fputs(" ->", stdout);
65926183Sfenner			if (parsefhn(dp, v3) != NULL)
66017680Spst				return;
66117680Spst		}
66217680Spst		break;
66317680Spst
66418976Sdfr	case NFSPROC_READDIR:
66518976Sdfr		printf(" readdir");
66626183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
66726183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
66818976Sdfr			if (v3) {
66975118Sfenner				TCHECK(dp[4]);
67018976Sdfr				/*
67118976Sdfr				 * We shouldn't really try to interpret the
67218976Sdfr				 * offset cookie here.
67318976Sdfr				 */
67475118Sfenner				printf(" %u bytes @ ",
67575118Sfenner				    (u_int32_t) ntohl(dp[4]));
67618976Sdfr				print_int64(dp, SIGNED);
67718976Sdfr				if (vflag)
67826183Sfenner					printf(" verf %08x%08x", dp[2],
67918976Sdfr					       dp[3]);
68018976Sdfr			} else {
68175118Sfenner				TCHECK(dp[1]);
68218976Sdfr				/*
68318976Sdfr				 * Print the offset as signed, since -1 is
68418976Sdfr				 * common, but offsets > 2^31 aren't.
68518976Sdfr				 */
68675118Sfenner				printf(" %u bytes @ %d",
68775118Sfenner				    (u_int32_t)ntohl(dp[1]),
68875118Sfenner				    (u_int32_t)ntohl(dp[0]));
68918976Sdfr			}
69018976Sdfr			return;
69117680Spst		}
69217680Spst		break;
69317680Spst
69418976Sdfr	case NFSPROC_READDIRPLUS:
69518976Sdfr		printf(" readdirplus");
69626183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
69726183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
69875118Sfenner			TCHECK(dp[4]);
69918976Sdfr			/*
70018976Sdfr			 * We don't try to interpret the offset
70118976Sdfr			 * cookie here.
70218976Sdfr			 */
70375118Sfenner			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[4]));
70418976Sdfr			print_int64(dp, SIGNED);
70518976Sdfr			if (vflag)
70675118Sfenner				printf(" max %u verf %08x%08x",
70775118Sfenner				       (u_int32_t) ntohl(dp[5]), dp[2], dp[3]);
70817680Spst			return;
70918976Sdfr		}
71017680Spst		break;
71117680Spst
71218976Sdfr	case NFSPROC_FSSTAT:
71318976Sdfr		printf(" fsstat");
71475118Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
71575118Sfenner		    parsefh(dp, v3) != NULL)
71617680Spst			return;
71717680Spst		break;
71817680Spst
71918976Sdfr	case NFSPROC_FSINFO:
72018976Sdfr		printf(" fsinfo");
72118976Sdfr		break;
72218976Sdfr
72318976Sdfr	case NFSPROC_PATHCONF:
72418976Sdfr		printf(" pathconf");
72518976Sdfr		break;
72618976Sdfr
72718976Sdfr	case NFSPROC_COMMIT:
72818976Sdfr		printf(" commit");
72926183Sfenner		if ((dp = parsereq(rp, length)) != NULL &&
73026183Sfenner		    (dp = parsefh(dp, v3)) != NULL) {
73175118Sfenner			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[2]));
73218976Sdfr			print_int64(dp, UNSIGNED);
73317680Spst			return;
73417680Spst		}
73517680Spst		break;
73617680Spst
73717680Spst	default:
73875118Sfenner		printf(" proc-%u", (u_int32_t)ntohl(rp->rm_call.cb_proc));
73917680Spst		return;
74017680Spst	}
74175118Sfenner
74217680Spsttrunc:
74326183Sfenner	if (!nfserr)
74426183Sfenner		fputs(" [|nfs]", stdout);
74517680Spst}
74617680Spst
74717680Spst/*
74817680Spst * Print out an NFS file handle.
74917680Spst * We assume packet was not truncated before the end of the
75017680Spst * file handle pointed to by dp.
75117680Spst *
75217680Spst * Note: new version (using portable file-handle parser) doesn't produce
75317680Spst * generation number.  It probably could be made to do that, with some
75417680Spst * additional hacking on the parser code.
75517680Spst */
75617680Spststatic void
75775118Sfennernfs_printfh(register const u_int32_t *dp, const u_int len)
75817680Spst{
75917680Spst	my_fsid fsid;
76017680Spst	ino_t ino;
76117680Spst	char *sfsname = NULL;
76217680Spst
76375118Sfenner	Parse_fh((caddr_t*)dp, len, &fsid, &ino, NULL, &sfsname, 0);
76417680Spst
76517680Spst	if (sfsname) {
76626183Sfenner		/* file system ID is ASCII, not numeric, for this server OS */
76726183Sfenner		static char temp[NFSX_V3FHMAX+1];
76817680Spst
76926183Sfenner		/* Make sure string is null-terminated */
77026183Sfenner		strncpy(temp, sfsname, NFSX_V3FHMAX);
77175118Sfenner		temp[sizeof(temp) - 1] = '\0';
77226183Sfenner		/* Remove trailing spaces */
77326183Sfenner		sfsname = strchr(temp, ' ');
77426183Sfenner		if (sfsname)
77526183Sfenner			*sfsname = 0;
77617680Spst
77775118Sfenner		(void)printf(" fh %s/", temp);
77826183Sfenner	} else {
77975118Sfenner		(void)printf(" fh %d,%d/",
78075118Sfenner			     fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
78117680Spst	}
78275118Sfenner
78375118Sfenner	if(fsid.Fsid_dev.Minor == 257 && uflag)
78475118Sfenner		/* Print the undecoded handle */
78575118Sfenner		(void)printf("%s", fsid.Opaque_Handle);
78675118Sfenner	else
78775118Sfenner		(void)printf("%ld", (long) ino);
78817680Spst}
78917680Spst
79017680Spst/*
79117680Spst * Maintain a small cache of recent client.XID.server/proc pairs, to allow
79217680Spst * us to match up replies with requests and thus to know how to parse
79317680Spst * the reply.
79417680Spst */
79517680Spst
79617680Spststruct xid_map_entry {
79775118Sfenner	u_int32_t	xid;		/* transaction ID (net order) */
79875118Sfenner	int ipver;			/* IP version (4 or 6) */
79975118Sfenner#ifdef INET6
80075118Sfenner	struct in6_addr	client;		/* client IP address (net order) */
80175118Sfenner	struct in6_addr	server;		/* server IP address (net order) */
80275118Sfenner#else
80317680Spst	struct in_addr	client;		/* client IP address (net order) */
80417680Spst	struct in_addr	server;		/* server IP address (net order) */
80575118Sfenner#endif
80675118Sfenner	u_int32_t	proc;		/* call proc number (host order) */
80775118Sfenner	u_int32_t	vers;		/* program version (host order) */
80817680Spst};
80917680Spst
81017680Spst/*
81117680Spst * Map entries are kept in an array that we manage as a ring;
81217680Spst * new entries are always added at the tail of the ring.  Initially,
81317680Spst * all the entries are zero and hence don't match anything.
81417680Spst */
81517680Spst
81617680Spst#define	XIDMAPSIZE	64
81717680Spst
81817680Spststruct xid_map_entry xid_map[XIDMAPSIZE];
81917680Spst
82017680Spstint	xid_map_next = 0;
82117680Spstint	xid_map_hint = 0;
82217680Spst
82317680Spststatic void
82475118Sfennerxid_map_enter(const struct rpc_msg *rp, const u_char *bp)
82517680Spst{
82675118Sfenner	struct ip *ip = NULL;
82775118Sfenner#ifdef INET6
82875118Sfenner	struct ip6_hdr *ip6 = NULL;
82975118Sfenner#endif
83017680Spst	struct xid_map_entry *xmep;
83117680Spst
83275118Sfenner	switch (IP_V((struct ip *)bp)) {
83375118Sfenner	case 4:
83475118Sfenner		ip = (struct ip *)bp;
83575118Sfenner		break;
83675118Sfenner#ifdef INET6
83775118Sfenner	case 6:
83875118Sfenner		ip6 = (struct ip6_hdr *)bp;
83975118Sfenner		break;
84075118Sfenner#endif
84175118Sfenner	default:
84275118Sfenner		return;
84375118Sfenner	}
84475118Sfenner
84517680Spst	xmep = &xid_map[xid_map_next];
84617680Spst
84717680Spst	if (++xid_map_next >= XIDMAPSIZE)
84817680Spst		xid_map_next = 0;
84917680Spst
85017680Spst	xmep->xid = rp->rm_xid;
85175118Sfenner	if (ip) {
85275118Sfenner		xmep->ipver = 4;
85375118Sfenner		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
85475118Sfenner		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
85575118Sfenner	}
85675118Sfenner#ifdef INET6
85775118Sfenner	else if (ip6) {
85875118Sfenner		xmep->ipver = 6;
85975118Sfenner		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
86075118Sfenner		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
86175118Sfenner	}
86275118Sfenner#endif
86317680Spst	xmep->proc = ntohl(rp->rm_call.cb_proc);
86418976Sdfr	xmep->vers = ntohl(rp->rm_call.cb_vers);
86517680Spst}
86617680Spst
86726183Sfenner/*
86826183Sfenner * Returns 0 and puts NFSPROC_xxx in proc return and
86926183Sfenner * version in vers return, or returns -1 on failure
87026183Sfenner */
87118976Sdfrstatic int
87275118Sfennerxid_map_find(const struct rpc_msg *rp, const u_char *bp, u_int32_t *proc,
87318976Sdfr	     u_int32_t *vers)
87417680Spst{
87517680Spst	int i;
87617680Spst	struct xid_map_entry *xmep;
87717680Spst	u_int32_t xid = rp->rm_xid;
87875118Sfenner	struct ip *ip = (struct ip *)bp;
87975118Sfenner#ifdef INET6
88075118Sfenner	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
88175118Sfenner#endif
88275118Sfenner	int cmp;
88317680Spst
88417680Spst	/* Start searching from where we last left off */
88575118Sfenner	i = xid_map_hint;
88617680Spst	do {
88717680Spst		xmep = &xid_map[i];
88875118Sfenner		cmp = 1;
88975118Sfenner		if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
89075118Sfenner			goto nextitem;
89175118Sfenner		switch (xmep->ipver) {
89275118Sfenner		case 4:
89375118Sfenner			if (memcmp(&ip->ip_src, &xmep->server,
89475118Sfenner				   sizeof(ip->ip_src)) != 0 ||
89575118Sfenner			    memcmp(&ip->ip_dst, &xmep->client,
89675118Sfenner				   sizeof(ip->ip_dst)) != 0) {
89775118Sfenner				cmp = 0;
89875118Sfenner			}
89975118Sfenner			break;
90075118Sfenner#ifdef INET6
90175118Sfenner		case 6:
90275118Sfenner			if (memcmp(&ip6->ip6_src, &xmep->server,
90375118Sfenner				   sizeof(ip6->ip6_src)) != 0 ||
90475118Sfenner			    memcmp(&ip6->ip6_dst, &xmep->client,
90575118Sfenner				   sizeof(ip6->ip6_dst)) != 0) {
90675118Sfenner				cmp = 0;
90775118Sfenner			}
90875118Sfenner			break;
90975118Sfenner#endif
91075118Sfenner		default:
91175118Sfenner			cmp = 0;
91275118Sfenner			break;
91375118Sfenner		}
91475118Sfenner		if (cmp) {
91517680Spst			/* match */
91617680Spst			xid_map_hint = i;
91718976Sdfr			*proc = xmep->proc;
91818976Sdfr			*vers = xmep->vers;
91918976Sdfr			return 0;
92017680Spst		}
92175118Sfenner	nextitem:
92217680Spst		if (++i >= XIDMAPSIZE)
92317680Spst			i = 0;
92417680Spst	} while (i != xid_map_hint);
92517680Spst
92617680Spst	/* search failed */
92775118Sfenner	return (-1);
92817680Spst}
92917680Spst
93017680Spst/*
93117680Spst * Routines for parsing reply packets
93217680Spst */
93317680Spst
93417680Spst/*
93517680Spst * Return a pointer to the beginning of the actual results.
93675118Sfenner * If the packet was truncated, return 0.
93717680Spst */
93817680Spststatic const u_int32_t *
93975118Sfennerparserep(register const struct rpc_msg *rp, register u_int length)
94017680Spst{
94117680Spst	register const u_int32_t *dp;
94275118Sfenner	u_int len;
94317680Spst	enum accept_stat astat;
94417680Spst
94517680Spst	/*
94617680Spst	 * Portability note:
94717680Spst	 * Here we find the address of the ar_verf credentials.
94817680Spst	 * Originally, this calculation was
94917680Spst	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
95017680Spst	 * On the wire, the rp_acpt field starts immediately after
95117680Spst	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
95217680Spst	 * "struct accepted_reply") contains a "struct opaque_auth",
95317680Spst	 * whose internal representation contains a pointer, so on a
95417680Spst	 * 64-bit machine the compiler inserts 32 bits of padding
95517680Spst	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
95617680Spst	 * the internal representation to parse the on-the-wire
95717680Spst	 * representation.  Instead, we skip past the rp_stat field,
95817680Spst	 * which is an "enum" and so occupies one 32-bit word.
95917680Spst	 */
96017680Spst	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
96175118Sfenner	TCHECK(dp[1]);
96217680Spst	len = ntohl(dp[1]);
96317680Spst	if (len >= length)
96426183Sfenner		return (NULL);
96517680Spst	/*
96617680Spst	 * skip past the ar_verf credentials.
96717680Spst	 */
96817680Spst	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
96926183Sfenner	TCHECK2(dp[0], 0);
97017680Spst
97117680Spst	/*
97217680Spst	 * now we can check the ar_stat field
97317680Spst	 */
97417680Spst	astat = ntohl(*(enum accept_stat *)dp);
97517680Spst	switch (astat) {
97617680Spst
97717680Spst	case SUCCESS:
97817680Spst		break;
97917680Spst
98017680Spst	case PROG_UNAVAIL:
98117680Spst		printf(" PROG_UNAVAIL");
98226183Sfenner		nfserr = 1;		/* suppress trunc string */
98326183Sfenner		return (NULL);
98417680Spst
98517680Spst	case PROG_MISMATCH:
98617680Spst		printf(" PROG_MISMATCH");
98726183Sfenner		nfserr = 1;		/* suppress trunc string */
98826183Sfenner		return (NULL);
98917680Spst
99017680Spst	case PROC_UNAVAIL:
99117680Spst		printf(" PROC_UNAVAIL");
99226183Sfenner		nfserr = 1;		/* suppress trunc string */
99326183Sfenner		return (NULL);
99417680Spst
99517680Spst	case GARBAGE_ARGS:
99617680Spst		printf(" GARBAGE_ARGS");
99726183Sfenner		nfserr = 1;		/* suppress trunc string */
99826183Sfenner		return (NULL);
99917680Spst
100017680Spst	case SYSTEM_ERR:
100117680Spst		printf(" SYSTEM_ERR");
100226183Sfenner		nfserr = 1;		/* suppress trunc string */
100326183Sfenner		return (NULL);
100417680Spst
100517680Spst	default:
100617680Spst		printf(" ar_stat %d", astat);
100726183Sfenner		nfserr = 1;		/* suppress trunc string */
100826183Sfenner		return (NULL);
100917680Spst	}
101017680Spst	/* successful return */
101175118Sfenner	TCHECK2(*dp, sizeof(astat));
101275118Sfenner	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
101326183Sfennertrunc:
101475118Sfenner	return (0);
101517680Spst}
101617680Spst
101717680Spststatic const u_int32_t *
101818976Sdfrparsestatus(const u_int32_t *dp, int *er)
101917680Spst{
102075118Sfenner	int errnum;
102117680Spst
102226183Sfenner	TCHECK(dp[0]);
102375118Sfenner
102426183Sfenner	errnum = ntohl(dp[0]);
102518976Sdfr	if (er)
102626183Sfenner		*er = errnum;
102726183Sfenner	if (errnum != 0) {
102826183Sfenner		if (!qflag)
102975118Sfenner			printf(" ERROR: %s",
103075118Sfenner			    tok2str(status2str, "unk %d", errnum));
103126183Sfenner		nfserr = 1;
103226183Sfenner		return (NULL);
103317680Spst	}
103417680Spst	return (dp + 1);
103526183Sfennertrunc:
103675118Sfenner	return NULL;
103717680Spst}
103817680Spst
103917680Spststatic const u_int32_t *
104018976Sdfrparsefattr(const u_int32_t *dp, int verbose, int v3)
104117680Spst{
104218976Sdfr	const struct nfs_fattr *fap;
104317680Spst
104418976Sdfr	fap = (const struct nfs_fattr *)dp;
104526184Sfenner	TCHECK(fap->fa_gid);
104617680Spst	if (verbose) {
104775118Sfenner		printf(" %s %o ids %d/%d",
104875118Sfenner		    tok2str(type2str, "unk-ft %d ",
104975118Sfenner		    (u_int32_t)ntohl(fap->fa_type)),
105075118Sfenner		    (u_int32_t)ntohl(fap->fa_mode),
105175118Sfenner		    (u_int32_t)ntohl(fap->fa_uid),
105275118Sfenner		    (u_int32_t) ntohl(fap->fa_gid));
105318976Sdfr		if (v3) {
105426184Sfenner			TCHECK(fap->fa3_size);
105518976Sdfr			printf(" sz ");
105618976Sdfr			print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED);
105718976Sdfr			putchar(' ');
105826184Sfenner		} else {
105926184Sfenner			TCHECK(fap->fa2_size);
106075118Sfenner			printf(" sz %d ", (u_int32_t) ntohl(fap->fa2_size));
106118976Sdfr		}
106217680Spst	}
106317680Spst	/* print lots more stuff */
106417680Spst	if (verbose > 1) {
106518976Sdfr		if (v3) {
106626184Sfenner			TCHECK(fap->fa3_ctime);
106775118Sfenner			printf("nlink %d rdev %d/%d ",
106875118Sfenner			       (u_int32_t)ntohl(fap->fa_nlink),
106975118Sfenner			       (u_int32_t) ntohl(fap->fa3_rdev.specdata1),
107075118Sfenner			       (u_int32_t) ntohl(fap->fa3_rdev.specdata2));
107118976Sdfr			printf("fsid ");
107218976Sdfr			print_int64((u_int32_t *)&fap->fa2_fsid, HEX);
107318976Sdfr			printf(" nodeid ");
107418976Sdfr			print_int64((u_int32_t *)&fap->fa2_fileid, HEX);
107575118Sfenner			printf(" a/m/ctime %u.%06u ",
107675118Sfenner			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_sec),
107775118Sfenner			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_nsec));
107875118Sfenner			printf("%u.%06u ",
107975118Sfenner			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_sec),
108075118Sfenner			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_nsec));
108175118Sfenner			printf("%u.%06u ",
108275118Sfenner			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_sec),
108375118Sfenner			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_nsec));
108418976Sdfr		} else {
108526184Sfenner			TCHECK(fap->fa2_ctime);
108675118Sfenner			printf("nlink %d rdev %x fsid %x nodeid %x a/m/ctime ",
108775118Sfenner			       (u_int32_t) ntohl(fap->fa_nlink),
108875118Sfenner			       (u_int32_t) ntohl(fap->fa2_rdev),
108975118Sfenner			       (u_int32_t) ntohl(fap->fa2_fsid),
109075118Sfenner			       (u_int32_t) ntohl(fap->fa2_fileid));
109175118Sfenner			printf("%u.%06u ",
109275118Sfenner			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_sec),
109375118Sfenner			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_usec));
109475118Sfenner			printf("%u.%06u ",
109575118Sfenner			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_sec),
109675118Sfenner			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_usec));
109775118Sfenner			printf("%u.%06u ",
109875118Sfenner			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_sec),
109975118Sfenner			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_usec));
110018976Sdfr		}
110117680Spst	}
110218976Sdfr	return ((const u_int32_t *)((unsigned char *)dp +
110318976Sdfr		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
110426184Sfennertrunc:
110526184Sfenner	return (NULL);
110617680Spst}
110717680Spst
110817680Spststatic int
110918976Sdfrparseattrstat(const u_int32_t *dp, int verbose, int v3)
111017680Spst{
111118976Sdfr	int er;
111218976Sdfr
111318976Sdfr	dp = parsestatus(dp, &er);
111418976Sdfr	if (dp == NULL || er)
111517680Spst		return (0);
111617680Spst
111726183Sfenner	return (parsefattr(dp, verbose, v3) != NULL);
111817680Spst}
111917680Spst
112017680Spststatic int
112117680Spstparsediropres(const u_int32_t *dp)
112217680Spst{
112318976Sdfr	int er;
112418976Sdfr
112575118Sfenner	if (!(dp = parsestatus(dp, &er)) || er)
112617680Spst		return (0);
112717680Spst
112818976Sdfr	dp = parsefh(dp, 0);
112917680Spst	if (dp == NULL)
113017680Spst		return (0);
113117680Spst
113218976Sdfr	return (parsefattr(dp, vflag, 0) != NULL);
113317680Spst}
113417680Spst
113517680Spststatic int
113618976Sdfrparselinkres(const u_int32_t *dp, int v3)
113717680Spst{
113818976Sdfr	int er;
113918976Sdfr
114018976Sdfr	dp = parsestatus(dp, &er);
114118976Sdfr	if (dp == NULL || er)
114217680Spst		return(0);
114375118Sfenner	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
114418976Sdfr		return (0);
114517680Spst	putchar(' ');
114617680Spst	return (parsefn(dp) != NULL);
114717680Spst}
114817680Spst
114917680Spststatic int
115018976Sdfrparsestatfs(const u_int32_t *dp, int v3)
115117680Spst{
115218976Sdfr	const struct nfs_statfs *sfsp;
115318976Sdfr	int er;
115417680Spst
115518976Sdfr	dp = parsestatus(dp, &er);
115618976Sdfr	if (dp == NULL || (!v3 && er))
115775118Sfenner		return (0);
115817680Spst
115918976Sdfr	if (qflag)
116018976Sdfr		return(1);
116118976Sdfr
116218976Sdfr	if (v3) {
116318976Sdfr		if (vflag)
116418976Sdfr			printf(" POST:");
116575118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
116618976Sdfr			return (0);
116717680Spst	}
116817680Spst
116926184Sfenner	TCHECK2(dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
117018976Sdfr
117118976Sdfr	sfsp = (const struct nfs_statfs *)dp;
117218976Sdfr
117318976Sdfr	if (v3) {
117418976Sdfr		printf(" tbytes ");
117518976Sdfr		print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED);
117618976Sdfr		printf(" fbytes ");
117718976Sdfr		print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED);
117818976Sdfr		printf(" abytes ");
117918976Sdfr		print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED);
118018976Sdfr		if (vflag) {
118118976Sdfr			printf(" tfiles ");
118218976Sdfr			print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED);
118318976Sdfr			printf(" ffiles ");
118418976Sdfr			print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED);
118518976Sdfr			printf(" afiles ");
118618976Sdfr			print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED);
118775118Sfenner			printf(" invar %u",
118875118Sfenner			       (u_int32_t) ntohl(sfsp->sf_invarsec));
118918976Sdfr		}
119018976Sdfr	} else {
119175118Sfenner		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
119275118Sfenner			(u_int32_t)ntohl(sfsp->sf_tsize),
119375118Sfenner			(u_int32_t)ntohl(sfsp->sf_bsize),
119475118Sfenner			(u_int32_t)ntohl(sfsp->sf_blocks),
119575118Sfenner			(u_int32_t)ntohl(sfsp->sf_bfree),
119675118Sfenner			(u_int32_t)ntohl(sfsp->sf_bavail));
119718976Sdfr	}
119818976Sdfr
119917680Spst	return (1);
120026184Sfennertrunc:
120126184Sfenner	return (0);
120217680Spst}
120317680Spst
120417680Spststatic int
120517680Spstparserddires(const u_int32_t *dp)
120617680Spst{
120718976Sdfr	int er;
120818976Sdfr
120918976Sdfr	dp = parsestatus(dp, &er);
121075118Sfenner	if (dp == 0 || er)
121117680Spst		return (0);
121218976Sdfr	if (qflag)
121318976Sdfr		return (1);
121418976Sdfr
121526184Sfenner	TCHECK(dp[2]);
121675118Sfenner	printf(" offset %x size %d ",
121775118Sfenner	       (u_int32_t)ntohl(dp[0]), (u_int32_t)ntohl(dp[1]));
121818976Sdfr	if (dp[2] != 0)
121975118Sfenner		printf(" eof");
122018976Sdfr
122118976Sdfr	return (1);
122226184Sfennertrunc:
122326184Sfenner	return (0);
122418976Sdfr}
122518976Sdfr
122618976Sdfrstatic const u_int32_t *
122718976Sdfrparse_wcc_attr(const u_int32_t *dp)
122818976Sdfr{
122918976Sdfr	printf(" sz ");
123018976Sdfr	print_int64(dp, UNSIGNED);
123175118Sfenner	printf(" mtime %u.%06u ctime %u.%06u",
123275118Sfenner	       (u_int32_t)ntohl(dp[2]), (u_int32_t)ntohl(dp[3]),
123375118Sfenner	       (u_int32_t)ntohl(dp[4]), (u_int32_t)ntohl(dp[5]));
123418976Sdfr	return (dp + 6);
123518976Sdfr}
123618976Sdfr
123718976Sdfr/*
123818976Sdfr * Pre operation attributes. Print only if vflag > 1.
123918976Sdfr */
124018976Sdfrstatic const u_int32_t *
124118976Sdfrparse_pre_op_attr(const u_int32_t *dp, int verbose)
124218976Sdfr{
124326184Sfenner	TCHECK(dp[0]);
124418976Sdfr	if (!ntohl(dp[0]))
124518976Sdfr		return (dp + 1);
124618976Sdfr	dp++;
124726184Sfenner	TCHECK2(dp, 24);
124818976Sdfr	if (verbose > 1) {
124918976Sdfr		return parse_wcc_attr(dp);
125018976Sdfr	} else {
125118976Sdfr		/* If not verbose enough, just skip over wcc_attr */
125218976Sdfr		return (dp + 6);
125317680Spst	}
125426184Sfennertrunc:
125526184Sfenner	return (NULL);
125618976Sdfr}
125717680Spst
125818976Sdfr/*
125918976Sdfr * Post operation attributes are printed if vflag >= 1
126018976Sdfr */
126118976Sdfrstatic const u_int32_t *
126218976Sdfrparse_post_op_attr(const u_int32_t *dp, int verbose)
126318976Sdfr{
126426184Sfenner	TCHECK(dp[0]);
126518976Sdfr	if (!ntohl(dp[0]))
126618976Sdfr		return (dp + 1);
126718976Sdfr	dp++;
126818976Sdfr	if (verbose) {
126918976Sdfr		return parsefattr(dp, verbose, 1);
127018976Sdfr	} else
127118976Sdfr		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
127226184Sfennertrunc:
127326184Sfenner	return (NULL);
127418976Sdfr}
127518976Sdfr
127618976Sdfrstatic const u_int32_t *
127718976Sdfrparse_wcc_data(const u_int32_t *dp, int verbose)
127818976Sdfr{
127918976Sdfr	if (verbose > 1)
128018976Sdfr		printf(" PRE:");
128175118Sfenner	if (!(dp = parse_pre_op_attr(dp, verbose)))
128275118Sfenner		return (0);
128318976Sdfr
128418976Sdfr	if (verbose)
128518976Sdfr		printf(" POST:");
128618976Sdfr	return parse_post_op_attr(dp, verbose);
128718976Sdfr}
128818976Sdfr
128918976Sdfrstatic const u_int32_t *
129018976Sdfrparsecreateopres(const u_int32_t *dp, int verbose)
129118976Sdfr{
129218976Sdfr	int er;
129318976Sdfr
129475118Sfenner	if (!(dp = parsestatus(dp, &er)))
129575118Sfenner		return (0);
129618976Sdfr	if (er)
129718976Sdfr		dp = parse_wcc_data(dp, verbose);
129818976Sdfr	else {
129926184Sfenner		TCHECK(dp[0]);
130018976Sdfr		if (!ntohl(dp[0]))
130118976Sdfr			return (dp + 1);
130218976Sdfr		dp++;
130375118Sfenner		if (!(dp = parsefh(dp, 1)))
130475118Sfenner			return (0);
130518976Sdfr		if (verbose) {
130675118Sfenner			if (!(dp = parse_post_op_attr(dp, verbose)))
130775118Sfenner				return (0);
130818976Sdfr			if (vflag > 1) {
130918976Sdfr				printf("dir attr:");
131018976Sdfr				dp = parse_wcc_data(dp, verbose);
131118976Sdfr			}
131218976Sdfr		}
131318976Sdfr	}
131418976Sdfr	return (dp);
131526184Sfennertrunc:
131626184Sfenner	return (NULL);
131718976Sdfr}
131818976Sdfr
131918976Sdfrstatic int
132018976Sdfrparsewccres(const u_int32_t *dp, int verbose)
132118976Sdfr{
132218976Sdfr	int er;
132318976Sdfr
132475118Sfenner	if (!(dp = parsestatus(dp, &er)))
132518976Sdfr		return (0);
132675118Sfenner	return parse_wcc_data(dp, verbose) != 0;
132718976Sdfr}
132818976Sdfr
132918976Sdfrstatic const u_int32_t *
133018976Sdfrparsev3rddirres(const u_int32_t *dp, int verbose)
133118976Sdfr{
133218976Sdfr	int er;
133318976Sdfr
133475118Sfenner	if (!(dp = parsestatus(dp, &er)))
133575118Sfenner		return (0);
133618976Sdfr	if (vflag)
133718976Sdfr		printf(" POST:");
133875118Sfenner	if (!(dp = parse_post_op_attr(dp, verbose)))
133975118Sfenner		return (0);
134018976Sdfr	if (er)
134118976Sdfr		return dp;
134218976Sdfr	if (vflag) {
134326184Sfenner		TCHECK(dp[1]);
134426183Sfenner		printf(" verf %08x%08x", dp[0], dp[1]);
134518976Sdfr		dp += 2;
134618976Sdfr	}
134718976Sdfr	return dp;
134826184Sfennertrunc:
134926184Sfenner	return (NULL);
135018976Sdfr}
135118976Sdfr
135218976Sdfrstatic int
135318976Sdfrparsefsinfo(const u_int32_t *dp)
135418976Sdfr{
135518976Sdfr	struct nfsv3_fsinfo *sfp;
135618976Sdfr	int er;
135718976Sdfr
135875118Sfenner	if (!(dp = parsestatus(dp, &er)))
135918976Sdfr		return (0);
136018976Sdfr	if (vflag)
136118976Sdfr		printf(" POST:");
136275118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
136318976Sdfr		return (0);
136418976Sdfr	if (er)
136518976Sdfr		return (1);
136618976Sdfr
136718976Sdfr	sfp = (struct nfsv3_fsinfo *)dp;
136826184Sfenner	TCHECK(*sfp);
136975118Sfenner	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
137075118Sfenner	       (u_int32_t) ntohl(sfp->fs_rtmax),
137175118Sfenner	       (u_int32_t) ntohl(sfp->fs_rtpref),
137275118Sfenner	       (u_int32_t) ntohl(sfp->fs_wtmax),
137375118Sfenner	       (u_int32_t) ntohl(sfp->fs_wtpref),
137475118Sfenner	       (u_int32_t) ntohl(sfp->fs_dtpref));
137518976Sdfr	if (vflag) {
137675118Sfenner		printf(" rtmult %u wtmult %u maxfsz ",
137775118Sfenner		       (u_int32_t) ntohl(sfp->fs_rtmult),
137875118Sfenner		       (u_int32_t) ntohl(sfp->fs_wtmult));
137918976Sdfr		print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED);
138075118Sfenner		printf(" delta %u.%06u ",
138175118Sfenner		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_sec),
138275118Sfenner		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_nsec));
138318976Sdfr	}
138475118Sfenner	return (0);
138575118Sfennertrunc:
138617680Spst	return (1);
138718976Sdfr}
138818976Sdfr
138918976Sdfrstatic int
139018976Sdfrparsepathconf(const u_int32_t *dp)
139118976Sdfr{
139218976Sdfr	int er;
139318976Sdfr	struct nfsv3_pathconf *spp;
139418976Sdfr
139575118Sfenner	if (!(dp = parsestatus(dp, &er)))
139618976Sdfr		return (0);
139718976Sdfr	if (vflag)
139818976Sdfr		printf(" POST:");
139975118Sfenner	if (!(dp = parse_post_op_attr(dp, vflag)))
140018976Sdfr		return (0);
140118976Sdfr	if (er)
140218976Sdfr		return (1);
140318976Sdfr
140418976Sdfr	spp = (struct nfsv3_pathconf *)dp;
140526184Sfenner	TCHECK(*spp);
140618976Sdfr
140775118Sfenner	printf(" linkmax %u namemax %u %s %s %s %s",
140875118Sfenner	       (u_int32_t) ntohl(spp->pc_linkmax),
140975118Sfenner	       (u_int32_t) ntohl(spp->pc_namemax),
141018976Sdfr	       ntohl(spp->pc_notrunc) ? "notrunc" : "",
141118976Sdfr	       ntohl(spp->pc_chownrestricted) ? "chownres" : "",
141218976Sdfr	       ntohl(spp->pc_caseinsensitive) ? "igncase" : "",
141318976Sdfr	       ntohl(spp->pc_casepreserving) ? "keepcase" : "");
141475118Sfenner	return (0);
141575118Sfennertrunc:
141626184Sfenner	return (1);
141717680Spst}
141875118Sfenner
141917680Spststatic void
142018976Sdfrinterp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
142117680Spst{
142217680Spst	register const u_int32_t *dp;
142318976Sdfr	register int v3;
142418976Sdfr	int er;
142517680Spst
142618976Sdfr	v3 = (vers == NFS_VER3);
142718976Sdfr
142818976Sdfr	if (!v3 && proc < NFS_NPROCS)
142918976Sdfr		proc = nfsv3_procid[proc];
143018976Sdfr
143117680Spst	switch (proc) {
143217680Spst
143317680Spst	case NFSPROC_NOOP:
143417680Spst		printf(" nop");
143517680Spst		return;
143618976Sdfr
143717680Spst	case NFSPROC_NULL:
143817680Spst		printf(" null");
143917680Spst		return;
144017680Spst
144117680Spst	case NFSPROC_GETATTR:
144217680Spst		printf(" getattr");
144317680Spst		dp = parserep(rp, length);
144426183Sfenner		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
144517680Spst			return;
144617680Spst		break;
144717680Spst
144817680Spst	case NFSPROC_SETATTR:
144917680Spst		printf(" setattr");
145075118Sfenner		if (!(dp = parserep(rp, length)))
145117680Spst			return;
145218976Sdfr		if (v3) {
145375118Sfenner			if (parsewccres(dp, vflag))
145418976Sdfr				return;
145518976Sdfr		} else {
145618976Sdfr			if (parseattrstat(dp, !qflag, 0) != 0)
145718976Sdfr				return;
145818976Sdfr		}
145917680Spst		break;
146017680Spst
146117680Spst	case NFSPROC_LOOKUP:
146217680Spst		printf(" lookup");
146375118Sfenner		if (!(dp = parserep(rp, length)))
146418976Sdfr			break;
146518976Sdfr		if (v3) {
146675118Sfenner			if (!(dp = parsestatus(dp, &er)))
146718976Sdfr				break;
146818976Sdfr			if (er) {
146918976Sdfr				if (vflag > 1) {
147018976Sdfr					printf(" post dattr:");
147118976Sdfr					dp = parse_post_op_attr(dp, vflag);
147218976Sdfr				}
147318976Sdfr			} else {
147475118Sfenner				if (!(dp = parsefh(dp, v3)))
147518976Sdfr					break;
147675118Sfenner				if ((dp = parse_post_op_attr(dp, vflag)) &&
147775118Sfenner				    vflag > 1) {
147818976Sdfr					printf(" post dattr:");
147918976Sdfr					dp = parse_post_op_attr(dp, vflag);
148018976Sdfr				}
148118976Sdfr			}
148275118Sfenner			if (dp)
148318976Sdfr				return;
148418976Sdfr		} else {
148518976Sdfr			if (parsediropres(dp) != 0)
148618976Sdfr				return;
148718976Sdfr		}
148817680Spst		break;
148917680Spst
149018976Sdfr	case NFSPROC_ACCESS:
149118976Sdfr		printf(" access");
149218976Sdfr		dp = parserep(rp, length);
149375118Sfenner		if (!(dp = parsestatus(dp, &er)))
149418976Sdfr			break;
149518976Sdfr		if (vflag)
149618976Sdfr			printf(" attr:");
149775118Sfenner		if (!(dp = parse_post_op_attr(dp, vflag)))
149818976Sdfr			break;
149918976Sdfr		if (!er)
150075118Sfenner			printf(" c %04x", (u_int32_t)ntohl(dp[0]));
150118976Sdfr		return;
150218976Sdfr
150317680Spst	case NFSPROC_READLINK:
150417680Spst		printf(" readlink");
150517680Spst		dp = parserep(rp, length);
150626183Sfenner		if (dp != NULL && parselinkres(dp, v3) != 0)
150717680Spst			return;
150817680Spst		break;
150917680Spst
151017680Spst	case NFSPROC_READ:
151117680Spst		printf(" read");
151275118Sfenner		if (!(dp = parserep(rp, length)))
151318976Sdfr			break;
151418976Sdfr		if (v3) {
151575118Sfenner			if (!(dp = parsestatus(dp, &er)))
151618976Sdfr				break;
151775118Sfenner			if (!(dp = parse_post_op_attr(dp, vflag)))
151818976Sdfr				break;
151918976Sdfr			if (er)
152018976Sdfr				return;
152118976Sdfr			if (vflag) {
152275118Sfenner				TCHECK(dp[1]);
152375118Sfenner				printf("%u bytes", (u_int32_t) ntohl(dp[0]));
152418976Sdfr				if (ntohl(dp[1]))
152518976Sdfr					printf(" EOF");
152618976Sdfr			}
152717680Spst			return;
152818976Sdfr		} else {
152918976Sdfr			if (parseattrstat(dp, vflag, 0) != 0)
153018976Sdfr				return;
153118976Sdfr		}
153217680Spst		break;
153317680Spst
153417680Spst	case NFSPROC_WRITE:
153517680Spst		printf(" write");
153675118Sfenner		if (!(dp = parserep(rp, length)))
153718976Sdfr			break;
153818976Sdfr		if (v3) {
153975118Sfenner			if (!(dp = parsestatus(dp, &er)))
154018976Sdfr				break;
154175118Sfenner			if (!(dp = parse_wcc_data(dp, vflag)))
154218976Sdfr				break;
154318976Sdfr			if (er)
154418976Sdfr				return;
154518976Sdfr			if (vflag) {
154675118Sfenner				TCHECK(dp[0]);
154775118Sfenner				printf("%u bytes", (u_int32_t) ntohl(dp[0]));
154818976Sdfr				if (vflag > 1) {
154975118Sfenner					TCHECK(dp[1]);
155018976Sdfr					printf(" <%s>",
155175118Sfenner						tok2str(nfsv3_writemodes,
155275118Sfenner							NULL, ntohl(dp[1])));
155318976Sdfr				}
155418976Sdfr				return;
155518976Sdfr			}
155618976Sdfr		} else {
155718976Sdfr			if (parseattrstat(dp, vflag, v3) != 0)
155818976Sdfr				return;
155918976Sdfr		}
156017680Spst		break;
156117680Spst
156217680Spst	case NFSPROC_CREATE:
156317680Spst		printf(" create");
156475118Sfenner		if (!(dp = parserep(rp, length)))
156518976Sdfr			break;
156618976Sdfr		if (v3) {
156775118Sfenner			if (parsecreateopres(dp, vflag) != 0)
156818976Sdfr				return;
156918976Sdfr		} else {
157018976Sdfr			if (parsediropres(dp) != 0)
157118976Sdfr				return;
157218976Sdfr		}
157318976Sdfr		break;
157418976Sdfr
157518976Sdfr	case NFSPROC_MKDIR:
157618976Sdfr		printf(" mkdir");
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_SYMLINK:
158918976Sdfr		printf(" symlink");
159075118Sfenner		if (!(dp = parserep(rp, length)))
159118976Sdfr			break;
159218976Sdfr		if (v3) {
159375118Sfenner			if (parsecreateopres(dp, vflag) != 0)
159418976Sdfr				return;
159518976Sdfr		} else {
159675118Sfenner			if (parsestatus(dp, &er) != 0)
159718976Sdfr				return;
159818976Sdfr		}
159918976Sdfr		break;
160018976Sdfr
160118976Sdfr	case NFSPROC_MKNOD:
160218976Sdfr		printf(" mknod");
160375118Sfenner		if (!(dp = parserep(rp, length)))
160418976Sdfr			break;
160575118Sfenner		if (parsecreateopres(dp, vflag) != 0)
160617680Spst			return;
160717680Spst		break;
160817680Spst
160917680Spst	case NFSPROC_REMOVE:
161017680Spst		printf(" remove");
161175118Sfenner		if (!(dp = parserep(rp, length)))
161218976Sdfr			break;
161318976Sdfr		if (v3) {
161475118Sfenner			if (parsewccres(dp, vflag))
161518976Sdfr				return;
161618976Sdfr		} else {
161775118Sfenner			if (parsestatus(dp, &er) != 0)
161818976Sdfr				return;
161918976Sdfr		}
162017680Spst		break;
162117680Spst
162218976Sdfr	case NFSPROC_RMDIR:
162318976Sdfr		printf(" rmdir");
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		}
163318976Sdfr		break;
163418976Sdfr
163517680Spst	case NFSPROC_RENAME:
163617680Spst		printf(" rename");
163775118Sfenner		if (!(dp = parserep(rp, length)))
163818976Sdfr			break;
163918976Sdfr		if (v3) {
164075118Sfenner			if (!(dp = parsestatus(dp, &er)))
164118976Sdfr				break;
164218976Sdfr			if (vflag) {
164318976Sdfr				printf(" from:");
164475118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
164518976Sdfr					break;
164618976Sdfr				printf(" to:");
164775118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
164818976Sdfr					break;
164918976Sdfr			}
165017680Spst			return;
165118976Sdfr		} else {
165275118Sfenner			if (parsestatus(dp, &er) != 0)
165318976Sdfr				return;
165418976Sdfr		}
165517680Spst		break;
165617680Spst
165717680Spst	case NFSPROC_LINK:
165817680Spst		printf(" link");
165975118Sfenner		if (!(dp = parserep(rp, length)))
166018976Sdfr			break;
166118976Sdfr		if (v3) {
166275118Sfenner			if (!(dp = parsestatus(dp, &er)))
166318976Sdfr				break;
166418976Sdfr			if (vflag) {
166518976Sdfr				printf(" file POST:");
166675118Sfenner				if (!(dp = parse_post_op_attr(dp, vflag)))
166718976Sdfr					break;
166818976Sdfr				printf(" dir:");
166975118Sfenner				if (!(dp = parse_wcc_data(dp, vflag)))
167018976Sdfr					break;
167118976Sdfr				return;
167218976Sdfr			}
167318976Sdfr		} else {
167475118Sfenner			if (parsestatus(dp, &er) != 0)
167518976Sdfr				return;
167618976Sdfr		}
167717680Spst		break;
167817680Spst
167918976Sdfr	case NFSPROC_READDIR:
168018976Sdfr		printf(" readdir");
168175118Sfenner		if (!(dp = parserep(rp, length)))
168218976Sdfr			break;
168318976Sdfr		if (v3) {
168475118Sfenner			if (parsev3rddirres(dp, vflag))
168518976Sdfr				return;
168618976Sdfr		} else {
168718976Sdfr			if (parserddires(dp) != 0)
168818976Sdfr				return;
168918976Sdfr		}
169018976Sdfr		break;
169118976Sdfr
169218976Sdfr	case NFSPROC_READDIRPLUS:
169318976Sdfr		printf(" readdirplus");
169475118Sfenner		if (!(dp = parserep(rp, length)))
169518976Sdfr			break;
169675118Sfenner		if (parsev3rddirres(dp, vflag))
169717680Spst			return;
169817680Spst		break;
169917680Spst
170018976Sdfr	case NFSPROC_FSSTAT:
170118976Sdfr		printf(" fsstat");
170217680Spst		dp = parserep(rp, length);
170375118Sfenner		if (dp != NULL && parsestatfs(dp, v3) != 0)
170417680Spst			return;
170517680Spst		break;
170617680Spst
170718976Sdfr	case NFSPROC_FSINFO:
170818976Sdfr		printf(" fsinfo");
170917680Spst		dp = parserep(rp, length);
171075118Sfenner		if (dp != NULL && parsefsinfo(dp) != 0)
171117680Spst			return;
171217680Spst		break;
171317680Spst
171418976Sdfr	case NFSPROC_PATHCONF:
171518976Sdfr		printf(" pathconf");
171617680Spst		dp = parserep(rp, length);
171726183Sfenner		if (dp != NULL && parsepathconf(dp) != 0)
171817680Spst			return;
171917680Spst		break;
172017680Spst
172118976Sdfr	case NFSPROC_COMMIT:
172218976Sdfr		printf(" commit");
172317680Spst		dp = parserep(rp, length);
172426183Sfenner		if (dp != NULL && parsewccres(dp, vflag) != 0)
172517680Spst			return;
172617680Spst		break;
172717680Spst
172817680Spst	default:
172926183Sfenner		printf(" proc-%u", proc);
173017680Spst		return;
173117680Spst	}
173218976Sdfrtrunc:
173326183Sfenner	if (!nfserr)
173426183Sfenner		fputs(" [|nfs]", stdout);
173517680Spst}
1736