1/*-
2 * Copyright (c) 2008 Peter Holm <pho@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <unistd.h>
31#include <sysexits.h>
32#include <string.h>
33#include <time.h>
34#include <err.h>
35
36#include "stress.h"
37
38static opt_t opt;
39opt_t *op;
40
41static char path[64];
42
43static void
44usage(const char *where)
45{
46	const char *help;
47
48	if (where != NULL)
49		printf("Error in \"%s\"\n", where);
50	fprintf(stderr, "Usage: %s [-t | -l | -i | -d | -h | -k | -v]\n", getprogname());
51	help =  " t <number><s|m|h|d> : time to run test\n"
52		" l <pct>             : load factor 0 - 100%\n"
53		" i <number>          : max # of parallel incarnations\n"
54		" d <path>            : working directory\n"
55		" h                   : hog resources\n"
56		" k                   : terminate with SIGHUP + SIGKILL\n"
57		" n                   : no startup delay\n"
58		" v                   : verbose\n";
59	printf("%s", help);
60	exit(EX_USAGE);
61}
62
63static int
64time2sec(const char *string)
65{
66	int r, s = 0;
67	char modifier;
68	r = sscanf(string, "%d%c", &s, &modifier);
69	if (r == 2)
70		switch(modifier) {
71		case 's': break;
72		case 'm': s = s * 60; break;
73		case 'h': s = s * 60 * 60; break;
74		case 'd': s = s * 60 * 60 * 24; break;
75		default:
76			usage("-t");
77		}
78	else
79		usage("-t");
80	return (s);
81}
82
83static char *gete(const char *name)
84{
85	char *cp;
86	char help[128];
87
88	snprintf(help, sizeof(help), "%s%s", getprogname(), name);
89	cp = getenv(help);
90	if (cp == NULL)
91		cp = getenv(name);
92	return (cp);
93}
94
95static void
96environment(void)
97{
98	char *cp;
99
100	if ((cp = gete("INCARNATIONS")) != NULL) {
101		if (sscanf(cp, "%d", &op->incarnations) != 1)
102			usage("INCARNATIONS");
103	}
104	if ((cp = gete("LOAD")) != NULL) {
105		if (sscanf(cp, "%d", &op->load) != 1)
106			usage("LOAD");
107	}
108	if ((cp = gete("RUNTIME")) != NULL) {
109		op->run_time = time2sec(cp);
110	}
111	if ((cp = gete("RUNDIR")) != NULL) {
112		op->wd = cp;
113	}
114	if ((cp = gete("CTRLDIR")) != NULL) {
115		op->cd = cp;
116	}
117	if ((cp = gete("HOG")) != NULL) {
118		op->hog = 1;
119	}
120	if ((cp = gete("KILL")) != NULL) {
121		op->kill = 1;
122	}
123	if ((cp = gete("NODELAY")) != NULL) {
124		op->nodelay = 1;
125	}
126	if ((cp = gete("VERBOSE")) != NULL) {
127		if (sscanf(cp, "%d", &op->verbose) != 1)
128			usage("VERBOSE");
129	}
130	if ((cp = gete("KBLOCKS")) != NULL) {
131		if (sscanf(cp, "%jd", &op->kblocks) != 1)
132			usage("KBLOCKS");
133	}
134	if ((cp = gete("INODES")) != NULL) {
135		if (sscanf(cp, "%jd", &op->inodes) != 1)
136			usage("INODES");
137	}
138}
139
140void
141options(int argc, char **argv)
142{
143	int ch;
144
145	op = &opt;
146
147	op->run_time	= 60;
148	op->load	= 100;
149	op->wd		= strdup("/tmp/stressX");
150	op->cd		= strdup("/tmp/stressX.control");
151	op->incarnations	= 1;
152	op->hog		= 0;
153	op->kill	= 0;
154	op->nodelay	= 0;
155	op->verbose	= 0;
156	op->kblocks	= 0;
157	op->inodes	= 0;
158
159	environment();
160
161	while ((ch = getopt(argc, argv, "t:l:i:d:hknv")) != -1)
162		switch(ch) {
163		case 't':	/* run time */
164			op->run_time = time2sec(optarg);
165			break;
166		case 'l':	/* load factor in pct */
167			if (sscanf(optarg, "%d", &op->load) != 1)
168				usage("-l");
169			break;
170		case 'i':	/* max incarnations */
171			if (sscanf(optarg, "%d", &op->incarnations) != 1)
172				usage("-i");
173			break;
174		case 'd':	/* working directory */
175			op->wd = strdup(optarg);
176			break;
177		case 'h':	/* hog flag */
178			op->hog += 1;
179			break;
180		case 'k':	/* kill flag */
181			op->kill = 1;
182			break;
183		case 'n':	/* no delay flag */
184			op->nodelay = 1;
185			break;
186		case 'v':	/* verbose flag */
187			op->verbose += 1;
188			break;
189		default:
190			usage(NULL);
191		}
192	op->argc = argc -= optind;
193	op->argv = argv += optind;
194
195	if (op->incarnations < 1)
196		op->incarnations = 1;
197	if (op->hog == 0)
198		op->incarnations = random_int(1, op->incarnations);
199	if (op->run_time < 15)
200		op->run_time = 15;
201	if (op->load < 0 || op->load > 100)
202		op->load = 100;
203}
204
205void
206show_status(void)
207{
208	char buf[80], pgname[9];
209	int days;
210	time_t t;
211
212	if (op->verbose > 0) {
213		strncpy(pgname, getprogname(), sizeof(pgname));
214		pgname[8] = 0;
215		t = op->run_time;
216		days = t / (60 * 60 * 24);
217		t = t % (60 * 60 * 24);
218		strftime(buf, sizeof(buf), "%T", gmtime(&t));
219		printf("%8s: run time %2d+%s, incarnations %3d, load %3d, "
220			"verbose %d\n",
221			pgname, days, buf, op->incarnations, op->load,
222			op->verbose);
223		fflush(stdout);
224	}
225}
226
227void
228rmval(void)
229{
230	if (snprintf(path, sizeof(path), "%s/%s.conf", op->cd,
231	    getprogname()) < 0)
232		err(1, "snprintf path");
233	(void) unlink(path);
234}
235
236void
237putval(unsigned long v)
238{
239	char buf[64];
240
241	rmval();
242	snprintf(buf, sizeof(buf), "%lu", v);
243	if (symlink(buf, path) < 0)
244		err(1, "symlink(%s, %s)", path, buf);
245}
246
247unsigned long
248getval(void)
249{
250	int i, n;
251	unsigned long val;
252	char buf[64];
253
254	if ((n = readlink(path, buf, sizeof(buf) -1)) < 0) {
255		for (i = 0; i < 60; i++) {
256			sleep(1);
257			if ((n = readlink(path, buf, sizeof(buf) -1)) > 0)
258				break;
259		}
260		if (n < 0)
261			err(1, "readlink(%s). %s:%d", path, __FILE__,
262			    __LINE__);
263	}
264	buf[n] = '\0';
265	if (sscanf(buf, "%ld", &val) != 1)
266		err(1, "sscanf(%s)", buf);
267	return val;
268}
269