1*70025d76Sjohnny /* 2*70025d76Sjohnny * CDDL HEADER START 3*70025d76Sjohnny * 4*70025d76Sjohnny * The contents of this file are subject to the terms of the 5*70025d76Sjohnny * Common Development and Distribution License, Version 1.0 only 6*70025d76Sjohnny * (the "License"). You may not use this file except in compliance 7*70025d76Sjohnny * with the License. 8*70025d76Sjohnny * 9*70025d76Sjohnny * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*70025d76Sjohnny * or http://www.opensolaris.org/os/licensing. 11*70025d76Sjohnny * See the License for the specific language governing permissions 12*70025d76Sjohnny * and limitations under the License. 13*70025d76Sjohnny * 14*70025d76Sjohnny * When distributing Covered Code, include this CDDL HEADER in each 15*70025d76Sjohnny * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*70025d76Sjohnny * If applicable, add the following below this CDDL HEADER, with the 17*70025d76Sjohnny * fields enclosed by brackets "[]" replaced with your own identifying 18*70025d76Sjohnny * information: Portions Copyright [yyyy] [name of copyright owner] 19*70025d76Sjohnny * 20*70025d76Sjohnny * CDDL HEADER END 21*70025d76Sjohnny */ 22*70025d76Sjohnny /* 23*70025d76Sjohnny * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*70025d76Sjohnny * Use is subject to license terms. 25*70025d76Sjohnny */ 26*70025d76Sjohnny 27*70025d76Sjohnny #pragma ident "%Z%%M% %I% %E% SMI" 28*70025d76Sjohnny 29*70025d76Sjohnny #include <stdio.h> 30*70025d76Sjohnny #include <stdlib.h> 31*70025d76Sjohnny #include <unistd.h> 32*70025d76Sjohnny #include <strings.h> 33*70025d76Sjohnny #include <string.h> 34*70025d76Sjohnny #include <errno.h> 35*70025d76Sjohnny #include <sys/param.h> 36*70025d76Sjohnny #include <sys/systeminfo.h> 37*70025d76Sjohnny #include <sys/sysevent/eventdefs.h> 38*70025d76Sjohnny #include <sys/sysevent/dr.h> 39*70025d76Sjohnny #include <syslog.h> 40*70025d76Sjohnny #include <libnvpair.h> 41*70025d76Sjohnny #include <stdarg.h> 42*70025d76Sjohnny #include <assert.h> 43*70025d76Sjohnny #include <sys/stat.h> 44*70025d76Sjohnny #include <dlfcn.h> 45*70025d76Sjohnny #include <signal.h> 46*70025d76Sjohnny #include <pcidr.h> 47*70025d76Sjohnny 48*70025d76Sjohnny /* 49*70025d76Sjohnny * pcidr takes in arguments of the form specified in the help() routine 50*70025d76Sjohnny * including a set of name=value pairs, then looks up a plugin (shared object) 51*70025d76Sjohnny * based on <plugin_paths> and however find_plugin() operates. The entry 52*70025d76Sjohnny * point of the plugin is <PCIDR_PLUGIN_SYM> and has the type 53*70025d76Sjohnny * <pcidr_plugin_t>. Plugins must use the <PCIDR_PLUGIN_PROTO> macro to 54*70025d76Sjohnny * define their entry point. 55*70025d76Sjohnny * 56*70025d76Sjohnny * The name=value arguments are intended to be used as a mechanism to pass 57*70025d76Sjohnny * arbitrary sysevent attributes using the macro expansion capability provided 58*70025d76Sjohnny * by the syseventd SLM processing sysevent.conf files (i.e. specifying 59*70025d76Sjohnny * "$attribute" arguments for the handler in a .conf file entry). They are 60*70025d76Sjohnny * converted into an nvlist_t (see libnvpair(3LIB)) by converting the values 61*70025d76Sjohnny * of recognized names into appropriate types using pcidr_name2type() and 62*70025d76Sjohnny * leaving all others as string types. Because pcidr is used as a sysevent.conf 63*70025d76Sjohnny * handler, the format of the value string for non-string attributes in each 64*70025d76Sjohnny * name=value argument must match that used by the syseventd macro capability 65*70025d76Sjohnny * 66*70025d76Sjohnny * The plugin will be passed this (nvlist_t *) along with a (pcidr_opt_t *) arg 67*70025d76Sjohnny * for other options. While pcidr does some basic checking of arguments, it 68*70025d76Sjohnny * leaves any name=value check (after conversion) up to each plugin. Note 69*70025d76Sjohnny * that pcidr_check_attrs() is used by the default plugin and can be used by 70*70025d76Sjohnny * any plugin that support the same or a superset of its attributes. If the 71*70025d76Sjohnny * default plugin supports additional publishers, it should be updated in 72*70025d76Sjohnny * pcidr_check_attrs(). 73*70025d76Sjohnny * 74*70025d76Sjohnny * See help() for an example of how pcidr can be specified in a sysevent.conf 75*70025d76Sjohnny * file. 76*70025d76Sjohnny */ 77*70025d76Sjohnny 78*70025d76Sjohnny /* 79*70025d76Sjohnny * plugin search paths (searched in order specified); 80*70025d76Sjohnny * macros begin MACRO_BEGTOK and end with MACRO_ENDTOK; 81*70025d76Sjohnny * 82*70025d76Sjohnny * be sure to update parse_path() and its support functions whenever macros 83*70025d76Sjohnny * are updated e.g. si_name2cmd(), as well as substring tokens (prefix or 84*70025d76Sjohnny * suffix) used to recognize different types of macros e.g. SI_MACRO 85*70025d76Sjohnny * 86*70025d76Sjohnny * NOTE: if plugin search algorithm is changed starting with find_plugin(), 87*70025d76Sjohnny * please update documentation here. 88*70025d76Sjohnny * 89*70025d76Sjohnny * macros: 90*70025d76Sjohnny * SI_PLATFORM = cmd of same name in sysinfo(2) 91*70025d76Sjohnny * SI_MACHINE = cmd of same name in sysinfo(2) 92*70025d76Sjohnny */ 93*70025d76Sjohnny #define MACRO_BEGTOK "${" 94*70025d76Sjohnny #define MACRO_ENDTOK "}" 95*70025d76Sjohnny #define SI_MACRO "SI_" 96*70025d76Sjohnny 97*70025d76Sjohnny static char *plugin_paths[] = { 98*70025d76Sjohnny "/usr/platform/${SI_PLATFORM}/lib/pci/" PCIDR_PLUGIN_NAME, 99*70025d76Sjohnny "/usr/platform/${SI_MACHINE}/lib/pci/" PCIDR_PLUGIN_NAME, 100*70025d76Sjohnny "/usr/lib/pci/" PCIDR_PLUGIN_NAME, 101*70025d76Sjohnny }; 102*70025d76Sjohnny static int plugin_paths_len = sizeof (plugin_paths) / sizeof (plugin_paths[0]); 103*70025d76Sjohnny 104*70025d76Sjohnny 105*70025d76Sjohnny static nvlist_t *nvlistp = NULL; /* attribute list */ 106*70025d76Sjohnny 107*70025d76Sjohnny typedef struct { 108*70025d76Sjohnny char *name; 109*70025d76Sjohnny char *beg; 110*70025d76Sjohnny char *end; 111*70025d76Sjohnny } macro_list_t; 112*70025d76Sjohnny static macro_list_t *parse_macros(char *const, int *); 113*70025d76Sjohnny static void free_macros(macro_list_t *, int); 114*70025d76Sjohnny static char *parse_path(char *const); 115*70025d76Sjohnny static void help(); 116*70025d76Sjohnny static void exiter(); 117*70025d76Sjohnny static char *find_plugin(nvlist_t *); 118*70025d76Sjohnny static int do_plugin(char *, nvlist_t *, pcidr_opt_t *); 119*70025d76Sjohnny static int nvadd(nvlist_t *, char *, char *, data_type_t); 120*70025d76Sjohnny static nvlist_t *parse_argv_attr(int, char **, int *); 121*70025d76Sjohnny static int si_name2cmd(char *); 122*70025d76Sjohnny 123*70025d76Sjohnny 124*70025d76Sjohnny static void 125*70025d76Sjohnny help() 126*70025d76Sjohnny { 127*70025d76Sjohnny /* since the handler is not public, we don't expose its usage normally */ 128*70025d76Sjohnny #ifdef DEBUG 129*70025d76Sjohnny (void) printf( 130*70025d76Sjohnny "%s [-h] [-s] [-v <level>] [-l <log_file>] <attributes>\n" 131*70025d76Sjohnny " -h help\n" 132*70025d76Sjohnny "\n" 133*70025d76Sjohnny " -s turn OFF messages to the syslog (use syslog by default)\n" 134*70025d76Sjohnny "\n" 135*70025d76Sjohnny " -v verbose mode; <level> range is %d..%d; default is %d\n" 136*70025d76Sjohnny "\n" 137*70025d76Sjohnny " -l also log messages to <log_file> (in addition to using\n" 138*70025d76Sjohnny " the syslog if that option is not disabled);\n" 139*70025d76Sjohnny " if <log_file> is '-', stdout is used\n" 140*70025d76Sjohnny "\n" 141*70025d76Sjohnny " <attributes>\n" 142*70025d76Sjohnny " whitespace seperated strings of <name>=<value> pairs\n" 143*70025d76Sjohnny "\n" 144*70025d76Sjohnny "Example 1 (command line):\n" 145*70025d76Sjohnny " %s -s -v%d -l- \\\n" 146*70025d76Sjohnny " class=EC_dr subclass=ESC_dr_req publisher=pcie_pci \\\n" 147*70025d76Sjohnny " dr_request_type=dr_request_outgoing_resource \\\n" 148*70025d76Sjohnny " dr_ap_id=/devices/foo/bar\n" 149*70025d76Sjohnny "\n" 150*70025d76Sjohnny "Example 2 (/etc/sysevent/config/SUNW,sysevent.conf entry):\n" 151*70025d76Sjohnny " EC_dr ESC_dr_req SUNW pcie_pci - - - %s -v%d -l/tmp/log \\\n" 152*70025d76Sjohnny " class=$class subclass=$subclass publisher=$publisher \\\n" 153*70025d76Sjohnny " dr_request_type=$dr_request_type\\\n" 154*70025d76Sjohnny " dr_ap_id=$dr_ap_id\n" 155*70025d76Sjohnny "\n", 156*70025d76Sjohnny prg, MIN_DLVL, MAX_DLVL, dlvl, 157*70025d76Sjohnny prg, MAX_DLVL, /* Example 1 */ 158*70025d76Sjohnny prg, DWARN); /* Example 2 */ 159*70025d76Sjohnny #endif 160*70025d76Sjohnny } 161*70025d76Sjohnny 162*70025d76Sjohnny 163*70025d76Sjohnny /* 164*70025d76Sjohnny * will convert <value> from a string to the type indicated by <type> 165*70025d76Sjohnny * and will add it with <name> to nvlist_t <listp>; function returns the same 166*70025d76Sjohnny * value as nvlist_add_*() 167*70025d76Sjohnny */ 168*70025d76Sjohnny static int 169*70025d76Sjohnny nvadd(nvlist_t *listp, char *name, char *value, data_type_t type) 170*70025d76Sjohnny { 171*70025d76Sjohnny char *fn = "nvadd"; 172*70025d76Sjohnny int rv = 0; 173*70025d76Sjohnny 174*70025d76Sjohnny switch (type) { 175*70025d76Sjohnny case DATA_TYPE_STRING: 176*70025d76Sjohnny rv = nvlist_add_string(listp, name, value); 177*70025d76Sjohnny if (rv != 0) { 178*70025d76Sjohnny dprint(DDEBUG, "%s: nvlist_add_string() failed: " 179*70025d76Sjohnny "name = %s, value = %s, rv = %d\n", 180*70025d76Sjohnny fn, name, value, rv); 181*70025d76Sjohnny } 182*70025d76Sjohnny break; 183*70025d76Sjohnny /* 184*70025d76Sjohnny * Conversion must support whatever string format syseventd uses for 185*70025d76Sjohnny * its .conf macros; in addition, minimum types supported must match 186*70025d76Sjohnny * those for pcidr_name2type() 187*70025d76Sjohnny */ 188*70025d76Sjohnny default: 189*70025d76Sjohnny dprint(DDEBUG, "%s: unsupported type: name = %s, value = %s, " 190*70025d76Sjohnny "type = 0x%x\n", fn, name, value, (int)type); 191*70025d76Sjohnny rv = EINVAL; 192*70025d76Sjohnny } 193*70025d76Sjohnny 194*70025d76Sjohnny return (rv); 195*70025d76Sjohnny } 196*70025d76Sjohnny 197*70025d76Sjohnny 198*70025d76Sjohnny /* 199*70025d76Sjohnny * argc: length of argv 200*70025d76Sjohnny * argv: each string starting from index <argip> has the format "name=value" 201*70025d76Sjohnny * argip: starting index in <argv>; also used to return ending index 202*70025d76Sjohnny * 203*70025d76Sjohnny * return: allocated nvlist on success, exits otherwise 204*70025d76Sjohnny * 205*70025d76Sjohnny * recognized names will have predetermined types, while all others will have 206*70025d76Sjohnny * values of type string 207*70025d76Sjohnny */ 208*70025d76Sjohnny static nvlist_t * 209*70025d76Sjohnny parse_argv_attr(int argc, char **argv, int *argip) 210*70025d76Sjohnny { 211*70025d76Sjohnny char *fn = "parse_argv_attr"; 212*70025d76Sjohnny int rv, i; 213*70025d76Sjohnny nvlist_t *attrlistp = NULL; 214*70025d76Sjohnny char *eqp, *name, *value; 215*70025d76Sjohnny data_type_t type; 216*70025d76Sjohnny 217*70025d76Sjohnny assert(*argip < argc); 218*70025d76Sjohnny 219*70025d76Sjohnny rv = nvlist_alloc(&attrlistp, NV_UNIQUE_NAME_TYPE, 0); 220*70025d76Sjohnny if (rv != 0) { 221*70025d76Sjohnny dprint(DDEBUG, "%s: nvlist_alloc() failed: rv = %d\n", fn, rv); 222*70025d76Sjohnny goto ERR; 223*70025d76Sjohnny } 224*70025d76Sjohnny 225*70025d76Sjohnny for (i = *argip; i < argc; i++) { 226*70025d76Sjohnny eqp = strchr(argv[i], '='); 227*70025d76Sjohnny if (eqp == NULL) 228*70025d76Sjohnny goto ERR_ARG; 229*70025d76Sjohnny *eqp = '\0'; 230*70025d76Sjohnny name = argv[i]; 231*70025d76Sjohnny value = eqp; 232*70025d76Sjohnny value++; 233*70025d76Sjohnny if (*name == '\0' || *value == '\0') 234*70025d76Sjohnny goto ERR_ARG; 235*70025d76Sjohnny 236*70025d76Sjohnny if (pcidr_name2type(name, &type) != 0) 237*70025d76Sjohnny type = DATA_TYPE_STRING; 238*70025d76Sjohnny 239*70025d76Sjohnny rv = nvadd(attrlistp, name, value, type); 240*70025d76Sjohnny if (rv != 0) { 241*70025d76Sjohnny dprint(DDEBUG, "%s: nvadd() failed: attribute \"%s\", " 242*70025d76Sjohnny "value = %s, type = %d, rv = %d\n", 243*70025d76Sjohnny fn, name, value, (int)type, rv); 244*70025d76Sjohnny goto ERR; 245*70025d76Sjohnny } 246*70025d76Sjohnny *eqp = '='; 247*70025d76Sjohnny } 248*70025d76Sjohnny 249*70025d76Sjohnny *argip = i; 250*70025d76Sjohnny return (attrlistp); 251*70025d76Sjohnny 252*70025d76Sjohnny /*NOTREACHED*/ 253*70025d76Sjohnny ERR_ARG: 254*70025d76Sjohnny if (eqp != NULL) 255*70025d76Sjohnny *eqp = '='; 256*70025d76Sjohnny dprint(DDEBUG, "%s: bad attribute argv[%d]: \"%s\"\n", fn, i, argv[i]); 257*70025d76Sjohnny ERR: 258*70025d76Sjohnny if (attrlistp != NULL) 259*70025d76Sjohnny nvlist_free(attrlistp); 260*70025d76Sjohnny return (NULL); 261*70025d76Sjohnny } 262*70025d76Sjohnny 263*70025d76Sjohnny 264*70025d76Sjohnny static struct { 265*70025d76Sjohnny int cmd; 266*70025d76Sjohnny char *name; 267*70025d76Sjohnny } si_cmd_nametab[] = { 268*70025d76Sjohnny SI_PLATFORM, "SI_PLATFORM", 269*70025d76Sjohnny SI_MACHINE, "SI_MACHINE", 270*70025d76Sjohnny }; 271*70025d76Sjohnny static int si_cmd_nametab_len = 272*70025d76Sjohnny sizeof (si_cmd_nametab) / sizeof (si_cmd_nametab[0]); 273*70025d76Sjohnny 274*70025d76Sjohnny static int 275*70025d76Sjohnny si_name2cmd(char *name) 276*70025d76Sjohnny { 277*70025d76Sjohnny int i; 278*70025d76Sjohnny 279*70025d76Sjohnny for (i = 0; i < si_cmd_nametab_len; i++) { 280*70025d76Sjohnny if (strcmp(name, si_cmd_nametab[i].name) == 0) 281*70025d76Sjohnny return (si_cmd_nametab[i].cmd); 282*70025d76Sjohnny } 283*70025d76Sjohnny return (-1); 284*70025d76Sjohnny } 285*70025d76Sjohnny 286*70025d76Sjohnny 287*70025d76Sjohnny /* 288*70025d76Sjohnny * finds occurences of substrings surrounded (delimited) by MACRO_BEGTOK and 289*70025d76Sjohnny * MACRO_ENDTOK in <str>; 290*70025d76Sjohnny * returns an allocated array of macro_list_t whose length is 291*70025d76Sjohnny * returned through <lenp>; array entries will be in order of the occurrence; 292*70025d76Sjohnny * else returns NULL if none are found 293*70025d76Sjohnny * 294*70025d76Sjohnny * macro_list_t members: 295*70025d76Sjohnny * char *name = allocated string containing name without macro delimiters 296*70025d76Sjohnny * char *beg = location in <str> at _first char_ of MACRO_BEGTOK 297*70025d76Sjohnny * char *end = location in <str> at _last char_ of MACRO_ENDTOK 298*70025d76Sjohnny */ 299*70025d76Sjohnny static macro_list_t * 300*70025d76Sjohnny parse_macros(char *const str, int *lenp) 301*70025d76Sjohnny { 302*70025d76Sjohnny char *beg, *end; 303*70025d76Sjohnny macro_list_t *lp; 304*70025d76Sjohnny size_t size; 305*70025d76Sjohnny int i, begtok_len, endtok_len; 306*70025d76Sjohnny 307*70025d76Sjohnny begtok_len = strlen(MACRO_BEGTOK); 308*70025d76Sjohnny endtok_len = strlen(MACRO_ENDTOK); 309*70025d76Sjohnny 310*70025d76Sjohnny /* count all occurrences */ 311*70025d76Sjohnny for (beg = str, i = 0; beg != NULL; i++) { 312*70025d76Sjohnny beg = strstr(beg, MACRO_BEGTOK); 313*70025d76Sjohnny if (beg == NULL) 314*70025d76Sjohnny break; 315*70025d76Sjohnny end = strstr(beg + begtok_len, MACRO_ENDTOK); 316*70025d76Sjohnny if (end == NULL) 317*70025d76Sjohnny break; 318*70025d76Sjohnny beg = end + endtok_len; 319*70025d76Sjohnny } 320*70025d76Sjohnny if (i <= 0) 321*70025d76Sjohnny return (NULL); 322*70025d76Sjohnny 323*70025d76Sjohnny *lenp = i; 324*70025d76Sjohnny lp = pcidr_malloc(sizeof (macro_list_t) * i); 325*70025d76Sjohnny 326*70025d76Sjohnny for (beg = str, i = 0; i < *lenp; i++) { 327*70025d76Sjohnny beg = strstr(beg, MACRO_BEGTOK); 328*70025d76Sjohnny assert(beg != NULL); 329*70025d76Sjohnny end = strstr(beg + begtok_len, MACRO_ENDTOK); 330*70025d76Sjohnny assert(end != NULL); 331*70025d76Sjohnny 332*70025d76Sjohnny size = (end - (beg + begtok_len)) + 1; 333*70025d76Sjohnny lp[i].name = pcidr_malloc(size * sizeof (char)); 334*70025d76Sjohnny (void) strlcpy(lp[i].name, beg + begtok_len, size); 335*70025d76Sjohnny 336*70025d76Sjohnny lp[i].beg = beg; 337*70025d76Sjohnny lp[i].end = (end + endtok_len) - 1; 338*70025d76Sjohnny 339*70025d76Sjohnny beg = end + endtok_len; 340*70025d76Sjohnny } 341*70025d76Sjohnny 342*70025d76Sjohnny return (lp); 343*70025d76Sjohnny } 344*70025d76Sjohnny 345*70025d76Sjohnny static void 346*70025d76Sjohnny free_macros(macro_list_t *lp, int len) 347*70025d76Sjohnny { 348*70025d76Sjohnny int i; 349*70025d76Sjohnny 350*70025d76Sjohnny for (i = 0; i < len; i++) 351*70025d76Sjohnny free(lp[i].name); 352*70025d76Sjohnny free(lp); 353*70025d76Sjohnny } 354*70025d76Sjohnny 355*70025d76Sjohnny 356*70025d76Sjohnny /* 357*70025d76Sjohnny * evaluates any macros in <opath> and returns allocated string on success; 358*70025d76Sjohnny * else NULL 359*70025d76Sjohnny */ 360*70025d76Sjohnny static char * 361*70025d76Sjohnny parse_path(char *const opath) 362*70025d76Sjohnny { 363*70025d76Sjohnny char *fn = "parse_path"; 364*70025d76Sjohnny char buf[MAXPATHLEN + 1]; 365*70025d76Sjohnny int bufsize = sizeof (buf) / sizeof (buf[0]); 366*70025d76Sjohnny char sibuf[257]; 367*70025d76Sjohnny int sibufsize = sizeof (sibuf) / sizeof (sibuf[0]); 368*70025d76Sjohnny macro_list_t *lp; 369*70025d76Sjohnny char *path, *pathp, *pathend; 370*70025d76Sjohnny int rv, i, lplen, si_cmd, pathlen, okmacro, si_macro_len; 371*70025d76Sjohnny size_t sz; 372*70025d76Sjohnny 373*70025d76Sjohnny /* 374*70025d76Sjohnny * make a copy so we can modify it for easier parsing; 375*70025d76Sjohnny * lp members will refer to the copy 376*70025d76Sjohnny */ 377*70025d76Sjohnny path = strdup(opath); 378*70025d76Sjohnny lp = parse_macros(path, &lplen); 379*70025d76Sjohnny if (lp == NULL) 380*70025d76Sjohnny return (path); 381*70025d76Sjohnny 382*70025d76Sjohnny rv = 0; 383*70025d76Sjohnny si_macro_len = strlen(SI_MACRO); 384*70025d76Sjohnny pathlen = strlen(path); 385*70025d76Sjohnny pathend = &path[pathlen - 1]; 386*70025d76Sjohnny pathp = path; 387*70025d76Sjohnny buf[0] = '\0'; 388*70025d76Sjohnny for (i = 0; i < lplen; i++) { 389*70025d76Sjohnny lp[i].beg[0] = '\0'; 390*70025d76Sjohnny sz = strlcat(buf, pathp, bufsize); 391*70025d76Sjohnny assert(sz < bufsize); 392*70025d76Sjohnny 393*70025d76Sjohnny okmacro = 0; 394*70025d76Sjohnny if (strncmp(lp[i].name, SI_MACRO, si_macro_len) == 0) { 395*70025d76Sjohnny si_cmd = si_name2cmd(lp[i].name); 396*70025d76Sjohnny assert(si_cmd >= 0); 397*70025d76Sjohnny 398*70025d76Sjohnny rv = sysinfo(si_cmd, sibuf, sibufsize); 399*70025d76Sjohnny if (rv < 0) { 400*70025d76Sjohnny dprint(DDEBUG, "%s: sysinfo cmd %d failed: " 401*70025d76Sjohnny "errno = %d\n", fn, si_cmd, errno); 402*70025d76Sjohnny goto OUT; 403*70025d76Sjohnny } 404*70025d76Sjohnny 405*70025d76Sjohnny sz = strlcat(buf, sibuf, bufsize); 406*70025d76Sjohnny assert(sz < bufsize); 407*70025d76Sjohnny okmacro = 1; 408*70025d76Sjohnny } 409*70025d76Sjohnny /* check for unrecognized macros */ 410*70025d76Sjohnny assert(okmacro); 411*70025d76Sjohnny pathp = lp[i].end + 1; 412*70025d76Sjohnny } 413*70025d76Sjohnny 414*70025d76Sjohnny rv = 0; 415*70025d76Sjohnny if (pathp < pathend) { 416*70025d76Sjohnny sz = strlcat(buf, pathp, bufsize); 417*70025d76Sjohnny assert(sz < bufsize); 418*70025d76Sjohnny } 419*70025d76Sjohnny OUT: 420*70025d76Sjohnny free_macros(lp, lplen); 421*70025d76Sjohnny free(path); 422*70025d76Sjohnny if (rv == 0) 423*70025d76Sjohnny return (strdup(buf)); 424*70025d76Sjohnny return (NULL); 425*70025d76Sjohnny } 426*70025d76Sjohnny 427*70025d76Sjohnny 428*70025d76Sjohnny /* 429*70025d76Sjohnny * returns allocated string containing plugin path which caller must free; 430*70025d76Sjohnny * else NULL; <attrlistp> is for future use if attributes can be used to 431*70025d76Sjohnny * determin plugin 432*70025d76Sjohnny */ 433*70025d76Sjohnny /*ARGSUSED*/ 434*70025d76Sjohnny static char * 435*70025d76Sjohnny find_plugin(nvlist_t *attrlistp) 436*70025d76Sjohnny { 437*70025d76Sjohnny char *fn = "find_plugin"; 438*70025d76Sjohnny char *path = NULL; 439*70025d76Sjohnny int i, rv; 440*70025d76Sjohnny struct stat statbuf; 441*70025d76Sjohnny 442*70025d76Sjohnny for (i = 0; i < plugin_paths_len; i++) { 443*70025d76Sjohnny path = parse_path(plugin_paths[i]); 444*70025d76Sjohnny if (path == NULL) { 445*70025d76Sjohnny dprint(DDEBUG, "%s: error parsing path %s\n", fn, 446*70025d76Sjohnny path); 447*70025d76Sjohnny return (NULL); 448*70025d76Sjohnny } 449*70025d76Sjohnny 450*70025d76Sjohnny rv = stat(path, &statbuf); 451*70025d76Sjohnny if (rv < 0) 452*70025d76Sjohnny dprint(DDEBUG, "%s: stat on %s failed: " 453*70025d76Sjohnny "errno = %d\n", fn, path, errno); 454*70025d76Sjohnny else if ((statbuf.st_mode & S_IFMT) != S_IFREG) 455*70025d76Sjohnny dprint(DDEBUG, "%s: %s is not a regular " 456*70025d76Sjohnny "file\n", fn, path); 457*70025d76Sjohnny else 458*70025d76Sjohnny return (path); 459*70025d76Sjohnny 460*70025d76Sjohnny free(path); 461*70025d76Sjohnny } 462*70025d76Sjohnny return (NULL); 463*70025d76Sjohnny } 464*70025d76Sjohnny 465*70025d76Sjohnny 466*70025d76Sjohnny /* 467*70025d76Sjohnny * load plugin specified by <path> and pass the proceeding arguments 468*70025d76Sjohnny * to the plugin interface; returns 0 on success (likewise for 469*70025d76Sjohnny * the plugin function) 470*70025d76Sjohnny */ 471*70025d76Sjohnny static int 472*70025d76Sjohnny do_plugin(char *path, nvlist_t *attrlistp, pcidr_opt_t *optp) 473*70025d76Sjohnny { 474*70025d76Sjohnny char *fn = "do_plugin"; 475*70025d76Sjohnny int rv; 476*70025d76Sjohnny void *dlh; 477*70025d76Sjohnny sigset_t set, oset; 478*70025d76Sjohnny pcidr_plugin_t fp; 479*70025d76Sjohnny 480*70025d76Sjohnny dlh = dlopen(path, RTLD_LAZY | RTLD_GLOBAL); 481*70025d76Sjohnny if (dlh == NULL) { 482*70025d76Sjohnny dprint(DDEBUG, "%s: dlopen() failed: %s\n", fn, dlerror()); 483*70025d76Sjohnny rv = EINVAL; 484*70025d76Sjohnny goto OUT; 485*70025d76Sjohnny } 486*70025d76Sjohnny 487*70025d76Sjohnny if (sigfillset(&set) != 0) { 488*70025d76Sjohnny dprint(DDEBUG, "%s: sigfillset() failed: errno = %d\n", fn, 489*70025d76Sjohnny errno); 490*70025d76Sjohnny rv = errno; 491*70025d76Sjohnny goto OUT; 492*70025d76Sjohnny } 493*70025d76Sjohnny if (sigprocmask(SIG_BLOCK, &set, &oset) != 0) { 494*70025d76Sjohnny dprint(DDEBUG, "%s: blocking signals with sigprocmask() " 495*70025d76Sjohnny "failed: errno = %d\n", fn, errno); 496*70025d76Sjohnny rv = errno; 497*70025d76Sjohnny goto OUT; 498*70025d76Sjohnny } 499*70025d76Sjohnny 500*70025d76Sjohnny fp = (pcidr_plugin_t)dlsym(dlh, PCIDR_PLUGIN_SYMSTR); 501*70025d76Sjohnny if (fp == NULL) { 502*70025d76Sjohnny dprint(DDEBUG, "%s: dlsym() failed: %s\n", fn, dlerror()); 503*70025d76Sjohnny rv = EINVAL; 504*70025d76Sjohnny goto OUT; 505*70025d76Sjohnny } 506*70025d76Sjohnny rv = fp(attrlistp, optp); 507*70025d76Sjohnny if (rv != 0) 508*70025d76Sjohnny dprint(DDEBUG, "%s: %s() failed: rv = %d\n", fn, 509*70025d76Sjohnny PCIDR_PLUGIN_SYMSTR, rv); 510*70025d76Sjohnny 511*70025d76Sjohnny if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) { 512*70025d76Sjohnny dprint(DDEBUG, "%s: unblocking signals with sigprocmask() " 513*70025d76Sjohnny "failed: errno = %d\n", fn, errno); 514*70025d76Sjohnny rv = errno; 515*70025d76Sjohnny goto OUT; 516*70025d76Sjohnny } 517*70025d76Sjohnny OUT: 518*70025d76Sjohnny if (dlh != NULL) 519*70025d76Sjohnny (void) dlclose(dlh); 520*70025d76Sjohnny return (rv); 521*70025d76Sjohnny } 522*70025d76Sjohnny 523*70025d76Sjohnny 524*70025d76Sjohnny static void 525*70025d76Sjohnny exiter() 526*70025d76Sjohnny { 527*70025d76Sjohnny extern FILE *dfp; 528*70025d76Sjohnny 529*70025d76Sjohnny if (nvlistp != NULL) 530*70025d76Sjohnny nvlist_free(nvlistp); 531*70025d76Sjohnny if (dfp != NULL) 532*70025d76Sjohnny (void) fclose(dfp); 533*70025d76Sjohnny #ifdef DEBUG 534*70025d76Sjohnny closelog(); 535*70025d76Sjohnny #endif 536*70025d76Sjohnny } 537*70025d76Sjohnny 538*70025d76Sjohnny 539*70025d76Sjohnny int 540*70025d76Sjohnny main(int argc, char **argv) 541*70025d76Sjohnny { 542*70025d76Sjohnny int rv, argi; 543*70025d76Sjohnny char *dfile = NULL, *plugin_path = NULL; 544*70025d76Sjohnny struct stat statbuf; 545*70025d76Sjohnny pcidr_opt_t plugin_opt; 546*70025d76Sjohnny char *optstr = NULL; 547*70025d76Sjohnny 548*70025d76Sjohnny extern char *optarg; 549*70025d76Sjohnny extern int optind, optopt; 550*70025d76Sjohnny int c; 551*70025d76Sjohnny 552*70025d76Sjohnny /*CONSTCOND*/ 553*70025d76Sjohnny assert(MIN_DLVL == 0); 554*70025d76Sjohnny /*CONSTCOND*/ 555*70025d76Sjohnny assert(MIN_DLVL == DNONE); 556*70025d76Sjohnny assert(MAX_DLVL == dpritab_len - 1); 557*70025d76Sjohnny 558*70025d76Sjohnny (void) atexit(exiter); 559*70025d76Sjohnny prg = argv[0]; 560*70025d76Sjohnny dfp = NULL; 561*70025d76Sjohnny 562*70025d76Sjohnny #ifdef DEBUG 563*70025d76Sjohnny openlog(prg, LOG_PID | LOG_CONS, LOG_DAEMON); 564*70025d76Sjohnny dlvl = DWARN; 565*70025d76Sjohnny dsys = 1; 566*70025d76Sjohnny optstr = "hsv:l:"; 567*70025d76Sjohnny #else 568*70025d76Sjohnny dlvl = DNONE; 569*70025d76Sjohnny dsys = 0; 570*70025d76Sjohnny optstr = "sv:l:"; 571*70025d76Sjohnny #endif 572*70025d76Sjohnny 573*70025d76Sjohnny while ((c = getopt(argc, argv, optstr)) != -1) { 574*70025d76Sjohnny switch (c) { 575*70025d76Sjohnny case 'h': 576*70025d76Sjohnny help(); 577*70025d76Sjohnny exit(0); 578*70025d76Sjohnny break; 579*70025d76Sjohnny case 's': 580*70025d76Sjohnny dsys = 0; 581*70025d76Sjohnny break; 582*70025d76Sjohnny case 'v': 583*70025d76Sjohnny dlvl = atoi(optarg); 584*70025d76Sjohnny break; 585*70025d76Sjohnny case 'l': 586*70025d76Sjohnny dfile = optarg; 587*70025d76Sjohnny break; 588*70025d76Sjohnny default: 589*70025d76Sjohnny dprint(DWARN, "bad option: %c\n", optopt); 590*70025d76Sjohnny return (EINVAL); 591*70025d76Sjohnny } 592*70025d76Sjohnny } 593*70025d76Sjohnny 594*70025d76Sjohnny /* 595*70025d76Sjohnny * [ -l ] do file option first so we can still get msgs if -s is used 596*70025d76Sjohnny */ 597*70025d76Sjohnny if (dfile != NULL) { 598*70025d76Sjohnny if (strcmp(dfile, "-") == 0) { 599*70025d76Sjohnny /* ignore if stdout is not open/valid */ 600*70025d76Sjohnny dfp = NULL; 601*70025d76Sjohnny if (stdout != NULL && 602*70025d76Sjohnny fstat(fileno(stdout), &statbuf) == 0) 603*70025d76Sjohnny dfp = stdout; 604*70025d76Sjohnny } else { 605*70025d76Sjohnny dfp = fopen(dfile, "a"); 606*70025d76Sjohnny if (dfp == NULL) { 607*70025d76Sjohnny dprint(DWARN, "cannot open %s: %s\n", 608*70025d76Sjohnny dfile, strerror(errno)); 609*70025d76Sjohnny return (EINVAL); 610*70025d76Sjohnny } 611*70025d76Sjohnny } 612*70025d76Sjohnny } 613*70025d76Sjohnny 614*70025d76Sjohnny /* [ -v ] */ 615*70025d76Sjohnny if (dlvl < MIN_DLVL || dlvl > MAX_DLVL) { 616*70025d76Sjohnny dprint(DWARN, "bad arg for -v: %d\n", dlvl); 617*70025d76Sjohnny return (EINVAL); 618*70025d76Sjohnny } 619*70025d76Sjohnny 620*70025d76Sjohnny argi = optind; 621*70025d76Sjohnny if (argi >= argc) { 622*70025d76Sjohnny dprint(DWARN, "missing attribute arguments\n"); 623*70025d76Sjohnny return (EINVAL); 624*70025d76Sjohnny } 625*70025d76Sjohnny 626*70025d76Sjohnny nvlistp = parse_argv_attr(argc, argv, &argi); 627*70025d76Sjohnny if (nvlistp == NULL) { 628*70025d76Sjohnny dprint(DWARN, "attribute parsing error\n"); 629*70025d76Sjohnny return (EINVAL); 630*70025d76Sjohnny } 631*70025d76Sjohnny 632*70025d76Sjohnny (void) memset(&plugin_opt, 0, sizeof (plugin_opt)); 633*70025d76Sjohnny plugin_opt.logopt.dlvl = dlvl; 634*70025d76Sjohnny plugin_opt.logopt.prg = prg; 635*70025d76Sjohnny plugin_opt.logopt.dfp = dfp; 636*70025d76Sjohnny plugin_opt.logopt.dsys = dsys; 637*70025d76Sjohnny 638*70025d76Sjohnny dprint(DINFO, "=== sysevent attributes ========================\n"); 639*70025d76Sjohnny pcidr_print_attrlist(DINFO, nvlistp, NULL); 640*70025d76Sjohnny dprint(DINFO, "================================================\n"); 641*70025d76Sjohnny 642*70025d76Sjohnny plugin_path = find_plugin(nvlistp); 643*70025d76Sjohnny if (plugin_path == NULL) { 644*70025d76Sjohnny dprint(DWARN, "cannot find plugin\n"); 645*70025d76Sjohnny return (EINVAL); 646*70025d76Sjohnny } 647*70025d76Sjohnny dprint(DINFO, "using plugin: %s\n\n", plugin_path); 648*70025d76Sjohnny 649*70025d76Sjohnny rv = do_plugin(plugin_path, nvlistp, &plugin_opt); 650*70025d76Sjohnny if (rv != 0) { 651*70025d76Sjohnny dprint(DWARN, "plugin %s failed\n", plugin_path); 652*70025d76Sjohnny } 653*70025d76Sjohnny if (plugin_path != NULL) 654*70025d76Sjohnny free(plugin_path); 655*70025d76Sjohnny return (rv); 656*70025d76Sjohnny } 657