1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * The "program" executed by the injector consists of a tree of commands. 31 * Routines in this file build and execute said command tree. 32 */ 33 34 #include <sys/fm/protocol.h> 35 #include <unistd.h> 36 37 #include <inj.h> 38 #include <inj_event.h> 39 #include <inj_lex.h> 40 #include <inj_err.h> 41 42 /* 43 * Command tree construction 44 */ 45 46 static inj_list_t inj_cmds; 47 48 void 49 inj_cmds_add(inj_cmd_t *cmd) 50 { 51 inj_list_append(&inj_cmds, cmd); 52 } 53 54 inj_list_t * 55 inj_cmds_get(void) 56 { 57 return (&inj_cmds); 58 } 59 60 inj_randelem_t * 61 inj_rand_create(inj_defn_t *ev, uint_t prob) 62 { 63 inj_randelem_t *re = inj_zalloc(sizeof (inj_randelem_t)); 64 65 re->re_event = ev; 66 re->re_prob = prob; 67 68 return (re); 69 } 70 71 inj_randelem_t * 72 inj_rand_add(inj_randelem_t *list, inj_randelem_t *new) 73 { 74 new->re_next = list; 75 return (new); 76 } 77 78 inj_cmd_t * 79 inj_cmd_rand(inj_randelem_t *rlist) 80 { 81 inj_randelem_t *r; 82 inj_cmd_t *cmd; 83 uint_t prob, tmpprob; 84 int nelems, i; 85 86 prob = 0; 87 for (i = 0, r = rlist; r != NULL; r = r->re_next, i++) 88 prob += r->re_prob; 89 90 if (prob != 100) { 91 yyerror("probabilities don't sum to 100\n"); 92 return (NULL); 93 } 94 95 nelems = i; 96 97 cmd = inj_zalloc(sizeof (inj_cmd_t)); 98 cmd->cmd_type = CMD_RANDOM; 99 cmd->cmd_num = nelems; 100 cmd->cmd_rand = inj_alloc(sizeof (inj_randelem_t *) * nelems); 101 102 prob = 0; 103 for (r = rlist, i = 0; i < nelems; i++, r = r->re_next) { 104 tmpprob = r->re_prob; 105 r->re_prob = prob; 106 prob += tmpprob; 107 108 cmd->cmd_rand[i] = r; 109 } 110 111 return (cmd); 112 } 113 114 inj_cmd_t * 115 inj_cmd_repeat(inj_cmd_t *repcmd, uint_t num) 116 { 117 inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); 118 119 cmd->cmd_type = CMD_REPEAT; 120 cmd->cmd_num = num; 121 cmd->cmd_subcmd = repcmd; 122 123 return (cmd); 124 } 125 126 inj_cmd_t * 127 inj_cmd_send(inj_defn_t *ev) 128 { 129 inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); 130 131 cmd->cmd_type = CMD_SEND_EVENT; 132 cmd->cmd_event = ev; 133 134 return (cmd); 135 } 136 137 inj_cmd_t * 138 inj_cmd_sleep(uint_t secs) 139 { 140 inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); 141 142 cmd->cmd_type = CMD_SLEEP; 143 cmd->cmd_num = secs; 144 145 return (cmd); 146 } 147 148 inj_cmd_t * 149 inj_cmd_addhrt(hrtime_t delta) 150 { 151 const char *class = "resource.sunos.fmd.clock.addhrtime"; 152 inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t)); 153 inj_defn_t *ev = inj_zalloc(sizeof (inj_defn_t)); 154 155 ev->defn_name = class; 156 ev->defn_lineno = yylineno; 157 158 if ((errno = nvlist_alloc(&ev->defn_nvl, NV_UNIQUE_NAME, 0)) != 0) 159 die("failed to allocate nvl for %s event", class); 160 161 if ((errno = nvlist_add_string(ev->defn_nvl, FM_CLASS, class)) != 0 || 162 (errno = nvlist_add_uint8(ev->defn_nvl, FM_VERSION, 1)) != 0 || 163 (errno = nvlist_add_int64(ev->defn_nvl, "delta", delta)) != 0) 164 die("failed to build nvl for %s event", class); 165 166 cmd->cmd_type = CMD_SEND_EVENT; 167 cmd->cmd_event = ev; 168 169 return (cmd); 170 } 171 172 inj_cmd_t * 173 inj_cmd_endhrt(void) 174 { 175 return (inj_cmd_addhrt(-1LL)); /* clock underflow causes end of time */ 176 } 177 178 static uint64_t 179 inj_ena(void) 180 { 181 return (((gethrtime() & ENA_FMT1_TIME_MASK) << 182 ENA_FMT1_TIME_SHFT) | (FM_ENA_FMT1 & ENA_FORMAT_MASK)); 183 } 184 185 static void 186 cmd_run_send(const inj_mode_ops_t *mode, void *hdl, inj_defn_t *ev) 187 { 188 if (!quiet) { 189 (void) printf("sending event %s ... ", ev->defn_name); 190 (void) fflush(stdout); 191 } 192 193 if (ev->defn_decl && (ev->defn_decl->decl_flags & DECL_F_AUTOENA) && 194 (errno = nvlist_add_uint64(ev->defn_nvl, "ena", inj_ena())) != 0) 195 warn("failed to add ena to %s", ev->defn_name); 196 197 if (verbose) { 198 nvlist_print(stdout, ev->defn_nvl); 199 (void) printf("\n"); 200 } 201 202 mode->mo_send(hdl, ev->defn_nvl); 203 204 if (!quiet) 205 (void) printf("done\n"); 206 } 207 208 static void 209 cmd_run_random(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd) 210 { 211 uint_t num = lrand48() % 100; 212 int i; 213 214 for (i = 1; i < cmd->cmd_num; i++) { 215 if (cmd->cmd_rand[i]->re_prob > num) 216 break; 217 } 218 219 cmd_run_send(mode, hdl, cmd->cmd_rand[i - 1]->re_event); 220 } 221 222 static void 223 cmd_run(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd) 224 { 225 switch (cmd->cmd_type) { 226 case CMD_SEND_EVENT: 227 cmd_run_send(mode, hdl, cmd->cmd_event); 228 break; 229 230 case CMD_SLEEP: 231 (void) printf("sleeping for %d sec%s ... ", 232 cmd->cmd_num, cmd->cmd_num > 1 ? "s" : ""); 233 (void) fflush(stdout); 234 (void) sleep(cmd->cmd_num); 235 (void) printf("done\n"); 236 break; 237 238 case CMD_RANDOM: 239 cmd_run_random(mode, hdl, cmd); 240 break; 241 242 default: 243 warn("ignoring unknown command type: %d\n", cmd->cmd_type); 244 } 245 } 246 247 void 248 inj_program_run(inj_list_t *prog, const inj_mode_ops_t *mode, void *mode_arg) 249 { 250 void *hdl = mode->mo_open(mode_arg); 251 inj_cmd_t *cmd; 252 int i; 253 254 for (cmd = inj_list_next(prog); cmd != NULL; cmd = inj_list_next(cmd)) { 255 if (cmd->cmd_type == CMD_REPEAT) { 256 for (i = 1; i <= cmd->cmd_num; i++) { 257 if (verbose) { 258 (void) printf("(repeat %d of %d)\n", 259 i, cmd->cmd_num); 260 } 261 cmd_run(mode, hdl, cmd->cmd_subcmd); 262 } 263 } else 264 cmd_run(mode, hdl, cmd); 265 } 266 267 mode->mo_close(hdl); 268 } 269