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