GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tcpdump/print-nfs.c Lines: 0 796 0.0 %
Date: 2017-11-07 Branches: 0 771 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: print-nfs.c,v 1.22 2016/01/15 03:03:07 mmcc Exp $	*/
2
3
/*
4
 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that: (1) source code distributions
9
 * retain the above copyright notice and this paragraph in its entirety, (2)
10
 * distributions including binary code include the above copyright notice and
11
 * this paragraph in its entirety in the documentation or other materials
12
 * provided with the distribution, and (3) all advertising materials mentioning
13
 * features or use of this software display the following acknowledgement:
14
 * ``This product includes software developed by the University of California,
15
 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16
 * the University nor the names of its contributors may be used to endorse
17
 * or promote products derived from this software without specific prior
18
 * written permission.
19
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22
 */
23
24
#include <sys/time.h>
25
#include <sys/socket.h>
26
27
struct mbuf;
28
struct rtentry;
29
#include <net/if.h>
30
31
#include <netinet/in.h>
32
#include <netinet/if_ether.h>
33
#include <netinet/ip.h>
34
#include <netinet/ip_var.h>
35
36
#ifdef INET6
37
#include <netinet/ip6.h>
38
#endif /*INET6*/
39
40
#include <rpc/rpc.h>
41
42
#include <ctype.h>
43
#include <pcap.h>
44
#include <stdio.h>
45
#include <string.h>
46
47
#include "interface.h"
48
#include "addrtoname.h"
49
50
#include "nfs.h"
51
#include "nfsfh.h"
52
53
static void nfs_printfh(const u_int32_t *, const u_int);
54
static void xid_map_enter(const struct rpc_msg *, const u_char *);
55
static int32_t xid_map_find(const struct rpc_msg *, const u_char *,
56
			    u_int32_t *, u_int32_t *);
57
static void interp_reply(const struct rpc_msg *, u_int32_t, u_int32_t, int);
58
static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
59
static void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
60
static int print_int64(const u_int32_t *dp, int how);
61
62
/*
63
 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
64
 */
65
u_int32_t nfsv3_procid[NFS_NPROCS] = {
66
	NFSPROC_NULL,
67
	NFSPROC_GETATTR,
68
	NFSPROC_SETATTR,
69
	NFSPROC_NOOP,
70
	NFSPROC_LOOKUP,
71
	NFSPROC_READLINK,
72
	NFSPROC_READ,
73
	NFSPROC_NOOP,
74
	NFSPROC_WRITE,
75
	NFSPROC_CREATE,
76
	NFSPROC_REMOVE,
77
	NFSPROC_RENAME,
78
	NFSPROC_LINK,
79
	NFSPROC_SYMLINK,
80
	NFSPROC_MKDIR,
81
	NFSPROC_RMDIR,
82
	NFSPROC_READDIR,
83
	NFSPROC_FSSTAT,
84
	NFSPROC_NOOP,
85
	NFSPROC_NOOP,
86
	NFSPROC_NOOP,
87
	NFSPROC_NOOP,
88
	NFSPROC_NOOP,
89
	NFSPROC_NOOP,
90
	NFSPROC_NOOP,
91
	NFSPROC_NOOP
92
};
93
94
95
static struct tok nfsvers2str[] = {
96
	{ NFS_VER2,	"NFSv2" },
97
	{ NFS_VER3,	"NFSv3" },
98
	{ NFS_VER4,	"NFSv4" },
99
	{ 0, NULL }
100
};
101
102
/*
103
 * NFS V2 and V3 status values.
104
 *
105
 * Some of these come from the RFCs for NFS V2 and V3, with the message
106
 * strings taken from the FreeBSD C library "errlst.c".
107
 *
108
 * Others are errors that are not in the RFC but that I suspect some
109
 * NFS servers could return; the values are FreeBSD errno values, as
110
 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
111
 * was primarily BSD-derived.
112
 */
