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