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 /*
30 *
31 * stats_create.c
32 *
33 * Routines for the `clean interface' to cachefs statistics.
34 */
35
36 #include <stdarg.h>
37 #include <libintl.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <assert.h>
41 #include <sys/fs/cachefs_fs.h>
42 #include <string.h>
43 #include "stats.h"
44
45 void *malloc(), *calloc();
46
47 /* forward declarations of statics */
48 static stats_cookie_t *stats_create(char *);
49
50 static stats_cookie_t *
stats_create(char * progname)51 stats_create(char *progname)
52 {
53 stats_cookie_t *rc;
54
55 if ((rc = (stats_cookie_t *)calloc(1, sizeof (*rc))) == NULL)
56 goto out;
57
58 rc->st_magic = STATS_MAGIC;
59 if (rc->st_progname = strrchr(progname, '/'))
60 rc->st_progname++;
61 else
62 rc->st_progname = progname;
63
64 if ((rc->st_kstat_cookie = kstat_open()) == NULL) {
65 stats_perror(rc, SE_KERNEL,
66 gettext("Cannot initialize kstats"));
67 goto out;
68 }
69
70 out:
71 return (rc);
72 }
73
74 stats_cookie_t *
stats_create_unbound(char * progname)75 stats_create_unbound(char *progname)
76 {
77 stats_cookie_t *st;
78
79 if ((st = stats_create(progname)) == NULL)
80 goto out;
81
82 st->st_flags |= ST_VALID;
83
84 out:
85 return (st);
86 }
87
88 stats_cookie_t *
stats_create_mountpath(char * mountpath,char * progname)89 stats_create_mountpath(char *mountpath, char *progname)
90 {
91 stats_cookie_t *st;
92 kstat_t *key;
93 cachefs_kstat_key_t *k;
94 dev_t dev;
95 ino64_t ino;
96 struct stat64 s;
97 int i, n;
98
99 if ((st = stats_create(progname)) == NULL)
100 goto out;
101
102 if ((key = kstat_lookup(st->st_kstat_cookie, "cachefs", 0, "key"))
103 == NULL) {
104 stats_perror(st, SE_KERNEL,
105 gettext("Cannot lookup cachefs key kstat"));
106 goto out;
107 }
108 if (kstat_read(st->st_kstat_cookie, key, NULL) < 0) {
109 stats_perror(st, SE_KERNEL,
110 gettext("Cannot read cachefs key kstat"));
111 goto out;
112 }
113 k = (cachefs_kstat_key_t *)key->ks_data;
114 n = key->ks_ndata;
115
116 if (stat64(mountpath, &s) != 0) {
117 stats_perror(st, SE_FILE,
118 gettext("Cannot stat %s"), mountpath);
119 goto out;
120 }
121 ino = s.st_ino;
122 dev = s.st_dev;
123
124 for (i = 0; i < n; i++) {
125 k[i].ks_mountpoint += (uintptr_t)k;
126 k[i].ks_backfs += (uintptr_t)k;
127 k[i].ks_cachedir += (uintptr_t)k;
128 k[i].ks_cacheid += (uintptr_t)k;
129
130 if (! k[i].ks_mounted)
131 continue;
132
133 if ((stat64((char *)(uintptr_t)k[i].ks_mountpoint, &s) == 0) &&
134 (s.st_dev == dev) &&
135 (s.st_ino == ino))
136 break;
137 }
138
139 if (i >= n) {
140 stats_perror(st, SE_FILE,
141 gettext("%s: not a cachefs mountpoint"), mountpath);
142 goto out;
143 }
144
145 st->st_fsid = k[i].ks_id;
146
147 st->st_flags |= ST_VALID | ST_BOUND;
148
149 out:
150 return (st);
151 }
152
153 /*
154 * stats_next - bind the cookie to the next valid cachefs mount.
155 *
156 * returns cachefs_kstat_key_t *, which gives all the info you need.
157 * returns NULL if we're out of mounts, or if an error occured.
158 * returns malloc()ed data, which the client has to free() itself.
159 */
160
161 cachefs_kstat_key_t *
stats_next(stats_cookie_t * st)162 stats_next(stats_cookie_t *st)
163 {
164 kstat_t *key;
165 cachefs_kstat_key_t *k, *prc = NULL, *rc = NULL;
166 int i, n;
167
168 assert(stats_good(st));
169
170 if (((key = kstat_lookup(st->st_kstat_cookie, "cachefs", 0,
171 "key")) == NULL) ||
172 (kstat_read(st->st_kstat_cookie, key, NULL) < 0)) {
173 stats_perror(st, SE_KERNEL,
174 gettext("Cannot get cachefs key kstat"));
175 goto out;
176 }
177 k = (cachefs_kstat_key_t *)key->ks_data;
178 n = key->ks_ndata;
179
180 if (st->st_flags & ST_BOUND) {
181 for (i = 0; i < n; i++)
182 if (st->st_fsid == k[i].ks_id)
183 break;
184 ++i;
185 if (i < n) {
186 prc = k + i;
187 st->st_fsid = k[i].ks_id;
188 } else
189 st->st_flags &= ~ST_BOUND;
190 } else if (n > 0) {
191 st->st_fsid = k[0].ks_id;
192 st->st_flags |= ST_BOUND;
193 prc = k;
194 }
195
196 out:
197 if (prc != NULL) {
198 char *s;
199 int size;
200
201 prc->ks_mountpoint += (uintptr_t)k;
202 prc->ks_backfs += (uintptr_t)k;
203 prc->ks_cachedir += (uintptr_t)k;
204 prc->ks_cacheid += (uintptr_t)k;
205
206 size = sizeof (*rc);
207 size += strlen((char *)(uintptr_t)prc->ks_mountpoint) + 1;
208 size += strlen((char *)(uintptr_t)prc->ks_backfs) + 1;
209 size += strlen((char *)(uintptr_t)prc->ks_cachedir) + 1;
210 size += strlen((char *)(uintptr_t)prc->ks_cacheid) + 1;
211
212 if ((rc = (cachefs_kstat_key_t *)
213 malloc(size)) == NULL) {
214 stats_perror(st, SE_NOMEM,
215 gettext("Cannot malloc return code"));
216 } else {
217 memcpy(rc, prc, sizeof (*rc));
218 s = (char *)((uintptr_t)rc + sizeof (*rc));
219
220 (void) strcpy(s, (char *)(uintptr_t)prc->ks_mountpoint);
221 rc->ks_mountpoint = (uintptr_t)s;
222 s += strlen(s) + 1;
223 (void) strcpy(s, (char *)(uintptr_t)prc->ks_backfs);
224 rc->ks_backfs = (uintptr_t)s;
225 s += strlen(s) + 1;
226 (void) strcpy(s, (char *)(uintptr_t)prc->ks_cachedir);
227 rc->ks_cachedir = (uintptr_t)s;
228 s += strlen(s) + 1;
229 (void) strcpy(s, (char *)(uintptr_t)prc->ks_cacheid);
230 rc->ks_cacheid = (uintptr_t)s;
231 }
232 }
233
234 return (rc);
235 }
236
237 cachefs_kstat_key_t *
stats_getkey(stats_cookie_t * st)238 stats_getkey(stats_cookie_t *st)
239 {
240 kstat_t *ksp;
241 cachefs_kstat_key_t *k, *key, *rc = NULL;
242 int size;
243 char *s;
244
245 assert(stats_good(st));
246 assert(st->st_flags & ST_BOUND);
247
248 if (((ksp = kstat_lookup(st->st_kstat_cookie, "cachefs", 0,
249 "key")) == NULL) ||
250 (kstat_read(st->st_kstat_cookie, ksp, NULL) < 0)) {
251 stats_perror(st, SE_KERNEL,
252 gettext("Cannot get cachefs key kstat"));
253 goto out;
254 }
255 key = (cachefs_kstat_key_t *)ksp->ks_data;
256 k = key + st->st_fsid - 1;
257 k->ks_mountpoint += (uintptr_t)key;
258 k->ks_backfs += (uintptr_t)key;
259 k->ks_cachedir += (uintptr_t)key;
260 k->ks_cacheid += (uintptr_t)key;
261 size = sizeof (*rc);
262 size += strlen((char *)(uintptr_t)k->ks_mountpoint) + 1;
263 size += strlen((char *)(uintptr_t)k->ks_backfs) + 1;
264 size += strlen((char *)(uintptr_t)k->ks_cachedir) + 1;
265 size += strlen((char *)(uintptr_t)k->ks_cacheid) + 1;
266
267 if ((rc = (cachefs_kstat_key_t *)malloc(size)) == NULL)
268 stats_perror(st, SE_NOMEM,
269 gettext("Cannot malloc return code"));
270 else {
271 memcpy(rc, k, sizeof (*rc));
272 s = (char *)((uintptr_t)rc + sizeof (*rc));
273
274 (void) strcpy(s, (char *)(uintptr_t)k->ks_mountpoint);
275 rc->ks_mountpoint = (uintptr_t)s;
276 s += strlen(s) + 1;
277 (void) strcpy(s, (char *)(uintptr_t)k->ks_backfs);
278 rc->ks_backfs = (uintptr_t)s;
279 s += strlen(s) + 1;
280 (void) strcpy(s, (char *)(uintptr_t)k->ks_cachedir);
281 rc->ks_cachedir = (uintptr_t)s;
282 s += strlen(s) + 1;
283 (void) strcpy(s, (char *)(uintptr_t)k->ks_cacheid);
284 rc->ks_cacheid = (uintptr_t)s;
285 s += strlen(s) + 1;
286 }
287
288 assert(rc->ks_id == st->st_fsid);
289
290 out:
291 return (rc);
292 }
293
294 void
stats_destroy(stats_cookie_t * st)295 stats_destroy(stats_cookie_t *st)
296 {
297 void free();
298
299 if (st == NULL)
300 return;
301
302 if (st->st_kstat_cookie != NULL)
303 kstat_close(st->st_kstat_cookie);
304 if (st->st_logxdr.x_ops != NULL)
305 xdr_destroy(&st->st_logxdr);
306 if ((st->st_logstream != NULL) && (st->st_flags & ST_LFOPEN))
307 (void) fclose(st->st_logstream);
308
309 /*
310 * we don't want to depend on dbm (or stats_dbm), so we don't
311 * do a stats_dbm_close. we do try to require the client to
312 * have done it, via an assert(), however.
313 */
314
315 assert(! (st->st_flags & ST_DBMOPEN));
316
317 st->st_magic++;
318
319 free(st);
320 }
321
322 int
stats_good(stats_cookie_t * st)323 stats_good(stats_cookie_t *st)
324 {
325 if (st == NULL)
326 return (0);
327 if (st->st_magic != STATS_MAGIC)
328 return (0);
329 if (! (st->st_flags & ST_VALID))
330 return (0);
331
332 return (1);
333 }
334
335 void
336 /*PRINTFLIKE3*/
stats_perror(stats_cookie_t * st,int Errno,char * fmt,...)337 stats_perror(stats_cookie_t *st, int Errno, char *fmt, ...)
338 {
339
340 va_list ap;
341
342 assert(st != NULL);
343 assert(st->st_magic == STATS_MAGIC);
344
345 va_start(ap, fmt);
346 (void) vsnprintf(st->st_errorstr, sizeof (st->st_errorstr), fmt, ap);
347 va_end(ap);
348
349 st->st_errno = Errno;
350
351 st->st_flags |= ST_ERROR;
352 }
353
354 char *
stats_errorstr(stats_cookie_t * st)355 stats_errorstr(stats_cookie_t *st)
356 {
357 assert(st != NULL);
358 assert(st->st_magic == STATS_MAGIC);
359
360 return (st->st_errorstr);
361 }
362
363 int
stats_errno(stats_cookie_t * st)364 stats_errno(stats_cookie_t *st)
365 {
366 assert(st != NULL);
367 assert(st->st_magic == STATS_MAGIC);
368
369 return (st->st_errno);
370 }
371
372 int
stats_inerror(stats_cookie_t * st)373 stats_inerror(stats_cookie_t *st)
374 {
375 assert(st != NULL);
376 assert(st->st_magic == STATS_MAGIC);
377
378 return (st->st_flags & ST_ERROR);
379 }
380