Sync usage with man page.
[netbsd-mini2440.git] / dist / tcpdump / print-nfs.c
blobea26cdebcb485dcfbd920be3750f0c3031f3104b
1 /* $NetBSD$ */
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.
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.
24 #include <sys/cdefs.h>
25 #ifndef lint
26 #if 0
27 static const char rcsid[] _U_ =
28 "@(#) Header: /tcpdump/master/tcpdump/print-nfs.c,v 1.106.2.4 2007/06/15 23:17:40 guy Exp (LBL)";
29 #else
30 __RCSID("$NetBSD: tcpdump2rcsid.ex,v 1.1 2001/06/25 20:09:58 itojun Exp $");
31 #endif
32 #endif
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
38 #include <tcpdump-stdinc.h>
40 #include <pcap.h>
41 #include <stdio.h>
42 #include <string.h>
44 #include "interface.h"
45 #include "addrtoname.h"
46 #include "extract.h"
48 #include "nfs.h"
49 #include "nfsfh.h"
51 #include "ip.h"
52 #ifdef INET6
53 #include "ip6.h"
54 #endif
55 #include "rpc_auth.h"
56 #include "rpc_msg.h"
58 static void nfs_printfh(const u_int32_t *, const u_int);
59 static void xid_map_enter(const struct sunrpc_msg *, const u_char *);
60 static int32_t xid_map_find(const struct sunrpc_msg *, const u_char *,
61 u_int32_t *, u_int32_t *);
62 static void interp_reply(const struct sunrpc_msg *, u_int32_t, u_int32_t, int);
63 static const u_int32_t *parse_post_op_attr(const u_int32_t *, int);
64 static void print_sattr3(const struct nfsv3_sattr *sa3, int verbose);
65 static void print_nfsaddr(const u_char *, const char *, const char *);
68 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
70 u_int32_t nfsv3_procid[NFS_NPROCS] = {
71 NFSPROC_NULL,
72 NFSPROC_GETATTR,
73 NFSPROC_SETATTR,
74 NFSPROC_NOOP,
75 NFSPROC_LOOKUP,
76 NFSPROC_READLINK,
77 NFSPROC_READ,
78 NFSPROC_NOOP,
79 NFSPROC_WRITE,
80 NFSPROC_CREATE,
81 NFSPROC_REMOVE,
82 NFSPROC_RENAME,
83 NFSPROC_LINK,
84 NFSPROC_SYMLINK,
85 NFSPROC_MKDIR,
86 NFSPROC_RMDIR,
87 NFSPROC_READDIR,
88 NFSPROC_FSSTAT,
89 NFSPROC_NOOP,
90 NFSPROC_NOOP,
91 NFSPROC_NOOP,
92 NFSPROC_NOOP,
93 NFSPROC_NOOP,
94 NFSPROC_NOOP,
95 NFSPROC_NOOP,
96 NFSPROC_NOOP
100 * NFS V2 and V3 status values.
102 * Some of these come from the RFCs for NFS V2 and V3, with the message
103 * strings taken from the FreeBSD C library "errlst.c".
105 * Others are errors that are not in the RFC but that I suspect some
106 * NFS servers could return; the values are FreeBSD errno values, as
107 * the first NFS server was the SunOS 2.0 one, and until 5.0 SunOS
108 * was primarily BSD-derived.
110 static struct tok status2str[] = {
111 { 1, "Operation not permitted" }, /* EPERM */
112 { 2, "No such file or directory" }, /* ENOENT */
113 { 5, "Input/output error" }, /* EIO */
114 { 6, "Device not configured" }, /* ENXIO */
115 { 11, "Resource deadlock avoided" }, /* EDEADLK */
116 { 12, "Cannot allocate memory" }, /* ENOMEM */
117 { 13, "Permission denied" }, /* EACCES */
118 { 17, "File exists" }, /* EEXIST */
119 { 18, "Cross-device link" }, /* EXDEV */
120 { 19, "Operation not supported by device" }, /* ENODEV */
121 { 20, "Not a directory" }, /* ENOTDIR */
122 { 21, "Is a directory" }, /* EISDIR */
123 { 22, "Invalid argument" }, /* EINVAL */
124 { 26, "Text file busy" }, /* ETXTBSY */
125 { 27, "File too large" }, /* EFBIG */
126 { 28, "No space left on device" }, /* ENOSPC */
127 { 30, "Read-only file system" }, /* EROFS */
128 { 31, "Too many links" }, /* EMLINK */
129 { 45, "Operation not supported" }, /* EOPNOTSUPP */
130 { 62, "Too many levels of symbolic links" }, /* ELOOP */
131 { 63, "File name too long" }, /* ENAMETOOLONG */
132 { 66, "Directory not empty" }, /* ENOTEMPTY */
133 { 69, "Disc quota exceeded" }, /* EDQUOT */
134 { 70, "Stale NFS file handle" }, /* ESTALE */
135 { 71, "Too many levels of remote in path" }, /* EREMOTE */
136 { 99, "Write cache flushed to disk" }, /* NFSERR_WFLUSH (not used) */
137 { 10001, "Illegal NFS file handle" }, /* NFS3ERR_BADHANDLE */
138 { 10002, "Update synchronization mismatch" }, /* NFS3ERR_NOT_SYNC */
139 { 10003, "READDIR/READDIRPLUS cookie is stale" }, /* NFS3ERR_BAD_COOKIE */
140 { 10004, "Operation not supported" }, /* NFS3ERR_NOTSUPP */
141 { 10005, "Buffer or request is too small" }, /* NFS3ERR_TOOSMALL */
142 { 10006, "Unspecified error on server" }, /* NFS3ERR_SERVERFAULT */
143 { 10007, "Object of that type not supported" }, /* NFS3ERR_BADTYPE */
144 { 10008, "Request couldn't be completed in time" }, /* NFS3ERR_JUKEBOX */
145 { 0, NULL }
148 static struct tok nfsv3_writemodes[] = {
149 { 0, "unstable" },
150 { 1, "datasync" },
151 { 2, "filesync" },
152 { 0, NULL }
155 static struct tok type2str[] = {
156 { NFNON, "NON" },
157 { NFREG, "REG" },
158 { NFDIR, "DIR" },
159 { NFBLK, "BLK" },
160 { NFCHR, "CHR" },
161 { NFLNK, "LNK" },
162 { NFFIFO, "FIFO" },
163 { 0, NULL }
166 static void
167 print_nfsaddr(const u_char *bp, const char *s, const char *d)
169 struct ip *ip;
170 #ifdef INET6
171 struct ip6_hdr *ip6;
172 char srcaddr[INET6_ADDRSTRLEN], dstaddr[INET6_ADDRSTRLEN];
173 #else
174 #ifndef INET_ADDRSTRLEN
175 #define INET_ADDRSTRLEN 16
176 #endif
177 char srcaddr[INET_ADDRSTRLEN], dstaddr[INET_ADDRSTRLEN];
178 #endif
180 srcaddr[0] = dstaddr[0] = '\0';
181 switch (IP_V((struct ip *)bp)) {
182 case 4:
183 ip = (struct ip *)bp;
184 strlcpy(srcaddr, ipaddr_string(&ip->ip_src), sizeof(srcaddr));
185 strlcpy(dstaddr, ipaddr_string(&ip->ip_dst), sizeof(dstaddr));
186 break;
187 #ifdef INET6
188 case 6:
189 ip6 = (struct ip6_hdr *)bp;
190 strlcpy(srcaddr, ip6addr_string(&ip6->ip6_src),
191 sizeof(srcaddr));
192 strlcpy(dstaddr, ip6addr_string(&ip6->ip6_dst),
193 sizeof(dstaddr));
194 break;
195 #endif
196 default:
197 strlcpy(srcaddr, "?", sizeof(srcaddr));
198 strlcpy(dstaddr, "?", sizeof(dstaddr));
199 break;
202 (void)printf("%s.%s > %s.%s: ", srcaddr, s, dstaddr, d);
205 static const u_int32_t *
206 parse_sattr3(const u_int32_t *dp, struct nfsv3_sattr *sa3)
208 TCHECK(dp[0]);
209 sa3->sa_modeset = EXTRACT_32BITS(dp);
210 dp++;
211 if (sa3->sa_modeset) {
212 TCHECK(dp[0]);
213 sa3->sa_mode = EXTRACT_32BITS(dp);
214 dp++;
217 TCHECK(dp[0]);
218 sa3->sa_uidset = EXTRACT_32BITS(dp);
219 dp++;
220 if (sa3->sa_uidset) {
221 TCHECK(dp[0]);
222 sa3->sa_uid = EXTRACT_32BITS(dp);
223 dp++;
226 TCHECK(dp[0]);
227 sa3->sa_gidset = EXTRACT_32BITS(dp);
228 dp++;
229 if (sa3->sa_gidset) {
230 TCHECK(dp[0]);
231 sa3->sa_gid = EXTRACT_32BITS(dp);
232 dp++;
235 TCHECK(dp[0]);
236 sa3->sa_sizeset = EXTRACT_32BITS(dp);
237 dp++;
238 if (sa3->sa_sizeset) {
239 TCHECK(dp[0]);
240 sa3->sa_size = EXTRACT_32BITS(dp);
241 dp++;
244 TCHECK(dp[0]);
245 sa3->sa_atimetype = EXTRACT_32BITS(dp);
246 dp++;
247 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT) {
248 TCHECK(dp[1]);
249 sa3->sa_atime.nfsv3_sec = EXTRACT_32BITS(dp);
250 dp++;
251 sa3->sa_atime.nfsv3_nsec = EXTRACT_32BITS(dp);
252 dp++;
255 TCHECK(dp[0]);
256 sa3->sa_mtimetype = EXTRACT_32BITS(dp);
257 dp++;
258 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT) {
259 TCHECK(dp[1]);
260 sa3->sa_mtime.nfsv3_sec = EXTRACT_32BITS(dp);
261 dp++;
262 sa3->sa_mtime.nfsv3_nsec = EXTRACT_32BITS(dp);
263 dp++;
266 return dp;
267 trunc:
268 return NULL;
271 static int nfserr; /* true if we error rather than trunc */
273 static void
274 print_sattr3(const struct nfsv3_sattr *sa3, int verbose)
276 if (sa3->sa_modeset)
277 printf(" mode %o", sa3->sa_mode);
278 if (sa3->sa_uidset)
279 printf(" uid %u", sa3->sa_uid);
280 if (sa3->sa_gidset)
281 printf(" gid %u", sa3->sa_gid);
282 if (verbose > 1) {
283 if (sa3->sa_atimetype == NFSV3SATTRTIME_TOCLIENT)
284 printf(" atime %u.%06u", sa3->sa_atime.nfsv3_sec,
285 sa3->sa_atime.nfsv3_nsec);
286 if (sa3->sa_mtimetype == NFSV3SATTRTIME_TOCLIENT)
287 printf(" mtime %u.%06u", sa3->sa_mtime.nfsv3_sec,
288 sa3->sa_mtime.nfsv3_nsec);
292 void
293 nfsreply_print(register const u_char *bp, u_int length,
294 register const u_char *bp2)
296 register const struct sunrpc_msg *rp;
297 u_int32_t proc, vers, reply_stat;
298 char srcid[20], dstid[20]; /*fits 32bit*/
299 enum sunrpc_reject_stat rstat;
300 u_int32_t rlow;
301 u_int32_t rhigh;
302 enum sunrpc_auth_stat rwhy;
304 nfserr = 0; /* assume no error */
305 rp = (const struct sunrpc_msg *)bp;
307 if (!nflag) {
308 strlcpy(srcid, "nfs", sizeof(srcid));
309 snprintf(dstid, sizeof(dstid), "%u",
310 EXTRACT_32BITS(&rp->rm_xid));
311 } else {
312 snprintf(srcid, sizeof(srcid), "%u", NFS_PORT);
313 snprintf(dstid, sizeof(dstid), "%u",
314 EXTRACT_32BITS(&rp->rm_xid));
316 print_nfsaddr(bp2, srcid, dstid);
317 reply_stat = EXTRACT_32BITS(&rp->rm_reply.rp_stat);
318 switch (reply_stat) {
320 case SUNRPC_MSG_ACCEPTED:
321 (void)printf("reply ok %u", length);
322 if (xid_map_find(rp, bp2, &proc, &vers) >= 0)
323 interp_reply(rp, proc, vers, length);
324 break;
326 case SUNRPC_MSG_DENIED:
327 (void)printf("reply ERR %u: ", length);
328 rstat = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_stat);
329 switch (rstat) {
331 case SUNRPC_RPC_MISMATCH:
332 rlow = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.low);
333 rhigh = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_vers.high);
334 (void)printf("RPC Version mismatch (%u-%u)",
335 rlow, rhigh);
336 break;
338 case SUNRPC_AUTH_ERROR:
339 rwhy = EXTRACT_32BITS(&rp->rm_reply.rp_reject.rj_why);
340 (void)printf("Auth ");
341 switch (rwhy) {
343 case SUNRPC_AUTH_OK:
344 (void)printf("OK");
345 break;
347 case SUNRPC_AUTH_BADCRED:
348 (void)printf("Bogus Credentials (seal broken)");
349 break;
351 case SUNRPC_AUTH_REJECTEDCRED:
352 (void)printf("Rejected Credentials (client should begin new session)");
353 break;
355 case SUNRPC_AUTH_BADVERF:
356 (void)printf("Bogus Verifier (seal broken)");
357 break;
359 case SUNRPC_AUTH_REJECTEDVERF:
360 (void)printf("Verifier expired or was replayed");
361 break;
363 case SUNRPC_AUTH_TOOWEAK:
364 (void)printf("Credentials are too weak");
365 break;
367 case SUNRPC_AUTH_INVALIDRESP:
368 (void)printf("Bogus response verifier");
369 break;
371 case SUNRPC_AUTH_FAILED:
372 (void)printf("Unknown failure");
373 break;
375 default:
376 (void)printf("Invalid failure code %u",
377 (unsigned int)rwhy);
378 break;
380 break;
382 default:
383 (void)printf("Unknown reason for rejecting rpc message %u",
384 (unsigned int)rstat);
385 break;
387 break;
389 default:
390 (void)printf("reply Unknown rpc response code=%u %u",
391 reply_stat, length);
392 break;
397 * Return a pointer to the first file handle in the packet.
398 * If the packet was truncated, return 0.
400 static const u_int32_t *
401 parsereq(register const struct sunrpc_msg *rp, register u_int length)
403 register const u_int32_t *dp;
404 register u_int len;
407 * find the start of the req data (if we captured it)
409 dp = (u_int32_t *)&rp->rm_call.cb_cred;
410 TCHECK(dp[1]);
411 len = EXTRACT_32BITS(&dp[1]);
412 if (len < length) {
413 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
414 TCHECK(dp[1]);
415 len = EXTRACT_32BITS(&dp[1]);
416 if (len < length) {
417 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp);
418 TCHECK2(dp[0], 0);
419 return (dp);
422 trunc:
423 return (NULL);
427 * Print out an NFS file handle and return a pointer to following word.
428 * If packet was truncated, return 0.
430 static const u_int32_t *
431 parsefh(register const u_int32_t *dp, int v3)
433 u_int len;
435 if (v3) {
436 TCHECK(dp[0]);
437 len = EXTRACT_32BITS(dp) / 4;
438 dp++;
439 } else
440 len = NFSX_V2FH / 4;
442 if (TTEST2(*dp, len * sizeof(*dp))) {
443 nfs_printfh(dp, len);
444 return (dp + len);
446 trunc:
447 return (NULL);
451 * Print out a file name and return pointer to 32-bit word past it.
452 * If packet was truncated, return 0.
454 static const u_int32_t *
455 parsefn(register const u_int32_t *dp)
457 register u_int32_t len;
458 register const u_char *cp;
460 /* Bail if we don't have the string length */
461 TCHECK(*dp);
463 /* Fetch string length; convert to host order */
464 len = *dp++;
465 NTOHL(len);
467 TCHECK2(*dp, ((len + 3) & ~3));
469 cp = (u_char *)dp;
470 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */
471 dp += ((len + 3) & ~3) / sizeof(*dp);
472 putchar('"');
473 if (fn_printn(cp, len, snapend)) {
474 putchar('"');
475 goto trunc;
477 putchar('"');
479 return (dp);
480 trunc:
481 return NULL;
485 * Print out file handle and file name.
486 * Return pointer to 32-bit word past file name.
487 * If packet was truncated (or there was some other error), return 0.
489 static const u_int32_t *
490 parsefhn(register const u_int32_t *dp, int v3)
492 dp = parsefh(dp, v3);
493 if (dp == NULL)
494 return (NULL);
495 putchar(' ');
496 return (parsefn(dp));
499 void
500 nfsreq_print(register const u_char *bp, u_int length,
501 register const u_char *bp2)
503 register const struct sunrpc_msg *rp;
504 register const u_int32_t *dp;
505 nfs_type type;
506 int v3;
507 u_int32_t proc;
508 struct nfsv3_sattr sa3;
509 char srcid[20], dstid[20]; /*fits 32bit*/
511 nfserr = 0; /* assume no error */
512 rp = (const struct sunrpc_msg *)bp;
513 if (!nflag) {
514 snprintf(srcid, sizeof(srcid), "%u",
515 EXTRACT_32BITS(&rp->rm_xid));
516 strlcpy(dstid, "nfs", sizeof(dstid));
517 } else {
518 snprintf(srcid, sizeof(srcid), "%u",
519 EXTRACT_32BITS(&rp->rm_xid));
520 snprintf(dstid, sizeof(dstid), "%u", NFS_PORT);
522 print_nfsaddr(bp2, srcid, dstid);
523 (void)printf("%d", length);
525 xid_map_enter(rp, bp2); /* record proc number for later on */
527 v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3);
528 proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
530 if (!v3 && proc < NFS_NPROCS)
531 proc = nfsv3_procid[proc];
533 switch (proc) {
534 case NFSPROC_NOOP:
535 printf(" nop");
536 return;
537 case NFSPROC_NULL:
538 printf(" null");
539 return;
541 case NFSPROC_GETATTR:
542 printf(" getattr");
543 if ((dp = parsereq(rp, length)) != NULL &&
544 parsefh(dp, v3) != NULL)
545 return;
546 break;
548 case NFSPROC_SETATTR:
549 printf(" setattr");
550 if ((dp = parsereq(rp, length)) != NULL &&
551 parsefh(dp, v3) != NULL)
552 return;
553 break;
555 case NFSPROC_LOOKUP:
556 printf(" lookup");
557 if ((dp = parsereq(rp, length)) != NULL &&
558 parsefhn(dp, v3) != NULL)
559 return;
560 break;
562 case NFSPROC_ACCESS:
563 printf(" access");
564 if ((dp = parsereq(rp, length)) != NULL &&
565 (dp = parsefh(dp, v3)) != NULL) {
566 TCHECK(dp[0]);
567 printf(" %04x", EXTRACT_32BITS(&dp[0]));
568 return;
570 break;
572 case NFSPROC_READLINK:
573 printf(" readlink");
574 if ((dp = parsereq(rp, length)) != NULL &&
575 parsefh(dp, v3) != NULL)
576 return;
577 break;
579 case NFSPROC_READ:
580 printf(" read");
581 if ((dp = parsereq(rp, length)) != NULL &&
582 (dp = parsefh(dp, v3)) != NULL) {
583 if (v3) {
584 TCHECK(dp[2]);
585 printf(" %u bytes @ %" PRIu64,
586 EXTRACT_32BITS(&dp[2]),
587 EXTRACT_64BITS(&dp[0]));
588 } else {
589 TCHECK(dp[1]);
590 printf(" %u bytes @ %u",
591 EXTRACT_32BITS(&dp[1]),
592 EXTRACT_32BITS(&dp[0]));
594 return;
596 break;
598 case NFSPROC_WRITE:
599 printf(" write");
600 if ((dp = parsereq(rp, length)) != NULL &&
601 (dp = parsefh(dp, v3)) != NULL) {
602 if (v3) {
603 TCHECK(dp[2]);
604 printf(" %u (%u) bytes @ %" PRIu64,
605 EXTRACT_32BITS(&dp[4]),
606 EXTRACT_32BITS(&dp[2]),
607 EXTRACT_64BITS(&dp[0]));
608 if (vflag) {
609 dp += 3;
610 TCHECK(dp[0]);
611 printf(" <%s>",
612 tok2str(nfsv3_writemodes,
613 NULL, EXTRACT_32BITS(dp)));
615 } else {
616 TCHECK(dp[3]);
617 printf(" %u (%u) bytes @ %u (%u)",
618 EXTRACT_32BITS(&dp[3]),
619 EXTRACT_32BITS(&dp[2]),
620 EXTRACT_32BITS(&dp[1]),
621 EXTRACT_32BITS(&dp[0]));
623 return;
625 break;
627 case NFSPROC_CREATE:
628 printf(" create");
629 if ((dp = parsereq(rp, length)) != NULL &&
630 parsefhn(dp, v3) != NULL)
631 return;
632 break;
634 case NFSPROC_MKDIR:
635 printf(" mkdir");
636 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0)
637 return;
638 break;
640 case NFSPROC_SYMLINK:
641 printf(" symlink");
642 if ((dp = parsereq(rp, length)) != 0 &&
643 (dp = parsefhn(dp, v3)) != 0) {
644 fputs(" ->", stdout);
645 if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0)
646 break;
647 if (parsefn(dp) == 0)
648 break;
649 if (v3 && vflag)
650 print_sattr3(&sa3, vflag);
651 return;
653 break;
655 case NFSPROC_MKNOD:
656 printf(" mknod");
657 if ((dp = parsereq(rp, length)) != 0 &&
658 (dp = parsefhn(dp, v3)) != 0) {
659 TCHECK(*dp);
660 type = (nfs_type)EXTRACT_32BITS(dp);
661 dp++;
662 if ((dp = parse_sattr3(dp, &sa3)) == 0)
663 break;
664 printf(" %s", tok2str(type2str, "unk-ft %d", type));
665 if (vflag && (type == NFCHR || type == NFBLK)) {
666 TCHECK(dp[1]);
667 printf(" %u/%u",
668 EXTRACT_32BITS(&dp[0]),
669 EXTRACT_32BITS(&dp[1]));
670 dp += 2;
672 if (vflag)
673 print_sattr3(&sa3, vflag);
674 return;
676 break;
678 case NFSPROC_REMOVE:
679 printf(" remove");
680 if ((dp = parsereq(rp, length)) != NULL &&
681 parsefhn(dp, v3) != NULL)
682 return;
683 break;
685 case NFSPROC_RMDIR:
686 printf(" rmdir");
687 if ((dp = parsereq(rp, length)) != NULL &&
688 parsefhn(dp, v3) != NULL)
689 return;
690 break;
692 case NFSPROC_RENAME:
693 printf(" rename");
694 if ((dp = parsereq(rp, length)) != NULL &&
695 (dp = parsefhn(dp, v3)) != NULL) {
696 fputs(" ->", stdout);
697 if (parsefhn(dp, v3) != NULL)
698 return;
700 break;
702 case NFSPROC_LINK:
703 printf(" link");
704 if ((dp = parsereq(rp, length)) != NULL &&
705 (dp = parsefh(dp, v3)) != NULL) {
706 fputs(" ->", stdout);
707 if (parsefhn(dp, v3) != NULL)
708 return;
710 break;
712 case NFSPROC_READDIR:
713 printf(" readdir");
714 if ((dp = parsereq(rp, length)) != NULL &&
715 (dp = parsefh(dp, v3)) != NULL) {
716 if (v3) {
717 TCHECK(dp[4]);
719 * We shouldn't really try to interpret the
720 * offset cookie here.
722 printf(" %u bytes @ %" PRId64,
723 EXTRACT_32BITS(&dp[4]),
724 EXTRACT_64BITS(&dp[0]));
725 if (vflag)
726 printf(" verf %08x%08x", dp[2],
727 dp[3]);
728 } else {
729 TCHECK(dp[1]);
731 * Print the offset as signed, since -1 is
732 * common, but offsets > 2^31 aren't.
734 printf(" %u bytes @ %d",
735 EXTRACT_32BITS(&dp[1]),
736 EXTRACT_32BITS(&dp[0]));
738 return;
740 break;
742 case NFSPROC_READDIRPLUS:
743 printf(" readdirplus");
744 if ((dp = parsereq(rp, length)) != NULL &&
745 (dp = parsefh(dp, v3)) != NULL) {
746 TCHECK(dp[4]);
748 * We don't try to interpret the offset
749 * cookie here.
751 printf(" %u bytes @ %" PRId64,
752 EXTRACT_32BITS(&dp[4]),
753 EXTRACT_64BITS(&dp[0]));
754 if (vflag) {
755 TCHECK(dp[5]);
756 printf(" max %u verf %08x%08x",
757 EXTRACT_32BITS(&dp[5]), dp[2], dp[3]);
759 return;
761 break;
763 case NFSPROC_FSSTAT:
764 printf(" fsstat");
765 if ((dp = parsereq(rp, length)) != NULL &&
766 parsefh(dp, v3) != NULL)
767 return;
768 break;
770 case NFSPROC_FSINFO:
771 printf(" fsinfo");
772 if ((dp = parsereq(rp, length)) != NULL &&
773 parsefh(dp, v3) != NULL)
774 return;
775 break;
777 case NFSPROC_PATHCONF:
778 printf(" pathconf");
779 if ((dp = parsereq(rp, length)) != NULL &&
780 parsefh(dp, v3) != NULL)
781 return;
782 break;
784 case NFSPROC_COMMIT:
785 printf(" commit");
786 if ((dp = parsereq(rp, length)) != NULL &&
787 (dp = parsefh(dp, v3)) != NULL) {
788 TCHECK(dp[2]);
789 printf(" %u bytes @ %" PRIu64,
790 EXTRACT_32BITS(&dp[2]),
791 EXTRACT_64BITS(&dp[0]));
792 return;
794 break;
796 default:
797 printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc));
798 return;
801 trunc:
802 if (!nfserr)
803 fputs(" [|nfs]", stdout);
807 * Print out an NFS file handle.
808 * We assume packet was not truncated before the end of the
809 * file handle pointed to by dp.
811 * Note: new version (using portable file-handle parser) doesn't produce
812 * generation number. It probably could be made to do that, with some
813 * additional hacking on the parser code.
815 static void
816 nfs_printfh(register const u_int32_t *dp, const u_int len)
818 my_fsid fsid;
819 ino_t ino;
820 const char *sfsname = NULL;
821 char *spacep;
823 if (uflag) {
824 u_int i;
825 char const *sep = "";
827 printf(" fh[");
828 for (i=0; i<len; i++) {
829 (void)printf("%s%x", sep, dp[i]);
830 sep = ":";
832 printf("]");
833 return;
836 Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0);
838 if (sfsname) {
839 /* file system ID is ASCII, not numeric, for this server OS */
840 static char temp[NFSX_V3FHMAX+1];
842 /* Make sure string is null-terminated */
843 strncpy(temp, sfsname, NFSX_V3FHMAX);
844 temp[sizeof(temp) - 1] = '\0';
845 /* Remove trailing spaces */
846 spacep = strchr(temp, ' ');
847 if (spacep)
848 *spacep = '\0';
850 (void)printf(" fh %s/", temp);
851 } else {
852 (void)printf(" fh %d,%d/",
853 fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor);
856 if(fsid.Fsid_dev.Minor == 257)
857 /* Print the undecoded handle */
858 (void)printf("%s", fsid.Opaque_Handle);
859 else
860 (void)printf("%ld", (long) ino);
864 * Maintain a small cache of recent client.XID.server/proc pairs, to allow
865 * us to match up replies with requests and thus to know how to parse
866 * the reply.
869 struct xid_map_entry {
870 u_int32_t xid; /* transaction ID (net order) */
871 int ipver; /* IP version (4 or 6) */
872 #ifdef INET6
873 struct in6_addr client; /* client IP address (net order) */
874 struct in6_addr server; /* server IP address (net order) */
875 #else
876 struct in_addr client; /* client IP address (net order) */
877 struct in_addr server; /* server IP address (net order) */
878 #endif
879 u_int32_t proc; /* call proc number (host order) */
880 u_int32_t vers; /* program version (host order) */
884 * Map entries are kept in an array that we manage as a ring;
885 * new entries are always added at the tail of the ring. Initially,
886 * all the entries are zero and hence don't match anything.
889 #define XIDMAPSIZE 64
891 struct xid_map_entry xid_map[XIDMAPSIZE];
893 int xid_map_next = 0;
894 int xid_map_hint = 0;
896 static void
897 xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp)
899 struct ip *ip = NULL;
900 #ifdef INET6
901 struct ip6_hdr *ip6 = NULL;
902 #endif
903 struct xid_map_entry *xmep;
905 switch (IP_V((struct ip *)bp)) {
906 case 4:
907 ip = (struct ip *)bp;
908 break;
909 #ifdef INET6
910 case 6:
911 ip6 = (struct ip6_hdr *)bp;
912 break;
913 #endif
914 default:
915 return;
918 xmep = &xid_map[xid_map_next];
920 if (++xid_map_next >= XIDMAPSIZE)
921 xid_map_next = 0;
923 xmep->xid = rp->rm_xid;
924 if (ip) {
925 xmep->ipver = 4;
926 memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src));
927 memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst));
929 #ifdef INET6
930 else if (ip6) {
931 xmep->ipver = 6;
932 memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src));
933 memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
935 #endif
936 xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc);
937 xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers);
941 * Returns 0 and puts NFSPROC_xxx in proc return and
942 * version in vers return, or returns -1 on failure
944 static int
945 xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc,
946 u_int32_t *vers)
948 int i;
949 struct xid_map_entry *xmep;
950 u_int32_t xid = rp->rm_xid;
951 struct ip *ip = (struct ip *)bp;
952 #ifdef INET6
953 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp;
954 #endif
955 int cmp;
957 /* Start searching from where we last left off */
958 i = xid_map_hint;
959 do {
960 xmep = &xid_map[i];
961 cmp = 1;
962 if (xmep->ipver != IP_V(ip) || xmep->xid != xid)
963 goto nextitem;
964 switch (xmep->ipver) {
965 case 4:
966 if (memcmp(&ip->ip_src, &xmep->server,
967 sizeof(ip->ip_src)) != 0 ||
968 memcmp(&ip->ip_dst, &xmep->client,
969 sizeof(ip->ip_dst)) != 0) {
970 cmp = 0;
972 break;
973 #ifdef INET6
974 case 6:
975 if (memcmp(&ip6->ip6_src, &xmep->server,
976 sizeof(ip6->ip6_src)) != 0 ||
977 memcmp(&ip6->ip6_dst, &xmep->client,
978 sizeof(ip6->ip6_dst)) != 0) {
979 cmp = 0;
981 break;
982 #endif
983 default:
984 cmp = 0;
985 break;
987 if (cmp) {
988 /* match */
989 xid_map_hint = i;
990 *proc = xmep->proc;
991 *vers = xmep->vers;
992 return 0;
994 nextitem:
995 if (++i >= XIDMAPSIZE)
996 i = 0;
997 } while (i != xid_map_hint);
999 /* search failed */
1000 return (-1);
1004 * Routines for parsing reply packets
1008 * Return a pointer to the beginning of the actual results.
1009 * If the packet was truncated, return 0.
1011 static const u_int32_t *
1012 parserep(register const struct sunrpc_msg *rp, register u_int length)
1014 register const u_int32_t *dp;
1015 u_int len;
1016 enum sunrpc_accept_stat astat;
1019 * Portability note:
1020 * Here we find the address of the ar_verf credentials.
1021 * Originally, this calculation was
1022 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf
1023 * On the wire, the rp_acpt field starts immediately after
1024 * the (32 bit) rp_stat field. However, rp_acpt (which is a
1025 * "struct accepted_reply") contains a "struct opaque_auth",
1026 * whose internal representation contains a pointer, so on a
1027 * 64-bit machine the compiler inserts 32 bits of padding
1028 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use
1029 * the internal representation to parse the on-the-wire
1030 * representation. Instead, we skip past the rp_stat field,
1031 * which is an "enum" and so occupies one 32-bit word.
1033 dp = ((const u_int32_t *)&rp->rm_reply) + 1;
1034 TCHECK(dp[1]);
1035 len = EXTRACT_32BITS(&dp[1]);
1036 if (len >= length)
1037 return (NULL);
1039 * skip past the ar_verf credentials.
1041 dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t);
1042 TCHECK2(dp[0], 0);
1045 * now we can check the ar_stat field
1047 astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp);
1048 switch (astat) {
1050 case SUNRPC_SUCCESS:
1051 break;
1053 case SUNRPC_PROG_UNAVAIL:
1054 printf(" PROG_UNAVAIL");
1055 nfserr = 1; /* suppress trunc string */
1056 return (NULL);
1058 case SUNRPC_PROG_MISMATCH:
1059 printf(" PROG_MISMATCH");
1060 nfserr = 1; /* suppress trunc string */
1061 return (NULL);
1063 case SUNRPC_PROC_UNAVAIL:
1064 printf(" PROC_UNAVAIL");
1065 nfserr = 1; /* suppress trunc string */
1066 return (NULL);
1068 case SUNRPC_GARBAGE_ARGS:
1069 printf(" GARBAGE_ARGS");
1070 nfserr = 1; /* suppress trunc string */
1071 return (NULL);
1073 case SUNRPC_SYSTEM_ERR:
1074 printf(" SYSTEM_ERR");
1075 nfserr = 1; /* suppress trunc string */
1076 return (NULL);
1078 default:
1079 printf(" ar_stat %d", astat);
1080 nfserr = 1; /* suppress trunc string */
1081 return (NULL);
1083 /* successful return */
1084 TCHECK2(*dp, sizeof(astat));
1085 return ((u_int32_t *) (sizeof(astat) + ((char *)dp)));
1086 trunc:
1087 return (0);
1090 static const u_int32_t *
1091 parsestatus(const u_int32_t *dp, int *er)
1093 int errnum;
1095 TCHECK(dp[0]);
1097 errnum = EXTRACT_32BITS(&dp[0]);
1098 if (er)
1099 *er = errnum;
1100 if (errnum != 0) {
1101 if (!qflag)
1102 printf(" ERROR: %s",
1103 tok2str(status2str, "unk %d", errnum));
1104 nfserr = 1;
1106 return (dp + 1);
1107 trunc:
1108 return NULL;
1111 static const u_int32_t *
1112 parsefattr(const u_int32_t *dp, int verbose, int v3)
1114 const struct nfs_fattr *fap;
1116 fap = (const struct nfs_fattr *)dp;
1117 TCHECK(fap->fa_gid);
1118 if (verbose) {
1119 printf(" %s %o ids %d/%d",
1120 tok2str(type2str, "unk-ft %d ",
1121 EXTRACT_32BITS(&fap->fa_type)),
1122 EXTRACT_32BITS(&fap->fa_mode),
1123 EXTRACT_32BITS(&fap->fa_uid),
1124 EXTRACT_32BITS(&fap->fa_gid));
1125 if (v3) {
1126 TCHECK(fap->fa3_size);
1127 printf(" sz %" PRIu64,
1128 EXTRACT_64BITS((u_int32_t *)&fap->fa3_size));
1129 } else {
1130 TCHECK(fap->fa2_size);
1131 printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size));
1134 /* print lots more stuff */
1135 if (verbose > 1) {
1136 if (v3) {
1137 TCHECK(fap->fa3_ctime);
1138 printf(" nlink %d rdev %d/%d",
1139 EXTRACT_32BITS(&fap->fa_nlink),
1140 EXTRACT_32BITS(&fap->fa3_rdev.specdata1),
1141 EXTRACT_32BITS(&fap->fa3_rdev.specdata2));
1142 printf(" fsid %" PRIx64,
1143 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid));
1144 printf(" fileid %" PRIx64,
1145 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid));
1146 printf(" a/m/ctime %u.%06u",
1147 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec),
1148 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec));
1149 printf(" %u.%06u",
1150 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec),
1151 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec));
1152 printf(" %u.%06u",
1153 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec),
1154 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec));
1155 } else {
1156 TCHECK(fap->fa2_ctime);
1157 printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime",
1158 EXTRACT_32BITS(&fap->fa_nlink),
1159 EXTRACT_32BITS(&fap->fa2_rdev),
1160 EXTRACT_32BITS(&fap->fa2_fsid),
1161 EXTRACT_32BITS(&fap->fa2_fileid));
1162 printf(" %u.%06u",
1163 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec),
1164 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec));
1165 printf(" %u.%06u",
1166 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec),
1167 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec));
1168 printf(" %u.%06u",
1169 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec),
1170 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec));
1173 return ((const u_int32_t *)((unsigned char *)dp +
1174 (v3 ? NFSX_V3FATTR : NFSX_V2FATTR)));
1175 trunc:
1176 return (NULL);
1179 static int
1180 parseattrstat(const u_int32_t *dp, int verbose, int v3)
1182 int er;
1184 dp = parsestatus(dp, &er);
1185 if (dp == NULL)
1186 return (0);
1187 if (er)
1188 return (1);
1190 return (parsefattr(dp, verbose, v3) != NULL);
1193 static int
1194 parsediropres(const u_int32_t *dp)
1196 int er;
1198 if (!(dp = parsestatus(dp, &er)))
1199 return (0);
1200 if (er)
1201 return (1);
1203 dp = parsefh(dp, 0);
1204 if (dp == NULL)
1205 return (0);
1207 return (parsefattr(dp, vflag, 0) != NULL);
1210 static int
1211 parselinkres(const u_int32_t *dp, int v3)
1213 int er;
1215 dp = parsestatus(dp, &er);
1216 if (dp == NULL)
1217 return(0);
1218 if (er)
1219 return(1);
1220 if (v3 && !(dp = parse_post_op_attr(dp, vflag)))
1221 return (0);
1222 putchar(' ');
1223 return (parsefn(dp) != NULL);
1226 static int
1227 parsestatfs(const u_int32_t *dp, int v3)
1229 const struct nfs_statfs *sfsp;
1230 int er;
1232 dp = parsestatus(dp, &er);
1233 if (dp == NULL)
1234 return (0);
1235 if (!v3 && er)
1236 return (1);
1238 if (qflag)
1239 return(1);
1241 if (v3) {
1242 if (vflag)
1243 printf(" POST:");
1244 if (!(dp = parse_post_op_attr(dp, vflag)))
1245 return (0);
1248 TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS));
1250 sfsp = (const struct nfs_statfs *)dp;
1252 if (v3) {
1253 printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64,
1254 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes),
1255 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes),
1256 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes));
1257 if (vflag) {
1258 printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u",
1259 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles),
1260 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles),
1261 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles),
1262 EXTRACT_32BITS(&sfsp->sf_invarsec));
1264 } else {
1265 printf(" tsize %d bsize %d blocks %d bfree %d bavail %d",
1266 EXTRACT_32BITS(&sfsp->sf_tsize),
1267 EXTRACT_32BITS(&sfsp->sf_bsize),
1268 EXTRACT_32BITS(&sfsp->sf_blocks),
1269 EXTRACT_32BITS(&sfsp->sf_bfree),
1270 EXTRACT_32BITS(&sfsp->sf_bavail));
1273 return (1);
1274 trunc:
1275 return (0);
1278 static int
1279 parserddires(const u_int32_t *dp)
1281 int er;
1283 dp = parsestatus(dp, &er);
1284 if (dp == NULL)
1285 return (0);
1286 if (er)
1287 return (1);
1288 if (qflag)
1289 return (1);
1291 TCHECK(dp[2]);
1292 printf(" offset %x size %d ",
1293 EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1]));
1294 if (dp[2] != 0)
1295 printf(" eof");
1297 return (1);
1298 trunc:
1299 return (0);
1302 static const u_int32_t *
1303 parse_wcc_attr(const u_int32_t *dp)
1305 printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0]));
1306 printf(" mtime %u.%06u ctime %u.%06u",
1307 EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]),
1308 EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5]));
1309 return (dp + 6);
1313 * Pre operation attributes. Print only if vflag > 1.
1315 static const u_int32_t *
1316 parse_pre_op_attr(const u_int32_t *dp, int verbose)
1318 TCHECK(dp[0]);
1319 if (!EXTRACT_32BITS(&dp[0]))
1320 return (dp + 1);
1321 dp++;
1322 TCHECK2(*dp, 24);
1323 if (verbose > 1) {
1324 return parse_wcc_attr(dp);
1325 } else {
1326 /* If not verbose enough, just skip over wcc_attr */
1327 return (dp + 6);
1329 trunc:
1330 return (NULL);
1334 * Post operation attributes are printed if vflag >= 1
1336 static const u_int32_t *
1337 parse_post_op_attr(const u_int32_t *dp, int verbose)
1339 TCHECK(dp[0]);
1340 if (!EXTRACT_32BITS(&dp[0]))
1341 return (dp + 1);
1342 dp++;
1343 if (verbose) {
1344 return parsefattr(dp, verbose, 1);
1345 } else
1346 return (dp + (NFSX_V3FATTR / sizeof (u_int32_t)));
1347 trunc:
1348 return (NULL);
1351 static const u_int32_t *
1352 parse_wcc_data(const u_int32_t *dp, int verbose)
1354 if (verbose > 1)
1355 printf(" PRE:");
1356 if (!(dp = parse_pre_op_attr(dp, verbose)))
1357 return (0);
1359 if (verbose)
1360 printf(" POST:");
1361 return parse_post_op_attr(dp, verbose);
1364 static const u_int32_t *
1365 parsecreateopres(const u_int32_t *dp, int verbose)
1367 int er;
1369 if (!(dp = parsestatus(dp, &er)))
1370 return (0);
1371 if (er)
1372 dp = parse_wcc_data(dp, verbose);
1373 else {
1374 TCHECK(dp[0]);
1375 if (!EXTRACT_32BITS(&dp[0]))
1376 return (dp + 1);
1377 dp++;
1378 if (!(dp = parsefh(dp, 1)))
1379 return (0);
1380 if (verbose) {
1381 if (!(dp = parse_post_op_attr(dp, verbose)))
1382 return (0);
1383 if (vflag > 1) {
1384 printf(" dir attr:");
1385 dp = parse_wcc_data(dp, verbose);
1389 return (dp);
1390 trunc:
1391 return (NULL);
1394 static int
1395 parsewccres(const u_int32_t *dp, int verbose)
1397 int er;
1399 if (!(dp = parsestatus(dp, &er)))
1400 return (0);
1401 return parse_wcc_data(dp, verbose) != 0;
1404 static const u_int32_t *
1405 parsev3rddirres(const u_int32_t *dp, int verbose)
1407 int er;
1409 if (!(dp = parsestatus(dp, &er)))
1410 return (0);
1411 if (vflag)
1412 printf(" POST:");
1413 if (!(dp = parse_post_op_attr(dp, verbose)))
1414 return (0);
1415 if (er)
1416 return dp;
1417 if (vflag) {
1418 TCHECK(dp[1]);
1419 printf(" verf %08x%08x", dp[0], dp[1]);
1420 dp += 2;
1422 return dp;
1423 trunc:
1424 return (NULL);
1427 static int
1428 parsefsinfo(const u_int32_t *dp)
1430 struct nfsv3_fsinfo *sfp;
1431 int er;
1433 if (!(dp = parsestatus(dp, &er)))
1434 return (0);
1435 if (vflag)
1436 printf(" POST:");
1437 if (!(dp = parse_post_op_attr(dp, vflag)))
1438 return (0);
1439 if (er)
1440 return (1);
1442 sfp = (struct nfsv3_fsinfo *)dp;
1443 TCHECK(*sfp);
1444 printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u",
1445 EXTRACT_32BITS(&sfp->fs_rtmax),
1446 EXTRACT_32BITS(&sfp->fs_rtpref),
1447 EXTRACT_32BITS(&sfp->fs_wtmax),
1448 EXTRACT_32BITS(&sfp->fs_wtpref),
1449 EXTRACT_32BITS(&sfp->fs_dtpref));
1450 if (vflag) {
1451 printf(" rtmult %u wtmult %u maxfsz %" PRIu64,
1452 EXTRACT_32BITS(&sfp->fs_rtmult),
1453 EXTRACT_32BITS(&sfp->fs_wtmult),
1454 EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize));
1455 printf(" delta %u.%06u ",
1456 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec),
1457 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec));
1459 return (1);
1460 trunc:
1461 return (0);
1464 static int
1465 parsepathconf(const u_int32_t *dp)
1467 int er;
1468 struct nfsv3_pathconf *spp;
1470 if (!(dp = parsestatus(dp, &er)))
1471 return (0);
1472 if (vflag)
1473 printf(" POST:");
1474 if (!(dp = parse_post_op_attr(dp, vflag)))
1475 return (0);
1476 if (er)
1477 return (1);
1479 spp = (struct nfsv3_pathconf *)dp;
1480 TCHECK(*spp);
1482 printf(" linkmax %u namemax %u %s %s %s %s",
1483 EXTRACT_32BITS(&spp->pc_linkmax),
1484 EXTRACT_32BITS(&spp->pc_namemax),
1485 EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "",
1486 EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "",
1487 EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "",
1488 EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : "");
1489 return (1);
1490 trunc:
1491 return (0);
1494 static void
1495 interp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length)
1497 register const u_int32_t *dp;
1498 register int v3;
1499 int er;
1501 v3 = (vers == NFS_VER3);
1503 if (!v3 && proc < NFS_NPROCS)
1504 proc = nfsv3_procid[proc];
1506 switch (proc) {
1508 case NFSPROC_NOOP:
1509 printf(" nop");
1510 return;
1512 case NFSPROC_NULL:
1513 printf(" null");
1514 return;
1516 case NFSPROC_GETATTR:
1517 printf(" getattr");
1518 dp = parserep(rp, length);
1519 if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0)
1520 return;
1521 break;
1523 case NFSPROC_SETATTR:
1524 printf(" setattr");
1525 if (!(dp = parserep(rp, length)))
1526 return;
1527 if (v3) {
1528 if (parsewccres(dp, vflag))
1529 return;
1530 } else {
1531 if (parseattrstat(dp, !qflag, 0) != 0)
1532 return;
1534 break;
1536 case NFSPROC_LOOKUP:
1537 printf(" lookup");
1538 if (!(dp = parserep(rp, length)))
1539 break;
1540 if (v3) {
1541 if (!(dp = parsestatus(dp, &er)))
1542 break;
1543 if (er) {
1544 if (vflag > 1) {
1545 printf(" post dattr:");
1546 dp = parse_post_op_attr(dp, vflag);
1548 } else {
1549 if (!(dp = parsefh(dp, v3)))
1550 break;
1551 if ((dp = parse_post_op_attr(dp, vflag)) &&
1552 vflag > 1) {
1553 printf(" post dattr:");
1554 dp = parse_post_op_attr(dp, vflag);
1557 if (dp)
1558 return;
1559 } else {
1560 if (parsediropres(dp) != 0)
1561 return;
1563 break;
1565 case NFSPROC_ACCESS:
1566 printf(" access");
1567 if (!(dp = parserep(rp, length)))
1568 break;
1569 if (!(dp = parsestatus(dp, &er)))
1570 break;
1571 if (vflag)
1572 printf(" attr:");
1573 if (!(dp = parse_post_op_attr(dp, vflag)))
1574 break;
1575 if (!er)
1576 printf(" c %04x", EXTRACT_32BITS(&dp[0]));
1577 return;
1579 case NFSPROC_READLINK:
1580 printf(" readlink");
1581 dp = parserep(rp, length);
1582 if (dp != NULL && parselinkres(dp, v3) != 0)
1583 return;
1584 break;
1586 case NFSPROC_READ:
1587 printf(" read");
1588 if (!(dp = parserep(rp, length)))
1589 break;
1590 if (v3) {
1591 if (!(dp = parsestatus(dp, &er)))
1592 break;
1593 if (!(dp = parse_post_op_attr(dp, vflag)))
1594 break;
1595 if (er)
1596 return;
1597 if (vflag) {
1598 TCHECK(dp[1]);
1599 printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1600 if (EXTRACT_32BITS(&dp[1]))
1601 printf(" EOF");
1603 return;
1604 } else {
1605 if (parseattrstat(dp, vflag, 0) != 0)
1606 return;
1608 break;
1610 case NFSPROC_WRITE:
1611 printf(" write");
1612 if (!(dp = parserep(rp, length)))
1613 break;
1614 if (v3) {
1615 if (!(dp = parsestatus(dp, &er)))
1616 break;
1617 if (!(dp = parse_wcc_data(dp, vflag)))
1618 break;
1619 if (er)
1620 return;
1621 if (vflag) {
1622 TCHECK(dp[0]);
1623 printf(" %u bytes", EXTRACT_32BITS(&dp[0]));
1624 if (vflag > 1) {
1625 TCHECK(dp[1]);
1626 printf(" <%s>",
1627 tok2str(nfsv3_writemodes,
1628 NULL, EXTRACT_32BITS(&dp[1])));
1630 return;
1632 } else {
1633 if (parseattrstat(dp, vflag, v3) != 0)
1634 return;
1636 break;
1638 case NFSPROC_CREATE:
1639 printf(" create");
1640 if (!(dp = parserep(rp, length)))
1641 break;
1642 if (v3) {
1643 if (parsecreateopres(dp, vflag) != 0)
1644 return;
1645 } else {
1646 if (parsediropres(dp) != 0)
1647 return;
1649 break;
1651 case NFSPROC_MKDIR:
1652 printf(" mkdir");
1653 if (!(dp = parserep(rp, length)))
1654 break;
1655 if (v3) {
1656 if (parsecreateopres(dp, vflag) != 0)
1657 return;
1658 } else {
1659 if (parsediropres(dp) != 0)
1660 return;
1662 break;
1664 case NFSPROC_SYMLINK:
1665 printf(" symlink");
1666 if (!(dp = parserep(rp, length)))
1667 break;
1668 if (v3) {
1669 if (parsecreateopres(dp, vflag) != 0)
1670 return;
1671 } else {
1672 if (parsestatus(dp, &er) != 0)
1673 return;
1675 break;
1677 case NFSPROC_MKNOD:
1678 printf(" mknod");
1679 if (!(dp = parserep(rp, length)))
1680 break;
1681 if (parsecreateopres(dp, vflag) != 0)
1682 return;
1683 break;
1685 case NFSPROC_REMOVE:
1686 printf(" remove");
1687 if (!(dp = parserep(rp, length)))
1688 break;
1689 if (v3) {
1690 if (parsewccres(dp, vflag))
1691 return;
1692 } else {
1693 if (parsestatus(dp, &er) != 0)
1694 return;
1696 break;
1698 case NFSPROC_RMDIR:
1699 printf(" rmdir");
1700 if (!(dp = parserep(rp, length)))
1701 break;
1702 if (v3) {
1703 if (parsewccres(dp, vflag))
1704 return;
1705 } else {
1706 if (parsestatus(dp, &er) != 0)
1707 return;
1709 break;
1711 case NFSPROC_RENAME:
1712 printf(" rename");
1713 if (!(dp = parserep(rp, length)))
1714 break;
1715 if (v3) {
1716 if (!(dp = parsestatus(dp, &er)))
1717 break;
1718 if (vflag) {
1719 printf(" from:");
1720 if (!(dp = parse_wcc_data(dp, vflag)))
1721 break;
1722 printf(" to:");
1723 if (!(dp = parse_wcc_data(dp, vflag)))
1724 break;
1726 return;
1727 } else {
1728 if (parsestatus(dp, &er) != 0)
1729 return;
1731 break;
1733 case NFSPROC_LINK:
1734 printf(" link");
1735 if (!(dp = parserep(rp, length)))
1736 break;
1737 if (v3) {
1738 if (!(dp = parsestatus(dp, &er)))
1739 break;
1740 if (vflag) {
1741 printf(" file POST:");
1742 if (!(dp = parse_post_op_attr(dp, vflag)))
1743 break;
1744 printf(" dir:");
1745 if (!(dp = parse_wcc_data(dp, vflag)))
1746 break;
1747 return;
1749 } else {
1750 if (parsestatus(dp, &er) != 0)
1751 return;
1753 break;
1755 case NFSPROC_READDIR:
1756 printf(" readdir");
1757 if (!(dp = parserep(rp, length)))
1758 break;
1759 if (v3) {
1760 if (parsev3rddirres(dp, vflag))
1761 return;
1762 } else {
1763 if (parserddires(dp) != 0)
1764 return;
1766 break;
1768 case NFSPROC_READDIRPLUS:
1769 printf(" readdirplus");
1770 if (!(dp = parserep(rp, length)))
1771 break;
1772 if (parsev3rddirres(dp, vflag))
1773 return;
1774 break;
1776 case NFSPROC_FSSTAT:
1777 printf(" fsstat");
1778 dp = parserep(rp, length);
1779 if (dp != NULL && parsestatfs(dp, v3) != 0)
1780 return;
1781 break;
1783 case NFSPROC_FSINFO:
1784 printf(" fsinfo");
1785 dp = parserep(rp, length);
1786 if (dp != NULL && parsefsinfo(dp) != 0)
1787 return;
1788 break;
1790 case NFSPROC_PATHCONF:
1791 printf(" pathconf");
1792 dp = parserep(rp, length);
1793 if (dp != NULL && parsepathconf(dp) != 0)
1794 return;
1795 break;
1797 case NFSPROC_COMMIT:
1798 printf(" commit");
1799 dp = parserep(rp, length);
1800 if (dp != NULL && parsewccres(dp, vflag) != 0)
1801 return;
1802 break;
1804 default:
1805 printf(" proc-%u", proc);
1806 return;
1808 trunc:
1809 if (!nfserr)
1810 fputs(" [|nfs]", stdout);