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