Home | History | Annotate | Download | only in snoop
      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