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