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