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