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