113
static struct tok status2str[] = {
114
	{ 1,     "Operation not permitted" },	/* EPERM */
115
	{ 2,     "No such file or directory" },	/* ENOENT */
116
	{ 5,     "Input/output error" },	/* EIO */
117
	{ 6,     "Device not configured" },	/* ENXIO */
118
	{ 11,    "Resource deadlock avoided" },	/* EDEADLK */
119
	{ 12,    "Cannot allocate memory" },	/* ENOMEM */
120
	{ 13,    "Permission denied" },		/* EACCES */
121
	{ 17,    "File exists" },		/* EEXIST */
122
	{ 18,    "Cross-device link" },		/* EXDEV */
123
	{ 19,    "Operation not supported by device" }, /* ENODEV */
124
	{ 20,    "Not a directory" },		/* ENOTDIR */
125
	{ 21,    "Is a directory" },		/* EISDIR */
126
	{ 22,    "Invalid argument" },		/* EINVAL */
127
	{ 26,    "Text file busy" },		/* ETXTBSY */
128
	{ 27,    "File too large" },		/* EFBIG */
129
	{ 28,    "No space left on device" },	/* ENOSPC */
130
	{ 30,    "Read-only file system" },	/* EROFS */
131
	{ 31,    "Too many links" },		/* EMLINK */
132
	{ 45,    "Operation not supported" },	/* EOPNOTSUPP */
133
	{ 62,    "Too many levels of symbolic links" }, /* ELOOP */
134
	{ 63,    "File name too long" },	/* ENAMETOOLONG */
135
	{ 66,    "Directory not empty" },	/* ENOTEMPTY */
136
	{ 69,    "Disc quota exceeded" },	/* EDQUOT */
137
	{ 70,    "Stale NFS file handle" },	/* ESTALE */
138
	{ 71,    "Too many levels of remote in path" }, /* EREMOTE */
139
	{ 99,    "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
140
	{ 10001, "Illegal NFS file handle" },	/* NFS3ERR_BADHANDLE */
141
	{ 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
142
	{ 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
143
	{ 10004, "Operation not supported" },	/* NFS3ERR_NOTSUPP */
144
	{ 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
145
	{ 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
146
	{ 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
147
	{ 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
148
	{ 0,     NULL }
149
};
150
151
static struct tok nfsv3_writemodes[] = {
152
	{ 0,		"unstable" },
153
	{ 1,		"datasync" },
154
	{ 2,		"filesync" },
155
	{ 0,		NULL }
156
};
157
158
static struct tok type2str[] = {
159
	{ NFNON,	"NON" },
160
	{ NFREG,	"REG" },
161
	{ NFDIR,	"DIR" },
162
	{ NFBLK,	"BLK" },
163
	{ NFCHR,	"CHR" },
164
	{ NFLNK,	"LNK" },
165
	{ NFFIFO,	"FIFO" },
166
	{ 0,		NULL }
167
};
168
169
/*
170
 * Print out a 64-bit integer. This appears to be different on each system,
171
 * try to make the best of it. The integer stored as 2 consecutive XDR
172
 * encoded 32-bit integers, to which a pointer is passed.
173
 *
174
 * Assume that a system that has INT64_FORMAT defined, has a 64-bit
175
 * integer datatype and can print it.
176
 */
177
178
#define UNSIGNED 0
179
#define SIGNED   1
180
#define HEX      2
181
182
static int print_int64(const u_int32_t *dp, int how)
183
{
184
#ifdef INT64_FORMAT
185
	u_int64_t res;
186
187
	TCHECK(dp[1]);
188
	res = ((u_int64_t)ntohl(dp[0]) << 32) | (u_int64_t)ntohl(dp[1]);
189
	switch (how) {
190
	case SIGNED:
191
		printf(INT64_FORMAT, res);
192
		break;
193
	case UNSIGNED:
194
		printf(U_INT64_FORMAT, res);
195
		break;
196
	case HEX:
197
		printf(HEX_INT64_FORMAT, res);
198
		break;
199
	default:
200
		return (0);
201
	}
202
#else
203
	switch (how) {
204
	case SIGNED:
205
	case UNSIGNED:
206
	case HEX:
207
		TCHECK(dp[1]);
208
		if (dp[0])
209
			printf("0x%x%08x", (u_int32_t)ntohl(dp[0]),
210
			    (u_int32_t)ntohl(dp[1]));
211
		else
212
			printf("0x%x", (u_int32_t)ntohl(dp[1]));
213
		break;
214
	default:
215
		return (0);
216
	}
217
#endif
218
	return 1;
219
220
trunc:
221
	return (0);
222
}
223
224
static const u_int32_t *
225
parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
226
{
227
	TCHECK(dp[0]);
228
	if ((sa3->sa_modeset = ntohl(*dp++))) {
229
		TCHECK(dp[0]);
230
		sa3->sa_mode = ntohl(*dp++);
231
	}
232
233
	TCHECK(dp[0]);
234
	if ((sa3->sa_uidset = ntohl(*dp++))) {
235
		TCHECK(dp[0]);
236
		sa3->sa_uid = ntohl(*dp++);
237
	}
238
239
	TCHECK(dp[0]);
240
	if ((sa3->sa_gidset = ntohl(*dp++))) {
241
		TCHECK(dp[0]);
242
		sa3->sa_gid = ntohl(*dp++);
243
	}
244
245
	TCHECK(dp[0]);
246
	if ((sa3->sa_sizeset = ntohl(*dp++))) {
247
		TCHECK(dp[0]);
248
		sa3->sa_size = ntohl(*dp++);
249
	}
250
251
	TCHECK(dp[0]);
252
	if ((sa3->sa_atimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
253
		TCHECK(dp[1]);
254
		sa3->sa_atime.nfsv3_sec = ntohl(*dp++);
255
		sa3->sa_atime.nfsv3_nsec = ntohl(*dp++);
256
	}
257
258
	TCHECK(dp[0]);
259
	if ((sa3->sa_mtimetype = ntohl(*dp++)) == NFSV3SATTRTIME_TOCLIENT) {
260
		TCHECK(dp[1]);
261
		sa3->sa_mtime.nfsv3_sec = ntohl(*dp++);
262
		sa3->sa_mtime.nfsv3_nsec = ntohl(*dp++);
263
	}
264
265
	return dp;
266
trunc:
267
	return NULL;
268
}
269
270
static int nfserr;		/* true if we error rather than trunc */
271
272
static void
273
print_sattr3(const struct nfsv3_sattr *sa3, int verbose)
274
{
275
	if (sa3->sa_modeset)
276
		printf(" mode %o", sa3->sa_mode);
277
	if (sa3->sa_uidset)
278
		printf(" uid %u", sa3->sa_uid);
279
	if (sa3->sa_gidset)
280
		printf(" gid %u", sa3->sa_gid);
281
	if (verbose > 1) {
282
		if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
283
			printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
284
			       sa3->sa_atime.nfsv3_nsec);
285
		if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
286
			printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
287
			       sa3->sa_mtime.nfsv3_nsec);
288
	}
289
}
290
291
void
292
nfsreply_print(const u_char *bp, u_int length, const u_char *bp2)
293
{
294
	const struct rpc_msg *rp;
295
	u_int32_t proc, vers;
296
297
	nfserr = 0;		/* assume no error */
298
	rp = (const struct rpc_msg *)bp;
299
300
	printf("xid 0x%x reply %s %d", (u_int32_t)ntohl(rp->rm_xid),
301
		ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED ? "ok":"ERR",
302
		length);
303
	if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
304
		interp_reply(rp, proc, vers, length);
305
}
306
307
/*
308
 * Return a pointer to the first file handle in the packet.
309
 * If the packet was truncated, return 0.
310
 */
311
static const u_int32_t *
312
parsereq(const struct rpc_msg *rp, u_int length)
313
{
314
	const u_int32_t *dp;
315
	u_int len;
316
317
	/*
318
	 * find the start of the req data (if we captured it)
319
	 */
320
	dp = (u_int32_t *)&rp->rm_call.cb_cred;
321
	TCHECK(dp[1]);
322
	len = ntohl(dp[1]);
323
	if (len < length) {
324
		dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
325
		TCHECK(dp[1]);
326
		len = ntohl(dp[1]);
327
		if (len < length) {
328
			dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
329
			TCHECK2(dp[0], 0);
330
			return (dp);
331
		}
332
	}
333
trunc:
334
	return (NULL);
335
}
336
337
/*
338
 * Print out an NFS file handle and return a pointer to following word.
339
 * If packet was truncated, return 0.
340
 */
341
static const u_int32_t *
342
parsefh(const u_int32_t *dp, int v3)
343
{
344
	int len;
345
346
	if (v3) {
347
		TCHECK(dp[0]);
348
		len = (int)ntohl(*dp) / 4;
349
		dp++;
350
	} else
351
		len = NFSX_V2FH / 4;
352
353
	if (TTEST2(*dp, len * sizeof(*dp))) {
354
		nfs_printfh(dp, len);
355
		return (dp + len);
356
	}
357
trunc:
358
	return (NULL);
359
}
360
361
/*
362
 * Print out a file name and return pointer to 32-bit word past it.
363
 * If packet was truncated, return 0.
364
 */
365
static const u_int32_t *
366
parsefn(const u_int32_t *dp)
367
{
368
	u_int32_t len;
369
	const u_char *cp;
370
371
	/* Bail if we don't have the string length */
372
	TCHECK(*dp);
373
374
	/* Fetch string length; convert to host order */
375
	len = *dp++;
376
	NTOHL(len);
377
378
	TCHECK2(*dp, ((len + 3) & ~3));
379
380
	cp = (u_char *)dp;
381
	/* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
382
	dp += ((len + 3) & ~3) / sizeof(*dp);
383
	putchar('"');
384
	if (fn_printn(cp, len, snapend)) {
385
		putchar('"');
386
		goto trunc;
387
	}
388
	putchar('"');
389
390
	return (dp);
391
trunc:
392
	return NULL;
393
}
394
395
/*
396
 * Print out file handle and file name.
397
 * Return pointer to 32-bit word past file name.
398
 * If packet was truncated (or there was some other error), return 0.
399
 */
400
static const u_int32_t *
401
parsefhn(const u_int32_t *dp, int v3)
402
{
403
	dp = parsefh(dp, v3);
404
	if (dp == NULL)
405
		return (NULL);
406
	putchar(' ');
407
	return (parsefn(dp));
408
}
409
410
void
411
nfsreq_print(const u_char *bp, u_int length, const u_char *bp2)
412
{
413
	const struct rpc_msg *rp;
414
	const u_int32_t *dp;
415
	nfstype type;
416
	int vers;
417
	int v3 = 0;
418
	u_int32_t proc;
419
	struct nfsv3_sattr sa3;
420
421
	nfserr = 0;		/* assume no error */
422
	rp = (const struct rpc_msg *)bp;
423
424
	vers = ntohl(rp->rm_call.cb_vers);
425
	if (vers == NFS_VER3)
426
		v3 = 1;
427
428
	printf("xid 0x%x (%s) %d", (u_int32_t)ntohl(rp->rm_xid),
429
	    tok2str(nfsvers2str, "Unk %i", vers), length);
430
431
	xid_map_enter(rp, bp2);	/* record proc number for later on */
432
	proc = ntohl(rp->rm_call.cb_proc);
433
434
	if (!v3 && proc < NFS_NPROCS)
435
		proc =  nfsv3_procid[proc];
436
437
	switch (proc) {
438
	case NFSPROC_NOOP:
439
		printf(" nop");
440
		return;
441
	case NFSPROC_NULL:
442
		printf(" null");
443
		return;
444
445
	case NFSPROC_GETATTR:
446
		printf(" getattr");
447
		if ((dp = parsereq(rp, length)) != NULL &&
448
		    parsefh(dp, v3) != NULL)
449
			return;
450
		break;
451
452
	case NFSPROC_SETATTR:
453
		printf(" setattr");
454
		if ((dp = parsereq(rp, length)) != NULL &&
455
		    parsefh(dp, v3) != NULL)
456
			return;
457
		break;
458
459
	case NFSPROC_LOOKUP:
460
		printf(" lookup");
461
		if ((dp = parsereq(rp, length)) != NULL &&
462
		    parsefhn(dp, v3) != NULL)
463
			return;
464
		break;
465
466
	case NFSPROC_ACCESS:
467
		printf(" access");
468
		if ((dp = parsereq(rp, length)) != NULL &&
469
		    (dp = parsefh(dp, v3)) != NULL) {
470
			TCHECK(dp[0]);
471
			printf(" %04x", (u_int32_t)ntohl(dp[0]));
472
			return;
473
		}
474
		break;
475
476
	case NFSPROC_READLINK:
477
		printf(" readlink");
478
		if ((dp = parsereq(rp, length)) != NULL &&
479
		    parsefh(dp, v3) != NULL)
480
			return;
481
		break;
482
483
	case NFSPROC_READ:
484
		printf(" read");
485
		if ((dp = parsereq(rp, length)) != NULL &&
486
		    (dp = parsefh(dp, v3)) != NULL) {
487
			if (v3) {
488
				TCHECK(dp[2]);
489
				printf(" %u bytes @ ",
490
				       (u_int32_t) ntohl(dp[2]));
491
				print_int64(dp, UNSIGNED);
492
			} else {
493
				TCHECK(dp[1]);
494
				printf(" %u bytes @ %u",
495
				    (u_int32_t)ntohl(dp[1]),
496
				    (u_int32_t)ntohl(dp[0]));
497
			}
498
			return;
499
		}
500
		break;
501
502
	case NFSPROC_WRITE:
503
		printf(" write");
504
		if ((dp = parsereq(rp, length)) != NULL &&
505
		    (dp = parsefh(dp, v3)) != NULL) {
506
			if (v3) {
507
				TCHECK(dp[4]);
508
				printf(" %u bytes @ ",
509
						(u_int32_t) ntohl(dp[4]));
510
				print_int64(dp, UNSIGNED);
511
				if (vflag) {
512
					dp += 3;
513
					TCHECK(dp[0]);
514
					printf(" <%s>",
515
						tok2str(nfsv3_writemodes,
516
							NULL, ntohl(*dp)));
517
				}
518
			} else {
519
				TCHECK(dp[3]);
520
				printf(" %u (%u) bytes @ %u (%u)",
521
						(u_int32_t)ntohl(dp[3]),
522
						(u_int32_t)ntohl(dp[2]),
523
						(u_int32_t)ntohl(dp[1]),
524
						(u_int32_t)ntohl(dp[0]));
525
			}
526
			return;
527
		}
528
		break;
529
530
	case NFSPROC_CREATE:
531
		printf(" create");
532
		if ((dp = parsereq(rp, length)) != NULL &&
533
		    parsefhn(dp, v3) != NULL)
534
			return;
535
		break;
536
537
	case NFSPROC_MKDIR:
538
		printf(" mkdir");
539
		if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
540
			return;
541
		break;
542
543
	case NFSPROC_SYMLINK:
544
		printf(" symlink");
545
		if ((dp = parsereq(rp, length)) != 0 &&
546
		    (dp = parsefhn(dp, v3)) != 0) {
547
			fputs(" ->", stdout);
548
			if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
549
				break;
550
			if (parsefn(dp) == 0)
551
				break;
552
			if (v3 && vflag)
553
				print_sattr3(&sa3, vflag);
554
			return;
555
		}
556
		break;
557
558
	case NFSPROC_MKNOD:
559
		printf(" mknod");
560
		if ((dp = parsereq(rp, length)) != 0 &&
561
		    (dp = parsefhn(dp, v3)) != 0) {
562
			TCHECK(*dp);
563
			type = (nfstype)ntohl(*dp++);
564
			if ((dp = parse_sattr3(dp, &sa3)) == 0)
565
				break;
566
			printf(" %s", tok2str(type2str, "unk-ft %d", type));
567
			if (vflag && (type == NFCHR || type == NFBLK)) {
568
				TCHECK(dp[1]);
569
				printf(" %u/%u",
570
				       (u_int32_t)ntohl(dp[0]),
571
				       (u_int32_t)ntohl(dp[1]));
572
				dp += 2;
573
			}
574
			if (vflag)
575
				print_sattr3(&sa3, vflag);
576
			return;
577
		}
578
		break;
579
580
	case NFSPROC_REMOVE:
581
		printf(" remove");
582
		if ((dp = parsereq(rp, length)) != NULL &&
583
		    parsefhn(dp, v3) != NULL)
584
			return;
585
		break;
586
587
	case NFSPROC_RMDIR:
588
		printf(" rmdir");
589
		if ((dp = parsereq(rp, length)) != NULL &&
590
		    parsefhn(dp, v3) != NULL)
591
			return;
592
		break;
593
594
	case NFSPROC_RENAME:
595
		printf(" rename");
596
		if ((dp = parsereq(rp, length)) != NULL &&
597
		    (dp = parsefhn(dp, v3)) != NULL) {
598
			fputs(" ->", stdout);
599
			if (parsefhn(dp, v3) != NULL)
600
				return;
601
		}
602
		break;
603
604
	case NFSPROC_LINK:
605
		printf(" link");
606
		if ((dp = parsereq(rp, length)) != NULL &&
607
		    (dp = parsefh(dp, v3)) != NULL) {
608
			fputs(" ->", stdout);
609
			if (parsefhn(dp, v3) != NULL)
610
				return;
611
		}
612
		break;
613
614
	case NFSPROC_READDIR:
615
		printf(" readdir");
616
		if ((dp = parsereq(rp, length)) != NULL &&
617
		    (dp = parsefh(dp, v3)) != NULL) {
618
			if (v3) {
619
				TCHECK(dp[4]);
620
				/*
621
				 * We shouldn't really try to interpret the
622
				 * offset cookie here.
623
				 */
624
				printf(" %u bytes @ ",
625
				    (u_int32_t) ntohl(dp[4]));
626
				print_int64(dp, SIGNED);
627
				if (vflag)
628
					printf(" verf %08x%08x", dp[2],
629
					       dp[3]);
630
			} else {
631
				TCHECK(dp[1]);
632
				/*
633
				 * Print the offset as signed, since -1 is
634
				 * common, but offsets > 2^31 aren't.
635
				 */
636
				printf(" %u bytes @ %d",
637
				    (u_int32_t)ntohl(dp[1]),
638
				    (u_int32_t)ntohl(dp[0]));
639
			}
640
			return;
641
		}
642
		break;
643
644
	case NFSPROC_READDIRPLUS:
645
		printf(" readdirplus");
646
		if ((dp = parsereq(rp, length)) != NULL &&
647
		    (dp = parsefh(dp, v3)) != NULL) {
648
			TCHECK(dp[4]);
649
			/*
650
			 * We don't try to interpret the offset
651
			 * cookie here.
652
			 */
653
			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[4]));
654
			print_int64(dp, SIGNED);
655
			if (vflag) {
656
				TCHECK(dp[5]);
657
				printf(" max %u verf %08x%08x",
658
				       (u_int32_t) ntohl(dp[5]), dp[2], dp[3]);
659
			}
660
			return;
661
		}
662
		break;
663
664
	case NFSPROC_FSSTAT:
665
		printf(" fsstat");
666
		if ((dp = parsereq(rp, length)) != NULL &&
667
		    parsefh(dp, v3) != NULL)
668
			return;
669
		break;
670
671
	case NFSPROC_FSINFO:
672
		printf(" fsinfo");
673
		if ((dp = parsereq(rp, length)) != NULL &&
674
		    parsefh(dp, v3) != NULL)
675
			return;
676
		break;
677
678
	case NFSPROC_PATHCONF:
679
		printf(" pathconf");
680
		if ((dp = parsereq(rp, length)) != NULL &&
681
		    parsefh(dp, v3) != NULL)
682
			return;
683
		break;
684
685
	case NFSPROC_COMMIT:
686
		printf(" commit");
687
		if ((dp = parsereq(rp, length)) != NULL &&
688
		    (dp = parsefh(dp, v3)) != NULL) {
689
			TCHECK(dp[2]);
690
			printf(" %u bytes @ ", (u_int32_t) ntohl(dp[2]));
691
			print_int64(dp, UNSIGNED);
692
			return;
693
		}
694
		break;
695
696
	default:
697
		printf(" proc-%u", (u_int32_t)ntohl(rp->rm_call.cb_proc));
698
		return;
699
	}
700
701
trunc:
702
	if (!nfserr)
703
		fputs(" [|nfs]", stdout);
704
}
705
706
/*
707
 * Print out an NFS file handle.
708
 * We assume packet was not truncated before the end of the
709
 * file handle pointed to by dp.
710
 *
711
 * Note: new version (using portable file-handle parser) doesn't produce
712
 * generation number.  It probably could be made to do that, with some
713
 * additional hacking on the parser code.
714
 */
715
static void
716
nfs_printfh(const u_int32_t *dp, const u_int len)
717
{
718
	my_fsid fsid;
719
	ino_t ino;
720
	char *sfsname = NULL;
721
722
	Parse_fh((caddr_t *)dp, &fsid, &ino, NULL, &sfsname);
723
724
	if (sfsname) {
725
		/* file system ID is ASCII, not numeric, for this server OS */
726
		static char temp[NFSX_V3FHMAX+1];
727
728
		/* Make sure string is null-terminated */
729
		strlcpy(temp, sfsname, sizeof(temp));
730
		/* Remove trailing spaces */
731
		sfsname = strchr(temp, ' ');
732
		if (sfsname)
733
			*sfsname = 0;
734
735
		(void)printf(" fh %s/%u", temp, (u_int32_t)ino);
736
	} else {
737
		(void)printf(" fh %u,%u/%u",
738
		    fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor, (u_int32_t)ino);
739
	}
740
}
741
742
/*
743
 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
744
 * us to match up replies with requests and thus to know how to parse
745
 * the reply.
746
 */
747
748
struct xid_map_entry {
749
	u_int32_t	xid;		/* transaction ID (net order) */
750
	int ipver;			/* IP version (4 or 6) */
751
#ifdef INET6
752
	struct in6_addr	client;		/* client IP address (net order) */
753
	struct in6_addr	server;		/* server IP address (net order) */
754
#else
755
	struct in_addr	client;		/* client IP address (net order) */
756
	struct in_addr	server;		/* server IP address (net order) */
757
#endif /*INET6*/
758
	u_int32_t	proc;		/* call proc number (host order) */
759
	u_int32_t	vers;		/* program version (host order) */
760
};
761
762
/*
763
 * Map entries are kept in an array that we manage as a ring;
764
 * new entries are always added at the tail of the ring.  Initially,
765
 * all the entries are zero and hence don't match anything.
766
 */
767
768
#define	XIDMAPSIZE	64
769
770
struct xid_map_entry xid_map[XIDMAPSIZE];
771
772
int	xid_map_next = 0;
773
int	xid_map_hint = 0;
774
775
static void
776
xid_map_enter(const struct rpc_msg *rp, const u_char *bp)
777
{
778
	struct ip *ip = NULL;
779
#ifdef INET6
780
	struct ip6_hdr *ip6 = NULL;
781
#endif /*INET6*/
782
	struct xid_map_entry *xmep;
783
784
	ip = (struct ip *)bp;
785
786
	xmep = &xid_map[xid_map_next];
787
788
	if (++xid_map_next >= XIDMAPSIZE)
789
		xid_map_next = 0;
790
791
	xmep->xid = rp->rm_xid;
792
	xmep->ipver = ip->ip_v;
793
794
	switch (xmep->ipver) {
795
	case 4:
796
		memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
797
		memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
798
		break;
799
#ifdef INET6
800
	case 6:
801
		ip6 = (struct ip6_hdr *)bp;
802
		memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
803
		memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
804
		break;
805
	default:
806
		return;
807
#endif /*INET6*/
808
	}
809
	xmep->proc = ntohl(rp->rm_call.cb_proc);
810
	xmep->vers = ntohl(rp->rm_call.cb_vers);
811
}
812
813
/*
814
 * Returns 0 and puts NFSPROC_xxx in proc return and
815
 * version in vers return, or returns -1 on failure
816
 */
817
static int
818
xid_map_find(const struct rpc_msg *rp, const u_char *bp, u_int32_t *proc,
819
	     u_int32_t *vers)
820
{
821
	int i;
822
	struct xid_map_entry *xmep;
823
	u_int32_t xid = rp->rm_xid;
824
	struct ip *ip = (struct ip *)bp;
825
#ifdef INET6
826
	struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
827
#endif /*INET6*/
828
	int cmp;
829
830
	/* Start searching from where we last left off */
831
	i = xid_map_hint;
832
	do {
833
		xmep = &xid_map[i];
834
		cmp = 1;
835
		if (xmep->ipver != ip->ip_v || xmep->xid != xid)
836
			goto nextitem;
837
		switch (xmep->ipver) {
838
		case 4:
839
			if (memcmp(&ip->ip_src, &xmep->server,
840
				   sizeof(ip->ip_src)) != 0 ||
841
			    memcmp(&ip->ip_dst, &xmep->client,
842
				   sizeof(ip->ip_dst)) != 0) {
843
				cmp = 0;
844
			}
845
			break;
846
#ifdef INET6
847
		case 6:
848
			if (memcmp(&ip6->ip6_src, &xmep->server,
849
				   sizeof(ip6->ip6_src)) != 0 ||
850
			    memcmp(&ip6->ip6_dst, &xmep->client,
851
				   sizeof(ip6->ip6_dst)) != 0) {
852
				cmp = 0;
853
			}
854
			break;
855
#endif /*INET6*/
856
		default:
857
			cmp = 0;
858
			break;
859
		}
860
		if (cmp) {
861
			/* match */
862
			xid_map_hint = i;
863
			*proc = xmep->proc;
864
			*vers = xmep->vers;
865
			return 0;
866
		}
867
	nextitem:
868
		if (++i >= XIDMAPSIZE)
869
			i = 0;
870
	} while (i != xid_map_hint);
871
872
	/* search failed */
873
	return (-1);
874
}
875
876
/*
877
 * Routines for parsing reply packets
878
 */
879
880
/*
881
 * Return a pointer to the beginning of the actual results.
882
 * If the packet was truncated, return 0.
883
 */
884
static const u_int32_t *
885
parserep(const struct rpc_msg *rp, u_int length)
886
{
887
	const u_int32_t *dp;
888
	u_int len;
889
	enum accept_stat astat;
890
891
	/*
892
	 * Portability note:
893
	 * Here we find the address of the ar_verf credentials.
894
	 * Originally, this calculation was
895
	 *	dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
896
	 * On the wire, the rp_acpt field starts immediately after
897
	 * the (32 bit) rp_stat field.  However, rp_acpt (which is a
898
	 * "struct accepted_reply") contains a "struct opaque_auth",
899
	 * whose internal representation contains a pointer, so on a
900
	 * 64-bit machine the compiler inserts 32 bits of padding
901
	 * before rp->rm_reply.rp_acpt.ar_verf.  So, we cannot use
902
	 * the internal representation to parse the on-the-wire
903
	 * representation.  Instead, we skip past the rp_stat field,
904
	 * which is an "enum" and so occupies one 32-bit word.
905
	 */
906
	dp = ((const u_int32_t *)&rp->rm_reply) + 1;
907
	TCHECK(dp[1]);
908
	len = ntohl(dp[1]);
909
	if (len >= length)
910
		return (NULL);
911
	/*
912
	 * skip past the ar_verf credentials.
913
	 */
914
	dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
915
	TCHECK2(dp[0], 0);
916
917
	/*
918
	 * now we can check the ar_stat field
919
	 */
920
	astat = ntohl(*(enum accept_stat *)dp);
921
	switch (astat) {
922
923
	case SUCCESS:
924
		break;
925
926
	case PROG_UNAVAIL:
927
		printf(" PROG_UNAVAIL");
928
		nfserr = 1;		/* suppress trunc string */
929
		return (NULL);
930
931
	case PROG_MISMATCH:
932
		printf(" PROG_MISMATCH");
933
		nfserr = 1;		/* suppress trunc string */
934
		return (NULL);
935
936
	case PROC_UNAVAIL:
937
		printf(" PROC_UNAVAIL");
938
		nfserr = 1;		/* suppress trunc string */
939
		return (NULL);
940
941
	case GARBAGE_ARGS:
942
		printf(" GARBAGE_ARGS");
943
		nfserr = 1;		/* suppress trunc string */
944
		return (NULL);
945
946
	case SYSTEM_ERR:
947
		printf(" SYSTEM_ERR");
948
		nfserr = 1;		/* suppress trunc string */
949
		return (NULL);
950
951
	default:
952
		printf(" ar_stat %d", astat);
953
		nfserr = 1;		/* suppress trunc string */
954
		return (NULL);
955
	}
956
	/* successful return */
957
	TCHECK2(*dp, sizeof(astat));
958
	return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
959
trunc:
960
	return (0);
961
}
962
963
static const u_int32_t *
964
parsestatus(const u_int32_t *dp, int *er)
965
{
966
	int errnum;
967
968
	TCHECK(dp[0]);
969
970
	errnum = ntohl(dp[0]);
971
	if (er)
972
		*er = errnum;
973
	if (errnum != 0) {
974
		if (!qflag)
975
			printf(" ERROR: %s",
976
			    tok2str(status2str, "unk %d", errnum));
977
		nfserr = 1;
978
	}
979
	return (dp + 1);
980
trunc:
981
	return NULL;
982
}
983
984
static const u_int32_t *
985
parsefattr(const u_int32_t *dp, int verbose, int v3)
986
{
987
	const struct nfs_fattr *fap;
988
989
	fap = (const struct nfs_fattr *)dp;
990
	TCHECK(fap->fa_gid);
991
	if (verbose) {
992
		printf(" %s %o ids %d/%d",
993
		    tok2str(type2str, "unk-ft %d ",
994
		    (u_int32_t)ntohl(fap->fa_type)),
995
		    (u_int32_t)ntohl(fap->fa_mode),
996
		    (u_int32_t)ntohl(fap->fa_uid),
997
		    (u_int32_t) ntohl(fap->fa_gid));
998
		if (v3) {
999
			TCHECK(fap->fa3_size);
1000
			printf(" sz ");
1001
			print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED);
1002
		} else {
1003
			TCHECK(fap->fa2_size);
1004
			printf(" sz %d", (u_int32_t) ntohl(fap->fa2_size));
1005
		}
1006
	}
1007
	/* print lots more stuff */
1008
	if (verbose > 1) {
1009
		if (v3) {
1010
			TCHECK(fap->fa3_ctime);
1011
			printf(" nlink %d rdev %d/%d",
1012
			       (u_int32_t)ntohl(fap->fa_nlink),
1013
			       (u_int32_t) ntohl(fap->fa3_rdev.specdata1),
1014
			       (u_int32_t) ntohl(fap->fa3_rdev.specdata2));
1015
			printf(" fsid ");
1016
			print_int64((u_int32_t *)&fap->fa3_fsid, HEX);
1017
			printf(" fileid ");
1018
			print_int64((u_int32_t *)&fap->fa3_fileid, HEX);
1019
			printf(" a/m/ctime %u.%06u",
1020
			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_sec),
1021
			       (u_int32_t) ntohl(fap->fa3_atime.nfsv3_nsec));
1022
			printf(" %u.%06u",
1023
			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_sec),
1024
			       (u_int32_t) ntohl(fap->fa3_mtime.nfsv3_nsec));
1025
			printf(" %u.%06u",
1026
			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_sec),
1027
			       (u_int32_t) ntohl(fap->fa3_ctime.nfsv3_nsec));
1028
		} else {
1029
			TCHECK(fap->fa2_ctime);
1030
			printf("nlink %d rdev %x fsid %x fileid %x a/m/ctime",
1031
			       (u_int32_t) ntohl(fap->fa_nlink),
1032
			       (u_int32_t) ntohl(fap->fa2_rdev),
1033
			       (u_int32_t) ntohl(fap->fa2_fsid),
1034
			       (u_int32_t) ntohl(fap->fa2_fileid));
1035
			printf(" %u.%06u",
1036
			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_sec),
1037
			       (u_int32_t) ntohl(fap->fa2_atime.nfsv2_usec));
1038
			printf(" %u.%06u",
1039
			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_sec),
1040
			       (u_int32_t) ntohl(fap->fa2_mtime.nfsv2_usec));
1041
			printf(" %u.%06u",
1042
			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_sec),
1043
			       (u_int32_t) ntohl(fap->fa2_ctime.nfsv2_usec));
1044
		}
