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