xref: /freebsd/contrib/tcpdump/print-nfs.c (revision 4edb46e9a85ca35d3bed523171d11a748861ce82)
14edb46e9SPaul Traina /*
24edb46e9SPaul Traina  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
204edb46e9SPaul Traina  */
214edb46e9SPaul Traina 
224edb46e9SPaul Traina #ifndef lint
234edb46e9SPaul Traina static char rcsid[] =
244edb46e9SPaul Traina     "@(#) $Header: print-nfs.c,v 1.56 96/07/23 14:17:25 leres Exp $ (LBL)";
254edb46e9SPaul Traina #endif
264edb46e9SPaul Traina 
274edb46e9SPaul Traina #include <sys/param.h>
284edb46e9SPaul Traina #include <sys/time.h>
294edb46e9SPaul Traina #include <sys/socket.h>
304edb46e9SPaul Traina 
314edb46e9SPaul Traina #if __STDC__
324edb46e9SPaul Traina struct mbuf;
334edb46e9SPaul Traina struct rtentry;
344edb46e9SPaul Traina #endif
354edb46e9SPaul Traina #include <net/if.h>
364edb46e9SPaul Traina 
374edb46e9SPaul Traina #include <netinet/in.h>
384edb46e9SPaul Traina #include <netinet/if_ether.h>
394edb46e9SPaul Traina #include <netinet/in_systm.h>
404edb46e9SPaul Traina #include <netinet/ip.h>
414edb46e9SPaul Traina #include <netinet/ip_var.h>
424edb46e9SPaul Traina 
434edb46e9SPaul Traina #include <rpc/rpc.h>
444edb46e9SPaul Traina 
454edb46e9SPaul Traina #include <ctype.h>
464edb46e9SPaul Traina #include <pcap.h>
474edb46e9SPaul Traina #include <stdio.h>
484edb46e9SPaul Traina #include <string.h>
494edb46e9SPaul Traina 
504edb46e9SPaul Traina #include "interface.h"
514edb46e9SPaul Traina #include "addrtoname.h"
524edb46e9SPaul Traina 
534edb46e9SPaul Traina #include "nfsv2.h"
544edb46e9SPaul Traina #include "nfsfh.h"
554edb46e9SPaul Traina 
564edb46e9SPaul Traina static void nfs_printfh(const u_int32_t *);
574edb46e9SPaul Traina static void xid_map_enter(const struct rpc_msg *, const struct ip *);
584edb46e9SPaul Traina static int32_t xid_map_find(const struct rpc_msg *, const struct ip *);
594edb46e9SPaul Traina static void interp_reply(const struct rpc_msg *, u_int32_t, u_int);
604edb46e9SPaul Traina 
614edb46e9SPaul Traina void
624edb46e9SPaul Traina nfsreply_print(register const u_char *bp, u_int length,
634edb46e9SPaul Traina 	       register const u_char *bp2)
644edb46e9SPaul Traina {
654edb46e9SPaul Traina 	register const struct rpc_msg *rp;
664edb46e9SPaul Traina 	register const struct ip *ip;
674edb46e9SPaul Traina 	int32_t proc;
684edb46e9SPaul Traina 
694edb46e9SPaul Traina 	rp = (const struct rpc_msg *)bp;
704edb46e9SPaul Traina 	ip = (const struct ip *)bp2;
714edb46e9SPaul Traina 
724edb46e9SPaul Traina 	if (!nflag)
734edb46e9SPaul Traina 		(void)printf("%s.nfs > %s.%x: reply %s %d",
744edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
754edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
764edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
774edb46e9SPaul Traina 			     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
784edb46e9SPaul Traina 				     "ok":"ERR",
794edb46e9SPaul Traina 			     length);
804edb46e9SPaul Traina 	else
814edb46e9SPaul Traina 		(void)printf("%s.%x > %s.%x: reply %s %d",
824edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
834edb46e9SPaul Traina 			     NFS_PORT,
844edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
854edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
864edb46e9SPaul Traina 			     ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED?
874edb46e9SPaul Traina 			     	"ok":"ERR",
884edb46e9SPaul Traina 			     length);
894edb46e9SPaul Traina 
904edb46e9SPaul Traina 	proc = xid_map_find(rp, ip);
914edb46e9SPaul Traina 	if (proc >= 0)
924edb46e9SPaul Traina 		interp_reply(rp, (u_int32_t)proc, length);
934edb46e9SPaul Traina }
944edb46e9SPaul Traina 
954edb46e9SPaul Traina /*
964edb46e9SPaul Traina  * Return a pointer to the first file handle in the packet.
974edb46e9SPaul Traina  * If the packet was truncated, return 0.
984edb46e9SPaul Traina  */
994edb46e9SPaul Traina static const u_int32_t *
1004edb46e9SPaul Traina parsereq(register const struct rpc_msg *rp, register u_int length)
1014edb46e9SPaul Traina {
1024edb46e9SPaul Traina 	register const u_int32_t *dp;
1034edb46e9SPaul Traina 	register u_int len;
1044edb46e9SPaul Traina 
1054edb46e9SPaul Traina 	/*
1064edb46e9SPaul Traina 	 * find the start of the req data (if we captured it)
1074edb46e9SPaul Traina 	 */
1084edb46e9SPaul Traina 	dp = (u_int32_t *)&rp->rm_call.cb_cred;
1094edb46e9SPaul Traina 	TCHECK(dp[1]);
1104edb46e9SPaul Traina 	len = ntohl(dp[1]);
1114edb46e9SPaul Traina 	if (len < length) {
1124edb46e9SPaul Traina 		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
1134edb46e9SPaul Traina 		TCHECK(dp[1]);
1144edb46e9SPaul Traina 		len = ntohl(dp[1]);
1154edb46e9SPaul Traina 		if (len < length) {
1164edb46e9SPaul Traina 			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
1174edb46e9SPaul Traina 			TCHECK2(dp[0], 0);
1184edb46e9SPaul Traina 			return (dp);
1194edb46e9SPaul Traina 		}
1204edb46e9SPaul Traina 	}
1214edb46e9SPaul Traina trunc:
1224edb46e9SPaul Traina 	return (0);
1234edb46e9SPaul Traina }
1244edb46e9SPaul Traina 
1254edb46e9SPaul Traina /*
1264edb46e9SPaul Traina  * Print out an NFS file handle and return a pointer to following word.
1274edb46e9SPaul Traina  * If packet was truncated, return 0.
1284edb46e9SPaul Traina  */
1294edb46e9SPaul Traina static const u_int32_t *
1304edb46e9SPaul Traina parsefh(register const u_int32_t *dp)
1314edb46e9SPaul Traina {
1324edb46e9SPaul Traina 	if (dp + 8 <= (u_int32_t *)snapend) {
1334edb46e9SPaul Traina 		nfs_printfh(dp);
1344edb46e9SPaul Traina 		return (dp + 8);
1354edb46e9SPaul Traina 	}
1364edb46e9SPaul Traina 	return (0);
1374edb46e9SPaul Traina }
1384edb46e9SPaul Traina 
1394edb46e9SPaul Traina /*
1404edb46e9SPaul Traina  * Print out a file name and return pointer to 32-bit word past it.
1414edb46e9SPaul Traina  * If packet was truncated, return 0.
1424edb46e9SPaul Traina  */
1434edb46e9SPaul Traina static const u_int32_t *
1444edb46e9SPaul Traina parsefn(register const u_int32_t *dp)
1454edb46e9SPaul Traina {
1464edb46e9SPaul Traina 	register u_int32_t len;
1474edb46e9SPaul Traina 	register const u_char *cp;
1484edb46e9SPaul Traina 
1494edb46e9SPaul Traina 	/* Bail if we don't have the string length */
1504edb46e9SPaul Traina 	if ((u_char *)dp > snapend - sizeof(*dp))
1514edb46e9SPaul Traina 		return(0);
1524edb46e9SPaul Traina 
1534edb46e9SPaul Traina 	/* Fetch string length; convert to host order */
1544edb46e9SPaul Traina 	len = *dp++;
1554edb46e9SPaul Traina 	NTOHL(len);
1564edb46e9SPaul Traina 
1574edb46e9SPaul Traina 	cp = (u_char *)dp;
1584edb46e9SPaul Traina 	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
1594edb46e9SPaul Traina 	dp += ((len + 3) & ~3) / sizeof(*dp);
1604edb46e9SPaul Traina 	if ((u_char *)dp > snapend)
1614edb46e9SPaul Traina 		return (0);
1624edb46e9SPaul Traina 	/* XXX seems like we should be checking the length */
1634edb46e9SPaul Traina 	putchar('"');
1644edb46e9SPaul Traina 	(void) fn_printn(cp, len, NULL);
1654edb46e9SPaul Traina 	putchar('"');
1664edb46e9SPaul Traina 
1674edb46e9SPaul Traina 	return (dp);
1684edb46e9SPaul Traina }
1694edb46e9SPaul Traina 
1704edb46e9SPaul Traina /*
1714edb46e9SPaul Traina  * Print out file handle and file name.
1724edb46e9SPaul Traina  * Return pointer to 32-bit word past file name.
1734edb46e9SPaul Traina  * If packet was truncated (or there was some other error), return 0.
1744edb46e9SPaul Traina  */
1754edb46e9SPaul Traina static const u_int32_t *
1764edb46e9SPaul Traina parsefhn(register const u_int32_t *dp)
1774edb46e9SPaul Traina {
1784edb46e9SPaul Traina 	dp = parsefh(dp);
1794edb46e9SPaul Traina 	if (dp == 0)
1804edb46e9SPaul Traina 		return (0);
1814edb46e9SPaul Traina 	putchar(' ');
1824edb46e9SPaul Traina 	return (parsefn(dp));
1834edb46e9SPaul Traina }
1844edb46e9SPaul Traina 
1854edb46e9SPaul Traina void
1864edb46e9SPaul Traina nfsreq_print(register const u_char *bp, u_int length,
1874edb46e9SPaul Traina     register const u_char *bp2)
1884edb46e9SPaul Traina {
1894edb46e9SPaul Traina 	register const struct rpc_msg *rp;
1904edb46e9SPaul Traina 	register const struct ip *ip;
1914edb46e9SPaul Traina 	register const u_int32_t *dp;
1924edb46e9SPaul Traina 
1934edb46e9SPaul Traina 	rp = (const struct rpc_msg *)bp;
1944edb46e9SPaul Traina 	ip = (const struct ip *)bp2;
1954edb46e9SPaul Traina 	if (!nflag)
1964edb46e9SPaul Traina 		(void)printf("%s.%x > %s.nfs: %d",
1974edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
1984edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
1994edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
2004edb46e9SPaul Traina 			     length);
2014edb46e9SPaul Traina 	else
2024edb46e9SPaul Traina 		(void)printf("%s.%x > %s.%x: %d",
2034edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_src),
2044edb46e9SPaul Traina 			     (u_int32_t)ntohl(rp->rm_xid),
2054edb46e9SPaul Traina 			     ipaddr_string(&ip->ip_dst),
2064edb46e9SPaul Traina 			     NFS_PORT,
2074edb46e9SPaul Traina 			     length);
2084edb46e9SPaul Traina 
2094edb46e9SPaul Traina 	xid_map_enter(rp, ip);	/* record proc number for later on */
2104edb46e9SPaul Traina 
2114edb46e9SPaul Traina 	switch (ntohl(rp->rm_call.cb_proc)) {
2124edb46e9SPaul Traina #ifdef NFSPROC_NOOP
2134edb46e9SPaul Traina 	case NFSPROC_NOOP:
2144edb46e9SPaul Traina 		printf(" nop");
2154edb46e9SPaul Traina 		return;
2164edb46e9SPaul Traina #else
2174edb46e9SPaul Traina #define NFSPROC_NOOP -1
2184edb46e9SPaul Traina #endif
2194edb46e9SPaul Traina 	case NFSPROC_NULL:
2204edb46e9SPaul Traina 		printf(" null");
2214edb46e9SPaul Traina 		return;
2224edb46e9SPaul Traina 
2234edb46e9SPaul Traina 	case NFSPROC_GETATTR:
2244edb46e9SPaul Traina 		printf(" getattr");
2254edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
2264edb46e9SPaul Traina 			return;
2274edb46e9SPaul Traina 		break;
2284edb46e9SPaul Traina 
2294edb46e9SPaul Traina 	case NFSPROC_SETATTR:
2304edb46e9SPaul Traina 		printf(" setattr");
2314edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
2324edb46e9SPaul Traina 			return;
2334edb46e9SPaul Traina 		break;
2344edb46e9SPaul Traina 
2354edb46e9SPaul Traina #if NFSPROC_ROOT != NFSPROC_NOOP
2364edb46e9SPaul Traina 	case NFSPROC_ROOT:
2374edb46e9SPaul Traina 		printf(" root");
2384edb46e9SPaul Traina 		break;
2394edb46e9SPaul Traina #endif
2404edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
2414edb46e9SPaul Traina 		printf(" lookup");
2424edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
2434edb46e9SPaul Traina 			return;
2444edb46e9SPaul Traina 		break;
2454edb46e9SPaul Traina 
2464edb46e9SPaul Traina 	case NFSPROC_READLINK:
2474edb46e9SPaul Traina 		printf(" readlink");
2484edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
2494edb46e9SPaul Traina 			return;
2504edb46e9SPaul Traina 		break;
2514edb46e9SPaul Traina 
2524edb46e9SPaul Traina 	case NFSPROC_READ:
2534edb46e9SPaul Traina 		printf(" read");
2544edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
2554edb46e9SPaul Traina 		    (dp = parsefh(dp)) != 0) {
2564edb46e9SPaul Traina 			TCHECK2(dp[0], 3 * sizeof(*dp));
2574edb46e9SPaul Traina 			printf(" %u bytes @ %u",
2584edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[1]),
2594edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[0]));
2604edb46e9SPaul Traina 			return;
2614edb46e9SPaul Traina 		}
2624edb46e9SPaul Traina 		break;
2634edb46e9SPaul Traina 
2644edb46e9SPaul Traina #if NFSPROC_WRITECACHE != NFSPROC_NOOP
2654edb46e9SPaul Traina 	case NFSPROC_WRITECACHE:
2664edb46e9SPaul Traina 		printf(" writecache");
2674edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
2684edb46e9SPaul Traina 		    (dp = parsefh(dp)) != 0) {
2694edb46e9SPaul Traina 			TCHECK2(dp[0], 4 * sizeof(*dp));
2704edb46e9SPaul Traina 			printf(" %u (%u) bytes @ %u (%u)",
2714edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[3]),
2724edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[2]),
2734edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[1]),
2744edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[0]));
2754edb46e9SPaul Traina 			return;
2764edb46e9SPaul Traina 		}
2774edb46e9SPaul Traina 		break;
2784edb46e9SPaul Traina #endif
2794edb46e9SPaul Traina 	case NFSPROC_WRITE:
2804edb46e9SPaul Traina 		printf(" write");
2814edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
2824edb46e9SPaul Traina 		    (dp = parsefh(dp)) != 0) {
2834edb46e9SPaul Traina 			TCHECK2(dp[0], 4 * sizeof(*dp));
2844edb46e9SPaul Traina 			printf(" %u (%u) bytes @ %u (%u)",
2854edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[3]),
2864edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[2]),
2874edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[1]),
2884edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[0]));
2894edb46e9SPaul Traina 			return;
2904edb46e9SPaul Traina 		}
2914edb46e9SPaul Traina 		break;
2924edb46e9SPaul Traina 
2934edb46e9SPaul Traina 	case NFSPROC_CREATE:
2944edb46e9SPaul Traina 		printf(" create");
2954edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
2964edb46e9SPaul Traina 			return;
2974edb46e9SPaul Traina 		break;
2984edb46e9SPaul Traina 
2994edb46e9SPaul Traina 	case NFSPROC_REMOVE:
3004edb46e9SPaul Traina 		printf(" remove");
3014edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
3024edb46e9SPaul Traina 			return;
3034edb46e9SPaul Traina 		break;
3044edb46e9SPaul Traina 
3054edb46e9SPaul Traina 	case NFSPROC_RENAME:
3064edb46e9SPaul Traina 		printf(" rename");
3074edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
3084edb46e9SPaul Traina 		    (dp = parsefhn(dp)) != 0) {
3094edb46e9SPaul Traina 			fputs(" ->", stdout);
3104edb46e9SPaul Traina 			if (parsefhn(dp) != 0)
3114edb46e9SPaul Traina 				return;
3124edb46e9SPaul Traina 		}
3134edb46e9SPaul Traina 		break;
3144edb46e9SPaul Traina 
3154edb46e9SPaul Traina 	case NFSPROC_LINK:
3164edb46e9SPaul Traina 		printf(" link");
3174edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
3184edb46e9SPaul Traina 		    (dp = parsefh(dp)) != 0) {
3194edb46e9SPaul Traina 			fputs(" ->", stdout);
3204edb46e9SPaul Traina 			if (parsefhn(dp) != 0)
3214edb46e9SPaul Traina 				return;
3224edb46e9SPaul Traina 		}
3234edb46e9SPaul Traina 		break;
3244edb46e9SPaul Traina 
3254edb46e9SPaul Traina 	case NFSPROC_SYMLINK:
3264edb46e9SPaul Traina 		printf(" symlink");
3274edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
3284edb46e9SPaul Traina 		    (dp = parsefhn(dp)) != 0) {
3294edb46e9SPaul Traina 			fputs(" -> ", stdout);
3304edb46e9SPaul Traina 			if (parsefn(dp) != 0)
3314edb46e9SPaul Traina 				return;
3324edb46e9SPaul Traina 		}
3334edb46e9SPaul Traina 		break;
3344edb46e9SPaul Traina 
3354edb46e9SPaul Traina 	case NFSPROC_MKDIR:
3364edb46e9SPaul Traina 		printf(" mkdir");
3374edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
3384edb46e9SPaul Traina 			return;
3394edb46e9SPaul Traina 		break;
3404edb46e9SPaul Traina 
3414edb46e9SPaul Traina 	case NFSPROC_RMDIR:
3424edb46e9SPaul Traina 		printf(" rmdir");
3434edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
3444edb46e9SPaul Traina 			return;
3454edb46e9SPaul Traina 		break;
3464edb46e9SPaul Traina 
3474edb46e9SPaul Traina 	case NFSPROC_READDIR:
3484edb46e9SPaul Traina 		printf(" readdir");
3494edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 &&
3504edb46e9SPaul Traina 		    (dp = parsefh(dp)) != 0) {
3514edb46e9SPaul Traina 			TCHECK2(dp[0], 2 * sizeof(*dp));
3524edb46e9SPaul Traina 			/*
3534edb46e9SPaul Traina 			 * Print the offset as signed, since -1 is common,
3544edb46e9SPaul Traina 			 * but offsets > 2^31 aren't.
3554edb46e9SPaul Traina 			 */
3564edb46e9SPaul Traina 			printf(" %u bytes @ %d",
3574edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[1]),
3584edb46e9SPaul Traina 			    (u_int32_t)ntohl(dp[0]));
3594edb46e9SPaul Traina 			return;
3604edb46e9SPaul Traina 		}
3614edb46e9SPaul Traina 		break;
3624edb46e9SPaul Traina 
3634edb46e9SPaul Traina 	case NFSPROC_STATFS:
3644edb46e9SPaul Traina 		printf(" statfs");
3654edb46e9SPaul Traina 		if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
3664edb46e9SPaul Traina 			return;
3674edb46e9SPaul Traina 		break;
3684edb46e9SPaul Traina 
3694edb46e9SPaul Traina 	default:
3704edb46e9SPaul Traina 		printf(" proc-%u", (u_int32_t)ntohl(rp->rm_call.cb_proc));
3714edb46e9SPaul Traina 		return;
3724edb46e9SPaul Traina 	}
3734edb46e9SPaul Traina trunc:
3744edb46e9SPaul Traina 	fputs(" [|nfs]", stdout);
3754edb46e9SPaul Traina }
3764edb46e9SPaul Traina 
3774edb46e9SPaul Traina /*
3784edb46e9SPaul Traina  * Print out an NFS file handle.
3794edb46e9SPaul Traina  * We assume packet was not truncated before the end of the
3804edb46e9SPaul Traina  * file handle pointed to by dp.
3814edb46e9SPaul Traina  *
3824edb46e9SPaul Traina  * Note: new version (using portable file-handle parser) doesn't produce
3834edb46e9SPaul Traina  * generation number.  It probably could be made to do that, with some
3844edb46e9SPaul Traina  * additional hacking on the parser code.
3854edb46e9SPaul Traina  */
3864edb46e9SPaul Traina static void
3874edb46e9SPaul Traina nfs_printfh(register const u_int32_t *dp)
3884edb46e9SPaul Traina {
3894edb46e9SPaul Traina 	my_fsid fsid;
3904edb46e9SPaul Traina 	ino_t ino;
3914edb46e9SPaul Traina 	char *sfsname = NULL;
3924edb46e9SPaul Traina 
3934edb46e9SPaul Traina 	Parse_fh((caddr_t*)dp, &fsid, &ino, NULL, &sfsname, 0);
3944edb46e9SPaul Traina 
3954edb46e9SPaul Traina 	if (sfsname) {
3964edb46e9SPaul Traina 	    /* file system ID is ASCII, not numeric, for this server OS */
3974edb46e9SPaul Traina 	    static char temp[NFS_FHSIZE+1];
3984edb46e9SPaul Traina 
3994edb46e9SPaul Traina 	    /* Make sure string is null-terminated */
4004edb46e9SPaul Traina 	    strncpy(temp, sfsname, NFS_FHSIZE);
4014edb46e9SPaul Traina 	    /* Remove trailing spaces */
4024edb46e9SPaul Traina 	    sfsname = strchr(temp, ' ');
4034edb46e9SPaul Traina 	    if (sfsname)
4044edb46e9SPaul Traina 		*sfsname = 0;
4054edb46e9SPaul Traina 
4064edb46e9SPaul Traina 	    (void)printf(" fh %s/%u", temp, (u_int32_t)ino);
4074edb46e9SPaul Traina 	}
4084edb46e9SPaul Traina 	else {
4094edb46e9SPaul Traina 	    (void)printf(" fh %u,%u/%u",
4104edb46e9SPaul Traina 		fsid.fsid_dev.Major,
4114edb46e9SPaul Traina 		fsid.fsid_dev.Minor,
4124edb46e9SPaul Traina 		(u_int32_t)ino);
4134edb46e9SPaul Traina 	}
4144edb46e9SPaul Traina }
4154edb46e9SPaul Traina 
4164edb46e9SPaul Traina /*
4174edb46e9SPaul Traina  * Maintain a small cache of recent client.XID.server/proc pairs, to allow
4184edb46e9SPaul Traina  * us to match up replies with requests and thus to know how to parse
4194edb46e9SPaul Traina  * the reply.
4204edb46e9SPaul Traina  */
4214edb46e9SPaul Traina 
4224edb46e9SPaul Traina struct xid_map_entry {
4234edb46e9SPaul Traina 	u_int32_t		xid;		/* transaction ID (net order) */
4244edb46e9SPaul Traina 	struct in_addr	client;		/* client IP address (net order) */
4254edb46e9SPaul Traina 	struct in_addr	server;		/* server IP address (net order) */
4264edb46e9SPaul Traina 	u_int32_t		proc;		/* call proc number (host order) */
4274edb46e9SPaul Traina };
4284edb46e9SPaul Traina 
4294edb46e9SPaul Traina /*
4304edb46e9SPaul Traina  * Map entries are kept in an array that we manage as a ring;
4314edb46e9SPaul Traina  * new entries are always added at the tail of the ring.  Initially,
4324edb46e9SPaul Traina  * all the entries are zero and hence don't match anything.
4334edb46e9SPaul Traina  */
4344edb46e9SPaul Traina 
4354edb46e9SPaul Traina #define	XIDMAPSIZE	64
4364edb46e9SPaul Traina 
4374edb46e9SPaul Traina struct xid_map_entry xid_map[XIDMAPSIZE];
4384edb46e9SPaul Traina 
4394edb46e9SPaul Traina int	xid_map_next = 0;
4404edb46e9SPaul Traina int	xid_map_hint = 0;
4414edb46e9SPaul Traina 
4424edb46e9SPaul Traina static void
4434edb46e9SPaul Traina xid_map_enter(const struct rpc_msg *rp, const struct ip *ip)
4444edb46e9SPaul Traina {
4454edb46e9SPaul Traina 	struct xid_map_entry *xmep;
4464edb46e9SPaul Traina 
4474edb46e9SPaul Traina 	xmep = &xid_map[xid_map_next];
4484edb46e9SPaul Traina 
4494edb46e9SPaul Traina 	if (++xid_map_next >= XIDMAPSIZE)
4504edb46e9SPaul Traina 		xid_map_next = 0;
4514edb46e9SPaul Traina 
4524edb46e9SPaul Traina 	xmep->xid = rp->rm_xid;
4534edb46e9SPaul Traina 	xmep->client = ip->ip_src;
4544edb46e9SPaul Traina 	xmep->server = ip->ip_dst;
4554edb46e9SPaul Traina 	xmep->proc = ntohl(rp->rm_call.cb_proc);
4564edb46e9SPaul Traina }
4574edb46e9SPaul Traina 
4584edb46e9SPaul Traina /* Returns NFSPROC_xxx or -1 on failure */
4594edb46e9SPaul Traina static int32_t
4604edb46e9SPaul Traina xid_map_find(const struct rpc_msg *rp, const struct ip *ip)
4614edb46e9SPaul Traina {
4624edb46e9SPaul Traina 	int i;
4634edb46e9SPaul Traina 	struct xid_map_entry *xmep;
4644edb46e9SPaul Traina 	u_int32_t xid = rp->rm_xid;
4654edb46e9SPaul Traina 	u_int32_t clip = ip->ip_dst.s_addr;
4664edb46e9SPaul Traina 	u_int32_t sip = ip->ip_src.s_addr;
4674edb46e9SPaul Traina 
4684edb46e9SPaul Traina 	/* Start searching from where we last left off */
4694edb46e9SPaul Traina 	i = xid_map_hint;
4704edb46e9SPaul Traina 	do {
4714edb46e9SPaul Traina 		xmep = &xid_map[i];
4724edb46e9SPaul Traina 		if (xmep->xid == xid && xmep->client.s_addr == clip &&
4734edb46e9SPaul Traina 		    xmep->server.s_addr == sip) {
4744edb46e9SPaul Traina 			/* match */
4754edb46e9SPaul Traina 			xid_map_hint = i;
4764edb46e9SPaul Traina 			return ((int32_t)xmep->proc);
4774edb46e9SPaul Traina 		}
4784edb46e9SPaul Traina 		if (++i >= XIDMAPSIZE)
4794edb46e9SPaul Traina 			i = 0;
4804edb46e9SPaul Traina 	} while (i != xid_map_hint);
4814edb46e9SPaul Traina 
4824edb46e9SPaul Traina 	/* search failed */
4834edb46e9SPaul Traina 	return(-1);
4844edb46e9SPaul Traina }
4854edb46e9SPaul Traina 
4864edb46e9SPaul Traina /*
4874edb46e9SPaul Traina  * Routines for parsing reply packets
4884edb46e9SPaul Traina  */
4894edb46e9SPaul Traina 
4904edb46e9SPaul Traina /*
4914edb46e9SPaul Traina  * Return a pointer to the beginning of the actual results.
4924edb46e9SPaul Traina  * If the packet was truncated, return 0.
4934edb46e9SPaul Traina  */
4944edb46e9SPaul Traina static const u_int32_t *
4954edb46e9SPaul Traina parserep(register const struct rpc_msg *rp, register u_int length)
4964edb46e9SPaul Traina {
4974edb46e9SPaul Traina 	register const u_int32_t *dp;
4984edb46e9SPaul Traina 	u_int len;
4994edb46e9SPaul Traina 	enum accept_stat astat;
5004edb46e9SPaul Traina 
5014edb46e9SPaul Traina 	/*
5024edb46e9SPaul Traina 	 * Portability note:
5034edb46e9SPaul Traina 	 * Here we find the address of the ar_verf credentials.
5044edb46e9SPaul Traina 	 * Originally, this calculation was
5054edb46e9SPaul Traina 	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
5064edb46e9SPaul Traina 	 * On the wire, the rp_acpt field starts immediately after
5074edb46e9SPaul Traina 	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
5084edb46e9SPaul Traina 	 * "struct accepted_reply") contains a "struct opaque_auth",
5094edb46e9SPaul Traina 	 * whose internal representation contains a pointer, so on a
5104edb46e9SPaul Traina 	 * 64-bit machine the compiler inserts 32 bits of padding
5114edb46e9SPaul Traina 	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
5124edb46e9SPaul Traina 	 * the internal representation to parse the on-the-wire
5134edb46e9SPaul Traina 	 * representation.  Instead, we skip past the rp_stat field,
5144edb46e9SPaul Traina 	 * which is an "enum" and so occupies one 32-bit word.
5154edb46e9SPaul Traina 	 */
5164edb46e9SPaul Traina 	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
5174edb46e9SPaul Traina 	TCHECK2(dp[0], 1);
5184edb46e9SPaul Traina 		return(0);
5194edb46e9SPaul Traina 	len = ntohl(dp[1]);
5204edb46e9SPaul Traina 	if (len >= length)
5214edb46e9SPaul Traina 		return(0);
5224edb46e9SPaul Traina 	/*
5234edb46e9SPaul Traina 	 * skip past the ar_verf credentials.
5244edb46e9SPaul Traina 	 */
5254edb46e9SPaul Traina 	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
5264edb46e9SPaul Traina 	TCHECK2(dp[0], 0);
5274edb46e9SPaul Traina 
5284edb46e9SPaul Traina 	/*
5294edb46e9SPaul Traina 	 * now we can check the ar_stat field
5304edb46e9SPaul Traina 	 */
5314edb46e9SPaul Traina 	astat = ntohl(*(enum accept_stat *)dp);
5324edb46e9SPaul Traina 	switch (astat) {
5334edb46e9SPaul Traina 
5344edb46e9SPaul Traina 	case SUCCESS:
5354edb46e9SPaul Traina 		break;
5364edb46e9SPaul Traina 
5374edb46e9SPaul Traina 	case PROG_UNAVAIL:
5384edb46e9SPaul Traina 		printf(" PROG_UNAVAIL");
5394edb46e9SPaul Traina 		return(0);
5404edb46e9SPaul Traina 
5414edb46e9SPaul Traina 	case PROG_MISMATCH:
5424edb46e9SPaul Traina 		printf(" PROG_MISMATCH");
5434edb46e9SPaul Traina 		return(0);
5444edb46e9SPaul Traina 
5454edb46e9SPaul Traina 	case PROC_UNAVAIL:
5464edb46e9SPaul Traina 		printf(" PROC_UNAVAIL");
5474edb46e9SPaul Traina 		return(0);
5484edb46e9SPaul Traina 
5494edb46e9SPaul Traina 	case GARBAGE_ARGS:
5504edb46e9SPaul Traina 		printf(" GARBAGE_ARGS");
5514edb46e9SPaul Traina 		return(0);
5524edb46e9SPaul Traina 
5534edb46e9SPaul Traina 	case SYSTEM_ERR:
5544edb46e9SPaul Traina 		printf(" SYSTEM_ERR");
5554edb46e9SPaul Traina 		return(0);
5564edb46e9SPaul Traina 
5574edb46e9SPaul Traina 	default:
5584edb46e9SPaul Traina 		printf(" ar_stat %d", astat);
5594edb46e9SPaul Traina 		return(0);
5604edb46e9SPaul Traina 	}
5614edb46e9SPaul Traina 	/* successful return */
5624edb46e9SPaul Traina 	if ((sizeof(astat) + ((u_char *)dp)) < snapend)
5634edb46e9SPaul Traina 		return((u_int32_t *) (sizeof(astat) + ((char *)dp)));
5644edb46e9SPaul Traina 
5654edb46e9SPaul Traina trunc:
5664edb46e9SPaul Traina 	return (0);
5674edb46e9SPaul Traina }
5684edb46e9SPaul Traina 
5694edb46e9SPaul Traina static const u_int32_t *
5704edb46e9SPaul Traina parsestatus(const u_int32_t *dp)
5714edb46e9SPaul Traina {
5724edb46e9SPaul Traina 	int errnum;
5734edb46e9SPaul Traina 
5744edb46e9SPaul Traina 	TCHECK(dp[0]);
5754edb46e9SPaul Traina 	errnum = ntohl(dp[0]);
5764edb46e9SPaul Traina 	if (errnum != 0) {
5774edb46e9SPaul Traina 		char *errmsg;
5784edb46e9SPaul Traina 
5794edb46e9SPaul Traina 		if (qflag)
5804edb46e9SPaul Traina 			return(0);
5814edb46e9SPaul Traina 
5824edb46e9SPaul Traina 		errmsg = pcap_strerror(errnum);
5834edb46e9SPaul Traina 		printf(" ERROR: %s", errmsg);
5844edb46e9SPaul Traina 		return(0);
5854edb46e9SPaul Traina 	}
5864edb46e9SPaul Traina 	return (dp + 1);
5874edb46e9SPaul Traina trunc:
5884edb46e9SPaul Traina 	return (0);
5894edb46e9SPaul Traina }
5904edb46e9SPaul Traina 
5914edb46e9SPaul Traina static struct tok type2str[] = {
5924edb46e9SPaul Traina 	{ NFNON,	"NON" },
5934edb46e9SPaul Traina 	{ NFREG,	"REG" },
5944edb46e9SPaul Traina 	{ NFDIR,	"DIR" },
5954edb46e9SPaul Traina 	{ NFBLK,	"BLK" },
5964edb46e9SPaul Traina 	{ NFCHR,	"CHR" },
5974edb46e9SPaul Traina 	{ NFLNK,	"LNK" },
5984edb46e9SPaul Traina 	{ 0,		NULL }
5994edb46e9SPaul Traina };
6004edb46e9SPaul Traina 
6014edb46e9SPaul Traina static const u_int32_t *
6024edb46e9SPaul Traina parsefattr(const u_int32_t *dp, int verbose)
6034edb46e9SPaul Traina {
6044edb46e9SPaul Traina 	const struct nfsv2_fattr *fap;
6054edb46e9SPaul Traina 
6064edb46e9SPaul Traina 	fap = (const struct nfsv2_fattr *)dp;
6074edb46e9SPaul Traina 	if (verbose) {
6084edb46e9SPaul Traina 		TCHECK(fap->fa_nfssize);
6094edb46e9SPaul Traina 		printf(" %s %o ids %u/%u sz %u ",
6104edb46e9SPaul Traina 		    tok2str(type2str, "unk-ft %d ",
6114edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_type)),
6124edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_mode),
6134edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_uid),
6144edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_gid),
6154edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfssize));
6164edb46e9SPaul Traina 	}
6174edb46e9SPaul Traina 	/* print lots more stuff */
6184edb46e9SPaul Traina 	if (verbose > 1) {
6194edb46e9SPaul Traina 		TCHECK(fap->fa_nfsfileid);
6204edb46e9SPaul Traina 		printf("nlink %u rdev %x fsid %x nodeid %x a/m/ctime ",
6214edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nlink),
6224edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsrdev),
6234edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsfsid),
6244edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsfileid));
6254edb46e9SPaul Traina 		TCHECK(fap->fa_nfsatime);
6264edb46e9SPaul Traina 		printf("%u.%06u ",
6274edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsatime.nfs_sec),
6284edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsatime.nfs_usec));
6294edb46e9SPaul Traina 		TCHECK(fap->fa_nfsmtime);
6304edb46e9SPaul Traina 		printf("%u.%06u ",
6314edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsmtime.nfs_sec),
6324edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsmtime.nfs_usec));
6334edb46e9SPaul Traina 		TCHECK(fap->fa_nfsctime);
6344edb46e9SPaul Traina 		printf("%u.%06u ",
6354edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsctime.nfs_sec),
6364edb46e9SPaul Traina 		    (u_int32_t)ntohl(fap->fa_nfsctime.nfs_usec));
6374edb46e9SPaul Traina 	}
6384edb46e9SPaul Traina 	return ((const u_int32_t *)&fap[1]);
6394edb46e9SPaul Traina trunc:
6404edb46e9SPaul Traina 	return (NULL);
6414edb46e9SPaul Traina }
6424edb46e9SPaul Traina 
6434edb46e9SPaul Traina static int
6444edb46e9SPaul Traina parseattrstat(const u_int32_t *dp, int verbose)
6454edb46e9SPaul Traina {
6464edb46e9SPaul Traina 	dp = parsestatus(dp);
6474edb46e9SPaul Traina 	if (dp == NULL)
6484edb46e9SPaul Traina 		return (0);
6494edb46e9SPaul Traina 
6504edb46e9SPaul Traina 	return (parsefattr(dp, verbose) != NULL);
6514edb46e9SPaul Traina }
6524edb46e9SPaul Traina 
6534edb46e9SPaul Traina static int
6544edb46e9SPaul Traina parsediropres(const u_int32_t *dp)
6554edb46e9SPaul Traina {
6564edb46e9SPaul Traina 	dp = parsestatus(dp);
6574edb46e9SPaul Traina 	if (dp == NULL)
6584edb46e9SPaul Traina 		return (0);
6594edb46e9SPaul Traina 
6604edb46e9SPaul Traina 	dp = parsefh(dp);
6614edb46e9SPaul Traina 	if (dp == NULL)
6624edb46e9SPaul Traina 		return (0);
6634edb46e9SPaul Traina 
6644edb46e9SPaul Traina 	return (parsefattr(dp, vflag) != NULL);
6654edb46e9SPaul Traina }
6664edb46e9SPaul Traina 
6674edb46e9SPaul Traina static int
6684edb46e9SPaul Traina parselinkres(const u_int32_t *dp)
6694edb46e9SPaul Traina {
6704edb46e9SPaul Traina 	dp = parsestatus(dp);
6714edb46e9SPaul Traina 	if (dp == NULL)
6724edb46e9SPaul Traina 		return(0);
6734edb46e9SPaul Traina 
6744edb46e9SPaul Traina 	putchar(' ');
6754edb46e9SPaul Traina 	return (parsefn(dp) != NULL);
6764edb46e9SPaul Traina }
6774edb46e9SPaul Traina 
6784edb46e9SPaul Traina static int
6794edb46e9SPaul Traina parsestatfs(const u_int32_t *dp)
6804edb46e9SPaul Traina {
6814edb46e9SPaul Traina 	const struct nfsv2_statfs *sfsp;
6824edb46e9SPaul Traina 
6834edb46e9SPaul Traina 	dp = parsestatus(dp);
6844edb46e9SPaul Traina 	if (dp == NULL)
6854edb46e9SPaul Traina 		return(0);
6864edb46e9SPaul Traina 
6874edb46e9SPaul Traina 	if (!qflag) {
6884edb46e9SPaul Traina 		sfsp = (const struct nfsv2_statfs *)dp;
6894edb46e9SPaul Traina 		TCHECK(sfsp->sf_bavail);
6904edb46e9SPaul Traina 		printf(" tsize %u bsize %u blocks %u bfree %u bavail %u",
6914edb46e9SPaul Traina 		    (u_int32_t)ntohl(sfsp->sf_tsize),
6924edb46e9SPaul Traina 		    (u_int32_t)ntohl(sfsp->sf_bsize),
6934edb46e9SPaul Traina 		    (u_int32_t)ntohl(sfsp->sf_blocks),
6944edb46e9SPaul Traina 		    (u_int32_t)ntohl(sfsp->sf_bfree),
6954edb46e9SPaul Traina 		    (u_int32_t)ntohl(sfsp->sf_bavail));
6964edb46e9SPaul Traina 	}
6974edb46e9SPaul Traina 
6984edb46e9SPaul Traina 	return (1);
6994edb46e9SPaul Traina trunc:
7004edb46e9SPaul Traina 	return (0);
7014edb46e9SPaul Traina }
7024edb46e9SPaul Traina 
7034edb46e9SPaul Traina static int
7044edb46e9SPaul Traina parserddires(const u_int32_t *dp)
7054edb46e9SPaul Traina {
7064edb46e9SPaul Traina 	dp = parsestatus(dp);
7074edb46e9SPaul Traina 	if (dp == 0)
7084edb46e9SPaul Traina 		return (0);
7094edb46e9SPaul Traina 	if (!qflag) {
7104edb46e9SPaul Traina 		TCHECK(dp[0]);
7114edb46e9SPaul Traina 		printf(" offset %x", (u_int32_t)ntohl(dp[0]));
7124edb46e9SPaul Traina 		TCHECK(dp[1]);
7134edb46e9SPaul Traina 		printf(" size %u", (u_int32_t)ntohl(dp[1]));
7144edb46e9SPaul Traina 		TCHECK(dp[2]);
7154edb46e9SPaul Traina 		if (dp[2] != 0)
7164edb46e9SPaul Traina 			printf(" eof");
7174edb46e9SPaul Traina 	}
7184edb46e9SPaul Traina 
7194edb46e9SPaul Traina 	return (1);
7204edb46e9SPaul Traina trunc:
7214edb46e9SPaul Traina 	return (0);
7224edb46e9SPaul Traina }
7234edb46e9SPaul Traina 
7244edb46e9SPaul Traina static void
7254edb46e9SPaul Traina interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int length)
7264edb46e9SPaul Traina {
7274edb46e9SPaul Traina 	register const u_int32_t *dp;
7284edb46e9SPaul Traina 
7294edb46e9SPaul Traina 	switch (proc) {
7304edb46e9SPaul Traina 
7314edb46e9SPaul Traina #ifdef NFSPROC_NOOP
7324edb46e9SPaul Traina 	case NFSPROC_NOOP:
7334edb46e9SPaul Traina 		printf(" nop");
7344edb46e9SPaul Traina 		return;
7354edb46e9SPaul Traina #else
7364edb46e9SPaul Traina #define NFSPROC_NOOP -1
7374edb46e9SPaul Traina #endif
7384edb46e9SPaul Traina 	case NFSPROC_NULL:
7394edb46e9SPaul Traina 		printf(" null");
7404edb46e9SPaul Traina 		return;
7414edb46e9SPaul Traina 
7424edb46e9SPaul Traina 	case NFSPROC_GETATTR:
7434edb46e9SPaul Traina 		printf(" getattr");
7444edb46e9SPaul Traina 		dp = parserep(rp, length);
7454edb46e9SPaul Traina 		if (dp != 0 && parseattrstat(dp, !qflag) != 0)
7464edb46e9SPaul Traina 			return;
7474edb46e9SPaul Traina 		break;
7484edb46e9SPaul Traina 
7494edb46e9SPaul Traina 	case NFSPROC_SETATTR:
7504edb46e9SPaul Traina 		printf(" setattr");
7514edb46e9SPaul Traina 		dp = parserep(rp, length);
7524edb46e9SPaul Traina 		if (dp != 0 && parseattrstat(dp, !qflag) != 0)
7534edb46e9SPaul Traina 			return;
7544edb46e9SPaul Traina 		break;
7554edb46e9SPaul Traina 
7564edb46e9SPaul Traina #if NFSPROC_ROOT != NFSPROC_NOOP
7574edb46e9SPaul Traina 	case NFSPROC_ROOT:
7584edb46e9SPaul Traina 		printf(" root");
7594edb46e9SPaul Traina 		break;
7604edb46e9SPaul Traina #endif
7614edb46e9SPaul Traina 	case NFSPROC_LOOKUP:
7624edb46e9SPaul Traina 		printf(" lookup");
7634edb46e9SPaul Traina 		dp = parserep(rp, length);
7644edb46e9SPaul Traina 		if (dp != 0 && parsediropres(dp) != 0)
7654edb46e9SPaul Traina 			return;
7664edb46e9SPaul Traina 		break;
7674edb46e9SPaul Traina 
7684edb46e9SPaul Traina 	case NFSPROC_READLINK:
7694edb46e9SPaul Traina 		printf(" readlink");
7704edb46e9SPaul Traina 		dp = parserep(rp, length);
7714edb46e9SPaul Traina 		if (dp != 0 && parselinkres(dp) != 0)
7724edb46e9SPaul Traina 			return;
7734edb46e9SPaul Traina 		break;
7744edb46e9SPaul Traina 
7754edb46e9SPaul Traina 	case NFSPROC_READ:
7764edb46e9SPaul Traina 		printf(" read");
7774edb46e9SPaul Traina 		dp = parserep(rp, length);
7784edb46e9SPaul Traina 		if (dp != 0 && parseattrstat(dp, vflag) != 0)
7794edb46e9SPaul Traina 			return;
7804edb46e9SPaul Traina 		break;
7814edb46e9SPaul Traina 
7824edb46e9SPaul Traina #if NFSPROC_WRITECACHE != NFSPROC_NOOP
7834edb46e9SPaul Traina 	case NFSPROC_WRITECACHE:
7844edb46e9SPaul Traina 		printf(" writecache");
7854edb46e9SPaul Traina 		break;
7864edb46e9SPaul Traina #endif
7874edb46e9SPaul Traina 	case NFSPROC_WRITE:
7884edb46e9SPaul Traina 		printf(" write");
7894edb46e9SPaul Traina 		dp = parserep(rp, length);
7904edb46e9SPaul Traina 		if (dp != 0 && parseattrstat(dp, vflag) != 0)
7914edb46e9SPaul Traina 			return;
7924edb46e9SPaul Traina 		break;
7934edb46e9SPaul Traina 
7944edb46e9SPaul Traina 	case NFSPROC_CREATE:
7954edb46e9SPaul Traina 		printf(" create");
7964edb46e9SPaul Traina 		dp = parserep(rp, length);
7974edb46e9SPaul Traina 		if (dp != 0 && parsediropres(dp) != 0)
7984edb46e9SPaul Traina 			return;
7994edb46e9SPaul Traina 		break;
8004edb46e9SPaul Traina 
8014edb46e9SPaul Traina 	case NFSPROC_REMOVE:
8024edb46e9SPaul Traina 		printf(" remove");
8034edb46e9SPaul Traina 		dp = parserep(rp, length);
8044edb46e9SPaul Traina 		if (dp != 0 && parsestatus(dp) != 0)
8054edb46e9SPaul Traina 			return;
8064edb46e9SPaul Traina 		break;
8074edb46e9SPaul Traina 
8084edb46e9SPaul Traina 	case NFSPROC_RENAME:
8094edb46e9SPaul Traina 		printf(" rename");
8104edb46e9SPaul Traina 		dp = parserep(rp, length);
8114edb46e9SPaul Traina 		if (dp != 0 && parsestatus(dp) != 0)
8124edb46e9SPaul Traina 			return;
8134edb46e9SPaul Traina 		break;
8144edb46e9SPaul Traina 
8154edb46e9SPaul Traina 	case NFSPROC_LINK:
8164edb46e9SPaul Traina 		printf(" link");
8174edb46e9SPaul Traina 		dp = parserep(rp, length);
8184edb46e9SPaul Traina 		if (dp != 0 && parsestatus(dp) != 0)
8194edb46e9SPaul Traina 			return;
8204edb46e9SPaul Traina 		break;
8214edb46e9SPaul Traina 
8224edb46e9SPaul Traina 	case NFSPROC_SYMLINK:
8234edb46e9SPaul Traina 		printf(" symlink");
8244edb46e9SPaul Traina 		dp = parserep(rp, length);
8254edb46e9SPaul Traina 		if (dp != 0 && parsestatus(dp) != 0)
8264edb46e9SPaul Traina 			return;
8274edb46e9SPaul Traina 		break;
8284edb46e9SPaul Traina 
8294edb46e9SPaul Traina 	case NFSPROC_MKDIR:
8304edb46e9SPaul Traina 		printf(" mkdir");
8314edb46e9SPaul Traina 		dp = parserep(rp, length);
8324edb46e9SPaul Traina 		if (dp != 0 && parsediropres(dp) != 0)
8334edb46e9SPaul Traina 			return;
8344edb46e9SPaul Traina 		break;
8354edb46e9SPaul Traina 
8364edb46e9SPaul Traina 	case NFSPROC_RMDIR:
8374edb46e9SPaul Traina 		printf(" rmdir");
8384edb46e9SPaul Traina 		dp = parserep(rp, length);
8394edb46e9SPaul Traina 		if (dp != 0 && parsestatus(dp) != 0)
8404edb46e9SPaul Traina 			return;
8414edb46e9SPaul Traina 		break;
8424edb46e9SPaul Traina 
8434edb46e9SPaul Traina 	case NFSPROC_READDIR:
8444edb46e9SPaul Traina 		printf(" readdir");
8454edb46e9SPaul Traina 		dp = parserep(rp, length);
8464edb46e9SPaul Traina 		if (dp != 0 && parserddires(dp) != 0)
8474edb46e9SPaul Traina 			return;
8484edb46e9SPaul Traina 		break;
8494edb46e9SPaul Traina 
8504edb46e9SPaul Traina 	case NFSPROC_STATFS:
8514edb46e9SPaul Traina 		printf(" statfs");
8524edb46e9SPaul Traina 		dp = parserep(rp, length);
8534edb46e9SPaul Traina 		if (dp != 0 && parsestatfs(dp) != 0)
8544edb46e9SPaul Traina 			return;
8554edb46e9SPaul Traina 		break;
8564edb46e9SPaul Traina 
8574edb46e9SPaul Traina 	default:
8584edb46e9SPaul Traina 		printf(" proc-%u", proc);
8594edb46e9SPaul Traina 		return;
8604edb46e9SPaul Traina 	}
8614edb46e9SPaul Traina 	fputs(" [|nfs]", stdout);
8624edb46e9SPaul Traina }
863