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