1 /* $OpenBSD: print-nfs.c,v 1.9 2000/12/05 08:17:45 jakob 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 #ifdef __STDC__ 34 struct mbuf; 35 struct rtentry; 36 #endif 37 #include <net/if.h> 38 39 #include <netinet/in.h> 40 #include <netinet/if_ether.h> 41 #include <netinet/in_systm.h> 42 #include <netinet/ip.h> 43 #include <netinet/ip_var.h> 44 45 #include <rpc/rpc.h> 46 47 #include <ctype.h> 48 #include <pcap.h> 49 #include <stdio.h> 50 #include <string.h> 51 52 #include "interface.h" 53 #include "addrtoname.h" 54 55 #include "nfsv2.h" 56 #include "nfsfh.h" 57 58 static void nfs_printfh(const u_int32_t *); 59 static void xid_map_enter(const struct rpc_msg *, const struct ip *); 60 static u_int32_t xid_map_find(const struct rpc_msg *, const struct ip *, 61 u_int32_t *); 62 static void interp_reply(const struct rpc_msg *, u_int32_t, u_int); 63 64 static int nfserr; /* true if we error rather than trunc */ 65 66 void 67 nfsreply_print(register const u_char *bp, u_int length, 68 register const u_char *bp2) 69 { 70 register const struct rpc_msg *rp; 71 register const struct ip *ip; 72 u_int32_t proc; 73 74 nfserr = 0; /* assume no error */ 75 rp = (const struct rpc_msg *)bp; 76 ip = (const struct ip *)bp2; 77 78 printf("xid 0x%x reply %s %d", (u_int32_t)ntohl(rp->rm_xid), 79 ntohl(rp->rm_reply.rp_stat) == MSG_ACCEPTED ? "ok":"ERR", 80 length); 81 if (xid_map_find(rp, ip, &proc)) 82 interp_reply(rp, proc, length); 83 } 84 85 /* 86 * Return a pointer to the first file handle in the packet. 87 * If the packet was truncated, return 0. 88 */ 89 static const u_int32_t * 90 parsereq(register const struct rpc_msg *rp, register u_int length) 91 { 92 register const u_int32_t *dp; 93 register u_int len; 94 95 /* 96 * find the start of the req data (if we captured it) 97 */ 98 dp = (u_int32_t *)&rp->rm_call.cb_cred; 99 TCHECK(dp[1]); 100 len = ntohl(dp[1]); 101 if (len < length) { 102 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 103 TCHECK(dp[1]); 104 len = ntohl(dp[1]); 105 if (len < length) { 106 dp += (len + (2 * sizeof(*dp) + 3)) / sizeof(*dp); 107 TCHECK2(dp[0], 0); 108 return (dp); 109 } 110 } 111 trunc: 112 return (NULL); 113 } 114 115 /* 116 * Print out an NFS file handle and return a pointer to following word. 117 * If packet was truncated, return 0. 118 */ 119 static const u_int32_t * 120 parsefh(register const u_int32_t *dp) 121 { 122 if (dp + 8 <= (u_int32_t *)snapend) { 123 nfs_printfh(dp); 124 return (dp + 8); 125 } 126 return (NULL); 127 } 128 129 /* 130 * Print out a file name and return pointer to 32-bit word past it. 131 * If packet was truncated, return 0. 132 */ 133 static const u_int32_t * 134 parsefn(register const u_int32_t *dp) 135 { 136 register u_int32_t len; 137 register const u_char *cp; 138 139 /* Bail if we don't have the string length */ 140 if ((u_char *)dp > snapend - sizeof(*dp)) 141 return (NULL); 142 143 /* Fetch string length; convert to host order */ 144 len = *dp++; 145 NTOHL(len); 146 147 cp = (u_char *)dp; 148 /* Update 32-bit pointer (NFS filenames padded to 32-bit boundaries) */ 149 dp += ((len + 3) & ~3) / sizeof(*dp); 150 if ((u_char *)dp > snapend) 151 return (NULL); 152 /* XXX seems like we should be checking the length */ 153 putchar('"'); 154 (void) fn_printn(cp, len, NULL); 155 putchar('"'); 156 157 return (dp); 158 } 159 160 /* 161 * Print out file handle and file name. 162 * Return pointer to 32-bit word past file name. 163 * If packet was truncated (or there was some other error), return 0. 164 */ 165 static const u_int32_t * 166 parsefhn(register const u_int32_t *dp) 167 { 168 dp = parsefh(dp); 169 if (dp == NULL) 170 return (NULL); 171 putchar(' '); 172 return (parsefn(dp)); 173 } 174 175 void 176 nfsreq_print(register const u_char *bp, u_int length, 177 register const u_char *bp2) 178 { 179 register const struct rpc_msg *rp; 180 register const struct ip *ip; 181 register const u_int32_t *dp; 182 183 nfserr = 0; /* assume no error */ 184 rp = (const struct rpc_msg *)bp; 185 ip = (const struct ip *)bp2; 186 printf("xid 0x%x %d", (u_int32_t)ntohl(rp->rm_xid), length); 187 188 xid_map_enter(rp, ip); /* record proc number for later on */ 189 190 switch (ntohl(rp->rm_call.cb_proc)) { 191 #ifdef NFSPROC_NOOP 192 case NFSPROC_NOOP: 193 printf(" nop"); 194 return; 195 #else 196 #define NFSPROC_NOOP -1 197 #endif 198 case NFSPROC_NULL: 199 printf(" null"); 200 return; 201 202 case NFSPROC_GETATTR: 203 printf(" getattr"); 204 if ((dp = parsereq(rp, length)) != NULL && parsefh(dp) != NULL) 205 return; 206 break; 207 208 case NFSPROC_SETATTR: 209 printf(" setattr"); 210 if ((dp = parsereq(rp, length)) != NULL && parsefh(dp) != NULL) 211 return; 212 break; 213 214 #if NFSPROC_ROOT != NFSPROC_NOOP 215 case NFSPROC_ROOT: 216 printf(" root"); 217 break; 218 #endif 219 case NFSPROC_LOOKUP: 220 printf(" lookup"); 221 if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp) != NULL) 222 return; 223 break; 224 225 case NFSPROC_READLINK: 226 printf(" readlink"); 227 if ((dp = parsereq(rp, length)) != NULL && parsefh(dp) != NULL) 228 return; 229 break; 230 231 case NFSPROC_READ: 232 printf(" read"); 233 if ((dp = parsereq(rp, length)) != NULL && 234 (dp = parsefh(dp)) != NULL) { 235 TCHECK2(dp[0], 3 * sizeof(*dp)); 236 printf(" %u bytes @ %u", 237 (u_int32_t)ntohl(dp[1]), 238 (u_int32_t)ntohl(dp[0])); 239 return; 240 } 241 break; 242 243 #if NFSPROC_WRITECACHE != NFSPROC_NOOP 244 case NFSPROC_WRITECACHE: 245 printf(" writecache"); 246 if ((dp = parsereq(rp, length)) != NULL && 247 (dp = parsefh(dp)) != NULL) { 248 TCHECK2(dp[0], 4 * sizeof(*dp)); 249 printf(" %u (%u) bytes @ %u (%u)", 250 (u_int32_t)ntohl(dp[3]), 251 (u_int32_t)ntohl(dp[2]), 252 (u_int32_t)ntohl(dp[1]), 253 (u_int32_t)ntohl(dp[0])); 254 return; 255 } 256 break; 257 #endif 258 case NFSPROC_WRITE: 259 printf(" write"); 260 if ((dp = parsereq(rp, length)) != NULL && 261 (dp = parsefh(dp)) != NULL) { 262 TCHECK2(dp[0], 4 * sizeof(*dp)); 263 printf(" %u (%u) bytes @ %u (%u)", 264 (u_int32_t)ntohl(dp[3]), 265 (u_int32_t)ntohl(dp[2]), 266 (u_int32_t)ntohl(dp[1]), 267 (u_int32_t)ntohl(dp[0])); 268 return; 269 } 270 break; 271 272 case NFSPROC_CREATE: 273 printf(" create"); 274 if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp) != NULL) 275 return; 276 break; 277 278 case NFSPROC_REMOVE: 279 printf(" remove"); 280 if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp) != NULL) 281 return; 282 break; 283 284 case NFSPROC_RENAME: 285 printf(" rename"); 286 if ((dp = parsereq(rp, length)) != NULL && 287 (dp = parsefhn(dp)) != NULL) { 288 fputs(" ->", stdout); 289 if (parsefhn(dp) != NULL) 290 return; 291 } 292 break; 293 294 case NFSPROC_LINK: 295 printf(" link"); 296 if ((dp = parsereq(rp, length)) != NULL && 297 (dp = parsefh(dp)) != NULL) { 298 fputs(" ->", stdout); 299 if (parsefhn(dp) != NULL) 300 return; 301 } 302 break; 303 304 case NFSPROC_SYMLINK: 305 printf(" symlink"); 306 if ((dp = parsereq(rp, length)) != NULL && 307 (dp = parsefhn(dp)) != NULL) { 308 fputs(" -> ", stdout); 309 if (parsefn(dp) != NULL) 310 return; 311 } 312 break; 313 314 case NFSPROC_MKDIR: 315 printf(" mkdir"); 316 if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp) != NULL) 317 return; 318 break; 319 320 case NFSPROC_RMDIR: 321 printf(" rmdir"); 322 if ((dp = parsereq(rp, length)) != NULL && parsefhn(dp) != NULL) 323 return; 324 break; 325 326 case NFSPROC_READDIR: 327 printf(" readdir"); 328 if ((dp = parsereq(rp, length)) != NULL && 329 (dp = parsefh(dp)) != NULL) { 330 TCHECK2(dp[0], 2 * sizeof(*dp)); 331 /* 332 * Print the offset as signed, since -1 is common, 333 * but offsets > 2^31 aren't. 334 */ 335 printf(" %u bytes @ %d", 336 (u_int32_t)ntohl(dp[1]), 337 (u_int32_t)ntohl(dp[0])); 338 return; 339 } 340 break; 341 342 case NFSPROC_STATFS: 343 printf(" statfs"); 344 if ((dp = parsereq(rp, length)) != NULL && parsefh(dp) != NULL) 345 return; 346 break; 347 348 default: 349 printf(" proc-%u", (u_int32_t)ntohl(rp->rm_call.cb_proc)); 350 return; 351 } 352 trunc: 353 if (!nfserr) 354 fputs(" [|nfs]", stdout); 355 } 356 357 /* 358 * Print out an NFS file handle. 359 * We assume packet was not truncated before the end of the 360 * file handle pointed to by dp. 361 * 362 * Note: new version (using portable file-handle parser) doesn't produce 363 * generation number. It probably could be made to do that, with some 364 * additional hacking on the parser code. 365 */ 366 static void 367 nfs_printfh(register const u_int32_t *dp) 368 { 369 my_fsid fsid; 370 ino_t ino; 371 char *sfsname = NULL; 372 373 Parse_fh((caddr_t *)dp, &fsid, &ino, NULL, &sfsname, 0); 374 375 if (sfsname) { 376 /* file system ID is ASCII, not numeric, for this server OS */ 377 static char temp[NFS_FHSIZE+1]; 378 379 /* Make sure string is null-terminated */ 380 strncpy(temp, sfsname, NFS_FHSIZE); 381 /* Remove trailing spaces */ 382 sfsname = strchr(temp, ' '); 383 if (sfsname) 384 *sfsname = 0; 385 386 (void)printf(" fh %s/%u", temp, (u_int32_t)ino); 387 } else { 388 (void)printf(" fh %u,%u/%u", 389 fsid.Fsid_dev.Major, fsid.Fsid_dev.Minor, (u_int32_t)ino); 390 } 391 } 392 393 /* 394 * Maintain a small cache of recent client.XID.server/proc pairs, to allow 395 * us to match up replies with requests and thus to know how to parse 396 * the reply. 397 */ 398 399 struct xid_map_entry { 400 u_int32_t xid; /* transaction ID (net order) */ 401 struct in_addr client; /* client IP address (net order) */ 402 struct in_addr server; /* server IP address (net order) */ 403 u_int32_t proc; /* call proc number (host order) */ 404 }; 405 406 /* 407 * Map entries are kept in an array that we manage as a ring; 408 * new entries are always added at the tail of the ring. Initially, 409 * all the entries are zero and hence don't match anything. 410 */ 411 412 #define XIDMAPSIZE 64 413 414 struct xid_map_entry xid_map[XIDMAPSIZE]; 415 416 int xid_map_next = 0; 417 int xid_map_hint = 0; 418 419 static void 420 xid_map_enter(const struct rpc_msg *rp, const struct ip *ip) 421 { 422 struct xid_map_entry *xmep; 423 424 xmep = &xid_map[xid_map_next]; 425 426 if (++xid_map_next >= XIDMAPSIZE) 427 xid_map_next = 0; 428 429 xmep->xid = rp->rm_xid; 430 xmep->client = ip->ip_src; 431 xmep->server = ip->ip_dst; 432 xmep->proc = ntohl(rp->rm_call.cb_proc); 433 } 434 435 /* Returns true and sets proc success or false on failure */ 436 static u_int32_t 437 xid_map_find(const struct rpc_msg *rp, const struct ip *ip, u_int32_t *proc) 438 { 439 int i; 440 struct xid_map_entry *xmep; 441 u_int32_t xid = rp->rm_xid; 442 u_int32_t clip = ip->ip_dst.s_addr; 443 u_int32_t sip = ip->ip_src.s_addr; 444 445 /* Start searching from where we last left off */ 446 i = xid_map_hint; 447 do { 448 xmep = &xid_map[i]; 449 if (xmep->xid == xid && xmep->client.s_addr == clip && 450 xmep->server.s_addr == sip) { 451 /* match */ 452 xid_map_hint = i; 453 *proc = xmep->proc; 454 return (1); 455 } 456 if (++i >= XIDMAPSIZE) 457 i = 0; 458 } while (i != xid_map_hint); 459 460 /* search failed */ 461 return (0); 462 } 463 464 /* 465 * Routines for parsing reply packets 466 */ 467 468 /* 469 * Return a pointer to the beginning of the actual results. 470 * If the packet was truncated, return 0. 471 */ 472 static const u_int32_t * 473 parserep(register const struct rpc_msg *rp, register u_int length) 474 { 475 register const u_int32_t *dp; 476 u_int len; 477 enum accept_stat astat; 478 479 /* 480 * Portability note: 481 * Here we find the address of the ar_verf credentials. 482 * Originally, this calculation was 483 * dp = (u_int32_t *)&rp->rm_reply.rp_acpt.ar_verf 484 * On the wire, the rp_acpt field starts immediately after 485 * the (32 bit) rp_stat field. However, rp_acpt (which is a 486 * "struct accepted_reply") contains a "struct opaque_auth", 487 * whose internal representation contains a pointer, so on a 488 * 64-bit machine the compiler inserts 32 bits of padding 489 * before rp->rm_reply.rp_acpt.ar_verf. So, we cannot use 490 * the internal representation to parse the on-the-wire 491 * representation. Instead, we skip past the rp_stat field, 492 * which is an "enum" and so occupies one 32-bit word. 493 */ 494 dp = ((const u_int32_t *)&rp->rm_reply) + 1; 495 TCHECK2(dp[0], 1); 496 len = ntohl(dp[1]); 497 if (len >= length) 498 return (NULL); 499 /* 500 * skip past the ar_verf credentials. 501 */ 502 dp += (len + (2*sizeof(u_int32_t) + 3)) / sizeof(u_int32_t); 503 TCHECK2(dp[0], 0); 504 505 /* 506 * now we can check the ar_stat field 507 */ 508 astat = ntohl(*(enum accept_stat *)dp); 509 switch (astat) { 510 511 case SUCCESS: 512 break; 513 514 case PROG_UNAVAIL: 515 printf(" PROG_UNAVAIL"); 516 nfserr = 1; /* suppress trunc string */ 517 return (NULL); 518 519 case PROG_MISMATCH: 520 printf(" PROG_MISMATCH"); 521 nfserr = 1; /* suppress trunc string */ 522 return (NULL); 523 524 case PROC_UNAVAIL: 525 printf(" PROC_UNAVAIL"); 526 nfserr = 1; /* suppress trunc string */ 527 return (NULL); 528 529 case GARBAGE_ARGS: 530 printf(" GARBAGE_ARGS"); 531 nfserr = 1; /* suppress trunc string */ 532 return (NULL); 533 534 case SYSTEM_ERR: 535 printf(" SYSTEM_ERR"); 536 nfserr = 1; /* suppress trunc string */ 537 return (NULL); 538 539 default: 540 printf(" ar_stat %d", astat); 541 nfserr = 1; /* suppress trunc string */ 542 return (NULL); 543 } 544 /* successful return */ 545 if ((sizeof(astat) + ((u_char *)dp)) < snapend) 546 return ((u_int32_t *) (sizeof(astat) + ((char *)dp))); 547 548 trunc: 549 return (NULL); 550 } 551 552 static const u_int32_t * 553 parsestatus(const u_int32_t *dp) 554 { 555 register int errnum; 556 557 TCHECK(dp[0]); 558 errnum = ntohl(dp[0]); 559 if (errnum != 0) { 560 if (!qflag) 561 printf(" ERROR: %s", pcap_strerror(errnum)); 562 nfserr = 1; /* suppress trunc string */ 563 return (NULL); 564 } 565 return (dp + 1); 566 trunc: 567 return (NULL); 568 } 569 570 static struct tok type2str[] = { 571 { NFNON, "NON" }, 572 { NFREG, "REG" }, 573 { NFDIR, "DIR" }, 574 { NFBLK, "BLK" }, 575 { NFCHR, "CHR" }, 576 { NFLNK, "LNK" }, 577 { 0, NULL } 578 }; 579 580 static const u_int32_t * 581 parsefattr(const u_int32_t *dp, int verbose) 582 { 583 const struct nfsv2_fattr *fap; 584 585 fap = (const struct nfsv2_fattr *)dp; 586 if (verbose) { 587 TCHECK(fap->fa_nfssize); 588 printf(" %s %o ids %u/%u sz %u ", 589 tok2str(type2str, "unk-ft %d ", 590 (u_int32_t)ntohl(fap->fa_type)), 591 (u_int32_t)ntohl(fap->fa_mode), 592 (u_int32_t)ntohl(fap->fa_uid), 593 (u_int32_t)ntohl(fap->fa_gid), 594 (u_int32_t)ntohl(fap->fa_nfssize)); 595 } 596 /* print lots more stuff */ 597 if (verbose > 1) { 598 TCHECK(fap->fa_nfsfileid); 599 printf("nlink %u rdev %x fsid %x nodeid %x a/m/ctime ", 600 (u_int32_t)ntohl(fap->fa_nlink), 601 (u_int32_t)ntohl(fap->fa_nfsrdev), 602 (u_int32_t)ntohl(fap->fa_nfsfsid), 603 (u_int32_t)ntohl(fap->fa_nfsfileid)); 604 TCHECK(fap->fa_nfsatime); 605 printf("%u.%06u ", 606 (u_int32_t)ntohl(fap->fa_nfsatime.nfs_sec), 607 (u_int32_t)ntohl(fap->fa_nfsatime.nfs_usec)); 608 TCHECK(fap->fa_nfsmtime); 609 printf("%u.%06u ", 610 (u_int32_t)ntohl(fap->fa_nfsmtime.nfs_sec), 611 (u_int32_t)ntohl(fap->fa_nfsmtime.nfs_usec)); 612 TCHECK(fap->fa_nfsctime); 613 printf("%u.%06u ", 614 (u_int32_t)ntohl(fap->fa_nfsctime.nfs_sec), 615 (u_int32_t)ntohl(fap->fa_nfsctime.nfs_usec)); 616 } 617 return ((const u_int32_t *)&fap[1]); 618 trunc: 619 return (NULL); 620 } 621 622 static int 623 parseattrstat(const u_int32_t *dp, int verbose) 624 { 625 626 dp = parsestatus(dp); 627 if (dp == NULL) 628 return (0); 629 630 return (parsefattr(dp, verbose) != NULL); 631 } 632 633 static int 634 parsediropres(const u_int32_t *dp) 635 { 636 637 dp = parsestatus(dp); 638 if (dp == NULL) 639 return (0); 640 641 dp = parsefh(dp); 642 if (dp == NULL) 643 return (0); 644 645 return (parsefattr(dp, vflag) != NULL); 646 } 647 648 static int 649 parselinkres(const u_int32_t *dp) 650 { 651 dp = parsestatus(dp); 652 if (dp == NULL) 653 return (0); 654 655 putchar(' '); 656 return (parsefn(dp) != NULL); 657 } 658 659 static int 660 parsestatfs(const u_int32_t *dp) 661 { 662 const struct nfsv2_statfs *sfsp; 663 664 dp = parsestatus(dp); 665 if (dp == NULL) 666 return (0); 667 668 if (!qflag) { 669 sfsp = (const struct nfsv2_statfs *)dp; 670 TCHECK(sfsp->sf_bavail); 671 printf(" tsize %u bsize %u blocks %u bfree %u bavail %u", 672 (u_int32_t)ntohl(sfsp->sf_tsize), 673 (u_int32_t)ntohl(sfsp->sf_bsize), 674 (u_int32_t)ntohl(sfsp->sf_blocks), 675 (u_int32_t)ntohl(sfsp->sf_bfree), 676 (u_int32_t)ntohl(sfsp->sf_bavail)); 677 } 678 679 return (1); 680 trunc: 681 return (0); 682 } 683 684 static int 685 parserddires(const u_int32_t *dp) 686 { 687 dp = parsestatus(dp); 688 if (dp == NULL) 689 return (0); 690 if (!qflag) { 691 TCHECK(dp[0]); 692 printf(" offset %x", (u_int32_t)ntohl(dp[0])); 693 TCHECK(dp[1]); 694 printf(" size %u", (u_int32_t)ntohl(dp[1])); 695 TCHECK(dp[2]); 696 if (dp[2] != 0) 697 printf(" eof"); 698 } 699 700 return (1); 701 trunc: 702 return (0); 703 } 704 705 static void 706 interp_reply(const struct rpc_msg *rp, u_int32_t proc, u_int length) 707 { 708 register const u_int32_t *dp; 709 710 switch (proc) { 711 712 #ifdef NFSPROC_NOOP 713 case NFSPROC_NOOP: 714 printf(" nop"); 715 return; 716 #else 717 #define NFSPROC_NOOP -1 718 #endif 719 case NFSPROC_NULL: 720 printf(" null"); 721 return; 722 723 case NFSPROC_GETATTR: 724 printf(" getattr"); 725 dp = parserep(rp, length); 726 if (dp != NULL && parseattrstat(dp, !qflag) != 0) 727 return; 728 break; 729 730 case NFSPROC_SETATTR: 731 printf(" setattr"); 732 dp = parserep(rp, length); 733 if (dp != NULL && parseattrstat(dp, !qflag) != 0) 734 return; 735 break; 736 737 #if NFSPROC_ROOT != NFSPROC_NOOP 738 case NFSPROC_ROOT: 739 printf(" root"); 740 break; 741 #endif 742 case NFSPROC_LOOKUP: 743 printf(" lookup"); 744 dp = parserep(rp, length); 745 if (dp != NULL && parsediropres(dp) != 0) 746 return; 747 break; 748 749 case NFSPROC_READLINK: 750 printf(" readlink"); 751 dp = parserep(rp, length); 752 if (dp != NULL && parselinkres(dp) != 0) 753 return; 754 break; 755 756 case NFSPROC_READ: 757 printf(" read"); 758 dp = parserep(rp, length); 759 if (dp != NULL && parseattrstat(dp, vflag) != 0) 760 return; 761 break; 762 763 #if NFSPROC_WRITECACHE != NFSPROC_NOOP 764 case NFSPROC_WRITECACHE: 765 printf(" writecache"); 766 break; 767 #endif 768 case NFSPROC_WRITE: 769 printf(" write"); 770 dp = parserep(rp, length); 771 if (dp != NULL && parseattrstat(dp, vflag) != 0) 772 return; 773 break; 774 775 case NFSPROC_CREATE: 776 printf(" create"); 777 dp = parserep(rp, length); 778 if (dp != NULL && parsediropres(dp) != 0) 779 return; 780 break; 781 782 case NFSPROC_REMOVE: 783 printf(" remove"); 784 dp = parserep(rp, length); 785 if (dp != NULL && parsestatus(dp) != 0) 786 return; 787 break; 788 789 case NFSPROC_RENAME: 790 printf(" rename"); 791 dp = parserep(rp, length); 792 if (dp != NULL && parsestatus(dp) != 0) 793 return; 794 break; 795 796 case NFSPROC_LINK: 797 printf(" link"); 798 dp = parserep(rp, length); 799 if (dp != NULL && parsestatus(dp) != 0) 800 return; 801 break; 802 803 case NFSPROC_SYMLINK: 804 printf(" symlink"); 805 dp = parserep(rp, length); 806 if (dp != NULL && parsestatus(dp) != 0) 807 return; 808 break; 809 810 case NFSPROC_MKDIR: 811 printf(" mkdir"); 812 dp = parserep(rp, length); 813 if (dp != NULL && parsediropres(dp) != 0) 814 return; 815 break; 816 817 case NFSPROC_RMDIR: 818 printf(" rmdir"); 819 dp = parserep(rp, length); 820 if (dp != NULL && parsestatus(dp) != 0) 821 return; 822 break; 823 824 case NFSPROC_READDIR: 825 printf(" readdir"); 826 dp = parserep(rp, length); 827 if (dp != NULL && parserddires(dp) != 0) 828 return; 829 break; 830 831 case NFSPROC_STATFS: 832 printf(" statfs"); 833 dp = parserep(rp, length); 834 if (dp != NULL && parsestatfs(dp) != 0) 835 return; 836 break; 837 838 default: 839 printf(" proc-%u", proc); 840 return; 841 } 842 if (!nfserr) 843 fputs(" [|nfs]", stdout); 844 } 845