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