17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*540db9a9SStephen Hanson  * Common Development and Distribution License (the "License").
6*540db9a9SStephen Hanson  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21d9638e54Smws 
227c478bd9Sstevel@tonic-gate /*
23*540db9a9SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * The "program" executed by the injector consists of a tree of commands.
297c478bd9Sstevel@tonic-gate  * Routines in this file build and execute said command tree.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <inj.h>
367c478bd9Sstevel@tonic-gate #include <inj_event.h>
377c478bd9Sstevel@tonic-gate #include <inj_lex.h>
387c478bd9Sstevel@tonic-gate #include <inj_err.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Command tree construction
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static inj_list_t inj_cmds;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate void
inj_cmds_add(inj_cmd_t * cmd)477c478bd9Sstevel@tonic-gate inj_cmds_add(inj_cmd_t *cmd)
487c478bd9Sstevel@tonic-gate {
497c478bd9Sstevel@tonic-gate 	inj_list_append(&inj_cmds, cmd);
507c478bd9Sstevel@tonic-gate }
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate inj_list_t *
inj_cmds_get(void)537c478bd9Sstevel@tonic-gate inj_cmds_get(void)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	return (&inj_cmds);
567c478bd9Sstevel@tonic-gate }
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate inj_randelem_t *
inj_rand_create(inj_defn_t * ev,uint_t prob)597c478bd9Sstevel@tonic-gate inj_rand_create(inj_defn_t *ev, uint_t prob)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate 	inj_randelem_t *re = inj_zalloc(sizeof (inj_randelem_t));
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	re->re_event = ev;
647c478bd9Sstevel@tonic-gate 	re->re_prob = prob;
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate 	return (re);
677c478bd9Sstevel@tonic-gate }
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate inj_randelem_t *
inj_rand_add(inj_randelem_t * list,inj_randelem_t * new)707c478bd9Sstevel@tonic-gate inj_rand_add(inj_randelem_t *list, inj_randelem_t *new)
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate 	new->re_next = list;
737c478bd9Sstevel@tonic-gate 	return (new);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_rand(inj_randelem_t * rlist)777c478bd9Sstevel@tonic-gate inj_cmd_rand(inj_randelem_t *rlist)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	inj_randelem_t *r;
807c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd;
817c478bd9Sstevel@tonic-gate 	uint_t prob, tmpprob;
827c478bd9Sstevel@tonic-gate 	int nelems, i;
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	prob = 0;
857c478bd9Sstevel@tonic-gate 	for (i = 0, r = rlist; r != NULL; r = r->re_next, i++)
867c478bd9Sstevel@tonic-gate 		prob += r->re_prob;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (prob != 100) {
897c478bd9Sstevel@tonic-gate 		yyerror("probabilities don't sum to 100\n");
907c478bd9Sstevel@tonic-gate 		return (NULL);
917c478bd9Sstevel@tonic-gate 	}
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	nelems = i;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	cmd = inj_zalloc(sizeof (inj_cmd_t));
967c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD_RANDOM;
977c478bd9Sstevel@tonic-gate 	cmd->cmd_num = nelems;
987c478bd9Sstevel@tonic-gate 	cmd->cmd_rand = inj_alloc(sizeof (inj_randelem_t *) * nelems);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	prob = 0;
1017c478bd9Sstevel@tonic-gate 	for (r = rlist, i = 0; i < nelems; i++, r = r->re_next) {
1027c478bd9Sstevel@tonic-gate 		tmpprob = r->re_prob;
1037c478bd9Sstevel@tonic-gate 		r->re_prob = prob;
1047c478bd9Sstevel@tonic-gate 		prob += tmpprob;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 		cmd->cmd_rand[i] = r;
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate 	return (cmd);
1107c478bd9Sstevel@tonic-gate }
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_repeat(inj_cmd_t * repcmd,uint_t num)1137c478bd9Sstevel@tonic-gate inj_cmd_repeat(inj_cmd_t *repcmd, uint_t num)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD_REPEAT;
1187c478bd9Sstevel@tonic-gate 	cmd->cmd_num = num;
1197c478bd9Sstevel@tonic-gate 	cmd->cmd_subcmd = repcmd;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	return (cmd);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_send(inj_defn_t * ev)1257c478bd9Sstevel@tonic-gate inj_cmd_send(inj_defn_t *ev)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD_SEND_EVENT;
1307c478bd9Sstevel@tonic-gate 	cmd->cmd_event = ev;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	return (cmd);
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_sleep(uint_t secs)1367c478bd9Sstevel@tonic-gate inj_cmd_sleep(uint_t secs)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD_SLEEP;
1417c478bd9Sstevel@tonic-gate 	cmd->cmd_num = secs;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	return (cmd);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_addhrt(hrtime_t delta)1477c478bd9Sstevel@tonic-gate inj_cmd_addhrt(hrtime_t delta)
1487c478bd9Sstevel@tonic-gate {
149d9638e54Smws 	const char *class = "resource.fm.fmd.clock.addhrtime";
1507c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd = inj_zalloc(sizeof (inj_cmd_t));
1517c478bd9Sstevel@tonic-gate 	inj_defn_t *ev = inj_zalloc(sizeof (inj_defn_t));
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	ev->defn_name = class;
1547c478bd9Sstevel@tonic-gate 	ev->defn_lineno = yylineno;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_alloc(&ev->defn_nvl, NV_UNIQUE_NAME, 0)) != 0)
1577c478bd9Sstevel@tonic-gate 		die("failed to allocate nvl for %s event", class);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(ev->defn_nvl, FM_CLASS, class)) != 0 ||
1607c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_uint8(ev->defn_nvl, FM_VERSION, 1)) != 0 ||
1617c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_int64(ev->defn_nvl, "delta", delta)) != 0)
1627c478bd9Sstevel@tonic-gate 		die("failed to build nvl for %s event", class);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD_SEND_EVENT;
1657c478bd9Sstevel@tonic-gate 	cmd->cmd_event = ev;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	return (cmd);
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate inj_cmd_t *
inj_cmd_endhrt(void)1717c478bd9Sstevel@tonic-gate inj_cmd_endhrt(void)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	return (inj_cmd_addhrt(-1LL)); /* clock underflow causes end of time */
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate static uint64_t
inj_ena(void)1777c478bd9Sstevel@tonic-gate inj_ena(void)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	return (((gethrtime() & ENA_FMT1_TIME_MASK) <<
1807c478bd9Sstevel@tonic-gate 	    ENA_FMT1_TIME_SHFT) | (FM_ENA_FMT1 & ENA_FORMAT_MASK));
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate static void
cmd_run_send(const inj_mode_ops_t * mode,void * hdl,inj_defn_t * ev)1847c478bd9Sstevel@tonic-gate cmd_run_send(const inj_mode_ops_t *mode, void *hdl, inj_defn_t *ev)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	if (!quiet) {
1877c478bd9Sstevel@tonic-gate 		(void) printf("sending event %s ... ", ev->defn_name);
1887c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
191*540db9a9SStephen Hanson 	if ((errno = nvlist_add_boolean_value(ev->defn_nvl, "__injected",
192*540db9a9SStephen Hanson 	    1)) != 0)
193*540db9a9SStephen Hanson 		warn("failed to add __injected to %s", ev->defn_name);
194*540db9a9SStephen Hanson 
1957c478bd9Sstevel@tonic-gate 	if (ev->defn_decl && (ev->defn_decl->decl_flags & DECL_F_AUTOENA) &&
1967c478bd9Sstevel@tonic-gate 	    (errno = nvlist_add_uint64(ev->defn_nvl, "ena", inj_ena())) != 0)
1977c478bd9Sstevel@tonic-gate 		warn("failed to add ena to %s", ev->defn_name);
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (verbose) {
2007c478bd9Sstevel@tonic-gate 		nvlist_print(stdout, ev->defn_nvl);
2017c478bd9Sstevel@tonic-gate 		(void) printf("\n");
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	mode->mo_send(hdl, ev->defn_nvl);
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (!quiet)
2077c478bd9Sstevel@tonic-gate 		(void) printf("done\n");
2087c478bd9Sstevel@tonic-gate }
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate static void
cmd_run_random(const inj_mode_ops_t * mode,void * hdl,inj_cmd_t * cmd)2117c478bd9Sstevel@tonic-gate cmd_run_random(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd)
2127c478bd9Sstevel@tonic-gate {
2137c478bd9Sstevel@tonic-gate 	uint_t num = lrand48() % 100;
2147c478bd9Sstevel@tonic-gate 	int i;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	for (i = 1; i < cmd->cmd_num; i++) {
2177c478bd9Sstevel@tonic-gate 		if (cmd->cmd_rand[i]->re_prob > num)
2187c478bd9Sstevel@tonic-gate 			break;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	cmd_run_send(mode, hdl, cmd->cmd_rand[i - 1]->re_event);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static void
cmd_run(const inj_mode_ops_t * mode,void * hdl,inj_cmd_t * cmd)2257c478bd9Sstevel@tonic-gate cmd_run(const inj_mode_ops_t *mode, void *hdl, inj_cmd_t *cmd)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	switch (cmd->cmd_type) {
2287c478bd9Sstevel@tonic-gate 	case CMD_SEND_EVENT:
2297c478bd9Sstevel@tonic-gate 		cmd_run_send(mode, hdl, cmd->cmd_event);
2307c478bd9Sstevel@tonic-gate 		break;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	case CMD_SLEEP:
2337c478bd9Sstevel@tonic-gate 		(void) printf("sleeping for %d sec%s ... ",
2347c478bd9Sstevel@tonic-gate 		    cmd->cmd_num, cmd->cmd_num > 1 ? "s" : "");
2357c478bd9Sstevel@tonic-gate 		(void) fflush(stdout);
2367c478bd9Sstevel@tonic-gate 		(void) sleep(cmd->cmd_num);
2377c478bd9Sstevel@tonic-gate 		(void) printf("done\n");
2387c478bd9Sstevel@tonic-gate 		break;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	case CMD_RANDOM:
2417c478bd9Sstevel@tonic-gate 		cmd_run_random(mode, hdl, cmd);
2427c478bd9Sstevel@tonic-gate 		break;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	default:
2457c478bd9Sstevel@tonic-gate 		warn("ignoring unknown command type: %d\n", cmd->cmd_type);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate void
inj_program_run(inj_list_t * prog,const inj_mode_ops_t * mode,void * mode_arg)2507c478bd9Sstevel@tonic-gate inj_program_run(inj_list_t *prog, const inj_mode_ops_t *mode, void *mode_arg)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	void *hdl = mode->mo_open(mode_arg);
2537c478bd9Sstevel@tonic-gate 	inj_cmd_t *cmd;
2547c478bd9Sstevel@tonic-gate 	int i;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	for (cmd = inj_list_next(prog); cmd != NULL; cmd = inj_list_next(cmd)) {
2577c478bd9Sstevel@tonic-gate 		if (cmd->cmd_type == CMD_REPEAT) {
2587c478bd9Sstevel@tonic-gate 			for (i = 1; i <= cmd->cmd_num; i++) {
2597c478bd9Sstevel@tonic-gate 				if (verbose) {
2607c478bd9Sstevel@tonic-gate 					(void) printf("(repeat %d of %d)\n",
2617c478bd9Sstevel@tonic-gate 					    i, cmd->cmd_num);
2627c478bd9Sstevel@tonic-gate 				}
2637c478bd9Sstevel@tonic-gate 				cmd_run(mode, hdl, cmd->cmd_subcmd);
2647c478bd9Sstevel@tonic-gate 			}
2657c478bd9Sstevel@tonic-gate 		} else
2667c478bd9Sstevel@tonic-gate 			cmd_run(mode, hdl, cmd);
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	mode->mo_close(hdl);
2707c478bd9Sstevel@tonic-gate }
271