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