/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_H #define _INJ_H /* * FMA Error injector */ #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * The injector allows for the declaration, definition, and injection of four * types of things - Events, FMRIs, Authorities, and lists. The first three * are essentially lists with extra membership requirements (FMRIs, for * example, must include a member called `scheme'). So while each has a * different function within the FMA framework, we can use a single struct to * store all three. The inj_itemtype_t enum is used to describe which of the * four types is being represented by a given object. */ typedef enum inj_itemtype { ITEMTYPE_EVENT, ITEMTYPE_FMRI, ITEMTYPE_AUTH, ITEMTYPE_LIST } inj_itemtype_t; #define ITEMTYPE_NITEMS 4 /* * The member name-value pairs of Events, FMRIs, and Authorities are typed. */ typedef enum inj_memtype { MEMTYPE_UNKNOWN, MEMTYPE_INT8, MEMTYPE_INT16, MEMTYPE_INT32, MEMTYPE_INT64, MEMTYPE_UINT8, MEMTYPE_UINT16, MEMTYPE_UINT32, MEMTYPE_UINT64, MEMTYPE_BOOL, MEMTYPE_STRING, MEMTYPE_ENUM, MEMTYPE_EVENT, MEMTYPE_FMRI, MEMTYPE_AUTH, MEMTYPE_LIST } inj_memtype_t; /* * Declarations * * Each declared item, be it an event, an fmri, or an authority, consists of * an inj_decl_t and a string of inj_declmem_t's, one of the latter for each * declared member. */ #define DECL_F_AUTOENA 0x1 /* ENA member to be auto-generated for event */ typedef struct inj_decl { inj_list_t decl_members; /* List of declared members */ inj_hash_t decl_memhash; /* Hash of said members */ const char *decl_name; /* Name of declared item */ inj_itemtype_t decl_type; /* Type of declared item */ uint_t decl_lineno; /* Line # of first member declared */ uint_t decl_flags; /* DECL_F_* */ } inj_decl_t; #define DECLMEM_F_ARRAY 0x1 /* This member is an array of the given type */ typedef struct inj_declmem { inj_list_t dlm_memlist; /* List of declared members */ const char *dlm_name; /* Name of this member */ inj_memtype_t dlm_type; /* Type of this member */ uint_t dlm_flags; /* DECLMEM_F_* */ uint_t dlm_arrdim; /* If arr flag set, dim of array */ union { inj_hash_t *_dlm_enumvals; /* If enum, hash of poss. values */ inj_decl_t *_dlm_decl; /* If evt, etc., ptr to decl for same */ } _dlm_u; } inj_declmem_t; #define dlm_enumvals _dlm_u._dlm_enumvals #define dlm_decl _dlm_u._dlm_decl /* * Definitions * * Each defined item consists of an inj_defn_t and a string of inj_defnmem_t's, * one of the latter for each defined member. The inj_defn_t also contains a * pointer to the corresponding declaration, thus allowing for correctness * checking. */ typedef struct inj_defn { inj_list_t defn_members; /* List of defined members */ const char *defn_name; /* Name of this definition */ inj_decl_t *defn_decl; /* Ptr to decl this defn instantiates */ uint_t defn_lineno; /* Line # of first member defined */ nvlist_t *defn_nvl; /* Built from validated members */ } inj_defn_t; /* * Embodiment of the information that we know about a given defined member at * the time of definition. These values are assigned before the individual * definition members are paired with their corresponding declarations, so we * don't know whether a given IDENT is, for example, an enum or an fmri * reference. Without these values, we wouldn't be able to distinguish between * a quoted string and an identifier, for example, and thus would have a harder * time with syntactic validation. */ typedef enum inj_defnmemtype { DEFNMEM_IMM, DEFNMEM_IDENT, DEFNMEM_QSTRING, DEFNMEM_EVENT, DEFNMEM_FMRI, DEFNMEM_AUTH, DEFNMEM_ARRAY, DEFNMEM_LIST } inj_defnmemtype_t; typedef struct inj_defnmem { inj_list_t dfm_memlist; /* List of defined members */ inj_defnmemtype_t dfm_type; /* Type of this member, from parser */ uint_t dfm_lineno; /* Last line of this member's defn */ union { const char *_dfm_str; /* String value of member */ inj_list_t _dfm_list; /* Enum, evt, auth, arr, list vals */ } _dfm_u; } inj_defnmem_t; #define dfm_str _dfm_u._dfm_str #define dfm_list _dfm_u._dfm_list /* * Operations performed by the injector (aside from declarations and * definitions) */ /* events and priorities list for the randomize command */ typedef struct inj_randelem { struct inj_randelem *re_next; inj_defn_t *re_event; uint_t re_prob; } inj_randelem_t; /* * Operations themselves are structured as a tree of inj_cmd_t's. Each one has * a command type and type-specific command data. The "program" is run via * iteration through the tree, with the injector performing the operation * requested by a given node. */ typedef enum inj_cmd_type { CMD_SEND_EVENT, CMD_SLEEP, CMD_REPEAT, CMD_RANDOM } inj_cmd_type_t; typedef struct inj_cmd { inj_list_t cmd_list; /* List of commands */ inj_cmd_type_t cmd_type; /* Type of this command */ union { inj_defn_t *_cmd_event; /* If send_event, evt to send */ inj_randelem_t **_cmd_rand; /* List of evts & probs */ struct inj_cmd *_cmd_subcmd; /* If repeat, cmd to be rpt'd */ } _cmd_u; uint_t cmd_num; /* If repeat, repeat count */ } inj_cmd_t; #define cmd_event _cmd_u._cmd_event #define cmd_rand _cmd_u._cmd_rand #define cmd_subcmd _cmd_u._cmd_subcmd /* * We support retargetable event-delivery mechanisms. Each method implements * a copy of the following ops vector, thus allowing us to switch mechanisms * simply by switching the structure. */ typedef struct inj_mode_ops { void *(*mo_open)(const char *); /* Init mechanism */ void (*mo_send)(void *, nvlist_t *); /* Send a single nvlist */ void (*mo_close)(void *); /* Shut down mechanism */ } inj_mode_ops_t; extern int verbose; extern int quiet; extern inj_list_t *inj_logfile_read(fmd_log_t *); extern inj_list_t *inj_program_read(const char *); extern void inj_program_run(inj_list_t *, const inj_mode_ops_t *, void *); extern void *inj_alloc(size_t); extern void *inj_zalloc(size_t); extern void inj_free(void *, size_t); #ifdef __cplusplus } #endif #endif /* _INJ_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * The "program" executed by the injector consists of a tree of commands. * Routines in this file build and execute said command tree. */ #include #include #include #include #include #include /* * Command tree construction */ static inj_list_t inj_cmds; void inj_cmds_add(inj_cmd_t *cmd) { inj_list_append(&inj_cmds, cmd); } inj_list_t * inj_cmds_get(void) { return (&inj_cmds); } inj_randelem_t * inj_rand_create(inj_defn_t *ev, uint_t prob) { inj_randelem_t *re = inj_zalloc(sizeof (inj_randelem_t)); re->re_event = ev; re->re_prob = prob; return (re); } inj_randelem_t * inj_rand_add(inj_randelem_t *list, inj_randelem_t *new) { new->re_next = list; return (new); } inj_cmd_t * inj_cmd_rand(inj_randelem_t *rlist) { inj_randelem_t *r; inj_cmd_t *cmd; uint_t prob, tmpprob; int nelems, i; prob = 0; for (i = 0, r = rlist; r != NULL; r = r->re_next, i++) prob += r->re_prob; if (prob != 100) { yyerror("probabilities don't sum to 100\n"); return (NULL); } nelems = i; cmd = inj_zalloc(sizeof (inj_cmd_t)); cmd->cmd_type = CMD_RANDOM; cmd->cmd_num = nelems; cmd->cmd_rand = inj_alloc(sizeof (inj_randelem_t *) * nelems); prob = 0; for (r = rlist, i = 0; i < nelems; i++, r = r->re_next) { tmpprob = r->re_prob; r->re_prob = prob; prob += tmpprob; cmd->cmd_rand[i] = r; } return (cmd); } inj_cmd_t * inj_cmd_repeat(inj_cmd_t *repcmd, uint_t num) { inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); cmd->cmd_type = CMD_REPEAT; cmd->cmd_num = num; cmd->cmd_subcmd = repcmd; return (cmd); } inj_cmd_t * inj_cmd_send(inj_defn_t *ev) { inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); cmd->cmd_type = CMD_SEND_EVENT; cmd->cmd_event = ev; return (cmd); } inj_cmd_t * inj_cmd_sleep(uint_t secs) { inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); cmd->cmd_type = CMD_SLEEP; cmd->cmd_num = secs; return (cmd); } inj_cmd_t * inj_cmd_addhrt(hrtime_t delta) { const char *class = "resource.fm.fmd.clock.addhrtime"; inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); inj_defn_t *ev = inj_zalloc(sizeof (inj_defn_t)); ev->defn_name = class; ev->defn_lineno = yylineno; if ((errno = nvlist_alloc(&ev->defn_nvl, NV_UNIQUE_NAME, 0)) != 0) die("failed to allocate nvl for %s event", class); if ((errno = nvlist_add_string(ev->defn_nvl, FM_CLASS, class)) != 0 || (errno = nvlist_add_uint8(ev->defn_nvl, FM_VERSION, 1)) != 0 || (errno = nvlist_add_int64(ev->defn_nvl, "delta", delta)) != 0) die("failed to build nvl for %s event", class); cmd->cmd_type = CMD_SEND_EVENT; cmd->cmd_event = ev; return (cmd); } inj_cmd_t * inj_cmd_endhrt(void) { return (inj_cmd_addhrt(-1LL)); /* clock underflow causes end of time */ } static uint64_t inj_ena(void) { return (((gethrtime() & ENA_FMT1_TIME_MASK) << ENA_FMT1_TIME_SHFT) | (FM_ENA_FMT1 & ENA_FORMAT_MASK)); } static void cmd_run_send(const inj_mode_ops_t *mode, void *hdl, inj_defn_t *ev) { if (!quiet) { (void) printf("sending event %s ... ", ev->defn_name); (void) fflush(stdout); } if ((errno = nvlist_add_boolean_value(ev->defn_nvl, "__injected", 1)) != 0) warn("failed to add __injected to %s", ev->defn_name); if (ev->defn_decl && (ev->defn_decl->decl_flags & DECL_F_AUTOENA) && (errno = nvlist_add_uint64(ev->defn_nvl, "ena", inj_ena())) != 0) warn("failed to add ena to %s", ev->defn_name); if (verbose) { nvlist_print(stdout, ev->defn_nvl); (void) printf("\n"); } mode->mo_send(hdl, ev->defn_nvl); if (!quiet) (void) printf("done\n"); } static void cmd_run_random(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd) { uint_t num = lrand48() % 100; int i; for (i = 1; i < cmd->cmd_num; i++) { if (cmd->cmd_rand[i]->re_prob > num) break; } cmd_run_send(mode, hdl, cmd->cmd_rand[i - 1]->re_event); } static void cmd_run(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd) { switch (cmd->cmd_type) { case CMD_SEND_EVENT: cmd_run_send(mode, hdl, cmd->cmd_event); break; case CMD_SLEEP: (void) printf("sleeping for %d sec%s ... ", cmd->cmd_num, cmd->cmd_num > 1 ? "s" : ""); (void) fflush(stdout); (void) sleep(cmd->cmd_num); (void) printf("done\n"); break; case CMD_RANDOM: cmd_run_random(mode, hdl, cmd); break; default: warn("ignoring unknown command type: %d\n", cmd->cmd_type); } } void inj_program_run(inj_list_t *prog, const inj_mode_ops_t *mode, void *mode_arg) { void *hdl = mode->mo_open(mode_arg); inj_cmd_t *cmd; int i; for (cmd = inj_list_next(prog); cmd != NULL; cmd = inj_list_next(cmd)) { if (cmd->cmd_type == CMD_REPEAT) { for (i = 1; i <= cmd->cmd_num; i++) { if (verbose) { (void) printf("(repeat %d of %d)\n", i, cmd->cmd_num); } cmd_run(mode, hdl, cmd->cmd_subcmd); } } else cmd_run(mode, hdl, cmd); } mode->mo_close(hdl); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Events, FMRIs and authorities must be declared before they can be used. * Routines in this file, driven by the parser, create the data structures * associated with the declarations. */ #include #include #include #include #include #include #include static inj_hash_t inj_decls[ITEMTYPE_NITEMS]; static int inj_decls_initialized; static inj_hash_t * item2hash(inj_itemtype_t item) { int i; assert(item >= 0 && item < sizeof (inj_decls) / sizeof (inj_hash_t)); if (!inj_decls_initialized) { for (i = 0; i < sizeof (inj_decls) / sizeof (inj_hash_t); i++) inj_strhash_create(&inj_decls[i]); inj_decls_initialized = 1; } return (&inj_decls[item]); } inj_decl_t * inj_decl_lookup(const char *name, inj_itemtype_t type) { inj_hash_t *hash = item2hash(type); inj_var_t *v; if ((v = inj_strhash_lookup(hash, name)) == NULL) return (NULL); return (inj_hash_get_cookie(v)); } void inj_decl_mem_destroy(inj_declmem_t *dlm) { inj_strfree(dlm->dlm_name); if (dlm->dlm_type == MEMTYPE_ENUM) inj_strhash_destroy(dlm->dlm_enumvals); } inj_declmem_t * inj_decl_mem_create(const char *name, inj_memtype_t type) { inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t)); dlm->dlm_name = name; dlm->dlm_type = type; return (dlm); } /* An embedded event, authority, or FMRI */ inj_declmem_t * inj_decl_mem_create_defined(const char *name, const char *declnm, inj_itemtype_t type) { inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t)); dlm->dlm_name = name; dlm->dlm_type = inj_item2mem(type); if ((dlm->dlm_decl = inj_decl_lookup(declnm, type)) == NULL) { yyerror("unknown %s %s", inj_item2str(type), declnm); return (NULL); } return (dlm); } inj_declmem_t * inj_decl_mem_create_enum(const char *name, inj_hash_t *vals) { inj_declmem_t *dlm = inj_zalloc(sizeof (inj_declmem_t)); dlm->dlm_name = name; dlm->dlm_type = MEMTYPE_ENUM; dlm->dlm_enumvals = vals; return (dlm); } /* Turn a previously-declared member into an array */ void inj_decl_mem_make_array(inj_declmem_t *dlm, uint_t dim) { dlm->dlm_flags |= DECLMEM_F_ARRAY; dlm->dlm_arrdim = dim; } void inj_decl_destroy(inj_decl_t *decl) { inj_declmem_t *m, *n; inj_strfree(decl->decl_name); inj_strhash_destroy(&decl->decl_memhash); for (m = inj_list_next(&decl->decl_members); m != NULL; m = n) { n = inj_list_next(m); inj_decl_mem_destroy(m); } inj_free(decl, sizeof (inj_declmem_t)); } inj_decl_t * inj_decl_create(inj_declmem_t *dlm) { inj_decl_t *decl = inj_zalloc(sizeof (inj_decl_t)); decl->decl_lineno = yylineno; inj_strhash_create(&decl->decl_memhash); inj_list_append(&decl->decl_members, dlm); (void) inj_strhash_insert(&decl->decl_memhash, dlm->dlm_name, (uintptr_t)dlm); return (decl); } void inj_decl_addmem(inj_decl_t *decl, inj_declmem_t *dlm) { inj_var_t *v; if ((v = inj_strhash_lookup(&decl->decl_memhash, dlm->dlm_name)) != NULL) { inj_decl_t *other = inj_hash_get_cookie(v); yyerror("duplicate member name %s (other on line %d)\n", dlm->dlm_name, other->decl_lineno); inj_decl_destroy(decl); return; } inj_list_append(&decl->decl_members, dlm); (void) inj_strhash_insert(&decl->decl_memhash, dlm->dlm_name, (uintptr_t)dlm); } /* * The various declaration types - events, FMRIs, and authorities - each have * their own semantic validation requirements. */ /* No user-defined class member. If ena isn't present, we'll generate it */ static int inj_decl_validate_event(inj_decl_t *decl) { if (inj_strhash_lookup(&decl->decl_memhash, "class") != NULL) { yyerror("class may not be explicitly declared\n"); return (0); } if (inj_strhash_lookup(&decl->decl_memhash, "ena") == NULL) decl->decl_flags |= DECL_F_AUTOENA; return (1); } /* FMRIs must have a string scheme member */ static int inj_decl_validate_fmri(inj_decl_t *decl) { inj_declmem_t *dlm; inj_var_t *v; if ((v = inj_strhash_lookup(&decl->decl_memhash, "scheme")) == NULL) { yyerror("fmri declared without scheme member\n"); return (0); } dlm = inj_hash_get_cookie(v); if (dlm->dlm_type != MEMTYPE_STRING) { yyerror("scheme member must be a string\n"); return (0); } return (1); } /*ARGSUSED*/ static int inj_decl_validate_nop(inj_decl_t *decl) { return (1); } void inj_decl_finish(inj_decl_t *decl, const char *name, inj_itemtype_t type) { static int (*const validators[])(inj_decl_t *) = { inj_decl_validate_event, inj_decl_validate_fmri, inj_decl_validate_nop, /* no validation for auth */ inj_decl_validate_nop /* no validation for lists */ }; inj_hash_t *hash = item2hash(type); inj_var_t *v; decl->decl_name = name; decl->decl_type = type; if (!validators[type](decl)) { inj_decl_destroy(decl); return; } if ((v = inj_strhash_lookup(hash, name)) != NULL) { inj_decl_t *other = inj_hash_get_cookie(v); yyerror("duplicate %s name %s (other on line %d)\n", inj_item2str(type), name, other->decl_lineno); inj_decl_destroy(decl); return; } (void) inj_strhash_insert(hash, name, (uintptr_t)decl); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * After having been declared, events, FMRIs and authorities must be defined * (instantiated) before they can be used as the subjects of commands. */ #include #include #include #include #include #include #include #include #include static inj_hash_t inj_defns[3]; static int inj_defns_initialized; /* Intrinsics (signed and unsigned integer integer constants) */ typedef struct intr { uchar_t ei_signed; uchar_t ei_width; } intr_t; static inj_hash_t * item2hash(inj_itemtype_t item) { int i; assert(item >= 0 && item < sizeof (inj_defns) / sizeof (inj_hash_t)); if (!inj_defns_initialized) { for (i = 0; i < sizeof (inj_defns) / sizeof (inj_hash_t); i++) inj_strhash_create(&inj_defns[i]); inj_defns_initialized = 1; } return (&inj_defns[item]); } inj_defn_t * inj_defn_lookup(const char *name, inj_memtype_t type) { inj_hash_t *hash = item2hash(inj_mem2item(type)); inj_var_t *v; if ((v = inj_strhash_lookup(hash, name)) == NULL) return (NULL); return (inj_hash_get_cookie(v)); } static void inj_defn_destroy_memlist(inj_defnmem_t *m) { inj_defnmem_t *n; for (/* */; m != NULL; m = n) { n = inj_list_next(m); switch (m->dfm_type) { case DEFNMEM_ARRAY: case DEFNMEM_LIST: inj_defn_destroy_memlist(inj_list_next(&m->dfm_list)); break; default: inj_strfree(m->dfm_str); } } } void inj_defn_destroy(inj_defn_t *defn) { if (defn->defn_name != NULL) inj_strfree(defn->defn_name); nvlist_free(defn->defn_nvl); inj_defn_destroy_memlist(inj_list_next(&defn->defn_members)); } static inj_defnmem_t * inj_defn_mem_create_common(inj_defnmemtype_t type) { inj_defnmem_t *dfm = inj_zalloc(sizeof (inj_defnmem_t)); dfm->dfm_type = type; dfm->dfm_lineno = yylineno; return (dfm); } inj_defnmem_t * inj_defn_mem_create(const char *str, inj_defnmemtype_t type) { inj_defnmem_t *dfm = inj_defn_mem_create_common(type); dfm->dfm_str = str; return (dfm); } inj_defnmem_t * inj_defn_mem_create_list(inj_defn_t *list, inj_defnmemtype_t type) { inj_defnmem_t *dfm = inj_defn_mem_create_common(type); dfm->dfm_list = list->defn_members; inj_free(list, sizeof (inj_defn_t)); return (dfm); } inj_defn_t * inj_defn_create(inj_defnmem_t *dfm) { inj_defn_t *defn = inj_zalloc(sizeof (inj_defn_t)); defn->defn_lineno = yylineno; inj_list_append(&defn->defn_members, dfm); return (defn); } void inj_defn_addmem(inj_defn_t *defn, inj_defnmem_t *dfm) { inj_list_append(&defn->defn_members, dfm); } /* * Validate the dimensions of an array. If the declared array size was zero, * accept (and return) whatever the definition used. If fewer cells were * defined than were declared, return the declared size - the calling code will * fill the remaining cells with zeros. The definition of more than the * declared number of cells triggers an error. We print and error message in * this case and return the declared number. This will allow processing to * continue. The act of emitting the error will guarantee that we never * pass from parsing to program execution. */ static size_t array_dim_check(inj_declmem_t *dlm, inj_defnmem_t *dfm) { inj_list_t *l; size_t dfnelems; for (dfnelems = 0, l = inj_list_next(&dfm->dfm_list); l != NULL; l = inj_list_next(l), dfnelems++); if (dlm->dlm_arrdim != 0 && dlm->dlm_arrdim != dfnelems) { yyerror(" %d: defined array has %d elements, expected %d\n", dfm->dfm_lineno, dfnelems, dlm->dlm_arrdim); dfnelems = dlm->dlm_arrdim; } return (MAX(dfnelems, dlm->dlm_arrdim)); } /* * The inj_defn_memcmp_* routines serve two purposes. First, they compare a * given defined member with the corresponding declared member, signalling an * error if the two are incompatible. * * Assuming that validation succeeds, an entry is added to the passed nvlist * for the defined member. */ /* Used to ease signed and unsigned integer validation */ static const intr_t inj_intrinsics[] = { { 0, 0 }, /* MEMTYPE_UNKNOWN */ { 1, 8 }, { 1, 16 }, { 1, 32 }, { 1, 64 }, { 0, 8 }, { 0, 16 }, { 0, 32 }, { 0, 64 } }; static int inj_defn_memcmp_signed(const intr_t *intr, inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { longlong_t val; if (dfm->dfm_type != DEFNMEM_IMM && dfm->dfm_type != DEFNMEM_IDENT) return (inj_set_errno(EINVAL)); if (inj_strtoll(dfm->dfm_str, intr->ei_width, &val) < 0) return (-1); /* errno is set for us */ switch (dlm->dlm_type) { case MEMTYPE_INT8: errno = nvlist_add_int8(nvl, (char *)dlm->dlm_name, (int8_t)val); break; case MEMTYPE_INT16: errno = nvlist_add_int16(nvl, (char *)dlm->dlm_name, (int16_t)val); break; case MEMTYPE_INT32: errno = nvlist_add_int32(nvl, (char *)dlm->dlm_name, (int32_t)val); break; case MEMTYPE_INT64: errno = nvlist_add_int64(nvl, (char *)dlm->dlm_name, (int64_t)val); } if (errno != 0) die("failed to add member %s\n", dlm->dlm_name); return (0); } static int inj_defn_memcmp_unsigned(const intr_t *intr, inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { u_longlong_t val; if (dfm->dfm_type != DEFNMEM_IMM && dfm->dfm_type != DEFNMEM_IDENT) return (inj_set_errno(EINVAL)); if (inj_strtoull(dfm->dfm_str, intr->ei_width, &val) < 0) return (-1); /* errno is set for us */ switch (dlm->dlm_type) { case MEMTYPE_UINT8: errno = nvlist_add_uint8(nvl, (char *)dlm->dlm_name, (uint8_t)val); break; case MEMTYPE_UINT16: errno = nvlist_add_uint16(nvl, (char *)dlm->dlm_name, (uint16_t)val); break; case MEMTYPE_UINT32: errno = nvlist_add_uint32(nvl, (char *)dlm->dlm_name, (uint32_t)val); break; case MEMTYPE_UINT64: errno = nvlist_add_uint64(nvl, (char *)dlm->dlm_name, (uint64_t)val); } if (errno != 0) die("failed to add member %s\n", dlm->dlm_name); return (0); } /* Validate an array of (un)signed integers. */ static int inj_defn_memcmp_intr_array(const intr_t *cont, inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { typedef int (*adder_t)(); static const adder_t signed_adders[] = { NULL, nvlist_add_int8_array, nvlist_add_int16_array, NULL, nvlist_add_int32_array, NULL, NULL, NULL, nvlist_add_int64_array }; static const adder_t unsigned_adders[] = { NULL, nvlist_add_uint8_array, nvlist_add_uint16_array, NULL, nvlist_add_uint32_array, NULL, NULL, NULL, nvlist_add_uint64_array }; union { char *a; int8_t *a8; uint8_t *au8; int16_t *a16; uint16_t *au16; int32_t *a32; uint32_t *au32; int64_t *a64; uint64_t *au64; } a; int (*adder)(nvlist_t *, const char *, char *, uint_t); size_t nelems; inj_defnmem_t *elem; char *arrbase, *arr; size_t arrsz; int err = 0; int i; if (dfm->dfm_type != DEFNMEM_ARRAY) return (inj_set_errno(EINVAL)); /* * Each nvlist array adder wants an array of its own type as input, * which is reasonable, but it complicates our general implementation. * We fight back with casting magic. */ nelems = array_dim_check(dlm, dfm); arrsz = (nelems + 1) * (cont->ei_width / NBBY); arrbase = inj_zalloc(arrsz); a.a = arr = (char *)P2ROUNDUP((uintptr_t)arrbase, cont->ei_width / NBBY); adder = (cont->ei_signed ? signed_adders : unsigned_adders)[cont->ei_width / NBBY]; assert(adder != NULL); for (i = 1, elem = inj_list_next(&dfm->dfm_list); elem != NULL; elem = inj_list_next(elem), i++) { if (elem->dfm_type != DEFNMEM_IMM && elem->dfm_type != DEFNMEM_IDENT) { yyerror(" %d: array cell %d is invalid\n", dfm->dfm_lineno, i); err++; continue; } if (cont->ei_signed) { longlong_t val; if (inj_strtoll(elem->dfm_str, cont->ei_width, &val) < 0) { yyerror(" %d: array cell %d %s\n", dfm->dfm_lineno, i, (errno == ERANGE ? "out of range for type" : "invalid")); err++; continue; } switch (cont->ei_width) { case 8: *a.a8++ = (int8_t)val; break; case 16: *a.a16++ = (int16_t)val; break; case 32: *a.a32++ = (int32_t)val; break; default: *a.a64++ = (int64_t)val; } } else { u_longlong_t val; if (inj_strtoull(elem->dfm_str, cont->ei_width, &val) < 0) { yyerror(" %d: array cell %d %s\n", dfm->dfm_lineno, i, (errno == ERANGE ? "out of range for type" : "invalid")); err++; continue; } switch (cont->ei_width) { case 8: *a.au8++ = (uint8_t)val; break; case 16: *a.au16++ = (uint16_t)val; break; case 32: *a.au32++ = (uint32_t)val; break; default: *a.au64++ = (uint64_t)val; } } } if (err == 0 && (errno = adder(nvl, dlm->dlm_name, arr, nelems)) != 0) die("failed to add array member %s", dlm->dlm_name); inj_free(arrbase, arrsz); if (err != 0) return (inj_set_errno(EINVAL)); return (0); } static int bool2val(const char *str, boolean_t *valp) { if (strcasecmp(str, "true") == 0) *valp = 1; else if (strcasecmp(str, "false") == 0) *valp = 0; else return (-1); return (0); } static int inj_defn_memcmp_bool(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { boolean_t val; if (dfm->dfm_type != DEFNMEM_IDENT) return (inj_set_errno(EINVAL)); if (bool2val(dfm->dfm_str, &val) < 0) return (inj_set_errno(EINVAL)); if ((errno = nvlist_add_boolean_value(nvl, (char *)dlm->dlm_name, val)) != 0) die("failed to add boolean member %s", dlm->dlm_name); return (0); } static int inj_defn_memcmp_bool_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { inj_defnmem_t *elem; boolean_t *arr; size_t nelems, arrsz; int err = 0; int i; if (dfm->dfm_type != DEFNMEM_ARRAY) return (inj_set_errno(EINVAL)); nelems = array_dim_check(dlm, dfm); arrsz = nelems * sizeof (boolean_t); arr = inj_zalloc(arrsz); for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL; elem = inj_list_next(elem), i++) { if (elem->dfm_type != DEFNMEM_IDENT) { yyerror(" %d: array cell %d is invalid\n", dfm->dfm_lineno, i + 1); err++; continue; } if (bool2val(elem->dfm_str, &arr[i]) < 0) return (inj_set_errno(EINVAL)); } if (err == 0 && (errno = nvlist_add_boolean_array(nvl, (char *)dlm->dlm_name, arr, nelems)) != 0) die("failed to add boolean array member %s", dlm->dlm_name); inj_free(arr, arrsz); return (0); } /* Used for both strings and enums */ static int inj_defn_memcmp_strenum(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { inj_defnmemtype_t defnmemtype = (dlm->dlm_type == MEMTYPE_ENUM ? DEFNMEM_IDENT : DEFNMEM_QSTRING); const char *strenum = (dlm->dlm_type == MEMTYPE_ENUM ? "enum" : "string"); if (dfm->dfm_type != defnmemtype) return (inj_set_errno(EINVAL)); if ((errno = nvlist_add_string(nvl, (char *)dlm->dlm_name, (char *)dfm->dfm_str)) != 0) die("failed to add %s member %s", strenum, dlm->dlm_name); return (0); } static int inj_defn_memcmp_strenum_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { inj_defnmemtype_t defnmemtype = (dlm->dlm_type == MEMTYPE_ENUM ? DEFNMEM_IDENT : DEFNMEM_QSTRING); const char *strenum = (dlm->dlm_type == MEMTYPE_ENUM ? "enum" : "string"); inj_defnmem_t *elem; size_t nelems, arrsz; const char **arr; int err = 0; int i; if (dfm->dfm_type != DEFNMEM_ARRAY) return (inj_set_errno(EINVAL)); nelems = array_dim_check(dlm, dfm); arrsz = nelems * sizeof (char *); arr = inj_zalloc(arrsz); for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL; elem = inj_list_next(elem), i++) { if (elem->dfm_type != defnmemtype) { yyerror(" %d: array cell %d is invalid\n", dfm->dfm_lineno, i + 1); err++; continue; } if (dlm->dlm_type == MEMTYPE_ENUM && inj_strhash_lookup(dlm->dlm_enumvals, elem->dfm_str) == NULL) { yyerror(" %d: invalid enum value %s\n", dfm->dfm_lineno, elem->dfm_str); err++; continue; } arr[i] = elem->dfm_str; } if (err == 0 && (errno = nvlist_add_string_array(nvl, dlm->dlm_name, (char **)arr, nelems)) != 0) die("failed to add %s array member %s", strenum, dlm->dlm_name); inj_free(arr, arrsz); return (0); } /* * Validator for embedded lists (events, fmris, authorities, lists, etc.). * There are two cases to deal with here. The user could either have provided * the name of a previously-defined list, in which case we just make a copy of * said list for insertion into ours. Alternatively, the user could simply * define a new list here. In that case, we recursively invoke the member * comparator, but against the list type for the member being defined. */ static nvlist_t *inj_defn_validate_memlist(inj_declmem_t *, inj_defnmem_t *); /* Embedded definition */ static nvlist_t * inj_defn_memcmp_sub_list(inj_declmem_t *dlm, inj_defnmem_t *dfm) { inj_declmem_t *subdlm = inj_list_next(&dlm->dlm_decl->decl_members); inj_defnmem_t *subdfm = inj_list_next(&dfm->dfm_list); return (inj_defn_validate_memlist(subdlm, subdfm)); } /* Reference to previously-defined thing */ static nvlist_t * inj_defn_memcmp_sub_defined(inj_declmem_t *dlm, inj_defnmem_t *dfm) { inj_defn_t *subdefn; nvlist_t *new; if ((subdefn = inj_defn_lookup(dfm->dfm_str, dlm->dlm_type)) == NULL) { yyerror(" %d: reference to undefined %s %s\n", dfm->dfm_lineno, inj_mem2str(dlm->dlm_type), dfm->dfm_str); (void) inj_set_errno(EINVAL); return (NULL); } if (subdefn->defn_decl != dlm->dlm_decl) { yyerror(" %d: %s %s is not a(n) %s\n", dfm->dfm_lineno, inj_mem2str(dlm->dlm_type), dfm->dfm_str, subdefn->defn_decl->decl_name); (void) inj_set_errno(EINVAL); return (NULL); } assert(subdefn->defn_nvl != NULL); if ((errno = nvlist_dup(subdefn->defn_nvl, &new, 0)) != 0) { die("failed to duplicate %s list %s", inj_item2str(subdefn->defn_decl->decl_type), dfm->dfm_str); } return (new); } static nvlist_t * inj_defn_memcmp_sub_makenvl(inj_declmem_t *dlm, inj_defnmem_t *dfm) { inj_defnmemtype_t dftype = dfm->dfm_type; inj_memtype_t dltype = dlm->dlm_type; nvlist_t *new = NULL; if (dftype == DEFNMEM_LIST) new = inj_defn_memcmp_sub_list(dlm, dfm); else if (dftype == DEFNMEM_IDENT && (dltype == MEMTYPE_EVENT || dltype == MEMTYPE_FMRI || dltype == MEMTYPE_AUTH)) new = inj_defn_memcmp_sub_defined(dlm, dfm); else (void) inj_set_errno(EINVAL); return (new); } /* A single sub-list */ static int inj_defn_memcmp_sub(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { nvlist_t *new; if ((new = inj_defn_memcmp_sub_makenvl(dlm, dfm)) == NULL) return (-1); /* errno is set for us */ if ((errno = nvlist_add_nvlist(nvl, (char *)dlm->dlm_name, new)) != 0) die("failed to add list member %s", dlm->dlm_name); return (0); } /* An array of sub-lists (for example, an array of events of a given type) */ static int inj_defn_memcmp_sub_array(inj_declmem_t *dlm, inj_defnmem_t *dfm, nvlist_t *nvl) { size_t nelems, arrsz; inj_defnmem_t *elem; nvlist_t **arr; int err = 0; int i; if (dfm->dfm_type != DEFNMEM_ARRAY) return (inj_set_errno(EINVAL)); nelems = array_dim_check(dlm, dfm); arrsz = nelems * sizeof (char *); arr = inj_zalloc(arrsz); for (i = 0, elem = inj_list_next(&dfm->dfm_list); elem != NULL; elem = inj_list_next(elem), i++) { if ((arr[i] = inj_defn_memcmp_sub_makenvl(dlm, elem)) == NULL) { yyerror(" %d: array cell %d is invalid\n", elem->dfm_lineno, i + 1); err++; continue; } } if (err == 0 && (errno = nvlist_add_nvlist_array(nvl, (char *)dlm->dlm_name, arr, nelems)) != 0) die("failed to add nvlist list member %s", dlm->dlm_name); inj_free(arr, arrsz); return (0); } /* * The declaration-definition member comparator. Designed to recursive * invocation to allow for the validation of embedded/referenced lists. */ nvlist_t * inj_defn_validate_memlist(inj_declmem_t *dlm, inj_defnmem_t *dfm) { const intr_t *intr; nvlist_t *nvl; int rc, nmem, dlnmem, dfnmem; int err = 0; if ((errno = nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) != 0) die("failed to allocate nvl for event"); for (nmem = 1; dlm != NULL && dfm != NULL; dlm = inj_list_next(dlm), dfm = inj_list_next(dfm), nmem++) { switch (dlm->dlm_type) { case MEMTYPE_INT8: case MEMTYPE_INT16: case MEMTYPE_INT32: case MEMTYPE_INT64: intr = &inj_intrinsics[dlm->dlm_type]; if (dlm->dlm_flags & DECLMEM_F_ARRAY) { rc = inj_defn_memcmp_intr_array(intr, dlm, dfm, nvl); } else { rc = inj_defn_memcmp_signed(intr, dlm, dfm, nvl); } break; case MEMTYPE_UINT8: case MEMTYPE_UINT16: case MEMTYPE_UINT32: case MEMTYPE_UINT64: intr = &inj_intrinsics[dlm->dlm_type]; if (dlm->dlm_flags & DECLMEM_F_ARRAY) { rc = inj_defn_memcmp_intr_array(intr, dlm, dfm, nvl); } else { rc = inj_defn_memcmp_unsigned(intr, dlm, dfm, nvl); } break; case MEMTYPE_BOOL: if (dlm->dlm_flags & DECLMEM_F_ARRAY) rc = inj_defn_memcmp_bool_array(dlm, dfm, nvl); else rc = inj_defn_memcmp_bool(dlm, dfm, nvl); break; case MEMTYPE_STRING: if (dlm->dlm_flags & DECLMEM_F_ARRAY) { rc = inj_defn_memcmp_strenum_array(dlm, dfm, nvl); } else rc = inj_defn_memcmp_strenum(dlm, dfm, nvl); break; case MEMTYPE_ENUM: if (dlm->dlm_flags & DECLMEM_F_ARRAY) { rc = inj_defn_memcmp_strenum_array(dlm, dfm, nvl); } else rc = inj_defn_memcmp_strenum(dlm, dfm, nvl); break; case MEMTYPE_EVENT: case MEMTYPE_FMRI: case MEMTYPE_AUTH: case MEMTYPE_LIST: if (dlm->dlm_flags & DECLMEM_F_ARRAY) rc = inj_defn_memcmp_sub_array(dlm, dfm, nvl); else rc = inj_defn_memcmp_sub(dlm, dfm, nvl); break; default: die("unknown decl member type %d on member %s\n", dlm->dlm_type, dlm->dlm_name); } if (rc < 0) { yyerror(" %d: %s for member %s\n", dfm->dfm_lineno, (errno == ERANGE ? "value out of range" : "invalid value"), dlm->dlm_name); err++; } } dlnmem = dfnmem = nmem; while (dlm != NULL) { dlm = inj_list_next(dlm); dlnmem++; } while (dfm != NULL) { dfm = inj_list_next(dfm); dfnmem++; } if (dlnmem != dfnmem) { yyerror("%d members found, expected %d", dfnmem, dlnmem); err++; } if (err > 0) { nvlist_free(nvl); return (NULL); } return (nvl); } /* * The members have all been defined. Validate the members against the * declaration, and add it to the appropriate "defined" list. */ void inj_defn_finish(inj_defn_t *defn, const char *declnm, const char *name, inj_itemtype_t type) { inj_decl_t *decl = inj_decl_lookup(declnm, type); inj_hash_t *hash = item2hash(type); inj_declmem_t *dlm; inj_defnmem_t *dfm; inj_var_t *v; defn->defn_name = name; defn->defn_decl = decl; if (decl == NULL) { yyerror("unknown %s type %s\n", inj_item2str(type), declnm); inj_defn_destroy(defn); return; } dlm = inj_list_next(&decl->decl_members); dfm = inj_list_next(&defn->defn_members); if ((defn->defn_nvl = inj_defn_validate_memlist(dlm, dfm)) == NULL) { inj_defn_destroy(defn); return; } if (type == ITEMTYPE_EVENT) { if ((errno = nvlist_add_string(defn->defn_nvl, "class", (char *)defn->defn_decl->decl_name)) != 0) die("failed to add class to %s", name); } if ((v = inj_strhash_lookup(hash, name)) != NULL) { inj_defn_t *other = inj_hash_get_cookie(v); yyerror("duplicate %s name %s (other on line %d)\n", inj_item2str(type), name, other->defn_lineno); inj_defn_destroy(defn); return; } (void) inj_strhash_insert(hash, name, (uintptr_t)defn); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Error-handling routines */ #include #include #include #include #include #include /*LINTLIBRARY*/ static const char *pname; #pragma init(getpname) const char * getpname(void) { const char *p, *q; if (pname != NULL) return (pname); if ((p = getexecname()) != NULL) q = strrchr(p, '/'); else q = NULL; if (q == NULL) pname = p; else pname = q + 1; return (pname); } void vwarn(const char *format, va_list alist) { int err = errno; if (pname != NULL) (void) fprintf(stderr, "%s: ", pname); (void) vfprintf(stderr, format, alist); if (strchr(format, '\n') == NULL) (void) fprintf(stderr, ": %s\n", strerror(err)); } /*PRINTFLIKE1*/ void warn(const char *format, ...) { va_list alist; va_start(alist, format); vwarn(format, alist); va_end(alist); } void vdie(const char *format, va_list alist) { vwarn(format, alist); exit(E_ERROR); } /*PRINTFLIKE1*/ void die(const char *format, ...) { va_list alist; va_start(alist, format); vdie(format, alist); va_end(alist); } int inj_set_errno(int err) { errno = err; return (-1); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_ERR_H #define _INJ_ERR_H #include #include #include #ifdef __cplusplus extern "C" { #endif #define E_SUCCESS 0 /* Exit status for success */ #define E_ERROR 1 /* Exit status for error */ #define E_USAGE 2 /* Exit status for usage error */ extern void vwarn(const char *, va_list); extern void vdie(const char *, va_list); /*PRINTFLIKE1*/ extern void warn(const char *, ...); /*PRINTFLIKE1*/ extern void die(const char *, ...); extern const char *getpname(void); extern int inj_set_errno(int); #ifdef __cplusplus } #endif #endif /* _INJ_ERR_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_EVENT_H #define _INJ_EVENT_H #include #include #ifdef __cplusplus extern "C" { #endif extern inj_decl_t *inj_decl_create(inj_declmem_t *); extern void inj_decl_addmem(inj_decl_t *, inj_declmem_t *); extern void inj_decl_finish(inj_decl_t *, const char *, inj_itemtype_t); extern void inj_decl_destroy(inj_decl_t *); extern inj_decl_t *inj_decl_lookup(const char *, inj_itemtype_t); extern inj_declmem_t *inj_decl_mem_create(const char *, inj_memtype_t); extern inj_declmem_t *inj_decl_mem_create_defined(const char *, const char *, inj_itemtype_t); extern inj_declmem_t *inj_decl_mem_create_enum(const char *, inj_hash_t *); extern void inj_decl_mem_destroy(inj_declmem_t *); extern void inj_decl_mem_make_array(inj_declmem_t *, uint_t); extern inj_defn_t *inj_defn_create(inj_defnmem_t *); extern void inj_defn_addmem(inj_defn_t *, inj_defnmem_t *); extern void inj_defn_finish(inj_defn_t *, const char *, const char *, inj_itemtype_t); extern inj_defn_t *inj_defn_lookup(const char *, inj_memtype_t); extern inj_defnmem_t *inj_defn_mem_create(const char *, inj_defnmemtype_t); extern inj_defnmem_t *inj_defn_mem_create_list(inj_defn_t *, inj_defnmemtype_t); extern const char *inj_item2str(inj_itemtype_t); extern inj_memtype_t inj_item2mem(inj_itemtype_t); extern const char *inj_mem2str(inj_memtype_t); extern inj_itemtype_t inj_mem2item(inj_memtype_t); extern inj_randelem_t *inj_rand_create(inj_defn_t *, uint_t); extern inj_randelem_t *inj_rand_add(inj_randelem_t *, inj_randelem_t *); extern void inj_cmds_add(inj_cmd_t *); extern inj_list_t *inj_cmds_get(void); extern inj_cmd_t *inj_cmd_rand(inj_randelem_t *); extern inj_cmd_t *inj_cmd_repeat(inj_cmd_t *, uint_t); extern inj_cmd_t *inj_cmd_send(inj_defn_t *); extern inj_cmd_t *inj_cmd_sleep(uint_t); extern inj_cmd_t *inj_cmd_addhrt(hrtime_t); extern inj_cmd_t *inj_cmd_endhrt(void); #ifdef __cplusplus } #endif #endif /* _INJ_EVENT_H */ %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * FMA Event Injector language parser */ #include #include #include #include #include #include #include #include %} %union { inj_decl_t *l_decl; inj_declmem_t *l_declmem; inj_defn_t *l_defn; inj_defnmem_t *l_defnmem; inj_cmd_t *l_command; inj_randelem_t *l_randelem; inj_hash_t *l_hash; char *l_string; uint_t l_number; hrtime_t l_hrtime; } %type decl_memlist %type decl_mem %type decl_baremem %type decl_mem_intr %type decl_intr_type %type decl_arraydim %type decl_mem_cplx %type decl_enumlist %type defn_memlist %type defn_memvals %type defn_val %type command %type cmd_repeatable %type rand_problist %type rand_element %type defined_event %type number %type hrtime %token INJ_TOK_EVDEF %token INJ_TOK_FMRIDEF %token INJ_TOK_AUTHDEF %token INJ_TOK_LISTDEF %token INJ_TOK_INT8 %token INJ_TOK_INT16 %token INJ_TOK_INT32 %token INJ_TOK_INT64 %token INJ_TOK_UINT8 %token INJ_TOK_UINT16 %token INJ_TOK_UINT32 %token INJ_TOK_UINT64 %token INJ_TOK_BOOLEAN %token INJ_TOK_STRING %token INJ_TOK_ENUM %token INJ_TOK_EVENT %token INJ_TOK_FMRI %token INJ_TOK_AUTH %token INJ_TOK_LIST %token INJ_TOK_ADDHRT %token INJ_TOK_ENDHRT %token INJ_TOK_SLEEP %token INJ_TOK_REPEAT %token INJ_TOK_RANDOMIZE %token INJ_TOK_IDENT %token INJ_TOK_FMACLASS %token INJ_TOK_IMM %token INJ_TOK_QSTRING %% statement_list: /* EMPTY */ | statement_list statement ';' ; statement: decl | defn | command { if ($1 != NULL) inj_cmds_add($1); } ; /* * Event, FMRI, Authority, and list declarations */ decl: INJ_TOK_EVDEF INJ_TOK_FMACLASS '{' decl_memlist '}' { if ($4 != NULL) inj_decl_finish($4, $2, ITEMTYPE_EVENT); } | INJ_TOK_FMRIDEF INJ_TOK_IDENT '{' decl_memlist '}' { if ($4 != NULL) inj_decl_finish($4, $2, ITEMTYPE_FMRI); } | INJ_TOK_AUTHDEF INJ_TOK_IDENT '{' decl_memlist '}' { if ($4 != NULL) inj_decl_finish($4, $2, ITEMTYPE_AUTH); } | INJ_TOK_LISTDEF INJ_TOK_IDENT '{' decl_memlist '}' { if ($4 != NULL) inj_decl_finish($4, $2, ITEMTYPE_LIST); } ; decl_memlist: /* EMPTY */ { $$ = NULL; } | decl_memlist decl_mem ';' { if ($2 == NULL) { $$ = $1; } else if ($1 == NULL) { $$ = inj_decl_create($2); } else { inj_decl_addmem($1, $2); $$ = $1; } } ; decl_mem: decl_baremem | decl_baremem decl_arraydim { if ($1 != NULL) inj_decl_mem_make_array($1, $2); $$ = $1; } ; decl_baremem: decl_mem_intr | decl_mem_cplx ; decl_mem_intr: decl_intr_type INJ_TOK_IDENT { $$ = inj_decl_mem_create($2, $1); } ; decl_intr_type: INJ_TOK_INT8 { $$ = MEMTYPE_INT8; } | INJ_TOK_INT16 { $$ = MEMTYPE_INT16; } | INJ_TOK_INT32 { $$ = MEMTYPE_INT32; } | INJ_TOK_INT64 { $$ = MEMTYPE_INT64; } | INJ_TOK_UINT8 { $$ = MEMTYPE_UINT8; } | INJ_TOK_UINT16 { $$ = MEMTYPE_UINT16; } | INJ_TOK_UINT32 { $$ = MEMTYPE_UINT32; } | INJ_TOK_UINT64 { $$ = MEMTYPE_UINT64; } | INJ_TOK_BOOLEAN { $$ = MEMTYPE_BOOL; } | INJ_TOK_STRING { $$ = MEMTYPE_STRING; } ; decl_arraydim: '[' number ']' { $$ = $2; } | '[' ']' { $$ = 0; } ; decl_mem_cplx: INJ_TOK_ENUM INJ_TOK_IDENT '{' decl_enumlist '}' { $$ = inj_decl_mem_create_enum($2, $4); } | INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT { $$ = inj_decl_mem_create_defined($3, $2, ITEMTYPE_EVENT); } | INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT { $$ = inj_decl_mem_create_defined($3, $2, ITEMTYPE_FMRI); } | INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT { $$ = inj_decl_mem_create_defined($3, $2, ITEMTYPE_AUTH); } | INJ_TOK_LIST INJ_TOK_IDENT INJ_TOK_IDENT { $$ = inj_decl_mem_create_defined($3, $2, ITEMTYPE_LIST); } ; decl_enumlist: INJ_TOK_IDENT { $$ = inj_zalloc(sizeof (inj_hash_t)); inj_strhash_create($$); inj_strhash_insert($$, $1, 1); } | decl_enumlist ',' INJ_TOK_IDENT { if (inj_strhash_lookup($1, $3) != NULL) yyerror("duplicate enum value \"%s\"", $3); else inj_strhash_insert($1, $3, 1); $$ = $1; } ; /* * Event, FMRI, Authority, and list definitions */ defn: INJ_TOK_EVENT INJ_TOK_FMACLASS INJ_TOK_IDENT '=' '{' defn_memlist '}' { inj_defn_finish($6, $2, $3, ITEMTYPE_EVENT); inj_strfree($2); } | INJ_TOK_FMRI INJ_TOK_IDENT INJ_TOK_IDENT '=' '{' defn_memlist '}' { inj_defn_finish($6, $2, $3, ITEMTYPE_FMRI); inj_strfree($2); } | INJ_TOK_AUTH INJ_TOK_IDENT INJ_TOK_IDENT '=' '{' defn_memlist '}' { inj_defn_finish($6, $2, $3, ITEMTYPE_AUTH); inj_strfree($2); } ; defn_memlist: defn_memvals { $$ = inj_defn_create($1); } | defn_memlist ',' defn_memvals { inj_defn_addmem($1, $3); $$ = $1; } ; defn_memvals: defn_val | INJ_TOK_EVENT INJ_TOK_FMACLASS { $$ = inj_defn_mem_create($2, DEFNMEM_EVENT); } | INJ_TOK_FMRI INJ_TOK_IDENT { $$ = inj_defn_mem_create($2, DEFNMEM_FMRI); } | INJ_TOK_AUTH INJ_TOK_IDENT { $$ = inj_defn_mem_create($2, DEFNMEM_AUTH); } | '[' defn_memlist ']' { $$ = inj_defn_mem_create_list($2, DEFNMEM_ARRAY); } | '{' defn_memlist '}' { $$ = inj_defn_mem_create_list($2, DEFNMEM_LIST); } ; defn_val: INJ_TOK_IMM { $$ = inj_defn_mem_create($1, DEFNMEM_IMM); } | INJ_TOK_IDENT { $$ = inj_defn_mem_create($1, DEFNMEM_IDENT); } | INJ_TOK_QSTRING { $$ = inj_defn_mem_create($1, DEFNMEM_QSTRING); } ; /* * Commands */ command: cmd_repeatable | INJ_TOK_ADDHRT hrtime { $$ = inj_cmd_addhrt($2); } | INJ_TOK_ENDHRT { $$ = inj_cmd_endhrt(); } | INJ_TOK_SLEEP number { $$ = inj_cmd_sleep($2); } | INJ_TOK_REPEAT number cmd_repeatable { $$ = ($3 == NULL ? NULL : inj_cmd_repeat($3, $2)); } ; cmd_repeatable: defined_event { $$ = ($1 == NULL ? NULL : inj_cmd_send($1)); } | INJ_TOK_RANDOMIZE '{' rand_problist '}' { $$ = ($3 == NULL ? NULL : inj_cmd_rand($3)); } ; rand_problist: rand_element | rand_problist ',' rand_element { $$ = ($1 == NULL || $3 == NULL) ? NULL : inj_rand_add($1, $3); } ; rand_element: '{' defined_event ',' number '}' { $$ = ($2 == NULL ? NULL : inj_rand_create($2, $4)); } ; defined_event: INJ_TOK_IDENT { inj_defn_t *ev; if ((ev = inj_defn_lookup($1, MEMTYPE_EVENT)) == NULL) { yyerror("unknown event \"%s\"\n", $1); $$ = NULL; } else $$ = ev; } number: INJ_TOK_IMM { u_longlong_t val; if (inj_strtoull($1, 32, &val) < 0) { yyerror("invalid number"); $$ = 0; } else $$ = (uint32_t)val; } hrtime: INJ_TOK_IMM INJ_TOK_IDENT { longlong_t val; if (inj_strtoll($1, 64, &val) < 0 || inj_strtime(&val, $2) < 0) { yyerror("invalid time"); $$ = 0; } else $$ = val; } %% inj_list_t * inj_program_read(const char *file) { if (strcmp(file, "-") == 0) { yyin = stdin; yyinname = "stdin"; } else { if ((yyin = fopen(file, "r")) == NULL) die("failed to open %s", file); yyinname = strrchr(file, '/'); if (yyinname != NULL) yyinname++; else yyinname = file; } yyreset(); (void) yyparse(); if (yyin != stdin) (void) fclose(yyin); if (yynerrors != 0) { die("parsing failed - %d error%s\n", yynerrors, (yynerrors > 1 ? "s" : "")); } return (inj_cmds_get()); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #define INJ_HASHSZ 211 struct inj_var { struct inj_var *v_next; uintmax_t v_uvalue; void *v_key; }; void inj_hash_create(inj_hash_t *h, ulong_t (*hfn)(void *), int (*cfn)(void *, void *)) { h->h_hash = inj_zalloc(sizeof (inj_var_t *) * INJ_HASHSZ); h->h_hashsz = INJ_HASHSZ; h->h_nelems = 0; h->h_hashfn = hfn; h->h_cmpfn = cfn; } static inj_var_t * inj_var_alloc(void *key, uintmax_t value, inj_var_t *next) { inj_var_t *v = inj_alloc(sizeof (inj_var_t)); v->v_next = next; v->v_key = key; v->v_uvalue = value; return (v); } static void inj_var_free(inj_var_t *v, void (*freefn)(inj_var_t *, void *), void *arg) { if (freefn != NULL) freefn(v, arg); inj_free(v, sizeof (inj_var_t)); } void inj_hash_destroy(inj_hash_t *h, void (*freefn)(inj_var_t *, void *), void *arg) { inj_var_t *v, *w; size_t i; for (i = 0; i < h->h_hashsz; i++) { for (v = h->h_hash[i]; v != NULL; v = w) { w = v->v_next; inj_var_free(v, freefn, arg); } } inj_free(h->h_hash, sizeof (inj_var_t *) * INJ_HASHSZ); } int inj_hash_insert(inj_hash_t *h, void *key, uintmax_t value) { size_t i = h->h_hashfn(key) % h->h_hashsz; inj_var_t *v; for (v = h->h_hash[i]; v != NULL; v = v->v_next) { if (h->h_cmpfn(v->v_key, key) == 0) return (-1); } /* not found - make a new one */ v = inj_var_alloc(key, value, h->h_hash[i]); h->h_hash[i] = v; h->h_nelems++; return (0); } inj_var_t * inj_hash_lookup(inj_hash_t *h, void *key) { size_t i = h->h_hashfn(key) % h->h_hashsz; inj_var_t *v; for (v = h->h_hash[i]; v != NULL; v = v->v_next) { if (h->h_cmpfn(v->v_key, key) == 0) return (v); } return (NULL); } void * inj_hash_get_key(inj_var_t *v) { return (v->v_key); } uintmax_t inj_hash_get_value(inj_var_t *v) { return (v->v_uvalue); } void * inj_hash_get_cookie(inj_var_t *v) { return ((void *)(uintptr_t)v->v_uvalue); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_HASH_H #define _INJ_HASH_H #include #ifdef __cplusplus extern "C" { #endif typedef struct inj_var inj_var_t; typedef struct inj_hash { inj_var_t **h_hash; size_t h_hashsz; size_t h_nelems; ulong_t (*h_hashfn)(void *); int (*h_cmpfn)(void *, void *); void (*h_freefn)(void *, uintmax_t); } inj_hash_t; extern void inj_hash_create(inj_hash_t *, ulong_t (*)(void *), int (*)(void *, void *)); extern void inj_hash_destroy(inj_hash_t *, void (*)(inj_var_t *, void *), void *); extern int inj_hash_insert(inj_hash_t *, void *, uintmax_t); extern inj_var_t *inj_hash_lookup(inj_hash_t *, void *); extern void *inj_hash_get_key(inj_var_t *); extern uintmax_t inj_hash_get_value(inj_var_t *); extern void *inj_hash_get_cookie(inj_var_t *); #ifdef __cplusplus } #endif #endif /* _INJ_HASH_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_LEX_H #define _INJ_LEX_H #ifdef __cplusplus extern "C" { #endif extern int yynerrors; extern const char *yyinname; extern FILE *yyin; extern int yylineno; /*PRINTFLIKE1*/ extern void yyerror(const char *, ...); extern void yyreset(void); extern int yyparse(void); extern int yylex(void); #ifdef __cplusplus } #endif #endif /* _INJ_LEX_H */ %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include int yynerrors; const char *yyinname; %} /* * S0 is for normal input processing. SCOMMENT is used to process comments. * We need a separate state for comments to prevent the lex regexp engine from * overflowing its own buffers as it searches for the end of comments. */ %s S0 SCOMMENT RGX_IMM_SEQ -?([0-9]+|0[xX][0-9A-Fa-f]+) RGX_STR_SEQ ([^"\\\n]|\\[^"\n]|\\\")* RGX_IDENT [a-zA-Z][a-zA-Z0-9\-_]* %% "/*" { BEGIN(SCOMMENT); } .|\n ; /* discard */ "*/" { BEGIN(S0); } evdef { return (INJ_TOK_EVDEF); } fmridef { return (INJ_TOK_FMRIDEF); } authdef { return (INJ_TOK_AUTHDEF); } listdef { return (INJ_TOK_LISTDEF); } int8_t { return (INJ_TOK_INT8); } int16_t { return (INJ_TOK_INT16); } int32_t { return (INJ_TOK_INT32); } int64_t { return (INJ_TOK_INT64); } uint8_t { return (INJ_TOK_UINT8); } uint16_t { return (INJ_TOK_UINT16); } uint32_t { return (INJ_TOK_UINT32); } uint64_t { return (INJ_TOK_UINT64); } boolean { return (INJ_TOK_BOOLEAN); } boolean_t { return (INJ_TOK_BOOLEAN); } string { return (INJ_TOK_STRING); } enum { return (INJ_TOK_ENUM); } event { return (INJ_TOK_EVENT); } fmri { return (INJ_TOK_FMRI); } auth { return (INJ_TOK_AUTH); } list { return (INJ_TOK_LIST); } addhrtime { return (INJ_TOK_ADDHRT); } endhrtime { return (INJ_TOK_ENDHRT); } sleep { return (INJ_TOK_SLEEP); } repeat { return (INJ_TOK_REPEAT); } randomize { return (INJ_TOK_RANDOMIZE); } \"{RGX_STR_SEQ}$ { yyerror("syntax error: \" unmatched"); } \"{RGX_STR_SEQ}\" { /* Quoted string */ yylval.l_string = inj_strndup(yytext + 1, yyleng - 2); return (INJ_TOK_QSTRING); } {RGX_IDENT}("."{RGX_IDENT})+ { yylval.l_string = inj_strdup(yytext); return (INJ_TOK_FMACLASS); } {RGX_IDENT} { yylval.l_string = inj_strdup(yytext); return (INJ_TOK_IDENT); } {RGX_IMM_SEQ} { yylval.l_string = inj_strdup(yytext); return (INJ_TOK_IMM); } [ \t\n] ; /* Ignore whitespace */ . { return (yytext[0]); } %% void yyerror(const char *format, ...) { int err = errno; va_list ap; char *s; /* Don't print the line number if the message begins with a space */ if (*format == ' ') { (void) fprintf(stderr, "%s: ", yyinname, yylineno); format++; } else (void) fprintf(stderr, "%s: %d: ", yyinname, yylineno); va_start(ap, format); (void) vfprintf(stderr, format, ap); va_end(ap); if (strchr(format, '\n') == NULL) (void) fprintf(stderr, " near \"%s\"\n", yytext); yynerrors++; errno = err; } int yywrap(void) { return (1); } void yyreset(void) { BEGIN(S0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include void inj_list_append(inj_list_t *mlp, void *new) { inj_list_t *p = mlp->ml_prev; /* p = tail list element */ inj_list_t *q = new; /* q = new list element */ mlp->ml_prev = q; q->ml_prev = p; q->ml_next = NULL; if (p != NULL) { assert(p->ml_next == NULL); p->ml_next = q; } else { assert(mlp->ml_next == NULL); mlp->ml_next = q; } } void inj_list_prepend(inj_list_t *mlp, void *new) { inj_list_t *p = new; /* p = new list element */ inj_list_t *q = mlp->ml_next; /* q = head list element */ mlp->ml_next = p; p->ml_prev = NULL; p->ml_next = q; if (q != NULL) { assert(q->ml_prev == NULL); q->ml_prev = p; } else { assert(mlp->ml_prev == NULL); mlp->ml_prev = p; } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_LIST_H #define _INJ_LIST_H #ifdef __cplusplus extern "C" { #endif /* * Simple doubly-linked list implementation. This implementation assumes that * each element contains an embedded inj_list_t structure. An additional * inj_list_t is used to store the head and tail pointers. The caller can * use inj_list_prev() on the master list_t to obtain the tail element, or * inj_list_next() to obtain the head element. The head and tail list elements * have their previous and next pointers set to NULL, respectively. */ typedef struct inj_list { struct inj_list *ml_prev; /* Link to previous list element */ struct inj_list *ml_next; /* Link to next list element */ } inj_list_t; #define inj_list_prev(elem) ((void *)(((inj_list_t *)(elem))->ml_prev)) #define inj_list_next(elem) ((void *)(((inj_list_t *)(elem))->ml_next)) extern void inj_list_append(inj_list_t *, void *); extern void inj_list_prepend(inj_list_t *, void *); #ifdef __cplusplus } #endif #endif /* _INJ_LIST_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include typedef struct inj_logfile { uint64_t ilf_sec; /* timestamp seconds from previous record */ uint64_t ilf_nsec; /* timestamp nanoseconds from previous record */ int ilf_index; /* record index in log file for fake lineno */ } inj_logfile_t; /*ARGSUSED*/ static int inj_logfile_event(fmd_log_t *lp, const fmd_log_record_t *rp, void *data) { inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); inj_defn_t *ev = inj_zalloc(sizeof (inj_defn_t)); hrtime_t rec_sec = rp->rec_sec + rp->rec_nsec / NANOSEC; hrtime_t rec_nsec = rp->rec_nsec % NANOSEC; inj_logfile_t *ilf = data; hrtime_t delta; if (ilf->ilf_index == 1) goto add_event; /* do not try to adjust time for first record */ /* * If the current record's time is before that of the previous record, * advance it to the previous record time. This may occur when delays * between capturing ENA and enqueuing a sysevent are observed. */ if (rec_sec < ilf->ilf_sec || (rec_sec == ilf->ilf_sec && rec_nsec < ilf->ilf_nsec)) { warn("record [%d] (%s) timestamp is out of order: " "advancing event time to %llx.%llx\n", ilf->ilf_index, rp->rec_class, ilf->ilf_sec, ilf->ilf_nsec); rec_sec = ilf->ilf_sec; rec_nsec = ilf->ilf_nsec; } /* * For now, compute the delta between the previous record and this one * as a number of nanoseconds and advance the clock. If a massively * large delay is observed (>INT64_MAX ns), we abort. This could be * improved if necessary by sending more than one cmd_addhrt in a loop. */ delta = (rec_sec - ilf->ilf_sec) * NANOSEC; delta += (hrtime_t)rec_nsec - (hrtime_t)ilf->ilf_nsec; if (delta < 0) die("record [%d] timestamp delta too large\n", ilf->ilf_index); if (delta > 0) inj_cmds_add(inj_cmd_addhrt(delta)); add_event: ev->defn_name = inj_strdup(rp->rec_class); ev->defn_lineno = ilf->ilf_index++; if ((errno = nvlist_dup(rp->rec_nvl, &ev->defn_nvl, 0)) != 0) die("failed to allocate nvl for %s event", rp->rec_class); cmd->cmd_type = CMD_SEND_EVENT; cmd->cmd_event = ev; inj_cmds_add(cmd); ilf->ilf_sec = rec_sec; ilf->ilf_nsec = rec_nsec; return (0); } inj_list_t * inj_logfile_read(fmd_log_t *lp) { const char *label = fmd_log_label(lp); inj_logfile_t ilf; if (strcmp(label, "error") != 0) die("cannot use '%s' log as injector input\n", label); bzero(&ilf, sizeof (ilf)); ilf.ilf_index = 1; if (fmd_log_iter(lp, inj_logfile_event, &ilf) != 0) { die("failed to process log: %s\n", fmd_log_errmsg(lp, fmd_log_errno(lp))); } return (inj_cmds_get()); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include int verbose; int quiet; static int usage(void) { (void) fprintf(stderr, "Usage: %s [-nqv] [-c chan] [file]\n" "\t-c specify alternate channel to use for publication\n" "\t-n compile program but do not inject any events\n" "\t-q enable quiet mode (silence status messages)\n" "\t-v enable verbose output (display event details)\n", getpname()); return (E_USAGE); } /* * Sysevent-based event delivery */ static void * sev_open(const char *chan) { evchan_t *hdl; if (chan == NULL) chan = FM_ERROR_CHAN; if ((errno = sysevent_evc_bind(chan, &hdl, EVCH_CREAT | EVCH_HOLD_PEND)) != 0) die("can't bind to error channel %s", chan); return (hdl); } static void sev_send(void *arg, nvlist_t *msg) { if ((errno = sysevent_evc_publish(arg, EC_FM, ESC_FM_ERROR, "com.sun", getpname(), msg, EVCH_SLEEP)) != 0) warn("failed to send event"); } static void sev_close(void *arg) { (void) sysevent_evc_unbind(arg); } static inj_mode_ops_t sysevent_ops = { sev_open, sev_send, sev_close }; /* * Simulated delivery */ /*ARGSUSED*/ static void * sim_open(const char *arg) { return ((void *)1); } /*ARGSUSED*/ static void sim_send(void *arg, nvlist_t *msg) { } /*ARGSUSED*/ static void sim_close(void *arg) { } static inj_mode_ops_t simulate_ops = { sim_open, sim_send, sim_close }; int main(int argc, char *argv[]) { const inj_mode_ops_t *mode = NULL; void *mode_arg = NULL; int c; const char *file; inj_list_t *program; fmd_log_t *lp; while ((c = getopt(argc, argv, "c:nqv")) != EOF) { switch (c) { case 'c': if (mode != NULL || mode_arg != NULL) return (usage()); mode = &sysevent_ops; mode_arg = optarg; break; case 'n': if (mode != NULL) return (usage()); mode = &simulate_ops; break; case 'q': quiet = 1; break; case 'v': verbose = 1; break; default: return (usage()); } } if (mode == NULL) mode = &sysevent_ops; argc -= optind; argv += optind; if (argc == 0) file = "-"; else if (argc == 1) file = argv[0]; else return (usage()); srand48(gethrtime()); if (argc > 0 && (lp = fmd_log_open(FMD_LOG_VERSION, file, &c)) != NULL) program = inj_logfile_read(lp); else program = inj_program_read(file); inj_program_run(program, mode, mode_arg); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include char * inj_strdup(const char *s) { char *s1 = inj_alloc(strlen(s) + 1); (void) strcpy(s1, s); return (s1); } char * inj_strndup(const char *s, size_t n) { char *s2 = inj_alloc(n + 1); (void) strncpy(s2, s, n + 1); s2[n] = '\0'; return (s2); } void inj_strfree(const char *s) { inj_free((void *)s, strlen(s) + 1); } typedef struct type_desc { int64_t td_min; uint64_t td_max; } type_desc_t; static const type_desc_t signed_types[] = { { 0, 0 }, { INT8_MIN, INT8_MAX }, { INT16_MIN, INT16_MAX }, { 0, 0 }, { INT32_MIN, INT32_MAX }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { INT64_MIN, INT64_MAX } }; static const type_desc_t unsigned_types[] = { { 0, 0 }, { 0, UINT8_MAX }, { 0, UINT16_MAX }, { 0, 0 }, { 0, UINT32_MAX }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, UINT64_MAX } }; int inj_strtoll(const char *str, int width, longlong_t *valp) { const type_desc_t *desc; longlong_t val; char *c; if (width != 0) { assert(width / 8 < (sizeof (signed_types) / sizeof (signed_types[0]))); desc = &signed_types[width / 8]; assert(desc->td_max != 0); } errno = 0; val = strtoll(str, &c, 0); if (*c != '\0' || errno == EINVAL) return (inj_set_errno(EINVAL)); if (errno == ERANGE || (width != 0 && (val < desc->td_min || val > (longlong_t)desc->td_max))) return (inj_set_errno(ERANGE)); if (valp != NULL) *valp = val; return (0); } int inj_strtoull(const char *str, int width, u_longlong_t *valp) { const type_desc_t *desc; u_longlong_t val; char *c; if (width != 0) { assert(width / 8 < (sizeof (unsigned_types) / sizeof (unsigned_types[0]))); desc = &unsigned_types[width / 8]; assert(desc->td_max != 0); } errno = 0; val = strtoull(str, &c, 0); if (*c != '\0' || errno == EINVAL) return (inj_set_errno(EINVAL)); if (errno == ERANGE || (width != 0 && val > desc->td_max)) return (inj_set_errno(ERANGE)); if (valp != NULL) *valp = val; return (0); } int inj_strtime(hrtime_t *nsp, const char *units) { static const struct { const char *name; hrtime_t mul; } suffix[] = { { "ns", NANOSEC / NANOSEC }, { "nsec", NANOSEC / NANOSEC }, { "us", NANOSEC / MICROSEC }, { "usec", NANOSEC / MICROSEC }, { "ms", NANOSEC / MILLISEC }, { "msec", NANOSEC / MILLISEC }, { "s", NANOSEC / SEC }, { "sec", NANOSEC / SEC }, { "m", NANOSEC * (hrtime_t)60 }, { "min", NANOSEC * (hrtime_t)60 }, { "h", NANOSEC * (hrtime_t)(60 * 60) }, { "hour", NANOSEC * (hrtime_t)(60 * 60) }, { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) }, { "hz", 0 }, { NULL } }; hrtime_t val = *nsp, mul = 1; int i; for (i = 0; suffix[i].name != NULL; i++) { if (strcasecmp(suffix[i].name, units) == 0) { mul = suffix[i].mul; break; } } if (suffix[i].name == NULL && *units != '\0') return (inj_set_errno(EINVAL)); if (mul == 0) { if (val != 0) val = NANOSEC / val; /* compute val as value per sec */ } else val *= mul; *nsp = val; return (0); } static ulong_t inj_hashfn_string(void *key) { size_t g, h = 0; char *p; assert(key != NULL); for (p = key; *p != '\0'; p++) { h = (h << 4) + *p; if ((g = (h & 0xf0000000)) != 0) { h ^= (g >> 24); h ^= g; } } return (h); } static int inj_hashcmp_string(void *k1, void *k2) { return (strcmp(k1, k2)); } /*ARGSUSED*/ static void inj_hashfree_string(inj_var_t *v, void *arg) { inj_strfree(inj_hash_get_key(v)); } void inj_strhash_create(inj_hash_t *h) { inj_hash_create(h, inj_hashfn_string, inj_hashcmp_string); } int inj_strhash_insert(inj_hash_t *h, const char *str, uintmax_t value) { return (inj_hash_insert(h, (void *)inj_strdup(str), value)); } inj_var_t * inj_strhash_lookup(inj_hash_t *h, const char *str) { return (inj_hash_lookup(h, (void *)str)); } void inj_strhash_destroy(inj_hash_t *h) { inj_hash_destroy(h, inj_hashfree_string, NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _INJ_STRING_H #define _INJ_STRING_H #include #include #include #ifdef __cplusplus extern "C" { #endif extern char *inj_strdup(const char *); extern char *inj_strndup(const char *, size_t); extern void inj_strfree(const char *); extern int inj_strtoll(const char *, int, longlong_t *); extern int inj_strtoull(const char *, int, u_longlong_t *); extern int inj_strtime(hrtime_t *, const char *); extern void inj_strhash_create(inj_hash_t *); extern int inj_strhash_insert(inj_hash_t *, const char *, uintmax_t); extern inj_var_t *inj_strhash_lookup(inj_hash_t *, const char *); extern void inj_strhash_destroy(inj_hash_t *); #ifdef __cplusplus } #endif #endif /* _INJ_STRING_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include void * inj_alloc(size_t sz) { return (umem_alloc(sz, UMEM_NOFAIL)); } void * inj_zalloc(size_t sz) { return (umem_zalloc(sz, UMEM_NOFAIL)); } void inj_free(void *buf, size_t sz) { umem_free(buf, sz); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include const char * inj_item2str(inj_itemtype_t item) { static const char *const names[] = { "event", "fmri", "auth", "list" }; return (item >= 0 && item < sizeof (names) / sizeof (char *) ? names[item] : "???"); } inj_memtype_t inj_item2mem(inj_itemtype_t item) { static const inj_memtype_t mems[] = { MEMTYPE_EVENT, MEMTYPE_FMRI, MEMTYPE_AUTH, MEMTYPE_LIST }; assert(item >= 0 && item < sizeof (mems) / sizeof (inj_memtype_t)); return (mems[item]); } /* * Convert a *subset* of inj_memtype_t's to inj_itemtype_t's. */ inj_itemtype_t inj_mem2item(inj_memtype_t mem) { switch (mem) { case MEMTYPE_EVENT: return (ITEMTYPE_EVENT); case MEMTYPE_FMRI: return (ITEMTYPE_FMRI); case MEMTYPE_AUTH: return (ITEMTYPE_AUTH); case MEMTYPE_LIST: return (ITEMTYPE_LIST); default: return (-1); } } const char * inj_mem2str(inj_memtype_t mem) { static const char *names[] = { "UNKNOWN", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "bool", "string", "enum", "event", "fmri", "auth" }; return (mem >= 0 && mem < sizeof (names) / sizeof (char *) ? names[mem] : "???"); }