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