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 * 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 * 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 * 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 * 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 * 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 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 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*/ 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 * 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 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 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 }