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 <kstat.h>
37 #include <locale.h>
38 #include <sys/fs/cachefs_log.h>
39 #include "stats.h"
40
41 void usage(char *);
42 void pr_err(char *, ...);
43
44 static int hflag = 0;
45 static char *fpath = NULL;
46 static int vflag = 0;
47 char *prog;
48
49 static void log_show(char *, char *);
50
51 int
main(int argc,char ** argv)52 main(int argc, char **argv)
53 {
54 int rc = 0, c;
55 int errflg = 0;
56 stats_cookie_t *fs = NULL;
57 char *logfile;
58
59 (void) setlocale(LC_ALL, "");
60 #if !defined(TEXT_DOMAIN)
61 #define TEXT_DOMAIN "SYS_TEST"
62 #endif /* TEXT_DOMAIN */
63 (void) textdomain(TEXT_DOMAIN);
64
65 if (prog = strrchr(argv[0], '/'))
66 ++prog;
67 else
68 prog = argv[0];
69
70 while ((c = getopt(argc, argv, "hf:v")) != EOF)
71 switch (c) {
72 case 'h':
73 if (fpath != NULL)
74 ++errflg;
75 else
76 ++hflag;
77 break;
78
79 case 'f':
80 if (hflag)
81 ++errflg;
82 else
83 fpath = optarg;
84 break;
85
86 case 'v':
87 ++vflag;
88 break;
89
90 case '?':
91 default:
92 ++errflg;
93 break;
94 }
95
96 if ((errflg) || (optind != (argc - 1))) {
97 usage(NULL);
98 rc = -1;
99 goto out;
100 }
101
102 fs = stats_create_mountpath(argv[optind], prog);
103 if (fs == NULL) {
104 pr_err(gettext("Cannot initialize cachefs library\n"));
105 rc = 1;
106 goto out;
107 }
108
109 if (! stats_good(fs)) {
110 pr_err(stats_errorstr(fs));
111 rc = stats_errno(fs);
112 goto out;
113 }
114
115 if ((logfile = stats_log_kernel_getname(fs)) == NULL) {
116 pr_err(stats_errorstr(fs));
117 rc = stats_errno(fs);
118 goto out;
119 }
120 if ((logfile[0] == '\0') && (hflag) && (! vflag)) {
121 log_show(argv[optind], logfile);
122 goto out;
123 }
124
125 if (fpath != NULL) {
126 if ((stats_log_kernel_setname(fs, fpath) != 0) ||
127 (stats_log_which(fs, CACHEFS_LOG_MOUNT, 1) != 0) ||
128 (stats_log_which(fs, CACHEFS_LOG_UMOUNT, 1) != 0) ||
129 (stats_log_which(fs, CACHEFS_LOG_REMOVE, 1) != 0) ||
130 (stats_log_which(fs, CACHEFS_LOG_RMDIR, 1) != 0) ||
131 (stats_log_which(fs, CACHEFS_LOG_TRUNCATE, 1) != 0) ||
132 (stats_log_which(fs, CACHEFS_LOG_CREATE, 1) != 0) ||
133 (stats_log_which(fs, CACHEFS_LOG_MKDIR, 1) != 0) ||
134 (stats_log_which(fs, CACHEFS_LOG_RENAME, 1) != 0) ||
135 (stats_log_which(fs, CACHEFS_LOG_SYMLINK, 1) != 0) ||
136 (stats_log_which(fs, CACHEFS_LOG_UALLOC, 1) != 0) ||
137 (stats_log_which(fs, CACHEFS_LOG_CSYMLINK, 1) != 0) ||
138 (stats_log_which(fs, CACHEFS_LOG_FILLDIR, 1) != 0) ||
139 (stats_log_which(fs, CACHEFS_LOG_MDCREATE, 1) != 0) ||
140 (stats_log_which(fs, CACHEFS_LOG_NOCACHE, 1) != 0) ||
141 (stats_log_which(fs, CACHEFS_LOG_CALLOC, 1) != 0) ||
142 (stats_log_which(fs, CACHEFS_LOG_RFDIR, 1) != 0)) {
143 pr_err(stats_errorstr(fs));
144 rc = stats_errno(fs);
145 goto out;
146 }
147 } else if (hflag) {
148 if (stats_log_kernel_setname(fs, NULL) != 0) {
149 pr_err(stats_errorstr(fs));
150 rc = stats_errno(fs);
151 goto out;
152 }
153 }
154
155 if ((logfile = stats_log_kernel_getname(fs)) == NULL) {
156 pr_err(stats_errorstr(fs));
157 rc = stats_errno(fs);
158 goto out;
159 }
160
161 log_show(argv[optind], logfile);
162
163 /*
164 * if they're changing state, inform them of other filesystems
165 * that they're changing state for by way of sharing the
166 * cache.
167 *
168 * or, if they're verbose (-v flag), tell them about the
169 * others.
170 */
171
172 if (((fpath) || (hflag) || (vflag)) && (! stats_inerror(fs))) {
173 cachefs_kstat_key_t *k, *origk;
174 stats_cookie_t *sc;
175 int before = 0;
176
177 origk = stats_getkey(fs);
178 sc = stats_create_unbound(prog);
179 if (sc == NULL) {
180 pr_err(gettext("Cannot create stats object"));
181 rc = 1;
182 goto out;
183 }
184
185 while ((k = stats_next(sc)) != NULL) {
186 if (! k->ks_mounted) {
187 free(k);
188 continue;
189 }
190 if (strcmp((char *)(uintptr_t)origk->ks_cachedir,
191 (char *)(uintptr_t)k->ks_cachedir) != 0) {
192 free(k);
193 continue;
194 }
195 if (origk->ks_id == k->ks_id) {
196 free(k);
197 continue;
198 }
199 if (! before)
200 printf("\n");
201 before = 1;
202 log_show((char *)(uintptr_t)k->ks_mountpoint, logfile);
203 free(k);
204 }
205 free(origk);
206 stats_destroy(sc);
207 }
208
209 if (stats_inerror(fs)) {
210 pr_err(stats_errorstr(fs));
211 rc = stats_errno(fs);
212 }
213
214 out:
215 stats_destroy(fs);
216 return (rc);
217 }
218
219 static void
log_show(char * mount,char * logfile)220 log_show(char *mount, char *logfile)
221 {
222 if (logfile[0] == '\0')
223 logfile = gettext("not logged");
224 printf("%s: %s\n", logfile, mount);
225 }
226
227 /*
228 *
229 * usage
230 *
231 * Description:
232 * Prints a short usage message.
233 * Arguments:
234 * msgp message to include with the usage message
235 * Returns:
236 * Preconditions:
237 */
238
239 void
usage(char * msgp)240 usage(char *msgp)
241 {
242 if (msgp) {
243 pr_err("%s", msgp);
244 }
245
246 fprintf(stderr,
247 gettext("Usage: "
248 "cachefslog [ -v ] [-h | -f <logfile>] mountpoint\n"));
249 }
250
251 /*
252 *
253 * pr_err
254 *
255 * Description:
256 * Prints an error message to stderr.
257 * Arguments:
258 * fmt printf style format
259 * ... arguments for fmt
260 * Returns:
261 * Preconditions:
262 * precond(fmt)
263 */
264
265 void
pr_err(char * fmt,...)266 pr_err(char *fmt, ...)
267 {
268 va_list ap;
269
270 va_start(ap, fmt);
271 (void) fprintf(stderr, gettext("cachefslog: "));
272 (void) vfprintf(stderr, fmt, ap);
273 (void) fprintf(stderr, "\n");
274 va_end(ap);
275 }
276