]> The Tcpdump Group git mirrors - tcpdump/blob - print-nfs.c
Initial revision
[tcpdump] / print-nfs.c
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: /tcpdump/master/tcpdump/print-nfs.c,v 1.65 1999-10-07 23:47:12 mcr 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 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.%u: 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.%u > %s.%u: 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.%u > %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.%u > %s.%u: %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 }