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