1045
	}
1046
	return ((const u_int32_t *)((unsigned char *)dp +
1047
		(v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
1048
trunc:
1049
	return (NULL);
1050
}
1051
1052
static int
1053
parseattrstat(const u_int32_t *dp, int verbose, int v3)
1054
{
1055
	int er;
1056
1057
	dp = parsestatus(dp, &er);
1058
	if (dp == NULL)
1059
		return (0);
1060
	if (er)
1061
		return (1);
1062
1063
	return (parsefattr(dp, verbose, v3) != NULL);
1064
}
1065
1066
static int
1067
parsediropres(const u_int32_t *dp)
1068
{
1069
	int er;
1070
1071
	if (!(dp = parsestatus(dp, &er)))
1072
		return (0);
1073
	if (er)
1074
		return (1);
1075
1076
	dp = parsefh(dp, 0);
1077
	if (dp == NULL)
1078
		return (0);
1079
1080
	return (parsefattr(dp, vflag, 0) != NULL);
1081
}
1082
1083
static int
1084
parselinkres(const u_int32_t *dp, int v3)
1085
{
1086
	int er;
1087
1088
	dp = parsestatus(dp, &er);
1089
	if (dp == NULL)
1090
		return(0);
1091
	if (er)
1092
		return(1);
1093
	if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
1094
		return (0);
1095
	putchar(' ');
1096
	return (parsefn(dp) != NULL);
1097
}
1098
1099
static int
1100
parsestatfs(const u_int32_t *dp, int v3)
1101
{
1102
	const struct nfs_statfs *sfsp;
1103
	int er;
1104
1105
	dp = parsestatus(dp, &er);
1106
	if (dp == NULL)
1107
		return (0);
1108
	if (!v3 && er)
1109
		return (1);
1110
1111
	if (qflag)
1112
		return(1);
1113
1114
	if (v3) {
1115
		if (vflag)
1116
			printf(" POST:");
1117
		if (!(dp = parse_post_op_attr(dp, vflag)))
1118
			return (0);
1119
	}
1120
1121
	TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1122
1123
	sfsp = (const struct nfs_statfs *)dp;
1124
1125
	if (v3) {
1126
		printf(" tbytes ");
1127
		print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED);
1128
		printf(" fbytes ");
1129
		print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED);
1130
		printf(" abytes ");
1131
		print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED);
1132
		if (vflag) {
1133
			printf(" tfiles ");
1134
			print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED);
1135
			printf(" ffiles ");
1136
			print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED);
