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
main(int argc,char ** argv)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
print_stats(stats_cookie_t * sc,cachefs_kstat_key_t * key,int zero)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
usage(char * msgp)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
pr_err(char * fmt,...)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 }
235