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 #include <sys/types.h> 30*0Sstevel@tonic-gate #include <sys/systeminfo.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <limits.h> 33*0Sstevel@tonic-gate #include <strings.h> 34*0Sstevel@tonic-gate #include <stddef.h> 35*0Sstevel@tonic-gate #include <unistd.h> 36*0Sstevel@tonic-gate #include <dlfcn.h> 37*0Sstevel@tonic-gate #include <errno.h> 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include <fmdump.h> 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate /* 42*0Sstevel@tonic-gate * fmdump loadable scheme support 43*0Sstevel@tonic-gate * 44*0Sstevel@tonic-gate * This file provides a pared-down implementation of fmd's fmd_fmri.c and 45*0Sstevel@tonic-gate * fmd_scheme.c and must be kept in sync with the set of service routines 46*0Sstevel@tonic-gate * required by scheme plug-ins. At some point if other utilities want to 47*0Sstevel@tonic-gate * use this we can refactor it into a more general library. (Note: fmd 48*0Sstevel@tonic-gate * cannot use such a library because it has its own internal locking, etc.) 49*0Sstevel@tonic-gate * As schemes are needed, we dlopen() them and cache a list of them which we 50*0Sstevel@tonic-gate * can search later. We also use the list as a negative cache: if we fail to 51*0Sstevel@tonic-gate * load a scheme, we add an entry with sch_dlp = NULL and sch_err recording 52*0Sstevel@tonic-gate * the errno to be returned to the caller. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate typedef struct fmd_scheme_ops { 56*0Sstevel@tonic-gate int (*sop_init)(void); 57*0Sstevel@tonic-gate void (*sop_fini)(void); 58*0Sstevel@tonic-gate ssize_t (*sop_nvl2str)(nvlist_t *, char *, size_t); 59*0Sstevel@tonic-gate } fmd_scheme_ops_t; 60*0Sstevel@tonic-gate 61*0Sstevel@tonic-gate typedef struct fmd_scheme_opd { 62*0Sstevel@tonic-gate const char *opd_name; /* symbol name of scheme function */ 63*0Sstevel@tonic-gate size_t opd_off; /* offset within fmd_scheme_ops_t */ 64*0Sstevel@tonic-gate } fmd_scheme_opd_t; 65*0Sstevel@tonic-gate 66*0Sstevel@tonic-gate typedef struct fmd_scheme { 67*0Sstevel@tonic-gate struct fmd_scheme *sch_next; /* next scheme on list of schemes */ 68*0Sstevel@tonic-gate char *sch_name; /* name of this scheme (fmri prefix) */ 69*0Sstevel@tonic-gate void *sch_dlp; /* libdl(3DL) shared library handle */ 70*0Sstevel@tonic-gate int sch_err; /* if negative entry, errno to return */ 71*0Sstevel@tonic-gate fmd_scheme_ops_t sch_ops; /* scheme function pointers */ 72*0Sstevel@tonic-gate } fmd_scheme_t; 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate static fmd_scheme_t *sch_list; /* list of cached schemes */ 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate static long 77*0Sstevel@tonic-gate fmd_scheme_notsup(void) 78*0Sstevel@tonic-gate { 79*0Sstevel@tonic-gate errno = ENOTSUP; 80*0Sstevel@tonic-gate return (-1); 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate static int 84*0Sstevel@tonic-gate fmd_scheme_nop(void) 85*0Sstevel@tonic-gate { 86*0Sstevel@tonic-gate return (0); 87*0Sstevel@tonic-gate } 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate /* 90*0Sstevel@tonic-gate * Default values for the scheme ops. If a scheme function is not defined in 91*0Sstevel@tonic-gate * the module, then this operation is implemented using the default function. 92*0Sstevel@tonic-gate */ 93*0Sstevel@tonic-gate static const fmd_scheme_ops_t _fmd_scheme_default_ops = { 94*0Sstevel@tonic-gate (int (*)())fmd_scheme_nop, /* sop_init */ 95*0Sstevel@tonic-gate (void (*)())fmd_scheme_nop, /* sop_fini */ 96*0Sstevel@tonic-gate (ssize_t (*)())fmd_scheme_notsup, /* sop_nvl2str */ 97*0Sstevel@tonic-gate }; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate /* 100*0Sstevel@tonic-gate * Scheme ops descriptions. These names and offsets are used by the function 101*0Sstevel@tonic-gate * fmd_scheme_rtld_init(), defined below, to load up a fmd_scheme_ops_t. 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate static const fmd_scheme_opd_t _fmd_scheme_ops[] = { 104*0Sstevel@tonic-gate { "fmd_fmri_init", offsetof(fmd_scheme_ops_t, sop_init) }, 105*0Sstevel@tonic-gate { "fmd_fmri_fini", offsetof(fmd_scheme_ops_t, sop_fini) }, 106*0Sstevel@tonic-gate { "fmd_fmri_nvl2str", offsetof(fmd_scheme_ops_t, sop_nvl2str) }, 107*0Sstevel@tonic-gate { NULL, 0 } 108*0Sstevel@tonic-gate }; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate static fmd_scheme_t * 111*0Sstevel@tonic-gate fmd_scheme_create(const char *name) 112*0Sstevel@tonic-gate { 113*0Sstevel@tonic-gate fmd_scheme_t *sp; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate if ((sp = malloc(sizeof (fmd_scheme_t))) == NULL || 116*0Sstevel@tonic-gate (sp->sch_name = strdup(name)) == NULL) { 117*0Sstevel@tonic-gate free(sp); 118*0Sstevel@tonic-gate return (NULL); 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gate sp->sch_next = sch_list; 122*0Sstevel@tonic-gate sp->sch_dlp = NULL; 123*0Sstevel@tonic-gate sp->sch_err = 0; 124*0Sstevel@tonic-gate sp->sch_ops = _fmd_scheme_default_ops; 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate sch_list = sp; 127*0Sstevel@tonic-gate return (sp); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate static int 131*0Sstevel@tonic-gate fmd_scheme_rtld_init(fmd_scheme_t *sp) 132*0Sstevel@tonic-gate { 133*0Sstevel@tonic-gate const fmd_scheme_opd_t *opd; 134*0Sstevel@tonic-gate void *p; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate for (opd = _fmd_scheme_ops; opd->opd_name != NULL; opd++) { 137*0Sstevel@tonic-gate if ((p = dlsym(sp->sch_dlp, opd->opd_name)) != NULL) 138*0Sstevel@tonic-gate *(void **)((uintptr_t)&sp->sch_ops + opd->opd_off) = p; 139*0Sstevel@tonic-gate } 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate return (sp->sch_ops.sop_init()); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate static fmd_scheme_t * 145*0Sstevel@tonic-gate fmd_scheme_lookup(const char *dir, const char *name) 146*0Sstevel@tonic-gate { 147*0Sstevel@tonic-gate fmd_scheme_t *sp; 148*0Sstevel@tonic-gate char path[PATH_MAX]; 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate for (sp = sch_list; sp != NULL; sp = sp->sch_next) { 151*0Sstevel@tonic-gate if (strcmp(name, sp->sch_name) == 0) 152*0Sstevel@tonic-gate return (sp); 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate 155*0Sstevel@tonic-gate if ((sp = fmd_scheme_create(name)) == NULL) 156*0Sstevel@tonic-gate return (NULL); /* errno is set for us */ 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s%s/%s.so", 159*0Sstevel@tonic-gate g_root ? g_root : "", dir, name); 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (access(path, F_OK) != 0) { 162*0Sstevel@tonic-gate sp->sch_err = errno; 163*0Sstevel@tonic-gate return (sp); 164*0Sstevel@tonic-gate } 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate if ((sp->sch_dlp = dlopen(path, RTLD_LOCAL | RTLD_NOW)) == NULL) { 167*0Sstevel@tonic-gate sp->sch_err = ELIBACC; 168*0Sstevel@tonic-gate return (sp); 169*0Sstevel@tonic-gate } 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate if (fmd_scheme_rtld_init(sp) != 0) { 172*0Sstevel@tonic-gate sp->sch_err = errno; 173*0Sstevel@tonic-gate (void) dlclose(sp->sch_dlp); 174*0Sstevel@tonic-gate sp->sch_dlp = NULL; 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate return (sp); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate char * 181*0Sstevel@tonic-gate fmdump_nvl2str(nvlist_t *nvl) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate fmd_scheme_t *sp; 184*0Sstevel@tonic-gate char c, *name, *s = NULL; 185*0Sstevel@tonic-gate ssize_t len; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate if (nvlist_lookup_string(nvl, FM_FMRI_SCHEME, &name) != 0) { 188*0Sstevel@tonic-gate fmdump_warn("fmri does not contain required '%s' nvpair\n", 189*0Sstevel@tonic-gate FM_FMRI_SCHEME); 190*0Sstevel@tonic-gate return (NULL); 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate if ((sp = fmd_scheme_lookup("/usr/lib/fm/fmd/schemes", name)) == NULL || 194*0Sstevel@tonic-gate sp->sch_dlp == NULL || sp->sch_err != 0) { 195*0Sstevel@tonic-gate const char *msg = 196*0Sstevel@tonic-gate sp->sch_err == ELIBACC ? dlerror() : strerror(sp->sch_err); 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate fmdump_warn("cannot init '%s' scheme library to " 199*0Sstevel@tonic-gate "format fmri: %s\n", name, msg ? msg : "unknown error"); 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gate return (NULL); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate if ((len = sp->sch_ops.sop_nvl2str(nvl, &c, sizeof (c))) == -1 || 205*0Sstevel@tonic-gate (s = malloc(len + 1)) == NULL || 206*0Sstevel@tonic-gate sp->sch_ops.sop_nvl2str(nvl, s, len + 1) == -1) { 207*0Sstevel@tonic-gate fmdump_warn("cannot format fmri using scheme '%s'", name); 208*0Sstevel@tonic-gate free(s); 209*0Sstevel@tonic-gate return (NULL); 210*0Sstevel@tonic-gate } 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate return (s); 213*0Sstevel@tonic-gate } 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate void * 217*0Sstevel@tonic-gate fmd_fmri_alloc(size_t size) 218*0Sstevel@tonic-gate { 219*0Sstevel@tonic-gate return (malloc(size)); 220*0Sstevel@tonic-gate } 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate void * 223*0Sstevel@tonic-gate fmd_fmri_zalloc(size_t size) 224*0Sstevel@tonic-gate { 225*0Sstevel@tonic-gate void *data; 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate if ((data = malloc(size)) != NULL) 228*0Sstevel@tonic-gate bzero(data, size); 229*0Sstevel@tonic-gate 230*0Sstevel@tonic-gate return (data); 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate /*ARGSUSED*/ 234*0Sstevel@tonic-gate void 235*0Sstevel@tonic-gate fmd_fmri_free(void *data, size_t size) 236*0Sstevel@tonic-gate { 237*0Sstevel@tonic-gate free(data); 238*0Sstevel@tonic-gate } 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate int 241*0Sstevel@tonic-gate fmd_fmri_error(int err) 242*0Sstevel@tonic-gate { 243*0Sstevel@tonic-gate errno = err; 244*0Sstevel@tonic-gate return (-1); 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate 247*0Sstevel@tonic-gate char * 248*0Sstevel@tonic-gate fmd_fmri_strescape(const char *s) 249*0Sstevel@tonic-gate { 250*0Sstevel@tonic-gate return (strdup(s)); 251*0Sstevel@tonic-gate } 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate char * 254*0Sstevel@tonic-gate fmd_fmri_strdup(const char *s) 255*0Sstevel@tonic-gate { 256*0Sstevel@tonic-gate return (strdup(s)); 257*0Sstevel@tonic-gate } 258*0Sstevel@tonic-gate 259*0Sstevel@tonic-gate void 260*0Sstevel@tonic-gate fmd_fmri_strfree(char *s) 261*0Sstevel@tonic-gate { 262*0Sstevel@tonic-gate free(s); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate const char * 266*0Sstevel@tonic-gate fmd_fmri_get_rootdir(void) 267*0Sstevel@tonic-gate { 268*0Sstevel@tonic-gate return (g_root ? g_root : ""); 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate const char * 272*0Sstevel@tonic-gate fmd_fmri_get_platform(void) 273*0Sstevel@tonic-gate { 274*0Sstevel@tonic-gate static char platform[MAXNAMELEN]; 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate if (platform[0] == '\0') 277*0Sstevel@tonic-gate (void) sysinfo(SI_PLATFORM, platform, sizeof (platform)); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate return (platform); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate uint64_t 283*0Sstevel@tonic-gate fmd_fmri_get_drgen(void) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate return (0); 286*0Sstevel@tonic-gate } 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate int 289*0Sstevel@tonic-gate fmd_fmri_set_errno(int err) 290*0Sstevel@tonic-gate { 291*0Sstevel@tonic-gate errno = err; 292*0Sstevel@tonic-gate return (-1); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate void 296*0Sstevel@tonic-gate fmd_fmri_warn(const char *format, ...) 297*0Sstevel@tonic-gate { 298*0Sstevel@tonic-gate va_list ap; 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gate va_start(ap, format); 301*0Sstevel@tonic-gate fmdump_vwarn(format, ap); 302*0Sstevel@tonic-gate va_end(ap); 303*0Sstevel@tonic-gate } 304