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