1137
			printf(" afiles ");
1138
			print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED);
1139
			printf(" invar %u",
1140
			       (u_int32_t) ntohl(sfsp->sf_invarsec));
1141
		}
1142
	} else {
1143
		printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1144
			(u_int32_t)ntohl(sfsp->sf_tsize),
1145
			(u_int32_t)ntohl(sfsp->sf_bsize),
1146
			(u_int32_t)ntohl(sfsp->sf_blocks),
1147
			(u_int32_t)ntohl(sfsp->sf_bfree),
1148
			(u_int32_t)ntohl(sfsp->sf_bavail));
1149
	}
1150
1151
	return (1);
1152
trunc:
1153
	return (0);
1154
}
1155
1156
static int
1157
parserddires(const u_int32_t *dp)
1158
{
1159
	int er;
1160
1161
	dp = parsestatus(dp, &er);
1162
	if (dp == NULL)
1163
		return (0);
1164
	if (er)
1165
		return (1);
1166
	if (qflag)
1167
		return (1);
1168
1169
	TCHECK(dp[2]);
1170
	printf(" offset %x size %d ",
1171
	       (u_int32_t)ntohl(dp[0]), (u_int32_t)ntohl(dp[1]));
1172
	if (dp[2] != 0)
1173
		printf(" eof");
1174
1175
	return (1);
1176
trunc:
1177
	return (0);
1178
}
1179
1180
static const u_int32_t *
1181
parse_wcc_attr(const u_int32_t *dp)
1182
{
1183
	printf(" sz ");
1184
	print_int64(dp, UNSIGNED);
1185
	TCHECK(dp[5]);
1186
	printf(" mtime %u.%06u ctime %u.%06u",
1187
	       (u_int32_t)ntohl(dp[2]), (u_int32_t)ntohl(dp[3]),
1188
	       (u_int32_t)ntohl(dp[4]), (u_int32_t)ntohl(dp[5]));
1189
	return (dp + 6);
1190
1191
trunc:
1192
	return (NULL);
1193
}
1194
1195
/*
1196
 * Pre operation attributes. Print only if vflag > 1.
1197
 */
