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