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