xref: /titanic_50/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_nfs3.c (revision 0a47c91c895e274dd0990009919e30e984364a8b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright (c) 1991, 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
25  */
26 
27 #ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
28 
29 #include <sys/types.h>
30 #include <sys/errno.h>
31 #include <sys/tiuser.h>
32 #include <setjmp.h>
33 #include <string.h>
34 
35 #include <rpc/types.h>
36 #include <rpc/xdr.h>
37 #include <rpc/auth.h>
38 #include <rpc/clnt.h>
39 #include <rpc/rpc_msg.h>
40 #include "snoop.h"
41 #include "snoop_nfs.h"
42 
43 #include <sys/stat.h>
44 #include <sys/param.h>
45 #include <rpcsvc/nfs_prot.h>
46 
47 #ifndef MIN
48 #define	MIN(a, b)	((a) < (b) ? (a) : (b))
49 #endif
50 
51 extern jmp_buf xdr_err;
52 
53 static void nfscall3(int);
54 static void nfsreply3(int);
55 static char *perms(int);
56 static char *filetype(int);
57 static char *sum_access(void);
58 static char *sum_readdirres(void);
59 static char *sum_readdirplusres(void);
60 static char *sum_createhow(void);
61 static char *sum_stablehow(void);
62 static void detail_sattr3(void);
63 static void detail_diropargs3(void);
64 static void detail_readdirres(void);
65 static void detail_readdirplusres(void);
66 static void detail_fattr3(void);
67 static void detail_access(void);
68 static void detail_mode(int);
69 static void detail_wcc_attr(void);
70 static void detail_pre_op_attr(char *);
71 static void detail_wcc_data(char *);
72 static void skip_postop(void);
73 static void skip_wcc_data(void);
74 static void skip_sattr3(void);
75 
76 #define	DONT_CHANGE		0
77 #define	SET_TO_SERVER_TIME	1
78 #define	SET_TO_CLIENT_TIME	2
79 
80 #define	UNCHECKED	0
81 #define	GUARDED		1
82 #define	EXCLUSIVE	2
83 
84 #define	ACCESS3_READ	0x0001
85 #define	ACCESS3_LOOKUP	0x0002
86 #define	ACCESS3_MODIFY	0x0004
87 #define	ACCESS3_EXTEND	0x0008
88 #define	ACCESS3_DELETE	0x0010
89 #define	ACCESS3_EXECUTE	0x0020
90 
91 #define	UNSTABLE	0
92 #define	DATA_SYNC	1
93 #define	FILE_SYNC	2
94 
95 #define	NF3REG		1	/* regular file */
96 #define	NF3DIR		2	/* directory */
97 #define	NF3BLK		3	/* block special */
98 #define	NF3CHR		4	/* character special */
99 #define	NF3LNK		5	/* symbolic link */
100 #define	NF3SOCK		6	/* unix domain socket */
101 #define	NF3FIFO		7	/* named pipe */
102 
103 #define	NFS3_FHSIZE	64
104 
105 static char *procnames_short[] = {
106 	"NULL3",	/*  0 */
107 	"GETATTR3",	/*  1 */
108 	"SETATTR3",	/*  2 */
109 	"LOOKUP3",	/*  3 */
110 	"ACCESS3",	/*  4 */
111 	"READLINK3",	/*  5 */
112 	"READ3",	/*  6 */
113 	"WRITE3",	/*  7 */
114 	"CREATE3",	/*  8 */
115 	"MKDIR3",	/*  9 */
116 	"SYMLINK3",	/* 10 */
117 	"MKNOD3",	/* 11 */
118 	"REMOVE3",	/* 12 */
119 	"RMDIR3",	/* 13 */
120 	"RENAME3",	/* 14 */
121 	"LINK3",	/* 15 */
122 	"READDIR3",	/* 16 */
123 	"READDIRPLUS3",	/* 17 */
124 	"FSSTAT3",	/* 18 */
125 	"FSINFO3",	/* 19 */
126 	"PATHCONF3",	/* 20 */
127 	"COMMIT3",	/* 21 */
128 };
129 
130 static char *procnames_long[] = {
131 	"Null procedure",		/*  0 */
132 	"Get file attributes",		/*  1 */
133 	"Set file attributes",		/*  2 */
134 	"Look up file name",		/*  3 */
135 	"Check access permission",	/*  4 */
136 	"Read from symbolic link",	/*  5 */
137 	"Read from file",		/*  6 */
138 	"Write to file",		/*  7 */
139 	"Create file",			/*  8 */
140 	"Make directory",		/*  9 */
141 	"Make symbolic link",		/* 10 */
142 	"Make special file",		/* 11 */
143 	"Remove file",			/* 12 */
144 	"Remove directory",		/* 13 */
145 	"Rename",			/* 14 */
146 	"Link",				/* 15 */
147 	"Read from directory",		/* 16 */
148 	"Read from directory - plus",	/* 17 */
149 	"Get filesystem statistics",	/* 18 */
150 	"Get filesystem information",	/* 19 */
151 	"Get POSIX information",	/* 20 */
152 	"Commit to stable storage",	/* 21 */
153 };
154 
155 #define	MAXPROC	21
156 
157 void
158 interpret_nfs3(flags, type, xid, vers, proc, data, len)
159 	int flags, type, xid, vers, proc;
160 	char *data;
161 	int len;
162 {
163 	char *line;
164 	char buff[NFS_MAXPATHLEN + 1];	/* protocol allows longer */
165 	u_longlong_t off;
166 	int sz, how;
167 	char *fh, *name;
168 
169 	if (proc < 0 || proc > MAXPROC)
170 		return;
171 
172 	if (flags & F_SUM) {
173 		line = get_sum_line();
174 
175 		if (type == CALL) {
176 			(void) sprintf(line, "NFS C %s",
177 				procnames_short[proc]);
178 			line += strlen(line);
179 			switch (proc) {
180 			case NFSPROC3_GETATTR:
181 			case NFSPROC3_READLINK:
182 			case NFSPROC3_FSSTAT:
183 			case NFSPROC3_FSINFO:
184 			case NFSPROC3_PATHCONF:
185 				(void) sprintf(line, sum_nfsfh3());
186 				break;
187 			case NFSPROC3_SETATTR:
188 				(void) sprintf(line, sum_nfsfh3());
189 				break;
190 			case NFSPROC3_READDIR:
191 				fh = sum_nfsfh3();
192 				off = getxdr_u_longlong();
193 				(void) getxdr_u_longlong();
194 				sz = getxdr_u_long();
195 				(void) sprintf(line, "%s Cookie=%llu for %lu",
196 					fh, off, sz);
197 				break;
198 			case NFSPROC3_READDIRPLUS:
199 				fh = sum_nfsfh3();
200 				off = getxdr_u_longlong();
201 				(void) getxdr_u_longlong();
202 				sz = getxdr_u_long();
203 				(void) sprintf(line,
204 						"%s Cookie=%llu for %lu/%lu",
205 						fh, off, sz, getxdr_u_long());
206 				break;
207 			case NFSPROC3_ACCESS:
208 				fh = sum_nfsfh3();
209 				(void) sprintf(line, "%s (%s)",
210 					fh, sum_access());
211 				break;
212 			case NFSPROC3_LOOKUP:
213 			case NFSPROC3_REMOVE:
214 			case NFSPROC3_RMDIR:
215 			case NFSPROC3_MKDIR:
216 				fh = sum_nfsfh3();
217 				(void) sprintf(line, "%s %s",
218 					fh, getxdr_string(buff,
219 						NFS_MAXPATHLEN));
220 				break;
221 			case NFSPROC3_CREATE:
222 				fh = sum_nfsfh3();
223 				name = getxdr_string(buff, NFS_MAXPATHLEN);
224 				(void) sprintf(line, "%s (%s) %s",
225 					fh, sum_createhow(), name);
226 				break;
227 			case NFSPROC3_MKNOD:
228 				fh = sum_nfsfh3();
229 				name = getxdr_string(buff, NFS_MAXPATHLEN);
230 				how = getxdr_long();
231 				(void) sprintf(line, "%s (%s) %s",
232 					fh, filetype(how), name);
233 				break;
234 			case NFSPROC3_READ:
235 				fh = sum_nfsfh3();
236 				off = getxdr_u_longlong();
237 				sz = getxdr_u_long();
238 				(void) sprintf(line, "%s at %llu for %lu",
239 					fh, off, sz);
240 				break;
241 			case NFSPROC3_WRITE:
242 				fh = sum_nfsfh3();
243 				off = getxdr_u_longlong();
244 				sz = getxdr_u_long();
245 				(void) sprintf(line, "%s at %llu for %lu (%s)",
246 					fh, off, sz, sum_stablehow());
247 				break;
248 			case NFSPROC3_SYMLINK:
249 				fh = sum_nfsfh3();
250 				(void) sprintf(line, "%s %s",
251 					fh, getxdr_string(buff,
252 						NFS_MAXPATHLEN));
253 				skip_sattr3();
254 				line += strlen(line);
255 				(void) sprintf(line, " to %s",
256 					getxdr_string(buff, NFS_MAXPATHLEN));
257 				break;
258 			case NFSPROC3_RENAME:
259 				fh = sum_nfsfh3();
260 				(void) sprintf(line, "%s %s",
261 					fh, getxdr_string(buff,
262 						NFS_MAXPATHLEN));
263 				line += strlen(line);
264 				fh = sum_nfsfh3();
265 				(void) sprintf(line, " to%s %s",
266 					fh, getxdr_string(buff,
267 						NFS_MAXPATHLEN));
268 				break;
269 			case NFSPROC3_LINK:
270 				fh = sum_nfsfh3();
271 				(void) sprintf(line, "%s", fh);
272 				line += strlen(line);
273 				fh = sum_nfsfh3();
274 				(void) sprintf(line, " to%s %s",
275 					fh, getxdr_string(buff,
276 						NFS_MAXPATHLEN));
277 				break;
278 			case NFSPROC3_COMMIT:
279 				fh = sum_nfsfh3();
280 				off = getxdr_u_longlong();
281 				sz  = getxdr_u_long();
282 				(void) sprintf(line, "%s at %llu for %lu",
283 					fh, off, sz);
284 				break;
285 			default:
286 				break;
287 			}
288 
289 			check_retransmit(line, xid);
290 		} else {
291 			(void) sprintf(line, "NFS R %s ",
292 				procnames_short[proc]);
293 			line += strlen(line);
294 			switch (proc) {
295 			case NFSPROC3_LOOKUP:
296 				if (sum_nfsstat3(line) == NFS3_OK)
297 					(void) strcat(line, sum_nfsfh3());
298 				break;
299 			case NFSPROC3_CREATE:
300 			case NFSPROC3_MKDIR:
301 			case NFSPROC3_SYMLINK:
302 			case NFSPROC3_MKNOD:
303 				if (sum_nfsstat3(line) == NFS3_OK) {
304 					if (getxdr_bool())
305 						(void) strcat(line,
306 							    sum_nfsfh3());
307 				}
308 				break;
309 			case NFSPROC3_READLINK:
310 				if (sum_nfsstat3(line) == NFS3_OK) {
311 					line += strlen(line);
312 					skip_postop();
313 					(void) sprintf(line, " (Path=%s)",
314 						getxdr_string(buff,
315 						    NFS_MAXPATHLEN));
316 				}
317 				break;
318 			case NFSPROC3_GETATTR:
319 			case NFSPROC3_SETATTR:
320 			case NFSPROC3_REMOVE:
321 			case NFSPROC3_RMDIR:
322 			case NFSPROC3_RENAME:
323 			case NFSPROC3_LINK:
324 			case NFSPROC3_FSSTAT:
325 			case NFSPROC3_FSINFO:
326 			case NFSPROC3_PATHCONF:
327 				(void) sum_nfsstat3(line);
328 				break;
329 			case NFSPROC3_ACCESS:
330 				if (sum_nfsstat3(line) == NFS3_OK) {
331 					line += strlen(line);
332 					skip_postop();
333 					(void) sprintf(line, " (%s)",
334 						sum_access());
335 				}
336 				break;
337 			case NFSPROC3_WRITE:
338 				if (sum_nfsstat3(line) == NFS3_OK) {
339 					line += strlen(line);
340 					skip_wcc_data();
341 					sz = getxdr_u_long();
342 					(void) sprintf(line, " %d (%s)",
343 						sz, sum_stablehow());
344 				}
345 				break;
346 			case NFSPROC3_READDIR:
347 				if (sum_nfsstat3(line) == NFS3_OK)
348 					(void) strcat(line, sum_readdirres());
349 				break;
350 			case NFSPROC3_READ:
351 				if (sum_nfsstat3(line) == NFS3_OK) {
352 					line += strlen(line);
353 					skip_postop();
354 					(void) sprintf(line, " (%lu bytes)",
355 						getxdr_u_long());
356 					if (getxdr_bool())
357 						(void) strcat(line, " EOF");
358 				}
359 				break;
360 			case NFSPROC3_READDIRPLUS:
361 				if (sum_nfsstat3(line) == NFS3_OK)
362 					(void) strcat(line,
363 						    sum_readdirplusres());
364 				break;
365 			case NFSPROC3_COMMIT:
366 				(void) sum_nfsstat3(line);
367 				break;
368 			default:
369 				break;
370 			}
371 		}
372 	}
373 
374 	if (flags & F_DTAIL) {
375 		show_header("NFS:  ", "Sun NFS", len);
376 		show_space();
377 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
378 			proc, procnames_long[proc]);
379 		if (type == CALL)
380 			nfscall3(proc);
381 		else
382 			nfsreply3(proc);
383 		show_trailer();
384 	}
385 }
386 
387 /*
388  *  Print out version 3 NFS call packets
389  */
390 static void
391 nfscall3(proc)
392 	int proc;
393 {
394 	int h;
395 
396 	switch (proc) {
397 	case NFSPROC3_GETATTR:
398 	case NFSPROC3_READLINK:
399 	case NFSPROC3_FSINFO:
400 	case NFSPROC3_FSSTAT:
401 	case NFSPROC3_PATHCONF:
402 		detail_nfsfh3();
403 		break;
404 	case NFSPROC3_SETATTR:
405 		detail_nfsfh3();
406 		detail_sattr3();
407 		if (getxdr_bool())
408 			(void) showxdr_date_ns("Guard = %s");
409 		break;
410 	case NFSPROC3_LOOKUP:
411 	case NFSPROC3_REMOVE:
412 	case NFSPROC3_RMDIR:
413 		detail_diropargs3();
414 		break;
415 	case NFSPROC3_ACCESS:
416 		detail_nfsfh3();
417 		detail_access();
418 		break;
419 	case NFSPROC3_MKDIR:
420 		detail_diropargs3();
421 		detail_sattr3();
422 		break;
423 	case NFSPROC3_CREATE:
424 		detail_diropargs3();
425 		h = getxdr_u_long();
426 		if (h == EXCLUSIVE)
427 			showxdr_hex(8, "Guard = %s");
428 		else {
429 			(void) sprintf(get_line(0, 0), "Method = %s",
430 			h == UNCHECKED ? "Unchecked" : "Guarded");
431 			detail_sattr3();
432 		}
433 		break;
434 	case NFSPROC3_MKNOD:
435 		detail_diropargs3();
436 		h = getxdr_u_long();
437 		(void) sprintf(get_line(0, 0), "File type = %s",
438 			filetype(h));
439 		switch (h) {
440 		case NF3CHR:
441 		case NF3BLK:
442 			detail_sattr3();
443 			showxdr_u_long("Major = %lu");
444 			showxdr_u_long("Minor = %lu");
445 			break;
446 		case NF3SOCK:
447 		case NF3FIFO:
448 			detail_sattr3();
449 			break;
450 		}
451 		break;
452 	case NFSPROC3_WRITE:
453 		detail_nfsfh3();
454 		(void) showxdr_u_longlong("Offset = %llu");
455 		(void) showxdr_u_long("Size   = %lu");
456 		(void) sprintf(get_line(0, 0), "Stable = %s",
457 				sum_stablehow());
458 		break;
459 	case NFSPROC3_RENAME:
460 		detail_diropargs3();
461 		detail_diropargs3();
462 		break;
463 	case NFSPROC3_LINK:
464 		detail_nfsfh3();
465 		detail_diropargs3();
466 		break;
467 	case NFSPROC3_SYMLINK:
468 		detail_diropargs3();
469 		detail_sattr3();
470 		(void) showxdr_string(MAXPATHLEN, "Path = %s");
471 		break;
472 	case NFSPROC3_READDIR:
473 		detail_nfsfh3();
474 		(void) showxdr_u_longlong("Cookie   = %llu");
475 		(void) showxdr_hex(8, "Verifier = %s");
476 		(void) showxdr_u_long("Count = %lu");
477 		break;
478 	case NFSPROC3_READDIRPLUS:
479 		detail_nfsfh3();
480 		(void) showxdr_u_longlong("Cookie   = %llu");
481 		(void) showxdr_hex(8, "Verifier = %s");
482 		(void) showxdr_u_long("Dircount = %lu");
483 		(void) showxdr_u_long("Maxcount = %lu");
484 		break;
485 	case NFSPROC3_READ:
486 	case NFSPROC3_COMMIT:
487 		detail_nfsfh3();
488 		(void) showxdr_u_longlong("Offset = %llu");
489 		(void) showxdr_long("Count = %lu");
490 		break;
491 	default:
492 		break;
493 	}
494 }
495 
496 /*
497  *  Print out version 3 NFS reply packets
498  */
499 static void
500 nfsreply3(proc)
501 	int proc;
502 {
503 	int bits;
504 
505 	switch (proc) {
506 	case NFSPROC3_GETATTR:
507 		if (detail_nfsstat3() == NFS3_OK) {
508 			detail_fattr3();
509 		}
510 		break;
511 	case NFSPROC3_SETATTR:
512 		(void) detail_nfsstat3();
513 		detail_wcc_data("");
514 		break;
515 	case NFSPROC3_WRITE:
516 		if (detail_nfsstat3() == NFS3_OK) {
517 			detail_wcc_data("");
518 			(void) showxdr_u_long("Count = %lu bytes written");
519 			(void) sprintf(get_line(0, 0), "Stable = %s",
520 					sum_stablehow());
521 			(void) showxdr_hex(8, "Verifier = %s");
522 		} else
523 			detail_wcc_data("");
524 		break;
525 	case NFSPROC3_LOOKUP:
526 		if (detail_nfsstat3() == NFS3_OK) {
527 			detail_nfsfh3();
528 			detail_post_op_attr("(object)");
529 		}
530 		detail_post_op_attr("(directory)");
531 		break;
532 	case NFSPROC3_CREATE:
533 	case NFSPROC3_MKDIR:
534 	case NFSPROC3_SYMLINK:
535 	case NFSPROC3_MKNOD:
536 		if (detail_nfsstat3() == NFS3_OK) {
537 			if (getxdr_bool())
538 				detail_nfsfh3();
539 			else
540 				(void) sprintf(get_line(0, 0),
541 						"(No file handle available)");
542 			detail_post_op_attr("");
543 		}
544 		detail_wcc_data("");
545 		break;
546 	case NFSPROC3_READLINK:
547 		if (detail_nfsstat3() == NFS3_OK) {
548 			detail_post_op_attr("");
549 			(void) showxdr_string(MAXPATHLEN, "Path = %s");
550 		} else
551 			detail_post_op_attr("");
552 		break;
553 	case NFSPROC3_READ:
554 		if (detail_nfsstat3() == NFS3_OK) {
555 			detail_post_op_attr("");
556 			(void) showxdr_u_long("Count = %lu bytes read");
557 			(void) showxdr_bool("End of file = %s");
558 		} else
559 			detail_post_op_attr("");
560 		break;
561 	case NFSPROC3_ACCESS:
562 		if (detail_nfsstat3() == NFS3_OK) {
563 			detail_post_op_attr("");
564 			(void) sprintf(get_line(0, 0), "Access = %s",
565 					sum_access());
566 		} else
567 			detail_post_op_attr("");
568 		break;
569 	case NFSPROC3_REMOVE:
570 	case NFSPROC3_RMDIR:
571 		(void) detail_nfsstat3();
572 		detail_wcc_data("");
573 		break;
574 	case NFSPROC3_RENAME:
575 		(void) detail_nfsstat3();
576 		detail_wcc_data("(from directory)");
577 		detail_wcc_data("(to directory)");
578 		break;
579 	case NFSPROC3_LINK:
580 		(void) detail_nfsstat3();
581 		detail_post_op_attr("");
582 		detail_wcc_data("");
583 		break;
584 	case NFSPROC3_READDIR:
585 		if (detail_nfsstat3() == NFS3_OK) {
586 			detail_readdirres();
587 		} else
588 			detail_post_op_attr("");
589 		break;
590 	case NFSPROC3_READDIRPLUS:
591 		if (detail_nfsstat3() == NFS3_OK) {
592 			detail_readdirplusres();
593 		} else
594 			detail_post_op_attr("");
595 		break;
596 	case NFSPROC3_FSSTAT:
597 		if (detail_nfsstat3() == NFS3_OK) {
598 			detail_post_op_attr("");
599 			(void) showxdr_u_longlong(
600 				"Total space = %llu bytes");
601 			(void) showxdr_u_longlong(
602 				"Available space = %llu bytes");
603 			(void) showxdr_u_longlong(
604 				"Available space - this user = %llu bytes");
605 			(void) showxdr_u_longlong(
606 				"Total file slots = %llu");
607 			(void) showxdr_u_longlong(
608 				"Available file slots = %llu");
609 			(void) showxdr_u_longlong(
610 				"Available file slots - this user = %llu");
611 			(void) showxdr_u_long("Invariant time = %lu sec");
612 		} else
613 			detail_post_op_attr("");
614 		break;
615 	case NFSPROC3_FSINFO:
616 		if (detail_nfsstat3() == NFS3_OK) {
617 			detail_post_op_attr("");
618 			(void) show_line("Read transfer sizes:");
619 			(void) showxdr_u_long("   Maximum = %lu bytes");
620 			(void) showxdr_u_long("   Preferred = %lu bytes");
621 			(void) showxdr_u_long(
622 			    "   Suggested multiple = %lu bytes");
623 			(void) show_line("Write transfer sizes:");
624 			(void) showxdr_u_long("   Maximum = %lu bytes");
625 			(void) showxdr_u_long("   Preferred = %lu bytes");
626 			(void) showxdr_u_long(
627 			    "   Suggested multiple = %lu bytes");
628 			(void) show_line("Directory read size:");
629 			(void) showxdr_u_long("   Preferred = %lu bytes");
630 			(void) show_line("File system limits:");
631 			(void) showxdr_u_longlong(
632 			    "   Max file size = %llu bytes");
633 			(void) showxdr_date_ns(
634 			    "   Server minimum time discrimination = %s sec");
635 			bits = showxdr_u_long("Properties = 0x%02x");
636 			(void) sprintf(get_line(0, 0), "	%s",
637 				getflag(bits, FSF3_LINK,
638 				"Hard links supported",
639 				"(hard links not supported)"));
640 			(void) sprintf(get_line(0, 0), "	%s",
641 				getflag(bits, FSF3_SYMLINK,
642 				"Symbolic links supported",
643 				"(symbolic links not supported)"));
644 			(void) sprintf(get_line(0, 0), "	%s",
645 				getflag(bits, FSF3_HOMOGENEOUS,
646 				"Pathconf cannot vary per file",
647 				"(pathconf can vary per file)"));
648 			(void) sprintf(get_line(0, 0), "	%s",
649 				getflag(bits, FSF3_CANSETTIME,
650 				"Server can always set file times",
651 				"(server cannot always set file times)"));
652 		} else
653 			detail_post_op_attr("");
654 		break;
655 	case NFSPROC3_PATHCONF:
656 		if (detail_nfsstat3() == NFS3_OK) {
657 			detail_post_op_attr("");
658 			(void) showxdr_u_long("Link max = %lu");
659 			(void) showxdr_u_long("Name max = %lu");
660 			(void) showxdr_bool("No trunc         = %s");
661 			(void) showxdr_bool("Chown restricted = %s");
662 			(void) showxdr_bool("Case insensitive = %s");
663 			(void) showxdr_bool("Case preserving  = %s");
664 		} else
665 			detail_post_op_attr("");
666 		break;
667 	case NFSPROC3_COMMIT:
668 		if (detail_nfsstat3() == NFS3_OK) {
669 			detail_wcc_data("");
670 			(void) showxdr_hex(8, "Verifier = %s");
671 		} else
672 			detail_wcc_data("");
673 		break;
674 	default:
675 		break;
676 	}
677 }
678 
679 static void
680 detail_diropargs3()
681 {
682 
683 	detail_nfsfh3();
684 	(void) showxdr_string(MAXPATHLEN, "File name = %s");
685 }
686 
687 int
688 sum_nfsstat3(line)
689 	char *line;
690 {
691 	ulong_t status;
692 	char *p;
693 
694 	status = getxdr_long();
695 	switch (status) {
696 	case NFS3_OK:		p = "OK"; break;
697 	case NFS3ERR_PERM:	p = "Not owner"; break;
698 	case NFS3ERR_NOENT:	p = "No such file or directory"; break;
699 	case NFS3ERR_IO:	p = "I/O error"; break;
700 	case NFS3ERR_NXIO:	p = "No such device or address"; break;
701 	case NFS3ERR_ACCES:	p = "Permission denied"; break;
702 	case NFS3ERR_EXIST:	p = "File exists"; break;
703 	case NFS3ERR_XDEV:	p = "Attempted cross-device link"; break;
704 	case NFS3ERR_NODEV:	p = "No such device"; break;
705 	case NFS3ERR_NOTDIR:	p = "Not a directory"; break;
706 	case NFS3ERR_ISDIR:	p = "Is a directory"; break;
707 	case NFS3ERR_INVAL:	p = "Invalid argument"; break;
708 	case NFS3ERR_FBIG:	p = "File too large"; break;
709 	case NFS3ERR_NOSPC:	p = "No space left on device"; break;
710 	case NFS3ERR_ROFS:	p = "Read-only file system"; break;
711 	case NFS3ERR_MLINK:	p = "Too many links"; break;
712 	case NFS3ERR_NAMETOOLONG:p = "File name too long"; break;
713 	case NFS3ERR_NOTEMPTY:	p = "Directory not empty"; break;
714 	case NFS3ERR_DQUOT:	p = "Disc quota exceeded"; break;
715 	case NFS3ERR_STALE:	p = "Stale NFS file handle"; break;
716 	case NFS3ERR_REMOTE:	p = "Too many levels of remote in path"; break;
717 	case NFS3ERR_BADHANDLE:	p = "Illegal NFS file handle"; break;
718 	case NFS3ERR_NOT_SYNC:	p = "Update synch mismatch"; break;
719 	case NFS3ERR_BAD_COOKIE:p = "Readdir cookie is stale"; break;
720 	case NFS3ERR_NOTSUPP:	p = "Operation not supported"; break;
721 	case NFS3ERR_TOOSMALL:	p = "Buffer/request too small"; break;
722 	case NFS3ERR_SERVERFAULT:p = "Server fault"; break;
723 	case NFS3ERR_BADTYPE:	p = "Bad type"; break;
724 	case NFS3ERR_JUKEBOX:	p = "File is temporarily unavailable"; break;
725 	default:		p = "(unknown error)"; break;
726 	}
727 
728 	(void) strcpy(line, p);
729 	return (status);
730 }
731 
732 int
733 detail_nfsstat3()
734 {
735 	ulong_t status;
736 	char buff[64];
737 	int pos;
738 
739 	pos = getxdr_pos();
740 	status = sum_nfsstat3(buff);
741 
742 	(void) sprintf(get_line(pos, getxdr_pos()), "Status = %d (%s)",
743 		status, buff);
744 
745 	return ((int)status);
746 }
747 
748 static void
749 skip_postop()
750 {
751 
752 	if (getxdr_bool())
753 		xdr_skip(21 * 4);	/* XDR size of fattr3 */
754 }
755 
756 static void
757 skip_wcc_data()
758 {
759 
760 	if (getxdr_bool() > 0)
761 		xdr_skip(3 * 8);
762 	skip_postop();
763 }
764 
765 static void
766 skip_sattr3()
767 {
768 
769 	if (getxdr_bool() > 0)
770 		xdr_skip(4);		/* mode */
771 	if (getxdr_bool() > 0)
772 		xdr_skip(4);		/* uid */
773 	if (getxdr_bool() > 0)
774 		xdr_skip(4);		/* gid */
775 	if (getxdr_bool() > 0)
776 		xdr_skip(8);		/* size */
777 	if (getxdr_bool() > 0)
778 		xdr_skip(8);		/* atime */
779 	if (getxdr_bool() > 0)
780 		xdr_skip(8);		/* mtime */
781 }
782 
783 char *
784 sum_nfsfh3()
785 {
786 	int len;
787 	int fh;
788 	static char buff[16];
789 
790 	len = getxdr_long();
791 	fh = sum_filehandle(len);
792 	(void) sprintf(buff, " FH=%04X", fh & 0xFFFF);
793 	return (buff);
794 }
795 
796 void
797 detail_nfsfh3()
798 {
799 	int pos;
800 	int i, l, len;
801 	int fh;
802 
803 	len = getxdr_long();
804 	pos = getxdr_pos();
805 	fh = sum_filehandle(len);
806 	setxdr_pos(pos);
807 	(void) sprintf(get_line(0, 0), "File handle = [%04X]", fh & 0xFFFF);
808 	i = 0;
809 	while (i < len) {
810 		l = MIN(len - i, 32);
811 		(void) showxdr_hex(l, " %s");
812 		i += l;
813 	}
814 }
815 
816 static char *
817 sum_access()
818 {
819 	int bits;
820 	static char buff[64];
821 
822 	bits = getxdr_u_long();
823 	buff[0] = '\0';
824 
825 	if (bits & ACCESS3_READ)
826 		(void) strcat(buff, "read,");
827 	if (bits & ACCESS3_LOOKUP)
828 		(void) strcat(buff, "lookup,");
829 	if (bits & ACCESS3_MODIFY)
830 		(void) strcat(buff, "modify,");
831 	if (bits & ACCESS3_EXTEND)
832 		(void) strcat(buff, "extend,");
833 	if (bits & ACCESS3_DELETE)
834 		(void) strcat(buff, "delete,");
835 	if (bits & ACCESS3_EXECUTE)
836 		(void) strcat(buff, "execute,");
837 	if (buff[0] != '\0')
838 		buff[strlen(buff) - 1] = '\0';
839 
840 	return (buff);
841 }
842 
843 static void
844 detail_access()
845 {
846 	uint_t bits;
847 
848 	bits = showxdr_u_long("Access bits = 0x%08x");
849 	(void) sprintf(get_line(0, 0), "	%s",
850 		getflag(bits, ACCESS3_READ, "Read", "(no read)"));
851 	(void) sprintf(get_line(0, 0), "	%s",
852 		getflag(bits, ACCESS3_LOOKUP, "Lookup", "(no lookup)"));
853 	(void) sprintf(get_line(0, 0), "	%s",
854 		getflag(bits, ACCESS3_MODIFY, "Modify", "(no modify)"));
855 	(void) sprintf(get_line(0, 0), "	%s",
856 		getflag(bits, ACCESS3_EXTEND, "Extend", "(no extend)"));
857 	(void) sprintf(get_line(0, 0), "	%s",
858 		getflag(bits, ACCESS3_DELETE, "Delete", "(no delete)"));
859 	(void) sprintf(get_line(0, 0), "	%s",
860 		getflag(bits, ACCESS3_EXECUTE, "Execute", "(no execute)"));
861 }
862 
863 static void
864 detail_mode(mode)
865 	int mode;
866 {
867 
868 	(void) sprintf(get_line(0, 0), "  Mode = 0%o", mode);
869 	(void) sprintf(get_line(0, 0),
870 		"   Setuid = %d, Setgid = %d, Sticky = %d",
871 		(mode & S_ISUID) != 0,
872 		(mode & S_ISGID) != 0,
873 		(mode & S_ISVTX) != 0);
874 	(void) sprintf(get_line(0, 0), "   Owner's permissions = %s",
875 		perms(mode >> 6 & 0x7));
876 	(void) sprintf(get_line(0, 0), "   Group's permissions = %s",
877 		perms(mode >> 3 & 0x7));
878 	(void) sprintf(get_line(0, 0), "   Other's permissions = %s",
879 		perms(mode & 0x7));
880 }
881 
882 static void
883 detail_fattr3()
884 {
885 	uint_t fltype, mode, nlinks, uid, gid;
886 	uint_t major, minor;
887 	u_longlong_t size, used, fsid, fileid;
888 
889 	fltype  = getxdr_u_long();
890 	mode	= getxdr_u_long();
891 	nlinks	= getxdr_u_long();
892 	uid	= getxdr_u_long();
893 	gid	= getxdr_u_long();
894 	size	= getxdr_u_longlong();
895 	used 	= getxdr_u_longlong();
896 	major	= getxdr_u_long();
897 	minor	= getxdr_u_long();
898 	fsid	= getxdr_u_longlong();
899 	fileid	= getxdr_u_longlong();
900 
901 	(void) sprintf(get_line(0, 0),
902 		"  File type = %d (%s)",
903 		fltype, filetype(fltype));
904 	detail_mode(mode);
905 	(void) sprintf(get_line(0, 0),
906 		"  Link count = %u, User ID = %u, Group ID = %u",
907 		nlinks, uid, gid);
908 	(void) sprintf(get_line(0, 0),
909 		"  File size = %llu, Used = %llu",
910 		size, used);
911 	(void) sprintf(get_line(0, 0),
912 		"  Special: Major = %u, Minor = %u",
913 		major, minor);
914 	(void) sprintf(get_line(0, 0),
915 		"  File system id = %llu, File id = %llu",
916 		fsid, fileid);
917 	(void) showxdr_date_ns("  Last access time      = %s");
918 	(void) showxdr_date_ns("  Modification time     = %s");
919 	(void) showxdr_date_ns("  Attribute change time = %s");
920 	(void) show_line("");
921 }
922 
923 static void
924 detail_sattr3()
925 {
926 	int t;
927 
928 	if (getxdr_bool())
929 		detail_mode(getxdr_u_long());
930 	else
931 		(void) sprintf(get_line(0, 0), "Mode = (not set)");
932 	if (getxdr_bool())
933 		(void) showxdr_long("User ID = %d");
934 	else
935 		(void) sprintf(get_line(0, 0), "User ID = (not set)");
936 	if (getxdr_bool())
937 		(void) showxdr_long("Group ID = %d");
938 	else
939 		(void) sprintf(get_line(0, 0), "Group ID = (not set)");
940 	if (getxdr_bool())
941 		(void) showxdr_u_longlong("Size = %llu");
942 	else
943 		(void) sprintf(get_line(0, 0), "Size = (not set)");
944 
945 	if ((t = getxdr_u_long()) == SET_TO_CLIENT_TIME)
946 		(void) showxdr_date("Access time = %s (set to client time)");
947 	else if (t == SET_TO_SERVER_TIME)
948 		(void) sprintf(get_line(0, 0),
949 				"Access time = (set to server time)");
950 	else
951 		(void) sprintf(get_line(0, 0), "Access time = (do not set)");
952 
953 	if ((t = getxdr_u_long()) == SET_TO_CLIENT_TIME) {
954 		(void) showxdr_date(
955 				"Modification time = %s (set to client time)");
956 	} else if (t == SET_TO_SERVER_TIME)
957 		(void) sprintf(get_line(0, 0),
958 				"Modification time = (set to server time)");
959 	else
960 		(void) sprintf(get_line(0, 0),
961 				"Modification time = (do not set)");
962 	(void) show_line("");
963 }
964 
965 static char *
966 filetype(n)
967 	int n;
968 {
969 
970 	switch (n) {
971 	case NF3REG:
972 		return ("Regular File");
973 	case NF3DIR:
974 		return ("Directory");
975 	case NF3BLK:
976 		return ("Block special");
977 	case NF3CHR:
978 		return ("Character special");
979 	case NF3LNK:
980 		return ("Symbolic Link");
981 	case NF3SOCK:
982 		return ("Unix domain socket");
983 	case NF3FIFO:
984 		return ("Named pipe");
985 	default:
986 		return ("?");
987 	}
988 	/* NOTREACHED */
989 }
990 
991 static char *
992 perms(n)
993 	int n;
994 {
995 	static char buff[4];
996 
997 	buff[0] = n & 4 ? 'r' : '-';
998 	buff[1] = n & 2 ? 'w' : '-';
999 	buff[2] = n & 1 ? 'x' : '-';
1000 	buff[3] = '\0';
1001 	return (buff);
1002 }
1003 
1004 static void
1005 detail_wcc_attr()
1006 {
1007 
1008 	(void) showxdr_u_longlong("  Size = %llu bytes");
1009 	(void) showxdr_date_ns("  Modification time      = %s");
1010 	(void) showxdr_date_ns("  Attribute change time  = %s");
1011 	(void) show_line("");
1012 }
1013 
1014 static void
1015 detail_pre_op_attr(str)
1016 	char *str;
1017 {
1018 
1019 	if (getxdr_bool()) {
1020 		(void) sprintf(get_line(0, 0),
1021 			"Pre-operation attributes: %s", str);
1022 		detail_wcc_attr();
1023 	} else
1024 		(void) sprintf(get_line(0, 0),
1025 			"Pre-operation attributes: %s (not available)", str);
1026 }
1027 
1028 void
1029 detail_post_op_attr(str)
1030 	char *str;
1031 {
1032 
1033 	if (getxdr_bool()) {
1034 		(void) sprintf(get_line(0, 0),
1035 			"Post-operation attributes: %s", str);
1036 		detail_fattr3();
1037 	} else
1038 		(void) sprintf(get_line(0, 0),
1039 			"Post-operation attributes: %s (not available)", str);
1040 }
1041 
1042 static void
1043 detail_wcc_data(str)
1044 	char *str;
1045 {
1046 
1047 	detail_pre_op_attr(str);
1048 	detail_post_op_attr(str);
1049 }
1050 
1051 static char *
1052 sum_readdirres()
1053 {
1054 	static char buff[NFS_MAXNAMLEN + 1]; /* protocol allows longer names */
1055 	static int entries;
1056 
1057 	entries = 0;
1058 	if (setjmp(xdr_err)) {
1059 		(void) sprintf(buff, " %d+ entries (incomplete)", entries);
1060 		return (buff);
1061 	}
1062 	skip_postop();
1063 	xdr_skip(8);	/* cookieverf */
1064 	while (getxdr_bool()) {
1065 		entries++;
1066 		xdr_skip(8);				/* fileid */
1067 		(void) getxdr_string(buff, NFS_MAXNAMLEN); /* name */
1068 		xdr_skip(8);				/* cookie */
1069 	}
1070 
1071 	(void) sprintf(buff, " %d entries (%s)",
1072 		entries, getxdr_bool() ? "No more" : "More");
1073 	return (buff);
1074 }
1075 
1076 static char *
1077 sum_readdirplusres()
1078 {
1079 	static char buff[NFS_MAXNAMLEN + 1]; /* protocol allows longer */
1080 	static int entries;
1081 	int skip;
1082 
1083 	entries = 0;
1084 	if (setjmp(xdr_err)) {
1085 		(void) sprintf(buff, " %d+ entries (incomplete)", entries);
1086 		return (buff);
1087 	}
1088 	skip_postop();
1089 	xdr_skip(8);	/* cookieverf */
1090 	while (getxdr_bool()) {
1091 		entries++;
1092 		xdr_skip(8);				/* fileid */
1093 		(void) getxdr_string(buff, NFS_MAXNAMLEN); /* name */
1094 		xdr_skip(8);				/* cookie */
1095 		skip_postop();				/* post-op */
1096 		if (getxdr_bool()) {
1097 			skip = getxdr_long();
1098 			xdr_skip(RNDUP(skip));		/* fhandle */
1099 		}
1100 	}
1101 
1102 	(void) sprintf(buff, " %d entries (%s)",
1103 		entries, getxdr_bool() ? "No more" : "More");
1104 	return (buff);
1105 }
1106 
1107 static void
1108 detail_readdirres()
1109 {
1110 	static int entries;
1111 	u_longlong_t fileid, cookie;
1112 	char *name;
1113 	char buff[NFS_MAXNAMLEN + 1];	/* protocol allows longer names */
1114 
1115 	entries = 0;
1116 	detail_post_op_attr("");
1117 	(void) showxdr_hex(8, "Cookie verifier = %s");
1118 	(void) show_line("");
1119 	(void) sprintf(get_line(0, 0), "   File id    Cookie   Name");
1120 
1121 	if (setjmp(xdr_err)) {
1122 		(void) sprintf(get_line(0, 0),
1123 			"  %d+ entries. (Frame is incomplete)",
1124 			entries);
1125 		return;
1126 	}
1127 	while (getxdr_bool()) {
1128 		entries++;
1129 		fileid = getxdr_u_longlong();
1130 		name = (char *)getxdr_string(buff, NFS_MAXNAMLEN);
1131 		cookie = getxdr_u_longlong();
1132 		(void) sprintf(get_line(0, 0),
1133 			" %10llu %10llu %s",
1134 			fileid, cookie, name);
1135 	}
1136 
1137 	(void) sprintf(get_line(0, 0), "  %d entries", entries);
1138 	(void) showxdr_bool("EOF = %s");
1139 }
1140 
1141 static void
1142 detail_readdirplusres()
1143 {
1144 	static int entries;
1145 
1146 	entries = 0;
1147 	detail_post_op_attr("");
1148 	(void) showxdr_hex(8, "Cookie verifier = %s");
1149 	(void) show_line("");
1150 
1151 	if (setjmp(xdr_err)) {
1152 		(void) sprintf(get_line(0, 0),
1153 			"  %d+ entries. (Frame is incomplete)",
1154 			entries);
1155 		return;
1156 	}
1157 	while (getxdr_bool()) {
1158 		entries++;
1159 		(void) sprintf(get_line(0, 0),
1160 			"------------------ entry #%d",
1161 			entries);
1162 		(void) showxdr_u_longlong("File ID = %llu");
1163 		(void) showxdr_string(NFS_MAXNAMLEN, "Name = %s");
1164 		(void) showxdr_u_longlong("Cookie = %llu");
1165 		detail_post_op_attr("");
1166 		if (getxdr_bool())
1167 			detail_nfsfh3();
1168 		else
1169 			(void) sprintf(get_line(0, 0),
1170 					"(No file handle available)");
1171 	}
1172 
1173 	(void) show_line("");
1174 	(void) sprintf(get_line(0, 0), "  %d entries", entries);
1175 	(void) showxdr_bool("EOF = %s");
1176 }
1177 
1178 static char *
1179 sum_createhow()
1180 {
1181 	long how;
1182 
1183 	how = getxdr_long();
1184 	switch (how) {
1185 	case UNCHECKED:
1186 		return ("UNCHECKED");
1187 	case GUARDED:
1188 		return ("GUARDED");
1189 	case EXCLUSIVE:
1190 		return ("EXCLUSIVE");
1191 	default:
1192 		return ("?");
1193 	}
1194 	/* NOTREACHED */
1195 }
1196 
1197 static char *
1198 sum_stablehow()
1199 {
1200 	long stable;
1201 
1202 	stable = getxdr_long();
1203 	switch (stable) {
1204 	case UNSTABLE:
1205 		return ("ASYNC");
1206 	case DATA_SYNC:
1207 		return ("DSYNC");
1208 	case FILE_SYNC:
1209 		return ("FSYNC");
1210 	default:
1211 		return ("?");
1212 	}
1213 	/* NOTREACHED */
1214 }
1215