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[] = 24 "@(#) $Header: print-nfs.c,v 1.65 97/08/17 13:24:22 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.%u: 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.%u > %s.%u: 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.%u > %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.%u > %s.%u: %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 (0); 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 static const u_int32_t * 854 parsestatus(const u_int32_t *dp, int *er) 855 { 856 register int errnum; 857 858 TCHECK(dp[0]); 859 errnum = ntohl(dp[0]); 860 if (er) 861 *er = errnum; 862 if (errnum != 0) { 863 if (!qflag) 864 printf(" ERROR: %s", pcap_strerror(errnum)); 865 nfserr = 1; 866 return (NULL); 867 } 868 return (dp + 1); 869 trunc: 870 return (NULL); 871 } 872 873 static const u_int32_t * 874 parsefattr(const u_int32_t *dp, int verbose, int v3) 875 { 876 const struct nfs_fattr *fap; 877 878 fap = (const struct nfs_fattr *)dp; 879 TCHECK(fap->fa_gid); 880 if (verbose) { 881 printf(" %s %lo ids %ld/%ld", 882 tok2str(type2str, "unk-ft %d ", ntohl(fap->fa_type)), 883 ntohl(fap->fa_mode), ntohl(fap->fa_uid), 884 ntohl(fap->fa_gid)); 885 if (v3) { 886 TCHECK(fap->fa3_size); 887 printf(" sz "); 888 print_int64((u_int32_t *)&fap->fa3_size, UNSIGNED); 889 putchar(' '); 890 } else { 891 TCHECK(fap->fa2_size); 892 printf(" sz %ld ", ntohl(fap->fa2_size)); 893 } 894 } 895 /* print lots more stuff */ 896 if (verbose > 1) { 897 if (v3) { 898 TCHECK(fap->fa3_ctime); 899 printf("nlink %ld rdev %ld/%ld ", 900 ntohl(fap->fa_nlink), 901 ntohl(fap->fa3_rdev.specdata1), 902 ntohl(fap->fa3_rdev.specdata2)); 903 printf("fsid "); 904 print_int64((u_int32_t *)&fap->fa2_fsid, HEX); 905 printf(" nodeid "); 906 print_int64((u_int32_t *)&fap->fa2_fileid, HEX); 907 printf(" a/m/ctime %lu.%06lu ", 908 ntohl(fap->fa3_atime.nfsv3_sec), 909 ntohl(fap->fa3_atime.nfsv3_nsec)); 910 printf("%lu.%06lu ", 911 ntohl(fap->fa3_mtime.nfsv3_sec), 912 ntohl(fap->fa3_mtime.nfsv3_nsec)); 913 printf("%lu.%06lu ", 914 ntohl(fap->fa3_ctime.nfsv3_sec), 915 ntohl(fap->fa3_ctime.nfsv3_nsec)); 916 } else { 917 TCHECK(fap->fa2_ctime); 918 printf("nlink %ld rdev %lx fsid %lx nodeid %lx a/m/ctime ", 919 ntohl(fap->fa_nlink), ntohl(fap->fa2_rdev), 920 ntohl(fap->fa2_fsid), ntohl(fap->fa2_fileid)); 921 printf("%lu.%06lu ", 922 ntohl(fap->fa2_atime.nfsv2_sec), 923 ntohl(fap->fa2_atime.nfsv2_usec)); 924 printf("%lu.%06lu ", 925 ntohl(fap->fa2_mtime.nfsv2_sec), 926 ntohl(fap->fa2_mtime.nfsv2_usec)); 927 printf("%lu.%06lu ", 928 ntohl(fap->fa2_ctime.nfsv2_sec), 929 ntohl(fap->fa2_ctime.nfsv2_usec)); 930 } 931 } 932 return ((const u_int32_t *)((unsigned char *)dp + 933 (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 934 trunc: 935 return (NULL); 936 } 937 938 static int 939 parseattrstat(const u_int32_t *dp, int verbose, int v3) 940 { 941 int er; 942 943 dp = parsestatus(dp, &er); 944 if (dp == NULL || er) 945 return (0); 946 947 return (parsefattr(dp, verbose, v3) != NULL); 948 } 949 950 static int 951 parsediropres(const u_int32_t *dp) 952 { 953 int er; 954 955 dp = parsestatus(dp, &er); 956 if (dp == NULL || er) 957 return (0); 958 959 dp = parsefh(dp, 0); 960 if (dp == NULL) 961 return (0); 962 963 return (parsefattr(dp, vflag, 0) != NULL); 964 } 965 966 static int 967 parselinkres(const u_int32_t *dp, int v3) 968 { 969 int er; 970 971 dp = parsestatus(dp, &er); 972 if (dp == NULL || er) 973 return(0); 974 975 if (v3 && ((dp = parse_post_op_attr(dp, vflag)) != NULL)) 976 return (0); 977 978 putchar(' '); 979 return (parsefn(dp) != NULL); 980 } 981 982 static int 983 parsestatfs(const u_int32_t *dp, int v3) 984 { 985 const struct nfs_statfs *sfsp; 986 int er; 987 988 dp = parsestatus(dp, &er); 989 if (dp == NULL || (!v3 && er)) 990 return(0); 991 992 if (qflag) 993 return(1); 994 995 if (v3) { 996 if (vflag) 997 printf(" POST:"); 998 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 999 return (0); 1000 } 1001 1002 TCHECK2(dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 1003 1004 sfsp = (const struct nfs_statfs *)dp; 1005 1006 if (v3) { 1007 printf(" tbytes "); 1008 print_int64((u_int32_t *)&sfsp->sf_tbytes, UNSIGNED); 1009 printf(" fbytes "); 1010 print_int64((u_int32_t *)&sfsp->sf_fbytes, UNSIGNED); 1011 printf(" abytes "); 1012 print_int64((u_int32_t *)&sfsp->sf_abytes, UNSIGNED); 1013 if (vflag) { 1014 printf(" tfiles "); 1015 print_int64((u_int32_t *)&sfsp->sf_tfiles, UNSIGNED); 1016 printf(" ffiles "); 1017 print_int64((u_int32_t *)&sfsp->sf_ffiles, UNSIGNED); 1018 printf(" afiles "); 1019 print_int64((u_int32_t *)&sfsp->sf_afiles, UNSIGNED); 1020 printf(" invar %lu", ntohl(sfsp->sf_invarsec)); 1021 } 1022 } else { 1023 printf(" tsize %ld bsize %ld blocks %ld bfree %ld bavail %ld", 1024 ntohl(sfsp->sf_tsize), ntohl(sfsp->sf_bsize), 1025 ntohl(sfsp->sf_blocks), ntohl(sfsp->sf_bfree), 1026 ntohl(sfsp->sf_bavail)); 1027 } 1028 1029 return (1); 1030 trunc: 1031 return (0); 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 TCHECK(dp[2]); 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 trunc: 1052 return (0); 1053 } 1054 1055 static const u_int32_t * 1056 parse_wcc_attr(const u_int32_t *dp) 1057 { 1058 printf(" sz "); 1059 print_int64(dp, UNSIGNED); 1060 printf(" mtime %lu.%06lu ctime %lu.%06lu", ntohl(dp[2]), ntohl(dp[3]), 1061 ntohl(dp[4]), ntohl(dp[5])); 1062 return (dp + 6); 1063 } 1064 1065 /* 1066 * Pre operation attributes. Print only if vflag > 1. 1067 */ 1068 static const u_int32_t * 1069 parse_pre_op_attr(const u_int32_t *dp, int verbose) 1070 { 1071 TCHECK(dp[0]); 1072 if (!ntohl(dp[0])) 1073 return (dp + 1); 1074 dp++; 1075 TCHECK2(dp, 24); 1076 if (verbose > 1) { 1077 return parse_wcc_attr(dp); 1078 } else { 1079 /* If not verbose enough, just skip over wcc_attr */ 1080 return (dp + 6); 1081 } 1082 trunc: 1083 return (NULL); 1084 } 1085 1086 /* 1087 * Post operation attributes are printed if vflag >= 1 1088 */ 1089 static const u_int32_t * 1090 parse_post_op_attr(const u_int32_t *dp, int verbose) 1091 { 1092 TCHECK(dp[0]); 1093 if (!ntohl(dp[0])) 1094 return (dp + 1); 1095 dp++; 1096 if (verbose) { 1097 return parsefattr(dp, verbose, 1); 1098 } else 1099 return (dp + (NFSX_V3FATTR / sizeof (u_int32_t))); 1100 trunc: 1101 return (NULL); 1102 } 1103 1104 static const u_int32_t * 1105 parse_wcc_data(const u_int32_t *dp, int verbose) 1106 { 1107 if (verbose > 1) 1108 printf(" PRE:"); 1109 if ((dp = parse_pre_op_attr(dp, verbose)) == NULL) 1110 return (NULL); 1111 1112 if (verbose) 1113 printf(" POST:"); 1114 return parse_post_op_attr(dp, verbose); 1115 } 1116 1117 static const u_int32_t * 1118 parsecreateopres(const u_int32_t *dp, int verbose) 1119 { 1120 int er; 1121 1122 if ((dp = parsestatus(dp, &er)) == NULL) 1123 return (NULL); 1124 if (er) 1125 dp = parse_wcc_data(dp, verbose); 1126 else { 1127 TCHECK(dp[0]); 1128 if (!ntohl(dp[0])) 1129 return (dp + 1); 1130 dp++; 1131 if ((dp = parsefh(dp, 1)) == NULL) 1132 return (NULL); 1133 if (verbose) { 1134 if ((dp = parse_post_op_attr(dp, verbose)) == NULL) 1135 return (NULL); 1136 if (vflag > 1) { 1137 printf("dir attr:"); 1138 dp = parse_wcc_data(dp, verbose); 1139 } 1140 } 1141 } 1142 return (dp); 1143 trunc: 1144 return (NULL); 1145 } 1146 1147 static int 1148 parsewccres(const u_int32_t *dp, int verbose) 1149 { 1150 int er; 1151 1152 if ((dp = parsestatus(dp, &er)) == NULL) 1153 return (0); 1154 return parse_wcc_data(dp, verbose) != NULL; 1155 } 1156 1157 static const u_int32_t * 1158 parsev3rddirres(const u_int32_t *dp, int verbose) 1159 { 1160 int er; 1161 1162 if ((dp = parsestatus(dp, &er)) == NULL) 1163 return (NULL); 1164 if (vflag) 1165 printf(" POST:"); 1166 if ((dp = parse_post_op_attr(dp, verbose)) == NULL) 1167 return (NULL); 1168 if (er) 1169 return dp; 1170 if (vflag) { 1171 TCHECK(dp[1]); 1172 printf(" verf %08x%08x", dp[0], dp[1]); 1173 dp += 2; 1174 } 1175 return dp; 1176 trunc: 1177 return (NULL); 1178 } 1179 1180 static int 1181 parsefsinfo(const u_int32_t *dp) 1182 { 1183 struct nfsv3_fsinfo *sfp; 1184 int er; 1185 1186 if ((dp = parsestatus(dp, &er)) == NULL) 1187 return (0); 1188 if (vflag) 1189 printf(" POST:"); 1190 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1191 return (0); 1192 if (er) 1193 return (1); 1194 1195 sfp = (struct nfsv3_fsinfo *)dp; 1196 TCHECK(*sfp); 1197 printf(" rtmax %lu rtpref %lu wtmax %lu wtpref %lu dtpref %lu", 1198 ntohl(sfp->fs_rtmax), ntohl(sfp->fs_rtpref), 1199 ntohl(sfp->fs_wtmax), ntohl(sfp->fs_wtpref), 1200 ntohl(sfp->fs_dtpref)); 1201 if (vflag) { 1202 printf(" rtmult %lu wtmult %lu maxfsz ", 1203 ntohl(sfp->fs_rtmult), ntohl(sfp->fs_wtmult)); 1204 print_int64((u_int32_t *)&sfp->fs_maxfilesize, UNSIGNED); 1205 printf(" delta %lu.%06lu ", ntohl(sfp->fs_timedelta.nfsv3_sec), 1206 ntohl(sfp->fs_timedelta.nfsv3_nsec)); 1207 } 1208 return (1); 1209 trunc: 1210 return (0); 1211 } 1212 1213 static int 1214 parsepathconf(const u_int32_t *dp) 1215 { 1216 int er; 1217 struct nfsv3_pathconf *spp; 1218 1219 if ((dp = parsestatus(dp, &er)) == NULL) 1220 return (0); 1221 if (vflag) 1222 printf(" POST:"); 1223 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1224 return (0); 1225 if (er) 1226 return (1); 1227 1228 spp = (struct nfsv3_pathconf *)dp; 1229 TCHECK(*spp); 1230 1231 printf(" linkmax %lu namemax %lu %s %s %s %s", 1232 ntohl(spp->pc_linkmax), 1233 ntohl(spp->pc_namemax), 1234 ntohl(spp->pc_notrunc) ? "notrunc" : "", 1235 ntohl(spp->pc_chownrestricted) ? "chownres" : "", 1236 ntohl(spp->pc_caseinsensitive) ? "igncase" : "", 1237 ntohl(spp->pc_casepreserving) ? "keepcase" : ""); 1238 return (1); 1239 trunc: 1240 return (0); 1241 } 1242 1243 static void 1244 interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int32_t vers, int length) 1245 { 1246 register const u_int32_t *dp; 1247 register int v3; 1248 1249 int er; 1250 1251 v3 = (vers == NFS_VER3); 1252 1253 if (!v3 && proc < NFS_NPROCS) 1254 proc = nfsv3_procid[proc]; 1255 1256 switch (proc) { 1257 1258 case NFSPROC_NOOP: 1259 printf(" nop"); 1260 return; 1261 1262 case NFSPROC_NULL: 1263 printf(" null"); 1264 return; 1265 1266 case NFSPROC_GETATTR: 1267 printf(" getattr"); 1268 dp = parserep(rp, length); 1269 if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0) 1270 return; 1271 break; 1272 1273 case NFSPROC_SETATTR: 1274 printf(" setattr"); 1275 if ((dp = parserep(rp, length)) == NULL) 1276 return; 1277 if (v3) { 1278 if (parsewccres(dp, vflag) != 0) 1279 return; 1280 } else { 1281 if (parseattrstat(dp, !qflag, 0) != 0) 1282 return; 1283 } 1284 break; 1285 1286 case NFSPROC_LOOKUP: 1287 printf(" lookup"); 1288 if ((dp = parserep(rp, length)) == NULL) 1289 break; 1290 if (v3) { 1291 if ((dp = parsestatus(dp, &er)) == NULL) 1292 break; 1293 if (er) { 1294 if (vflag > 1) { 1295 printf(" post dattr:"); 1296 dp = parse_post_op_attr(dp, vflag); 1297 } 1298 } else { 1299 if ((dp = parsefh(dp, v3)) == NULL) 1300 break; 1301 if (((dp = parse_post_op_attr(dp, vflag)) != NULL) && 1302 (vflag > 1)) { 1303 printf(" post dattr:"); 1304 dp = parse_post_op_attr(dp, vflag); 1305 } 1306 } 1307 if (dp != NULL) 1308 return; 1309 } else { 1310 if (parsediropres(dp) != 0) 1311 return; 1312 } 1313 break; 1314 1315 case NFSPROC_ACCESS: 1316 printf(" access"); 1317 dp = parserep(rp, length); 1318 if ((dp = parsestatus(dp, &er)) == NULL) 1319 break; 1320 if (vflag) 1321 printf(" attr:"); 1322 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1323 break; 1324 if (!er) 1325 printf(" c %04lx", ntohl(dp[0])); 1326 return; 1327 1328 case NFSPROC_READLINK: 1329 printf(" readlink"); 1330 dp = parserep(rp, length); 1331 if (dp != NULL && parselinkres(dp, v3) != 0) 1332 return; 1333 break; 1334 1335 case NFSPROC_READ: 1336 printf(" read"); 1337 if ((dp = parserep(rp, length)) == NULL) 1338 break; 1339 if (v3) { 1340 if ((dp = parsestatus(dp, &er)) == NULL) 1341 break; 1342 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1343 break; 1344 if (er) 1345 return; 1346 if (vflag) { 1347 TCHECK2(*dp, 8); 1348 printf("%lu bytes", ntohl(dp[0])); 1349 if (ntohl(dp[1])) 1350 printf(" EOF"); 1351 } 1352 return; 1353 } else { 1354 if (parseattrstat(dp, vflag, 0) != 0) 1355 return; 1356 } 1357 break; 1358 1359 case NFSPROC_WRITE: 1360 printf(" write"); 1361 if ((dp = parserep(rp, length)) == NULL) 1362 break; 1363 if (v3) { 1364 if ((dp = parsestatus(dp, &er)) == NULL) 1365 break; 1366 if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1367 break; 1368 if (er) 1369 return; 1370 if (vflag) { 1371 TCHECK2(*dp, 4); 1372 printf("%lu bytes", ntohl(dp[0])); 1373 if (vflag > 1) { 1374 TCHECK2(*dp, 4); 1375 printf(" <%s>", 1376 nfsv3_writemodes[ntohl(dp[1])]); 1377 } 1378 return; 1379 } 1380 } else { 1381 if (parseattrstat(dp, vflag, v3) != 0) 1382 return; 1383 } 1384 break; 1385 1386 case NFSPROC_CREATE: 1387 printf(" create"); 1388 if ((dp = parserep(rp, length)) == NULL) 1389 break; 1390 if (v3) { 1391 if (parsecreateopres(dp, vflag) != NULL) 1392 return; 1393 } else { 1394 if (parsediropres(dp) != 0) 1395 return; 1396 } 1397 break; 1398 1399 case NFSPROC_MKDIR: 1400 printf(" mkdir"); 1401 if ((dp = parserep(rp, length)) == NULL) 1402 break; 1403 if (v3) { 1404 if (parsecreateopres(dp, vflag) != NULL) 1405 return; 1406 } else { 1407 if (parsediropres(dp) != 0) 1408 return; 1409 } 1410 break; 1411 1412 case NFSPROC_SYMLINK: 1413 printf(" symlink"); 1414 if ((dp = parserep(rp, length)) == NULL) 1415 break; 1416 if (v3) { 1417 if (parsecreateopres(dp, vflag) != NULL) 1418 return; 1419 } else { 1420 if (parsestatus(dp, &er) != NULL) 1421 return; 1422 } 1423 break; 1424 1425 case NFSPROC_MKNOD: 1426 printf(" mknod"); 1427 if ((dp = parserep(rp, length)) == NULL) 1428 break; 1429 if (parsecreateopres(dp, vflag) != NULL) 1430 return; 1431 break; 1432 1433 case NFSPROC_REMOVE: 1434 printf(" remove"); 1435 if ((dp = parserep(rp, length)) == NULL) 1436 break; 1437 if (v3) { 1438 if (parsewccres(dp, vflag) != 0) 1439 return; 1440 } else { 1441 if (parsestatus(dp, &er) != NULL) 1442 return; 1443 } 1444 break; 1445 1446 case NFSPROC_RMDIR: 1447 printf(" rmdir"); 1448 if ((dp = parserep(rp, length)) == NULL) 1449 break; 1450 if (v3) { 1451 if (parsewccres(dp, vflag) != 0) 1452 return; 1453 } else { 1454 if (parsestatus(dp, &er) != NULL) 1455 return; 1456 } 1457 break; 1458 1459 case NFSPROC_RENAME: 1460 printf(" rename"); 1461 if ((dp = parserep(rp, length)) == NULL) 1462 break; 1463 if (v3) { 1464 if ((dp = parsestatus(dp, &er)) == NULL) 1465 break; 1466 if (vflag) { 1467 printf(" from:"); 1468 if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1469 break; 1470 printf(" to:"); 1471 if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1472 break; 1473 } 1474 return; 1475 } else { 1476 if (parsestatus(dp, &er) != NULL) 1477 return; 1478 } 1479 break; 1480 1481 case NFSPROC_LINK: 1482 printf(" link"); 1483 if ((dp = parserep(rp, length)) == NULL) 1484 break; 1485 if (v3) { 1486 if ((dp = parsestatus(dp, &er)) == NULL) 1487 break; 1488 if (vflag) { 1489 printf(" file POST:"); 1490 if ((dp = parse_post_op_attr(dp, vflag)) == NULL) 1491 break; 1492 printf(" dir:"); 1493 if ((dp = parse_wcc_data(dp, vflag)) == NULL) 1494 break; 1495 return; 1496 } 1497 } else { 1498 if (parsestatus(dp, &er) != NULL) 1499 return; 1500 } 1501 break; 1502 1503 case NFSPROC_READDIR: 1504 printf(" readdir"); 1505 if ((dp = parserep(rp, length)) == NULL) 1506 break; 1507 if (v3) { 1508 if (parsev3rddirres(dp, vflag) != NULL) 1509 return; 1510 } else { 1511 if (parserddires(dp) != 0) 1512 return; 1513 } 1514 break; 1515 1516 case NFSPROC_READDIRPLUS: 1517 printf(" readdirplus"); 1518 if ((dp = parserep(rp, length)) == NULL) 1519 break; 1520 if (parsev3rddirres(dp, vflag) != NULL) 1521 return; 1522 break; 1523 1524 case NFSPROC_FSSTAT: 1525 printf(" fsstat"); 1526 dp = parserep(rp, length); 1527 if (dp != NULL && parsestatfs(dp, v3) != NULL) 1528 return; 1529 break; 1530 1531 case NFSPROC_FSINFO: 1532 printf(" fsinfo"); 1533 dp = parserep(rp, length); 1534 if (dp != NULL && parsefsinfo(dp) != NULL) 1535 return; 1536 break; 1537 1538 case NFSPROC_PATHCONF: 1539 printf(" pathconf"); 1540 dp = parserep(rp, length); 1541 if (dp != NULL && parsepathconf(dp) != 0) 1542 return; 1543 break; 1544 1545 case NFSPROC_COMMIT: 1546 printf(" commit"); 1547 dp = parserep(rp, length); 1548 if (dp != NULL && parsewccres(dp, vflag) != 0) 1549 return; 1550 break; 1551 1552 default: 1553 printf(" proc-%u", proc); 1554 return; 1555 } 1556 1557 trunc: 1558 if (!nfserr) 1559 fputs(" [|nfs]", stdout); 1560 } 1561