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