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.106.2.2 2005/05/06 07:57:18 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 void 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; 293 char srcid[20], dstid[20]; /*fits 32bit*/ 294 295 nfserr = 0; /* assume no error */ 296 rp = (const struct sunrpc_msg *)bp; 297 298 if (!nflag) { 299 strlcpy(srcid, "nfs", sizeof(srcid)); 300 snprintf(dstid, sizeof(dstid), "%u", 301 EXTRACT_32BITS(&rp->rm_xid)); 302 } else { 303 snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); 304 snprintf(dstid, sizeof(dstid), "%u", 305 EXTRACT_32BITS(&rp->rm_xid)); 306 } 307 print_nfsaddr(bp2, srcid, dstid); 308 (void)printf("reply %s %d", 309 EXTRACT_32BITS(&rp->rm_reply.rp_stat) == SUNRPC_MSG_ACCEPTED? 310 "ok":"ERR", 311 length); 312 313 if (xid_map_find(rp, bp2, &proc, &vers) >= 0) 314 interp_reply(rp, proc, vers, length); 315 } 316 317 /* 318 * Return a pointer to the first file handle in the packet. 319 * If the packet was truncated, return 0. 320 */ 321 static const u_int32_t * 322 parsereq(register const struct sunrpc_msg *rp, register u_int length) 323 { 324 register const u_int32_t *dp; 325 register u_int len; 326 327 /* 328 * find the start of the req data (if we captured it) 329 */ 330 dp = (u_int32_t *)&rp->rm_call.cb_cred; 331 TCHECK(dp[1]); 332 len = EXTRACT_32BITS(&dp[1]); 333 if (len < length) { 334 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 335 TCHECK(dp[1]); 336 len = EXTRACT_32BITS(&dp[1]); 337 if (len < length) { 338 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 339 TCHECK2(dp[0], 0); 340 return (dp); 341 } 342 } 343 trunc: 344 return (NULL); 345 } 346 347 /* 348 * Print out an NFS file handle and return a pointer to following word. 349 * If packet was truncated, return 0. 350 */ 351 static const u_int32_t * 352 parsefh(register const u_int32_t *dp, int v3) 353 { 354 u_int len; 355 356 if (v3) { 357 TCHECK(dp[0]); 358 len = EXTRACT_32BITS(dp) / 4; 359 dp++; 360 } else 361 len = NFSX_V2FH / 4; 362 363 if (TTEST2(*dp, len * sizeof(*dp))) { 364 nfs_printfh(dp, len); 365 return (dp + len); 366 } 367 trunc: 368 return (NULL); 369 } 370 371 /* 372 * Print out a file name and return pointer to 32-bit word past it. 373 * If packet was truncated, return 0. 374 */ 375 static const u_int32_t * 376 parsefn(register const u_int32_t *dp) 377 { 378 register u_int32_t len; 379 register const u_char *cp; 380 381 /* Bail if we don't have the string length */ 382 TCHECK(*dp); 383 384 /* Fetch string length; convert to host order */ 385 len = *dp++; 386 NTOHL(len); 387 388 TCHECK2(*dp, ((len + 3) & ~3)); 389 390 cp = (u_char *)dp; 391 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 392 dp += ((len + 3) & ~3) / sizeof(*dp); 393 putchar('"'); 394 if (fn_printn(cp, len, snapend)) { 395 putchar('"'); 396 goto trunc; 397 } 398 putchar('"'); 399 400 return (dp); 401 trunc: 402 return NULL; 403 } 404 405 /* 406 * Print out file handle and file name. 407 * Return pointer to 32-bit word past file name. 408 * If packet was truncated (or there was some other error), return 0. 409 */ 410 static const u_int32_t * 411 parsefhn(register const u_int32_t *dp, int v3) 412 { 413 dp = parsefh(dp, v3); 414 if (dp == NULL) 415 return (NULL); 416 putchar(' '); 417 return (parsefn(dp)); 418 } 419 420 void 421 nfsreq_print(register const u_char *bp, u_int length, 422 register const u_char *bp2) 423 { 424 register const struct sunrpc_msg *rp; 425 register const u_int32_t *dp; 426 nfs_type type; 427 int v3; 428 u_int32_t proc; 429 struct nfsv3_sattr sa3; 430 char srcid[20], dstid[20]; /*fits 32bit*/ 431 432 nfserr = 0; /* assume no error */ 433 rp = (const struct sunrpc_msg *)bp; 434 if (!nflag) { 435 snprintf(srcid, sizeof(srcid), "%u", 436 EXTRACT_32BITS(&rp->rm_xid)); 437 strlcpy(dstid, "nfs", sizeof(dstid)); 438 } else { 439 snprintf(srcid, sizeof(srcid), "%u", 440 EXTRACT_32BITS(&rp->rm_xid)); 441 snprintf(dstid, sizeof(dstid), "%u", NFS_PORT); 442 } 443 print_nfsaddr(bp2, srcid, dstid); 444 (void)printf("%d", length); 445 446 xid_map_enter(rp, bp2); /* record proc number for later on */ 447 448 v3 = (EXTRACT_32BITS(&rp->rm_call.cb_vers) == NFS_VER3); 449 proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 450 451 if (!v3 && proc < NFS_NPROCS) 452 proc = nfsv3_procid[proc]; 453 454 switch (proc) { 455 case NFSPROC_NOOP: 456 printf(" nop"); 457 return; 458 case NFSPROC_NULL: 459 printf(" null"); 460 return; 461 462 case NFSPROC_GETATTR: 463 printf(" getattr"); 464 if ((dp = parsereq(rp, length)) != NULL && 465 parsefh(dp, v3) != NULL) 466 return; 467 break; 468 469 case NFSPROC_SETATTR: 470 printf(" setattr"); 471 if ((dp = parsereq(rp, length)) != NULL && 472 parsefh(dp, v3) != NULL) 473 return; 474 break; 475 476 case NFSPROC_LOOKUP: 477 printf(" lookup"); 478 if ((dp = parsereq(rp, length)) != NULL && 479 parsefhn(dp, v3) != NULL) 480 return; 481 break; 482 483 case NFSPROC_ACCESS: 484 printf(" access"); 485 if ((dp = parsereq(rp, length)) != NULL && 486 (dp = parsefh(dp, v3)) != NULL) { 487 TCHECK(dp[0]); 488 printf(" %04x", EXTRACT_32BITS(&dp[0])); 489 return; 490 } 491 break; 492 493 case NFSPROC_READLINK: 494 printf(" readlink"); 495 if ((dp = parsereq(rp, length)) != NULL && 496 parsefh(dp, v3) != NULL) 497 return; 498 break; 499 500 case NFSPROC_READ: 501 printf(" read"); 502 if ((dp = parsereq(rp, length)) != NULL && 503 (dp = parsefh(dp, v3)) != NULL) { 504 if (v3) { 505 TCHECK(dp[2]); 506 printf(" %u bytes @ %" PRIu64, 507 EXTRACT_32BITS(&dp[2]), 508 EXTRACT_64BITS(&dp[0])); 509 } else { 510 TCHECK(dp[1]); 511 printf(" %u bytes @ %u", 512 EXTRACT_32BITS(&dp[1]), 513 EXTRACT_32BITS(&dp[0])); 514 } 515 return; 516 } 517 break; 518 519 case NFSPROC_WRITE: 520 printf(" write"); 521 if ((dp = parsereq(rp, length)) != NULL && 522 (dp = parsefh(dp, v3)) != NULL) { 523 if (v3) { 524 TCHECK(dp[2]); 525 printf(" %u (%u) bytes @ %" PRIu64, 526 EXTRACT_32BITS(&dp[4]), 527 EXTRACT_32BITS(&dp[2]), 528 EXTRACT_64BITS(&dp[0])); 529 if (vflag) { 530 dp += 3; 531 TCHECK(dp[0]); 532 printf(" <%s>", 533 tok2str(nfsv3_writemodes, 534 NULL, EXTRACT_32BITS(dp))); 535 } 536 } else { 537 TCHECK(dp[3]); 538 printf(" %u (%u) bytes @ %u (%u)", 539 EXTRACT_32BITS(&dp[3]), 540 EXTRACT_32BITS(&dp[2]), 541 EXTRACT_32BITS(&dp[1]), 542 EXTRACT_32BITS(&dp[0])); 543 } 544 return; 545 } 546 break; 547 548 case NFSPROC_CREATE: 549 printf(" create"); 550 if ((dp = parsereq(rp, length)) != NULL && 551 parsefhn(dp, v3) != NULL) 552 return; 553 break; 554 555 case NFSPROC_MKDIR: 556 printf(" mkdir"); 557 if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp, v3) != 0) 558 return; 559 break; 560 561 case NFSPROC_SYMLINK: 562 printf(" symlink"); 563 if ((dp = parsereq(rp, length)) != 0 && 564 (dp = parsefhn(dp, v3)) != 0) { 565 fputs(" ->", stdout); 566 if (v3 && (dp = parse_sattr3(dp, &sa3)) == 0) 567 break; 568 if (parsefn(dp) == 0) 569 break; 570 if (v3 && vflag) 571 print_sattr3(&sa3, vflag); 572 return; 573 } 574 break; 575 576 case NFSPROC_MKNOD: 577 printf(" mknod"); 578 if ((dp = parsereq(rp, length)) != 0 && 579 (dp = parsefhn(dp, v3)) != 0) { 580 TCHECK(*dp); 581 type = (nfs_type)EXTRACT_32BITS(dp); 582 dp++; 583 if ((dp = parse_sattr3(dp, &sa3)) == 0) 584 break; 585 printf(" %s", tok2str(type2str, "unk-ft %d", type)); 586 if (vflag && (type == NFCHR || type == NFBLK)) { 587 TCHECK(dp[1]); 588 printf(" %u/%u", 589 EXTRACT_32BITS(&dp[0]), 590 EXTRACT_32BITS(&dp[1])); 591 dp += 2; 592 } 593 if (vflag) 594 print_sattr3(&sa3, vflag); 595 return; 596 } 597 break; 598 599 case NFSPROC_REMOVE: 600 printf(" remove"); 601 if ((dp = parsereq(rp, length)) != NULL && 602 parsefhn(dp, v3) != NULL) 603 return; 604 break; 605 606 case NFSPROC_RMDIR: 607 printf(" rmdir"); 608 if ((dp = parsereq(rp, length)) != NULL && 609 parsefhn(dp, v3) != NULL) 610 return; 611 break; 612 613 case NFSPROC_RENAME: 614 printf(" rename"); 615 if ((dp = parsereq(rp, length)) != NULL && 616 (dp = parsefhn(dp, v3)) != NULL) { 617 fputs(" ->", stdout); 618 if (parsefhn(dp, v3) != NULL) 619 return; 620 } 621 break; 622 623 case NFSPROC_LINK: 624 printf(" link"); 625 if ((dp = parsereq(rp, length)) != NULL && 626 (dp = parsefh(dp, v3)) != NULL) { 627 fputs(" ->", stdout); 628 if (parsefhn(dp, v3) != NULL) 629 return; 630 } 631 break; 632 633 case NFSPROC_READDIR: 634 printf(" readdir"); 635 if ((dp = parsereq(rp, length)) != NULL && 636 (dp = parsefh(dp, v3)) != NULL) { 637 if (v3) { 638 TCHECK(dp[4]); 639 /* 640 * We shouldn't really try to interpret the 641 * offset cookie here. 642 */ 643 printf(" %u bytes @ %" PRId64, 644 EXTRACT_32BITS(&dp[4]), 645 EXTRACT_64BITS(&dp[0])); 646 if (vflag) 647 printf(" verf %08x%08x", dp[2], 648 dp[3]); 649 } else { 650 TCHECK(dp[1]); 651 /* 652 * Print the offset as signed, since -1 is 653 * common, but offsets > 2^31 aren't. 654 */ 655 printf(" %u bytes @ %d", 656 EXTRACT_32BITS(&dp[1]), 657 EXTRACT_32BITS(&dp[0])); 658 } 659 return; 660 } 661 break; 662 663 case NFSPROC_READDIRPLUS: 664 printf(" readdirplus"); 665 if ((dp = parsereq(rp, length)) != NULL && 666 (dp = parsefh(dp, v3)) != NULL) { 667 TCHECK(dp[4]); 668 /* 669 * We don't try to interpret the offset 670 * cookie here. 671 */ 672 printf(" %u bytes @ %" PRId64, 673 EXTRACT_32BITS(&dp[4]), 674 EXTRACT_64BITS(&dp[0])); 675 if (vflag) { 676 TCHECK(dp[5]); 677 printf(" max %u verf %08x%08x", 678 EXTRACT_32BITS(&dp[5]), dp[2], dp[3]); 679 } 680 return; 681 } 682 break; 683 684 case NFSPROC_FSSTAT: 685 printf(" fsstat"); 686 if ((dp = parsereq(rp, length)) != NULL && 687 parsefh(dp, v3) != NULL) 688 return; 689 break; 690 691 case NFSPROC_FSINFO: 692 printf(" fsinfo"); 693 if ((dp = parsereq(rp, length)) != NULL && 694 parsefh(dp, v3) != NULL) 695 return; 696 break; 697 698 case NFSPROC_PATHCONF: 699 printf(" pathconf"); 700 if ((dp = parsereq(rp, length)) != NULL && 701 parsefh(dp, v3) != NULL) 702 return; 703 break; 704 705 case NFSPROC_COMMIT: 706 printf(" commit"); 707 if ((dp = parsereq(rp, length)) != NULL && 708 (dp = parsefh(dp, v3)) != NULL) { 709 TCHECK(dp[2]); 710 printf(" %u bytes @ %" PRIu64, 711 EXTRACT_32BITS(&dp[2]), 712 EXTRACT_64BITS(&dp[0])); 713 return; 714 } 715 break; 716 717 default: 718 printf(" proc-%u", EXTRACT_32BITS(&rp->rm_call.cb_proc)); 719 return; 720 } 721 722 trunc: 723 if (!nfserr) 724 fputs(" [|nfs]", stdout); 725 } 726 727 /* 728 * Print out an NFS file handle. 729 * We assume packet was not truncated before the end of the 730 * file handle pointed to by dp. 731 * 732 * Note: new version (using portable file-handle parser) doesn't produce 733 * generation number. It probably could be made to do that, with some 734 * additional hacking on the parser code. 735 */ 736 static void 737 nfs_printfh(register const u_int32_t *dp, const u_int len) 738 { 739 my_fsid fsid; 740 ino_t ino; 741 const char *sfsname = NULL; 742 char *spacep; 743 744 if (uflag) { 745 u_int i; 746 char const *sep = ""; 747 748 printf(" fh["); 749 for (i=0; i<len; i++) { 750 (void)printf("%s%x", sep, dp[i]); 751 sep = ":"; 752 } 753 printf("]"); 754 return; 755 } 756 757 Parse_fh((const u_char *)dp, len, &fsid, &ino, NULL, &sfsname, 0); 758 759 if (sfsname) { 760 /* file system ID is ASCII, not numeric, for this server OS */ 761 static char temp[NFSX_V3FHMAX+1]; 762 763 /* Make sure string is null-terminated */ 764 strncpy(temp, sfsname, NFSX_V3FHMAX); 765 temp[sizeof(temp) - 1] = '\0'; 766 /* Remove trailing spaces */ 767 spacep = strchr(temp, ' '); 768 if (spacep) 769 *spacep = '\0'; 770 771 (void)printf(" fh %s/", temp); 772 } else { 773 (void)printf(" fh %d,%d/", 774 fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor); 775 } 776 777 if(fsid.Fsid_dev.Minor == 257) 778 /* Print the undecoded handle */ 779 (void)printf("%s", fsid.Opaque_Handle); 780 else 781 (void)printf("%ld", (long) ino); 782 } 783 784 /* 785 * Maintain a small cache of recent client.XID.server/proc pairs, to allow 786 * us to match up replies with requests and thus to know how to parse 787 * the reply. 788 */ 789 790 struct xid_map_entry { 791 u_int32_t xid; /* transaction ID (net order) */ 792 int ipver; /* IP version (4 or 6) */ 793 #ifdef INET6 794 struct in6_addr client; /* client IP address (net order) */ 795 struct in6_addr server; /* server IP address (net order) */ 796 #else 797 struct in_addr client; /* client IP address (net order) */ 798 struct in_addr server; /* server IP address (net order) */ 799 #endif 800 u_int32_t proc; /* call proc number (host order) */ 801 u_int32_t vers; /* program version (host order) */ 802 }; 803 804 /* 805 * Map entries are kept in an array that we manage as a ring; 806 * new entries are always added at the tail of the ring. Initially, 807 * all the entries are zero and hence don't match anything. 808 */ 809 810 #define XIDMAPSIZE 64 811 812 struct xid_map_entry xid_map[XIDMAPSIZE]; 813 814 int xid_map_next = 0; 815 int xid_map_hint = 0; 816 817 static void 818 xid_map_enter(const struct sunrpc_msg *rp, const u_char *bp) 819 { 820 struct ip *ip = NULL; 821 #ifdef INET6 822 struct ip6_hdr *ip6 = NULL; 823 #endif 824 struct xid_map_entry *xmep; 825 826 switch (IP_V((struct ip *)bp)) { 827 case 4: 828 ip = (struct ip *)bp; 829 break; 830 #ifdef INET6 831 case 6: 832 ip6 = (struct ip6_hdr *)bp; 833 break; 834 #endif 835 default: 836 return; 837 } 838 839 xmep = &xid_map[xid_map_next]; 840 841 if (++xid_map_next >= XIDMAPSIZE) 842 xid_map_next = 0; 843 844 xmep->xid = rp->rm_xid; 845 if (ip) { 846 xmep->ipver = 4; 847 memcpy(&xmep->client, &ip->ip_src, sizeof(ip->ip_src)); 848 memcpy(&xmep->server, &ip->ip_dst, sizeof(ip->ip_dst)); 849 } 850 #ifdef INET6 851 else if (ip6) { 852 xmep->ipver = 6; 853 memcpy(&xmep->client, &ip6->ip6_src, sizeof(ip6->ip6_src)); 854 memcpy(&xmep->server, &ip6->ip6_dst, sizeof(ip6->ip6_dst)); 855 } 856 #endif 857 xmep->proc = EXTRACT_32BITS(&rp->rm_call.cb_proc); 858 xmep->vers = EXTRACT_32BITS(&rp->rm_call.cb_vers); 859 } 860 861 /* 862 * Returns 0 and puts NFSPROC_xxx in proc return and 863 * version in vers return, or returns -1 on failure 864 */ 865 static int 866 xid_map_find(const struct sunrpc_msg *rp, const u_char *bp, u_int32_t *proc, 867 u_int32_t *vers) 868 { 869 int i; 870 struct xid_map_entry *xmep; 871 u_int32_t xid = rp->rm_xid; 872 struct ip *ip = (struct ip *)bp; 873 #ifdef INET6 874 struct ip6_hdr *ip6 = (struct ip6_hdr *)bp; 875 #endif 876 int cmp; 877 878 /* Start searching from where we last left off */ 879 i = xid_map_hint; 880 do { 881 xmep = &xid_map[i]; 882 cmp = 1; 883 if (xmep->ipver != IP_V(ip) || xmep->xid != xid) 884 goto nextitem; 885 switch (xmep->ipver) { 886 case 4: 887 if (memcmp(&ip->ip_src, &xmep->server, 888 sizeof(ip->ip_src)) != 0 || 889 memcmp(&ip->ip_dst, &xmep->client, 890 sizeof(ip->ip_dst)) != 0) { 891 cmp = 0; 892 } 893 break; 894 #ifdef INET6 895 case 6: 896 if (memcmp(&ip6->ip6_src, &xmep->server, 897 sizeof(ip6->ip6_src)) != 0 || 898 memcmp(&ip6->ip6_dst, &xmep->client, 899 sizeof(ip6->ip6_dst)) != 0) { 900 cmp = 0; 901 } 902 break; 903 #endif 904 default: 905 cmp = 0; 906 break; 907 } 908 if (cmp) { 909 /* match */ 910 xid_map_hint = i; 911 *proc = xmep->proc; 912 *vers = xmep->vers; 913 return 0; 914 } 915 nextitem: 916 if (++i >= XIDMAPSIZE) 917 i = 0; 918 } while (i != xid_map_hint); 919 920 /* search failed */ 921 return (-1); 922 } 923 924 /* 925 * Routines for parsing reply packets 926 */ 927 928 /* 929 * Return a pointer to the beginning of the actual results. 930 * If the packet was truncated, return 0. 931 */ 932 static const u_int32_t * 933 parserep(register const struct sunrpc_msg *rp, register u_int length) 934 { 935 register const u_int32_t *dp; 936 u_int len; 937 enum sunrpc_accept_stat astat; 938 939 /* 940 * Portability note: 941 * Here we find the address of the ar_verf credentials. 942 * Originally, this calculation was 943 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf 944 * On the wire, the rp_acpt field starts immediately after 945 * the (32 bit) rp_stat field. However, rp_acpt (which is a 946 * "struct accepted_reply") contains a "struct opaque_auth", 947 * whose internal representation contains a pointer, so on a 948 * 64-bit machine the compiler inserts 32 bits of padding 949 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 950 * the internal representation to parse the on-the-wire 951 * representation. Instead, we skip past the rp_stat field, 952 * which is an "enum" and so occupies one 32-bit word. 953 */ 954 dp = ((const u_int32_t *)&rp->rm_reply) + 1; 955 TCHECK(dp[1]); 956 len = EXTRACT_32BITS(&dp[1]); 957 if (len >= length) 958 return (NULL); 959 /* 960 * skip past the ar_verf credentials. 961 */ 962 dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t); 963 TCHECK2(dp[0], 0); 964 965 /* 966 * now we can check the ar_stat field 967 */ 968 astat = (enum sunrpc_accept_stat) EXTRACT_32BITS(dp); 969 switch (astat) { 970 971 case SUNRPC_SUCCESS: 972 break; 973 974 case SUNRPC_PROG_UNAVAIL: 975 printf(" PROG_UNAVAIL"); 976 nfserr = 1; /* suppress trunc string */ 977 return (NULL); 978 979 case SUNRPC_PROG_MISMATCH: 980 printf(" PROG_MISMATCH"); 981 nfserr = 1; /* suppress trunc string */ 982 return (NULL); 983 984 case SUNRPC_PROC_UNAVAIL: 985 printf(" PROC_UNAVAIL"); 986 nfserr = 1; /* suppress trunc string */ 987 return (NULL); 988 989 case SUNRPC_GARBAGE_ARGS: 990 printf(" GARBAGE_ARGS"); 991 nfserr = 1; /* suppress trunc string */ 992 return (NULL); 993 994 case SUNRPC_SYSTEM_ERR: 995 printf(" SYSTEM_ERR"); 996 nfserr = 1; /* suppress trunc string */ 997 return (NULL); 998 999 default: 1000 printf(" ar_stat %d", astat); 1001 nfserr = 1; /* suppress trunc string */ 1002 return (NULL); 1003 } 1004 /* successful return */ 1005 TCHECK2(*dp, sizeof(astat)); 1006 return ((u_int32_t *) (sizeof(astat) + ((char *)dp))); 1007 trunc: 1008 return (0); 1009 } 1010 1011 static const u_int32_t * 1012 parsestatus(const u_int32_t *dp, int *er) 1013 { 1014 int errnum; 1015 1016 TCHECK(dp[0]); 1017 1018 errnum = EXTRACT_32BITS(&dp[0]); 1019 if (er) 1020 *er = errnum; 1021 if (errnum != 0) { 1022 if (!qflag) 1023 printf(" ERROR: %s", 1024 tok2str(status2str, "unk %d", errnum)); 1025 nfserr = 1; 1026 } 1027 return (dp + 1); 1028 trunc: 1029 return NULL; 1030 } 1031 1032 static const u_int32_t * 1033 parsefattr(const u_int32_t *dp, int verbose, int v3) 1034 { 1035 const struct nfs_fattr *fap; 1036 1037 fap = (const struct nfs_fattr *)dp; 1038 TCHECK(fap->fa_gid); 1039 if (verbose) { 1040 printf(" %s %o ids %d/%d", 1041 tok2str(type2str, "unk-ft %d ", 1042 EXTRACT_32BITS(&fap->fa_type)), 1043 EXTRACT_32BITS(&fap->fa_mode), 1044 EXTRACT_32BITS(&fap->fa_uid), 1045 EXTRACT_32BITS(&fap->fa_gid)); 1046 if (v3) { 1047 TCHECK(fap->fa3_size); 1048 printf(" sz %" PRIu64, 1049 EXTRACT_64BITS((u_int32_t *)&fap->fa3_size)); 1050 } else { 1051 TCHECK(fap->fa2_size); 1052 printf(" sz %d", EXTRACT_32BITS(&fap->fa2_size)); 1053 } 1054 } 1055 /* print lots more stuff */ 1056 if (verbose > 1) { 1057 if (v3) { 1058 TCHECK(fap->fa3_ctime); 1059 printf(" nlink %d rdev %d/%d", 1060 EXTRACT_32BITS(&fap->fa_nlink), 1061 EXTRACT_32BITS(&fap->fa3_rdev.specdata1), 1062 EXTRACT_32BITS(&fap->fa3_rdev.specdata2)); 1063 printf(" fsid %" PRIx64, 1064 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fsid)); 1065 printf(" fileid %" PRIx64, 1066 EXTRACT_64BITS((u_int32_t *)&fap->fa3_fileid)); 1067 printf(" a/m/ctime %u.%06u", 1068 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_sec), 1069 EXTRACT_32BITS(&fap->fa3_atime.nfsv3_nsec)); 1070 printf(" %u.%06u", 1071 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_sec), 1072 EXTRACT_32BITS(&fap->fa3_mtime.nfsv3_nsec)); 1073 printf(" %u.%06u", 1074 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_sec), 1075 EXTRACT_32BITS(&fap->fa3_ctime.nfsv3_nsec)); 1076 } else { 1077 TCHECK(fap->fa2_ctime); 1078 printf(" nlink %d rdev %x fsid %x nodeid %x a/m/ctime", 1079 EXTRACT_32BITS(&fap->fa_nlink), 1080 EXTRACT_32BITS(&fap->fa2_rdev), 1081 EXTRACT_32BITS(&fap->fa2_fsid), 1082 EXTRACT_32BITS(&fap->fa2_fileid)); 1083 printf(" %u.%06u", 1084 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_sec), 1085 EXTRACT_32BITS(&fap->fa2_atime.nfsv2_usec)); 1086 printf(" %u.%06u", 1087 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_sec), 1088 EXTRACT_32BITS(&fap->fa2_mtime.nfsv2_usec)); 1089 printf(" %u.%06u", 1090 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_sec), 1091 EXTRACT_32BITS(&fap->fa2_ctime.nfsv2_usec)); 1092 } 1093 } 1094 return ((const u_int32_t *)((unsigned char *)dp + 1095 (v3 ? NFSX_V3FATTR : NFSX_V2FATTR))); 1096 trunc: 1097 return (NULL); 1098 } 1099 1100 static int 1101 parseattrstat(const u_int32_t *dp, int verbose, int v3) 1102 { 1103 int er; 1104 1105 dp = parsestatus(dp, &er); 1106 if (dp == NULL) 1107 return (0); 1108 if (er) 1109 return (1); 1110 1111 return (parsefattr(dp, verbose, v3) != NULL); 1112 } 1113 1114 static int 1115 parsediropres(const u_int32_t *dp) 1116 { 1117 int er; 1118 1119 if (!(dp = parsestatus(dp, &er))) 1120 return (0); 1121 if (er) 1122 return (1); 1123 1124 dp = parsefh(dp, 0); 1125 if (dp == NULL) 1126 return (0); 1127 1128 return (parsefattr(dp, vflag, 0) != NULL); 1129 } 1130 1131 static int 1132 parselinkres(const u_int32_t *dp, int v3) 1133 { 1134 int er; 1135 1136 dp = parsestatus(dp, &er); 1137 if (dp == NULL) 1138 return(0); 1139 if (er) 1140 return(1); 1141 if (v3 && !(dp = parse_post_op_attr(dp, vflag))) 1142 return (0); 1143 putchar(' '); 1144 return (parsefn(dp) != NULL); 1145 } 1146 1147 static int 1148 parsestatfs(const u_int32_t *dp, int v3) 1149 { 1150 const struct nfs_statfs *sfsp; 1151 int er; 1152 1153 dp = parsestatus(dp, &er); 1154 if (dp == NULL) 1155 return (0); 1156 if (!v3 && er) 1157 return (1); 1158 1159 if (qflag) 1160 return(1); 1161 1162 if (v3) { 1163 if (vflag) 1164 printf(" POST:"); 1165 if (!(dp = parse_post_op_attr(dp, vflag))) 1166 return (0); 1167 } 1168 1169 TCHECK2(*dp, (v3 ? NFSX_V3STATFS : NFSX_V2STATFS)); 1170 1171 sfsp = (const struct nfs_statfs *)dp; 1172 1173 if (v3) { 1174 printf(" tbytes %" PRIu64 " fbytes %" PRIu64 " abytes %" PRIu64, 1175 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tbytes), 1176 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_fbytes), 1177 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_abytes)); 1178 if (vflag) { 1179 printf(" tfiles %" PRIu64 " ffiles %" PRIu64 " afiles %" PRIu64 " invar %u", 1180 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_tfiles), 1181 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_ffiles), 1182 EXTRACT_64BITS((u_int32_t *)&sfsp->sf_afiles), 1183 EXTRACT_32BITS(&sfsp->sf_invarsec)); 1184 } 1185 } else { 1186 printf(" tsize %d bsize %d blocks %d bfree %d bavail %d", 1187 EXTRACT_32BITS(&sfsp->sf_tsize), 1188 EXTRACT_32BITS(&sfsp->sf_bsize), 1189 EXTRACT_32BITS(&sfsp->sf_blocks), 1190 EXTRACT_32BITS(&sfsp->sf_bfree), 1191 EXTRACT_32BITS(&sfsp->sf_bavail)); 1192 } 1193 1194 return (1); 1195 trunc: 1196 return (0); 1197 } 1198 1199 static int 1200 parserddires(const u_int32_t *dp) 1201 { 1202 int er; 1203 1204 dp = parsestatus(dp, &er); 1205 if (dp == NULL) 1206 return (0); 1207 if (er) 1208 return (1); 1209 if (qflag) 1210 return (1); 1211 1212 TCHECK(dp[2]); 1213 printf(" offset %x size %d ", 1214 EXTRACT_32BITS(&dp[0]), EXTRACT_32BITS(&dp[1])); 1215 if (dp[2] != 0) 1216 printf(" eof"); 1217 1218 return (1); 1219 trunc: 1220 return (0); 1221 } 1222 1223 static const u_int32_t * 1224 parse_wcc_attr(const u_int32_t *dp) 1225 { 1226 printf(" sz %" PRIu64, EXTRACT_64BITS(&dp[0])); 1227 printf(" mtime %u.%06u ctime %u.%06u", 1228 EXTRACT_32BITS(&dp[2]), EXTRACT_32BITS(&dp[3]), 1229 EXTRACT_32BITS(&dp[4]), EXTRACT_32BITS(&dp[5])); 1230 return (dp + 6); 1231 } 1232 1233 /* 1234 * Pre operation attributes. Print only if vflag > 1. 1235 */ 1236 static const u_int32_t * 1237 parse_pre_op_attr(const u_int32_t *dp, int verbose) 1238 { 1239 TCHECK(dp[0]); 1240 if (!EXTRACT_32BITS(&dp[0])) 1241 return (dp + 1); 1242 dp++; 1243 TCHECK2(*dp, 24); 1244 if (verbose > 1) { 1245 return parse_wcc_attr(dp); 1246 } else { 1247 /* If not verbose enough, just skip over wcc_attr */ 1248 return (dp + 6); 1249 } 1250 trunc: 1251 return (NULL); 1252 } 1253 1254 /* 1255 * Post operation attributes are printed if vflag >= 1 1256 */ 1257 static const u_int32_t * 1258 parse_post_op_attr(const u_int32_t *dp, int verbose) 1259 { 1260 TCHECK(dp[0]); 1261 if (!EXTRACT_32BITS(&dp[0])) 1262 return (dp + 1); 1263 dp++; 1264 if (verbose) { 1265 return parsefattr(dp, verbose, 1); 1266 } else 1267 return (dp + (NFSX_V3FATTR / sizeof (u_int32_t))); 1268 trunc: 1269 return (NULL); 1270 } 1271 1272 static const u_int32_t * 1273 parse_wcc_data(const u_int32_t *dp, int verbose) 1274 { 1275 if (verbose > 1) 1276 printf(" PRE:"); 1277 if (!(dp = parse_pre_op_attr(dp, verbose))) 1278 return (0); 1279 1280 if (verbose) 1281 printf(" POST:"); 1282 return parse_post_op_attr(dp, verbose); 1283 } 1284 1285 static const u_int32_t * 1286 parsecreateopres(const u_int32_t *dp, int verbose) 1287 { 1288 int er; 1289 1290 if (!(dp = parsestatus(dp, &er))) 1291 return (0); 1292 if (er) 1293 dp = parse_wcc_data(dp, verbose); 1294 else { 1295 TCHECK(dp[0]); 1296 if (!EXTRACT_32BITS(&dp[0])) 1297 return (dp + 1); 1298 dp++; 1299 if (!(dp = parsefh(dp, 1))) 1300 return (0); 1301 if (verbose) { 1302 if (!(dp = parse_post_op_attr(dp, verbose))) 1303 return (0); 1304 if (vflag > 1) { 1305 printf(" dir attr:"); 1306 dp = parse_wcc_data(dp, verbose); 1307 } 1308 } 1309 } 1310 return (dp); 1311 trunc: 1312 return (NULL); 1313 } 1314 1315 static int 1316 parsewccres(const u_int32_t *dp, int verbose) 1317 { 1318 int er; 1319 1320 if (!(dp = parsestatus(dp, &er))) 1321 return (0); 1322 return parse_wcc_data(dp, verbose) != 0; 1323 } 1324 1325 static const u_int32_t * 1326 parsev3rddirres(const u_int32_t *dp, int verbose) 1327 { 1328 int er; 1329 1330 if (!(dp = parsestatus(dp, &er))) 1331 return (0); 1332 if (vflag) 1333 printf(" POST:"); 1334 if (!(dp = parse_post_op_attr(dp, verbose))) 1335 return (0); 1336 if (er) 1337 return dp; 1338 if (vflag) { 1339 TCHECK(dp[1]); 1340 printf(" verf %08x%08x", dp[0], dp[1]); 1341 dp += 2; 1342 } 1343 return dp; 1344 trunc: 1345 return (NULL); 1346 } 1347 1348 static int 1349 parsefsinfo(const u_int32_t *dp) 1350 { 1351 struct nfsv3_fsinfo *sfp; 1352 int er; 1353 1354 if (!(dp = parsestatus(dp, &er))) 1355 return (0); 1356 if (vflag) 1357 printf(" POST:"); 1358 if (!(dp = parse_post_op_attr(dp, vflag))) 1359 return (0); 1360 if (er) 1361 return (1); 1362 1363 sfp = (struct nfsv3_fsinfo *)dp; 1364 TCHECK(*sfp); 1365 printf(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u", 1366 EXTRACT_32BITS(&sfp->fs_rtmax), 1367 EXTRACT_32BITS(&sfp->fs_rtpref), 1368 EXTRACT_32BITS(&sfp->fs_wtmax), 1369 EXTRACT_32BITS(&sfp->fs_wtpref), 1370 EXTRACT_32BITS(&sfp->fs_dtpref)); 1371 if (vflag) { 1372 printf(" rtmult %u wtmult %u maxfsz %" PRIu64, 1373 EXTRACT_32BITS(&sfp->fs_rtmult), 1374 EXTRACT_32BITS(&sfp->fs_wtmult), 1375 EXTRACT_64BITS((u_int32_t *)&sfp->fs_maxfilesize)); 1376 printf(" delta %u.%06u ", 1377 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_sec), 1378 EXTRACT_32BITS(&sfp->fs_timedelta.nfsv3_nsec)); 1379 } 1380 return (1); 1381 trunc: 1382 return (0); 1383 } 1384 1385 static int 1386 parsepathconf(const u_int32_t *dp) 1387 { 1388 int er; 1389 struct nfsv3_pathconf *spp; 1390 1391 if (!(dp = parsestatus(dp, &er))) 1392 return (0); 1393 if (vflag) 1394 printf(" POST:"); 1395 if (!(dp = parse_post_op_attr(dp, vflag))) 1396 return (0); 1397 if (er) 1398 return (1); 1399 1400 spp = (struct nfsv3_pathconf *)dp; 1401 TCHECK(*spp); 1402 1403 printf(" linkmax %u namemax %u %s %s %s %s", 1404 EXTRACT_32BITS(&spp->pc_linkmax), 1405 EXTRACT_32BITS(&spp->pc_namemax), 1406 EXTRACT_32BITS(&spp->pc_notrunc) ? "notrunc" : "", 1407 EXTRACT_32BITS(&spp->pc_chownrestricted) ? "chownres" : "", 1408 EXTRACT_32BITS(&spp->pc_caseinsensitive) ? "igncase" : "", 1409 EXTRACT_32BITS(&spp->pc_casepreserving) ? "keepcase" : ""); 1410 return (1); 1411 trunc: 1412 return (0); 1413 } 1414 1415 static void 1416 interp_reply(const struct sunrpc_msg *rp, u_int32_t proc, u_int32_t vers, int length) 1417 { 1418 register const u_int32_t *dp; 1419 register int v3; 1420 int er; 1421 1422 v3 = (vers == NFS_VER3); 1423 1424 if (!v3 && proc < NFS_NPROCS) 1425 proc = nfsv3_procid[proc]; 1426 1427 switch (proc) { 1428 1429 case NFSPROC_NOOP: 1430 printf(" nop"); 1431 return; 1432 1433 case NFSPROC_NULL: 1434 printf(" null"); 1435 return; 1436 1437 case NFSPROC_GETATTR: 1438 printf(" getattr"); 1439 dp = parserep(rp, length); 1440 if (dp != NULL && parseattrstat(dp, !qflag, v3) != 0) 1441 return; 1442 break; 1443 1444 case NFSPROC_SETATTR: 1445 printf(" setattr"); 1446 if (!(dp = parserep(rp, length))) 1447 return; 1448 if (v3) { 1449 if (parsewccres(dp, vflag)) 1450 return; 1451 } else { 1452 if (parseattrstat(dp, !qflag, 0) != 0) 1453 return; 1454 } 1455 break; 1456 1457 case NFSPROC_LOOKUP: 1458 printf(" lookup"); 1459 if (!(dp = parserep(rp, length))) 1460 break; 1461 if (v3) { 1462 if (!(dp = parsestatus(dp, &er))) 1463 break; 1464 if (er) { 1465 if (vflag > 1) { 1466 printf(" post dattr:"); 1467 dp = parse_post_op_attr(dp, vflag); 1468 } 1469 } else { 1470 if (!(dp = parsefh(dp, v3))) 1471 break; 1472 if ((dp = parse_post_op_attr(dp, vflag)) && 1473 vflag > 1) { 1474 printf(" post dattr:"); 1475 dp = parse_post_op_attr(dp, vflag); 1476 } 1477 } 1478 if (dp) 1479 return; 1480 } else { 1481 if (parsediropres(dp) != 0) 1482 return; 1483 } 1484 break; 1485 1486 case NFSPROC_ACCESS: 1487 printf(" access"); 1488 if (!(dp = parserep(rp, length))) 1489 break; 1490 if (!(dp = parsestatus(dp, &er))) 1491 break; 1492 if (vflag) 1493 printf(" attr:"); 1494 if (!(dp = parse_post_op_attr(dp, vflag))) 1495 break; 1496 if (!er) 1497 printf(" c %04x", EXTRACT_32BITS(&dp[0])); 1498 return; 1499 1500 case NFSPROC_READLINK: 1501 printf(" readlink"); 1502 dp = parserep(rp, length); 1503 if (dp != NULL && parselinkres(dp, v3) != 0) 1504 return; 1505 break; 1506 1507 case NFSPROC_READ: 1508 printf(" read"); 1509 if (!(dp = parserep(rp, length))) 1510 break; 1511 if (v3) { 1512 if (!(dp = parsestatus(dp, &er))) 1513 break; 1514 if (!(dp = parse_post_op_attr(dp, vflag))) 1515 break; 1516 if (er) 1517 return; 1518 if (vflag) { 1519 TCHECK(dp[1]); 1520 printf(" %u bytes", EXTRACT_32BITS(&dp[0])); 1521 if (EXTRACT_32BITS(&dp[1])) 1522 printf(" EOF"); 1523 } 1524 return; 1525 } else { 1526 if (parseattrstat(dp, vflag, 0) != 0) 1527 return; 1528 } 1529 break; 1530 1531 case NFSPROC_WRITE: 1532 printf(" write"); 1533 if (!(dp = parserep(rp, length))) 1534 break; 1535 if (v3) { 1536 if (!(dp = parsestatus(dp, &er))) 1537 break; 1538 if (!(dp = parse_wcc_data(dp, vflag))) 1539 break; 1540 if (er) 1541 return; 1542 if (vflag) { 1543 TCHECK(dp[0]); 1544 printf(" %u bytes", EXTRACT_32BITS(&dp[0])); 1545 if (vflag > 1) { 1546 TCHECK(dp[1]); 1547 printf(" <%s>", 1548 tok2str(nfsv3_writemodes, 1549 NULL, EXTRACT_32BITS(&dp[1]))); 1550 } 1551 return; 1552 } 1553 } else { 1554 if (parseattrstat(dp, vflag, v3) != 0) 1555 return; 1556 } 1557 break; 1558 1559 case NFSPROC_CREATE: 1560 printf(" create"); 1561 if (!(dp = parserep(rp, length))) 1562 break; 1563 if (v3) { 1564 if (parsecreateopres(dp, vflag) != 0) 1565 return; 1566 } else { 1567 if (parsediropres(dp) != 0) 1568 return; 1569 } 1570 break; 1571 1572 case NFSPROC_MKDIR: 1573 printf(" mkdir"); 1574 if (!(dp = parserep(rp, length))) 1575 break; 1576 if (v3) { 1577 if (parsecreateopres(dp, vflag) != 0) 1578 return; 1579 } else { 1580 if (parsediropres(dp) != 0) 1581 return; 1582 } 1583 break; 1584 1585 case NFSPROC_SYMLINK: 1586 printf(" symlink"); 1587 if (!(dp = parserep(rp, length))) 1588 break; 1589 if (v3) { 1590 if (parsecreateopres(dp, vflag) != 0) 1591 return; 1592 } else { 1593 if (parsestatus(dp, &er) != 0) 1594 return; 1595 } 1596 break; 1597 1598 case NFSPROC_MKNOD: 1599 printf(" mknod"); 1600 if (!(dp = parserep(rp, length))) 1601 break; 1602 if (parsecreateopres(dp, vflag) != 0) 1603 return; 1604 break; 1605 1606 case NFSPROC_REMOVE: 1607 printf(" remove"); 1608 if (!(dp = parserep(rp, length))) 1609 break; 1610 if (v3) { 1611 if (parsewccres(dp, vflag)) 1612 return; 1613 } else { 1614 if (parsestatus(dp, &er) != 0) 1615 return; 1616 } 1617 break; 1618 1619 case NFSPROC_RMDIR: 1620 printf(" rmdir"); 1621 if (!(dp = parserep(rp, length))) 1622 break; 1623 if (v3) { 1624 if (parsewccres(dp, vflag)) 1625 return; 1626 } else { 1627 if (parsestatus(dp, &er) != 0) 1628 return; 1629 } 1630 break; 1631 1632 case NFSPROC_RENAME: 1633 printf(" rename"); 1634 if (!(dp = parserep(rp, length))) 1635 break; 1636 if (v3) { 1637 if (!(dp = parsestatus(dp, &er))) 1638 break; 1639 if (vflag) { 1640 printf(" from:"); 1641 if (!(dp = parse_wcc_data(dp, vflag))) 1642 break; 1643 printf(" to:"); 1644 if (!(dp = parse_wcc_data(dp, vflag))) 1645 break; 1646 } 1647 return; 1648 } else { 1649 if (parsestatus(dp, &er) != 0) 1650 return; 1651 } 1652 break; 1653 1654 case NFSPROC_LINK: 1655 printf(" link"); 1656 if (!(dp = parserep(rp, length))) 1657 break; 1658 if (v3) { 1659 if (!(dp = parsestatus(dp, &er))) 1660 break; 1661 if (vflag) { 1662 printf(" file POST:"); 1663 if (!(dp = parse_post_op_attr(dp, vflag))) 1664 break; 1665 printf(" dir:"); 1666 if (!(dp = parse_wcc_data(dp, vflag))) 1667 break; 1668 return; 1669 } 1670 } else { 1671 if (parsestatus(dp, &er) != 0) 1672 return; 1673 } 1674 break; 1675 1676 case NFSPROC_READDIR: 1677 printf(" readdir"); 1678 if (!(dp = parserep(rp, length))) 1679 break; 1680 if (v3) { 1681 if (parsev3rddirres(dp, vflag)) 1682 return; 1683 } else { 1684 if (parserddires(dp) != 0) 1685 return; 1686 } 1687 break; 1688 1689 case NFSPROC_READDIRPLUS: 1690 printf(" readdirplus"); 1691 if (!(dp = parserep(rp, length))) 1692 break; 1693 if (parsev3rddirres(dp, vflag)) 1694 return; 1695 break; 1696 1697 case NFSPROC_FSSTAT: 1698 printf(" fsstat"); 1699 dp = parserep(rp, length); 1700 if (dp != NULL && parsestatfs(dp, v3) != 0) 1701 return; 1702 break; 1703 1704 case NFSPROC_FSINFO: 1705 printf(" fsinfo"); 1706 dp = parserep(rp, length); 1707 if (dp != NULL && parsefsinfo(dp) != 0) 1708 return; 1709 break; 1710 1711 case NFSPROC_PATHCONF: 1712 printf(" pathconf"); 1713 dp = parserep(rp, length); 1714 if (dp != NULL && parsepathconf(dp) != 0) 1715 return; 1716 break; 1717 1718 case NFSPROC_COMMIT: 1719 printf(" commit"); 1720 dp = parserep(rp, length); 1721 if (dp != NULL && parsewccres(dp, vflag) != 0) 1722 return; 1723 break; 1724 1725 default: 1726 printf(" proc-%u", proc); 1727 return; 1728 } 1729 trunc: 1730 if (!nfserr) 1731 fputs(" [|nfs]", stdout); 1732 } 1733