/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1991-2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include "snoop.h" #include "snoop_nfs.h" #include #include static char *perms(int); static char *filetype(int); static char *sum_readdirres(void); static void detail_readdirres(void); static void detail_diroparg(void); static void nfscall2(int); static void nfsreply2(int); static void detail_mode(int); static void detail_sattr(void); static void interpret_nfs2(int, int, int, int, int, char *, int); extern jmp_buf xdr_err; static char *procnames_short[] = { "NULL2", /* 0 */ "GETATTR2", /* 1 */ "SETATTR2", /* 2 */ "ROOT2", /* 3 */ "LOOKUP2", /* 4 */ "READLINK2", /* 5 */ "READ2", /* 6 */ "WRITECACHE2", /* 7 */ "WRITE2", /* 8 */ "CREATE2", /* 9 */ "REMOVE2", /* 10 */ "RENAME2", /* 11 */ "LINK2", /* 12 */ "SYMLINK2", /* 13 */ "MKDIR2", /* 14 */ "RMDIR2", /* 15 */ "READDIR2", /* 16 */ "STATFS2", /* 17 */ }; static char *procnames_long[] = { "Null procedure", /* 0 */ "Get file attributes", /* 1 */ "Set file attributes", /* 2 */ "Get root filehandle", /* 3 */ "Look up file name", /* 4 */ "Read from symbolic link", /* 5 */ "Read from file", /* 6 */ "Write to cache", /* 7 */ "Write to file", /* 8 */ "Create file", /* 9 */ "Remove file", /* 10 */ "Rename", /* 11 */ "Link", /* 12 */ "Make symbolic link", /* 13 */ "Make directory", /* 14 */ "Remove directory", /* 15 */ "Read from directory", /* 16 */ "Get filesystem attributes", /* 17 */ }; #define MAXPROC 17 /* ARGSUSED */ void interpret_nfs(flags, type, xid, vers, proc, data, len) int flags, type, xid, vers, proc; char *data; int len; { if (vers == 2) { interpret_nfs2(flags, type, xid, vers, proc, data, len); return; } if (vers == 3) { interpret_nfs3(flags, type, xid, vers, proc, data, len); return; } if (vers == 4) { interpret_nfs4(flags, type, xid, vers, proc, data, len); return; } } static void interpret_nfs2(flags, type, xid, vers, proc, data, len) int flags, type, xid, vers, proc; char *data; int len; { char *line; char buff[NFS_MAXPATHLEN + 1]; int off, sz; char *fh; if (proc < 0 || proc > MAXPROC) return; if (flags & F_SUM) { line = get_sum_line(); if (type == CALL) { (void) sprintf(line, "NFS C %s", procnames_short[proc]); line += strlen(line); switch (proc) { case NFSPROC_GETATTR: case NFSPROC_READLINK: case NFSPROC_STATFS: case NFSPROC_SETATTR: (void) sprintf(line, sum_nfsfh()); break; case NFSPROC_LOOKUP: case NFSPROC_REMOVE: case NFSPROC_RMDIR: case NFSPROC_CREATE: case NFSPROC_MKDIR: fh = sum_nfsfh(); (void) sprintf(line, "%s %s", fh, getxdr_string(buff, NFS_MAXNAMLEN)); break; case NFSPROC_WRITE: fh = sum_nfsfh(); (void) getxdr_long(); /* beginoff */ off = getxdr_long(); (void) getxdr_long(); /* totalcount */ sz = getxdr_long(); (void) sprintf(line, "%s at %d for %d", fh, off, sz); break; case NFSPROC_RENAME: fh = sum_nfsfh(); (void) sprintf(line, "%s %s", fh, getxdr_string(buff, NFS_MAXNAMLEN)); line += strlen(line); fh = sum_nfsfh(); (void) sprintf(line, " to%s %s", fh, getxdr_string(buff, NFS_MAXNAMLEN)); break; case NFSPROC_LINK: fh = sum_nfsfh(); (void) sprintf(line, "%s", fh); line += strlen(line); fh = sum_nfsfh(); (void) sprintf(line, " to%s %s", fh, getxdr_string(buff, NFS_MAXNAMLEN)); break; case NFSPROC_SYMLINK: fh = sum_nfsfh(); (void) sprintf(line, "%s %s", fh, getxdr_string(buff, NFS_MAXNAMLEN)); line += strlen(line); (void) sprintf(line, " to %s", getxdr_string(buff, NFS_MAXPATHLEN)); break; case NFSPROC_READDIR: fh = sum_nfsfh(); (void) sprintf(line, "%s Cookie=%lu", fh, getxdr_u_long()); break; case NFSPROC_READ: fh = sum_nfsfh(); off = getxdr_long(); sz = getxdr_long(); (void) sprintf(line, "%s at %d for %d", fh, off, sz); break; default: break; } check_retransmit(line, (ulong_t)xid); } else { (void) sprintf(line, "NFS R %s ", procnames_short[proc]); line += strlen(line); switch (proc) { case NFSPROC_CREATE: case NFSPROC_MKDIR: case NFSPROC_LOOKUP: if (sum_nfsstat(line) == 0) { line += strlen(line); (void) sprintf(line, sum_nfsfh()); } break; case NFSPROC_READLINK: if (sum_nfsstat(line) == 0) { line += strlen(line); (void) sprintf(line, " (Path=%s)", getxdr_string(buff, NFS_MAXPATHLEN)); } break; case NFSPROC_GETATTR: case NFSPROC_SYMLINK: case NFSPROC_STATFS: case NFSPROC_SETATTR: case NFSPROC_REMOVE: case NFSPROC_RMDIR: case NFSPROC_WRITE: case NFSPROC_RENAME: case NFSPROC_LINK: (void) sum_nfsstat(line); break; case NFSPROC_READDIR: if (sum_nfsstat(line) == 0) { line += strlen(line); (void) strcat(line, sum_readdirres()); } break; case NFSPROC_READ: if (sum_nfsstat(line) == 0) { line += strlen(line); xdr_skip(68); /* fattrs */ (void) sprintf(line, " (%ld bytes)", getxdr_long()); } break; default: break; } } } if (flags & F_DTAIL) { show_header("NFS: ", "Sun NFS", len); show_space(); (void) sprintf(get_line(0, 0), "Proc = %d (%s)", proc, procnames_long[proc]); if (type == CALL) nfscall2(proc); else nfsreply2(proc); show_trailer(); } } /* * Print out version 2 NFS call packets */ static void nfscall2(proc) int proc; { switch (proc) { case NFSPROC_GETATTR: case NFSPROC_READLINK: case NFSPROC_STATFS: detail_nfsfh(); break; case NFSPROC_SETATTR: detail_nfsfh(); detail_sattr(); break; case NFSPROC_LOOKUP: case NFSPROC_REMOVE: case NFSPROC_RMDIR: detail_diroparg(); break; case NFSPROC_MKDIR: case NFSPROC_CREATE: detail_diroparg(); detail_sattr(); break; case NFSPROC_WRITE: detail_nfsfh(); (void) getxdr_long(); /* begoff */ (void) showxdr_long("Offset = %d"); (void) getxdr_long(); /* totalcount */ (void) showxdr_long("(%d bytes(s) of data)"); break; case NFSPROC_RENAME: detail_diroparg(); detail_diroparg(); break; case NFSPROC_LINK: detail_nfsfh(); detail_diroparg(); break; case NFSPROC_SYMLINK: detail_diroparg(); (void) showxdr_string(NFS_MAXPATHLEN, "Path = %s"); detail_sattr(); break; case NFSPROC_READDIR: detail_nfsfh(); (void) showxdr_u_long("Cookie = %lu"); (void) showxdr_long("Count = %d"); break; case NFSPROC_READ: detail_nfsfh(); (void) showxdr_long("Offset = %d"); (void) showxdr_long("Count = %d"); break; default: break; } } /* * Print out version 2 NFS reply packets */ static void nfsreply2(proc) int proc; { switch (proc) { case NFSPROC_GETATTR: case NFSPROC_SETATTR: case NFSPROC_WRITE: /* attrstat */ if (detail_nfsstat() == 0) { detail_fattr(); } break; case NFSPROC_LOOKUP: case NFSPROC_CREATE: case NFSPROC_MKDIR: /* diropres */ if (detail_nfsstat() == 0) { detail_nfsfh(); detail_fattr(); } break; case NFSPROC_READLINK: /* readlinkres */ if (detail_nfsstat() == 0) { (void) showxdr_string(NFS_MAXPATHLEN, "Path = %s"); } break; case NFSPROC_READ: /* readres */ if (detail_nfsstat() == 0) { detail_fattr(); (void) showxdr_long("(%d byte(s) of data)"); } break; case NFSPROC_REMOVE: case NFSPROC_RENAME: case NFSPROC_LINK: case NFSPROC_SYMLINK: case NFSPROC_RMDIR: /* stat */ detail_nfsstat(); break; case NFSPROC_READDIR: /* readdirres */ if (detail_nfsstat() == 0) detail_readdirres(); break; case NFSPROC_STATFS: /* statfsres */ if (detail_nfsstat() == 0) { (void) showxdr_long("Transfer size = %d"); (void) showxdr_long("Block size = %d"); (void) showxdr_long("Total blocks = %d"); (void) showxdr_long("Free blocks = %d"); (void) showxdr_long("Available blocks = %d"); } break; default: break; } } static void detail_diroparg() { detail_nfsfh(); (void) showxdr_string(NFS_MAXPATHLEN, "File name = %s"); } /* * V2 NFS protocol was implicitly linked with SunOS errnos. * Some of the errno values changed in SVr4. * Need to map errno value so that SVr4 snoop will interpret * them correctly. */ static char * statusmsg(status) ulong_t status; { switch (status) { case NFS_OK: return ("OK"); case NFSERR_PERM: return ("Not owner"); case NFSERR_NOENT: return ("No such file or directory"); case NFSERR_IO: return ("I/O error"); case NFSERR_NXIO: return ("No such device or address"); case NFSERR_ACCES: return ("Permission denied"); case NFSERR_EXIST: return ("File exists"); case NFSERR_XDEV: return ("Cross-device link"); case NFSERR_NODEV: return ("No such device"); case NFSERR_NOTDIR: return ("Not a directory"); case NFSERR_ISDIR: return ("Is a directory"); case NFSERR_INVAL: return ("Invalid argument"); case NFSERR_FBIG: return ("File too large"); case NFSERR_NOSPC: return ("No space left on device"); case NFSERR_ROFS: return ("Read-only file system"); case NFSERR_OPNOTSUPP: return ("Operation not supported"); case NFSERR_NAMETOOLONG: return ("File name too long"); case NFSERR_NOTEMPTY: return ("Directory not empty"); case NFSERR_DQUOT: return ("Disc quota exceeded"); case NFSERR_STALE: return ("Stale NFS file handle"); case NFSERR_REMOTE: return ("Object is remote"); case NFSERR_WFLUSH: return ("write cache flushed"); default: return ("(unknown error)"); } /* NOTREACHED */ } int sum_nfsstat(line) char *line; { ulong_t status; status = getxdr_long(); (void) strcpy(line, statusmsg(status)); return (status); } int detail_nfsstat() { ulong_t status; int pos; pos = getxdr_pos(); status = getxdr_long(); (void) sprintf(get_line(pos, getxdr_pos()), "Status = %lu (%s)", status, statusmsg(status)); return ((int)status); } int sum_filehandle(len) int len; { int i, l; int fh = 0; for (i = 0; i < len; i += 4) { l = getxdr_long(); fh ^= (l >> 16) ^ l; } return (fh); } char * sum_nfsfh() { int fh; static char buff[16]; fh = sum_filehandle(NFS_FHSIZE); (void) sprintf(buff, " FH=%04X", fh & 0xFFFF); return (buff); } void detail_nfsfh() { int pos; int fh; pos = getxdr_pos(); fh = sum_filehandle(NFS_FHSIZE); setxdr_pos(pos); (void) sprintf(get_line(0, 0), "File handle = [%04X]", fh & 0xFFFF); (void) showxdr_hex(NFS_FHSIZE, " %s"); } static void detail_mode(mode) int mode; { char *str; switch (mode & S_IFMT) { case S_IFDIR: str = "Directory"; break; case S_IFCHR: str = "Character"; break; case S_IFBLK: str = "Block"; break; case S_IFREG: str = "Regular file"; break; case S_IFLNK: str = "Link"; break; case S_IFSOCK: str = "Socket"; break; case S_IFIFO: str = "Fifo"; break; default: str = "?"; break; } (void) sprintf(get_line(0, 0), "Mode = 0%o", mode); (void) sprintf(get_line(0, 0), " Type = %s", str); (void) sprintf(get_line(0, 0), " Setuid = %d, Setgid = %d, Sticky = %d", (mode & S_ISUID) != 0, (mode & S_ISGID) != 0, (mode & S_ISVTX) != 0); (void) sprintf(get_line(0, 0), " Owner's permissions = %s", perms(mode >> 6 & 0x7)); (void) sprintf(get_line(0, 0), " Group's permissions = %s", perms(mode >> 3 & 0x7)); (void) sprintf(get_line(0, 0), " Other's permissions = %s", perms(mode & 0x7)); } void detail_fattr() { int fltype, mode, nlinks, uid, gid, size, blksz; int rdev, blocks, fsid, fileid; fltype = getxdr_long(); mode = getxdr_long(); nlinks = getxdr_long(); uid = getxdr_long(); gid = getxdr_long(); size = getxdr_long(); blksz = getxdr_long(); rdev = getxdr_long(); blocks = getxdr_long(); fsid = getxdr_long(); fileid = getxdr_long(); (void) sprintf(get_line(0, 0), "File type = %d (%s)", fltype, filetype(fltype)); detail_mode(mode); (void) sprintf(get_line(0, 0), "Link count = %d, UID = %d, GID = %d, Rdev = 0x%x", nlinks, uid, gid, rdev); (void) sprintf(get_line(0, 0), "File size = %d, Block size = %d, No. of blocks = %d", size, blksz, blocks); (void) sprintf(get_line(0, 0), "File system id = %d, File id = %d", fsid, fileid); (void) showxdr_date("Access time = %s"); (void) showxdr_date("Modification time = %s"); (void) showxdr_date("Inode change time = %s"); } static void detail_sattr() { int mode; mode = getxdr_long(); detail_mode(mode); (void) showxdr_long("UID = %d"); (void) showxdr_long("GID = %d"); (void) showxdr_long("Size = %d"); (void) showxdr_date("Access time = %s"); (void) showxdr_date("Modification time = %s"); } static char * filetype(n) int n; { switch (n) { case NFREG: return ("Regular File"); case NFDIR: return ("Directory"); case NFBLK: return ("Block special"); case NFCHR: return ("Character special"); case NFLNK: return ("Symbolic Link"); default: return ("?"); } } static char * perms(n) int n; { static char buff[4]; buff[0] = n & 4 ? 'r' : '-'; buff[1] = n & 2 ? 'w' : '-'; buff[2] = n & 1 ? 'x' : '-'; buff[3] = '\0'; return (buff); } static char * sum_readdirres() { static char buff[NFS_MAXNAMLEN + 1]; int entries = 0; if (setjmp(xdr_err)) { (void) sprintf(buff, " %d+ entries (incomplete)", entries); return (buff); } while (getxdr_long()) { entries++; (void) getxdr_long(); /* fileid */ (void) getxdr_string(buff, NFS_MAXNAMLEN); /* name */ (void) getxdr_u_long(); /* cookie */ } (void) sprintf(buff, " %d entries (%s)", entries, getxdr_long() ? "No more" : "More"); return (buff); } static void detail_readdirres() { ulong_t fileid, cookie; int entries = 0; char *name; char buff[NFS_MAXNAMLEN + 1]; (void) sprintf(get_line(0, 0), " File id Cookie Name"); if (setjmp(xdr_err)) { (void) sprintf(get_line(0, 0), " %d+ entries. (Frame is incomplete)", entries); return; } while (getxdr_long()) { entries++; fileid = getxdr_long(); name = (char *)getxdr_string(buff, NFS_MAXNAMLEN); cookie = getxdr_u_long(); (void) sprintf(get_line(0, 0), " %7lu %7lu %s", fileid, cookie, name); } (void) sprintf(get_line(0, 0), " %d entries", entries); (void) showxdr_long("EOF = %d"); } void skip_fattr() { xdr_skip(17 * 4); /* XDR sizeof nfsfattr */ }