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 2008 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 /* 120 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot 121 * include that file here. 122 */ 123 #define MI4_MIRRORMOUNT 0x4000 124 #define NFS_V4 4 125 126 static int req_width(kstat_t *, int); 127 static int stat_width(kstat_t *, int); 128 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */ 129 130 /* 131 * Struct holds the previous kstat values so 132 * we can compute deltas when using the -i flag 133 */ 134 typedef struct old_kstat 135 { 136 kstat_t kst; 137 int tot; 138 } old_kstat_t; 139 140 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat; 141 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat; 142 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat; 143 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat; 144 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat; 145 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat; 146 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat; 147 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat; 148 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat; 149 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat; 150 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat; 151 152 153 154 int 155 main(int argc, char *argv[]) 156 { 157 int c, go_forever, j; 158 int cflag = 0; /* client stats */ 159 int sflag = 0; /* server stats */ 160 int nflag = 0; /* nfs stats */ 161 int rflag = 0; /* rpc stats */ 162 int mflag = 0; /* mount table stats */ 163 int aflag = 0; /* print acl statistics */ 164 int vflag = 0; /* version specified, 0 specifies all */ 165 int zflag = 0; /* zero stats after printing */ 166 char *split_line = "*******************************************" 167 "*************************************"; 168 169 interval = 0; 170 count = 0; 171 go_forever = 0; 172 173 while ((c = getopt(argc, argv, "cnrsmzav:")) != EOF) { 174 switch (c) { 175 case 'c': 176 cflag++; 177 break; 178 case 'n': 179 nflag++; 180 break; 181 case 'r': 182 rflag++; 183 break; 184 case 's': 185 sflag++; 186 break; 187 case 'm': 188 mflag++; 189 break; 190 case 'z': 191 if (geteuid()) 192 fail(0, "Must be root for z flag\n"); 193 zflag++; 194 break; 195 case 'a': 196 aflag++; 197 break; 198 case 'v': 199 vflag = atoi(optarg); 200 if ((vflag < 2) || (vflag > 4)) 201 fail(0, "Invalid version number\n"); 202 break; 203 case '?': 204 default: 205 usage(); 206 } 207 } 208 209 if (((argc - optind) > 0) && !mflag) { 210 211 interval = safe_strtoi(argv[optind], "invalid interval"); 212 if (interval < 1) 213 fail(0, "invalid interval\n"); 214 optind++; 215 216 if ((argc - optind) > 0) { 217 count = safe_strtoi(argv[optind], "invalid count"); 218 if ((count <= 0) || (count == NULL)) 219 fail(0, "invalid count\n"); 220 } 221 optind++; 222 223 if ((argc - optind) > 0) 224 usage(); 225 226 /* 227 * no count number was set, so we will loop infinitely 228 * at interval specified 229 */ 230 if (!count) 231 go_forever = 1; 232 stats_timer(interval); 233 } else if (mflag) { 234 235 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag) 236 fail(0, 237 "The -m flag may not be used with any other flags"); 238 239 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) { 240 path[j] = argv[optind]; 241 if (*path[j] != '/') 242 fail(0, "Please fully qualify your pathname " 243 "with a leading '/'"); 244 optind++; 245 } 246 path[j] = NULL; 247 if (argc - optind > 0) 248 fprintf(stderr, "Only the first 50 paths " 249 "will be searched for\n"); 250 } 251 252 setup(); 253 254 do { 255 if (mflag) { 256 mi_print(); 257 } else { 258 259 if (sflag && 260 (rpc_clts_server_kstat == NULL || 261 nfs_server_v4_kstat == NULL)) { 262 fprintf(stderr, 263 "nfsstat: kernel is not configured with " 264 "the server nfs and rpc code.\n"); 265 } 266 267 /* if s and nothing else, all 3 prints are called */ 268 if (sflag || (!sflag && !cflag)) { 269 if (rflag || (!rflag && !nflag && !aflag)) 270 sr_print(zflag); 271 if (nflag || (!rflag && !nflag && !aflag)) 272 sn_print(zflag, vflag); 273 if (aflag || (!rflag && !nflag && !aflag)) 274 sa_print(zflag, vflag); 275 } 276 if (cflag && 277 (rpc_clts_client_kstat == NULL || 278 nfs_client_kstat == NULL)) { 279 fprintf(stderr, 280 "nfsstat: kernel is not configured with" 281 " the client nfs and rpc code.\n"); 282 } 283 if (cflag || (!sflag && !cflag)) { 284 if (rflag || (!rflag && !nflag && !aflag)) 285 cr_print(zflag); 286 if (nflag || (!rflag && !nflag && !aflag)) 287 cn_print(zflag, vflag); 288 if (aflag || (!rflag && !nflag && !aflag)) 289 ca_print(zflag, vflag); 290 } 291 } 292 293 if (zflag) 294 putstats(); 295 if (interval) 296 printf("%s\n", split_line); 297 298 if (interval > 0) 299 (void) pause(); 300 } while ((--count > 0) || go_forever); 301 302 kstat_close(kc); 303 free(ksum_kstat); 304 return (0); 305 } 306 307 308 static int 309 getstats_rpc(void) 310 { 311 int field_width = 0; 312 313 if (rpc_clts_client_kstat != NULL) { 314 safe_kstat_read(kc, rpc_clts_client_kstat, NULL); 315 field_width = stat_width(rpc_clts_client_kstat, field_width); 316 } 317 318 if (rpc_cots_client_kstat != NULL) { 319 safe_kstat_read(kc, rpc_cots_client_kstat, NULL); 320 field_width = stat_width(rpc_cots_client_kstat, field_width); 321 } 322 323 if (rpc_rdma_client_kstat != NULL) { 324 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL); 325 field_width = stat_width(rpc_rdma_client_kstat, field_width); 326 } 327 328 if (rpc_clts_server_kstat != NULL) { 329 safe_kstat_read(kc, rpc_clts_server_kstat, NULL); 330 field_width = stat_width(rpc_clts_server_kstat, field_width); 331 } 332 if (rpc_cots_server_kstat != NULL) { 333 safe_kstat_read(kc, rpc_cots_server_kstat, NULL); 334 field_width = stat_width(rpc_cots_server_kstat, field_width); 335 } 336 if (rpc_rdma_server_kstat != NULL) { 337 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL); 338 field_width = stat_width(rpc_rdma_server_kstat, field_width); 339 } 340 return (field_width); 341 } 342 343 static int 344 getstats_nfs(void) 345 { 346 int field_width = 0; 347 348 if (nfs_client_kstat != NULL) { 349 safe_kstat_read(kc, nfs_client_kstat, NULL); 350 field_width = stat_width(nfs_client_kstat, field_width); 351 } 352 if (nfs4_client_kstat != NULL) { 353 safe_kstat_read(kc, nfs4_client_kstat, NULL); 354 field_width = stat_width(nfs4_client_kstat, field_width); 355 } 356 if (nfs_server_v2_kstat != NULL) { 357 safe_kstat_read(kc, nfs_server_v2_kstat, NULL); 358 field_width = stat_width(nfs_server_v2_kstat, field_width); 359 } 360 if (nfs_server_v3_kstat != NULL) { 361 safe_kstat_read(kc, nfs_server_v3_kstat, NULL); 362 field_width = stat_width(nfs_server_v3_kstat, field_width); 363 } 364 if (nfs_server_v4_kstat != NULL) { 365 safe_kstat_read(kc, nfs_server_v4_kstat, NULL); 366 field_width = stat_width(nfs_server_v4_kstat, field_width); 367 } 368 return (field_width); 369 } 370 371 static int 372 getstats_rfsproc(int ver) 373 { 374 int field_width = 0; 375 376 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) { 377 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL); 378 field_width = req_width(rfsproccnt_v2_kstat, field_width); 379 } 380 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) { 381 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL); 382 field_width = req_width(rfsproccnt_v3_kstat, field_width); 383 } 384 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) { 385 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL); 386 field_width = req_width(rfsproccnt_v4_kstat, field_width); 387 } 388 return (field_width); 389 } 390 391 static int 392 getstats_rfsreq(int ver) 393 { 394 int field_width = 0; 395 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) { 396 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL); 397 field_width = req_width(rfsreqcnt_v2_kstat, field_width); 398 } 399 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) { 400 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL); 401 field_width = req_width(rfsreqcnt_v3_kstat, field_width); 402 } 403 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) { 404 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL); 405 field_width = req_width(rfsreqcnt_v4_kstat, field_width); 406 } 407 return (field_width); 408 } 409 410 static int 411 getstats_aclproc(void) 412 { 413 int field_width = 0; 414 if (aclproccnt_v2_kstat != NULL) { 415 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL); 416 field_width = req_width(aclproccnt_v2_kstat, field_width); 417 } 418 if (aclproccnt_v3_kstat != NULL) { 419 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL); 420 field_width = req_width(aclproccnt_v3_kstat, field_width); 421 } 422 return (field_width); 423 } 424 425 static int 426 getstats_aclreq(void) 427 { 428 int field_width = 0; 429 if (aclreqcnt_v2_kstat != NULL) { 430 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL); 431 field_width = req_width(aclreqcnt_v2_kstat, field_width); 432 } 433 if (aclreqcnt_v3_kstat != NULL) { 434 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL); 435 field_width = req_width(aclreqcnt_v3_kstat, field_width); 436 } 437 return (field_width); 438 } 439 440 static void 441 putstats(void) 442 { 443 if (rpc_clts_client_kstat != NULL) 444 safe_kstat_write(kc, rpc_clts_client_kstat, NULL); 445 if (rpc_cots_client_kstat != NULL) 446 safe_kstat_write(kc, rpc_cots_client_kstat, NULL); 447 if (rpc_rdma_client_kstat != NULL) 448 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL); 449 if (nfs_client_kstat != NULL) 450 safe_kstat_write(kc, nfs_client_kstat, NULL); 451 if (nfs4_client_kstat != NULL) 452 safe_kstat_write(kc, nfs4_client_kstat, NULL); 453 if (rpc_clts_server_kstat != NULL) 454 safe_kstat_write(kc, rpc_clts_server_kstat, NULL); 455 if (rpc_cots_server_kstat != NULL) 456 safe_kstat_write(kc, rpc_cots_server_kstat, NULL); 457 if (rpc_rdma_server_kstat != NULL) 458 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL); 459 if (nfs_server_v2_kstat != NULL) 460 safe_kstat_write(kc, nfs_server_v2_kstat, NULL); 461 if (nfs_server_v3_kstat != NULL) 462 safe_kstat_write(kc, nfs_server_v3_kstat, NULL); 463 if (nfs_server_v4_kstat != NULL) 464 safe_kstat_write(kc, nfs_server_v4_kstat, NULL); 465 if (rfsproccnt_v2_kstat != NULL) 466 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL); 467 if (rfsproccnt_v3_kstat != NULL) 468 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL); 469 if (rfsproccnt_v4_kstat != NULL) 470 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL); 471 if (rfsreqcnt_v2_kstat != NULL) 472 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL); 473 if (rfsreqcnt_v3_kstat != NULL) 474 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL); 475 if (rfsreqcnt_v4_kstat != NULL) 476 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL); 477 if (aclproccnt_v2_kstat != NULL) 478 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL); 479 if (aclproccnt_v3_kstat != NULL) 480 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL); 481 if (aclreqcnt_v2_kstat != NULL) 482 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL); 483 if (aclreqcnt_v3_kstat != NULL) 484 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL); 485 } 486 487 static void 488 setup(void) 489 { 490 if ((kc = kstat_open()) == NULL) 491 fail(1, "kstat_open(): can't open /dev/kstat"); 492 493 /* malloc space for our temporary kstat */ 494 ksum_kstat = malloc(sizeof (kstat_t)); 495 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client"); 496 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server"); 497 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client"); 498 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server"); 499 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client"); 500 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server"); 501 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client"); 502 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client"); 503 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server"); 504 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server"); 505 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server"); 506 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2"); 507 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3"); 508 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4"); 509 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2"); 510 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3"); 511 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4"); 512 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2"); 513 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3"); 514 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2"); 515 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3"); 516 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL && 517 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL) 518 fail(0, "Multiple kstat lookups failed." 519 "Your kernel module may not be loaded\n"); 520 } 521 522 static int 523 req_width(kstat_t *req, int field_width) 524 { 525 int i, nreq, per, len; 526 char fixlen[128]; 527 kstat_named_t *knp; 528 uint64_t tot; 529 530 tot = 0; 531 knp = KSTAT_NAMED_PTR(req); 532 for (i = 0; i < req->ks_ndata; i++) 533 tot += knp[i].value.ui64; 534 535 knp = kstat_data_lookup(req, "null"); 536 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 537 538 for (i = 0; i < nreq; i++) { 539 len = strlen(knp[i].name) + 1; 540 if (field_width < len) 541 field_width = len; 542 if (tot) 543 per = (int)(knp[i].value.ui64 * 100 / tot); 544 else 545 per = 0; 546 (void) sprintf(fixlen, "%" PRIu64 " %d%%", 547 knp[i].value.ui64, per); 548 len = strlen(fixlen) + 1; 549 if (field_width < len) 550 field_width = len; 551 } 552 return (field_width); 553 } 554 555 static int 556 stat_width(kstat_t *req, int field_width) 557 { 558 int i, nreq, len; 559 char fixlen[128]; 560 kstat_named_t *knp; 561 562 knp = KSTAT_NAMED_PTR(req); 563 nreq = req->ks_ndata; 564 565 for (i = 0; i < nreq; i++) { 566 len = strlen(knp[i].name) + 1; 567 if (field_width < len) 568 field_width = len; 569 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64); 570 len = strlen(fixlen) + 1; 571 if (field_width < len) 572 field_width = len; 573 } 574 return (field_width); 575 } 576 577 static void 578 cr_print(int zflag) 579 { 580 int field_width; 581 582 field_width = getstats_rpc(); 583 if (field_width == 0) 584 return; 585 586 stat_print("\nClient rpc:\nConnection oriented:", 587 rpc_cots_client_kstat, 588 &old_rpc_cots_client_kstat.kst, field_width, zflag); 589 stat_print("Connectionless:", rpc_clts_client_kstat, 590 &old_rpc_clts_client_kstat.kst, field_width, zflag); 591 stat_print("RDMA based:", rpc_rdma_client_kstat, 592 &old_rpc_rdma_client_kstat.kst, field_width, zflag); 593 } 594 595 static void 596 sr_print(int zflag) 597 { 598 int field_width; 599 600 field_width = getstats_rpc(); 601 if (field_width == 0) 602 return; 603 604 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat, 605 &old_rpc_cots_server_kstat.kst, field_width, zflag); 606 stat_print("Connectionless:", rpc_clts_server_kstat, 607 &old_rpc_clts_server_kstat.kst, field_width, zflag); 608 stat_print("RDMA based:", rpc_rdma_server_kstat, 609 &old_rpc_rdma_server_kstat.kst, field_width, zflag); 610 } 611 612 static void 613 cn_print(int zflag, int vflag) 614 { 615 int field_width; 616 617 field_width = getstats_nfs(); 618 if (field_width == 0) 619 return; 620 621 if (vflag == 0) { 622 kstat_sum(nfs_client_kstat, nfs4_client_kstat, ksum_kstat); 623 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst, 624 field_width, zflag); 625 } 626 627 if (vflag == 2 || vflag == 3) { 628 stat_print("\nClient nfs:", nfs_client_kstat, 629 &old_nfs_client_kstat.kst, field_width, zflag); 630 } 631 632 if (vflag == 4) { 633 stat_print("\nClient nfs:", nfs4_client_kstat, 634 &old_nfs4_client_kstat.kst, field_width, zflag); 635 } 636 637 if (vflag == 2 || vflag == 0) { 638 field_width = getstats_rfsreq(2); 639 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst, 640 2, field_width, zflag); 641 } 642 643 if (vflag == 3 || vflag == 0) { 644 field_width = getstats_rfsreq(3); 645 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3, 646 field_width, zflag); 647 } 648 649 if (vflag == 4 || vflag == 0) { 650 field_width = getstats_rfsreq(4); 651 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst, 652 field_width, zflag); 653 } 654 } 655 656 static void 657 sn_print(int zflag, int vflag) 658 { 659 int field_width; 660 661 field_width = getstats_nfs(); 662 if (field_width == 0) 663 return; 664 665 if (vflag == 2 || vflag == 0) { 666 stat_print("\nServer NFSv2:", nfs_server_v2_kstat, 667 &old_nfs_server_v2_kstat.kst, field_width, zflag); 668 } 669 670 if (vflag == 3 || vflag == 0) { 671 stat_print("\nServer NFSv3:", nfs_server_v3_kstat, 672 &old_nfs_server_v3_kstat.kst, field_width, zflag); 673 } 674 675 if (vflag == 4 || vflag == 0) { 676 stat_print("\nServer NFSv4:", nfs_server_v4_kstat, 677 &old_nfs_server_v4_kstat.kst, field_width, zflag); 678 } 679 680 if (vflag == 2 || vflag == 0) { 681 field_width = getstats_rfsproc(2); 682 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst, 683 2, field_width, zflag); 684 } 685 686 if (vflag == 3 || vflag == 0) { 687 field_width = getstats_rfsproc(3); 688 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst, 689 3, field_width, zflag); 690 } 691 692 if (vflag == 4 || vflag == 0) { 693 field_width = getstats_rfsproc(4); 694 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst, 695 field_width, zflag); 696 } 697 } 698 699 static void 700 ca_print(int zflag, int vflag) 701 { 702 int field_width; 703 704 field_width = getstats_aclreq(); 705 if (field_width == 0) 706 return; 707 708 printf("\nClient nfs_acl:\n"); 709 710 if (vflag == 2 || vflag == 0) { 711 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2, 712 field_width, zflag); 713 } 714 715 if (vflag == 3 || vflag == 0) { 716 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst, 717 3, field_width, zflag); 718 } 719 } 720 721 static void 722 sa_print(int zflag, int vflag) 723 { 724 int field_width; 725 726 field_width = getstats_aclproc(); 727 if (field_width == 0) 728 return; 729 730 printf("\nServer nfs_acl:\n"); 731 732 if (vflag == 2 || vflag == 0) { 733 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst, 734 2, field_width, zflag); 735 } 736 737 if (vflag == 3 || vflag == 0) { 738 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst, 739 3, field_width, zflag); 740 } 741 } 742 743 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 744 745 static void 746 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width, 747 int zflag) 748 { 749 int i, j, nreq, per, ncolumns; 750 uint64_t tot, old_tot; 751 char fixlen[128]; 752 kstat_named_t *knp; 753 kstat_named_t *kptr; 754 kstat_named_t *knp_old; 755 756 if (req == NULL) 757 return; 758 759 if (field_width == 0) 760 return; 761 762 ncolumns = (MAX_COLUMNS -1)/field_width; 763 knp = kstat_data_lookup(req, "null"); 764 knp_old = KSTAT_NAMED_PTR(req_old); 765 766 kptr = KSTAT_NAMED_PTR(req); 767 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 768 769 tot = 0; 770 old_tot = 0; 771 772 if (knp_old == NULL) { 773 old_tot = 0; 774 } 775 776 for (i = 0; i < req->ks_ndata; i++) 777 tot += kptr[i].value.ui64; 778 779 if (interval && knp_old != NULL) { 780 for (i = 0; i < req_old->ks_ndata; i++) 781 old_tot += knp_old[i].value.ui64; 782 tot -= old_tot; 783 } 784 785 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot); 786 787 for (i = 0; i < nreq; i += ncolumns) { 788 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 789 printf("%-*s", field_width, knp[j].name); 790 } 791 printf("\n"); 792 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 793 if (tot && interval && knp_old != NULL) 794 per = (int)((knp[j].value.ui64 - 795 knp_old[j].value.ui64) * 100 / tot); 796 else if (tot) 797 per = (int)(knp[j].value.ui64 * 100 / tot); 798 else 799 per = 0; 800 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 801 ((interval && knp_old != NULL) ? 802 (knp[j].value.ui64 - knp_old[j].value.ui64) 803 : knp[j].value.ui64), per); 804 printf("%-*s", field_width, fixlen); 805 } 806 printf("\n"); 807 } 808 if (zflag) { 809 for (i = 0; i < req->ks_ndata; i++) 810 knp[i].value.ui64 = 0; 811 } 812 if (knp_old != NULL) 813 kstat_copy(req, req_old, 1); 814 else 815 kstat_copy(req, req_old, 0); 816 } 817 818 /* 819 * Separate version of the req_print() to deal with V4 and its use of 820 * procedures and operations. It looks odd to have the counts for 821 * both of those lumped into the same set of statistics so this 822 * function (copy of req_print() does the separation and titles). 823 */ 824 825 #define COUNT 2 826 827 static void 828 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) 829 { 830 int i, j, nreq, per, ncolumns; 831 uint64_t tot, tot_ops, old_tot, old_tot_ops; 832 char fixlen[128]; 833 kstat_named_t *kptr; 834 kstat_named_t *knp; 835 kstat_named_t *kptr_old; 836 837 if (req == NULL) 838 return; 839 840 if (field_width == 0) 841 return; 842 843 ncolumns = (MAX_COLUMNS)/field_width; 844 kptr = KSTAT_NAMED_PTR(req); 845 kptr_old = KSTAT_NAMED_PTR(req_old); 846 847 if (kptr_old == NULL) { 848 old_tot_ops = 0; 849 old_tot = 0; 850 } else { 851 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64; 852 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++) 853 old_tot_ops += kptr_old[i].value.ui64; 854 } 855 856 /* Count the number of operations sent */ 857 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++) 858 tot_ops += kptr[i].value.ui64; 859 /* For v4 NULL/COMPOUND are the only procedures */ 860 tot = kptr[0].value.ui64 + kptr[1].value.ui64; 861 862 if (interval) { 863 tot -= old_tot; 864 tot_ops -= old_tot_ops; 865 } 866 867 printf("Version 4: (%" PRIu64 " calls)\n", tot); 868 869 knp = kstat_data_lookup(req, "null"); 870 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 871 872 for (i = 0; i < COUNT; i += ncolumns) { 873 for (j = i; j < MIN(i + ncolumns, 2); j++) { 874 printf("%-*s", field_width, knp[j].name); 875 } 876 printf("\n"); 877 for (j = i; j < MIN(i + ncolumns, 2); j++) { 878 if (tot && interval && kptr_old != NULL) 879 per = (int)((knp[j].value.ui64 - 880 kptr_old[j].value.ui64) * 100 / tot); 881 else if (tot) 882 per = (int)(knp[j].value.ui64 * 100 / tot); 883 else 884 per = 0; 885 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 886 ((interval && kptr_old != NULL) ? 887 (knp[j].value.ui64 - kptr_old[j].value.ui64) 888 : knp[j].value.ui64), per); 889 printf("%-*s", field_width, fixlen); 890 } 891 printf("\n"); 892 } 893 894 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops); 895 for (i = 2; i < nreq; i += ncolumns) { 896 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 897 printf("%-*s", field_width, knp[j].name); 898 } 899 printf("\n"); 900 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 901 if (tot_ops && interval && kptr_old != NULL) 902 per = (int)((knp[j].value.ui64 - 903 kptr_old[j].value.ui64) * 100 / tot_ops); 904 else if (tot_ops) 905 per = (int)(knp[j].value.ui64 * 100 / tot_ops); 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 if (zflag) { 917 for (i = 0; i < req->ks_ndata; i++) 918 kptr[i].value.ui64 = 0; 919 } 920 if (kptr_old != NULL) 921 kstat_copy(req, req_old, 1); 922 else 923 kstat_copy(req, req_old, 0); 924 } 925 926 static void 927 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, 928 int field_width, int zflag) 929 { 930 int i, j, nreq, ncolumns; 931 char fixlen[128]; 932 kstat_named_t *knp; 933 kstat_named_t *knp_old; 934 935 if (req == NULL) 936 return; 937 938 if (field_width == 0) 939 return; 940 941 printf("%s\n", title_string); 942 ncolumns = (MAX_COLUMNS -1)/field_width; 943 944 /* MEANS knp = (kstat_named_t *)req->ks_data */ 945 knp = KSTAT_NAMED_PTR(req); 946 nreq = req->ks_ndata; 947 knp_old = KSTAT_NAMED_PTR(req_old); 948 949 for (i = 0; i < nreq; i += ncolumns) { 950 /* prints out the titles of the columns */ 951 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 952 printf("%-*s", field_width, knp[j].name); 953 } 954 printf("\n"); 955 /* prints out the stat numbers */ 956 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 957 (void) sprintf(fixlen, "%" PRIu64 " ", 958 (interval && knp_old != NULL) ? 959 (knp[j].value.ui64 - knp_old[j].value.ui64) 960 : knp[j].value.ui64); 961 printf("%-*s", field_width, fixlen); 962 } 963 printf("\n"); 964 965 } 966 if (zflag) { 967 for (i = 0; i < req->ks_ndata; i++) 968 knp[i].value.ui64 = 0; 969 } 970 971 if (knp_old != NULL) 972 kstat_copy(req, req_old, 1); 973 else 974 kstat_copy(req, req_old, 0); 975 } 976 977 static void 978 kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum) 979 { 980 int i; 981 kstat_named_t *knp1, *knp2, *knpsum; 982 if (kstat1 == NULL || kstat2 == NULL) 983 return; 984 985 knp1 = KSTAT_NAMED_PTR(kstat1); 986 knp2 = KSTAT_NAMED_PTR(kstat2); 987 if (sum->ks_data == NULL) 988 kstat_copy(kstat1, sum, 0); 989 knpsum = KSTAT_NAMED_PTR(sum); 990 991 for (i = 0; i < (kstat1->ks_ndata); i++) 992 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64; 993 } 994 995 /* 996 * my_dir and my_path could be pointers 997 */ 998 struct myrec { 999 ulong_t my_fsid; 1000 char my_dir[MAXPATHLEN]; 1001 char *my_path; 1002 char *ig_path; 1003 struct myrec *next; 1004 }; 1005 1006 /* 1007 * Print the mount table info 1008 */ 1009 static void 1010 mi_print(void) 1011 { 1012 FILE *mt; 1013 struct extmnttab m; 1014 struct myrec *list, *mrp, *pmrp; 1015 char *flavor; 1016 int ignored = 0; 1017 seconfig_t nfs_sec; 1018 kstat_t *ksp; 1019 struct mntinfo_kstat mik; 1020 int transport_flag = 0; 1021 int path_count; 1022 int found; 1023 char *timer_name[] = { 1024 "Lookups", 1025 "Reads", 1026 "Writes", 1027 "All" 1028 }; 1029 1030 mt = fopen(MNTTAB, "r"); 1031 if (mt == NULL) { 1032 perror(MNTTAB); 1033 exit(0); 1034 } 1035 1036 list = NULL; 1037 resetmnttab(mt); 1038 1039 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1040 /* ignore non "nfs" and save the "ignore" entries */ 1041 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0) 1042 continue; 1043 /* 1044 * Check to see here if user gave a path(s) to 1045 * only show the mount point they wanted 1046 * Iterate through the list of paths the user gave and see 1047 * if any of them match our current nfs mount 1048 */ 1049 if (path[0] != NULL) { 1050 found = 0; 1051 for (path_count = 0; path[path_count] != NULL; 1052 path_count++) { 1053 if (strcmp(path[path_count], m.mnt_mountp) 1054 == 0) { 1055 found = 1; 1056 break; 1057 } 1058 } 1059 if (!found) 1060 continue; 1061 } 1062 1063 if ((mrp = malloc(sizeof (struct myrec))) == 0) { 1064 fprintf(stderr, "nfsstat: not enough memory\n"); 1065 exit(1); 1066 } 1067 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor); 1068 if (ignore(m.mnt_mntopts)) { 1069 /* 1070 * ignored entries cannot be ignored for this 1071 * option. We have to display the info for this 1072 * nfs mount. The ignore is an indication 1073 * that the actual mount point is different and 1074 * something is in between the nfs mount. 1075 * So save the mount point now 1076 */ 1077 if ((mrp->ig_path = malloc( 1078 strlen(m.mnt_mountp) + 1)) == 0) { 1079 fprintf(stderr, "nfsstat: not enough memory\n"); 1080 exit(1); 1081 } 1082 (void) strcpy(mrp->ig_path, m.mnt_mountp); 1083 ignored++; 1084 } else { 1085 mrp->ig_path = 0; 1086 (void) strcpy(mrp->my_dir, m.mnt_mountp); 1087 } 1088 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) { 1089 fprintf(stderr, "nfsstat: not enough memory\n"); 1090 exit(1); 1091 } 1092 mrp->next = list; 1093 list = mrp; 1094 } 1095 1096 /* 1097 * If something got ignored, go to the beginning of the mnttab 1098 * and look for the cachefs entries since they are the one 1099 * causing this. The mount point saved for the ignored entries 1100 * is matched against the special to get the actual mount point. 1101 * We are interested in the acutal mount point so that the output 1102 * look nice too. 1103 */ 1104 if (ignored) { 1105 rewind(mt); 1106 resetmnttab(mt); 1107 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1108 1109 /* ignore non "cachefs" */ 1110 if (strcmp(m.mnt_fstype, MNTTYPE_CACHEFS) != 0) 1111 continue; 1112 1113 for (mrp = list; mrp; mrp = mrp->next) { 1114 if (mrp->ig_path == 0) 1115 continue; 1116 if (strcmp(mrp->ig_path, m.mnt_special) == 0) { 1117 mrp->ig_path = 0; 1118 (void) strcpy(mrp->my_dir, 1119 m.mnt_mountp); 1120 } 1121 } 1122 } 1123 /* 1124 * Now ignored entries which do not have 1125 * the my_dir initialized are really ignored; This never 1126 * happens unless the mnttab is corrupted. 1127 */ 1128 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) { 1129 if (mrp->ig_path == 0) 1130 pmrp = mrp; 1131 else if (pmrp) 1132 pmrp->next = mrp->next; 1133 else 1134 list = mrp->next; 1135 } 1136 } 1137 1138 (void) fclose(mt); 1139 1140 1141 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1142 int i; 1143 1144 if (ksp->ks_type != KSTAT_TYPE_RAW) 1145 continue; 1146 if (strcmp(ksp->ks_module, "nfs") != 0) 1147 continue; 1148 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1149 continue; 1150 1151 for (mrp = list; mrp; mrp = mrp->next) { 1152 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance) 1153 break; 1154 } 1155 if (mrp == 0) 1156 continue; 1157 1158 if (safe_kstat_read(kc, ksp, &mik) == -1) 1159 continue; 1160 1161 printf("%s from %s\n", mrp->my_dir, mrp->my_path); 1162 1163 /* 1164 * for printing rdma transport and provider string. 1165 * This way we avoid modifying the kernel mntinfo_kstat 1166 * struct for protofmly. 1167 */ 1168 if (strcmp(mik.mik_proto, "ibtf") == 0) { 1169 printf(" Flags: vers=%u,proto=rdma", 1170 mik.mik_vers); 1171 transport_flag = 1; 1172 } else { 1173 printf(" Flags: vers=%u,proto=%s", 1174 mik.mik_vers, mik.mik_proto); 1175 transport_flag = 0; 1176 } 1177 1178 /* 1179 * get the secmode name from /etc/nfssec.conf. 1180 */ 1181 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) { 1182 flavor = nfs_sec.sc_name; 1183 } else 1184 flavor = NULL; 1185 1186 if (flavor != NULL) 1187 printf(",sec=%s", flavor); 1188 else 1189 printf(",sec#=%d", mik.mik_secmod); 1190 1191 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft"); 1192 if (mik.mik_flags & MI_PRINTED) 1193 printf(",printed"); 1194 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr"); 1195 if (mik.mik_flags & MI_DOWN) 1196 printf(",down"); 1197 if (mik.mik_flags & MI_NOAC) 1198 printf(",noac"); 1199 if (mik.mik_flags & MI_NOCTO) 1200 printf(",nocto"); 1201 if (mik.mik_flags & MI_DYNAMIC) 1202 printf(",dynamic"); 1203 if (mik.mik_flags & MI_LLOCK) 1204 printf(",llock"); 1205 if (mik.mik_flags & MI_GRPID) 1206 printf(",grpid"); 1207 if (mik.mik_flags & MI_RPCTIMESYNC) 1208 printf(",rpctimesync"); 1209 if (mik.mik_flags & MI_LINK) 1210 printf(",link"); 1211 if (mik.mik_flags & MI_SYMLINK) 1212 printf(",symlink"); 1213 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY) 1214 printf(",readdironly"); 1215 if (mik.mik_flags & MI_ACL) 1216 printf(",acl"); 1217 1218 if (mik.mik_vers >= NFS_V4) { 1219 if (mik.mik_flags & MI4_MIRRORMOUNT) 1220 printf(",mirrormount"); 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 "[interval [count]]\n"); 1301 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n"); 1302 exit(1); 1303 } 1304 1305 static 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 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 1407 * to have the desired space. We exit via fail 1408 * if we can't get the space. 1409 */ 1410 void 1411 safe_zalloc(void **ptr, uint_t size, int free_first) 1412 { 1413 if (*ptr == NULL) 1414 fail(1, "invalid pointer"); 1415 if (free_first && *ptr != NULL) 1416 free(*ptr); 1417 if ((*ptr = (void *)malloc(size)) == NULL) 1418 fail(1, "malloc failed"); 1419 (void) memset(*ptr, 0, size); 1420 } 1421 1422 static int 1423 safe_strtoi(char const *val, char *errmsg) 1424 { 1425 char *end; 1426 long tmp; 1427 errno = 0; 1428 tmp = strtol(val, &end, 10); 1429 if (*end != '\0' || errno) 1430 fail(0, "%s %s", errmsg, val); 1431 return ((int)tmp); 1432 } 1433