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 if (zflag) { 807 for (i = 0; i < req->ks_ndata; i++) 808 knp[i].value.ui64 = 0; 809 } 810 printf("\n"); 811 if (knp_old != NULL) 812 kstat_copy(req, req_old, 1); 813 else 814 kstat_copy(req, req_old, 0); 815 816 } 817 } 818 819 /* 820 * Separate version of the req_print() to deal with V4 and its use of 821 * procedures and operations. It looks odd to have the counts for 822 * both of those lumped into the same set of statistics so this 823 * function (copy of req_print() does the separation and titles). 824 */ 825 826 #define COUNT 2 827 828 static void 829 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) 830 { 831 int i, j, nreq, per, ncolumns; 832 uint64_t tot, tot_ops, old_tot, old_tot_ops; 833 char fixlen[128]; 834 kstat_named_t *kptr; 835 kstat_named_t *knp; 836 kstat_named_t *kptr_old; 837 838 if (req == NULL) 839 return; 840 841 if (field_width == 0) 842 return; 843 844 ncolumns = (MAX_COLUMNS)/field_width; 845 kptr = KSTAT_NAMED_PTR(req); 846 kptr_old = KSTAT_NAMED_PTR(req_old); 847 848 if (kptr_old == NULL) { 849 old_tot_ops = 0; 850 old_tot = 0; 851 } else { 852 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64; 853 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++) 854 old_tot_ops += kptr_old[i].value.ui64; 855 } 856 857 /* Count the number of operations sent */ 858 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++) 859 tot_ops += kptr[i].value.ui64; 860 /* For v4 NULL/COMPOUND are the only procedures */ 861 tot = kptr[0].value.ui64 + kptr[1].value.ui64; 862 863 if (interval) { 864 tot -= old_tot; 865 tot_ops -= old_tot_ops; 866 } 867 868 printf("Version 4: (%" PRIu64 " calls)\n", tot); 869 870 knp = kstat_data_lookup(req, "null"); 871 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 872 873 for (i = 0; i < COUNT; i += ncolumns) { 874 for (j = i; j < MIN(i + ncolumns, 2); j++) { 875 printf("%-*s", field_width, knp[j].name); 876 } 877 printf("\n"); 878 for (j = i; j < MIN(i + ncolumns, 2); j++) { 879 if (tot && interval && kptr_old != NULL) 880 per = (int)((knp[j].value.ui64 - 881 kptr_old[j].value.ui64) * 100 / tot); 882 else if (tot) 883 per = (int)(knp[j].value.ui64 * 100 / tot); 884 else 885 per = 0; 886 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 887 ((interval && kptr_old != NULL) ? 888 (knp[j].value.ui64 - kptr_old[j].value.ui64) 889 : knp[j].value.ui64), per); 890 printf("%-*s", field_width, fixlen); 891 } 892 printf("\n"); 893 } 894 895 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops); 896 for (i = 2; i < nreq; i += ncolumns) { 897 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 898 printf("%-*s", field_width, knp[j].name); 899 } 900 printf("\n"); 901 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 902 if (tot_ops && interval && kptr_old != NULL) 903 per = (int)((knp[j].value.ui64 - 904 kptr_old[j].value.ui64) * 100 / tot_ops); 905 else if (tot_ops) 906 per = (int)(knp[j].value.ui64 * 100 / tot_ops); 907 else 908 per = 0; 909 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 910 ((interval && kptr_old != NULL) ? 911 (knp[j].value.ui64 - kptr_old[j].value.ui64) 912 : knp[j].value.ui64), per); 913 printf("%-*s", field_width, fixlen); 914 } 915 printf("\n"); 916 } 917 if (zflag) { 918 for (i = 0; i < req->ks_ndata; i++) 919 kptr[i].value.ui64 = 0; 920 } 921 if (kptr_old != NULL) 922 kstat_copy(req, req_old, 1); 923 else 924 kstat_copy(req, req_old, 0); 925 } 926 927 static void 928 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, 929 int field_width, int zflag) 930 { 931 int i, j, nreq, ncolumns; 932 char fixlen[128]; 933 kstat_named_t *knp; 934 kstat_named_t *knp_old; 935 936 if (req == NULL) 937 return; 938 939 if (field_width == 0) 940 return; 941 942 printf("%s\n", title_string); 943 ncolumns = (MAX_COLUMNS -1)/field_width; 944 945 /* MEANS knp = (kstat_named_t *)req->ks_data */ 946 knp = KSTAT_NAMED_PTR(req); 947 nreq = req->ks_ndata; 948 knp_old = KSTAT_NAMED_PTR(req_old); 949 950 for (i = 0; i < nreq; i += ncolumns) { 951 /* prints out the titles of the columns */ 952 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 953 printf("%-*s", field_width, knp[j].name); 954 } 955 printf("\n"); 956 /* prints out the stat numbers */ 957 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 958 (void) sprintf(fixlen, "%" PRIu64 " ", 959 (interval && knp_old != NULL) ? 960 (knp[j].value.ui64 - knp_old[j].value.ui64) 961 : knp[j].value.ui64); 962 printf("%-*s", field_width, fixlen); 963 } 964 printf("\n"); 965 966 } 967 if (zflag) { 968 for (i = 0; i < req->ks_ndata; i++) 969 knp[i].value.ui64 = 0; 970 } 971 972 if (knp_old != NULL) 973 kstat_copy(req, req_old, 1); 974 else 975 kstat_copy(req, req_old, 0); 976 } 977 978 static void 979 kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum) 980 { 981 int i; 982 kstat_named_t *knp1, *knp2, *knpsum; 983 if (kstat1 == NULL || kstat2 == NULL) 984 return; 985 986 knp1 = KSTAT_NAMED_PTR(kstat1); 987 knp2 = KSTAT_NAMED_PTR(kstat2); 988 if (sum->ks_data == NULL) 989 kstat_copy(kstat1, sum, 0); 990 knpsum = KSTAT_NAMED_PTR(sum); 991 992 for (i = 0; i < (kstat1->ks_ndata); i++) 993 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64; 994 } 995 996 /* 997 * my_dir and my_path could be pointers 998 */ 999 struct myrec { 1000 ulong_t my_fsid; 1001 char my_dir[MAXPATHLEN]; 1002 char *my_path; 1003 char *ig_path; 1004 struct myrec *next; 1005 }; 1006 1007 /* 1008 * Print the mount table info 1009 */ 1010 static void 1011 mi_print(void) 1012 { 1013 FILE *mt; 1014 struct extmnttab m; 1015 struct myrec *list, *mrp, *pmrp; 1016 char *flavor; 1017 int ignored = 0; 1018 seconfig_t nfs_sec; 1019 kstat_t *ksp; 1020 struct mntinfo_kstat mik; 1021 int transport_flag = 0; 1022 int path_count; 1023 int found; 1024 char *timer_name[] = { 1025 "Lookups", 1026 "Reads", 1027 "Writes", 1028 "All" 1029 }; 1030 1031 mt = fopen(MNTTAB, "r"); 1032 if (mt == NULL) { 1033 perror(MNTTAB); 1034 exit(0); 1035 } 1036 1037 list = NULL; 1038 resetmnttab(mt); 1039 1040 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1041 /* ignore non "nfs" and save the "ignore" entries */ 1042 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0) 1043 continue; 1044 /* 1045 * Check to see here if user gave a path(s) to 1046 * only show the mount point they wanted 1047 * Iterate through the list of paths the user gave and see 1048 * if any of them match our current nfs mount 1049 */ 1050 if (path[0] != NULL) { 1051 found = 0; 1052 for (path_count = 0; path[path_count] != NULL; 1053 path_count++) { 1054 if (strcmp(path[path_count], m.mnt_mountp) 1055 == 0) { 1056 found = 1; 1057 break; 1058 } 1059 } 1060 if (!found) 1061 continue; 1062 } 1063 1064 if ((mrp = malloc(sizeof (struct myrec))) == 0) { 1065 fprintf(stderr, "nfsstat: not enough memory\n"); 1066 exit(1); 1067 } 1068 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor); 1069 if (ignore(m.mnt_mntopts)) { 1070 /* 1071 * ignored entries cannot be ignored for this 1072 * option. We have to display the info for this 1073 * nfs mount. The ignore is an indication 1074 * that the actual mount point is different and 1075 * something is in between the nfs mount. 1076 * So save the mount point now 1077 */ 1078 if ((mrp->ig_path = malloc( 1079 strlen(m.mnt_mountp) + 1)) == 0) { 1080 fprintf(stderr, "nfsstat: not enough memory\n"); 1081 exit(1); 1082 } 1083 (void) strcpy(mrp->ig_path, m.mnt_mountp); 1084 ignored++; 1085 } else { 1086 mrp->ig_path = 0; 1087 (void) strcpy(mrp->my_dir, m.mnt_mountp); 1088 } 1089 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) { 1090 fprintf(stderr, "nfsstat: not enough memory\n"); 1091 exit(1); 1092 } 1093 mrp->next = list; 1094 list = mrp; 1095 } 1096 1097 /* 1098 * If something got ignored, go to the beginning of the mnttab 1099 * and look for the cachefs entries since they are the one 1100 * causing this. The mount point saved for the ignored entries 1101 * is matched against the special to get the actual mount point. 1102 * We are interested in the acutal mount point so that the output 1103 * look nice too. 1104 */ 1105 if (ignored) { 1106 rewind(mt); 1107 resetmnttab(mt); 1108 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1109 1110 /* ignore non "cachefs" */ 1111 if (strcmp(m.mnt_fstype, MNTTYPE_CACHEFS) != 0) 1112 continue; 1113 1114 for (mrp = list; mrp; mrp = mrp->next) { 1115 if (mrp->ig_path == 0) 1116 continue; 1117 if (strcmp(mrp->ig_path, m.mnt_special) == 0) { 1118 mrp->ig_path = 0; 1119 (void) strcpy(mrp->my_dir, 1120 m.mnt_mountp); 1121 } 1122 } 1123 } 1124 /* 1125 * Now ignored entries which do not have 1126 * the my_dir initialized are really ignored; This never 1127 * happens unless the mnttab is corrupted. 1128 */ 1129 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) { 1130 if (mrp->ig_path == 0) 1131 pmrp = mrp; 1132 else if (pmrp) 1133 pmrp->next = mrp->next; 1134 else 1135 list = mrp->next; 1136 } 1137 } 1138 1139 (void) fclose(mt); 1140 1141 1142 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1143 int i; 1144 1145 if (ksp->ks_type != KSTAT_TYPE_RAW) 1146 continue; 1147 if (strcmp(ksp->ks_module, "nfs") != 0) 1148 continue; 1149 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1150 continue; 1151 1152 for (mrp = list; mrp; mrp = mrp->next) { 1153 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance) 1154 break; 1155 } 1156 if (mrp == 0) 1157 continue; 1158 1159 if (safe_kstat_read(kc, ksp, &mik) == -1) 1160 continue; 1161 1162 printf("%s from %s\n", mrp->my_dir, mrp->my_path); 1163 1164 /* 1165 * for printing rdma transport and provider string. 1166 * This way we avoid modifying the kernel mntinfo_kstat 1167 * struct for protofmly. 1168 */ 1169 if (strcmp(mik.mik_proto, "ibtf") == 0) { 1170 printf(" Flags: vers=%u,proto=rdma", 1171 mik.mik_vers); 1172 transport_flag = 1; 1173 } else { 1174 printf(" Flags: vers=%u,proto=%s", 1175 mik.mik_vers, mik.mik_proto); 1176 transport_flag = 0; 1177 } 1178 1179 /* 1180 * get the secmode name from /etc/nfssec.conf. 1181 */ 1182 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) { 1183 flavor = nfs_sec.sc_name; 1184 } else 1185 flavor = NULL; 1186 1187 if (flavor != NULL) 1188 printf(",sec=%s", flavor); 1189 else 1190 printf(",sec#=%d", mik.mik_secmod); 1191 1192 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft"); 1193 if (mik.mik_flags & MI_PRINTED) 1194 printf(",printed"); 1195 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr"); 1196 if (mik.mik_flags & MI_DOWN) 1197 printf(",down"); 1198 if (mik.mik_flags & MI_NOAC) 1199 printf(",noac"); 1200 if (mik.mik_flags & MI_NOCTO) 1201 printf(",nocto"); 1202 if (mik.mik_flags & MI_DYNAMIC) 1203 printf(",dynamic"); 1204 if (mik.mik_flags & MI_LLOCK) 1205 printf(",llock"); 1206 if (mik.mik_flags & MI_GRPID) 1207 printf(",grpid"); 1208 if (mik.mik_flags & MI_RPCTIMESYNC) 1209 printf(",rpctimesync"); 1210 if (mik.mik_flags & MI_LINK) 1211 printf(",link"); 1212 if (mik.mik_flags & MI_SYMLINK) 1213 printf(",symlink"); 1214 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY) 1215 printf(",readdironly"); 1216 if (mik.mik_flags & MI_ACL) 1217 printf(",acl"); 1218 1219 if (mik.mik_vers >= NFS_V4) { 1220 if (mik.mik_flags & MI4_MIRRORMOUNT) 1221 printf(",mirrormount"); 1222 } 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(" %s: srtt=%d (%dms), " 1247 "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 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] " 1301 "[interval [count]]\n"); 1302 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n"); 1303 exit(1); 1304 } 1305 1306 static void 1307 fail(int do_perror, char *message, ...) 1308 { 1309 va_list args; 1310 1311 va_start(args, message); 1312 fprintf(stderr, "nfsstat: "); 1313 vfprintf(stderr, message, args); 1314 va_end(args); 1315 if (do_perror) 1316 fprintf(stderr, ": %s", strerror(errno)); 1317 fprintf(stderr, "\n"); 1318 exit(1); 1319 } 1320 1321 kid_t 1322 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1323 { 1324 kid_t kstat_chain_id = kstat_read(kc, ksp, data); 1325 1326 if (kstat_chain_id == -1) 1327 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name); 1328 return (kstat_chain_id); 1329 } 1330 1331 kid_t 1332 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1333 { 1334 kid_t kstat_chain_id = 0; 1335 1336 if (ksp->ks_data != NULL) { 1337 kstat_chain_id = kstat_write(kc, ksp, data); 1338 1339 if (kstat_chain_id == -1) 1340 fail(1, "kstat_write(%x, '%s') failed", kc, 1341 ksp->ks_name); 1342 } 1343 return (kstat_chain_id); 1344 } 1345 1346 void 1347 stats_timer(int interval) 1348 { 1349 timer_t t_id; 1350 itimerspec_t time_struct; 1351 struct sigevent sig_struct; 1352 struct sigaction act; 1353 1354 bzero(&sig_struct, sizeof (struct sigevent)); 1355 bzero(&act, sizeof (struct sigaction)); 1356 1357 /* Create timer */ 1358 sig_struct.sigev_notify = SIGEV_SIGNAL; 1359 sig_struct.sigev_signo = SIGUSR1; 1360 sig_struct.sigev_value.sival_int = 0; 1361 1362 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) { 1363 fail(1, "Timer creation failed"); 1364 } 1365 1366 act.sa_handler = handle_sig; 1367 1368 if (sigaction(SIGUSR1, &act, NULL) != 0) { 1369 fail(1, "Could not set up signal handler"); 1370 } 1371 1372 time_struct.it_value.tv_sec = interval; 1373 time_struct.it_value.tv_nsec = 0; 1374 time_struct.it_interval.tv_sec = interval; 1375 time_struct.it_interval.tv_nsec = 0; 1376 1377 /* Arm timer */ 1378 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) { 1379 fail(1, "Setting timer failed"); 1380 } 1381 } 1382 1383 void 1384 handle_sig(int x) 1385 { 1386 } 1387 1388 static void 1389 kstat_copy(kstat_t *src, kstat_t *dst, int fr) 1390 { 1391 1392 if (fr) 1393 free(dst->ks_data); 1394 1395 *dst = *src; 1396 1397 if (src->ks_data != NULL) { 1398 safe_zalloc(&dst->ks_data, src->ks_data_size, 0); 1399 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size); 1400 } else { 1401 dst->ks_data = NULL; 1402 dst->ks_data_size = 0; 1403 } 1404 } 1405 1406 /* 1407 * "Safe" allocators - if we return we're guaranteed 1408 * to have the desired space. We exit via fail 1409 * if we can't get the space. 1410 */ 1411 void 1412 safe_zalloc(void **ptr, uint_t size, int free_first) 1413 { 1414 if (*ptr == NULL) 1415 fail(1, "invalid pointer"); 1416 if (free_first && *ptr != NULL) 1417 free(*ptr); 1418 if ((*ptr = (void *)malloc(size)) == NULL) 1419 fail(1, "malloc failed"); 1420 (void) memset(*ptr, 0, size); 1421 } 1422 1423 static int 1424 safe_strtoi(char const *val, char *errmsg) 1425 { 1426 char *end; 1427 long tmp; 1428 errno = 0; 1429 tmp = strtol(val, &end, 10); 1430 if (*end != '\0' || errno) 1431 fail(0, "%s %s", errmsg, val); 1432 return ((int)tmp); 1433 } 1434