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