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