1192811Srmacklem/*- 2192811Srmacklem * Copyright (c) 2009 Rick Macklem, University of Guelph 3192811Srmacklem * All rights reserved. 4192811Srmacklem * 5192811Srmacklem * Redistribution and use in source and binary forms, with or without 6192811Srmacklem * modification, are permitted provided that the following conditions 7192811Srmacklem * are met: 8192811Srmacklem * 1. Redistributions of source code must retain the above copyright 9192811Srmacklem * notice, this list of conditions and the following disclaimer. 10192811Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 11192811Srmacklem * notice, this list of conditions and the following disclaimer in the 12192811Srmacklem * documentation and/or other materials provided with the distribution. 13192811Srmacklem * 14192811Srmacklem * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15192811Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16192811Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17192811Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18192811Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19192811Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20192811Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21192811Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22192811Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23192811Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24192811Srmacklem * SUCH DAMAGE. 25192811Srmacklem * 26192811Srmacklem */ 27192811Srmacklem 28192811Srmacklem#include <sys/cdefs.h> 29192811Srmacklem__FBSDID("$FreeBSD$"); 30192811Srmacklem 31192811Srmacklem#include <sys/param.h> 32192811Srmacklem#include <sys/linker.h> 33192811Srmacklem#include <sys/module.h> 34192811Srmacklem#include <sys/socket.h> 35192811Srmacklem 36192811Srmacklem#include <arpa/inet.h> 37192811Srmacklem 38192811Srmacklem#include <netinet/in.h> 39192811Srmacklem 40192811Srmacklem#include <nfs/nfssvc.h> 41192811Srmacklem 42192811Srmacklem#include <fs/nfs/rpcv2.h> 43192811Srmacklem#include <fs/nfs/nfsproto.h> 44192811Srmacklem#include <fs/nfs/nfskpiport.h> 45192811Srmacklem#include <fs/nfs/nfs.h> 46192811Srmacklem 47192811Srmacklem#include <ctype.h> 48192811Srmacklem#include <err.h> 49192811Srmacklem#include <errno.h> 50192811Srmacklem#include <stdio.h> 51192811Srmacklem#include <stdlib.h> 52192811Srmacklem#include <string.h> 53192811Srmacklem#include <unistd.h> 54192811Srmacklem 55192811Srmacklem#define DUMPSIZE 10000 56192811Srmacklem 57192811Srmacklemstatic void dump_lockstate(char *); 58192811Srmacklemstatic void dump_openstate(void); 59192811Srmacklemstatic void usage(void); 60192811Srmacklemstatic char *open_flags(uint32_t); 61192811Srmacklemstatic char *deleg_flags(uint32_t); 62192811Srmacklemstatic char *lock_flags(uint32_t); 63192811Srmacklemstatic char *client_flags(uint32_t); 64192811Srmacklem 65192811Srmacklemstatic struct nfsd_dumpclients dp[DUMPSIZE]; 66192811Srmacklemstatic struct nfsd_dumplocks lp[DUMPSIZE]; 67192811Srmacklemstatic char flag_string[20]; 68192811Srmacklem 69192811Srmacklemint 70192811Srmacklemmain(int argc, char **argv) 71192811Srmacklem{ 72192811Srmacklem int ch, openstate; 73192811Srmacklem char *lockfile; 74192811Srmacklem 75192811Srmacklem if (modfind("nfsd") < 0) 76192811Srmacklem errx(1, "nfsd not loaded - self terminating"); 77192811Srmacklem openstate = 0; 78192811Srmacklem lockfile = NULL; 79210272Srmacklem while ((ch = getopt(argc, argv, "ol:")) != -1) 80192811Srmacklem switch (ch) { 81192811Srmacklem case 'o': 82192811Srmacklem openstate = 1; 83192811Srmacklem break; 84192811Srmacklem case 'l': 85192811Srmacklem lockfile = optarg; 86192811Srmacklem break; 87192811Srmacklem default: 88192811Srmacklem usage(); 89192811Srmacklem } 90192811Srmacklem argc -= optind; 91192811Srmacklem argv += optind; 92192811Srmacklem 93192811Srmacklem if (openstate == 0 && lockfile == NULL) 94192811Srmacklem openstate = 1; 95192811Srmacklem else if (openstate != 0 && lockfile != NULL) 96192811Srmacklem errx(1, "-o and -l cannot both be specified"); 97192811Srmacklem 98192811Srmacklem /* 99192811Srmacklem * For -o, dump all open/lock state. 100192811Srmacklem * For -l, dump lock state for that file. 101192811Srmacklem */ 102192811Srmacklem if (openstate != 0) 103192811Srmacklem dump_openstate(); 104192811Srmacklem else 105192811Srmacklem dump_lockstate(lockfile); 106192811Srmacklem exit(0); 107192811Srmacklem} 108192811Srmacklem 109192811Srmacklemstatic void 110192811Srmacklemusage(void) 111192811Srmacklem{ 112192811Srmacklem 113192811Srmacklem errx(1, "usage: nfsdumpstate [-o] [-l]"); 114192811Srmacklem} 115192811Srmacklem 116192811Srmacklem/* 117192811Srmacklem * Dump all open/lock state. 118192811Srmacklem */ 119192811Srmacklemstatic void 120192811Srmacklemdump_openstate(void) 121192811Srmacklem{ 122192811Srmacklem struct nfsd_dumplist dumplist; 123192811Srmacklem int cnt, i; 124192811Srmacklem 125192811Srmacklem dumplist.ndl_size = DUMPSIZE; 126192811Srmacklem dumplist.ndl_list = (void *)dp; 127192811Srmacklem if (nfssvc(NFSSVC_DUMPCLIENTS, &dumplist) < 0) 128192811Srmacklem errx(1, "Can't perform dump clients syscall"); 129192811Srmacklem 130192811Srmacklem printf("%-13s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %-15s %s\n", 131192811Srmacklem "Flags", "OpenOwner", "Open", "LockOwner", 132192811Srmacklem "Lock", "Deleg", "OldDeleg", "Clientaddr", "ClientID"); 133192811Srmacklem /* 134192811Srmacklem * Loop through results, printing them out. 135192811Srmacklem */ 136192811Srmacklem cnt = 0; 137192811Srmacklem while (dp[cnt].ndcl_clid.nclid_idlen > 0 && cnt < DUMPSIZE) { 138192811Srmacklem printf("%-13s ", client_flags(dp[cnt].ndcl_flags)); 139192811Srmacklem printf("%9d %9d %9d %9d %9d %9d ", 140192811Srmacklem dp[cnt].ndcl_nopenowners, 141192811Srmacklem dp[cnt].ndcl_nopens, 142192811Srmacklem dp[cnt].ndcl_nlockowners, 143192811Srmacklem dp[cnt].ndcl_nlocks, 144192811Srmacklem dp[cnt].ndcl_ndelegs, 145192811Srmacklem dp[cnt].ndcl_nolddelegs); 146192811Srmacklem if (dp[cnt].ndcl_addrfam == AF_INET) 147192811Srmacklem printf("%-15s ", 148192811Srmacklem inet_ntoa(dp[cnt].ndcl_cbaddr.sin_addr)); 149192811Srmacklem for (i = 0; i < dp[cnt].ndcl_clid.nclid_idlen; i++) 150192811Srmacklem printf("%02x", dp[cnt].ndcl_clid.nclid_id[i]); 151192811Srmacklem printf("\n"); 152192811Srmacklem cnt++; 153192811Srmacklem } 154192811Srmacklem} 155192811Srmacklem 156192811Srmacklem/* 157192811Srmacklem * Dump the lock state for a file. 158192811Srmacklem */ 159192811Srmacklemstatic void 160192811Srmacklemdump_lockstate(char *fname) 161192811Srmacklem{ 162192811Srmacklem struct nfsd_dumplocklist dumplocklist; 163192811Srmacklem int cnt, i; 164192811Srmacklem 165192811Srmacklem dumplocklist.ndllck_size = DUMPSIZE; 166192811Srmacklem dumplocklist.ndllck_list = (void *)lp; 167192811Srmacklem dumplocklist.ndllck_fname = fname; 168192811Srmacklem if (nfssvc(NFSSVC_DUMPLOCKS, &dumplocklist) < 0) 169192811Srmacklem errx(1, "Can't dump locks for %s\n", fname); 170192811Srmacklem 171192811Srmacklem printf("%-11s %-36s %-15s %s\n", 172192811Srmacklem "Open/Lock", 173192811Srmacklem " Stateid or Lock Range", 174192811Srmacklem "Clientaddr", 175192811Srmacklem "Owner and ClientID"); 176192811Srmacklem /* 177192811Srmacklem * Loop through results, printing them out. 178192811Srmacklem */ 179192811Srmacklem cnt = 0; 180192811Srmacklem while (lp[cnt].ndlck_clid.nclid_idlen > 0 && cnt < DUMPSIZE) { 181192811Srmacklem if (lp[cnt].ndlck_flags & NFSLCK_OPEN) 182192811Srmacklem printf("%-11s %9d %08x %08x %08x ", 183192811Srmacklem open_flags(lp[cnt].ndlck_flags), 184192811Srmacklem lp[cnt].ndlck_stateid.seqid, 185192811Srmacklem lp[cnt].ndlck_stateid.other[0], 186192811Srmacklem lp[cnt].ndlck_stateid.other[1], 187192811Srmacklem lp[cnt].ndlck_stateid.other[2]); 188192811Srmacklem else if (lp[cnt].ndlck_flags & (NFSLCK_DELEGREAD | 189192811Srmacklem NFSLCK_DELEGWRITE)) 190192811Srmacklem printf("%-11s %9d %08x %08x %08x ", 191192811Srmacklem deleg_flags(lp[cnt].ndlck_flags), 192192811Srmacklem lp[cnt].ndlck_stateid.seqid, 193192811Srmacklem lp[cnt].ndlck_stateid.other[0], 194192811Srmacklem lp[cnt].ndlck_stateid.other[1], 195192811Srmacklem lp[cnt].ndlck_stateid.other[2]); 196192811Srmacklem else 197193070Sdelphij printf("%-11s %17jd %17jd ", 198192811Srmacklem lock_flags(lp[cnt].ndlck_flags), 199192811Srmacklem lp[cnt].ndlck_first, 200192811Srmacklem lp[cnt].ndlck_end); 201192811Srmacklem if (lp[cnt].ndlck_addrfam == AF_INET) 202192811Srmacklem printf("%-15s ", 203192811Srmacklem inet_ntoa(lp[cnt].ndlck_cbaddr.sin_addr)); 204192811Srmacklem else 205192811Srmacklem printf("%-15s ", " "); 206192811Srmacklem for (i = 0; i < lp[cnt].ndlck_owner.nclid_idlen; i++) 207192811Srmacklem printf("%02x", lp[cnt].ndlck_owner.nclid_id[i]); 208192811Srmacklem printf(" "); 209192811Srmacklem for (i = 0; i < lp[cnt].ndlck_clid.nclid_idlen; i++) 210192811Srmacklem printf("%02x", lp[cnt].ndlck_clid.nclid_id[i]); 211192811Srmacklem printf("\n"); 212192811Srmacklem cnt++; 213192811Srmacklem } 214192811Srmacklem} 215192811Srmacklem 216192811Srmacklem/* 217192811Srmacklem * Parse the Open/Lock flag bits and create a string to be printed. 218192811Srmacklem */ 219192811Srmacklemstatic char * 220192811Srmacklemopen_flags(uint32_t flags) 221192811Srmacklem{ 222192811Srmacklem int i, j; 223192811Srmacklem 224192811Srmacklem strlcpy(flag_string, "Open ", sizeof (flag_string)); 225192811Srmacklem i = 5; 226192811Srmacklem if (flags & NFSLCK_READACCESS) 227192811Srmacklem flag_string[i++] = 'R'; 228192811Srmacklem if (flags & NFSLCK_WRITEACCESS) 229192811Srmacklem flag_string[i++] = 'W'; 230192811Srmacklem flag_string[i++] = ' '; 231192811Srmacklem flag_string[i++] = 'D'; 232192811Srmacklem flag_string[i] = 'N'; 233192811Srmacklem j = i; 234192811Srmacklem if (flags & NFSLCK_READDENY) 235192811Srmacklem flag_string[i++] = 'R'; 236192811Srmacklem if (flags & NFSLCK_WRITEDENY) 237192811Srmacklem flag_string[i++] = 'W'; 238192811Srmacklem if (i == j) 239192811Srmacklem i++; 240192811Srmacklem flag_string[i] = '\0'; 241192811Srmacklem return (flag_string); 242192811Srmacklem} 243192811Srmacklem 244192811Srmacklemstatic char * 245192811Srmacklemdeleg_flags(uint32_t flags) 246192811Srmacklem{ 247192811Srmacklem 248192811Srmacklem if (flags & NFSLCK_DELEGREAD) 249192811Srmacklem strlcpy(flag_string, "Deleg R", sizeof (flag_string)); 250192811Srmacklem else 251192811Srmacklem strlcpy(flag_string, "Deleg W", sizeof (flag_string)); 252192811Srmacklem return (flag_string); 253192811Srmacklem} 254192811Srmacklem 255192811Srmacklemstatic char * 256192811Srmacklemlock_flags(uint32_t flags) 257192811Srmacklem{ 258192811Srmacklem 259192811Srmacklem if (flags & NFSLCK_READ) 260192811Srmacklem strlcpy(flag_string, "Lock R", sizeof (flag_string)); 261192811Srmacklem else 262192811Srmacklem strlcpy(flag_string, "Lock W", sizeof (flag_string)); 263192811Srmacklem return (flag_string); 264192811Srmacklem} 265192811Srmacklem 266192811Srmacklemstatic char * 267192811Srmacklemclient_flags(uint32_t flags) 268192811Srmacklem{ 269192811Srmacklem 270192811Srmacklem flag_string[0] = '\0'; 271192811Srmacklem if (flags & LCL_NEEDSCONFIRM) 272192811Srmacklem strlcat(flag_string, "NC ", sizeof (flag_string)); 273192811Srmacklem if (flags & LCL_CALLBACKSON) 274192811Srmacklem strlcat(flag_string, "CB ", sizeof (flag_string)); 275192811Srmacklem if (flags & LCL_GSS) 276192811Srmacklem strlcat(flag_string, "GSS ", sizeof (flag_string)); 277192811Srmacklem if (flags & LCL_ADMINREVOKED) 278192811Srmacklem strlcat(flag_string, "REV", sizeof (flag_string)); 279192811Srmacklem return (flag_string); 280192811Srmacklem} 281