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