1198
static const u_int32_t *
1199
parse_pre_op_attr(const u_int32_t *dp, int verbose)
1200
{
1201
	TCHECK(dp[0]);
1202
	if (!ntohl(dp[0]))
1203
		return (dp + 1);
1204
	dp++;
1205
	TCHECK2(*dp, 24);
1206
	if (verbose > 1) {
1207
		return parse_wcc_attr(dp);
1208
	} else {
1209
		/* If not verbose enough, just skip over wcc_attr */
1210
		return (dp + 6);
1211
	}
1212
trunc:
1213
	return (NULL);
1214
}
1215
1216
/*
1217
 * Post operation attributes are printed if vflag >= 1
1218
 */
1219
static const u_int32_t *
1220
parse_post_op_attr(const u_int32_t *dp, int verbose)
1221
{
1222
	TCHECK(dp[0]);
1223
	if (!ntohl(dp[0]))
1224
		return (dp + 1);
1225
	dp++;
1226
	if (verbose) {
1227
		return parsefattr(dp, verbose, 1);
1228
	} else
1229
		return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1230
trunc:
1231
	return (NULL);
1232
}
1233
1234
static const u_int32_t *
1235
parse_wcc_data(const u_int32_t *dp, int verbose)
1236
{
1237
	if (verbose > 1)
1238
		printf(" PRE:");
1239
	if (!(dp = parse_pre_op_attr(dp, verbose)))
1240
		return (0);
1241
1242
	if (verbose)
1243
		printf(" POST:");
1244
	return parse_post_op_attr(dp, verbose);
1245
}
1246
1247
static const u_int32_t *
1248
parsecreateopres(const u_int32_t *dp, int verbose)
1249
{
1250
	int er;
1251
1252
	if (!(dp = parsestatus(dp, &er)))
1253
		return (0);
1254
	if (er)
1255
		dp = parse_wcc_data(dp, verbose);
1256
	else {
1257
		TCHECK(dp[0]);
1258
		if (!ntohl(dp[0]))
1259
			return (dp + 1);
1260
		dp++;
1261
		if (!(dp = parsefh(dp, 1)))
1262
			return (0);
1263
		if (verbose) {
1264
			if (!(dp = parse_post_op_attr(dp, verbose)))
1265
				return (0);
1266
			if (vflag > 1) {
1267
				printf(" dir attr:");
1268
				dp = parse_wcc_data(dp, verbose);
1269
			}
1270
		}
1271
	}
1272
	return (dp);
1273
trunc:
1274
	return (NULL);
1275
}
1276
1277
static int
1278
parsewccres(const u_int32_t *dp, int verbose)
1279
{
1280
	int er;
1281
1282
	if (!(dp = parsestatus(dp, &er)))
1283
		return (0);
1284
	return parse_wcc_data(dp, verbose) != 0;
1285
}
1286
1287
static const u_int32_t *
1288
parsev3rddirres(const u_int32_t *dp, int verbose)
1289
{
1290
	int er;
1291
1292
	if (!(dp = parsestatus(dp, &er)))
1293
		return (0);
1294
	if (vflag)
1295
		printf(" POST:");
1296
	if (!(dp = parse_post_op_attr(dp, verbose)))
1297
		return (0);
1298
	if (er)
1299
		return dp;
1300
	if (vflag) {
1301
		TCHECK(dp[1]);
1302
		printf(" verf %08x%08x", dp[0], dp[1]);
1303
		dp += 2;
1304
	}
1305
	return dp;
1306
trunc:
1307
	return (NULL);
1308
}
1309
1310
static int
1311
parsefsinfo(const u_int32_t *dp)
1312
{
1313
	struct nfsv3_fsinfo *sfp;
1314
	int er;
1315
1316
	if (!(dp = parsestatus(dp, &er)))
1317
		return (0);
1318
	if (vflag)
1319
		printf(" POST:");
1320
	if (!(dp = parse_post_op_attr(dp, vflag)))
1321
		return (0);
1322
	if (er)
1323
		return (1);
1324
1325
	sfp = (struct nfsv3_fsinfo *)dp;
1326
	TCHECK(*sfp);
1327
	printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1328
	       (u_int32_t) ntohl(sfp->fs_rtmax),
1329
	       (u_int32_t) ntohl(sfp->fs_rtpref),
1330
	       (u_int32_t) ntohl(sfp->fs_wtmax),
1331
	       (u_int32_t) ntohl(sfp->fs_wtpref),
1332
	       (u_int32_t) ntohl(sfp->fs_dtpref));
