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