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