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