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