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
38 static opt_t opt;
39 opt_t *op;
40
41 static char path[64];
42
43 static void
usage(const char * where)44 usage(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
63 static int
time2sec(const char * string)64 time2sec(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
gete(const char * name)83 static 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
95 static void
environment(void)96 environment(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
140 void
options(int argc,char ** argv)141 options(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
205 void
show_status(void)206 show_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
227 void
rmval(void)228 rmval(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
236 void
putval(unsigned long v)237 putval(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
247 unsigned long
getval(void)248 getval(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