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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "%Z%%M% %I%     %E% SMI"
  28 
  29 #include <stdio.h>
  30 #include <stdlib.h>
  31 #include <string.h>
  32 #include <stdarg.h>
  33 #include <libintl.h>
  34 #include <sys/types.h>
  35 #include <sys/ioctl.h>
  36 #include <sys/stat.h>
  37 #include <kstat.h>
  38 #include <locale.h>
  39 #include <sys/fs/cachefs_log.h>
  40 #include "stats.h"
  41 
  42 void usage(char *);
  43 void pr_err(char *, ...);
  44 
  45 static int zflag;
  46 char *prog;
  47 
  48 static void print_stats(stats_cookie_t *, cachefs_kstat_key_t *, int);
  49 
  50 int
  51 main(int argc, char **argv)
  52 {
  53         int rc = 0;
  54         int i, c, errflg = 0;
  55         stats_cookie_t *sc = NULL;
  56         cachefs_kstat_key_t *key;
  57 
  58         (void) setlocale(LC_ALL, "");
  59 #if !defined(TEXT_DOMAIN)
  60 #define TEXT_DOMAIN "SYS_TEST"
  61 #endif /* TEXT_DOMAIN */
  62         (void) textdomain(TEXT_DOMAIN);
  63 
  64         if (prog = strrchr(argv[0], '/'))
  65                 ++prog;
  66         else
  67                 prog = argv[0];
  68 
  69         while ((c = getopt(argc, argv, "z")) != EOF)
  70                 switch (c) {
  71                 case 'z':
  72                         ++zflag;
  73                         break;
  74 
  75                 case '?':
  76                 default:
  77                         ++errflg;
  78                         break;
  79                 }
  80 
  81         if (errflg) {
  82                 usage(NULL);
  83                 rc = -1;
  84                 goto out;
  85         }
  86 
  87         /*
  88          * handle multiple mountpoints specified on command line
  89          */
  90 
  91         for (i = optind; i < argc; i++) {
  92                 if ((sc = stats_create_mountpath(argv[i], prog)) == NULL) {
  93                         pr_err(gettext("Cannot use %s"), argv[i]);
  94                         rc = 1;
  95                         continue;
  96                 }
  97 
  98                 if (stats_inerror(sc)) {
  99                         pr_err(stats_errorstr(sc));
 100                         rc = stats_errno(sc);
 101                         continue;
 102                 }
 103                 print_stats(sc, key = stats_getkey(sc), zflag);
 104                 if (stats_inerror(sc)) {
 105                         pr_err(stats_errorstr(sc));
 106                         rc = stats_errno(sc);
 107                 }
 108 
 109                 stats_destroy(sc);
 110                 free(key);
 111         }
 112 
 113         /*
 114          * handle the case where no mountpoints were specified,
 115          * i.e. show stats for all.
 116          */
 117 
 118         if (optind >= argc) {
 119                 sc = stats_create_unbound(prog);
 120 
 121                 while ((key = stats_next(sc)) != NULL) {
 122                         if (! key->ks_mounted) {
 123                                 free(key);
 124                                 continue;
 125                         }
 126 
 127                         print_stats(sc, key, zflag);
 128                         if (stats_inerror(sc)) {
 129                                 pr_err(stats_errorstr(sc));
 130                                 rc = stats_errno(sc);
 131                         }
 132                         free(key);
 133                 }
 134                 stats_destroy(sc);
 135         }
 136 
 137 out:
 138         return (rc);
 139 }
 140 
 141 static void
 142 print_stats(stats_cookie_t *sc, cachefs_kstat_key_t *key, int zero)
 143 {
 144         uint_t misses, passes, fails, modifies;
 145         uint_t hitp, passtotal;
 146         uint_t gccount;
 147         u_longlong_t hits;
 148 
 149         hits = (u_longlong_t)stats_hits(sc);
 150         misses = stats_misses(sc);
 151         if (hits + misses != 0)
 152                 hitp = (uint_t)((100 * hits) / (hits + misses));
 153         else
 154                 hitp = 100;
 155 
 156         passes = stats_passes(sc);
 157         fails = stats_fails(sc);
 158         passtotal = passes + fails;
 159 
 160         modifies = stats_modifies(sc);
 161 
 162         gccount = stats_gc_count(sc);
 163 
 164         printf("\n    %s\n", (char *)(uintptr_t)key->ks_mountpoint);
 165         printf(gettext(
 166                 "\t         cache hit rate: %5u%% (%llu hits, %u misses)\n"),
 167                 hitp, hits, misses);
 168         printf(gettext("\t     consistency checks: %6d (%d pass, %d fail)\n"),
 169             passtotal, passes, fails);
 170         printf(gettext("\t               modifies: %6d\n"), modifies);
 171         printf(gettext("\t     garbage collection: %6d\n"), gccount);
 172         if (gccount != 0) {
 173                 time_t gctime = stats_gc_time(sc);
 174                 time_t before = stats_gc_before(sc);
 175                 time_t after = stats_gc_after(sc);
 176 
 177                 if (gctime != (time_t)0)
 178                         printf(gettext("\tlast garbage collection: %s"),
 179                             ctime(&gctime));
 180         }
 181 
 182         if (zero)
 183                 (void) stats_zero_stats(sc);
 184 }
 185 
 186 
 187 /*
 188  *
 189  *                      usage
 190  *
 191  * Description:
 192  *      Prints a short usage message.
 193  * Arguments:
 194  *      msgp    message to include with the usage message
 195  * Returns:
 196  * Preconditions:
 197  */
 198 
 199 void
 200 usage(char *msgp)
 201 {
 202         if (msgp) {
 203                 pr_err("%s", msgp);
 204         }
 205 
 206         fprintf(stderr,
 207             gettext("Usage: cachefsstat [ -z ] [ path ... ]\n"));
 208 }
 209 
 210 /*
 211  *
 212  *                      pr_err
 213  *
 214  * Description:
 215  *      Prints an error message to stderr.
 216  * Arguments:
 217  *      fmt     printf style format
 218  *      ...     arguments for fmt
 219  * Returns:
 220  * Preconditions:
 221  *      precond(fmt)
 222  */
 223 
 224 void
 225 pr_err(char *fmt, ...)
 226 {
 227         va_list ap;
 228 
 229         va_start(ap, fmt);
 230         (void) fprintf(stderr, gettext("cachefsstat: "));
 231         (void) vfprintf(stderr, fmt, ap);
 232         (void) fprintf(stderr, "\n");
 233         va_end(ap);
 234 }