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