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