1333
	if (vflag) {
1334
		printf(" rtmult %u wtmult %u maxfsz ",
1335
		       (u_int32_t) ntohl(sfp->fs_rtmult),
1336
		       (u_int32_t) ntohl(sfp->fs_wtmult));
1337
		print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED);
1338
		printf(" delta %u.%06u ",
1339
		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_sec),
1340
		       (u_int32_t) ntohl(sfp->fs_timedelta.nfsv3_nsec));
1341
	}
1342
	return (1);
1343
trunc:
1344
	return (0);
1345
}
1346
1347
static int
1348
parsepathconf(const u_int32_t *dp)
1349
{
1350
	int er;
1351
	struct nfsv3_pathconf *spp;
1352
1353
	if (!(dp = parsestatus(dp, &er)))
1354
		return (0);
1355
	if (vflag)
1356
		printf(" POST:");
1357
	if (!(dp = parse_post_op_attr(dp, vflag)))
1358
		return (0);
1359
	if (er)
1360
		return (1);
1361
1362
	spp = (struct nfsv3_pathconf *)dp;
1363
	TCHECK(*spp);
1364
1365
	printf(" linkmax %u namemax %u %s %s %s %s",
1366
	       (u_int32_t) ntohl(spp->pc_linkmax),
1367
	       (u_int32_t) ntohl(spp->pc_namemax),
1368
	       ntohl(spp->pc_notrunc) ? "notrunc" : "",
1369
	       ntohl(spp->pc_chownrestricted) ? "chownres" : "",
1370
	       ntohl(spp->pc_caseinsensitive) ? "igncase" : "",
1371
	       ntohl(spp->pc_casepreserving) ? "keepcase" : "");
1372
	return (1);
1373
trunc:
1374
	return (0);
1375
}
1376
1377
static void
1378
interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
1379
{
1380
	const u_int32_t *dp;
1381
	int v3;
1382
	int er;
1383
1384
	v3 = (vers == NFS_VER3);
1385
1386
	if (!v3 && proc < NFS_NPROCS)
1387
		proc = nfsv3_procid[proc];
1388
1389
	switch (proc) {
1390
1391
	case NFSPROC_NOOP:
1392
		printf(" nop");
1393
		return;
1394
1395
	case NFSPROC_NULL:
1396
		printf(" null");
1397
		return;
1398
1399
	case NFSPROC_GETATTR:
1400
		printf(" getattr");
1401
		dp = parserep(rp, length);
1402
		if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
1403
			return;
1404
		break;
1405
1406
	case NFSPROC_SETATTR:
1407
		printf(" setattr");
1408
		if (!(dp = parserep(rp, length)))
1409
			return;
1410
		if (v3) {
1411
			if (parsewccres(dp, vflag))
1412
				return;
1413
		} else {
1414
			if (parseattrstat(dp, !qflag, 0) != 0)
1415
				return;
1416
		}
1417
		break;
1418
1419
	case NFSPROC_LOOKUP:
1420
		printf(" lookup");
1421
		if (!(dp = parserep(rp, length)))
1422
			break;
1423
		if (v3) {
1424
			if (!(dp = parsestatus(dp, &er)))
1425
				break;
1426
			if (er) {
1427
				if (vflag > 1) {
1428
					printf(" post dattr:");
1429
					dp = parse_post_op_attr(dp, vflag);
1430
				}
1431
			} else {
1432
				if (!(dp = parsefh(dp, v3)))
1433
					break;
1434
				if ((dp = parse_post_op_attr(dp, vflag)) &&
1435
				    vflag > 1) {
1436
					printf(" post dattr:");
1437
					dp = parse_post_op_attr(dp, vflag);
1438
				}
1439
			}
1440
			if (dp)
1441
				return;
1442
		} else {
1443
			if (parsediropres(dp) != 0)
1444
				return;
1445
		}
1446
		break;
1447
1448
	case NFSPROC_ACCESS:
1449
		printf(" access");
1450
		if (!(dp = parserep(rp, length)))
1451
			break;
1452
		if (!(dp = parsestatus(dp, &er)))
1453
			break;
1454
		if (vflag)
1455
			printf(" attr:");
1456
		if (!(dp = parse_post_op_attr(dp, vflag)))
1457
			break;
1458
		if (!er) {
1459
			TCHECK(dp[0]);
1460
			printf(" c %04x", (u_int32_t)ntohl(dp[0]));
1461
		}
1462
		return;
1463
1464
	case NFSPROC_READLINK:
1465
		printf(" readlink");
1466
		dp = parserep(rp, length);
1467
		if (dp != NULL && parselinkres(dp, v3) != 0)
1468
			return;
1469
		break;
1470
1471
	case NFSPROC_READ:
1472
		printf(" read");
1473
		if (!(dp = parserep(rp, length)))
1474
			break;
1475
		if (v3) {
1476
			if (!(dp = parsestatus(dp, &er)))
1477
				break;
1478
			if (!(dp = parse_post_op_attr(dp, vflag)))
1479
				break;
1480
			if (er)
1481
				return;
1482
			if (vflag) {
1483
				TCHECK(dp[1]);
1484
				printf(" %u bytes", (u_int32_t) ntohl(dp[0]));
1485
				if (ntohl(dp[1]))
1486
					printf(" EOF");
1487
			}
1488
			return;
1489
		} else {
1490
			if (parseattrstat(dp, vflag, 0) != 0)
1491
				return;
1492
		}
1493
		break;
1494
1495
	case NFSPROC_WRITE:
1496
		printf(" write");
1497
		if (!(dp = parserep(rp, length)))
1498
			break;
1499
		if (v3) {
1500
			if (!(dp = parsestatus(dp, &er)))
1501
				break;
1502
			if (!(dp = parse_wcc_data(dp, vflag)))
1503
				break;
1504
			if (er)
1505
				return;
1506
			if (vflag) {
1507
				TCHECK(dp[0]);
1508
				printf(" %u bytes", (u_int32_t) ntohl(dp[0]));
1509
				if (vflag > 1) {
1510
					TCHECK(dp[1]);
1511
					printf(" <%s>",
1512
						tok2str(nfsv3_writemodes,
1513
							NULL, ntohl(dp[1])));
1514
				}
1515
				return;
1516
			}
1517
		} else {
1518
			if (parseattrstat(dp, vflag, v3) != 0)
1519
				return;
1520
		}
1521
		break;
1522
1523
	case NFSPROC_CREATE:
1524
		printf(" create");
1525
		if (!(dp = parserep(rp, length)))
1526
			break;
1527
		if (v3) {
1528
			if (parsecreateopres(dp, vflag) != 0)
1529
				return;
1530
		} else {
1531
			if (parsediropres(dp) != 0)
1532
				return;
1533
		}
1534
		break;
1535
1536
	case NFSPROC_MKDIR:
1537
		printf(" mkdir");
1538
		if (!(dp = parserep(rp, length)))
1539
			break;
1540
		if (v3) {
1541
			if (parsecreateopres(dp, vflag) != 0)
1542
				return;
1543
		} else {
1544
			if (parsediropres(dp) != 0)
1545
				return;
1546
		}
1547
		break;
1548
1549
	case NFSPROC_SYMLINK:
1550
		printf(" symlink");
1551
		if (!(dp = parserep(rp, length)))
1552
			break;
1553
		if (v3) {
1554
			if (parsecreateopres(dp, vflag) != 0)
1555
				return;
1556
		} else {
1557
			if (parsestatus(dp, &er) != 0)
1558
				return;
1559
		}
1560
		break;
1561
1562
	case NFSPROC_MKNOD:
1563
		printf(" mknod");
1564
		if (!(dp = parserep(rp, length)))
1565
			break;
1566
		if (parsecreateopres(dp, vflag) != 0)
1567
			return;
1568
		break;
1569
1570
	case NFSPROC_REMOVE:
1571
		printf(" remove");
1572
		if (!(dp = parserep(rp, length)))
1573
			break;
1574
		if (v3) {
1575
			if (parsewccres(dp, vflag))
1576
				return;
1577
		} else {
1578
			if (parsestatus(dp, &er) != 0)
1579
				return;
1580
		}
1581
		break;
1582
1583
	case NFSPROC_RMDIR:
1584
		printf(" rmdir");
1585
		if (!(dp = parserep(rp, length)))
1586
			break;
1587
		if (v3) {
1588
			if (parsewccres(dp, vflag))
1589
				return;
1590
		} else {
1591
			if (parsestatus(dp, &er) != 0)
1592
				return;
1593
		}
1594
		break;
1595
1596
	case NFSPROC_RENAME:
1597
		printf(" rename");
1598
		if (!(dp = parserep(rp, length)))
1599
			break;
1600
		if (v3) {
1601
			if (!(dp = parsestatus(dp, &er)))
1602
				break;
1603
			if (vflag) {
1604
				printf(" from:");
1605
				if (!(dp = parse_wcc_data(dp, vflag)))
1606
					break;
1607
				printf(" to:");
1608
				if (!(dp = parse_wcc_data(dp, vflag)))
1609
					break;
1610
			}
1611
			return;
1612
		} else {
1613
			if (parsestatus(dp, &er) != 0)
1614
				return;
1615
		}
1616
		break;
1617
1618
	case NFSPROC_LINK:
1619
		printf(" link");
1620
		if (!(dp = parserep(rp, length)))
1621
			break;
1622
		if (v3) {
1623
			if (!(dp = parsestatus(dp, &er)))
1624
				break;
1625
			if (vflag) {
1626
				printf(" file POST:");
1627
				if (!(dp = parse_post_op_attr(dp, vflag)))
1628
					break;
1629
				printf(" dir:");
1630
				if (!(dp = parse_wcc_data(dp, vflag)))
1631
					break;
1632
				return;
1633
			}
1634
		} else {
1635
			if (parsestatus(dp, &er) != 0)
1636
				return;
1637
		}
1638
		break;
1639
1640
	case NFSPROC_READDIR:
1641
		printf(" readdir");
1642
		if (!(dp = parserep(rp, length)))
1643
			break;
1644
		if (v3) {
1645
			if (parsev3rddirres(dp, vflag))
1646
				return;
1647
		} else {
1648
			if (parserddires(dp) != 0)
1649
				return;
1650
		}
1651
		break;
1652
1653
	case NFSPROC_READDIRPLUS:
1654
		printf(" readdirplus");
1655
		if (!(dp = parserep(rp, length)))
1656
			break;
1657
		if (parsev3rddirres(dp, vflag))
1658
			return;
1659
		break;
1660
1661
	case NFSPROC_FSSTAT:
1662
		printf(" fsstat");
1663
		dp = parserep(rp, length);
1664
		if (dp != NULL && parsestatfs(dp, v3) != 0)
1665
			return;
1666
		break;
1667
1668
	case NFSPROC_FSINFO:
1669
		printf(" fsinfo");
1670
		dp = parserep(rp, length);
1671
		if (dp != NULL && parsefsinfo(dp) != 0)
1672
			return;
1673
		break;
1674
1675
	case NFSPROC_PATHCONF:
1676
		printf(" pathconf");
1677
		dp = parserep(rp, length);
1678
		if (dp != NULL && parsepathconf(dp) != 0)
1679
			return;
1680
		break;
1681
1682
	case NFSPROC_COMMIT:
1683
		printf(" commit");
1684
		dp = parserep(rp, length);
1685
		if (dp != NULL && parsewccres(dp, vflag) != 0)
1686
			return;
1687
		break;
1688
1689
	default:
1690
		printf(" proc-%u", proc);
1691
		return;
1692
	}
1693
trunc:
1694
	if (!nfserr)
1695
		fputs(" [|nfs]", stdout);
1696
}