1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* LINTLIBRARY */ 23 /* PROTOLIB1 */ 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 29 */ 30 31 /* 32 * nfsstat: Network File System statistics 33 * 34 */ 35 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <unistd.h> 39 #include <stdarg.h> 40 #include <string.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <kvm.h> 44 #include <kstat.h> 45 #include <sys/param.h> 46 #include <sys/types.h> 47 #include <sys/t_lock.h> 48 #include <sys/tiuser.h> 49 #include <sys/statvfs.h> 50 #include <sys/mntent.h> 51 #include <sys/mnttab.h> 52 #include <sys/sysmacros.h> 53 #include <sys/mkdev.h> 54 #include <rpc/types.h> 55 #include <rpc/xdr.h> 56 #include <rpc/auth.h> 57 #include <rpc/clnt.h> 58 #include <nfs/nfs.h> 59 #include <nfs/nfs_clnt.h> 60 #include <nfs/nfs_sec.h> 61 #include <inttypes.h> 62 #include <signal.h> 63 #include <time.h> 64 #include <sys/time.h> 65 #include <strings.h> 66 #include <ctype.h> 67 #include <locale.h> 68 69 #include "statcommon.h" 70 71 static kstat_ctl_t *kc = NULL; /* libkstat cookie */ 72 static kstat_t *rpc_clts_client_kstat, *rpc_clts_server_kstat; 73 static kstat_t *rpc_cots_client_kstat, *rpc_cots_server_kstat; 74 static kstat_t *rpc_rdma_client_kstat, *rpc_rdma_server_kstat; 75 static kstat_t *nfs_client_kstat, *nfs_server_v2_kstat, *nfs_server_v3_kstat; 76 static kstat_t *nfs4_client_kstat, *nfs_server_v4_kstat; 77 static kstat_t *rfsproccnt_v2_kstat, *rfsproccnt_v3_kstat, *rfsproccnt_v4_kstat; 78 static kstat_t *rfsreqcnt_v2_kstat, *rfsreqcnt_v3_kstat, *rfsreqcnt_v4_kstat; 79 static kstat_t *aclproccnt_v2_kstat, *aclproccnt_v3_kstat; 80 static kstat_t *aclreqcnt_v2_kstat, *aclreqcnt_v3_kstat; 81 static kstat_t *ksum_kstat; 82 83 static void handle_sig(int); 84 static int getstats_rpc(void); 85 static int getstats_nfs(void); 86 static int getstats_rfsproc(int); 87 static int getstats_rfsreq(int); 88 static int getstats_aclproc(void); 89 static int getstats_aclreq(void); 90 static void putstats(void); 91 static void setup(void); 92 static void cr_print(int); 93 static void sr_print(int); 94 static void cn_print(int, int); 95 static void sn_print(int, int); 96 static void ca_print(int, int); 97 static void sa_print(int, int); 98 static void req_print(kstat_t *, kstat_t *, int, int, int); 99 static void req_print_v4(kstat_t *, kstat_t *, int, int); 100 static void stat_print(const char *, kstat_t *, kstat_t *, int, int); 101 static void nfsstat_kstat_sum(kstat_t *, kstat_t *, kstat_t *); 102 static void stats_timer(int); 103 static void safe_zalloc(void **, uint_t, int); 104 static int safe_strtoi(char const *, char *); 105 106 107 static void nfsstat_kstat_copy(kstat_t *, kstat_t *, int); 108 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *); 109 static kid_t safe_kstat_write(kstat_ctl_t *, kstat_t *, void *); 110 111 static void usage(void); 112 static void mi_print(void); 113 static int ignore(char *); 114 static int interval; /* interval between stats */ 115 static int count; /* number of iterations the stat is printed */ 116 #define MAX_COLUMNS 80 117 #define MAX_PATHS 50 /* max paths that can be taken by -m */ 118 119 /* 120 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot 121 * include that file here. Same with MI4_REFERRAL. 122 */ 123 #define MI4_MIRRORMOUNT 0x4000 124 #define MI4_REFERRAL 0x8000 125 #define NFS_V4 4 126 127 static int req_width(kstat_t *, int); 128 static int stat_width(kstat_t *, int); 129 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */ 130 131 /* 132 * Struct holds the previous kstat values so 133 * we can compute deltas when using the -i flag 134 */ 135 typedef struct old_kstat 136 { 137 kstat_t kst; 138 int tot; 139 } old_kstat_t; 140 141 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat; 142 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat; 143 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat; 144 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat; 145 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat; 146 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat; 147 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat; 148 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat; 149 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat; 150 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat; 151 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat; 152 153 static uint_t timestamp_fmt = NODATE; 154 155 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 156 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't */ 157 #endif 158 159 int 160 main(int argc, char *argv[]) 161 { 162 int c, go_forever, j; 163 int cflag = 0; /* client stats */ 164 int sflag = 0; /* server stats */ 165 int nflag = 0; /* nfs stats */ 166 int rflag = 0; /* rpc stats */ 167 int mflag = 0; /* mount table stats */ 168 int aflag = 0; /* print acl statistics */ 169 int vflag = 0; /* version specified, 0 specifies all */ 170 int zflag = 0; /* zero stats after printing */ 171 char *split_line = "*******************************************" 172 "*************************************"; 173 174 interval = 0; 175 count = 0; 176 go_forever = 0; 177 178 (void) setlocale(LC_ALL, ""); 179 (void) textdomain(TEXT_DOMAIN); 180 181 while ((c = getopt(argc, argv, "cnrsmzav:T:")) != EOF) { 182 switch (c) { 183 case 'c': 184 cflag++; 185 break; 186 case 'n': 187 nflag++; 188 break; 189 case 'r': 190 rflag++; 191 break; 192 case 's': 193 sflag++; 194 break; 195 case 'm': 196 mflag++; 197 break; 198 case 'z': 199 if (geteuid()) 200 fail(0, "Must be root for z flag\n"); 201 zflag++; 202 break; 203 case 'a': 204 aflag++; 205 break; 206 case 'v': 207 vflag = atoi(optarg); 208 if ((vflag < 2) || (vflag > 4)) 209 fail(0, "Invalid version number\n"); 210 break; 211 case 'T': 212 if (optarg) { 213 if (*optarg == 'u') 214 timestamp_fmt = UDATE; 215 else if (*optarg == 'd') 216 timestamp_fmt = DDATE; 217 else 218 usage(); 219 } else { 220 usage(); 221 } 222 break; 223 case '?': 224 default: 225 usage(); 226 } 227 } 228 229 if (((argc - optind) > 0) && !mflag) { 230 231 interval = safe_strtoi(argv[optind], "invalid interval"); 232 if (interval < 1) 233 fail(0, "invalid interval\n"); 234 optind++; 235 236 if ((argc - optind) > 0) { 237 count = safe_strtoi(argv[optind], "invalid count"); 238 if ((count <= 0) || (count == NULL)) 239 fail(0, "invalid count\n"); 240 } 241 optind++; 242 243 if ((argc - optind) > 0) 244 usage(); 245 246 /* 247 * no count number was set, so we will loop infinitely 248 * at interval specified 249 */ 250 if (!count) 251 go_forever = 1; 252 stats_timer(interval); 253 } else if (mflag) { 254 255 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag) 256 fail(0, 257 "The -m flag may not be used with any other flags"); 258 259 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) { 260 path[j] = argv[optind]; 261 if (*path[j] != '/') 262 fail(0, "Please fully qualify your pathname " 263 "with a leading '/'"); 264 optind++; 265 } 266 path[j] = NULL; 267 if (argc - optind > 0) 268 fprintf(stderr, "Only the first 50 paths " 269 "will be searched for\n"); 270 } 271 272 setup(); 273 274 do { 275 if (mflag) { 276 mi_print(); 277 } else { 278 if (timestamp_fmt != NODATE) 279 print_timestamp(timestamp_fmt); 280 281 if (sflag && 282 (rpc_clts_server_kstat == NULL || 283 nfs_server_v4_kstat == NULL)) { 284 fprintf(stderr, 285 "nfsstat: kernel is not configured with " 286 "the server nfs and rpc code.\n"); 287 } 288 289 /* if s and nothing else, all 3 prints are called */ 290 if (sflag || (!sflag && !cflag)) { 291 if (rflag || (!rflag && !nflag && !aflag)) 292 sr_print(zflag); 293 if (nflag || (!rflag && !nflag && !aflag)) 294 sn_print(zflag, vflag); 295 if (aflag || (!rflag && !nflag && !aflag)) 296 sa_print(zflag, vflag); 297 } 298 if (cflag && 299 (rpc_clts_client_kstat == NULL || 300 nfs_client_kstat == NULL)) { 301 fprintf(stderr, 302 "nfsstat: kernel is not configured with" 303 " the client nfs and rpc code.\n"); 304 } 305 if (cflag || (!sflag && !cflag)) { 306 if (rflag || (!rflag && !nflag && !aflag)) 307 cr_print(zflag); 308 if (nflag || (!rflag && !nflag && !aflag)) 309 cn_print(zflag, vflag); 310 if (aflag || (!rflag && !nflag && !aflag)) 311 ca_print(zflag, vflag); 312 } 313 } 314 315 if (zflag) 316 putstats(); 317 if (interval) 318 printf("%s\n", split_line); 319 320 if (interval > 0) 321 (void) pause(); 322 } while ((--count > 0) || go_forever); 323 324 kstat_close(kc); 325 free(ksum_kstat); 326 return (0); 327 } 328 329 330 static int 331 getstats_rpc(void) 332 { 333 int field_width = 0; 334 335 if (rpc_clts_client_kstat != NULL) { 336 safe_kstat_read(kc, rpc_clts_client_kstat, NULL); 337 field_width = stat_width(rpc_clts_client_kstat, field_width); 338 } 339 340 if (rpc_cots_client_kstat != NULL) { 341 safe_kstat_read(kc, rpc_cots_client_kstat, NULL); 342 field_width = stat_width(rpc_cots_client_kstat, field_width); 343 } 344 345 if (rpc_rdma_client_kstat != NULL) { 346 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL); 347 field_width = stat_width(rpc_rdma_client_kstat, field_width); 348 } 349 350 if (rpc_clts_server_kstat != NULL) { 351 safe_kstat_read(kc, rpc_clts_server_kstat, NULL); 352 field_width = stat_width(rpc_clts_server_kstat, field_width); 353 } 354 if (rpc_cots_server_kstat != NULL) { 355 safe_kstat_read(kc, rpc_cots_server_kstat, NULL); 356 field_width = stat_width(rpc_cots_server_kstat, field_width); 357 } 358 if (rpc_rdma_server_kstat != NULL) { 359 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL); 360 field_width = stat_width(rpc_rdma_server_kstat, field_width); 361 } 362 return (field_width); 363 } 364 365 static int 366 getstats_nfs(void) 367 { 368 int field_width = 0; 369 370 if (nfs_client_kstat != NULL) { 371 safe_kstat_read(kc, nfs_client_kstat, NULL); 372 field_width = stat_width(nfs_client_kstat, field_width); 373 } 374 if (nfs4_client_kstat != NULL) { 375 safe_kstat_read(kc, nfs4_client_kstat, NULL); 376 field_width = stat_width(nfs4_client_kstat, field_width); 377 } 378 if (nfs_server_v2_kstat != NULL) { 379 safe_kstat_read(kc, nfs_server_v2_kstat, NULL); 380 field_width = stat_width(nfs_server_v2_kstat, field_width); 381 } 382 if (nfs_server_v3_kstat != NULL) { 383 safe_kstat_read(kc, nfs_server_v3_kstat, NULL); 384 field_width = stat_width(nfs_server_v3_kstat, field_width); 385 } 386 if (nfs_server_v4_kstat != NULL) { 387 safe_kstat_read(kc, nfs_server_v4_kstat, NULL); 388 field_width = stat_width(nfs_server_v4_kstat, field_width); 389 } 390 return (field_width); 391 } 392 393 static int 394 getstats_rfsproc(int ver) 395 { 396 int field_width = 0; 397 398 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) { 399 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL); 400 field_width = req_width(rfsproccnt_v2_kstat, field_width); 401 } 402 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) { 403 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL); 404 field_width = req_width(rfsproccnt_v3_kstat, field_width); 405 } 406 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) { 407 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL); 408 field_width = req_width(rfsproccnt_v4_kstat, field_width); 409 } 410 return (field_width); 411 } 412 413 static int 414 getstats_rfsreq(int ver) 415 { 416 int field_width = 0; 417 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) { 418 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL); 419 field_width = req_width(rfsreqcnt_v2_kstat, field_width); 420 } 421 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) { 422 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL); 423 field_width = req_width(rfsreqcnt_v3_kstat, field_width); 424 } 425 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) { 426 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL); 427 field_width = req_width(rfsreqcnt_v4_kstat, field_width); 428 } 429 return (field_width); 430 } 431 432 static int 433 getstats_aclproc(void) 434 { 435 int field_width = 0; 436 if (aclproccnt_v2_kstat != NULL) { 437 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL); 438 field_width = req_width(aclproccnt_v2_kstat, field_width); 439 } 440 if (aclproccnt_v3_kstat != NULL) { 441 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL); 442 field_width = req_width(aclproccnt_v3_kstat, field_width); 443 } 444 return (field_width); 445 } 446 447 static int 448 getstats_aclreq(void) 449 { 450 int field_width = 0; 451 if (aclreqcnt_v2_kstat != NULL) { 452 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL); 453 field_width = req_width(aclreqcnt_v2_kstat, field_width); 454 } 455 if (aclreqcnt_v3_kstat != NULL) { 456 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL); 457 field_width = req_width(aclreqcnt_v3_kstat, field_width); 458 } 459 return (field_width); 460 } 461 462 static void 463 putstats(void) 464 { 465 if (rpc_clts_client_kstat != NULL) 466 safe_kstat_write(kc, rpc_clts_client_kstat, NULL); 467 if (rpc_cots_client_kstat != NULL) 468 safe_kstat_write(kc, rpc_cots_client_kstat, NULL); 469 if (rpc_rdma_client_kstat != NULL) 470 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL); 471 if (nfs_client_kstat != NULL) 472 safe_kstat_write(kc, nfs_client_kstat, NULL); 473 if (nfs4_client_kstat != NULL) 474 safe_kstat_write(kc, nfs4_client_kstat, NULL); 475 if (rpc_clts_server_kstat != NULL) 476 safe_kstat_write(kc, rpc_clts_server_kstat, NULL); 477 if (rpc_cots_server_kstat != NULL) 478 safe_kstat_write(kc, rpc_cots_server_kstat, NULL); 479 if (rpc_rdma_server_kstat != NULL) 480 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL); 481 if (nfs_server_v2_kstat != NULL) 482 safe_kstat_write(kc, nfs_server_v2_kstat, NULL); 483 if (nfs_server_v3_kstat != NULL) 484 safe_kstat_write(kc, nfs_server_v3_kstat, NULL); 485 if (nfs_server_v4_kstat != NULL) 486 safe_kstat_write(kc, nfs_server_v4_kstat, NULL); 487 if (rfsproccnt_v2_kstat != NULL) 488 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL); 489 if (rfsproccnt_v3_kstat != NULL) 490 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL); 491 if (rfsproccnt_v4_kstat != NULL) 492 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL); 493 if (rfsreqcnt_v2_kstat != NULL) 494 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL); 495 if (rfsreqcnt_v3_kstat != NULL) 496 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL); 497 if (rfsreqcnt_v4_kstat != NULL) 498 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL); 499 if (aclproccnt_v2_kstat != NULL) 500 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL); 501 if (aclproccnt_v3_kstat != NULL) 502 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL); 503 if (aclreqcnt_v2_kstat != NULL) 504 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL); 505 if (aclreqcnt_v3_kstat != NULL) 506 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL); 507 } 508 509 static void 510 setup(void) 511 { 512 if ((kc = kstat_open()) == NULL) 513 fail(1, "kstat_open(): can't open /dev/kstat"); 514 515 /* alloc space for our temporary kstat */ 516 safe_zalloc((void **)&ksum_kstat, sizeof (kstat_t), 0); 517 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client"); 518 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server"); 519 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client"); 520 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server"); 521 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client"); 522 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server"); 523 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client"); 524 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client"); 525 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server"); 526 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server"); 527 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server"); 528 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2"); 529 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3"); 530 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4"); 531 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2"); 532 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3"); 533 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4"); 534 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2"); 535 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3"); 536 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2"); 537 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3"); 538 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL && 539 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL) 540 fail(0, "Multiple kstat lookups failed." 541 "Your kernel module may not be loaded\n"); 542 } 543 544 static int 545 req_width(kstat_t *req, int field_width) 546 { 547 int i, nreq, per, len; 548 char fixlen[128]; 549 kstat_named_t *knp; 550 uint64_t tot; 551 552 tot = 0; 553 knp = KSTAT_NAMED_PTR(req); 554 for (i = 0; i < req->ks_ndata; i++) 555 tot += knp[i].value.ui64; 556 557 knp = kstat_data_lookup(req, "null"); 558 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 559 560 for (i = 0; i < nreq; i++) { 561 len = strlen(knp[i].name) + 1; 562 if (field_width < len) 563 field_width = len; 564 if (tot) 565 per = (int)(knp[i].value.ui64 * 100 / tot); 566 else 567 per = 0; 568 (void) sprintf(fixlen, "%" PRIu64 " %d%%", 569 knp[i].value.ui64, per); 570 len = strlen(fixlen) + 1; 571 if (field_width < len) 572 field_width = len; 573 } 574 return (field_width); 575 } 576 577 static int 578 stat_width(kstat_t *req, int field_width) 579 { 580 int i, nreq, len; 581 char fixlen[128]; 582 kstat_named_t *knp; 583 584 knp = KSTAT_NAMED_PTR(req); 585 nreq = req->ks_ndata; 586 587 for (i = 0; i < nreq; i++) { 588 len = strlen(knp[i].name) + 1; 589 if (field_width < len) 590 field_width = len; 591 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64); 592 len = strlen(fixlen) + 1; 593 if (field_width < len) 594 field_width = len; 595 } 596 return (field_width); 597 } 598 599 static void 600 cr_print(int zflag) 601 { 602 int field_width; 603 604 field_width = getstats_rpc(); 605 if (field_width == 0) 606 return; 607 608 stat_print("\nClient rpc:\nConnection oriented:", 609 rpc_cots_client_kstat, 610 &old_rpc_cots_client_kstat.kst, field_width, zflag); 611 stat_print("Connectionless:", rpc_clts_client_kstat, 612 &old_rpc_clts_client_kstat.kst, field_width, zflag); 613 stat_print("RDMA based:", rpc_rdma_client_kstat, 614 &old_rpc_rdma_client_kstat.kst, field_width, zflag); 615 } 616 617 static void 618 sr_print(int zflag) 619 { 620 int field_width; 621 622 field_width = getstats_rpc(); 623 if (field_width == 0) 624 return; 625 626 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat, 627 &old_rpc_cots_server_kstat.kst, field_width, zflag); 628 stat_print("Connectionless:", rpc_clts_server_kstat, 629 &old_rpc_clts_server_kstat.kst, field_width, zflag); 630 stat_print("RDMA based:", rpc_rdma_server_kstat, 631 &old_rpc_rdma_server_kstat.kst, field_width, zflag); 632 } 633 634 static void 635 cn_print(int zflag, int vflag) 636 { 637 int field_width; 638 639 field_width = getstats_nfs(); 640 if (field_width == 0) 641 return; 642 643 if (vflag == 0) { 644 nfsstat_kstat_sum(nfs_client_kstat, nfs4_client_kstat, 645 ksum_kstat); 646 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst, 647 field_width, zflag); 648 } 649 650 if (vflag == 2 || vflag == 3) { 651 stat_print("\nClient nfs:", nfs_client_kstat, 652 &old_nfs_client_kstat.kst, field_width, zflag); 653 } 654 655 if (vflag == 4) { 656 stat_print("\nClient nfs:", nfs4_client_kstat, 657 &old_nfs4_client_kstat.kst, field_width, zflag); 658 } 659 660 if (vflag == 2 || vflag == 0) { 661 field_width = getstats_rfsreq(2); 662 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst, 663 2, field_width, zflag); 664 } 665 666 if (vflag == 3 || vflag == 0) { 667 field_width = getstats_rfsreq(3); 668 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3, 669 field_width, zflag); 670 } 671 672 if (vflag == 4 || vflag == 0) { 673 field_width = getstats_rfsreq(4); 674 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst, 675 field_width, zflag); 676 } 677 } 678 679 static void 680 sn_print(int zflag, int vflag) 681 { 682 int field_width; 683 684 field_width = getstats_nfs(); 685 if (field_width == 0) 686 return; 687 688 if (vflag == 2 || vflag == 0) { 689 stat_print("\nServer NFSv2:", nfs_server_v2_kstat, 690 &old_nfs_server_v2_kstat.kst, field_width, zflag); 691 } 692 693 if (vflag == 3 || vflag == 0) { 694 stat_print("\nServer NFSv3:", nfs_server_v3_kstat, 695 &old_nfs_server_v3_kstat.kst, field_width, zflag); 696 } 697 698 if (vflag == 4 || vflag == 0) { 699 stat_print("\nServer NFSv4:", nfs_server_v4_kstat, 700 &old_nfs_server_v4_kstat.kst, field_width, zflag); 701 } 702 703 if (vflag == 2 || vflag == 0) { 704 field_width = getstats_rfsproc(2); 705 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst, 706 2, field_width, zflag); 707 } 708 709 if (vflag == 3 || vflag == 0) { 710 field_width = getstats_rfsproc(3); 711 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst, 712 3, field_width, zflag); 713 } 714 715 if (vflag == 4 || vflag == 0) { 716 field_width = getstats_rfsproc(4); 717 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst, 718 field_width, zflag); 719 } 720 } 721 722 static void 723 ca_print(int zflag, int vflag) 724 { 725 int field_width; 726 727 field_width = getstats_aclreq(); 728 if (field_width == 0) 729 return; 730 731 printf("\nClient nfs_acl:\n"); 732 733 if (vflag == 2 || vflag == 0) { 734 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2, 735 field_width, zflag); 736 } 737 738 if (vflag == 3 || vflag == 0) { 739 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst, 740 3, field_width, zflag); 741 } 742 } 743 744 static void 745 sa_print(int zflag, int vflag) 746 { 747 int field_width; 748 749 field_width = getstats_aclproc(); 750 if (field_width == 0) 751 return; 752 753 printf("\nServer nfs_acl:\n"); 754 755 if (vflag == 2 || vflag == 0) { 756 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst, 757 2, field_width, zflag); 758 } 759 760 if (vflag == 3 || vflag == 0) { 761 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst, 762 3, field_width, zflag); 763 } 764 } 765 766 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 767 768 static void 769 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width, 770 int zflag) 771 { 772 int i, j, nreq, per, ncolumns; 773 uint64_t tot, old_tot; 774 char fixlen[128]; 775 kstat_named_t *knp; 776 kstat_named_t *kptr; 777 kstat_named_t *knp_old; 778 779 if (req == NULL) 780 return; 781 782 if (field_width == 0) 783 return; 784 785 ncolumns = (MAX_COLUMNS -1)/field_width; 786 knp = kstat_data_lookup(req, "null"); 787 knp_old = KSTAT_NAMED_PTR(req_old); 788 789 kptr = KSTAT_NAMED_PTR(req); 790 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 791 792 tot = 0; 793 old_tot = 0; 794 795 if (knp_old == NULL) { 796 old_tot = 0; 797 } 798 799 for (i = 0; i < req->ks_ndata; i++) 800 tot += kptr[i].value.ui64; 801 802 if (interval && knp_old != NULL) { 803 for (i = 0; i < req_old->ks_ndata; i++) 804 old_tot += knp_old[i].value.ui64; 805 tot -= old_tot; 806 } 807 808 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot); 809 810 for (i = 0; i < nreq; i += ncolumns) { 811 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 812 printf("%-*s", field_width, knp[j].name); 813 } 814 printf("\n"); 815 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 816 if (tot && interval && knp_old != NULL) 817 per = (int)((knp[j].value.ui64 - 818 knp_old[j].value.ui64) * 100 / tot); 819 else if (tot) 820 per = (int)(knp[j].value.ui64 * 100 / tot); 821 else 822 per = 0; 823 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 824 ((interval && knp_old != NULL) ? 825 (knp[j].value.ui64 - knp_old[j].value.ui64) 826 : knp[j].value.ui64), per); 827 printf("%-*s", field_width, fixlen); 828 } 829 printf("\n"); 830 } 831 if (zflag) { 832 for (i = 0; i < req->ks_ndata; i++) 833 knp[i].value.ui64 = 0; 834 } 835 if (knp_old != NULL) 836 nfsstat_kstat_copy(req, req_old, 1); 837 else 838 nfsstat_kstat_copy(req, req_old, 0); 839 } 840 841 /* 842 * Separate version of the req_print() to deal with V4 and its use of 843 * procedures and operations. It looks odd to have the counts for 844 * both of those lumped into the same set of statistics so this 845 * function (copy of req_print() does the separation and titles). 846 */ 847 848 #define COUNT 2 849 850 static void 851 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) 852 { 853 int i, j, nreq, per, ncolumns; 854 uint64_t tot, tot_ops, old_tot, old_tot_ops; 855 char fixlen[128]; 856 kstat_named_t *kptr; 857 kstat_named_t *knp; 858 kstat_named_t *kptr_old; 859 860 if (req == NULL) 861 return; 862 863 if (field_width == 0) 864 return; 865 866 ncolumns = (MAX_COLUMNS)/field_width; 867 kptr = KSTAT_NAMED_PTR(req); 868 kptr_old = KSTAT_NAMED_PTR(req_old); 869 870 if (kptr_old == NULL) { 871 old_tot_ops = 0; 872 old_tot = 0; 873 } else { 874 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64; 875 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++) 876 old_tot_ops += kptr_old[i].value.ui64; 877 } 878 879 /* Count the number of operations sent */ 880 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++) 881 tot_ops += kptr[i].value.ui64; 882 /* For v4 NULL/COMPOUND are the only procedures */ 883 tot = kptr[0].value.ui64 + kptr[1].value.ui64; 884 885 if (interval) { 886 tot -= old_tot; 887 tot_ops -= old_tot_ops; 888 } 889 890 printf("Version 4: (%" PRIu64 " calls)\n", tot); 891 892 knp = kstat_data_lookup(req, "null"); 893 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 894 895 for (i = 0; i < COUNT; i += ncolumns) { 896 for (j = i; j < MIN(i + ncolumns, 2); j++) { 897 printf("%-*s", field_width, knp[j].name); 898 } 899 printf("\n"); 900 for (j = i; j < MIN(i + ncolumns, 2); j++) { 901 if (tot && interval && kptr_old != NULL) 902 per = (int)((knp[j].value.ui64 - 903 kptr_old[j].value.ui64) * 100 / tot); 904 else if (tot) 905 per = (int)(knp[j].value.ui64 * 100 / tot); 906 else 907 per = 0; 908 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 909 ((interval && kptr_old != NULL) ? 910 (knp[j].value.ui64 - kptr_old[j].value.ui64) 911 : knp[j].value.ui64), per); 912 printf("%-*s", field_width, fixlen); 913 } 914 printf("\n"); 915 } 916 917 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops); 918 for (i = 2; i < nreq; i += ncolumns) { 919 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 920 printf("%-*s", field_width, knp[j].name); 921 } 922 printf("\n"); 923 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 924 if (tot_ops && interval && kptr_old != NULL) 925 per = (int)((knp[j].value.ui64 - 926 kptr_old[j].value.ui64) * 100 / tot_ops); 927 else if (tot_ops) 928 per = (int)(knp[j].value.ui64 * 100 / tot_ops); 929 else 930 per = 0; 931 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 932 ((interval && kptr_old != NULL) ? 933 (knp[j].value.ui64 - kptr_old[j].value.ui64) 934 : knp[j].value.ui64), per); 935 printf("%-*s", field_width, fixlen); 936 } 937 printf("\n"); 938 } 939 if (zflag) { 940 for (i = 0; i < req->ks_ndata; i++) 941 kptr[i].value.ui64 = 0; 942 } 943 if (kptr_old != NULL) 944 nfsstat_kstat_copy(req, req_old, 1); 945 else 946 nfsstat_kstat_copy(req, req_old, 0); 947 } 948 949 static void 950 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, 951 int field_width, int zflag) 952 { 953 int i, j, nreq, ncolumns; 954 char fixlen[128]; 955 kstat_named_t *knp; 956 kstat_named_t *knp_old; 957 958 if (req == NULL) 959 return; 960 961 if (field_width == 0) 962 return; 963 964 printf("%s\n", title_string); 965 ncolumns = (MAX_COLUMNS -1)/field_width; 966 967 /* MEANS knp = (kstat_named_t *)req->ks_data */ 968 knp = KSTAT_NAMED_PTR(req); 969 nreq = req->ks_ndata; 970 knp_old = KSTAT_NAMED_PTR(req_old); 971 972 for (i = 0; i < nreq; i += ncolumns) { 973 /* prints out the titles of the columns */ 974 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 975 printf("%-*s", field_width, knp[j].name); 976 } 977 printf("\n"); 978 /* prints out the stat numbers */ 979 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 980 (void) sprintf(fixlen, "%" PRIu64 " ", 981 (interval && knp_old != NULL) ? 982 (knp[j].value.ui64 - knp_old[j].value.ui64) 983 : knp[j].value.ui64); 984 printf("%-*s", field_width, fixlen); 985 } 986 printf("\n"); 987 988 } 989 if (zflag) { 990 for (i = 0; i < req->ks_ndata; i++) 991 knp[i].value.ui64 = 0; 992 } 993 994 if (knp_old != NULL) 995 nfsstat_kstat_copy(req, req_old, 1); 996 else 997 nfsstat_kstat_copy(req, req_old, 0); 998 } 999 1000 static void 1001 nfsstat_kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum) 1002 { 1003 int i; 1004 kstat_named_t *knp1, *knp2, *knpsum; 1005 if (kstat1 == NULL || kstat2 == NULL) 1006 return; 1007 1008 knp1 = KSTAT_NAMED_PTR(kstat1); 1009 knp2 = KSTAT_NAMED_PTR(kstat2); 1010 if (sum->ks_data == NULL) 1011 nfsstat_kstat_copy(kstat1, sum, 0); 1012 knpsum = KSTAT_NAMED_PTR(sum); 1013 1014 for (i = 0; i < (kstat1->ks_ndata); i++) 1015 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64; 1016 } 1017 1018 /* 1019 * my_dir and my_path could be pointers 1020 */ 1021 struct myrec { 1022 ulong_t my_fsid; 1023 char my_dir[MAXPATHLEN]; 1024 char *my_path; 1025 char *ig_path; 1026 struct myrec *next; 1027 }; 1028 1029 /* 1030 * Print the mount table info 1031 */ 1032 static void 1033 mi_print(void) 1034 { 1035 FILE *mt; 1036 struct extmnttab m; 1037 struct myrec *list, *mrp, *pmrp; 1038 char *flavor; 1039 int ignored = 0; 1040 seconfig_t nfs_sec; 1041 kstat_t *ksp; 1042 struct mntinfo_kstat mik; 1043 int transport_flag = 0; 1044 int path_count; 1045 int found; 1046 char *timer_name[] = { 1047 "Lookups", 1048 "Reads", 1049 "Writes", 1050 "All" 1051 }; 1052 1053 mt = fopen(MNTTAB, "r"); 1054 if (mt == NULL) { 1055 perror(MNTTAB); 1056 exit(0); 1057 } 1058 1059 list = NULL; 1060 resetmnttab(mt); 1061 1062 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1063 /* ignore non "nfs" and save the "ignore" entries */ 1064 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0) 1065 continue; 1066 /* 1067 * Check to see here if user gave a path(s) to 1068 * only show the mount point they wanted 1069 * Iterate through the list of paths the user gave and see 1070 * if any of them match our current nfs mount 1071 */ 1072 if (path[0] != NULL) { 1073 found = 0; 1074 for (path_count = 0; path[path_count] != NULL; 1075 path_count++) { 1076 if (strcmp(path[path_count], m.mnt_mountp) 1077 == 0) { 1078 found = 1; 1079 break; 1080 } 1081 } 1082 if (!found) 1083 continue; 1084 } 1085 1086 if ((mrp = malloc(sizeof (struct myrec))) == 0) { 1087 fprintf(stderr, "nfsstat: not enough memory\n"); 1088 exit(1); 1089 } 1090 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor); 1091 if (ignore(m.mnt_mntopts)) { 1092 /* 1093 * ignored entries cannot be ignored for this 1094 * option. We have to display the info for this 1095 * nfs mount. The ignore is an indication 1096 * that the actual mount point is different and 1097 * something is in between the nfs mount. 1098 * So save the mount point now 1099 */ 1100 if ((mrp->ig_path = malloc( 1101 strlen(m.mnt_mountp) + 1)) == 0) { 1102 fprintf(stderr, "nfsstat: not enough memory\n"); 1103 exit(1); 1104 } 1105 (void) strcpy(mrp->ig_path, m.mnt_mountp); 1106 ignored++; 1107 } else { 1108 mrp->ig_path = 0; 1109 (void) strcpy(mrp->my_dir, m.mnt_mountp); 1110 } 1111 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) { 1112 fprintf(stderr, "nfsstat: not enough memory\n"); 1113 exit(1); 1114 } 1115 mrp->next = list; 1116 list = mrp; 1117 } 1118 1119 (void) fclose(mt); 1120 1121 if (ignored) { 1122 /* 1123 * Now ignored entries which do not have 1124 * the my_dir initialized are really ignored; This never 1125 * happens unless the mnttab is corrupted. 1126 */ 1127 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) { 1128 if (mrp->ig_path == 0) 1129 pmrp = mrp; 1130 else if (pmrp) 1131 pmrp->next = mrp->next; 1132 else 1133 list = mrp->next; 1134 } 1135 } 1136 1137 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1138 int i; 1139 1140 if (ksp->ks_type != KSTAT_TYPE_RAW) 1141 continue; 1142 if (strcmp(ksp->ks_module, "nfs") != 0) 1143 continue; 1144 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1145 continue; 1146 1147 for (mrp = list; mrp; mrp = mrp->next) { 1148 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance) 1149 break; 1150 } 1151 if (mrp == 0) 1152 continue; 1153 1154 if (safe_kstat_read(kc, ksp, &mik) == -1) 1155 continue; 1156 1157 printf("%s from %s\n", mrp->my_dir, mrp->my_path); 1158 1159 /* 1160 * for printing rdma transport and provider string. 1161 * This way we avoid modifying the kernel mntinfo_kstat 1162 * struct for protofmly. 1163 */ 1164 if (strcmp(mik.mik_proto, "ibtf") == 0) { 1165 printf(" Flags: vers=%u,proto=rdma", 1166 mik.mik_vers); 1167 transport_flag = 1; 1168 } else { 1169 printf(" Flags: vers=%u,proto=%s", 1170 mik.mik_vers, mik.mik_proto); 1171 transport_flag = 0; 1172 } 1173 1174 /* 1175 * get the secmode name from /etc/nfssec.conf. 1176 */ 1177 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) { 1178 flavor = nfs_sec.sc_name; 1179 } else 1180 flavor = NULL; 1181 1182 if (flavor != NULL) 1183 printf(",sec=%s", flavor); 1184 else 1185 printf(",sec#=%d", mik.mik_secmod); 1186 1187 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft"); 1188 if (mik.mik_flags & MI_PRINTED) 1189 printf(",printed"); 1190 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr"); 1191 if (mik.mik_flags & MI_DOWN) 1192 printf(",down"); 1193 if (mik.mik_flags & MI_NOAC) 1194 printf(",noac"); 1195 if (mik.mik_flags & MI_NOCTO) 1196 printf(",nocto"); 1197 if (mik.mik_flags & MI_DYNAMIC) 1198 printf(",dynamic"); 1199 if (mik.mik_flags & MI_LLOCK) 1200 printf(",llock"); 1201 if (mik.mik_flags & MI_GRPID) 1202 printf(",grpid"); 1203 if (mik.mik_flags & MI_RPCTIMESYNC) 1204 printf(",rpctimesync"); 1205 if (mik.mik_flags & MI_LINK) 1206 printf(",link"); 1207 if (mik.mik_flags & MI_SYMLINK) 1208 printf(",symlink"); 1209 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY) 1210 printf(",readdironly"); 1211 if (mik.mik_flags & MI_ACL) 1212 printf(",acl"); 1213 if (mik.mik_flags & MI_DIRECTIO) 1214 printf(",forcedirectio"); 1215 1216 if (mik.mik_vers >= NFS_V4) { 1217 if (mik.mik_flags & MI4_MIRRORMOUNT) 1218 printf(",mirrormount"); 1219 if (mik.mik_flags & MI4_REFERRAL) 1220 printf(",referral"); 1221 } 1222 1223 printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d", 1224 mik.mik_curread, mik.mik_curwrite, mik.mik_retrans, 1225 mik.mik_timeo); 1226 printf("\n"); 1227 printf(" Attr cache: acregmin=%d,acregmax=%d" 1228 ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin, 1229 mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax); 1230 1231 if (transport_flag) { 1232 printf(" Transport: proto=rdma, plugin=%s\n", 1233 mik.mik_proto); 1234 } 1235 1236 #define srtt_to_ms(x) x, (x * 2 + x / 2) 1237 #define dev_to_ms(x) x, (x * 5) 1238 1239 for (i = 0; i < NFS_CALLTYPES + 1; i++) { 1240 int j; 1241 1242 j = (i == NFS_CALLTYPES ? i - 1 : i); 1243 if (mik.mik_timers[j].srtt || 1244 mik.mik_timers[j].rtxcur) { 1245 printf(" %s: srtt=%d (%dms), " 1246 "dev=%d (%dms), cur=%u (%ums)\n", 1247 timer_name[i], 1248 srtt_to_ms(mik.mik_timers[i].srtt), 1249 dev_to_ms(mik.mik_timers[i].deviate), 1250 mik.mik_timers[i].rtxcur, 1251 mik.mik_timers[i].rtxcur * 20); 1252 } 1253 } 1254 1255 if (strchr(mrp->my_path, ',')) 1256 printf( 1257 " Failover: noresponse=%d,failover=%d," 1258 "remap=%d,currserver=%s\n", 1259 mik.mik_noresponse, mik.mik_failover, 1260 mik.mik_remap, mik.mik_curserver); 1261 printf("\n"); 1262 } 1263 } 1264 1265 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL }; 1266 #define IGNORE 0 1267 #define DEV 1 1268 1269 /* 1270 * Return 1 if "ignore" appears in the options string 1271 */ 1272 static int 1273 ignore(char *opts) 1274 { 1275 char *value; 1276 char *s; 1277 1278 if (opts == NULL) 1279 return (0); 1280 s = strdup(opts); 1281 if (s == NULL) 1282 return (0); 1283 opts = s; 1284 1285 while (*opts != '\0') { 1286 if (getsubopt(&opts, mntopts, &value) == IGNORE) { 1287 free(s); 1288 return (1); 1289 } 1290 } 1291 1292 free(s); 1293 return (0); 1294 } 1295 1296 void 1297 usage(void) 1298 { 1299 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] " 1300 "[-T d|u] [interval [count]]\n"); 1301 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n"); 1302 exit(1); 1303 } 1304 1305 void 1306 fail(int do_perror, char *message, ...) 1307 { 1308 va_list args; 1309 1310 va_start(args, message); 1311 fprintf(stderr, "nfsstat: "); 1312 vfprintf(stderr, message, args); 1313 va_end(args); 1314 if (do_perror) 1315 fprintf(stderr, ": %s", strerror(errno)); 1316 fprintf(stderr, "\n"); 1317 exit(1); 1318 } 1319 1320 kid_t 1321 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1322 { 1323 kid_t kstat_chain_id = kstat_read(kc, ksp, data); 1324 1325 if (kstat_chain_id == -1) 1326 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name); 1327 return (kstat_chain_id); 1328 } 1329 1330 kid_t 1331 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1332 { 1333 kid_t kstat_chain_id = 0; 1334 1335 if (ksp->ks_data != NULL) { 1336 kstat_chain_id = kstat_write(kc, ksp, data); 1337 1338 if (kstat_chain_id == -1) 1339 fail(1, "kstat_write(%x, '%s') failed", kc, 1340 ksp->ks_name); 1341 } 1342 return (kstat_chain_id); 1343 } 1344 1345 void 1346 stats_timer(int interval) 1347 { 1348 timer_t t_id; 1349 itimerspec_t time_struct; 1350 struct sigevent sig_struct; 1351 struct sigaction act; 1352 1353 bzero(&sig_struct, sizeof (struct sigevent)); 1354 bzero(&act, sizeof (struct sigaction)); 1355 1356 /* Create timer */ 1357 sig_struct.sigev_notify = SIGEV_SIGNAL; 1358 sig_struct.sigev_signo = SIGUSR1; 1359 sig_struct.sigev_value.sival_int = 0; 1360 1361 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) { 1362 fail(1, "Timer creation failed"); 1363 } 1364 1365 act.sa_handler = handle_sig; 1366 1367 if (sigaction(SIGUSR1, &act, NULL) != 0) { 1368 fail(1, "Could not set up signal handler"); 1369 } 1370 1371 time_struct.it_value.tv_sec = interval; 1372 time_struct.it_value.tv_nsec = 0; 1373 time_struct.it_interval.tv_sec = interval; 1374 time_struct.it_interval.tv_nsec = 0; 1375 1376 /* Arm timer */ 1377 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) { 1378 fail(1, "Setting timer failed"); 1379 } 1380 } 1381 1382 void 1383 handle_sig(int x) 1384 { 1385 } 1386 1387 static void 1388 nfsstat_kstat_copy(kstat_t *src, kstat_t *dst, int fr) 1389 { 1390 1391 if (fr) 1392 free(dst->ks_data); 1393 1394 *dst = *src; 1395 1396 if (src->ks_data != NULL) { 1397 safe_zalloc(&dst->ks_data, src->ks_data_size, 0); 1398 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size); 1399 } else { 1400 dst->ks_data = NULL; 1401 dst->ks_data_size = 0; 1402 } 1403 } 1404 1405 /* 1406 * "Safe" allocators - if we return we're guaranteed to have the desired space 1407 * allocated and zero-filled. We exit via fail if we can't get the space. 1408 */ 1409 void 1410 safe_zalloc(void **ptr, uint_t size, int free_first) 1411 { 1412 if (ptr == NULL) 1413 fail(1, "invalid pointer"); 1414 if (free_first && *ptr != NULL) 1415 free(*ptr); 1416 if ((*ptr = (void *)malloc(size)) == NULL) 1417 fail(1, "malloc failed"); 1418 (void) memset(*ptr, 0, size); 1419 } 1420 1421 static int 1422 safe_strtoi(char const *val, char *errmsg) 1423 { 1424 char *end; 1425 long tmp; 1426 errno = 0; 1427 tmp = strtol(val, &end, 10); 1428 if (*end != '\0' || errno) 1429 fail(0, "%s %s", errmsg, val); 1430 return ((int)tmp); 1431 }