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