/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2015 Nexenta Systems, Inc. All rights reserved. */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "snoop.h" #include #include #include #include /* use the same nfs4_prot.h as the xdr code */ #include "rpcsvc/nfs4_prot.h" /* * XXX With NFS v2 and v3, we only need to xdr the pieces that we care * about. Anything else we can ignore and just skip to the next packet. * So all the stuff that deals directly with XDR lives in snoop_display.c * With v4, we need to XDR entire structures so that we can skip over * uninteresting bits in a compound array, so we call XDR directly from * here. We need to rethink how we're going to structure XDR access. Do * we continue to hide it all in snoop_display.c, or do we expose it to all * the protocol modules? */ extern XDR xdrm; #ifndef MIN #define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif /* * Maximum number of characters to display in compound4 summary line. */ #define SUM_COMPND_MAX 100 /* * Maximum number of recognized attributes. */ #define MAX_ATTRIBUTES 56 /* * This data structure provides a more convenient way to access an * attribute bitmask. map[N] = value of bit N in a bitmap4. * It's defined as a struct so as to step around all the weird rules in C * about arrays, pointers, passing them as arguments, etc. */ typedef struct { char map[MAX_ATTRIBUTES]; } unpkd_attrmap_t; static void sumarg_cb_getattr(char *buf, size_t buflen, void *obj); static void dtlarg_cb_getattr(void *obj); static void sumarg_cb_recall(char *buf, size_t buflen, void *obj); static void dtlarg_cb_recall(void *obj); static void sumarg_access(char *buf, size_t buflen, void *obj); static void dtlarg_access(void *obj); static void sumarg_close(char *buf, size_t buflen, void *obj); static void dtlarg_close(void *obj); static void sumarg_commit(char *buf, size_t buflen, void *obj); static void dtlarg_commit(void *obj); static void sumarg_compnt(char *buf, size_t buflen, void *obj); static void dtlarg_compnt(void *obj); static void sumarg_create(char *buf, size_t buflen, void *obj); static void dtlarg_create(void *obj); static void sumarg_delprge(char *buf, size_t buflen, void *obj); static void dtlarg_delprge(void *obj); static void sumarg_delret(char *buf, size_t buflen, void *obj); static void dtlarg_delret(void *obj); static void sumarg_getattr(char *buf, size_t buflen, void *obj); static void dtlarg_getattr(void *obj); static void sumarg_link(char *buf, size_t buflen, void *obj); static void dtlarg_link(void *obj); static void sum_open_to_lock_owner(char *buf, int buflen, open_to_lock_owner4 *own); static void sum_exist_lock_owner(char *buf, int buflen, exist_lock_owner4 *own); static void sum_locker(char *buf, size_t buflen, locker4 *lk); static void sumarg_lock(char *buf, size_t buflen, void *obj); static void detail_open_to_lock_owner(open_to_lock_owner4 *own); static void detail_exist_lock_owner(exist_lock_owner4 *own); static void detail_locker(locker4 *lk); static void dtlarg_lock(void *obj); static void sumarg_lockt(char *buf, size_t buflen, void *obj); static void dtlarg_lockt(void *obj); static void sumarg_locku(char *buf, size_t buflen, void *obj); static void dtlarg_locku(void *obj); static void sumarg_lookup(char *buf, size_t buflen, void *obj); static void dtlarg_lookup(void *obj); static void sumarg_open(char *buf, size_t buflen, void *obj); static void dtlarg_open(void *obj); static void sumarg_openattr(char *buf, size_t buflen, void *obj); static void dtlarg_openattr(void *obj); static void sumarg_open_confirm(char *buf, size_t buflen, void *obj); static void dtlarg_open_confirm(void *obj); static void sumarg_open_downgrd(char *buf, size_t buflen, void *obj); static void dtlarg_open_downgrd(void *obj); static void sumarg_putfh(char *buf, size_t buflen, void *obj); static void dtlarg_putfh(void *obj); static void sumarg_read(char *buf, size_t buflen, void *obj); static void dtlarg_read(void *obj); static void sumarg_readdir(char *buf, size_t buflen, void *obj); static void dtlarg_readdir(void *obj); static void sumarg_release_lkown(char *buf, size_t buflen, void *obj); static void dtlarg_release_lkown(void *obj); static void sumarg_rename(char *buf, size_t buflen, void *obj); static void dtlarg_rename(void *obj); static void sumarg_renew(char *buf, size_t buflen, void *obj); static void dtlarg_renew(void *buf); static void sumarg_secinfo(char *buf, size_t buflen, void *obj); static void dtlarg_secinfo(void *obj); static void sumarg_setattr(char *buf, size_t buflen, void *obj); static void dtlarg_setattr(void *obj); static void sumarg_setclid(char *buf, size_t buflen, void *obj); static void dtlarg_setclid(void *obj); static void sumarg_setclid_cfm(char *buf, size_t buflen, void *obj); static void dtlarg_setclid_cfm(void *obj); static void dtlarg_verify(void *obj); static void sumarg_write(char *buf, size_t buflen, void *obj); static void dtlarg_write(void *obj); static void sumres_cb_getattr(char *buf, size_t buflen, void *obj); static void dtlres_cb_getattr(void *obj); static void sumres_access(char *buf, size_t buflen, void *obj); static void dtlres_access(void *obj); static void sumres_close(char *buf, size_t buflen, void *obj); static void dtlres_close(void *obj); static void sumres_commit(char *buf, size_t buflen, void *obj); static void dtlres_commit(void *obj); static void dtlres_create(void *obj); static void sumres_getattr(char *buf, size_t buflen, void *obj); static void dtlres_getattr(void *obj); static void sumres_getfh(char *buf, size_t buflen, void *obj); static void dtlres_getfh(void *obj); static void dtlres_link(void *obj); static void sumres_lock(char *buf, size_t buflen, void *obj); static void dtlres_lock(void *obj); static void sumres_lockt(char *buf, size_t buflen, void *obj); static void dtlres_lockt(void *obj); static void sumres_locku(char *buf, size_t buflen, void *obj); static void dtlres_locku(void *obj); static void sumres_open(char *buf, size_t buflen, void *obj); static void dtlres_open(void *obj); static void sumres_open_confirm(char *buf, size_t buflen, void *obj); static void dtlres_open_confirm(void *obj); static void sumres_open_downgrd(char *buf, size_t buflen, void *obj); static void dtlres_open_downgrd(void *obj); static void sumres_read(char *buf, size_t buflen, void *obj); static void dtlres_read(void *obj); static void sumres_readdir(char *buf, size_t buflen, void *obj); static void dtlres_readdir(void *obj); static void sumres_readlnk(char *buf, size_t buflen, void *obj); static void dtlres_readlnk(void *obj); static void dtlres_remove(void *obj); static void dtlres_rename(void *obj); static void sumres_secinfo(char *buf, size_t buflen, void *obj); static void dtlres_secinfo(void *obj); static void sumres_setattr(char *buf, size_t buflen, void *obj); static void dtlres_setattr(void *obj); static void sumres_setclid(char *buf, size_t buflen, void *obj); static void dtlres_setclid(void *obj); static void sumres_write(char *buf, size_t buflen, void *obj); static void dtlres_write(void *obj); static void sum_nfsstat4(char *buf, size_t buflen, void *obj); static void dtl_nfsstat4(void *obj); static uint32_t adler16(void *, int); static void nfs4_xdr_skip(int nbytes); static char *sum_lock_type_name(enum nfs_lock_type4 type); int nfs4_pkt_start; int nfs4_pkt_len; int nfs4_skip_bytes; int nfs4_fragged_rpc; char *nfs4err_fragrpc = ""; char *nfs4err_xdrfrag = ""; /* * need a way to enable this if current testcases are parsing snoop * error text. -- maybe an env var would do as temp workaround until * testcases changed to grep for new error text. */ int nfs4_use_old_error_text = 0; /* * Information about each operation that can appear in a compound call. * The function pointers are to formatting functions for summary arguments * and results, and detail arguments & results. */ typedef struct { char *name; void (*sumarg)(char *, size_t, void *); void (*sumres)(char *, size_t, void *); void (*dtlarg)(void *); void (*dtlres)(void *); } op_info_t; static op_info_t cb_opcode_info[] = { {"OP_ZERO", NULL, NULL, NULL, NULL}, /* 0 */ {"OP_ONE", NULL, NULL, NULL, NULL}, {"OP_TWO", NULL, NULL, NULL, NULL}, /* minor vers */ {"CB_GETATTR", sumarg_cb_getattr, sumres_cb_getattr, dtlarg_cb_getattr, dtlres_cb_getattr}, {"CB_RECALL", sumarg_cb_recall, sum_nfsstat4, dtlarg_cb_recall, dtl_nfsstat4}, }; static uint_t cb_num_opcodes = ARRAY_SIZE(cb_opcode_info); static op_info_t opcode_info[] = { {"OP_ZERO", NULL, NULL, NULL, NULL}, /* 0 */ {"OP_ONE", NULL, NULL, NULL, NULL}, {"OP_TWO", NULL, NULL, NULL, NULL}, /* minor vers */ {"ACCESS", sumarg_access, sumres_access, dtlarg_access, dtlres_access}, {"CLOSE", sumarg_close, sumres_close, dtlarg_close, dtlres_close}, {"COMMIT", sumarg_commit, sumres_commit, dtlarg_commit, dtlres_commit}, {"CREATE", /* 5 */ sumarg_create, sum_nfsstat4, dtlarg_create, dtlres_create}, {"DELEGPURGE", sumarg_delprge, sum_nfsstat4, dtlarg_delprge, dtl_nfsstat4}, {"DELEGRETURN", sumarg_delret, sum_nfsstat4, dtlarg_delret, dtl_nfsstat4}, {"GETATTR", sumarg_getattr, sumres_getattr, dtlarg_getattr, dtlres_getattr}, {"GETFH", NULL, sumres_getfh, NULL, dtlres_getfh}, {"LINK", /* 10 */ sumarg_link, sum_nfsstat4, dtlarg_link, dtlres_link}, {"LOCK", sumarg_lock, sumres_lock, dtlarg_lock, dtlres_lock}, {"LOCKT", sumarg_lockt, sumres_lockt, dtlarg_lockt, dtlres_lockt}, {"LOCKU", sumarg_locku, sumres_locku, dtlarg_locku, dtlres_locku}, {"LOOKUP", sumarg_lookup, sum_nfsstat4, dtlarg_lookup, dtl_nfsstat4}, {"LOOKUPP", /* 15 */ NULL, sum_nfsstat4, NULL, dtl_nfsstat4}, {"NVERIFY", NULL, sum_nfsstat4, dtlarg_verify, dtl_nfsstat4}, {"OPEN", sumarg_open, sumres_open, dtlarg_open, dtlres_open}, {"OPENATTR", sumarg_openattr, sum_nfsstat4, dtlarg_openattr, dtl_nfsstat4}, {"OPEN_CONFIRM", sumarg_open_confirm, sumres_open_confirm, dtlarg_open_confirm, dtlres_open_confirm}, {"OPEN_DOWNGRADE", sumarg_open_downgrd, sumres_open_downgrd, dtlarg_open_downgrd, dtlres_open_downgrd}, {"PUTFH", sumarg_putfh, sum_nfsstat4, dtlarg_putfh, dtl_nfsstat4}, {"PUTPUBFH", /* 20 */ NULL, sum_nfsstat4, NULL, dtl_nfsstat4}, {"PUTROOTFH", NULL, sum_nfsstat4, NULL, dtl_nfsstat4}, {"READ", sumarg_read, sumres_read, dtlarg_read, dtlres_read}, {"READDIR", sumarg_readdir, sumres_readdir, dtlarg_readdir, dtlres_readdir}, {"READLINK", NULL, sumres_readlnk, NULL, dtlres_readlnk}, {"REMOVE", /* 25 */ sumarg_compnt, sum_nfsstat4, dtlarg_compnt, dtlres_remove}, {"RENAME", sumarg_rename, sum_nfsstat4, dtlarg_rename, dtlres_rename}, {"RENEW", sumarg_renew, sum_nfsstat4, dtlarg_renew, dtl_nfsstat4}, {"RESTOREFH", NULL, sum_nfsstat4, NULL, dtl_nfsstat4}, {"SAVEFH", NULL, sum_nfsstat4, NULL, dtl_nfsstat4}, {"SECINFO", /* 30 */ sumarg_secinfo, sumres_secinfo, dtlarg_secinfo, dtlres_secinfo}, {"SETATTR", sumarg_setattr, sumres_setattr, dtlarg_setattr, dtlres_setattr}, {"SETCLIENTID", sumarg_setclid, sumres_setclid, dtlarg_setclid, dtlres_setclid}, {"SETCLIENTID_CONFIRM", sumarg_setclid_cfm, sum_nfsstat4, dtlarg_setclid_cfm, dtl_nfsstat4}, {"VERIFY", NULL, sum_nfsstat4, dtlarg_verify, dtl_nfsstat4}, {"WRITE", sumarg_write, sumres_write, dtlarg_write, dtlres_write}, {"RELEASE_LOCKOWNER", sumarg_release_lkown, sum_nfsstat4, dtlarg_release_lkown, dtl_nfsstat4}, }; static uint_t num_opcodes = ARRAY_SIZE(opcode_info); /* * File types. */ typedef struct { char *short_name; /* for summary output */ char *long_name; /* for detail output */ } ftype_names_t; static ftype_names_t ftype_names[] = { {"Type 0", "Type 0"}, {"REG", "Regular File"}, {"DIR", "Directory"}, {"BLK", "Block Device"}, {"CHR", "Character Device"}, {"LNK", "Symbolic Link"}, /* 5 */ {"SOCK", "Socket"}, {"FIFO", "FIFO"}, {"ATTRDIR", "Attribute Directory"}, {"NAMEDATTR", "Named Attribute"}, }; static uint_t num_ftypes = sizeof (ftype_names) / sizeof (ftype_names_t); static ftype_names_t open_rflags[] = { {"?", "UNKNOWN"}, /* 0 */ {"CF", "CONFIRM"}, /* 1 */ {"PL", "POSIX LOCK"}, /* 2 */ {"?", "UNKNOWN"}, }; static uint_t num_open_rflags = sizeof (open_rflags) / sizeof (ftype_names_t) - 1; static char *get_flags(uint_t, ftype_names_t *, uint_t, int, char *); #define sum_open_rflags(flag) \ get_flags((flag), open_rflags, num_open_rflags, 1, " RF=") #define detail_open_rflags(flag) \ get_flags((flag), open_rflags, num_open_rflags, 0, NULL) static void prt_supported_attrs(XDR *); static void prt_type(XDR *); static void prt_fh_expire_type(XDR *); static void prt_change(XDR *); static void prt_size(XDR *); static void prt_link_support(XDR *); static void prt_symlink_support(XDR *); static void prt_named_attr(XDR *); static void prt_fsid(XDR *); static void prt_unique_handles(XDR *); static void prt_lease_time(XDR *); static void prt_rdattr_error(XDR *); static void prt_acl(XDR *); static void prt_aclsupport(XDR *); static void prt_archive(XDR *); static void prt_cansettime(XDR *); static void prt_case_insensitive(XDR *); static void prt_case_preserving(XDR *); static void prt_chown_restricted(XDR *); static void prt_filehandle(XDR *); static void prt_fileid(XDR *); static void prt_mounted_on_fileid(XDR *); static void prt_files_avail(XDR *); static void prt_files_free(XDR *); static void prt_files_total(XDR *); static void prt_fs_locations(XDR *); static void prt_hidden(XDR *); static void prt_homogeneous(XDR *); static void prt_maxfilesize(XDR *); static void prt_maxlink(XDR *); static void prt_maxname(XDR *); static void prt_maxread(XDR *); static void prt_maxwrite(XDR *); static void prt_mimetype(XDR *); static void prt_mode(XDR *); static void prt_no_trunc(XDR *); static void prt_numlinks(XDR *); static void prt_owner(XDR *); static void prt_owner_group(XDR *); static void prt_quota_avail_hard(XDR *); static void prt_quota_avail_soft(XDR *); static void prt_quota_used(XDR *); static void prt_rawdev(XDR *); static void prt_space_avail(XDR *); static void prt_space_free(XDR *); static void prt_space_total(XDR *); static void prt_space_used(XDR *); static void prt_system(XDR *); static void prt_time_access(XDR *); static void prt_time_access_set(XDR *); static void prt_time_backup(XDR *); static void prt_time_create(XDR *); static void prt_time_delta(XDR *); static void prt_time_metadata(XDR *); static void prt_time_modify(XDR *); static void prt_time_modify_set(XDR *); /* * Information for attributes. * name name of the attribute. * prt_details function to XDR decode the attribute and print it. * * XXX If this table ever gets extensively changed (including * reorganization to track changes to the spec), it would probably be a * good idea to change to a scheme where the table is mechanically * generated. Look at $SRC/uts/common/rpcsvc for how this is done in the * kernel. */ typedef struct { char *name; void (*prt_details)(XDR *); } attr_info_t; static attr_info_t attr_info[MAX_ATTRIBUTES] = { {"SUPPORTED_ATTRS", prt_supported_attrs}, {"TYPE", prt_type}, {"FH_EXPIRE_TYPE", prt_fh_expire_type}, {"CHANGE", prt_change}, {"SIZE", prt_size}, {"LINK_SUPPORT", prt_link_support}, /* 5 */ {"SYMLINK_SUPPORT", prt_symlink_support}, {"NAMED_ATTR", prt_named_attr}, {"FSID", prt_fsid}, {"UNIQUE_HANDLES", prt_unique_handles}, {"LEASE_TIME", prt_lease_time}, /* 10 */ {"RDATTR_ERROR", prt_rdattr_error}, {"ACL", prt_acl}, {"ACLSUPPORT", prt_aclsupport}, {"ARCHIVE", prt_archive}, {"CANSETTIME", prt_cansettime}, /* 15 */ {"CASE_INSENSITIVE", prt_case_insensitive}, {"CASE_PRESERVING", prt_case_preserving}, {"CHOWN_RESTRICTED", prt_chown_restricted}, {"FILEHANDLE", prt_filehandle}, {"FILEID", prt_fileid}, /* 20 */ {"FILES_AVAIL", prt_files_avail}, {"FILES_FREE", prt_files_free}, {"FILES_TOTAL", prt_files_total}, {"FS_LOCATIONS", prt_fs_locations}, {"HIDDEN", prt_hidden}, /* 25 */ {"HOMOGENEOUS", prt_homogeneous}, {"MAXFILESIZE", prt_maxfilesize}, {"MAXLINK", prt_maxlink}, {"MAXNAME", prt_maxname}, {"MAXREAD", prt_maxread}, /* 30 */ {"MAXWRITE", prt_maxwrite}, {"MIMETYPE", prt_mimetype}, {"MODE", prt_mode}, {"NO_TRUNC", prt_no_trunc}, {"NUMLINKS", prt_numlinks}, /* 35 */ {"OWNER", prt_owner}, {"OWNER_GROUP", prt_owner_group}, {"QUOTA_AVAIL_HARD", prt_quota_avail_hard}, {"QUOTA_AVAIL_SOFT", prt_quota_avail_soft}, {"QUOTA_USED", prt_quota_used}, /* 40 */ {"RAWDEV", prt_rawdev}, {"SPACE_AVAIL", prt_space_avail}, {"SPACE_FREE", prt_space_free}, {"SPACE_TOTAL", prt_space_total}, {"SPACE_USED", prt_space_used}, /* 45 */ {"SYSTEM", prt_system}, {"TIME_ACCESS", prt_time_access}, {"TIME_ACCESS_SET", prt_time_access_set}, {"TIME_BACKUP", prt_time_backup}, {"TIME_CREATE", prt_time_create}, /* 50 */ {"TIME_DELTA", prt_time_delta}, {"TIME_METADATA", prt_time_metadata}, {"TIME_MODIFY", prt_time_modify}, {"TIME_MODIFY_SET", prt_time_modify_set}, {"MOUNTED_ON_FILEID", prt_mounted_on_fileid}, }; extern char *get_sum_line(); extern jmp_buf xdr_err; static void sum_comp4res(char *, char *(*)(void)); static char *sum_compound4args(void); static char *sum_compound4res(void); static char *sum_operand(nfs_argop4 *opp); static char *sum_result(nfs_resop4 *resp); static char *sum_cb_compound4args(void); static char *sum_cb_compound4res(void); static char *sum_cb_operand(nfs_cb_argop4 *opp); static char *sum_cb_result(nfs_cb_resop4 *resp); static void detail_acetype4(acetype4); static void detail_uint32_bitmap(uint32_t, char *[], int); static void detail_aceflag4(aceflag4); static void detail_acemask4(acemask4); static void detail_nfs_argop4(void); static void detail_nfs_resop4(void); static void detail_cb_argop4(void); static void detail_cb_resop4(void); static char *attr_name(uint_t); static char *claim_name(enum open_claim_type4 claim_type); static char *delegation_type_name(enum open_delegation_type4 type); static char *flavor_name(uint_t flavor); static char *gss_svc_name(rpc_gss_svc_t svc); static char *limitby_name(enum limit_by4 limitby); static char *lock_type_name(enum nfs_lock_type4); static char *opcode_name(uint_t); static char *cb_opcode_name(uint_t opnum); static char *status_name(int); static char *status_name_compat(int); static char *status_name_pcol(int); static char *sum_type_name(nfs_ftype4); static void sum_access4(char *buf, size_t buflen, uint32_t bits); static void detail_access4(char *, uint32_t); static void sum_claim(char *buf, size_t buflen, open_claim4 *claim); static void detail_claim(open_claim4 *claim); static char *sum_clientid(clientid4 client); static void detail_clientid(clientid4 client); static char *_sum_stateid(stateid4 *, char *prefix); static void sum_delegation(char *buf, size_t buflen, open_delegation4 *delp); static void detail_delegation(open_delegation4 *delp); static void detail_lock_owner(lock_owner4 *owner); static void detail_open_owner(open_owner4 *owner); static void sum_openflag(char *bufp, int buflen, openflag4 *flagp); static char *get_deleg_typestr(open_delegation_type4 dt); static void detail_openflag(openflag4 *flagp); static void sum_name(char *buf, size_t buflen, open_claim4 *claim); static void detail_rpcsec_gss(rpcsec_gss_info *); static void detail_secinfo4(secinfo4 *infop); static char *sum_space_limit(nfs_space_limit4 *limitp); static void detail_space_limit(nfs_space_limit4 *limitp); static char *detail_type_name(nfs_ftype4); static char *createhow4_name(createhow4 *crtp); static void showxdr_utf8string(char *); static char *utf8localize(utf8string *); static void utf8free(void); static void sum_pathname4(char *, size_t, pathname4 *); static void detail_pathname4(pathname4 *pathp, char *); static void sum_compname4(char *buf, size_t buflen, component4 *comp); static void detail_compname4(component4 *comp); static void detail_fattr4(fattr4 *attrp); static void detail_attr_bitmap(char *, bitmap4 *, unpkd_attrmap_t *); static void sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp); static void detail_fattr4_change(char *msg, fattr4_change chg); static char *sum_fh4(nfs_fh4 *fhp); static void detail_fh4(nfs_fh4 *fh); #define fh4_hash(fh) adler16((fh)->nfs_fh4_val, (fh)->nfs_fh4_len) #define stateid_hash(st) adler16((st)->other, sizeof ((st)->other)) #define owner_hash(own) adler16((own)->owner_val, (own)->owner_len) #define sum_deleg_stateid(st) _sum_stateid((st), "DST=") #define sum_open_stateid(st) _sum_stateid((st), "OST=") #define sum_lock_stateid(st) _sum_stateid((st), "LST=") #define sum_stateid(st) _sum_stateid((st), "ST=") #define detail_deleg_stateid(st) _detail_stateid((st), "Delegation ") #define detail_open_stateid(st) _detail_stateid((st), "Open ") #define detail_lock_stateid(st) _detail_stateid((st), "Lock ") #define detail_stateid(st) _detail_stateid((st), "") #define SPECIAL_STATEID0 "SPC0" #define SPECIAL_STATEID1 "SPC1" #define DONT_CHANGE 0 #define SET_TO_SERVER_TIME 1 #define SET_TO_CLIENT_TIME 2 static stateid4 spec_stateid_0 = {0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; static stateid4 spec_stateid_1 = {0xFFFFFFFF, {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}; static char *procnames_short[] = { "NULL4", /* 0 */ "COMPOUND4" /* 1 */ }; static char *procnames_long[] = { "Null procedure", /* 0 */ "Compound", /* 1 */ }; static char *cb_procnames_short[] = { "CB_NULL", /* 0 */ "CB_COMPOUND" /* 1 */ }; static char *cb_procnames_long[] = { "Null CallBack procedure", /* 0 */ "CallBack compound", /* 1 */ }; static char *acetype4_names[] = { "ACE4_ACCESS_ALLOWED_ACE_TYPE", "ACE4_ACCESS_DENIED_ACE_TYPE", "ACE4_SYSTEM_AUDIT_ACE_TYPE", "ACE4_SYSTEM_ALARM_ACE_TYPE" }; #define ACETYPE4_NAMES_MAX (sizeof (acetype4_names) / sizeof (char *)) static char *aceflag4_names[] = { "ACE4_FILE_INHERIT_ACE", "ACE4_DIRECTORY_INHERIT_ACE", "ACE4_NO_PROPAGATE_INHERIT_ACE", "ACE4_INHERIT_ONLY_ACE", "ACE4_SUCCESSFUL_ACCESS_ACE_FLAG", "ACE4_FAILED_ACCESS_ACE_FLAG", "ACE4_IDENTIFIER_GROUP" }; #define ACEFLAG4_NAMES_MAX (sizeof (aceflag4_names) / sizeof (char *)) static char *acemask4_names[] = { "ACE4_READ_DATA/ACE4_LIST_DIRECTORY", "ACE4_WRITE_DATA/ACE4_ADD_FILE", "ACE4_APPEND_DATA/ACE4_ADD_SUBDIRECTORY", "ACE4_READ_NAMED_ATTRS", "ACE4_WRITE_NAMED_ATTRS", "ACE4_EXECUTE", "ACE4_DELETE_CHILD", "ACE4_READ_ATTRIBUTES", "ACE4_WRITE_ATTRIBUTES", "UNDEFINED", /* 0x00000200 */ "UNDEFINED", /* 0x00000400 */ "UNDEFINED", /* 0x00000800 */ "UNDEFINED", /* 0x00001000 */ "UNDEFINED", /* 0x00002000 */ "UNDEFINED", /* 0x00004000 */ "UNDEFINED", /* 0x00008000 */ "ACE4_DELETE", "ACE4_READ_ACL", "ACE4_WRITE_ACL", "ACE4_WRITE_OWNER", "ACE4_SYNCHRONIZE" }; #define ACEMASK4_NAMES_MAX (sizeof (acemask4_names) / sizeof (char *)) #define MAXPROC 1 /*ARGSUSED*/ void interpret_nfs4_cb(int flags, int type, int xid, int vers, int proc, char *data, int len) { char *line = NULL; if (proc < 0 || proc > MAXPROC) return; if (flags & F_SUM) { line = get_sum_line(); if (type == CALL) { (void) sprintf(line, "NFS C %s", proc == CB_COMPOUND ? "CB4" : cb_procnames_short[proc]); line += strlen(line); if (proc == CB_COMPOUND) { static utf8string tag; if (!xdr_utf8string(&xdrm, &tag)) longjmp(xdr_err, 1); sprintf(line, " (%.20s) %s", utf8localize(&tag), sum_cb_compound4args()); xdr_free(xdr_utf8string, (char *)&tag); } check_retransmit(line, xid); } else { (void) sprintf(line, "NFS R %s ", proc == CB_COMPOUND ? "CB4" : cb_procnames_short[proc]); line += strlen(line); if (proc == CB_COMPOUND) sum_comp4res(line, sum_cb_compound4res); } } if (flags & F_DTAIL) { show_header("NFS: ", "Sun NFS4 CallBack", len); show_space(); (void) sprintf(get_line(0, 0), "Proc = %d (%s)", proc, cb_procnames_long[proc]); if (proc == CB_COMPOUND) { if (type == CALL) { showxdr_utf8string("Tag = %s"); detail_cb_argop4(); } else { nfsstat4 status; status = getxdr_long(); showxdr_utf8string("Tag = %s"); sprintf(get_line(0, 0), "Status = %d (%s)", status, status_name(status)); detail_cb_resop4(); } } show_trailer(); } utf8free(); /* cf. utf8localize() */ } /*ARGSUSED*/ void interpret_nfs4(int flags, int type, int xid, int vers, int proc, char *data, int len) { char *line = NULL; if (proc < 0 || proc > MAXPROC) return; nfs4_fragged_rpc = 0; nfs4_pkt_len = len; nfs4_pkt_start = xdr_getpos(&xdrm); if (flags & F_SUM) { line = get_sum_line(); if (type == CALL) { (void) sprintf(line, "NFS C %s", proc == NFSPROC4_COMPOUND ? "4" : procnames_short[proc]); line += strlen(line); if (proc == NFSPROC4_COMPOUND) { static utf8string tag; if (!xdr_utf8string(&xdrm, &tag)) longjmp(xdr_err, 1); sprintf(line, " (%.20s) %s", utf8localize(&tag), sum_compound4args()); xdr_free(xdr_utf8string, (char *)&tag); } check_retransmit(line, xid); } else { (void) sprintf(line, "NFS R %s ", proc == NFSPROC4_COMPOUND ? "4" : procnames_short[proc]); line += strlen(line); if (proc == NFSPROC4_COMPOUND) sum_comp4res(line, sum_compound4res); } } 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 (proc == NFSPROC4_COMPOUND) { if (type == CALL) { showxdr_utf8string("Tag = %s"); detail_nfs_argop4(); } else { nfsstat4 status; status = getxdr_long(); showxdr_utf8string("Tag = %s"); sprintf(get_line(0, 0), "Status = %d (%s)", status, status_name(status)); detail_nfs_resop4(); } } show_trailer(); } utf8free(); /* cf. utf8localize() */ } /* * Return the names and arguments of the oplist elements, up to * SUM_COMPND_MAX characters. If the elements don't fit, include a "..." * at the end of the string. */ static char * sum_compound4args(void) { static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */ int numops; const size_t buflen = sizeof (buf); char *bp; nfs_argop4 one_op; uint32_t minor_version; buf[0] = '\0'; if (setjmp(xdr_err)) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag); return (buf); } /* * might be nice to print minor version, but doesn't * seem like very useful info for summary mode */ if (!xdr_uint32_t(&xdrm, &minor_version)) longjmp(xdr_err, 1); numops = getxdr_long(); bp = buf; while (numops-- > 0) { char *operand; bzero(&one_op, sizeof (one_op)); if (!xdr_nfs_argop4(&xdrm, &one_op)) { xdr_free(xdr_nfs_argop4, (char *)&one_op); longjmp(xdr_err, 1); } snprintf(bp, buflen - (bp - buf), "%s ", opcode_name(one_op.argop)); bp += strlen(bp); operand = sum_operand(&one_op); if (strlen(operand) > 0) { snprintf(bp, buflen - (bp - buf), "%s ", operand); bp += strlen(bp); } /* nfs4_skip_bytes set by xdr_nfs4_argop4 */ if (nfs4_skip_bytes != 0) nfs4_xdr_skip(nfs4_skip_bytes); xdr_free(xdr_nfs_argop4, (char *)&one_op); /* add "..." if past the "end" of the buffer */ if (bp - buf > SUM_COMPND_MAX) { strcpy(buf + SUM_COMPND_MAX - strlen("..."), "..."); break; } } return (buf); } static void nfs4_xdr_skip(int nbytes) { int resid, off, len, cur_pos, new_pos; len = RNDUP(nbytes); cur_pos = xdr_getpos(&xdrm); /* * Time to skip over the rd/wr data. If the * rd/wr data is completely contained in the first * frag, we must skip over it to process the rest of * the packet. * * nfs4_pkt_start: XDR position of start of NFS4 compound * nfs4_pkt_len: number of bytes in pkt relative to * nfs4_pkt_start * * cur_pos: current XDR position * off: current XDR position relative to nfs4_pkt_start * resid: number of unprocessed bytes in current pkt * (relative to cur_pos/off) * * If nbytes <= resid, then we must skip over the rd/wr * bytes so we can read the next op/compound in this * packet. Otherwise, set the fragged flag so we can * display the fragged_rpc message. */ off = cur_pos - nfs4_pkt_start; resid = nfs4_pkt_len - off; /* * set nfs4_fragged_rpc if the requested number of "skip" * bytes is larger than the bytes remaining in the XDR * stream/current packet. The global is reset to 0 at * start of interpret_nfs4. */ new_pos = cur_pos + ((nfs4_fragged_rpc = len > resid) ? resid : len); /* there's nothing to do for error case (if it fails pkt is doomed) */ xdr_setpos(&xdrm, new_pos); } /* * Return the names and arguments of the oplist elements, up to * SUM_COMPND_MAX characters. If the elements don't fit, include a "..." * at the end of the string. */ static char * sum_cb_compound4args(void) { static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */ int numops; const size_t buflen = sizeof (buf); char *bp; nfs_cb_argop4 one_op; uint32_t minor_version, callback_ident; buf[0] = '\0'; if (setjmp(xdr_err)) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), ""); return (buf); } /* * might be nice to print minor version, but doesn't * seem like very useful info for summary mode */ if (!xdr_uint32_t(&xdrm, &minor_version)) longjmp(xdr_err, 1); /* print callback_ident */ if (!xdr_uint32_t(&xdrm, &callback_ident)) longjmp(xdr_err, 1); snprintf(buf, buflen, "CBID=%u ", callback_ident); bp = buf + strlen(buf); numops = getxdr_long(); while (numops-- > 0) { char *operand; bzero(&one_op, sizeof (one_op)); if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) { xdr_free(xdr_nfs_cb_argop4, (char *)&one_op); longjmp(xdr_err, 1); } snprintf(bp, buflen - (bp - buf), "%s ", cb_opcode_name(one_op.argop)); bp += strlen(bp); operand = sum_cb_operand(&one_op); if (strlen(operand) > 0) { snprintf(bp, buflen - (bp - buf), "%s ", operand); bp += strlen(bp); } xdr_free(xdr_nfs_cb_argop4, (char *)&one_op); /* add "..." if past the "end" of the buffer */ if (bp - buf > SUM_COMPND_MAX) { strcpy(buf + SUM_COMPND_MAX - strlen("..."), "..."); break; } } return (buf); } /* * Return the summarized argument list for the given nfs_argop4. */ static char * sum_operand(nfs_argop4 *opp) { static char buf[1024]; void (*fmtproc)(char *, size_t, void *); buf[0] = '\0'; if (opp->argop < num_opcodes) { fmtproc = opcode_info[opp->argop].sumarg; if (fmtproc != NULL) fmtproc(buf, sizeof (buf), &opp->nfs_argop4_u); } return (buf); } /* * Return the summarized argument list for the given nfs_argop4. */ static char * sum_cb_operand(nfs_cb_argop4 *opp) { static char buf[1024]; void (*fmtproc)(char *, size_t, void *); buf[0] = '\0'; if (opp->argop < cb_num_opcodes) { fmtproc = cb_opcode_info[opp->argop].sumarg; if (fmtproc != NULL) fmtproc(buf, sizeof (buf), &opp->nfs_cb_argop4_u); } return (buf); } /* * Print details about the nfs_argop4 that is next in the XDR stream. */ static void detail_nfs_argop4(void) { int numops; nfs_argop4 one_op; void (*fmtproc)(void *); uint32_t minor_version; if (!xdr_uint32_t(&xdrm, &minor_version)) longjmp(xdr_err, 1); (void) sprintf(get_line(0, 0), "Minor version = %u", minor_version); numops = getxdr_long(); (void) sprintf(get_line(0, 0), "Number of operations = %d", numops); while (numops-- > 0) { bzero(&one_op, sizeof (one_op)); if (!xdr_nfs_argop4(&xdrm, &one_op)) { xdr_free(xdr_nfs_argop4, (char *)&one_op); longjmp(xdr_err, 1); } get_line(0, 0); /* blank line to separate ops */ sprintf(get_line(0, 0), "Op = %d (%s)", one_op.argop, opcode_name(one_op.argop)); if (one_op.argop < num_opcodes) { fmtproc = opcode_info[one_op.argop].dtlarg; if (fmtproc != NULL) fmtproc(&one_op.nfs_argop4_u); } /* nfs4_skip_bytes set by xdr_nfs_argop4() */ if (nfs4_skip_bytes) nfs4_xdr_skip(nfs4_skip_bytes); xdr_free(xdr_nfs_argop4, (char *)&one_op); } } /* * Print details about the nfs_argop4 that is next in the XDR stream. */ static void detail_cb_argop4(void) { int numops; nfs_cb_argop4 one_op; void (*fmtproc)(void *); uint32_t minor_version, callback_ident; if (!xdr_uint32_t(&xdrm, &minor_version)) longjmp(xdr_err, 1); (void) sprintf(get_line(0, 0), "Minor version = %u", minor_version); if (!xdr_uint32_t(&xdrm, &callback_ident)) longjmp(xdr_err, 1); (void) sprintf(get_line(0, 0), "Callback Ident = %u", callback_ident); numops = getxdr_long(); (void) sprintf(get_line(0, 0), "Number of operations = %d", numops); while (numops-- > 0) { bzero(&one_op, sizeof (one_op)); if (!xdr_nfs_cb_argop4(&xdrm, &one_op)) { xdr_free(xdr_nfs_cb_argop4, (char *)&one_op); longjmp(xdr_err, 1); } get_line(0, 0); /* blank line to separate ops */ sprintf(get_line(0, 0), "Op = %d (%s)", one_op.argop, cb_opcode_name(one_op.argop)); if (one_op.argop < cb_num_opcodes) { fmtproc = cb_opcode_info[one_op.argop].dtlarg; if (fmtproc != NULL) fmtproc(&one_op.nfs_cb_argop4_u); } xdr_free(xdr_nfs_cb_argop4, (char *)&one_op); } } /* * component_name: return a printable string for the given component4. I'm * leaving this as a separate function (as opposed to having the callers * call utf8localize() directly) in case the definition of component4 * changes. */ static char * component_name(component4 *cp) { return (utf8localize(cp)); } /* * linktext_name. cf. component_name(). */ static char * linktext_name(linktext4 *lp) { return (utf8localize((utf8string *)lp)); } /* * stable_how4_name: return a string for "how". */ static char * stable_how4_name(stable_how4 how) { char *result; switch (how) { case UNSTABLE4: result = "ASYNC"; break; case DATA_SYNC4: result = "DSYNC"; break; case FILE_SYNC4: result = "FSYNC"; break; default: result = "?"; break; } return (result); } /* * sum_open_share_access: return a string corresponding to the * given OPEN share access bitmask. */ static char * sum_open_share_access(int32_t mask) { char *result; switch (mask) { case 0: result = "N"; break; case OPEN4_SHARE_ACCESS_READ: result = "R"; break; case OPEN4_SHARE_ACCESS_WRITE: result = "W"; break; case OPEN4_SHARE_ACCESS_BOTH: result = "RW"; break; default: result = "?"; break; } return (result); } /* * sum_open_share_deny: return a string corresponding to the * given OPEN share deny bitmask. */ static char * sum_open_share_deny(int32_t mask) { char *result; switch (mask) { case OPEN4_SHARE_DENY_NONE: result = "N"; break; case OPEN4_SHARE_DENY_READ: result = "R"; break; case OPEN4_SHARE_DENY_WRITE: result = "W"; break; case OPEN4_SHARE_DENY_BOTH: result = "RW"; break; default: result = "?"; break; } return (result); } static int special_stateid(stateid4 *stateid) { if (! memcmp(stateid, &spec_stateid_0, sizeof (*stateid))) return (0); if (! memcmp(stateid, &spec_stateid_1, sizeof (*stateid))) return (1); return (-1); } static char * _sum_stateid(stateid4 *stateid, char *prefix) { static char buf[32]; int spec; if ((spec = special_stateid(stateid)) < 0) snprintf(buf, sizeof (buf), "%s%04X:%u", prefix, stateid_hash(stateid), stateid->seqid); else snprintf(buf, sizeof (buf), "%s%s", prefix, spec == 0 ? "SPC0" : (spec == 1 ? "SPC1" : "SPC?")); return (buf); } static void _detail_stateid(stateid4 *stateid, char *prefix) { int spec; char seqstr[32] = {0}; spec = special_stateid(stateid); if (spec < 0) sprintf(get_line(0, 0), "%sState ID hash = %04X", prefix, stateid_hash(stateid)); else sprintf(get_line(0, 0), "%sState ID hash = %s", prefix, spec == 0 ? "SPECIAL_0" : (spec == 1 ? "SPECIAL_1" : "SPECIAL_?")); sprintf(get_line(0, 0), " len = %u val = %s", sizeof (stateid->other), tohex(stateid->other, sizeof (stateid->other))); /* * If spec 0/1 stateid, print seqid in hex; otherwise, * use decimal. This makes it more clear how spec stateids * are constructed [obvious that either all bits are 0, or all * bits are 1]. */ if (spec == -1) sprintf(seqstr, "%d", stateid->seqid); else sprintf(seqstr, "%08X", stateid->seqid); sprintf(get_line(0, 0), " %sState ID Sequence ID = %s", prefix, seqstr); } static char * sum_lock_denied(LOCK4denied *denied) { static char buf[64]; sprintf(buf, "%s %llu:%llu LO=%04X", sum_lock_type_name(denied->locktype), denied->offset, denied->length, owner_hash(&denied->owner.owner)); return (buf); } static void detail_lock_denied(LOCK4denied *denied) { sprintf(get_line(0, 0), "Type = %s", lock_type_name(denied->locktype)); detail_lock_owner(&denied->owner); sprintf(get_line(0, 0), "Offset = %llu", denied->offset); sprintf(get_line(0, 0), "Length = %llu", denied->length); } /* * sum_createhow4: return the string name of "how". */ static char * createhow4_name(createhow4 *crtp) { char *result; switch (crtp->mode) { case UNCHECKED4: result = "UNCHECKED"; break; case GUARDED4: result = "GUARDED"; break; case EXCLUSIVE4: result = "EXCLUSIVE"; break; default: result = "?"; break; } return (result); } /* * detail_createhow4: print detail information about "how". */ static void detail_createhow4(createhow4 *crtp) { sprintf(get_line(0, 0), "Method = %s", createhow4_name(crtp)); switch (crtp->mode) { case UNCHECKED4: case GUARDED4: detail_fattr4(&crtp->createhow4_u.createattrs); break; case EXCLUSIVE4: sprintf(get_line(0, 0), " Verifier = %s", tohex(crtp->createhow4_u.createverf, NFS4_VERIFIER_SIZE)); break; } } static void detail_createtype4(createtype4 *crtp) { sprintf(get_line(0, 0), "Type = %s", detail_type_name(crtp->type)); switch (crtp->type) { case NF4LNK: sprintf(get_line(0, 0), "Linkdata = %s", utf8localize((utf8string *)&crtp->createtype4_u.linkdata)); break; case NF4BLK: case NF4CHR: sprintf(get_line(0, 0), "Specdata1 = %04x Specdata2 = %04x", crtp->createtype4_u.devdata.specdata1, crtp->createtype4_u.devdata.specdata2); break; default: break; } } static void sumarg_access(char *buf, size_t buflen, void *obj) { ACCESS4args *args = (ACCESS4args *)obj; sum_access4(buf, buflen, args->access); } static void dtlarg_access(void *obj) { ACCESS4args *args = (ACCESS4args *)obj; detail_access4("Access bits", args->access); } static void sumarg_close(char *buf, size_t buflen, void *obj) { CLOSE4args *args = (CLOSE4args *)obj; snprintf(buf, buflen, "SQ=%u %s", args->seqid, sum_open_stateid(&args->open_stateid)); } static void dtlarg_close(void *obj) { CLOSE4args *args = (CLOSE4args *)obj; detail_open_stateid(&args->open_stateid); sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid); } static void sumarg_commit(char *buf, size_t buflen, void *obj) { COMMIT4args *args = (COMMIT4args *)obj; snprintf(buf, buflen, "at %llu for %u ", args->offset, args->count); } static void dtlarg_commit(void *obj) { COMMIT4args *args = (COMMIT4args *)obj; sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Count = %u", args->count); } static void sumarg_compnt(char *buf, size_t buflen, void *obj) { component4 *comp = (component4 *)obj; snprintf(buf, buflen, "%s", component_name(comp)); } static void dtlarg_compnt(void *obj) { component4 *comp = (component4 *)obj; sprintf(get_line(0, 0), "Name = %s", component_name(comp)); } static void sumarg_create(char *buf, size_t buflen, void *obj) { CREATE4args *args = (CREATE4args *)obj; snprintf(buf, buflen, "%s %s ", component_name(&args->objname), sum_type_name(args->objtype.type)); } static void dtlarg_create(void *obj) { CREATE4args *args = (CREATE4args *)obj; sprintf(get_line(0, 0), "Name = %s", component_name(&args->objname)); detail_createtype4(&args->objtype); detail_fattr4(&args->createattrs); } static void sumarg_delprge(char *buf, size_t buflen, void *obj) { DELEGPURGE4args *args = (DELEGPURGE4args *)obj; snprintf(buf, buflen, "%s", sum_clientid(args->clientid)); } static void dtlarg_delprge(void *obj) { DELEGPURGE4args *args = (DELEGPURGE4args *)obj; detail_clientid(args->clientid); } static void sumarg_delret(char *buf, size_t buflen, void *obj) { DELEGRETURN4args *args = (DELEGRETURN4args *)obj; snprintf(buf, buflen, "%s", sum_deleg_stateid(&args->deleg_stateid)); } static void dtlarg_delret(void *obj) { DELEGRETURN4args *args = (DELEGRETURN4args *)obj; detail_deleg_stateid(&args->deleg_stateid); } static void sumarg_getattr(char *buf, size_t buflen, void *obj) { GETATTR4args *args = (GETATTR4args *)obj; sum_attr_bitmap(buf, buflen, &args->attr_request); } static void dtlarg_getattr(void *obj) { GETATTR4args *args = (GETATTR4args *)obj; detail_attr_bitmap("", &args->attr_request, NULL); } static void sumarg_cb_getattr(char *buf, size_t buflen, void *obj) { CB_GETATTR4args *args = (CB_GETATTR4args *)obj; char *bp = buf; snprintf(bp, buflen, "%s ", sum_fh4(&args->fh)); bp += strlen(bp); sum_attr_bitmap(bp, buflen - (bp - buf), &args->attr_request); } static void dtlarg_cb_getattr(void *obj) { CB_GETATTR4args *args = (CB_GETATTR4args *)obj; detail_fh4(&args->fh); detail_attr_bitmap("", &args->attr_request, NULL); } static void sumarg_cb_recall(char *buf, size_t buflen, void *obj) { CB_RECALL4args *args = (CB_RECALL4args *)obj; char *bp = buf; snprintf(bp, buflen, "%s %s TR=%s", sum_fh4(&args->fh), sum_stateid(&args->stateid), args->truncate ? "T" : "F"); } static void dtlarg_cb_recall(void *obj) { CB_RECALL4args *args = (CB_RECALL4args *)obj; detail_fh4(&args->fh); detail_stateid(&args->stateid); sprintf(get_line(0, 0), "Truncate = %s", args->truncate ? "True" : "False"); } /* * name openhow seqid claim access deny owner */ static void sumarg_open(char *buf, size_t buflen, void *obj) { OPEN4args *args = (OPEN4args *)obj; char *bp = buf; int blen = buflen, len; sum_name(bp, buflen, &args->claim); bp += (len = strlen(bp)); blen -= len; sum_openflag(bp, blen, &args->openhow); bp += (len = strlen(bp)); blen -= len; snprintf(bp, blen, " SQ=%u", args->seqid); bp += (len = strlen(bp)); blen -= len; sum_claim(bp, blen, &args->claim); bp += (len = strlen(bp)); blen -= len; snprintf(bp, blen, " AC=%s DN=%s OO=%04X", sum_open_share_access(args->share_access), sum_open_share_deny(args->share_deny), owner_hash(&args->owner.owner)); } static void dtlarg_open(void *obj) { OPEN4args *args = (OPEN4args *)obj; detail_claim(&args->claim); detail_openflag(&args->openhow); detail_open_owner(&args->owner); sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid); sprintf(get_line(0, 0), "Access = 0x%x (%s)", args->share_access, sum_open_share_access(args->share_access)); sprintf(get_line(0, 0), "Deny = 0x%x (%s)", args->share_deny, sum_open_share_access(args->share_deny)); } static void sumarg_openattr(char *buf, size_t buflen, void *obj) { OPENATTR4args *args = (OPENATTR4args *)obj; snprintf(buf, buflen, "CD=%s", args->createdir ? "T" : "F"); } static void dtlarg_openattr(void *obj) { OPENATTR4args *args = (OPENATTR4args *)obj; sprintf(get_line(0, 0), "CreateDir = %s", args->createdir ? "True" : "False"); } static void sumarg_open_confirm(char *buf, size_t buflen, void *obj) { char *bp = buf; OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj; snprintf(bp, buflen, "SQ=%u %s", args->seqid, sum_open_stateid(&args->open_stateid)); } static void dtlarg_open_confirm(void *obj) { OPEN_CONFIRM4args *args = (OPEN_CONFIRM4args *)obj; sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid); detail_open_stateid(&args->open_stateid); } static void sumarg_open_downgrd(char *buf, size_t buflen, void *obj) { OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj; snprintf(buf, buflen, "SQ=%u %s AC=%s DN=%s", args->seqid, sum_open_stateid(&args->open_stateid), sum_open_share_access(args->share_access), sum_open_share_deny(args->share_deny)); } static void dtlarg_open_downgrd(void *obj) { OPEN_DOWNGRADE4args *args = (OPEN_DOWNGRADE4args *)obj; sprintf(get_line(0, 0), "Open Sequence ID = %u", args->seqid); detail_open_stateid(&args->open_stateid); sprintf(get_line(0, 0), "Access = 0x%x (%s)", args->share_access, sum_open_share_access(args->share_access)); sprintf(get_line(0, 0), "Deny = 0x%x (%s)", args->share_deny, sum_open_share_access(args->share_deny)); } static void sumarg_putfh(char *buf, size_t buflen, void *obj) { PUTFH4args *args = (PUTFH4args *)obj; snprintf(buf, buflen, "%s", sum_fh4(&args->object)); } static void dtlarg_putfh(void *obj) { PUTFH4args *args = (PUTFH4args *)obj; detail_fh4(&args->object); } static void sumarg_link(char *buf, size_t buflen, void *obj) { LINK4args *args = (LINK4args *)obj; snprintf(buf, buflen, "%s", component_name(&args->newname)); } static void dtlarg_link(void *obj) { LINK4args *args = (LINK4args *)obj; sprintf(get_line(0, 0), "New name = %s", component_name(&args->newname)); } static void sum_open_to_lock_owner(char *buf, int buflen, open_to_lock_owner4 *own) { snprintf(buf, buflen, " OSQ=%u %s LSQ=%u LO=%04X", own->open_seqid, sum_open_stateid(&own->open_stateid), own->lock_seqid, owner_hash(&own->lock_owner.owner)); } static void sum_exist_lock_owner(char *buf, int buflen, exist_lock_owner4 *own) { snprintf(buf, buflen, " LSQ=%u %s", own->lock_seqid, sum_lock_stateid(&own->lock_stateid)); } static void sum_locker(char *buf, size_t len, locker4 *lk) { if (lk->new_lock_owner == TRUE) sum_open_to_lock_owner(buf, len, &lk->locker4_u.open_owner); else sum_exist_lock_owner(buf, len, &lk->locker4_u.lock_owner); } static char * sum_lock_type_name(enum nfs_lock_type4 type) { char *result; switch (type) { case READ_LT: result = "RD"; break; case WRITE_LT: result = "WR"; break; case READW_LT: result = "RDW"; break; case WRITEW_LT: result = "WRW"; break; default: result = "?"; break; } return (result); } static void sumarg_lock(char *buf, size_t buflen, void *obj) { LOCK4args *args = (LOCK4args *)obj; char *bp = buf; snprintf(buf, buflen, "%s%s%llu:%llu", sum_lock_type_name(args->locktype), args->reclaim ? " reclaim " : " ", args->offset, args->length); bp += strlen(buf); sum_locker(bp, buflen - (bp - buf), &args->locker); } static void detail_open_to_lock_owner(open_to_lock_owner4 *own) { sprintf(get_line(0, 0), "Open Sequence ID = %u", own->open_seqid); detail_open_stateid(&own->open_stateid); sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid); detail_lock_owner(&own->lock_owner); } static void detail_exist_lock_owner(exist_lock_owner4 *own) { detail_lock_stateid(&own->lock_stateid); sprintf(get_line(0, 0), "Lock Sequence ID = %u", own->lock_seqid); } static void detail_locker(locker4 *lk) { if (lk->new_lock_owner == TRUE) detail_open_to_lock_owner(&lk->locker4_u.open_owner); else detail_exist_lock_owner(&lk->locker4_u.lock_owner); } static void dtlarg_lock(void *obj) { LOCK4args *args = (LOCK4args *)obj; sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype)); sprintf(get_line(0, 0), "Reclaim = %s", args->reclaim ? "TRUE" : "FALSE"); sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Length = %llu", args->length); detail_locker(&args->locker); } static void sumarg_lockt(char *buf, size_t buflen, void *obj) { LOCKT4args *args = (LOCKT4args *)obj; snprintf(buf, buflen, "%s %llu:%llu", sum_lock_type_name(args->locktype), args->offset, args->length); } static void dtlarg_lockt(void *obj) { LOCKT4args *args = (LOCKT4args *)obj; sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype)); detail_lock_owner(&args->owner); sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Length = %llu", args->length); } static void sumarg_locku(char *buf, size_t buflen, void *obj) { LOCKU4args *args = (LOCKU4args *)obj; snprintf(buf, buflen, "%llu:%llu LSQ=%u %s", args->offset, args->length, args->seqid, sum_lock_stateid(&args->lock_stateid)); } static void dtlarg_locku(void *obj) { LOCKU4args *args = (LOCKU4args *)obj; sprintf(get_line(0, 0), "Type = %s", lock_type_name(args->locktype)); sprintf(get_line(0, 0), "Sequence ID = %u", args->seqid); detail_lock_stateid(&args->lock_stateid); sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Length = %llu", args->length); } static void sumarg_lookup(char *buf, size_t buflen, void *obj) { LOOKUP4args *args = (LOOKUP4args *)obj; sum_compname4(buf, buflen, &args->objname); } static void dtlarg_lookup(void *obj) { LOOKUP4args *args = (LOOKUP4args *)obj; detail_compname4(&args->objname); } static void sumarg_read(char *buf, size_t buflen, void *obj) { READ4args *args = (READ4args *)obj; snprintf(buf, buflen, "%s at %llu for %u", sum_stateid(&args->stateid), args->offset, args->count); } static void dtlarg_read(void *obj) { READ4args *args = (READ4args *)obj; sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Count = %u", args->count); detail_stateid(&args->stateid); } static void sumarg_readdir(char *buf, size_t buflen, void *obj) { READDIR4args *args = (READDIR4args *)obj; snprintf(buf, buflen, "Cookie=%llu (%s) for %u/%u", args->cookie, tohex(args->cookieverf, NFS4_VERIFIER_SIZE), args->dircount, args->maxcount); } static void dtlarg_readdir(void *obj) { READDIR4args *args = (READDIR4args *)obj; sprintf(get_line(0, 0), "Cookie = %llu", args->cookie); sprintf(get_line(0, 0), "Verifier = %s", tohex(args->cookieverf, NFS4_VERIFIER_SIZE)); sprintf(get_line(0, 0), "Dircount = %u", args->dircount); sprintf(get_line(0, 0), "Maxcount = %u", args->maxcount); detail_attr_bitmap("", &args->attr_request, NULL); } static void dtlarg_release_lkown(void *obj) { RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj; detail_lock_owner(&args->lock_owner); } static void sumarg_release_lkown(char *buf, size_t buflen, void *obj) { RELEASE_LOCKOWNER4args *args = (RELEASE_LOCKOWNER4args *)obj; snprintf(buf, buflen, "LO=%04X", owner_hash(&args->lock_owner.owner)); } static void sumarg_rename(char *buf, size_t buflen, void *obj) { RENAME4args *args = (RENAME4args *)obj; snprintf(buf, buflen, "%s to %s", component_name(&args->oldname), component_name(&args->newname)); } static void dtlarg_rename(void *obj) { RENAME4args *args = (RENAME4args *)obj; sprintf(get_line(0, 0), "Old name = %s", component_name(&args->oldname)); sprintf(get_line(0, 0), "New name = %s", component_name(&args->newname)); } static void sumarg_renew(char *buf, size_t buflen, void *obj) { RENEW4args *args = (RENEW4args *)obj; snprintf(buf, buflen, "%s", sum_clientid(args->clientid)); } static void dtlarg_renew(void *obj) { RENEW4args *args = (RENEW4args *)obj; detail_clientid(args->clientid); } static void sumarg_secinfo(char *buf, size_t buflen, void *obj) { SECINFO4args *args = (SECINFO4args *)obj; snprintf(buf, buflen, "%s", component_name(&args->name)); } static void dtlarg_secinfo(void *obj) { SECINFO4args *args = (SECINFO4args *)obj; sprintf(get_line(0, 0), "Name = %s", component_name(&args->name)); } static void sumarg_setattr(char *buf, size_t buflen, void *obj) { SETATTR4args *args = (SETATTR4args *)obj; snprintf(buf, buflen, "%s", sum_stateid(&args->stateid)); } static void dtlarg_setattr(void *obj) { SETATTR4args *args = (SETATTR4args *)obj; detail_stateid(&args->stateid); detail_fattr4(&args->obj_attributes); } static void sumarg_setclid(char *buf, size_t buflen, void *obj) { SETCLIENTID4args *args = (SETCLIENTID4args *)obj; snprintf(buf, buflen, "Prog=%u ID=%s Addr=%s CBID=%u", args->callback.cb_program, args->callback.cb_location.r_netid, args->callback.cb_location.r_addr, args->callback_ident); } static void dtlarg_setclid(void *obj) { SETCLIENTID4args *args = (SETCLIENTID4args *)obj; sprintf(get_line(0, 0), "Verifier=%s", tohex(args->client.verifier, NFS4_VERIFIER_SIZE)); sprintf(get_line(0, 0), "ID = (%d) %s", args->client.id.id_len, tohex(args->client.id.id_val, args->client.id.id_len)); sprintf(get_line(0, 0), "Callback Program = %u", args->callback.cb_program); sprintf(get_line(0, 0), "Callback Net ID = %s", args->callback.cb_location.r_netid); sprintf(get_line(0, 0), "Callback Addr = %s", args->callback.cb_location.r_addr); sprintf(get_line(0, 0), "Callback Ident = %u", args->callback_ident); } static void sumarg_setclid_cfm(char *buf, size_t buflen, void *obj) { SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj; snprintf(buf, buflen, "%s CFV=%s", sum_clientid(args->clientid), tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE)); } static void dtlarg_setclid_cfm(void *obj) { SETCLIENTID_CONFIRM4args *args = (SETCLIENTID_CONFIRM4args *)obj; detail_clientid(args->clientid); sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s", tohex(args->setclientid_confirm, NFS4_VERIFIER_SIZE)); } static void dtlarg_verify(void *obj) { NVERIFY4args *args = (NVERIFY4args *)obj; detail_fattr4(&args->obj_attributes); } static void sumarg_write(char *buf, size_t buflen, void *obj) { WRITE4args *args = (WRITE4args *)obj; snprintf(buf, buflen, "%s at %llu for %u", sum_stateid(&args->stateid), args->offset, args->data.data_len); } static void dtlarg_write(void *obj) { WRITE4args *args = (WRITE4args *)obj; sprintf(get_line(0, 0), "Offset = %llu", args->offset); sprintf(get_line(0, 0), "Count = %u", args->data.data_len); sprintf(get_line(0, 0), "Stable = %s", stable_how4_name(args->stable)); detail_stateid(&args->stateid); } static char * sum_fh4(nfs_fh4 *fh) { static char buf[20]; sprintf(buf, "FH=%04X", fh4_hash(fh)); return (buf); } static void detail_fh4(nfs_fh4 *fh) { int i; uchar_t *cp; char *bufp; sprintf(get_line(0, 0), "File handle = [%04X]", fh4_hash(fh)); bufp = get_line(0, 0); sprintf(bufp, "(%d) ", fh->nfs_fh4_len); bufp += strlen(bufp); /* XXX use tohex()? */ for (i = 0, cp = (uchar_t *)fh->nfs_fh4_val; i < fh->nfs_fh4_len; i++, cp++) { if (i != 0 && i % 32 == 0) bufp = get_line(0, 0); sprintf(bufp, "%02x", *cp); bufp += strlen(bufp); } } static void detail_fattr4(fattr4 *attrp) { unpkd_attrmap_t provided; uint_t attrnum; XDR attrxdr; jmp_buf old_errbuf; xdrmem_create(&attrxdr, attrp->attr_vals.attrlist4_val, attrp->attr_vals.attrlist4_len, XDR_DECODE); bcopy(xdr_err, old_errbuf, sizeof (old_errbuf)); if (setjmp(xdr_err)) { sprintf(get_line(0, 0), ""); goto done; } detail_attr_bitmap("", &attrp->attrmask, &provided); for (attrnum = 0; attrnum < MAX_ATTRIBUTES; attrnum++) { if (provided.map[attrnum]) { attr_info[attrnum].prt_details(&attrxdr); } } done: bcopy(old_errbuf, xdr_err, sizeof (old_errbuf)); } static void sum_attr_bitmap(char *buf, size_t buflen, bitmap4 *mapp) { uint_t num_words; char *bp; size_t curlen, remaining; buf[0] = '\0'; for (num_words = 0; num_words < mapp->bitmap4_len; num_words++) { curlen = strlen(buf); if (curlen + sizeof ("") >= buflen) { strcpy(buf + buflen - sizeof (""), ""); return; } bp = buf + curlen; remaining = buflen - curlen; snprintf(bp, remaining, num_words == 0 ? "%x" : " %x", mapp->bitmap4_val[num_words]); } } /* * Print detail information for the given attribute bitmap, and fill in the * unpacked version of the map if "unpacked" is non-null. Returns the * number of bytes in the bitmap. "prefix" is an initial string that is * printed at the front of each line. */ static void detail_attr_bitmap(char *prefix, bitmap4 *bitp, unpkd_attrmap_t *unpacked) { uint_t num_words; uint32_t *wp; uint_t byte_num; if (unpacked != NULL) memset(unpacked, 0, sizeof (unpkd_attrmap_t)); /* * Break the bitmap into octets, then print in hex and * symbolically. */ for (num_words = 0, wp = bitp->bitmap4_val; num_words < bitp->bitmap4_len; num_words++, wp++) { for (byte_num = 0; byte_num < 4; byte_num++) { uchar_t val = (*wp) >> (byte_num * 8); char *buf = get_line(0, 0); uint_t attrnum; int bit; sprintf(buf, "%s 0x%02x ", prefix, val); attrnum = num_words * 32 + byte_num * 8; for (bit = 7; bit >= 0; bit--) { if (val & (1 << bit)) { strcat(buf, " "); strcat(buf, attr_name(attrnum + bit)); if (unpacked != NULL) unpacked->map[attrnum + bit] = 1; } } } } } /* * Format the summary line results from a COMPOUND4 call. */ static void sum_comp4res(char *line, char *(*sumres_fn)(void)) { nfsstat4 status; static utf8string tag; status = getxdr_long(); if (!xdr_utf8string(&xdrm, &tag)) longjmp(xdr_err, 1); sprintf(line, "(%.20s) %s %s", utf8localize(&tag), status_name(status), sumres_fn()); xdr_free(xdr_utf8string, (char *)&tag); } /* * Return a set of summary strings for the result data that's next in the * XDR stream, up to SUM_COMPND_MAX characters. If the strings don't fit, * include a "..." at the end of the string. */ static char * sum_compound4res(void) { static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */ int numres; const size_t buflen = sizeof (buf); char *bp; nfs_resop4 one_res; buf[0] = '\0'; if (setjmp(xdr_err)) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), nfs4_fragged_rpc ? nfs4err_fragrpc : nfs4err_xdrfrag); return (buf); } numres = getxdr_long(); bp = buf; while (numres-- > 0) { char *result; bzero(&one_res, sizeof (one_res)); if (!xdr_nfs_resop4(&xdrm, &one_res)) { xdr_free(xdr_nfs_resop4, (char *)&one_res); longjmp(xdr_err, 1); } snprintf(bp, buflen - (bp - buf), "%s ", opcode_name(one_res.resop)); bp += strlen(bp); result = sum_result(&one_res); if (strlen(result) > 0) { snprintf(bp, buflen - (bp - buf), "%s ", result); bp += strlen(bp); } /* nfs4_skip_bytes set by xdr_nfs4_argop4() */ if (nfs4_skip_bytes != 0) nfs4_xdr_skip(nfs4_skip_bytes); xdr_free(xdr_nfs_resop4, (char *)&one_res); /* add "..." if past the "end" of the buffer */ if (bp - buf > SUM_COMPND_MAX) { strcpy(buf + SUM_COMPND_MAX - strlen("..."), "..."); break; } } return (buf); } /* * Return a set of summary strings for the result data that's next in the * XDR stream, up to SUM_COMPND_MAX characters. If the strings don't fit, * include a "..." at the end of the string. */ static char * sum_cb_compound4res(void) { static char buf[SUM_COMPND_MAX + 2]; /* 1 for null, 1 for overflow */ int numres; const size_t buflen = sizeof (buf); char *bp; nfs_cb_resop4 one_res; buf[0] = '\0'; if (setjmp(xdr_err)) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), ""); return (buf); } numres = getxdr_long(); bp = buf; while (numres-- > 0) { bzero(&one_res, sizeof (one_res)); if (!xdr_nfs_cb_resop4(&xdrm, &one_res)) { xdr_free(xdr_nfs_cb_resop4, (char *)&one_res); longjmp(xdr_err, 1); } snprintf(bp, buflen - (bp - buf), "%s %s ", cb_opcode_name(one_res.resop), sum_cb_result(&one_res)); bp += strlen(bp); xdr_free(xdr_nfs_cb_resop4, (char *)&one_res); /* add "..." if past the "end" of the buffer */ if (bp - buf > SUM_COMPND_MAX) { strcpy(buf + SUM_COMPND_MAX - strlen("..."), "..."); break; } } return (buf); } /* * Return the summarized results for the given resultdata. */ static char * sum_result(nfs_resop4 *resp) { static char buf[1024]; void (*fmtproc)(char *, size_t, void *); buf[0] = '\0'; if (resp->resop < num_opcodes) fmtproc = opcode_info[resp->resop].sumres; else if (resp->resop == OP_ILLEGAL) fmtproc = sum_nfsstat4; else fmtproc = NULL; if (fmtproc != NULL) fmtproc(buf, sizeof (buf), &resp->nfs_resop4_u); return (buf); } /* * Return the summarized results for the given resultdata. */ static char * sum_cb_result(nfs_cb_resop4 *resp) { static char buf[1024]; void (*fmtproc)(char *, size_t, void *); buf[0] = '\0'; if (resp->resop < cb_num_opcodes) fmtproc = cb_opcode_info[resp->resop].sumres; else if (resp->resop == OP_CB_ILLEGAL) fmtproc = sum_nfsstat4; else fmtproc = NULL; if (fmtproc != NULL) fmtproc(buf, sizeof (buf), &resp->nfs_cb_resop4_u); return (buf); } static void dtl_change_info(char *msg, change_info4 *infop) { sprintf(get_line(0, 0), "%s:", msg); sprintf(get_line(0, 0), " Atomic = %s", infop->atomic ? "TRUE" : "FALSE"); detail_fattr4_change(" Before", infop->before); detail_fattr4_change(" After", infop->after); } static void detail_fattr4_change(char *msg, fattr4_change chg) { sprintf(get_line(0, 0), "%s: 0x%llx", msg, chg); /* XXX print as time_t, too? */ } static void sum_nfsstat4(char *buf, size_t buflen, void *obj) { nfsstat4 status = *(nfsstat4 *)obj; strncpy(buf, status_name(status), buflen); } static void dtl_nfsstat4(void *obj) { nfsstat4 status = *(nfsstat4 *)obj; sprintf(get_line(0, 0), "Status = %d (%s)", status, status_name(status)); } static void sumres_access(char *buf, size_t buflen, void *obj) { ACCESS4res *res = (ACCESS4res *)obj; char *bp = buf; int len, blen = buflen; strcpy(bp, status_name(res->status)); if (res->status == NFS4_OK) { bp += (len = strlen(bp)); blen -= len; snprintf(bp, blen, " Supp="); bp += (len = strlen(bp)); blen -= len; sum_access4(bp, blen, res->ACCESS4res_u.resok4.supported); bp += (len = strlen(bp)); blen -= len; snprintf(bp, blen, " Allow="); bp += (len = strlen(bp)); blen -= len; sum_access4(bp, blen, res->ACCESS4res_u.resok4.access); } } static void dtlres_access(void *obj) { ACCESS4res *res = (ACCESS4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_access4("Supported Attributes", res->ACCESS4res_u.resok4.supported); detail_access4("Allowed Attributes", res->ACCESS4res_u.resok4.access); } } static void sumres_close(char *buf, size_t buflen, void *obj) { CLOSE4res *res = (CLOSE4res *)obj; if (res->status == NFS4_OK) snprintf(buf, buflen, "%s", sum_open_stateid(&res->CLOSE4res_u.open_stateid)); } static void dtlres_close(void *obj) { CLOSE4res *res = (CLOSE4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_open_stateid(&res->CLOSE4res_u.open_stateid); } } static void sumres_commit(char *buf, size_t buflen, void *obj) { COMMIT4res *res = (COMMIT4res *)obj; if (res->status == NFS4_OK) snprintf(buf, buflen, "Verf=%s", tohex(res->COMMIT4res_u.resok4.writeverf, NFS4_VERIFIER_SIZE)); } static void dtlres_commit(void *obj) { COMMIT4res *res = (COMMIT4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { sprintf(get_line(0, 0), "Verifier = %s", tohex(res->COMMIT4res_u.resok4.writeverf, NFS4_VERIFIER_SIZE)); } } static void dtlres_create(void *obj) { CREATE4res *res = (CREATE4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { dtl_change_info("Change Information", &res->CREATE4res_u.resok4.cinfo); detail_attr_bitmap("", &res->CREATE4res_u.resok4.attrset, NULL); } } static void sumres_getattr(char *buf, size_t buflen, void *obj) { GETATTR4res *res = (GETATTR4res *)obj; strncpy(buf, status_name(res->status), buflen); } static void dtlres_getattr(void *obj) { GETATTR4res *res = (GETATTR4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_fattr4(&res->GETATTR4res_u.resok4.obj_attributes); } } static void sumres_cb_getattr(char *buf, size_t buflen, void *obj) { CB_GETATTR4res *res = (CB_GETATTR4res *)obj; strncpy(buf, status_name(res->status), buflen); } static void dtlres_cb_getattr(void *obj) { CB_GETATTR4res *res = (CB_GETATTR4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_fattr4(&res->CB_GETATTR4res_u.resok4.obj_attributes); } } static void sumres_getfh(char *buf, size_t buflen, void *obj) { char *bp; GETFH4res *res = (GETFH4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_fh4(&res->GETFH4res_u.resok4.object)); } } static void dtlres_getfh(void *obj) { GETFH4res *res = (GETFH4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_fh4(&res->GETFH4res_u.resok4.object); } } static void dtlres_link(void *obj) { LINK4res *res = (LINK4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { dtl_change_info("Change Information", &res->LINK4res_u.resok4.cinfo); } } static void sumres_lock(char *buf, size_t buflen, void *obj) { char *bp; LOCK4res *res = (LOCK4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid)); } if (res->status == NFS4ERR_DENIED) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_lock_denied(&res->LOCK4res_u.denied)); } } static void dtlres_lock(void *obj) { LOCK4res *res = (LOCK4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_lock_stateid(&res->LOCK4res_u.resok4.lock_stateid); } if (res->status == NFS4ERR_DENIED) { detail_lock_denied(&res->LOCK4res_u.denied); } } static void sumres_lockt(char *buf, size_t buflen, void *obj) { char *bp; LOCKT4res *res = (LOCKT4res *)obj; strcpy(buf, status_name(res->status)); if (res->status == NFS4ERR_DENIED) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_lock_denied(&res->LOCKT4res_u.denied)); } } static void dtlres_lockt(void *obj) { LOCKT4res *res = (LOCKT4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4ERR_DENIED) { detail_lock_denied(&res->LOCKT4res_u.denied); } } static void sumres_locku(char *buf, size_t buflen, void *obj) { char *bp; LOCKU4res *res = (LOCKU4res *)obj; strncpy(buf, status_name(res->status), buflen); bp = buf + strlen(buf); if (res->status == NFS4_OK) snprintf(bp, buflen - (bp - buf), " %s", sum_lock_stateid(&res->LOCKU4res_u.lock_stateid)); } static void dtlres_locku(void *obj) { LOCKU4res *res = (LOCKU4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) detail_lock_stateid(&res->LOCKU4res_u.lock_stateid); } static void sumres_open(char *buf, size_t buflen, void *obj) { char *bp = buf; OPEN4res *res = (OPEN4res *)obj; uint_t rflags; int len, blen = buflen; strncpy(bp, status_name(res->status), blen); if (res->status == NFS4_OK) { bp += (len = strlen(bp)); blen -= len; snprintf(bp, blen, " %s", sum_stateid(&res->OPEN4res_u.resok4.stateid)); bp += (len = strlen(bp)); blen -= len; if ((rflags = res->OPEN4res_u.resok4.rflags) != 0) { snprintf(bp, blen, "%s", sum_open_rflags(rflags)); bp += (len = strlen(bp)); blen -= len; } sum_delegation(bp, blen, &res->OPEN4res_u.resok4.delegation); } } static void dtlres_open(void *obj) { OPEN4res *res = (OPEN4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_stateid(&res->OPEN4res_u.resok4.stateid); dtl_change_info("Change Information", &res->OPEN4res_u.resok4.cinfo); sprintf(get_line(0, 0), "Flags = 0x%x (%s)", res->OPEN4res_u.resok4.rflags, detail_open_rflags(res->OPEN4res_u.resok4.rflags)); detail_attr_bitmap("", &res->OPEN4res_u.resok4.attrset, NULL); detail_delegation(&res->OPEN4res_u.resok4.delegation); } } static void sumres_open_confirm(char *buf, size_t buflen, void *obj) { char *bp; OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_open_stateid(&res->OPEN_CONFIRM4res_u.resok4. open_stateid)); } } static void dtlres_open_confirm(void *obj) { OPEN_CONFIRM4res *res = (OPEN_CONFIRM4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_open_stateid(&res->OPEN_CONFIRM4res_u.resok4. open_stateid); } } static void sumres_open_downgrd(char *buf, size_t buflen, void *obj) { char *bp; OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", sum_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4. open_stateid)); } } static void dtlres_open_downgrd(void *obj) { OPEN_DOWNGRADE4res *res = (OPEN_DOWNGRADE4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { detail_open_stateid(&res->OPEN_DOWNGRADE4res_u.resok4. open_stateid); } } static void sumres_read(char *buf, size_t buflen, void *obj) { char *bp; READ4res *res = (READ4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " (%u bytes) %s", res->READ4res_u.resok4.data.data_len, res->READ4res_u.resok4.eof ? "EOF" : ""); } } static void dtlres_read(void *obj) { READ4res *res = (READ4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { sprintf(get_line(0, 0), "Count = %u bytes read", res->READ4res_u.resok4.data.data_len); sprintf(get_line(0, 0), "End of file = %s", res->READ4res_u.resok4.eof ? "TRUE" : "FALSE"); } } static void sumres_readdir(char *buf, size_t buflen, void *obj) { char *bp; READDIR4res *res = (READDIR4res *)obj; int num_entries = 0; entry4 *ep; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { for (ep = res->READDIR4res_u.resok4.reply.entries; ep != NULL; ep = ep->nextentry) num_entries++; bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %d entries (%s)", num_entries, res->READDIR4res_u.resok4.reply.eof ? "No more" : "More"); } } static void dtlres_readdir(void *obj) { READDIR4res *res = (READDIR4res *)obj; int num_entries = 0; entry4 *ep; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { for (ep = res->READDIR4res_u.resok4.reply.entries; ep != NULL; ep = ep->nextentry) { num_entries++; sprintf(get_line(0, 0), "------------------ entry #%d", num_entries); sprintf(get_line(0, 0), "Cookie = %llu", ep->cookie); sprintf(get_line(0, 0), "Name = %s", component_name(&ep->name)); detail_fattr4(&ep->attrs); } if (num_entries == 0) sprintf(get_line(0, 0), "(No entries)"); sprintf(get_line(0, 0), "EOF = %s", res->READDIR4res_u.resok4.reply.eof ? "TRUE" : "FALSE"); sprintf(get_line(0, 0), "Verifer = %s", tohex(res->READDIR4res_u.resok4.cookieverf, NFS4_VERIFIER_SIZE)); } } static void sumres_readlnk(char *buf, size_t buflen, void *obj) { char *bp; READLINK4res *res = (READLINK4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s", linktext_name(&res->READLINK4res_u.resok4.link)); } } static void dtlres_readlnk(void *obj) { READLINK4res *res = (READLINK4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { sprintf(get_line(0, 0), "Link = %s", linktext_name(&res->READLINK4res_u.resok4.link)); } } static void dtlres_remove(void *obj) { REMOVE4res *res = (REMOVE4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { dtl_change_info("Change Information", &res->REMOVE4res_u.resok4.cinfo); } } static void dtlres_rename(void *obj) { RENAME4res *res = (RENAME4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { dtl_change_info("Source Change Information", &res->RENAME4res_u.resok4.source_cinfo); dtl_change_info("Target Change Information", &res->RENAME4res_u.resok4.target_cinfo); } } static void sumres_secinfo(char *buf, size_t buflen, void *obj) { char *bp; SECINFO4res *res = (SECINFO4res *)obj; strncpy(buf, status_name(res->status), buflen); bp = buf + strlen(buf); if (res->status == NFS4_OK) { uint_t numinfo = res->SECINFO4res_u.resok4.SECINFO4resok_len; secinfo4 *infop; for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val; numinfo != 0; infop++, numinfo--) { snprintf(bp, buflen - (bp - buf), " %s", flavor_name(infop->flavor)); bp += strlen(bp); } } } static void dtlres_secinfo(void *obj) { SECINFO4res *res = (SECINFO4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { uint_t numinfo = res->SECINFO4res_u.resok4.SECINFO4resok_len; secinfo4 *infop; for (infop = res->SECINFO4res_u.resok4.SECINFO4resok_val; numinfo != 0; infop++, numinfo--) { detail_secinfo4(infop); } } } static void sumres_setattr(char *buf, size_t buflen, void *obj) { SETATTR4res *res = (SETATTR4res *)obj; size_t len; (void) snprintf(buf, buflen, "%s ", status_name(res->status)); len = strlen(buf); sum_attr_bitmap(buf + len, buflen - len, &res->attrsset); } static void dtlres_setattr(void *obj) { SETATTR4res *res = (SETATTR4res *)obj; dtl_nfsstat4(obj); detail_attr_bitmap("", &res->attrsset, NULL); } static void sumres_setclid(char *buf, size_t buflen, void *obj) { char *bp; SETCLIENTID4res *res = (SETCLIENTID4res *)obj; strncpy(buf, status_name(res->status), buflen); switch (res->status) { case NFS_OK: bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %s CFV=%s", sum_clientid(res->SETCLIENTID4res_u.resok4.clientid), tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm, NFS4_VERIFIER_SIZE)); break; case NFS4ERR_CLID_INUSE: bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " ID=%s Addr=%s", res->SETCLIENTID4res_u.client_using.r_netid, res->SETCLIENTID4res_u.client_using.r_addr); break; } } static void dtlres_setclid(void *obj) { SETCLIENTID4res *res = (SETCLIENTID4res *)obj; dtl_nfsstat4(obj); switch (res->status) { case NFS_OK: detail_clientid(res->SETCLIENTID4res_u.resok4.clientid); sprintf(get_line(0, 0), "Set Client ID Confirm Verifier = %s", tohex(res->SETCLIENTID4res_u.resok4.setclientid_confirm, NFS4_VERIFIER_SIZE)); break; case NFS4ERR_CLID_INUSE: sprintf(get_line(0, 0), "Used by Net ID = %s", res->SETCLIENTID4res_u.client_using.r_netid); sprintf(get_line(0, 0), "Used by Addr = %s", res->SETCLIENTID4res_u.client_using.r_addr); break; } } static void sumres_write(char *buf, size_t buflen, void *obj) { char *bp; WRITE4res *res = (WRITE4res *)obj; strncpy(buf, status_name(res->status), buflen); if (res->status == NFS4_OK) { bp = buf + strlen(buf); snprintf(bp, buflen - (bp - buf), " %u (%s)", res->WRITE4res_u.resok4.count, stable_how4_name(res->WRITE4res_u.resok4.committed)); } } static void dtlres_write(void *obj) { WRITE4res *res = (WRITE4res *)obj; dtl_nfsstat4(obj); if (res->status == NFS4_OK) { sprintf(get_line(0, 0), "Count = %u bytes written", res->WRITE4res_u.resok4.count); sprintf(get_line(0, 0), "Stable = %s", stable_how4_name(res->WRITE4res_u.resok4.committed)); sprintf(get_line(0, 0), "Verifier = %s", tohex(res->WRITE4res_u.resok4.writeverf, NFS4_VERIFIER_SIZE)); } } /* * Print details about the nfs_resop4 that is next in the XDR stream. */ static void detail_nfs_resop4(void) { int numres; nfs_resop4 one_res; void (*fmtproc)(void *); numres = getxdr_long(); (void) sprintf(get_line(0, 0), "Number of results = %d", numres); while (numres-- > 0) { bzero(&one_res, sizeof (one_res)); if (!xdr_nfs_resop4(&xdrm, &one_res)) { xdr_free(xdr_nfs_resop4, (char *)&one_res); longjmp(xdr_err, 1); } get_line(0, 0); /* blank line to separate ops */ sprintf(get_line(0, 0), "Op = %d (%s)", one_res.resop, opcode_name(one_res.resop)); if (one_res.resop < num_opcodes) fmtproc = opcode_info[one_res.resop].dtlres; else if (one_res.resop == OP_ILLEGAL) fmtproc = dtl_nfsstat4; else fmtproc = NULL; if (fmtproc != NULL) fmtproc(&one_res.nfs_resop4_u); /* nfs4_skip_bytes set by xdr_nfs_resop4()() */ if (nfs4_skip_bytes) nfs4_xdr_skip(nfs4_skip_bytes); xdr_free(xdr_nfs_resop4, (char *)&one_res); } } /* * Print details about the nfs_cb_resop4 that is next in the XDR stream. */ static void detail_cb_resop4(void) { int numres; nfs_cb_resop4 one_res; void (*fmtproc)(void *); numres = getxdr_long(); (void) sprintf(get_line(0, 0), "Number of results = %d", numres); while (numres-- > 0) { bzero(&one_res, sizeof (one_res)); if (!xdr_nfs_cb_resop4(&xdrm, &one_res)) longjmp(xdr_err, 1); get_line(0, 0); /* blank line to separate ops */ sprintf(get_line(0, 0), "Op = %d (%s)", one_res.resop, cb_opcode_name(one_res.resop)); if (one_res.resop < cb_num_opcodes) fmtproc = cb_opcode_info[one_res.resop].dtlres; else if (one_res.resop == OP_CB_ILLEGAL) fmtproc = dtl_nfsstat4; else fmtproc = NULL; if (fmtproc != NULL) fmtproc(&one_res.nfs_cb_resop4_u); xdr_free(xdr_nfs_cb_resop4, (char *)&one_res); } } /* * Return the name of a lock type. */ static char * lock_type_name(enum nfs_lock_type4 type) { char *result; switch (type) { case READ_LT: result = "READ"; break; case WRITE_LT: result = "WRITE"; break; case READW_LT: result = "READW"; break; case WRITEW_LT: result = "WRITEW"; break; default: result = "?"; break; } return (result); } /* * Return the name of an opcode. */ static char * opcode_name(uint_t opnum) { static char buf[20]; if (opnum < num_opcodes) return (opcode_info[opnum].name); if (opnum == OP_ILLEGAL) return ("ILLEGAL"); sprintf(buf, "op %d", opnum); return (buf); } /* * Return the name of an opcode. */ static char * cb_opcode_name(uint_t opnum) { static char buf[20]; if (opnum < cb_num_opcodes) return (cb_opcode_info[opnum].name); if (opnum == OP_CB_ILLEGAL) return ("CB_ILLEGAL"); sprintf(buf, "op %d", opnum); return (buf); } /* * Fill in a summary string for the given access bitmask. */ static void sum_access4(char *buf, size_t buflen, uint32_t bits) { buf[0] = '\0'; if (bits & ACCESS4_READ) (void) strncat(buf, "rd,", buflen); if (bits & ACCESS4_LOOKUP) (void) strncat(buf, "lk,", buflen); if (bits & ACCESS4_MODIFY) (void) strncat(buf, "mo,", buflen); if (bits & ACCESS4_EXTEND) (void) strncat(buf, "ext,", buflen); if (bits & ACCESS4_DELETE) (void) strncat(buf, "dl,", buflen); if (bits & ACCESS4_EXECUTE) (void) strncat(buf, "exc,", buflen); if (buf[0] != '\0') buf[strlen(buf) - 1] = '\0'; } /* * Print detail information about the given access bitmask. */ static void detail_access4(char *descrip, uint32_t bits) { sprintf(get_line(0, 0), "%s = 0x%08x", descrip, bits); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_READ, "Read", "(no read)")); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_LOOKUP, "Lookup", "(no lookup)")); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_MODIFY, "Modify", "(no modify)")); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_EXTEND, "Extend", "(no extend)")); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_DELETE, "Delete", "(no delete)")); (void) sprintf(get_line(0, 0), " %s", getflag(bits, ACCESS4_EXECUTE, "Execute", "(no execute)")); } /* * Fill in a summary string for the given open_claim4. */ static void sum_name(char *buf, size_t buflen, open_claim4 *claim) { char *bp = buf; switch (claim->claim) { case CLAIM_NULL: snprintf(bp, buflen, "%s ", component_name(&claim->open_claim4_u.file)); break; case CLAIM_PREVIOUS: break; case CLAIM_DELEGATE_CUR: snprintf(bp, buflen, "%s ", component_name(&claim->open_claim4_u. delegate_cur_info.file)); break; case CLAIM_DELEGATE_PREV: snprintf(bp, buflen, "%s ", component_name(&claim->open_claim4_u. file_delegate_prev)); break; } } /* * Fill in a summary string for the given open_claim4. */ static void sum_claim(char *buf, size_t buflen, open_claim4 *claim) { char *bp = buf; switch (claim->claim) { case CLAIM_NULL: snprintf(bp, buflen, " CT=N"); break; case CLAIM_PREVIOUS: snprintf(bp, buflen, " CT=P DT=%s", get_deleg_typestr(claim->open_claim4_u.delegate_type)); break; case CLAIM_DELEGATE_CUR: snprintf(bp, buflen, " CT=DC %s", sum_deleg_stateid(&claim->open_claim4_u. delegate_cur_info.delegate_stateid)); break; case CLAIM_DELEGATE_PREV: snprintf(bp, buflen, " CT=DP"); break; default: snprintf(bp, buflen, " CT=?"); break; } } static char * get_deleg_typestr(open_delegation_type4 dt) { char *str = ""; switch (dt) { case OPEN_DELEGATE_NONE: str = "N"; break; case OPEN_DELEGATE_READ: str = "R"; break; case OPEN_DELEGATE_WRITE: str = "W"; break; default: str = "?"; } return (str); } /* * Print detail information for the given open_claim4. */ static void detail_claim(open_claim4 *claim) { sprintf(get_line(0, 0), "Claim Type = %d (%s)", claim->claim, claim_name(claim->claim)); switch (claim->claim) { case CLAIM_NULL: detail_compname4(&claim->open_claim4_u.file); break; case CLAIM_PREVIOUS: sprintf(get_line(0, 0), "Delegate Type = %s (val = %d)", get_deleg_typestr(claim->open_claim4_u.delegate_type), claim->open_claim4_u.delegate_type); break; case CLAIM_DELEGATE_CUR: detail_compname4(&claim->open_claim4_u.delegate_cur_info.file); detail_deleg_stateid(&claim->open_claim4_u.delegate_cur_info. delegate_stateid); break; case CLAIM_DELEGATE_PREV: detail_compname4(&claim->open_claim4_u.file_delegate_prev); break; } } /* * Return a summary string for the given clientid4. */ static char * sum_clientid(clientid4 client) { static char buf[50]; snprintf(buf, sizeof (buf), "CL=%llx", client); return (buf); } /* * Print a detail string for the given clientid4. */ static void detail_clientid(clientid4 client) { sprintf(get_line(0, 0), "Client ID = %llx", client); } /* * Write a summary string for the given delegation into buf. */ static void sum_delegation(char *buf, size_t buflen, open_delegation4 *delp) { switch (delp->delegation_type) { case OPEN_DELEGATE_NONE: snprintf(buf, buflen, " DT=N"); break; case OPEN_DELEGATE_READ: snprintf(buf, buflen, " DT=R %s", sum_deleg_stateid(&delp->open_delegation4_u.write. stateid)); break; case OPEN_DELEGATE_WRITE: snprintf(buf, buflen, " DT=W %s %s", sum_deleg_stateid(&delp->open_delegation4_u.write. stateid), sum_space_limit(&delp->open_delegation4_u.write. space_limit)); break; default: snprintf(buf, buflen, " DT=?"); break; } } static void detail_delegation(open_delegation4 *delp) { sprintf(get_line(0, 0), "Delegation Type = %d (%s)", delp->delegation_type, delegation_type_name(delp->delegation_type)); switch (delp->delegation_type) { case OPEN_DELEGATE_NONE: /* no-op */ break; case OPEN_DELEGATE_READ: detail_deleg_stateid(&delp->open_delegation4_u.read.stateid); sprintf(get_line(0, 0), "Recall = %s", delp->open_delegation4_u.read.recall ? "TRUE" : "FALSE"); sprintf(get_line(0, 0), "[nfsacl4]"); break; case OPEN_DELEGATE_WRITE: detail_deleg_stateid(&delp->open_delegation4_u.write.stateid); sprintf(get_line(0, 0), "Recall = %s", delp->open_delegation4_u.write.recall ? "TRUE" : "FALSE"); detail_space_limit(&delp->open_delegation4_u.write. space_limit); sprintf(get_line(0, 0), "[nfsacl4]"); break; } } static void detail_open_owner(open_owner4 *owner) { sprintf(get_line(0, 0), "Open Owner hash = [%04X] ", owner_hash(&owner->owner)); sprintf(get_line(0, 0), " len = %u val = %s ", owner->owner.owner_len, tohex(owner->owner.owner_val, owner->owner.owner_len)); detail_clientid(owner->clientid); } static void detail_lock_owner(lock_owner4 *owner) { sprintf(get_line(0, 0), "Lock Owner hash = [%04X] ", owner_hash(&owner->owner)); sprintf(get_line(0, 0), " len = %u val = %s ", owner->owner.owner_len, tohex(owner->owner.owner_val, owner->owner.owner_len)); detail_clientid(owner->clientid); } static void sum_openflag(char *bufp, int buflen, openflag4 *flagp) { if (flagp->opentype == OPEN4_CREATE) { switch (flagp->openflag4_u.how.mode) { case UNCHECKED4: snprintf(bufp, buflen, "OT=CR(U)"); break; case GUARDED4: snprintf(bufp, buflen, "OT=CR(G)"); break; case EXCLUSIVE4: snprintf(bufp, buflen, "OT=CR(E)"); break; default: snprintf(bufp, buflen, "OT=CR(?:%d)", flagp->openflag4_u.how.mode); break; } } else snprintf(bufp, buflen, "OT=NC"); } static void detail_openflag(openflag4 *flagp) { sprintf(get_line(0, 0), "Open Type = %s", flagp->opentype == OPEN4_CREATE ? "CREATE" : "NOCREATE"); if (flagp->opentype == OPEN4_CREATE) detail_createhow4(&flagp->openflag4_u.how); } /* * Fill in buf with the given path. */ static void sum_pathname4(char *buf, size_t buflen, pathname4 *pathp) { char *bp = buf; uint_t component; for (component = 0; component < pathp->pathname4_len; component++) { snprintf(bp, buflen - (bp - buf), component == 0 ? "%s" : "/%s", component_name(&pathp->pathname4_val[component])); bp += strlen(bp); } } static void sum_compname4(char *buf, size_t buflen, component4 *comp) { snprintf(buf, buflen, "%s", component_name(comp)); } static void detail_compname4(component4 *comp) { sprintf(get_line(0, 0), "%s", component_name(comp)); } static void detail_pathname4(pathname4 *pathp, char *what) { char *bp = get_line(0, 0); uint_t component; sprintf(bp, what); bp += strlen(bp); for (component = 0; component < pathp->pathname4_len; component++) { sprintf(bp, component == 0 ? "%s" : "/%s", component_name(&pathp->pathname4_val[component])); bp += strlen(bp); } } /* * Print detail information about the rpcsec_gss_info that is XDR-encoded * at mem. */ static void detail_rpcsec_gss(rpcsec_gss_info *info) { sprintf(get_line(0, 0), "OID = %s", tohex(info->oid.sec_oid4_val, info->oid.sec_oid4_len)); sprintf(get_line(0, 0), "QOP = %u", info->qop); sprintf(get_line(0, 0), "Service = %d (%s)", info->service, gss_svc_name(info->service)); } /* * Print detail information about the given secinfo4. */ static void detail_secinfo4(secinfo4 *infop) { sprintf(get_line(0, 0), "Flavor = %d (%s)", infop->flavor, flavor_name(infop->flavor)); switch (infop->flavor) { case RPCSEC_GSS: detail_rpcsec_gss(&infop->secinfo4_u.flavor_info); break; } } /* * Return a summary string corresponding to the given nfs_space_limit4. */ static char * sum_space_limit(nfs_space_limit4 *limitp) { static char buf[64]; int buflen = sizeof (buf); buf[0] = '\0'; switch (limitp->limitby) { case NFS_LIMIT_SIZE: snprintf(buf, buflen, "LB=SZ(%llu)", limitp->nfs_space_limit4_u.filesize); break; case NFS_LIMIT_BLOCKS: snprintf(buf, buflen, "LB=BL(%u*%u)", limitp->nfs_space_limit4_u.mod_blocks.num_blocks, limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block); break; default: snprintf(buf, buflen, "LB=?(%d)", limitp->limitby); break; } return (buf); } /* * Print detail information about the given nfs_space_limit4. */ static void detail_space_limit(nfs_space_limit4 *limitp) { sprintf(get_line(0, 0), "LimitBy = %d (%s)", limitp->limitby, limitby_name(limitp->limitby)); switch (limitp->limitby) { case NFS_LIMIT_SIZE: sprintf(get_line(0, 0), "Bytes = %llu", limitp->nfs_space_limit4_u.filesize); break; case NFS_LIMIT_BLOCKS: sprintf(get_line(0, 0), "Blocks = %u", limitp->nfs_space_limit4_u.mod_blocks.num_blocks); sprintf(get_line(0, 0), "Bytes Per Block = %u", limitp->nfs_space_limit4_u.mod_blocks.bytes_per_block); break; } } /* * Return the short name of a file type. */ static char * sum_type_name(nfs_ftype4 type) { static char buf[20]; if (type < num_ftypes) return (ftype_names[type].short_name); else { sprintf(buf, "type %d", type); return (buf); } } /* * Return string with long/short flag names */ static char * get_flags(uint_t flag, ftype_names_t *names, uint_t num_flags, int shortname, char *prefix) { static char buf[200]; char *bp = buf, *str; int i, len, blen = sizeof (buf); ftype_names_t *fn = NULL; *bp = '\0'; if (prefix) { snprintf(bp, blen, "%s", prefix); bp += (len = sizeof (bp)); blen -= len; } for (i = 0; i < 32; i++) if (flag & (1 << i)) { fn = names + (i < num_flags ? i : num_flags); str = (shortname ? fn->short_name : fn->long_name); snprintf(bp, blen, "%s,", str); bp += (len = strlen(bp)); blen -= len; } if (fn) *(bp - 1) = '\0'; else *buf = '\0'; return (buf); } /* * Return the long name of a file type. */ static char * detail_type_name(nfs_ftype4 type) { static char buf[20]; if (type < num_ftypes) return (ftype_names[type].long_name); else { sprintf(buf, "type %d", type); return (buf); } } /* * Return the name of an attribute. */ static char * attr_name(uint_t attrnum) { static char buf[20]; if (attrnum < MAX_ATTRIBUTES) return (attr_info[attrnum].name); else { sprintf(buf, "attr #%d", attrnum); return (buf); } } /* * Return the name of the given open_claim_type4. */ static char * claim_name(enum open_claim_type4 claim_type) { char *result; switch (claim_type) { case CLAIM_NULL: result = "NULL"; break; case CLAIM_PREVIOUS: result = "PREVIOUS"; break; case CLAIM_DELEGATE_CUR: result = "DELEGATE CURRENT"; break; case CLAIM_DELEGATE_PREV: result = "DELEGATE PREVIOUS"; break; default: result = "?"; break; } return (result); } /* * Return a string naming the given delegation. */ static char * delegation_type_name(enum open_delegation_type4 type) { char *result; switch (type) { case OPEN_DELEGATE_NONE: result = "NONE"; break; case OPEN_DELEGATE_READ: result = "READ"; break; case OPEN_DELEGATE_WRITE: result = "WRITE"; break; default: result = "?"; break; } return (result); } /* * Return the name of the given authentication flavor. */ static char * flavor_name(uint_t flavor) { char *result; static char buf[50]; switch (flavor) { case AUTH_SYS: result = "AUTH_SYS"; break; case AUTH_NONE: result = "AUTH_NONE"; break; case AUTH_DH: result = "AUTH_DH"; break; case RPCSEC_GSS: result = "RPCSEC_GSS"; break; default: sprintf(buf, "[flavor %d]", flavor); result = buf; break; } return (result); } /* * Return the name of the given rpc_gss_svc_t. */ static char * gss_svc_name(rpc_gss_svc_t svc) { char *result; static char buf[50]; switch (svc) { case RPC_GSS_SVC_NONE: result = "NONE"; break; case RPC_GSS_SVC_INTEGRITY: result = "INTEGRITY"; break; case RPC_GSS_SVC_PRIVACY: result = "PRIVACY"; break; default: sprintf(buf, "Service %d", svc); result = buf; break; } return (result); } /* * Return a string name for the given limit_by4. */ static char * limitby_name(enum limit_by4 limitby) { char *result; switch (limitby) { case NFS_LIMIT_SIZE: result = "SIZE"; break; case NFS_LIMIT_BLOCKS: result = "BLOCKS"; break; default: result = "?"; break; } return (result); } static char * status_name(int status) { char *p; switch (status) { case NFS4_OK: p = "NFS4_OK"; break; case NFS4ERR_PERM: p = "NFS4ERR_PERM"; break; case NFS4ERR_NOENT: p = "NFS4ERR_NOENT"; break; case NFS4ERR_IO: p = "NFS4ERR_IO"; break; case NFS4ERR_NXIO: p = "NFS4ERR_NXIO"; break; case NFS4ERR_ACCESS: p = "NFS4ERR_ACCESS"; break; case NFS4ERR_EXIST: p = "NFS4ERR_EXIST"; break; case NFS4ERR_XDEV: p = "NFS4ERR_XDEV"; break; case NFS4ERR_NOTDIR: p = "NFS4ERR_NOTDIR"; break; case NFS4ERR_ISDIR: p = "NFS4ERR_ISDIR"; break; case NFS4ERR_INVAL: p = "NFS4ERR_INVAL"; break; case NFS4ERR_FBIG: p = "NFS4ERR_FBIG"; break; case NFS4ERR_NOSPC: p = "NFS4ERR_NOSPC"; break; case NFS4ERR_ROFS: p = "NFS4ERR_ROFS"; break; case NFS4ERR_MLINK: p = "NFS4ERR_MLINK"; break; case NFS4ERR_NAMETOOLONG:p = "NFS4ERR_NAMETOOLONG"; break; case NFS4ERR_NOTEMPTY: p = "NFS4ERR_NOTEMPTY"; break; case NFS4ERR_DQUOT: p = "NFS4ERR_DQUOT"; break; case NFS4ERR_STALE: p = "NFS4ERR_STALE"; break; case NFS4ERR_BADHANDLE: p = "NFS4ERR_BADHANDLE"; break; case NFS4ERR_BAD_COOKIE:p = "NFS4ERR_BAD_COOKIE"; break; case NFS4ERR_NOTSUPP: p = "NFS4ERR_NOTSUPP"; break; case NFS4ERR_TOOSMALL: p = "NFS4ERR_TOOSMALL"; break; case NFS4ERR_SERVERFAULT:p = "NFS4ERR_SERVERFAULT"; break; case NFS4ERR_BADTYPE: p = "NFS4ERR_BADTYPE"; break; case NFS4ERR_DELAY: p = "NFS4ERR_DELAY"; break; case NFS4ERR_SAME: p = "NFS4ERR_SAME"; break; case NFS4ERR_DENIED: p = "NFS4ERR_DENIED"; break; case NFS4ERR_EXPIRED: p = "NFS4ERR_EXPIRED"; break; case NFS4ERR_LOCKED: p = "NFS4ERR_LOCKED"; break; case NFS4ERR_GRACE: p = "NFS4ERR_GRACE"; break; case NFS4ERR_FHEXPIRED: p = "NFS4ERR_FHEXPIRED"; break; case NFS4ERR_SHARE_DENIED: p = "NFS4ERR_SHARE_DENIED"; break; case NFS4ERR_WRONGSEC: p = "NFS4ERR_WRONGSEC"; break; case NFS4ERR_CLID_INUSE: p = "NFS4ERR_CLID_INUSE"; break; case NFS4ERR_RESOURCE: p = "NFS4ERR_RESOURCE"; break; case NFS4ERR_MOVED: p = "NFS4ERR_MOVED"; break; case NFS4ERR_NOFILEHANDLE: p = "NFS4ERR_NOFILEHANDLE"; break; case NFS4ERR_MINOR_VERS_MISMATCH: p = "NFS4ERR_MINOR_VERS_MISMATCH"; break; case NFS4ERR_STALE_CLIENTID: p = "NFS4ERR_STALE_CLIENTID"; break; case NFS4ERR_STALE_STATEID: p = "NFS4ERR_STALE_STATEID"; break; case NFS4ERR_OLD_STATEID: p = "NFS4ERR_OLD_STATEID"; break; case NFS4ERR_BAD_STATEID: p = "NFS4ERR_BAD_STATEID"; break; case NFS4ERR_BAD_SEQID: p = "NFS4ERR_BAD_SEQID"; break; case NFS4ERR_NOT_SAME: p = "NFS4ERR_NOT_SAME"; break; case NFS4ERR_LOCK_RANGE: p = "NFS4ERR_LOCK_RANGE"; break; case NFS4ERR_SYMLINK: p = "NFS4ERR_SYMLINK"; break; case NFS4ERR_RESTOREFH: p = "NFS4ERR_RESTOREFH"; break; case NFS4ERR_LEASE_MOVED: p = "NFS4ERR_LEASE_MOVED"; break; case NFS4ERR_ATTRNOTSUPP: p = "NFS4ERR_ATTRNOTSUPP"; break; case NFS4ERR_NO_GRACE: p = "NFS4ERR_NO_GRACE"; break; case NFS4ERR_RECLAIM_BAD: p = "NFS4ERR_RECLAIM_BAD"; break; case NFS4ERR_RECLAIM_CONFLICT: p = "NFS4ERR_RECLAIM_CONFLICT"; break; case NFS4ERR_BADXDR: p = "NFS4ERR_BADXDR"; break; case NFS4ERR_LOCKS_HELD: p = "NFS4ERR_LOCKS_HELD"; break; case NFS4ERR_OPENMODE: p = "NFS4ERR_OPENMODE"; break; case NFS4ERR_BADOWNER: p = "NFS4ERR_BADOWNER"; break; case NFS4ERR_BADCHAR: p = "NFS4ERR_BADCHAR"; break; case NFS4ERR_BADNAME: p = "NFS4ERR_BADNAME"; break; case NFS4ERR_BAD_RANGE: p = "NFS4ERR_BAD_RANGE"; break; case NFS4ERR_LOCK_NOTSUPP: p = "NFS4ERR_LOCK_NOTSUPP"; break; case NFS4ERR_OP_ILLEGAL: p = "NFS4ERR_OP_ILLEGAL"; break; case NFS4ERR_DEADLOCK: p = "NFS4ERR_DEADLOCK"; break; case NFS4ERR_FILE_OPEN: p = "NFS4ERR_FILE_OPEN"; break; case NFS4ERR_ADMIN_REVOKED: p = "NFS4ERR_ADMIN_REVOKED"; break; case NFS4ERR_CB_PATH_DOWN: p = "NFS4ERR_CB_PATH_DOWN"; break; default: p = "(unknown error)"; break; } return (p); } char * nfsstat4_to_name(int status) { return (status_name(status)); } /* * Attribute print functions. See attr_info_t. */ static void prt_supported_attrs(XDR *xdr) { static bitmap4 val; if (!xdr_bitmap4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Supported Attributes:"); detail_attr_bitmap("\t", &val, NULL); xdr_free(xdr_bitmap4, (char *)&val); } static void prt_type(XDR *xdr) { nfs_ftype4 val; if (!xdr_nfs_ftype4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Type = %s", sum_type_name(val)); } static void prt_fh_expire_type(XDR *xdr) { fattr4_fh_expire_type val; char *buf; bool_t first = TRUE; if (!xdr_fattr4_fh_expire_type(xdr, &val)) longjmp(xdr_err, 1); buf = get_line(0, 0); sprintf(buf, "Filehandle expire type = "); if ((val & (FH4_NOEXPIRE_WITH_OPEN | FH4_VOLATILE_ANY | FH4_VOL_MIGRATION | FH4_VOL_RENAME)) == 0) { strcat(buf, "Persistent"); return; } if (val & FH4_NOEXPIRE_WITH_OPEN) { strcat(buf, "No Expire With OPEN"); first = FALSE; } if (val & FH4_VOLATILE_ANY) { if (first) first = FALSE; else strcat(buf, ", "); strcat(buf, "Volatile at any time"); } if (val & FH4_VOL_MIGRATION) { if (first) first = FALSE; else strcat(buf, ", "); strcat(buf, "Volatile at Migration"); } if (val & FH4_VOL_RENAME) { if (first) first = FALSE; else strcat(buf, ", "); strcat(buf, "Volatile at Rename"); } } static void prt_change(XDR *xdr) { changeid4 val; if (!xdr_changeid4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Change ID = 0x%llx", val); /* XXX print as time_t, too? */ } static void prt_size(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Size = %llu", val); } static void prt_link_support(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Link Support = %s", val ? "TRUE" : "FALSE"); } static void prt_symlink_support(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Symlink Support = %s", val ? "TRUE" : "FALSE"); } static void prt_named_attr(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Has Named Attributes = %s", val ? "TRUE" : "FALSE"); } static void prt_fsid(XDR *xdr) { fsid4 val; if (!xdr_fsid4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "FS ID: Major = %llx, Minor = %llx", val.major, val.minor); } static void prt_unique_handles(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Unique Handles = %s", val ? "TRUE" : "FALSE"); } static void prt_lease_time(XDR *xdr) { uint32_t val; if (!xdr_uint32_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Lease Time = %u", val); } static void prt_rdattr_error(XDR *xdr) { nfsstat4 val; if (!xdr_nfsstat4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Rdattr Error = %u (%s)", val, status_name(val)); } static void prt_acl(XDR *xdr) { static fattr4_acl val; char buffy[NFS4_OPAQUE_LIMIT]; int i, len; if (!xdr_fattr4_acl(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "ACL of %d entries", val.fattr4_acl_len); for (i = 0; i < val.fattr4_acl_len; i++) { sprintf(get_line(0, 0), "nfsace4[%d]", i); sprintf(get_line(0, 0), " type = %x", val.fattr4_acl_val[i].type); detail_acetype4(val.fattr4_acl_val[i].type); sprintf(get_line(0, 0), " flags = %x", val.fattr4_acl_val[i].flag); detail_aceflag4(val.fattr4_acl_val[i].flag); sprintf(get_line(0, 0), " mask = %x", val.fattr4_acl_val[i].access_mask); detail_acemask4(val.fattr4_acl_val[i].access_mask); len = val.fattr4_acl_val[i].who.utf8string_len; if (len >= NFS4_OPAQUE_LIMIT) len = NFS4_OPAQUE_LIMIT - 1; (void) strncpy(buffy, val.fattr4_acl_val[i].who.utf8string_val, len); buffy[len] = '\0'; sprintf(get_line(0, 0), " who = %s", buffy); } xdr_free(xdr_fattr4_acl, (char *)&val); } static void detail_acetype4(acetype4 type) { if (type >= ACETYPE4_NAMES_MAX) { sprintf(get_line(0, 0), " unknown type"); } else { sprintf(get_line(0, 0), " %s", acetype4_names[type]); } } static void detail_uint32_bitmap(uint32_t mask, char *mask_names[], int names_max) { char buffy[BUFSIZ], *name; char *indent = " "; char *spacer = " "; int pending = 0; int bit; int len, namelen, spacelen; strcpy(buffy, indent); len = strlen(buffy); spacelen = strlen(spacer); for (bit = 0; bit < names_max; bit++) { if (mask & (1 << bit)) { name = mask_names[bit]; namelen = strlen(name); /* 80 - 6 for "NFS: " = 74 */ if ((len + spacelen + namelen) >= 74) { sprintf(get_line(0, 0), "%s", buffy); strcpy(buffy, indent); len = strlen(buffy); pending = 0; } (void) strlcat(buffy, spacer, sizeof (buffy)); (void) strlcat(buffy, name, sizeof (buffy)); pending = 1; len += spacelen + namelen; } } if (pending) sprintf(get_line(0, 0), "%s", buffy); } static void detail_aceflag4(aceflag4 flag) { detail_uint32_bitmap(flag, aceflag4_names, ACEFLAG4_NAMES_MAX); } static void detail_acemask4(acemask4 mask) { detail_uint32_bitmap(mask, acemask4_names, ACEMASK4_NAMES_MAX); } static void prt_aclsupport(XDR *xdr) { fattr4_aclsupport val; if (!xdr_fattr4_aclsupport(xdr, &val)) longjmp(xdr_err, 1); if (val & ACL4_SUPPORT_ALLOW_ACL) sprintf(get_line(0, 0), "ALLOW ACL Supported"); if (val & ACL4_SUPPORT_DENY_ACL) sprintf(get_line(0, 0), "DENY ACL Supported"); if (val & ACL4_SUPPORT_AUDIT_ACL) sprintf(get_line(0, 0), "AUDIT ACL Supported"); if (val & ACL4_SUPPORT_ALARM_ACL) sprintf(get_line(0, 0), "ALARM ACL Supported"); } static void prt_archive(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Archived = %s", val ? "TRUE" : "FALSE"); } static void prt_cansettime(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Server Can Set Time = %s", val ? "TRUE" : "FALSE"); } static void prt_case_insensitive(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Case Insensitive Lookups = %s", val ? "TRUE" : "FALSE"); } static void prt_case_preserving(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Case Preserving = %s", val ? "TRUE" : "FALSE"); } static void prt_chown_restricted(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Chown Is Restricted = %s", val ? "TRUE" : "FALSE"); } static void prt_filehandle(XDR *xdr) { static nfs_fh4 val; if (!xdr_nfs_fh4(xdr, &val)) longjmp(xdr_err, 1); detail_fh4(&val); xdr_free(xdr_nfs_fh4, (char *)&val); } static void prt_fileid(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "File ID = %llu", val); } static void prt_mounted_on_fileid(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Mounted On File ID = %llu", val); } static void prt_files_avail(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Files Available = %llu", val); } static void prt_files_free(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Files Free = %llu", val); } static void prt_files_total(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Files Total = %llu", val); } static void prt_fs_location(fs_location4 *fsl) { int i; for (i = 0; i < fsl->server.server_len; i++) sprintf(get_line(0, 0), "server: %s", utf8localize(&fsl->server.server_val[i])); detail_pathname4(&fsl->rootpath, "rootpath: "); } static void prt_fs_locations(XDR *xdr) { static fs_locations4 val; int i; if (!xdr_fs_locations4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "[fs_locations]"); detail_pathname4(&val.fs_root, "fs_root: "); for (i = 0; i < val.locations.locations_len; i++) prt_fs_location(&val.locations.locations_val[i]); xdr_free(xdr_fs_locations4, (char *)&val); } static void prt_hidden(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Hidden = %s", val ? "TRUE" : "FALSE"); } static void prt_homogeneous(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "FS Is Homogeneous = %s", val ? "TRUE" : "FALSE"); } static void prt_maxfilesize(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Maximum File Size = %llu", val); } static void prt_maxlink(XDR *xdr) { uint32_t val; if (!xdr_uint32_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Maximum Number of Links = %u", val); } static void prt_maxname(XDR *xdr) { uint32_t val; if (!xdr_uint32_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Maximum File Name Length = %u", val); } static void prt_maxread(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Maximum Read Size = %llu", val); } static void prt_maxwrite(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Maximum Write Size = %llu", val); } static void prt_mimetype(XDR *xdr) { static utf8string val; if (!xdr_utf8string(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "MIME Type = %s", utf8localize(&val)); xdr_free(xdr_utf8string, (char *)&val); } static void prt_mode(XDR *xdr) { mode4 val; if (!xdr_mode4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Mode = 0%03o", val); } static void prt_no_trunc(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Long Names Are Error (no_trunc) = %s", val ? "TRUE" : "FALSE"); } static void prt_numlinks(XDR *xdr) { uint32_t val; if (!xdr_uint32_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Number of Links = %u", val); } static void prt_owner(XDR *xdr) { static utf8string val; if (!xdr_utf8string(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Owner = %s", utf8localize(&val)); xdr_free(xdr_utf8string, (char *)&val); } static void prt_owner_group(XDR *xdr) { static utf8string val; if (!xdr_utf8string(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Group = %s", utf8localize(&val)); xdr_free(xdr_utf8string, (char *)&val); } static void prt_quota_avail_hard(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Quota Hard Limit = %llu", val); } static void prt_quota_avail_soft(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Quota Soft Limit = %llu", val); } static void prt_quota_used(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Quota Used = %llu", val); } static void prt_rawdev(XDR *xdr) { specdata4 val; if (!xdr_specdata4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Raw Device ID = %u, %u", val.specdata1, val.specdata2); } static void prt_space_avail(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Space Available = %llu", val); } static void prt_space_free(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Space Free = %llu", val); } static void prt_space_total(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Total Disk Space = %llu", val); } static void prt_space_used(XDR *xdr) { uint64_t val; if (!xdr_uint64_t(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Space Used (this object) = %llu", val); } static void prt_system(XDR *xdr) { bool_t val; if (!xdr_bool(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "System File = %s", val ? "TRUE" : "FALSE"); } static void prt_time_access(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Last Access Time = %s", format_time(val.seconds, val.nseconds)); } static void prt_time_access_set(XDR *xdr) { settime4 val; if (!xdr_settime4(xdr, &val)) longjmp(xdr_err, 1); if (val.set_it == SET_TO_CLIENT_TIME4) { sprintf(get_line(0, 0), "Access Time = %s (set to client time)", format_time(val.settime4_u.time.seconds, val.settime4_u.time.nseconds)); } else if (val.set_it == SET_TO_SERVER_TIME4) { sprintf(get_line(0, 0), "Access Time (set to server time)"); } else longjmp(xdr_err, 1); } static void prt_time_backup(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Last Backup Time = %s", format_time(val.seconds, val.nseconds)); } static void prt_time_create(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Creation Time = %s", format_time(val.seconds, val.nseconds)); } static void prt_time_delta(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Server Time Granularity = %lld.%09d sec", val.seconds, val.nseconds); } static void prt_time_metadata(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Last Metadata Change Time = %s", format_time(val.seconds, val.nseconds)); } static void prt_time_modify(XDR *xdr) { nfstime4 val; if (!xdr_nfstime4(xdr, &val)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), "Last Modification Time = %s", format_time(val.seconds, val.nseconds)); } static void prt_time_modify_set(XDR *xdr) { settime4 val; if (!xdr_settime4(xdr, &val)) longjmp(xdr_err, 1); if (val.set_it == SET_TO_CLIENT_TIME4) { sprintf(get_line(0, 0), "Modification Time = %s (set to client time)", format_time(val.settime4_u.time.seconds, val.settime4_u.time.nseconds)); } else if (val.set_it == SET_TO_SERVER_TIME4) { sprintf(get_line(0, 0), "Modification Time (set to server time)"); } else longjmp(xdr_err, 1); } /* * Display the UTF8 string that is next in the XDR stream. */ static void showxdr_utf8string(char *fmt) { static utf8string string; if (!xdr_utf8string(&xdrm, &string)) longjmp(xdr_err, 1); sprintf(get_line(0, 0), fmt, utf8localize(&string)); xdr_free(xdr_utf8string, (char *)&string); } /* * utf8string is defined in nfs4_prot.x as an opaque array, which means * when it is decoded into a string, the string might not have a trailing * null. Also, the string will still be encoded in UTF-8, rather than * whatever character encoding is associated with the current locale. This * routine converts a utf8string into a (null-terminated) C string. One day * it will convert into the current character encoding, too. To avoid * dealing with storage management issues, it allocates storage for each * new string, then this storage is "freed" when the packet has been * processed. */ #define MAX_UTF8_STRINGS 512 static char *utf_buf[MAX_UTF8_STRINGS]; static size_t utf_buflen[MAX_UTF8_STRINGS]; static uint_t cur_utf_buf = 0; static char * utf8localize(utf8string *utf8str) { size_t newsize, oldsize, len; char *result, *cp; len = utf8str->utf8string_len; if (len == 0) return (""); if (cur_utf_buf >= MAX_UTF8_STRINGS) return ("[Too Many UTF-8 Strings]"); newsize = oldsize = utf_buflen[cur_utf_buf]; if (oldsize < len + 1) { /* truncate opaques at NFS4_OPAQUE_LIMIT */ if (len > NFS4_OPAQUE_LIMIT) len = NFS4_OPAQUE_LIMIT; newsize = len + 1; } if (newsize != oldsize) { utf_buf[cur_utf_buf] = realloc(utf_buf[cur_utf_buf], newsize); if (utf_buf[cur_utf_buf] == NULL) { pr_err("out of memory\n"); utf_buflen[cur_utf_buf] = 0; return (""); } utf_buflen[cur_utf_buf] = newsize; } result = utf_buf[cur_utf_buf]; strncpy(result, utf8str->utf8string_val, len); result[len] = '\0'; for (cp = result; cp < result + len; cp++) { if (!isprint(*cp)) { *cp = '.'; } } cur_utf_buf++; return (result); } static void utf8free() { cur_utf_buf = 0; } /* * adler16(): adler32 hash code shamelessly copied and mutiliated from * usr/src/uts/common/io/ppp/spppcomp/zlib.[ch] * * The alg was originally created to provide a running * checksum, but we don't need that -- we just want to * chksum data described by buf,len; therefore, the first * parameter was removed (held the running checksum), * and s1/s2 are always set to their required initial * values (1 and 0). I also ripped out code which only * applied to large data sets (bufs larger than 5k). All * I wanted was their core checksum alg (which is supposed * to do really well). The v2/v3 hash alg didn't work well * at all for v4 stuff -- it produced too many collisions. * * The copyright info from uts/common/io/ppp/spppcomp/zlib.[ch] * is included below. */ /* -----zlib.c copyright info below */ /* * Copyright 2000 Sun Microsystems, Inc. * All rights reserved. * * Updated from zlib-1.0.4 to zlib-1.1.3 by James Carlson. * * This file is derived from various .h and .c files from the zlib-1.0.4 * distribution by Jean-loup Gailly and Mark Adler, with some additions * by Paul Mackerras to aid in implementing Deflate compression and * decompression for PPP packets. See zlib.h for conditions of * distribution and use. * * Changes that have been made include: * - added Z_PACKET_FLUSH (see zlib.h for details) * - added inflateIncomp and deflateOutputPending * - allow strm->next_out to be NULL, meaning discard the output * * $Id: zlib.c,v 1.11 1998/09/13 23:37:12 paulus Exp $ */ /* +++ adler32.c */ /* * adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-1998 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */ /* -----zlib.c copyright info above */ /* -----zlib.h copyright info below */ /* * Copyright 2000 Sun Microsystems, Inc. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation is hereby granted, provided that the above * copyright notice appears in all copies. * * SUN MAKES NO REPRESENTATION OR WARRANTIES ABOUT THE SUITABILITY OF * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES * * This file has been altered from its original by Sun Microsystems to * fit local coding style. */ /* -----zlib.h copyright info above */ #define DO1(buf, i) {s1 += buf[i]; s2 += s1; } #define DO2(buf, i) DO1(buf, i); DO1(buf, i+1); #define DO4(buf, i) DO2(buf, i); DO2(buf, i+2); #define DO8(buf, i) DO4(buf, i); DO4(buf, i+4); #define DO16(buf) DO8(buf, 0); DO8(buf, 8); static uint32_t adler16(void *p, int len) { uint32_t s1 = 1; uint32_t s2 = 0; uchar_t *buf = p; while (len >= 16) { DO16(buf); buf += 16; len -= 16; } while (len > 0) { s1 += *buf++; s2 += s1; len--; } return ((uint32_t)(s2 ^ s1) & 0xFFFFU); }