Home | History | Annotate | Download | only in snoop
      1  0  stevel /*
      2  0  stevel  * CDDL HEADER START
      3  0  stevel  *
      4  0  stevel  * The contents of this file are subject to the terms of the
      5  0  stevel  * Common Development and Distribution License, Version 1.0 only
      6  0  stevel  * (the "License").  You may not use this file except in compliance
      7  0  stevel  * with the License.
      8  0  stevel  *
      9  0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  0  stevel  * or http://www.opensolaris.org/os/licensing.
     11  0  stevel  * See the License for the specific language governing permissions
     12  0  stevel  * and limitations under the License.
     13  0  stevel  *
     14  0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     15  0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     17  0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     18  0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  0  stevel  *
     20  0  stevel  * CDDL HEADER END
     21  0  stevel  */
     22  0  stevel /*
     23  0  stevel  * Copyright 1991-2003 Sun Microsystems, Inc.  All rights reserved.
     24  0  stevel  * Use is subject to license terms.
     25  0  stevel  */
     26  0  stevel 
     27  0  stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28  0  stevel 
     29  0  stevel #include <sys/types.h>
     30  0  stevel #include <sys/errno.h>
     31  0  stevel #include <sys/tiuser.h>
     32  0  stevel #include <setjmp.h>
     33  0  stevel 
     34  0  stevel #include <rpc/types.h>
     35  0  stevel #include <rpc/xdr.h>
     36  0  stevel #include <rpc/auth.h>
     37  0  stevel #include <rpc/clnt.h>
     38  0  stevel #include <rpc/rpc_msg.h>
     39  0  stevel #include <string.h>
     40  0  stevel #include "snoop.h"
     41  0  stevel #include "snoop_nfs.h"
     42  0  stevel 
     43  0  stevel #include <sys/stat.h>
     44  0  stevel #include <rpcsvc/nfs_prot.h>
     45  0  stevel 
     46  0  stevel static char *perms(int);
     47  0  stevel static char *filetype(int);
     48  0  stevel static char *sum_readdirres(void);
     49  0  stevel static void detail_readdirres(void);
     50  0  stevel static void detail_diroparg(void);
     51  0  stevel static void nfscall2(int);
     52  0  stevel static void nfsreply2(int);
     53  0  stevel static void detail_mode(int);
     54  0  stevel static void detail_sattr(void);
     55  0  stevel static void interpret_nfs2(int, int, int, int, int, char *, int);
     56  0  stevel 
     57  0  stevel extern jmp_buf xdr_err;
     58  0  stevel 
     59  0  stevel static char *procnames_short[] = {
     60  0  stevel 	"NULL2",	/*  0 */
     61  0  stevel 	"GETATTR2",	/*  1 */
     62  0  stevel 	"SETATTR2",	/*  2 */
     63  0  stevel 	"ROOT2",	/*  3 */
     64  0  stevel 	"LOOKUP2",	/*  4 */
     65  0  stevel 	"READLINK2",	/*  5 */
     66  0  stevel 	"READ2",	/*  6 */
     67  0  stevel 	"WRITECACHE2",	/*  7 */
     68  0  stevel 	"WRITE2",	/*  8 */
     69  0  stevel 	"CREATE2",	/*  9 */
     70  0  stevel 	"REMOVE2",	/* 10 */
     71  0  stevel 	"RENAME2",	/* 11 */
     72  0  stevel 	"LINK2",	/* 12 */
     73  0  stevel 	"SYMLINK2",	/* 13 */
     74  0  stevel 	"MKDIR2",	/* 14 */
     75  0  stevel 	"RMDIR2",	/* 15 */
     76  0  stevel 	"READDIR2",	/* 16 */
     77  0  stevel 	"STATFS2",	/* 17 */
     78  0  stevel };
     79  0  stevel 
     80  0  stevel static char *procnames_long[] = {
     81  0  stevel 	"Null procedure",		/*  0 */
     82  0  stevel 	"Get file attributes",		/*  1 */
     83  0  stevel 	"Set file attributes",		/*  2 */
     84  0  stevel 	"Get root filehandle",		/*  3 */
     85  0  stevel 	"Look up file name",		/*  4 */
     86  0  stevel 	"Read from symbolic link",	/*  5 */
     87  0  stevel 	"Read from file",		/*  6 */
     88  0  stevel 	"Write to cache",		/*  7 */
     89  0  stevel 	"Write to file",		/*  8 */
     90  0  stevel 	"Create file",			/*  9 */
     91  0  stevel 	"Remove file",			/* 10 */
     92  0  stevel 	"Rename",			/* 11 */
     93  0  stevel 	"Link",				/* 12 */
     94  0  stevel 	"Make symbolic link",		/* 13 */
     95  0  stevel 	"Make directory",		/* 14 */
     96  0  stevel 	"Remove directory",		/* 15 */
     97  0  stevel 	"Read from directory",		/* 16 */
     98  0  stevel 	"Get filesystem attributes",	/* 17 */
     99  0  stevel };
    100  0  stevel 
    101  0  stevel #define	MAXPROC	17
    102  0  stevel 
    103  0  stevel /* ARGSUSED */
    104  0  stevel void
    105  0  stevel interpret_nfs(flags, type, xid, vers, proc, data, len)
    106  0  stevel 	int flags, type, xid, vers, proc;
    107  0  stevel 	char *data;
    108  0  stevel 	int len;
    109  0  stevel {
    110  0  stevel 
    111  0  stevel 	if (vers == 2) {
    112  0  stevel 		interpret_nfs2(flags, type, xid, vers, proc, data, len);
    113  0  stevel 		return;
    114  0  stevel 	}
    115  0  stevel 
    116  0  stevel 	if (vers == 3) {
    117  0  stevel 		interpret_nfs3(flags, type, xid, vers, proc, data, len);
    118  0  stevel 		return;
    119  0  stevel 	}
    120  0  stevel 
    121  0  stevel 	if (vers == 4) {
    122  0  stevel 		interpret_nfs4(flags, type, xid, vers, proc, data, len);
    123  0  stevel 		return;
    124  0  stevel 	}
    125  0  stevel }
    126  0  stevel 
    127  0  stevel static void
    128  0  stevel interpret_nfs2(flags, type, xid, vers, proc, data, len)
    129  0  stevel 	int flags, type, xid, vers, proc;
    130  0  stevel 	char *data;
    131  0  stevel 	int len;
    132  0  stevel {
    133  0  stevel 	char *line;
    134  0  stevel 	char buff[NFS_MAXPATHLEN + 1];
    135  0  stevel 	int off, sz;
    136  0  stevel 	char *fh;
    137  0  stevel 
    138  0  stevel 	if (proc < 0 || proc > MAXPROC)
    139  0  stevel 		return;
    140  0  stevel 
    141  0  stevel 	if (flags & F_SUM) {
    142  0  stevel 		line = get_sum_line();
    143  0  stevel 
    144  0  stevel 		if (type == CALL) {
    145  0  stevel 			(void) sprintf(line,
    146  0  stevel 				"NFS C %s",
    147  0  stevel 				procnames_short[proc]);
    148  0  stevel 			line += strlen(line);
    149  0  stevel 			switch (proc) {
    150  0  stevel 			case NFSPROC_GETATTR:
    151  0  stevel 			case NFSPROC_READLINK:
    152  0  stevel 			case NFSPROC_STATFS:
    153  0  stevel 			case NFSPROC_SETATTR:
    154  0  stevel 				(void) sprintf(line, sum_nfsfh());
    155  0  stevel 				break;
    156  0  stevel 			case NFSPROC_LOOKUP:
    157  0  stevel 			case NFSPROC_REMOVE:
    158  0  stevel 			case NFSPROC_RMDIR:
    159  0  stevel 			case NFSPROC_CREATE:
    160  0  stevel 			case NFSPROC_MKDIR:
    161  0  stevel 				fh = sum_nfsfh();
    162  0  stevel 				(void) sprintf(line, "%s %s",
    163  0  stevel 					fh,
    164  0  stevel 					getxdr_string(buff, NFS_MAXNAMLEN));
    165  0  stevel 				break;
    166  0  stevel 			case NFSPROC_WRITE:
    167  0  stevel 				fh = sum_nfsfh();
    168  0  stevel 				(void) getxdr_long();	/* beginoff */
    169  0  stevel 				off = getxdr_long();
    170  0  stevel 				(void) getxdr_long();	/* totalcount */
    171  0  stevel 				sz  = getxdr_long();
    172  0  stevel 				(void) sprintf(line, "%s at %d for %d",
    173  0  stevel 					fh, off, sz);
    174  0  stevel 				break;
    175  0  stevel 			case NFSPROC_RENAME:
    176  0  stevel 				fh = sum_nfsfh();
    177  0  stevel 				(void) sprintf(line, "%s %s",
    178  0  stevel 					fh,
    179  0  stevel 					getxdr_string(buff, NFS_MAXNAMLEN));
    180  0  stevel 				line += strlen(line);
    181  0  stevel 				fh = sum_nfsfh();
    182  0  stevel 				(void) sprintf(line, " to%s %s",
    183  0  stevel 					fh,
    184  0  stevel 					getxdr_string(buff, NFS_MAXNAMLEN));
    185  0  stevel 				break;
    186  0  stevel 			case NFSPROC_LINK:
    187  0  stevel 				fh = sum_nfsfh();
    188  0  stevel 				(void) sprintf(line, "%s", fh);
    189  0  stevel 				line += strlen(line);
    190  0  stevel 				fh = sum_nfsfh();
    191  0  stevel 				(void) sprintf(line, " to%s %s",
    192  0  stevel 					fh,
    193  0  stevel 					getxdr_string(buff, NFS_MAXNAMLEN));
    194  0  stevel 				break;
    195  0  stevel 			case NFSPROC_SYMLINK:
    196  0  stevel 				fh = sum_nfsfh();
    197  0  stevel 				(void) sprintf(line, "%s %s",
    198  0  stevel 					fh,
    199  0  stevel 					getxdr_string(buff, NFS_MAXNAMLEN));
    200  0  stevel 				line += strlen(line);
    201  0  stevel 				(void) sprintf(line, " to %s",
    202  0  stevel 					getxdr_string(buff, NFS_MAXPATHLEN));
    203  0  stevel 				break;
    204  0  stevel 			case NFSPROC_READDIR:
    205  0  stevel 				fh = sum_nfsfh();
    206  0  stevel 				(void) sprintf(line, "%s Cookie=%lu",
    207  0  stevel 					fh, getxdr_u_long());
    208  0  stevel 				break;
    209  0  stevel 			case NFSPROC_READ:
    210  0  stevel 				fh = sum_nfsfh();
    211  0  stevel 				off = getxdr_long();
    212  0  stevel 				sz  = getxdr_long();
    213  0  stevel 				(void) sprintf(line, "%s at %d for %d",
    214  0  stevel 					fh, off, sz);
    215  0  stevel 				break;
    216  0  stevel 			default:
    217  0  stevel 				break;
    218  0  stevel 			}
    219  0  stevel 
    220  0  stevel 			check_retransmit(line, (ulong_t)xid);
    221  0  stevel 		} else {
    222  0  stevel 			(void) sprintf(line, "NFS R %s ",
    223  0  stevel 				procnames_short[proc]);
    224  0  stevel 			line += strlen(line);
    225  0  stevel 			switch (proc) {
    226  0  stevel 			case NFSPROC_CREATE:
    227  0  stevel 			case NFSPROC_MKDIR:
    228  0  stevel 			case NFSPROC_LOOKUP:
    229  0  stevel 				if (sum_nfsstat(line) == 0) {
    230  0  stevel 					line += strlen(line);
    231  0  stevel 					(void) sprintf(line, sum_nfsfh());
    232  0  stevel 				}
    233  0  stevel 				break;
    234  0  stevel 			case NFSPROC_READLINK:
    235  0  stevel 				if (sum_nfsstat(line) == 0) {
    236  0  stevel 					line += strlen(line);
    237  0  stevel 					(void) sprintf(line, " (Path=%s)",
    238  0  stevel 						getxdr_string(buff,
    239  0  stevel 							NFS_MAXPATHLEN));
    240  0  stevel 				}
    241  0  stevel 				break;
    242  0  stevel 			case NFSPROC_GETATTR:
    243  0  stevel 			case NFSPROC_SYMLINK:
    244  0  stevel 			case NFSPROC_STATFS:
    245  0  stevel 			case NFSPROC_SETATTR:
    246  0  stevel 			case NFSPROC_REMOVE:
    247  0  stevel 			case NFSPROC_RMDIR:
    248  0  stevel 			case NFSPROC_WRITE:
    249  0  stevel 			case NFSPROC_RENAME:
    250  0  stevel 			case NFSPROC_LINK:
    251  0  stevel 				(void) sum_nfsstat(line);
    252  0  stevel 				break;
    253  0  stevel 			case NFSPROC_READDIR:
    254  0  stevel 				if (sum_nfsstat(line) == 0) {
    255  0  stevel 					line += strlen(line);
    256  0  stevel 					(void) strcat(line, sum_readdirres());
    257  0  stevel 				}
    258  0  stevel 				break;
    259  0  stevel 			case NFSPROC_READ:
    260  0  stevel 				if (sum_nfsstat(line) == 0) {
    261  0  stevel 					line += strlen(line);
    262  0  stevel 					xdr_skip(68); /* fattrs */
    263  0  stevel 					(void) sprintf(line, " (%ld bytes)",
    264  0  stevel 						getxdr_long());
    265  0  stevel 				}
    266  0  stevel 				break;
    267  0  stevel 			default:
    268  0  stevel 				break;
    269  0  stevel 			}
    270  0  stevel 		}
    271  0  stevel 	}
    272  0  stevel 
    273  0  stevel 	if (flags & F_DTAIL) {
    274  0  stevel 		show_header("NFS:  ", "Sun NFS", len);
    275  0  stevel 		show_space();
    276  0  stevel 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    277  0  stevel 			proc, procnames_long[proc]);
    278  0  stevel 		if (type == CALL)
    279  0  stevel 			nfscall2(proc);
    280  0  stevel 		else
    281  0  stevel 			nfsreply2(proc);
    282  0  stevel 		show_trailer();
    283  0  stevel 	}
    284  0  stevel }
    285  0  stevel 
    286  0  stevel /*
    287  0  stevel  *  Print out version 2 NFS call packets
    288  0  stevel  */
    289  0  stevel static void
    290  0  stevel nfscall2(proc)
    291  0  stevel 	int proc;
    292  0  stevel {
    293  0  stevel 	switch (proc) {
    294  0  stevel 	case NFSPROC_GETATTR:
    295  0  stevel 	case NFSPROC_READLINK:
    296  0  stevel 	case NFSPROC_STATFS:
    297  0  stevel 		detail_nfsfh();
    298  0  stevel 		break;
    299  0  stevel 	case NFSPROC_SETATTR:
    300  0  stevel 		detail_nfsfh();
    301  0  stevel 		detail_sattr();
    302  0  stevel 		break;
    303  0  stevel 	case NFSPROC_LOOKUP:
    304  0  stevel 	case NFSPROC_REMOVE:
    305  0  stevel 	case NFSPROC_RMDIR:
    306  0  stevel 		detail_diroparg();
    307  0  stevel 		break;
    308  0  stevel 	case NFSPROC_MKDIR:
    309  0  stevel 	case NFSPROC_CREATE:
    310  0  stevel 		detail_diroparg();
    311  0  stevel 		detail_sattr();
    312  0  stevel 		break;
    313  0  stevel 	case NFSPROC_WRITE:
    314  0  stevel 		detail_nfsfh();
    315  0  stevel 		(void) getxdr_long();	/* begoff */
    316  0  stevel 		(void) showxdr_long("Offset = %d");
    317  0  stevel 		(void) getxdr_long();	/* totalcount */
    318  0  stevel 		(void) showxdr_long("(%d bytes(s) of data)");
    319  0  stevel 		break;
    320  0  stevel 	case NFSPROC_RENAME:
    321  0  stevel 		detail_diroparg();
    322  0  stevel 		detail_diroparg();
    323  0  stevel 		break;
    324  0  stevel 	case NFSPROC_LINK:
    325  0  stevel 		detail_nfsfh();
    326  0  stevel 		detail_diroparg();
    327  0  stevel 		break;
    328  0  stevel 	case NFSPROC_SYMLINK:
    329  0  stevel 		detail_diroparg();
    330  0  stevel 		(void) showxdr_string(NFS_MAXPATHLEN, "Path = %s");
    331  0  stevel 		detail_sattr();
    332  0  stevel 		break;
    333  0  stevel 	case NFSPROC_READDIR:
    334  0  stevel 		detail_nfsfh();
    335  0  stevel 		(void) showxdr_u_long("Cookie = %lu");
    336  0  stevel 		(void) showxdr_long("Count = %d");
    337  0  stevel 		break;
    338  0  stevel 	case NFSPROC_READ:
    339  0  stevel 		detail_nfsfh();
    340  0  stevel 		(void) showxdr_long("Offset = %d");
    341  0  stevel 		(void) showxdr_long("Count = %d");
    342  0  stevel 		break;
    343  0  stevel 	default:
    344  0  stevel 		break;
    345  0  stevel 	}
    346  0  stevel }
    347  0  stevel 
    348  0  stevel /*
    349  0  stevel  *  Print out version 2 NFS reply packets
    350  0  stevel  */
    351  0  stevel static void
    352  0  stevel nfsreply2(proc)
    353  0  stevel 	int proc;
    354  0  stevel {
    355  0  stevel 	switch (proc) {
    356  0  stevel 	    case NFSPROC_GETATTR:
    357  0  stevel 	    case NFSPROC_SETATTR:
    358  0  stevel 	    case NFSPROC_WRITE:
    359  0  stevel 		/* attrstat */
    360  0  stevel 		if (detail_nfsstat() == 0) {
    361  0  stevel 			detail_fattr();
    362  0  stevel 		}
    363  0  stevel 		break;
    364  0  stevel 	    case NFSPROC_LOOKUP:
    365  0  stevel 	    case NFSPROC_CREATE:
    366  0  stevel 	    case NFSPROC_MKDIR:
    367  0  stevel 		/* diropres */
    368  0  stevel 		if (detail_nfsstat() == 0) {
    369  0  stevel 			detail_nfsfh();
    370  0  stevel 			detail_fattr();
    371  0  stevel 		}
    372  0  stevel 		break;
    373  0  stevel 	    case NFSPROC_READLINK:
    374  0  stevel 		/* readlinkres */
    375  0  stevel 		if (detail_nfsstat() == 0) {
    376  0  stevel 			(void) showxdr_string(NFS_MAXPATHLEN, "Path = %s");
    377  0  stevel 		}
    378  0  stevel 		break;
    379  0  stevel 	    case NFSPROC_READ:
    380  0  stevel 		/* readres */
    381  0  stevel 		if (detail_nfsstat() == 0) {
    382  0  stevel 			detail_fattr();
    383  0  stevel 			(void) showxdr_long("(%d byte(s) of data)");
    384  0  stevel 		}
    385  0  stevel 		break;
    386  0  stevel 	    case NFSPROC_REMOVE:
    387  0  stevel 	    case NFSPROC_RENAME:
    388  0  stevel 	    case NFSPROC_LINK:
    389  0  stevel 	    case NFSPROC_SYMLINK:
    390  0  stevel 	    case NFSPROC_RMDIR:
    391  0  stevel 		/* stat */
    392  0  stevel 		detail_nfsstat();
    393  0  stevel 		break;
    394  0  stevel 	    case NFSPROC_READDIR:
    395  0  stevel 		/* readdirres */
    396  0  stevel 		if (detail_nfsstat() == 0)
    397  0  stevel 			detail_readdirres();
    398  0  stevel 		break;
    399  0  stevel 	    case NFSPROC_STATFS:
    400  0  stevel 		/* statfsres */
    401  0  stevel 		if (detail_nfsstat() == 0) {
    402  0  stevel 			(void) showxdr_long("Transfer size = %d");
    403  0  stevel 			(void) showxdr_long("Block size = %d");
    404  0  stevel 			(void) showxdr_long("Total blocks = %d");
    405  0  stevel 			(void) showxdr_long("Free blocks = %d");
    406  0  stevel 			(void) showxdr_long("Available blocks = %d");
    407  0  stevel 		}
    408  0  stevel 		break;
    409  0  stevel 	    default:
    410  0  stevel 		break;
    411  0  stevel 	}
    412  0  stevel }
    413  0  stevel 
    414  0  stevel static void
    415  0  stevel detail_diroparg()
    416  0  stevel {
    417  0  stevel 	detail_nfsfh();
    418  0  stevel 	(void) showxdr_string(NFS_MAXPATHLEN, "File name = %s");
    419  0  stevel }
    420  0  stevel 
    421  0  stevel /*
    422  0  stevel  * V2 NFS protocol was implicitly linked with SunOS errnos.
    423  0  stevel  * Some of the errno values changed in SVr4.
    424  0  stevel  * Need to map errno value so that SVr4 snoop will interpret
    425  0  stevel  * them correctly.
    426  0  stevel  */
    427  0  stevel static char *
    428  0  stevel statusmsg(status)
    429  0  stevel 	ulong_t status;
    430  0  stevel {
    431  0  stevel 	switch (status) {
    432  0  stevel 	case NFS_OK: return ("OK");
    433  0  stevel 	case NFSERR_PERM: return ("Not owner");
    434  0  stevel 	case NFSERR_NOENT: return ("No such file or directory");
    435  0  stevel 	case NFSERR_IO: return ("I/O error");
    436  0  stevel 	case NFSERR_NXIO: return ("No such device or address");
    437  0  stevel 	case NFSERR_ACCES: return ("Permission denied");
    438  0  stevel 	case NFSERR_EXIST: return ("File exists");
    439  0  stevel 	case NFSERR_XDEV: return ("Cross-device link");
    440  0  stevel 	case NFSERR_NODEV: return ("No such device");
    441  0  stevel 	case NFSERR_NOTDIR: return ("Not a directory");
    442  0  stevel 	case NFSERR_ISDIR: return ("Is a directory");
    443  0  stevel 	case NFSERR_INVAL: return ("Invalid argument");
    444  0  stevel 	case NFSERR_FBIG: return ("File too large");
    445  0  stevel 	case NFSERR_NOSPC: return ("No space left on device");
    446  0  stevel 	case NFSERR_ROFS: return ("Read-only file system");
    447  0  stevel 	case NFSERR_OPNOTSUPP: return ("Operation not supported");
    448  0  stevel 	case NFSERR_NAMETOOLONG: return ("File name too long");
    449  0  stevel 	case NFSERR_NOTEMPTY: return ("Directory not empty");
    450  0  stevel 	case NFSERR_DQUOT: return ("Disc quota exceeded");
    451  0  stevel 	case NFSERR_STALE: return ("Stale NFS file handle");
    452  0  stevel 	case NFSERR_REMOTE: return ("Object is remote");
    453  0  stevel 	case NFSERR_WFLUSH: return ("write cache flushed");
    454  0  stevel 	default: return ("(unknown error)");
    455  0  stevel 	}
    456  0  stevel 	/* NOTREACHED */
    457  0  stevel }
    458  0  stevel 
    459  0  stevel int
    460  0  stevel sum_nfsstat(line)
    461  0  stevel 	char *line;
    462  0  stevel {
    463  0  stevel 	ulong_t status;
    464  0  stevel 
    465  0  stevel 	status = getxdr_long();
    466  0  stevel 	(void) strcpy(line, statusmsg(status));
    467  0  stevel 	return (status);
    468  0  stevel }
    469  0  stevel 
    470  0  stevel int
    471  0  stevel detail_nfsstat()
    472  0  stevel {
    473  0  stevel 	ulong_t status;
    474  0  stevel 	int pos;
    475  0  stevel 
    476  0  stevel 	pos = getxdr_pos();
    477  0  stevel 	status = getxdr_long();
    478  0  stevel 	(void) sprintf(get_line(pos, getxdr_pos()),
    479  0  stevel 		"Status = %lu (%s)",
    480  0  stevel 		status, statusmsg(status));
    481  0  stevel 
    482  0  stevel 	return ((int)status);
    483  0  stevel }
    484  0  stevel 
    485  0  stevel int
    486  0  stevel sum_filehandle(len)
    487  0  stevel 	int len;
    488  0  stevel {
    489  0  stevel 	int i, l;
    490  0  stevel 	int fh = 0;
    491  0  stevel 
    492  0  stevel 	for (i = 0; i < len; i += 4) {
    493  0  stevel 		l = getxdr_long();
    494  0  stevel 		fh ^= (l >> 16) ^ l;
    495  0  stevel 	}
    496  0  stevel 
    497  0  stevel 	return (fh);
    498  0  stevel }
    499  0  stevel 
    500  0  stevel char *
    501  0  stevel sum_nfsfh()
    502  0  stevel {
    503  0  stevel 	int fh;
    504  0  stevel 	static char buff[16];
    505  0  stevel 
    506  0  stevel 	fh = sum_filehandle(NFS_FHSIZE);
    507  0  stevel 	(void) sprintf(buff, " FH=%04X", fh & 0xFFFF);
    508  0  stevel 	return (buff);
    509  0  stevel }
    510  0  stevel 
    511  0  stevel void
    512  0  stevel detail_nfsfh()
    513  0  stevel {
    514  0  stevel 	int pos;
    515  0  stevel 	int fh;
    516  0  stevel 
    517  0  stevel 	pos = getxdr_pos();
    518  0  stevel 	fh = sum_filehandle(NFS_FHSIZE);
    519  0  stevel 	setxdr_pos(pos);
    520  0  stevel 	(void) sprintf(get_line(0, 0), "File handle = [%04X]", fh & 0xFFFF);
    521  0  stevel 	(void) showxdr_hex(NFS_FHSIZE, " %s");
    522  0  stevel }
    523  0  stevel 
    524  0  stevel static void
    525  0  stevel detail_mode(mode)
    526  0  stevel 	int mode;
    527  0  stevel {
    528  0  stevel 	char *str;
    529  0  stevel 
    530  0  stevel 	switch (mode & S_IFMT) {
    531  0  stevel 	case S_IFDIR: str = "Directory";	break;
    532  0  stevel 	case S_IFCHR: str = "Character";	break;
    533  0  stevel 	case S_IFBLK: str = "Block";		break;
    534  0  stevel 	case S_IFREG: str = "Regular file";	break;
    535  0  stevel 	case S_IFLNK: str = "Link";		break;
    536  0  stevel 	case S_IFSOCK: str = "Socket";		break;
    537  0  stevel 	case S_IFIFO: str = "Fifo";		break;
    538  0  stevel 	default: str = "?";			break;
    539  0  stevel 	}
    540  0  stevel 
    541  0  stevel 	(void) sprintf(get_line(0, 0), "Mode = 0%o", mode);
    542  0  stevel 	(void) sprintf(get_line(0, 0), " Type = %s", str);
    543  0  stevel 	(void) sprintf(get_line(0, 0),
    544  0  stevel 		" Setuid = %d, Setgid = %d, Sticky = %d",
    545  0  stevel 		(mode & S_ISUID) != 0,
    546  0  stevel 		(mode & S_ISGID) != 0,
    547  0  stevel 		(mode & S_ISVTX) != 0);
    548  0  stevel 	(void) sprintf(get_line(0, 0), " Owner's permissions = %s",
    549  0  stevel 		perms(mode >> 6 & 0x7));
    550  0  stevel 	(void) sprintf(get_line(0, 0), " Group's permissions = %s",
    551  0  stevel 		perms(mode >> 3 & 0x7));
    552  0  stevel 	(void) sprintf(get_line(0, 0), " Other's permissions = %s",
    553  0  stevel 		perms(mode & 0x7));
    554  0  stevel }
    555  0  stevel 
    556  0  stevel void
    557  0  stevel detail_fattr()
    558  0  stevel {
    559  0  stevel 	int fltype, mode, nlinks, uid, gid, size, blksz;
    560  0  stevel 	int rdev, blocks, fsid, fileid;
    561  0  stevel 
    562  0  stevel 	fltype = getxdr_long();
    563  0  stevel 	mode = getxdr_long();
    564  0  stevel 	nlinks = getxdr_long();
    565  0  stevel 	uid = getxdr_long();
    566  0  stevel 	gid = getxdr_long();
    567  0  stevel 	size = getxdr_long();
    568  0  stevel 	blksz = getxdr_long();
    569  0  stevel 	rdev = getxdr_long();
    570  0  stevel 	blocks = getxdr_long();
    571  0  stevel 	fsid = getxdr_long();
    572  0  stevel 	fileid = getxdr_long();
    573  0  stevel 
    574  0  stevel 	(void) sprintf(get_line(0, 0),
    575  0  stevel 		"File type = %d (%s)",
    576  0  stevel 		fltype, filetype(fltype));
    577  0  stevel 	detail_mode(mode);
    578  0  stevel 	(void) sprintf(get_line(0, 0),
    579  0  stevel 		"Link count = %d, UID = %d, GID = %d, Rdev = 0x%x",
    580  0  stevel 		nlinks, uid, gid, rdev);
    581  0  stevel 	(void) sprintf(get_line(0, 0),
    582  0  stevel 		"File size = %d, Block size = %d, No. of blocks = %d",
    583  0  stevel 		size, blksz, blocks);
    584  0  stevel 	(void) sprintf(get_line(0, 0),
    585  0  stevel 		"File system id = %d, File id = %d",
    586  0  stevel 		fsid, fileid);
    587  0  stevel 	(void) showxdr_date("Access time       = %s");
    588  0  stevel 	(void) showxdr_date("Modification time = %s");
    589  0  stevel 	(void) showxdr_date("Inode change time = %s");
    590  0  stevel }
    591  0  stevel 
    592  0  stevel static void
    593  0  stevel detail_sattr()
    594  0  stevel {
    595  0  stevel 	int mode;
    596  0  stevel 
    597  0  stevel 	mode = getxdr_long();
    598  0  stevel 	detail_mode(mode);
    599  0  stevel 	(void) showxdr_long("UID = %d");
    600  0  stevel 	(void) showxdr_long("GID = %d");
    601  0  stevel 	(void) showxdr_long("Size = %d");
    602  0  stevel 	(void) showxdr_date("Access time       = %s");
    603  0  stevel 	(void) showxdr_date("Modification time = %s");
    604  0  stevel }
    605  0  stevel 
    606  0  stevel static char *
    607  0  stevel filetype(n)
    608  0  stevel 	int n;
    609  0  stevel {
    610  0  stevel 	switch (n) {
    611  0  stevel 	    case NFREG: return ("Regular File");
    612  0  stevel 	    case NFDIR: return ("Directory");
    613  0  stevel 	    case NFBLK: return ("Block special");
    614  0  stevel 	    case NFCHR: return ("Character special");
    615  0  stevel 	    case NFLNK: return ("Symbolic Link");
    616  0  stevel 	    default:	return ("?");
    617  0  stevel 	}
    618  0  stevel }
    619  0  stevel 
    620  0  stevel static char *
    621  0  stevel perms(n)
    622  0  stevel 	int n;
    623  0  stevel {
    624  0  stevel 	static char buff[4];
    625  0  stevel 
    626  0  stevel 	buff[0] = n & 4 ? 'r' : '-';
    627  0  stevel 	buff[1] = n & 2 ? 'w' : '-';
    628  0  stevel 	buff[2] = n & 1 ? 'x' : '-';
    629  0  stevel 	buff[3] = '\0';
    630  0  stevel 	return (buff);
    631  0  stevel }
    632  0  stevel 
    633  0  stevel static char *
    634  0  stevel sum_readdirres()
    635  0  stevel {
    636  0  stevel 	static char buff[NFS_MAXNAMLEN + 1];
    637  0  stevel 	int entries = 0;
    638  0  stevel 
    639  0  stevel 	if (setjmp(xdr_err)) {
    640  0  stevel 		(void) sprintf(buff, " %d+ entries (incomplete)", entries);
    641  0  stevel 		return (buff);
    642  0  stevel 	}
    643  0  stevel 	while (getxdr_long()) {
    644  0  stevel 		entries++;
    645  0  stevel 		(void) getxdr_long();			/* fileid */
    646  0  stevel 		(void) getxdr_string(buff, NFS_MAXNAMLEN); /* name */
    647  0  stevel 		(void) getxdr_u_long();			/* cookie */
    648  0  stevel 	}
    649  0  stevel 
    650  0  stevel 	(void) sprintf(buff, " %d entries (%s)",
    651  0  stevel 		entries,
    652  0  stevel 		getxdr_long() ? "No more" : "More");
    653  0  stevel 	return (buff);
    654  0  stevel }
    655  0  stevel 
    656  0  stevel static void
    657  0  stevel detail_readdirres()
    658  0  stevel {
    659  0  stevel 	ulong_t fileid, cookie;
    660  0  stevel 	int entries = 0;
    661  0  stevel 	char *name;
    662  0  stevel 	char buff[NFS_MAXNAMLEN + 1];
    663  0  stevel 
    664  0  stevel 	(void) sprintf(get_line(0, 0), " File id  Cookie Name");
    665  0  stevel 
    666  0  stevel 	if (setjmp(xdr_err)) {
    667  0  stevel 		(void) sprintf(get_line(0, 0),
    668  0  stevel 			"  %d+ entries. (Frame is incomplete)",
    669  0  stevel 			entries);
    670  0  stevel 		return;
    671  0  stevel 	}
    672  0  stevel 	while (getxdr_long()) {
    673  0  stevel 		entries++;
    674  0  stevel 		fileid = getxdr_long();
    675  0  stevel 		name = (char *)getxdr_string(buff, NFS_MAXNAMLEN);
    676  0  stevel 		cookie = getxdr_u_long();
    677  0  stevel 		(void) sprintf(get_line(0, 0),
    678  0  stevel 			" %7lu %7lu %s",
    679  0  stevel 			fileid, cookie, name);
    680  0  stevel 	}
    681  0  stevel 
    682  0  stevel 	(void) sprintf(get_line(0, 0), "  %d entries", entries);
    683  0  stevel 	(void) showxdr_long("EOF = %d");
    684  0  stevel }
    685  0  stevel 
    686  0  stevel void
    687  0  stevel skip_fattr()
    688  0  stevel {
    689  0  stevel 
    690  0  stevel 	xdr_skip(17 * 4);	/* XDR sizeof nfsfattr */
    691  0  stevel }
    692