xref: /onnv-gate/usr/src/cmd/filebench/common/parser_gram.y (revision 5184:da60d2b4a9e2)
1*5184Sek110237 
2*5184Sek110237 /*
3*5184Sek110237  * CDDL HEADER START
4*5184Sek110237  *
5*5184Sek110237  * The contents of this file are subject to the terms of the
6*5184Sek110237  * Common Development and Distribution License (the "License").
7*5184Sek110237  * You may not use this file except in compliance with the License.
8*5184Sek110237  *
9*5184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*5184Sek110237  * or http://www.opensolaris.org/os/licensing.
11*5184Sek110237  * See the License for the specific language governing permissions
12*5184Sek110237  * and limitations under the License.
13*5184Sek110237  *
14*5184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
15*5184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*5184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
17*5184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
18*5184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
19*5184Sek110237  *
20*5184Sek110237  * CDDL HEADER END
21*5184Sek110237  */
22*5184Sek110237 /*
23*5184Sek110237  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*5184Sek110237  * Use is subject to license terms.
25*5184Sek110237  */
26*5184Sek110237 
27*5184Sek110237 %{
28*5184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29*5184Sek110237 %}
30*5184Sek110237 
31*5184Sek110237 %{
32*5184Sek110237 
33*5184Sek110237 #include <stdlib.h>
34*5184Sek110237 #include <stdio.h>
35*5184Sek110237 #include <string.h>
36*5184Sek110237 #include <signal.h>
37*5184Sek110237 #include <errno.h>
38*5184Sek110237 #include <sys/types.h>
39*5184Sek110237 #include <locale.h>
40*5184Sek110237 #include <sys/utsname.h>
41*5184Sek110237 #ifdef HAVE_STDINT_H
42*5184Sek110237 #include <stdint.h>
43*5184Sek110237 #endif
44*5184Sek110237 #include <fcntl.h>
45*5184Sek110237 #include <sys/mman.h>
46*5184Sek110237 #include <sys/wait.h>
47*5184Sek110237 #ifdef HAVE_LIBTECLA
48*5184Sek110237 #include <libtecla.h>
49*5184Sek110237 #endif
50*5184Sek110237 #include "parsertypes.h"
51*5184Sek110237 #include "filebench.h"
52*5184Sek110237 #include "utils.h"
53*5184Sek110237 #include "stats.h"
54*5184Sek110237 #include "vars.h"
55*5184Sek110237 #include "eventgen.h"
56*5184Sek110237 #ifdef HAVE_LIBTECLA
57*5184Sek110237 #include "auto_comp.h"
58*5184Sek110237 #endif
59*5184Sek110237 
60*5184Sek110237 int dofile = FS_FALSE;
61*5184Sek110237 static const char cmdname[] = "filebench";
62*5184Sek110237 static const char cmd_options[] = "pa:f:hi:s:m:";
63*5184Sek110237 static void usage(int);
64*5184Sek110237 
65*5184Sek110237 static cmd_t *cmd = NULL;		/* Command being processed */
66*5184Sek110237 #ifdef HAVE_LIBTECLA
67*5184Sek110237 static GetLine *gl;			/* GetLine resource object */
68*5184Sek110237 #endif
69*5184Sek110237 
70*5184Sek110237 char *execname;
71*5184Sek110237 char *fscriptname;
72*5184Sek110237 int noproc = 0;
73*5184Sek110237 var_t *var_list = NULL;
74*5184Sek110237 pidlist_t *pidlist = NULL;
75*5184Sek110237 char *cwd = NULL;
76*5184Sek110237 FILE *parentscript = NULL;
77*5184Sek110237 
78*5184Sek110237 /* yacc externals */
79*5184Sek110237 extern FILE *yyin;
80*5184Sek110237 extern int yydebug;
81*5184Sek110237 extern void yyerror(char *s);
82*5184Sek110237 
83*5184Sek110237 /* utilities */
84*5184Sek110237 static void terminate(void);
85*5184Sek110237 static cmd_t *alloc_cmd(void);
86*5184Sek110237 static attr_t *alloc_attr(void);
87*5184Sek110237 static attr_t *get_attr(cmd_t *cmd, int64_t name);
88*5184Sek110237 static attr_t *get_attr_integer(cmd_t *cmd, int64_t name);
89*5184Sek110237 static attr_t *get_attr_bool(cmd_t *cmd, int64_t name);
90*5184Sek110237 static var_t *alloc_var(void);
91*5184Sek110237 static var_t *get_var(cmd_t *cmd, int64_t name);
92*5184Sek110237 static list_t *alloc_list();
93*5184Sek110237 
94*5184Sek110237 /* Info Commands */
95*5184Sek110237 static void parser_show(cmd_t *);
96*5184Sek110237 static void parser_list(cmd_t *);
97*5184Sek110237 
98*5184Sek110237 /* Define Commands */
99*5184Sek110237 static void parser_proc_define(cmd_t *);
100*5184Sek110237 static void parser_thread_define(cmd_t *, procflow_t *, int instances);
101*5184Sek110237 static void parser_flowop_define(cmd_t *, threadflow_t *);
102*5184Sek110237 static void parser_file_define(cmd_t *);
103*5184Sek110237 static void parser_fileset_define(cmd_t *);
104*5184Sek110237 
105*5184Sek110237 /* Create Commands */
106*5184Sek110237 static void parser_proc_create(cmd_t *);
107*5184Sek110237 static void parser_thread_create(cmd_t *);
108*5184Sek110237 static void parser_flowop_create(cmd_t *);
109*5184Sek110237 static void parser_file_create(cmd_t *);
110*5184Sek110237 static void parser_fileset_create(cmd_t *);
111*5184Sek110237 
112*5184Sek110237 /* Shutdown Commands */
113*5184Sek110237 static void parser_proc_shutdown(cmd_t *);
114*5184Sek110237 static void parser_filebench_shutdown(cmd_t *cmd);
115*5184Sek110237 
116*5184Sek110237 /* Other Commands */
117*5184Sek110237 static void parser_foreach_integer(cmd_t *cmd);
118*5184Sek110237 static void parser_foreach_string(cmd_t *cmd);
119*5184Sek110237 static void parser_sleep(cmd_t *cmd);
120*5184Sek110237 static void parser_sleep_variable(cmd_t *cmd);
121*5184Sek110237 static void parser_log(cmd_t *cmd);
122*5184Sek110237 static void parser_statscmd(cmd_t *cmd);
123*5184Sek110237 static void parser_statsdump(cmd_t *cmd);
124*5184Sek110237 static void parser_statsxmldump(cmd_t *cmd);
125*5184Sek110237 static void parser_echo(cmd_t *cmd);
126*5184Sek110237 static void parser_usage(cmd_t *cmd);
127*5184Sek110237 static void parser_vars(cmd_t *cmd);
128*5184Sek110237 static void parser_printvars(cmd_t *cmd);
129*5184Sek110237 static void parser_system(cmd_t *cmd);
130*5184Sek110237 static void parser_statssnap(cmd_t *cmd);
131*5184Sek110237 static void parser_directory(cmd_t *cmd);
132*5184Sek110237 static void parser_eventgen(cmd_t *cmd);
133*5184Sek110237 static void parser_run(cmd_t *cmd);
134*5184Sek110237 static void parser_run_variable(cmd_t *cmd);
135*5184Sek110237 static void parser_help(cmd_t *cmd);
136*5184Sek110237 static void arg_parse(const char *command);
137*5184Sek110237 static void parser_abort(int arg);
138*5184Sek110237 
139*5184Sek110237 %}
140*5184Sek110237 
141*5184Sek110237 %union {
142*5184Sek110237 	int64_t	 ival;
143*5184Sek110237 	uchar_t  bval;
144*5184Sek110237 	char *	 sval;
145*5184Sek110237 	fs_u	 val;
146*5184Sek110237 	cmd_t	 *cmd;
147*5184Sek110237 	attr_t	 *attr;
148*5184Sek110237 	list_t	 *list;
149*5184Sek110237 }
150*5184Sek110237 
151*5184Sek110237 %start commands
152*5184Sek110237 
153*5184Sek110237 %token FSC_LIST FSC_DEFINE FSC_EXEC FSC_QUIT FSC_DEBUG FSC_CREATE
154*5184Sek110237 %token FSC_SLEEP FSC_STATS FSC_FOREACH FSC_SET FSC_SHUTDOWN FSC_LOG
155*5184Sek110237 %token FSC_SYSTEM FSC_FLOWOP FSC_EVENTGEN FSC_ECHO FSC_LOAD FSC_RUN
156*5184Sek110237 %token FSC_USAGE FSC_HELP FSC_VARS
157*5184Sek110237 %token FSV_STRING FSV_VAL_INT FSV_VAL_BOOLEAN FSV_VARIABLE FSV_WHITESTRING
158*5184Sek110237 %token FST_INT FST_BOOLEAN
159*5184Sek110237 %token FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSE_ALL FSE_SNAP FSE_DUMP
160*5184Sek110237 %token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP
161*5184Sek110237 %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_ASSIGN FSK_IN FSK_QUOTE
162*5184Sek110237 %token FSK_DIRSEPLST
163*5184Sek110237 %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE
164*5184Sek110237 %token FSA_PROCESS FSA_MEMSIZE FSA_RATE FSA_CACHED
165*5184Sek110237 %token FSA_IOSIZE FSA_FILE FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES
166*5184Sek110237 %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING
167*5184Sek110237 %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD
168*5184Sek110237 %token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA
169*5184Sek110237 %token FSA_DIRGAMMA FSA_USEISM
170*5184Sek110237 
171*5184Sek110237 %type <ival> FSV_VAL_INT
172*5184Sek110237 %type <bval> FSV_VAL_BOOLEAN
173*5184Sek110237 %type <sval> FSV_STRING
174*5184Sek110237 %type <sval> FSV_WHITESTRING
175*5184Sek110237 %type <sval> FSV_VARIABLE
176*5184Sek110237 %type <sval> FSK_ASSIGN
177*5184Sek110237 
178*5184Sek110237 %type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN
179*5184Sek110237 %type <ival> FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSC_HELP
180*5184Sek110237 
181*5184Sek110237 %type <sval> name
182*5184Sek110237 %type <ival> entity
183*5184Sek110237 %type <val>  value
184*5184Sek110237 
185*5184Sek110237 %type <cmd> command inner_commands load_command run_command
186*5184Sek110237 %type <cmd> list_command define_command debug_command create_command
187*5184Sek110237 %type <cmd> sleep_command stats_command set_command shutdown_command
188*5184Sek110237 %type <cmd> foreach_command log_command system_command flowop_command
189*5184Sek110237 %type <cmd> eventgen_command quit_command flowop_list thread_list
190*5184Sek110237 %type <cmd> thread echo_command usage_command help_command vars_command
191*5184Sek110237 
192*5184Sek110237 %type <attr> attr_op attr_ops
193*5184Sek110237 %type <attr> attr_value
194*5184Sek110237 %type <list> integer_seplist string_seplist string_list var_string_list var_string
195*5184Sek110237 %type <list> whitevar_string whitevar_string_list
196*5184Sek110237 %type <ival> attrs_define_file attrs_define_thread attrs_flowop attrs_define_fileset
197*5184Sek110237 %type <ival> attrs_define_proc attrs_eventgen
198*5184Sek110237 %type <ival> attr_name
199*5184Sek110237 
200*5184Sek110237 %%
201*5184Sek110237 
202*5184Sek110237 commands: commands command
203*5184Sek110237 {
204*5184Sek110237 	list_t *list = NULL;
205*5184Sek110237 	list_t *list_end = NULL;
206*5184Sek110237 
207*5184Sek110237 	if ($2->cmd != NULL)
208*5184Sek110237 		$2->cmd($2);
209*5184Sek110237 
210*5184Sek110237 	free($2);
211*5184Sek110237 }
212*5184Sek110237 | commands error
213*5184Sek110237 {
214*5184Sek110237 	if (dofile)
215*5184Sek110237 		YYABORT;
216*5184Sek110237 }
217*5184Sek110237 |;
218*5184Sek110237 
219*5184Sek110237 inner_commands: command
220*5184Sek110237 {
221*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "inner_command %zx", $1);
222*5184Sek110237 	$$ = $1;
223*5184Sek110237 }
224*5184Sek110237 | inner_commands command
225*5184Sek110237 {
226*5184Sek110237 	cmd_t *list = NULL;
227*5184Sek110237 	cmd_t *list_end = NULL;
228*5184Sek110237 
229*5184Sek110237 	/* Find end of list */
230*5184Sek110237 	for (list = $1; list != NULL;
231*5184Sek110237 	    list = list->cmd_next)
232*5184Sek110237 		list_end = list;
233*5184Sek110237 
234*5184Sek110237 	list_end->cmd_next = $2;
235*5184Sek110237 
236*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
237*5184Sek110237 	    "inner_commands adding cmd %zx to list %zx", $2, $1);
238*5184Sek110237 
239*5184Sek110237 	$$ = $1;
240*5184Sek110237 };
241*5184Sek110237 
242*5184Sek110237 command:
243*5184Sek110237   define_command
244*5184Sek110237 | debug_command
245*5184Sek110237 | eventgen_command
246*5184Sek110237 | create_command
247*5184Sek110237 | echo_command
248*5184Sek110237 | usage_command
249*5184Sek110237 | vars_command
250*5184Sek110237 | foreach_command
251*5184Sek110237 | help_command
252*5184Sek110237 | list_command
253*5184Sek110237 | load_command
254*5184Sek110237 | log_command
255*5184Sek110237 | run_command
256*5184Sek110237 | set_command
257*5184Sek110237 | shutdown_command
258*5184Sek110237 | sleep_command
259*5184Sek110237 | stats_command
260*5184Sek110237 | system_command
261*5184Sek110237 | quit_command;
262*5184Sek110237 
263*5184Sek110237 foreach_command: FSC_FOREACH
264*5184Sek110237 {
265*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
266*5184Sek110237 		YYERROR;
267*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "foreach_command %zx", $$);
268*5184Sek110237 }
269*5184Sek110237 | foreach_command FSV_VARIABLE FSK_IN integer_seplist FSK_OPENLST inner_commands FSK_CLOSELST
270*5184Sek110237 {
271*5184Sek110237 	cmd_t *cmd, *inner_cmd;
272*5184Sek110237 	list_t *list;
273*5184Sek110237 
274*5184Sek110237 	$$ = $1;
275*5184Sek110237 	$$->cmd_list = $6;
276*5184Sek110237 	$$->cmd_tgt1 = $2;
277*5184Sek110237 	$$->cmd_param_list = $4;
278*5184Sek110237 	$$->cmd = parser_foreach_integer;
279*5184Sek110237 
280*5184Sek110237 	for (list = $$->cmd_param_list; list != NULL;
281*5184Sek110237 	    list = list->list_next) {
282*5184Sek110237 		for (inner_cmd = $$->cmd_list;
283*5184Sek110237 		    inner_cmd != NULL;
284*5184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
285*5184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
286*5184Sek110237 			    "packing foreach: %zx %s=%lld, cmd %zx",
287*5184Sek110237 			    $$,
288*5184Sek110237 			    $$->cmd_tgt1,
289*5184Sek110237 			    *list->list_integer, inner_cmd);
290*5184Sek110237 		}
291*5184Sek110237 	}
292*5184Sek110237 }| foreach_command FSV_VARIABLE FSK_IN string_seplist FSK_OPENLST inner_commands FSK_CLOSELST
293*5184Sek110237 {
294*5184Sek110237 	cmd_t *cmd, *inner_cmd;
295*5184Sek110237 	list_t *list;
296*5184Sek110237 
297*5184Sek110237 	$$ = $1;
298*5184Sek110237 	$$->cmd_list = $6;
299*5184Sek110237 	$$->cmd_tgt1 = $2;
300*5184Sek110237 	$$->cmd_param_list = $4;
301*5184Sek110237 	$$->cmd = parser_foreach_string;
302*5184Sek110237 
303*5184Sek110237 	for (list = $$->cmd_param_list; list != NULL;
304*5184Sek110237 	    list = list->list_next) {
305*5184Sek110237 		for (inner_cmd = $$->cmd_list;
306*5184Sek110237 		    inner_cmd != NULL;
307*5184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
308*5184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
309*5184Sek110237 			    "packing foreach: %zx %s=%s, cmd %zx",
310*5184Sek110237 			    $$,
311*5184Sek110237 			    $$->cmd_tgt1,
312*5184Sek110237 			    *list->list_string, inner_cmd);
313*5184Sek110237 		}
314*5184Sek110237 	}
315*5184Sek110237 };
316*5184Sek110237 
317*5184Sek110237 integer_seplist: FSV_VAL_INT
318*5184Sek110237 {
319*5184Sek110237 	if (($$ = alloc_list()) == NULL)
320*5184Sek110237 		YYERROR;
321*5184Sek110237 
322*5184Sek110237 	$$->list_integer = integer_alloc($1);
323*5184Sek110237 }
324*5184Sek110237 | integer_seplist FSK_SEPLST FSV_VAL_INT
325*5184Sek110237 {
326*5184Sek110237 	list_t *list = NULL;
327*5184Sek110237 	list_t *list_end = NULL;
328*5184Sek110237 
329*5184Sek110237 	if (($$ = alloc_list()) == NULL)
330*5184Sek110237 		YYERROR;
331*5184Sek110237 
332*5184Sek110237 	$$->list_integer = integer_alloc($3);
333*5184Sek110237 
334*5184Sek110237 	/* Find end of list */
335*5184Sek110237 	for (list = $1; list != NULL;
336*5184Sek110237 	    list = list->list_next)
337*5184Sek110237 		list_end = list;
338*5184Sek110237 	list_end->list_next = $$;
339*5184Sek110237 	$$ = $1;
340*5184Sek110237 };
341*5184Sek110237 
342*5184Sek110237 string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
343*5184Sek110237 {
344*5184Sek110237 	if (($$ = alloc_list()) == NULL)
345*5184Sek110237 		YYERROR;
346*5184Sek110237 
347*5184Sek110237 	$$->list_string = string_alloc($2);
348*5184Sek110237 }
349*5184Sek110237 | string_seplist FSK_SEPLST FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
350*5184Sek110237 {
351*5184Sek110237 	list_t *list = NULL;
352*5184Sek110237 	list_t *list_end = NULL;
353*5184Sek110237 
354*5184Sek110237 	if (($$ = alloc_list()) == NULL)
355*5184Sek110237 			YYERROR;
356*5184Sek110237 
357*5184Sek110237 	$$->list_string = string_alloc($4);
358*5184Sek110237 
359*5184Sek110237 	/* Find end of list */
360*5184Sek110237 	for (list = $1; list != NULL;
361*5184Sek110237 	    list = list->list_next)
362*5184Sek110237 		list_end = list;
363*5184Sek110237 	list_end->list_next = $$;
364*5184Sek110237 	$$ = $1;
365*5184Sek110237 };
366*5184Sek110237 
367*5184Sek110237 eventgen_command: FSC_EVENTGEN
368*5184Sek110237 {
369*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
370*5184Sek110237 		YYERROR;
371*5184Sek110237 	$$->cmd = &parser_eventgen;
372*5184Sek110237 }
373*5184Sek110237 | eventgen_command attr_ops
374*5184Sek110237 {
375*5184Sek110237 	$1->cmd_attr_list = $2;
376*5184Sek110237 };
377*5184Sek110237 
378*5184Sek110237 system_command: FSC_SYSTEM whitevar_string_list
379*5184Sek110237 {
380*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
381*5184Sek110237 		YYERROR;
382*5184Sek110237 
383*5184Sek110237 	$$->cmd_param_list = $2;
384*5184Sek110237 	$$->cmd = parser_system;
385*5184Sek110237 };
386*5184Sek110237 
387*5184Sek110237 echo_command: FSC_ECHO whitevar_string_list
388*5184Sek110237 {
389*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
390*5184Sek110237 		YYERROR;
391*5184Sek110237 
392*5184Sek110237 	$$->cmd_param_list = $2;
393*5184Sek110237 	$$->cmd = parser_echo;
394*5184Sek110237 };
395*5184Sek110237 
396*5184Sek110237 usage_command: FSC_USAGE whitevar_string_list
397*5184Sek110237 {
398*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
399*5184Sek110237 		YYERROR;
400*5184Sek110237 
401*5184Sek110237 	$$->cmd_param_list = $2;
402*5184Sek110237 	$$->cmd = parser_usage;
403*5184Sek110237 };
404*5184Sek110237 
405*5184Sek110237 vars_command: FSC_VARS
406*5184Sek110237 {
407*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
408*5184Sek110237 		YYERROR;
409*5184Sek110237 
410*5184Sek110237 	$$->cmd = parser_printvars;
411*5184Sek110237 };
412*5184Sek110237 
413*5184Sek110237 string_list: FSV_VARIABLE
414*5184Sek110237 {
415*5184Sek110237 	if (($$ = alloc_list()) == NULL)
416*5184Sek110237 			YYERROR;
417*5184Sek110237 
418*5184Sek110237 	$$->list_string = string_alloc($1);
419*5184Sek110237 }
420*5184Sek110237 | string_list FSK_SEPLST FSV_VARIABLE
421*5184Sek110237 {
422*5184Sek110237 	list_t *list = NULL;
423*5184Sek110237 	list_t *list_end = NULL;
424*5184Sek110237 
425*5184Sek110237 	if (($$ = alloc_list()) == NULL)
426*5184Sek110237 		YYERROR;
427*5184Sek110237 
428*5184Sek110237 	$$->list_string = string_alloc($3);
429*5184Sek110237 
430*5184Sek110237 	/* Find end of list */
431*5184Sek110237 	for (list = $1; list != NULL;
432*5184Sek110237 	    list = list->list_next)
433*5184Sek110237 		list_end = list;
434*5184Sek110237 	list_end->list_next = $$;
435*5184Sek110237 	$$ = $1;
436*5184Sek110237 };
437*5184Sek110237 
438*5184Sek110237 var_string: FSV_VARIABLE
439*5184Sek110237 {
440*5184Sek110237 	if (($$ = alloc_list()) == NULL)
441*5184Sek110237 			YYERROR;
442*5184Sek110237 
443*5184Sek110237 	$$->list_string = string_alloc($1);
444*5184Sek110237 }
445*5184Sek110237 | FSV_STRING
446*5184Sek110237 {
447*5184Sek110237 	if (($$ = alloc_list()) == NULL)
448*5184Sek110237 			YYERROR;
449*5184Sek110237 
450*5184Sek110237 	$$->list_string = string_alloc($1);
451*5184Sek110237 };
452*5184Sek110237 
453*5184Sek110237 var_string_list: var_string
454*5184Sek110237 {
455*5184Sek110237 	$$ = $1;
456*5184Sek110237 }| var_string FSV_STRING
457*5184Sek110237 {
458*5184Sek110237 	list_t *list = NULL;
459*5184Sek110237 	list_t *list_end = NULL;
460*5184Sek110237 
461*5184Sek110237 	/* Add string */
462*5184Sek110237 	if (($$ = alloc_list()) == NULL)
463*5184Sek110237 		YYERROR;
464*5184Sek110237 
465*5184Sek110237 	$$->list_string = string_alloc($2);
466*5184Sek110237 
467*5184Sek110237 	/* Find end of list */
468*5184Sek110237 	for (list = $1; list != NULL;
469*5184Sek110237 	    list = list->list_next)
470*5184Sek110237 		list_end = list;
471*5184Sek110237 	list_end->list_next = $$;
472*5184Sek110237 	$$ = $1;
473*5184Sek110237 
474*5184Sek110237 }| var_string FSV_VARIABLE
475*5184Sek110237 {
476*5184Sek110237 	list_t *list = NULL;
477*5184Sek110237 	list_t *list_end = NULL;
478*5184Sek110237 
479*5184Sek110237 	/* Add variable */
480*5184Sek110237 	if (($$ = alloc_list()) == NULL)
481*5184Sek110237 		YYERROR;
482*5184Sek110237 
483*5184Sek110237 	$$->list_string = string_alloc($2);
484*5184Sek110237 
485*5184Sek110237 	/* Find end of list */
486*5184Sek110237 	for (list = $1; list != NULL;
487*5184Sek110237 	    list = list->list_next)
488*5184Sek110237 		list_end = list;
489*5184Sek110237 	list_end->list_next = $$;
490*5184Sek110237 	$$ = $1;
491*5184Sek110237 } |var_string_list FSV_STRING
492*5184Sek110237 {
493*5184Sek110237 	list_t *list = NULL;
494*5184Sek110237 	list_t *list_end = NULL;
495*5184Sek110237 
496*5184Sek110237 	/* Add string */
497*5184Sek110237 	if (($$ = alloc_list()) == NULL)
498*5184Sek110237 		YYERROR;
499*5184Sek110237 
500*5184Sek110237 	$$->list_string = string_alloc($2);
501*5184Sek110237 
502*5184Sek110237 	/* Find end of list */
503*5184Sek110237 	for (list = $1; list != NULL;
504*5184Sek110237 	    list = list->list_next)
505*5184Sek110237 		list_end = list;
506*5184Sek110237 	list_end->list_next = $$;
507*5184Sek110237 	$$ = $1;
508*5184Sek110237 
509*5184Sek110237 }| var_string_list FSV_VARIABLE
510*5184Sek110237 {
511*5184Sek110237 	list_t *list = NULL;
512*5184Sek110237 	list_t *list_end = NULL;
513*5184Sek110237 
514*5184Sek110237 	/* Add variable */
515*5184Sek110237 	if (($$ = alloc_list()) == NULL)
516*5184Sek110237 		YYERROR;
517*5184Sek110237 
518*5184Sek110237 	$$->list_string = string_alloc($2);
519*5184Sek110237 
520*5184Sek110237 	/* Find end of list */
521*5184Sek110237 	for (list = $1; list != NULL;
522*5184Sek110237 	    list = list->list_next)
523*5184Sek110237 		list_end = list;
524*5184Sek110237 	list_end->list_next = $$;
525*5184Sek110237 	$$ = $1;
526*5184Sek110237 };
527*5184Sek110237 
528*5184Sek110237 whitevar_string: FSK_QUOTE FSV_VARIABLE
529*5184Sek110237 {
530*5184Sek110237 	if (($$ = alloc_list()) == NULL)
531*5184Sek110237 			YYERROR;
532*5184Sek110237 
533*5184Sek110237 	$$->list_string = string_alloc($2);
534*5184Sek110237 }
535*5184Sek110237 | FSK_QUOTE FSV_WHITESTRING
536*5184Sek110237 {
537*5184Sek110237 	if (($$ = alloc_list()) == NULL)
538*5184Sek110237 			YYERROR;
539*5184Sek110237 
540*5184Sek110237 	$$->list_string = string_alloc($2);
541*5184Sek110237 };
542*5184Sek110237 
543*5184Sek110237 whitevar_string_list: whitevar_string FSV_WHITESTRING
544*5184Sek110237 {
545*5184Sek110237 	list_t *list = NULL;
546*5184Sek110237 	list_t *list_end = NULL;
547*5184Sek110237 
548*5184Sek110237 	/* Add string */
549*5184Sek110237 	if (($$ = alloc_list()) == NULL)
550*5184Sek110237 		YYERROR;
551*5184Sek110237 
552*5184Sek110237 	$$->list_string = string_alloc($2);
553*5184Sek110237 
554*5184Sek110237 	/* Find end of list */
555*5184Sek110237 	for (list = $1; list != NULL;
556*5184Sek110237 	    list = list->list_next)
557*5184Sek110237 		list_end = list;
558*5184Sek110237 	list_end->list_next = $$;
559*5184Sek110237 	$$ = $1;
560*5184Sek110237 
561*5184Sek110237 }| whitevar_string FSV_VARIABLE
562*5184Sek110237 {
563*5184Sek110237 	list_t *list = NULL;
564*5184Sek110237 	list_t *list_end = NULL;
565*5184Sek110237 
566*5184Sek110237 	/* Add variable */
567*5184Sek110237 	if (($$ = alloc_list()) == NULL)
568*5184Sek110237 		YYERROR;
569*5184Sek110237 
570*5184Sek110237 	$$->list_string = string_alloc($2);
571*5184Sek110237 
572*5184Sek110237 	/* Find end of list */
573*5184Sek110237 	for (list = $1; list != NULL;
574*5184Sek110237 	    list = list->list_next)
575*5184Sek110237 		list_end = list;
576*5184Sek110237 	list_end->list_next = $$;
577*5184Sek110237 	$$ = $1;
578*5184Sek110237 } |whitevar_string_list FSV_WHITESTRING
579*5184Sek110237 {
580*5184Sek110237 	list_t *list = NULL;
581*5184Sek110237 	list_t *list_end = NULL;
582*5184Sek110237 
583*5184Sek110237 	/* Add string */
584*5184Sek110237 	if (($$ = alloc_list()) == NULL)
585*5184Sek110237 		YYERROR;
586*5184Sek110237 
587*5184Sek110237 	$$->list_string = string_alloc($2);
588*5184Sek110237 
589*5184Sek110237 	/* Find end of list */
590*5184Sek110237 	for (list = $1; list != NULL;
591*5184Sek110237 	    list = list->list_next)
592*5184Sek110237 		list_end = list;
593*5184Sek110237 	list_end->list_next = $$;
594*5184Sek110237 	$$ = $1;
595*5184Sek110237 
596*5184Sek110237 }| whitevar_string_list FSV_VARIABLE
597*5184Sek110237 {
598*5184Sek110237 	list_t *list = NULL;
599*5184Sek110237 	list_t *list_end = NULL;
600*5184Sek110237 
601*5184Sek110237 	/* Add variable */
602*5184Sek110237 	if (($$ = alloc_list()) == NULL)
603*5184Sek110237 		YYERROR;
604*5184Sek110237 
605*5184Sek110237 	$$->list_string = string_alloc($2);
606*5184Sek110237 
607*5184Sek110237 	/* Find end of list */
608*5184Sek110237 	for (list = $1; list != NULL;
609*5184Sek110237 	    list = list->list_next)
610*5184Sek110237 		list_end = list;
611*5184Sek110237 	list_end->list_next = $$;
612*5184Sek110237 	$$ = $1;
613*5184Sek110237 }| whitevar_string_list FSK_QUOTE
614*5184Sek110237 {
615*5184Sek110237 	$$ = $1;
616*5184Sek110237 }| whitevar_string FSK_QUOTE
617*5184Sek110237 {
618*5184Sek110237 	$$ = $1;
619*5184Sek110237 };
620*5184Sek110237 
621*5184Sek110237 list_command: FSC_LIST
622*5184Sek110237 {
623*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
624*5184Sek110237 		YYERROR;
625*5184Sek110237 	$$->cmd = &parser_list;
626*5184Sek110237 };
627*5184Sek110237 
628*5184Sek110237 log_command: FSC_LOG whitevar_string_list
629*5184Sek110237 {
630*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
631*5184Sek110237 		YYERROR;
632*5184Sek110237 	$$->cmd = &parser_log;
633*5184Sek110237 	$$->cmd_param_list = $2;
634*5184Sek110237 };
635*5184Sek110237 
636*5184Sek110237 debug_command: FSC_DEBUG FSV_VAL_INT
637*5184Sek110237 {
638*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
639*5184Sek110237 		YYERROR;
640*5184Sek110237 	$$->cmd = NULL;
641*5184Sek110237 	filebench_shm->debug_level = $2;
642*5184Sek110237 	if (filebench_shm->debug_level > 9)
643*5184Sek110237 		yydebug = 1;
644*5184Sek110237 };
645*5184Sek110237 
646*5184Sek110237 set_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT
647*5184Sek110237 {
648*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
649*5184Sek110237 		YYERROR;
650*5184Sek110237 	var_assign_integer($2, $4);
651*5184Sek110237 	if (parentscript) {
652*5184Sek110237 		$$->cmd_tgt1 = $2;
653*5184Sek110237 		parser_vars($$);
654*5184Sek110237 	}
655*5184Sek110237 	$$->cmd = NULL;
656*5184Sek110237 }
657*5184Sek110237 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
658*5184Sek110237 {
659*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
660*5184Sek110237 		YYERROR;
661*5184Sek110237 	var_assign_string($2, $5);
662*5184Sek110237 	if (parentscript) {
663*5184Sek110237 		$$->cmd_tgt1 = $2;
664*5184Sek110237 		parser_vars($$);
665*5184Sek110237 	}
666*5184Sek110237 	$$->cmd = NULL;
667*5184Sek110237 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_STRING
668*5184Sek110237 {
669*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
670*5184Sek110237 		YYERROR;
671*5184Sek110237 	var_assign_string($2, $4);
672*5184Sek110237 	if (parentscript) {
673*5184Sek110237 		$$->cmd_tgt1 = $2;
674*5184Sek110237 		parser_vars($$);
675*5184Sek110237 	}
676*5184Sek110237 	$$->cmd = NULL;
677*5184Sek110237 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
678*5184Sek110237 {
679*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
680*5184Sek110237 		YYERROR;
681*5184Sek110237 	var_assign_var($2, $4);
682*5184Sek110237 	if (parentscript) {
683*5184Sek110237 		$$->cmd_tgt1 = $2;
684*5184Sek110237 		parser_vars($$);
685*5184Sek110237 	}
686*5184Sek110237 	$$->cmd = NULL;
687*5184Sek110237 };
688*5184Sek110237 
689*5184Sek110237 stats_command: FSC_STATS FSE_SNAP
690*5184Sek110237 {
691*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
692*5184Sek110237 		YYERROR;
693*5184Sek110237 	$$->cmd = (void (*)(struct cmd *))&parser_statssnap;
694*5184Sek110237 	break;
695*5184Sek110237 
696*5184Sek110237 }
697*5184Sek110237 | FSC_STATS FSE_CLEAR
698*5184Sek110237 {
699*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
700*5184Sek110237 		YYERROR;
701*5184Sek110237 	$$->cmd = (void (*)(struct cmd *))&stats_clear;
702*5184Sek110237 
703*5184Sek110237 }
704*5184Sek110237 | FSC_STATS FSE_DIRECTORY var_string_list
705*5184Sek110237 {
706*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
707*5184Sek110237 		YYERROR;
708*5184Sek110237 	$$->cmd_param_list = $3;
709*5184Sek110237 	$$->cmd = (void (*)(struct cmd *))&parser_directory;
710*5184Sek110237 
711*5184Sek110237 }
712*5184Sek110237 | FSC_STATS FSE_COMMAND whitevar_string_list
713*5184Sek110237 {
714*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
715*5184Sek110237 		YYERROR;
716*5184Sek110237 
717*5184Sek110237 	$$->cmd_param_list = $3;
718*5184Sek110237 	$$->cmd = parser_statscmd;
719*5184Sek110237 
720*5184Sek110237 }| FSC_STATS FSE_DUMP whitevar_string_list
721*5184Sek110237 {
722*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
723*5184Sek110237 		YYERROR;
724*5184Sek110237 
725*5184Sek110237 	$$->cmd_param_list = $3;
726*5184Sek110237 	$$->cmd = parser_statsdump;
727*5184Sek110237 }| FSC_STATS FSE_XMLDUMP whitevar_string_list
728*5184Sek110237 {
729*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
730*5184Sek110237 		YYERROR;
731*5184Sek110237 
732*5184Sek110237 	$$->cmd_param_list = $3;
733*5184Sek110237 	$$->cmd = parser_statsxmldump;
734*5184Sek110237 };
735*5184Sek110237 
736*5184Sek110237 quit_command: FSC_QUIT
737*5184Sek110237 {
738*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
739*5184Sek110237 		YYERROR;
740*5184Sek110237 	$$->cmd = parser_filebench_shutdown;
741*5184Sek110237 };
742*5184Sek110237 
743*5184Sek110237 flowop_list: flowop_command
744*5184Sek110237 {
745*5184Sek110237 	$$ = $1;
746*5184Sek110237 }| flowop_list flowop_command
747*5184Sek110237 {
748*5184Sek110237 	cmd_t *list = NULL;
749*5184Sek110237 	cmd_t *list_end = NULL;
750*5184Sek110237 
751*5184Sek110237 	/* Find end of list */
752*5184Sek110237 	for (list = $1; list != NULL;
753*5184Sek110237 	    list = list->cmd_next)
754*5184Sek110237 		list_end = list;
755*5184Sek110237 
756*5184Sek110237 	list_end->cmd_next = $2;
757*5184Sek110237 
758*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
759*5184Sek110237 	    "flowop_list adding cmd %zx to list %zx", $2, $1);
760*5184Sek110237 
761*5184Sek110237 	$$ = $1;
762*5184Sek110237 };
763*5184Sek110237 
764*5184Sek110237 thread: FSE_THREAD attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
765*5184Sek110237 {
766*5184Sek110237 	/*
767*5184Sek110237 	 * Allocate a cmd node per thread, with a
768*5184Sek110237 	 * list of flowops attached to the cmd_list
769*5184Sek110237 	 */
770*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
771*5184Sek110237 		YYERROR;
772*5184Sek110237 	$$->cmd_list = $4;
773*5184Sek110237 	$$->cmd_attr_list = $2;
774*5184Sek110237 };
775*5184Sek110237 
776*5184Sek110237 thread_list: thread
777*5184Sek110237 {
778*5184Sek110237 	$$ = $1;
779*5184Sek110237 }| thread_list thread
780*5184Sek110237 {
781*5184Sek110237 	cmd_t *list = NULL;
782*5184Sek110237 	cmd_t *list_end = NULL;
783*5184Sek110237 
784*5184Sek110237 	/* Find end of list */
785*5184Sek110237 	for (list = $1; list != NULL;
786*5184Sek110237 	    list = list->cmd_next)
787*5184Sek110237 		list_end = list;
788*5184Sek110237 
789*5184Sek110237 	list_end->cmd_next = $2;
790*5184Sek110237 
791*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
792*5184Sek110237 	    "thread_list adding cmd %zx to list %zx", $2, $1);
793*5184Sek110237 
794*5184Sek110237 	$$ = $1;
795*5184Sek110237 };
796*5184Sek110237 
797*5184Sek110237 define_command: FSC_DEFINE FSE_PROC attr_ops FSK_OPENLST thread_list FSK_CLOSELST
798*5184Sek110237 {
799*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
800*5184Sek110237 		YYERROR;
801*5184Sek110237 	$$->cmd = &parser_proc_define;
802*5184Sek110237 	$$->cmd_list = $5;
803*5184Sek110237 	$$->cmd_attr_list = $3;
804*5184Sek110237 
805*5184Sek110237 }| FSC_DEFINE FSE_FILE
806*5184Sek110237 {
807*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
808*5184Sek110237 		YYERROR;
809*5184Sek110237 	$$->cmd = &parser_file_define;
810*5184Sek110237 }| FSC_DEFINE FSE_FILESET
811*5184Sek110237 {
812*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
813*5184Sek110237 		YYERROR;
814*5184Sek110237 	$$->cmd = &parser_fileset_define;
815*5184Sek110237 }
816*5184Sek110237 | define_command attr_ops
817*5184Sek110237 {
818*5184Sek110237 	$1->cmd_attr_list = $2;
819*5184Sek110237 };
820*5184Sek110237 
821*5184Sek110237 create_command: FSC_CREATE entity
822*5184Sek110237 {
823*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
824*5184Sek110237 		YYERROR;
825*5184Sek110237 	switch ($2) {
826*5184Sek110237 	case FSE_PROC:
827*5184Sek110237 		$$->cmd = &parser_proc_create;
828*5184Sek110237 		break;
829*5184Sek110237 	case FSE_FILE:
830*5184Sek110237 		$$->cmd = &parser_file_create;
831*5184Sek110237 		break;
832*5184Sek110237 	case FSE_FILESET:
833*5184Sek110237 		$$->cmd = &parser_fileset_create;
834*5184Sek110237 		break;
835*5184Sek110237 	default:
836*5184Sek110237 		filebench_log(LOG_ERROR, "unknown entity", $2);
837*5184Sek110237 		YYERROR;
838*5184Sek110237 	}
839*5184Sek110237 
840*5184Sek110237 };
841*5184Sek110237 
842*5184Sek110237 shutdown_command: FSC_SHUTDOWN entity
843*5184Sek110237 {
844*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
845*5184Sek110237 		YYERROR;
846*5184Sek110237 	switch ($2) {
847*5184Sek110237 	case FSE_PROC:
848*5184Sek110237 		$$->cmd = &parser_proc_shutdown;
849*5184Sek110237 		break;
850*5184Sek110237 	default:
851*5184Sek110237 		filebench_log(LOG_ERROR, "unknown entity", $2);
852*5184Sek110237 		YYERROR;
853*5184Sek110237 	}
854*5184Sek110237 
855*5184Sek110237 };
856*5184Sek110237 
857*5184Sek110237 sleep_command: FSC_SLEEP FSV_VAL_INT
858*5184Sek110237 {
859*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
860*5184Sek110237 		YYERROR;
861*5184Sek110237 	$$->cmd = parser_sleep;
862*5184Sek110237 	$$->cmd_qty = $2;
863*5184Sek110237 }
864*5184Sek110237 | FSC_SLEEP FSV_VARIABLE
865*5184Sek110237 {
866*5184Sek110237 	vinteger_t *integer;
867*5184Sek110237 
868*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
869*5184Sek110237 		YYERROR;
870*5184Sek110237 	$$->cmd = parser_sleep_variable;
871*5184Sek110237 	$$->cmd_tgt1 = fb_stralloc($2);
872*5184Sek110237 };
873*5184Sek110237 
874*5184Sek110237 run_command: FSC_RUN FSV_VAL_INT
875*5184Sek110237 {
876*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
877*5184Sek110237 		YYERROR;
878*5184Sek110237 	$$->cmd = parser_run;
879*5184Sek110237 	$$->cmd_qty = $2;
880*5184Sek110237 }
881*5184Sek110237 | FSC_RUN FSV_VARIABLE
882*5184Sek110237 {
883*5184Sek110237 	vinteger_t *integer;
884*5184Sek110237 
885*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
886*5184Sek110237 		YYERROR;
887*5184Sek110237 	$$->cmd = parser_run_variable;
888*5184Sek110237 	$$->cmd_tgt1 = fb_stralloc($2);
889*5184Sek110237 }
890*5184Sek110237 | FSC_RUN
891*5184Sek110237 {
892*5184Sek110237 	vinteger_t *integer;
893*5184Sek110237 
894*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
895*5184Sek110237 		YYERROR;
896*5184Sek110237 	$$->cmd = parser_run;
897*5184Sek110237 	$$->cmd_qty = 60UL;
898*5184Sek110237 };
899*5184Sek110237 
900*5184Sek110237 help_command: FSC_HELP
901*5184Sek110237 {
902*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
903*5184Sek110237 		YYERROR;
904*5184Sek110237 	$$->cmd = parser_help;
905*5184Sek110237 };
906*5184Sek110237 
907*5184Sek110237 flowop_command: FSC_FLOWOP name
908*5184Sek110237 {
909*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
910*5184Sek110237 		YYERROR;
911*5184Sek110237 	$$->cmd_name = fb_stralloc($2);
912*5184Sek110237 }
913*5184Sek110237 | flowop_command attr_ops
914*5184Sek110237 {
915*5184Sek110237 	$1->cmd_attr_list = $2;
916*5184Sek110237 };
917*5184Sek110237 
918*5184Sek110237 load_command: FSC_LOAD FSV_STRING
919*5184Sek110237 {
920*5184Sek110237 	FILE *newfile;
921*5184Sek110237 	char loadfile[128];
922*5184Sek110237 
923*5184Sek110237 	if (($$ = alloc_cmd()) == NULL)
924*5184Sek110237 		YYERROR;
925*5184Sek110237 
926*5184Sek110237 	(void) strcpy(loadfile, $2);
927*5184Sek110237 	(void) strcat(loadfile, ".f");
928*5184Sek110237 
929*5184Sek110237 	if ((newfile = fopen(loadfile, "r")) == NULL) {
930*5184Sek110237 		(void) strcpy(loadfile, FILEBENCHDIR);
931*5184Sek110237 		(void) strcat(loadfile, "/workloads/");
932*5184Sek110237 		(void) strcat(loadfile, $2);
933*5184Sek110237 		(void) strcat(loadfile, ".f");
934*5184Sek110237 		if ((newfile = fopen(loadfile, "r")) == NULL) {
935*5184Sek110237 			filebench_log(LOG_ERROR, "Cannot open %s", loadfile);
936*5184Sek110237 			YYERROR;
937*5184Sek110237 		}
938*5184Sek110237 	}
939*5184Sek110237 
940*5184Sek110237 	parentscript = yyin;
941*5184Sek110237 	yyin = newfile;
942*5184Sek110237 	yy_switchfileparent(yyin);
943*5184Sek110237 };
944*5184Sek110237 
945*5184Sek110237 entity: FSE_PROC {$$ = FSE_PROC;}
946*5184Sek110237 | FSE_THREAD {$$ = FSE_THREAD;}
947*5184Sek110237 | FSE_FILESET {$$ = FSE_FILESET;}
948*5184Sek110237 | FSE_FILE {$$ = FSE_FILE;};
949*5184Sek110237 
950*5184Sek110237 value: FSV_VAL_INT { $$.i = $1;}
951*5184Sek110237 | FSV_STRING { $$.s = $1;}
952*5184Sek110237 | FSV_VAL_BOOLEAN { $$.b = $1;};
953*5184Sek110237 
954*5184Sek110237 name: FSV_STRING;
955*5184Sek110237 
956*5184Sek110237 attr_ops: attr_op
957*5184Sek110237 {
958*5184Sek110237 	$$ = $1;
959*5184Sek110237 }
960*5184Sek110237 | attr_ops FSK_SEPLST attr_op
961*5184Sek110237 {
962*5184Sek110237 	attr_t *attr = NULL;
963*5184Sek110237 	attr_t *list_end = NULL;
964*5184Sek110237 
965*5184Sek110237 	for (attr = $1; attr != NULL;
966*5184Sek110237 	    attr = attr->attr_next)
967*5184Sek110237 		list_end = attr; /* Find end of list */
968*5184Sek110237 
969*5184Sek110237 	list_end->attr_next = $3;
970*5184Sek110237 
971*5184Sek110237 	$$ = $1;
972*5184Sek110237 };
973*5184Sek110237 
974*5184Sek110237 attr_op: attr_name FSK_ASSIGN attr_value
975*5184Sek110237 {
976*5184Sek110237 	$$ = $3;
977*5184Sek110237 	$$->attr_name = $1;
978*5184Sek110237 }
979*5184Sek110237 | attr_name
980*5184Sek110237 {
981*5184Sek110237 	if (($$ = alloc_attr()) == NULL)
982*5184Sek110237 		YYERROR;
983*5184Sek110237 	$$->attr_name = $1;
984*5184Sek110237 }
985*5184Sek110237 
986*5184Sek110237 attr_name: attrs_define_file
987*5184Sek110237 |attrs_define_fileset
988*5184Sek110237 |attrs_define_thread
989*5184Sek110237 |attrs_define_proc
990*5184Sek110237 |attrs_flowop
991*5184Sek110237 |attrs_eventgen;
992*5184Sek110237 
993*5184Sek110237 attrs_define_proc:
994*5184Sek110237 FSA_NICE { $$ = FSA_NICE;}
995*5184Sek110237 |FSA_INSTANCES { $$ = FSA_INSTANCES;};
996*5184Sek110237 
997*5184Sek110237 attrs_define_file:
998*5184Sek110237 FSA_SIZE { $$ = FSA_SIZE;}
999*5184Sek110237 | FSA_PATH { $$ = FSA_PATH;}
1000*5184Sek110237 | FSA_REUSE { $$ = FSA_REUSE;}
1001*5184Sek110237 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1002*5184Sek110237 | FSA_PARALLOC { $$ = FSA_PARALLOC;};
1003*5184Sek110237 
1004*5184Sek110237 attrs_define_fileset:
1005*5184Sek110237 FSA_SIZE { $$ = FSA_SIZE;}
1006*5184Sek110237 | FSA_PATH { $$ = FSA_PATH;}
1007*5184Sek110237 | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;}
1008*5184Sek110237 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
1009*5184Sek110237 | FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;}
1010*5184Sek110237 | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
1011*5184Sek110237 | FSA_CACHED { $$ = FSA_CACHED;}
1012*5184Sek110237 | FSA_ENTRIES { $$ = FSA_ENTRIES;};
1013*5184Sek110237 
1014*5184Sek110237 attrs_define_thread:
1015*5184Sek110237 FSA_PROCESS { $$ = FSA_PROCESS;}
1016*5184Sek110237 |FSA_MEMSIZE { $$ = FSA_MEMSIZE;}
1017*5184Sek110237 |FSA_USEISM { $$ = FSA_USEISM;}
1018*5184Sek110237 |FSA_INSTANCES { $$ = FSA_INSTANCES;};
1019*5184Sek110237 
1020*5184Sek110237 attrs_flowop:
1021*5184Sek110237 FSA_WSS { $$ = FSA_WSS;}
1022*5184Sek110237 |FSA_FILE { $$ = FSA_FILE;}
1023*5184Sek110237 |FSA_NAME { $$ = FSA_NAME;}
1024*5184Sek110237 |FSA_RANDOM { $$ = FSA_RANDOM;}
1025*5184Sek110237 |FSA_FD { $$ = FSA_FD;}
1026*5184Sek110237 |FSA_SRCFD { $$ = FSA_SRCFD;}
1027*5184Sek110237 |FSA_ROTATEFD { $$ = FSA_ROTATEFD;}
1028*5184Sek110237 |FSA_DSYNC { $$ = FSA_DSYNC;}
1029*5184Sek110237 |FSA_DIRECTIO { $$ = FSA_DIRECTIO;}
1030*5184Sek110237 |FSA_TARGET { $$ = FSA_TARGET;}
1031*5184Sek110237 |FSA_ITERS { $$ = FSA_ITERS;}
1032*5184Sek110237 |FSA_VALUE { $$ = FSA_VALUE;}
1033*5184Sek110237 |FSA_BLOCKING { $$ = FSA_BLOCKING;}
1034*5184Sek110237 |FSA_HIGHWATER { $$ = FSA_HIGHWATER;}
1035*5184Sek110237 |FSA_IOSIZE { $$ = FSA_IOSIZE;};
1036*5184Sek110237 
1037*5184Sek110237 attrs_eventgen:
1038*5184Sek110237 FSA_RATE { $$ = FSA_RATE;};
1039*5184Sek110237 
1040*5184Sek110237 attr_value: var_string_list {
1041*5184Sek110237 	if (($$ = alloc_attr()) == NULL)
1042*5184Sek110237 		YYERROR;
1043*5184Sek110237 	$$->attr_param_list = $1;
1044*5184Sek110237 } | FSV_STRING
1045*5184Sek110237 {
1046*5184Sek110237 	if (($$ = alloc_attr()) == NULL)
1047*5184Sek110237 		YYERROR;
1048*5184Sek110237 	$$->attr_string = string_alloc($1);
1049*5184Sek110237 } | FSV_VAL_INT {
1050*5184Sek110237 	if (($$ = alloc_attr()) == NULL)
1051*5184Sek110237 		YYERROR;
1052*5184Sek110237 	$$->attr_integer = integer_alloc($1);
1053*5184Sek110237 } | FSV_VARIABLE {
1054*5184Sek110237 	if (($$ = alloc_attr()) == NULL)
1055*5184Sek110237 		YYERROR;
1056*5184Sek110237 	$$->attr_integer = var_ref_integer($1);
1057*5184Sek110237 	$$->attr_string = var_ref_string($1);
1058*5184Sek110237 };
1059*5184Sek110237 
1060*5184Sek110237 %%
1061*5184Sek110237 
1062*5184Sek110237 /*
1063*5184Sek110237  *  The following 'c' routines implement the various commands defined in the
1064*5184Sek110237  * above yacc parser code. The yacc portion checks the syntax of the commands
1065*5184Sek110237  * found in a workload file, or typed on interactive command lines, parsing
1066*5184Sek110237  * the commands' parameters into lists. The lists are then passed in a cmd_t
1067*5184Sek110237  * struct for each command to its related routine in the following section
1068*5184Sek110237  * for actual execution. This section also includes a few utility routines
1069*5184Sek110237  * and the main entry point for the program.
1070*5184Sek110237  */
1071*5184Sek110237 
1072*5184Sek110237 /*
1073*5184Sek110237  * Entry point for filebench. Processes command line arguements. The -f
1074*5184Sek110237  * option will read in a workload file (the full name and extension must
1075*5184Sek110237  * must be given). The -a, -s, -m and -i options are used by worker process
1076*5184Sek110237  * to receive their name, the base address of shared memory, its path, and
1077*5184Sek110237  * the process' instance number, respectively. This information is supplied
1078*5184Sek110237  * by the master process when it execs worker processes under the process
1079*5184Sek110237  * model of execution. If the worker process arguments are passed then main
1080*5184Sek110237  * will call the procflow_exec routine which creates worker threadflows and
1081*5184Sek110237  * flowops and executes the procflow's portion of the workload model until
1082*5184Sek110237  * completion. If worker process arguments are not passed to the process,
1083*5184Sek110237  * then it becomes the master process for a filebench run. It initializes
1084*5184Sek110237  * the various filebench components and either executes the supplied workload
1085*5184Sek110237  * file, or enters interactive mode.
1086*5184Sek110237  */
1087*5184Sek110237 
1088*5184Sek110237 int
1089*5184Sek110237 main(int argc, char *argv[])
1090*5184Sek110237 {
1091*5184Sek110237 	int opt;
1092*5184Sek110237 	int docmd = FS_FALSE;
1093*5184Sek110237 	int instance;
1094*5184Sek110237 	char procname[128];
1095*5184Sek110237 	caddr_t shmaddr;
1096*5184Sek110237 	char dir[MAXPATHLEN];
1097*5184Sek110237 #ifdef HAVE_SETRLIMIT
1098*5184Sek110237 	struct rlimit rlp;
1099*5184Sek110237 #endif
1100*5184Sek110237 #ifdef HAVE_LIBTECLA
1101*5184Sek110237 	char *line;
1102*5184Sek110237 #else
1103*5184Sek110237 	char line[1024];
1104*5184Sek110237 #endif
1105*5184Sek110237 	char shmpathtmp[1024];
1106*5184Sek110237 
1107*5184Sek110237 #ifdef HAVE_SETRLIMIT
1108*5184Sek110237 	/* Set resource limits */
1109*5184Sek110237 	(void) getrlimit(RLIMIT_NOFILE, &rlp);
1110*5184Sek110237 	rlp.rlim_cur = rlp.rlim_max;
1111*5184Sek110237 	setrlimit(RLIMIT_NOFILE, &rlp);
1112*5184Sek110237 #endif
1113*5184Sek110237 
1114*5184Sek110237 	yydebug = 0;
1115*5184Sek110237 	execname = argv[0];
1116*5184Sek110237 	*procname = 0;
1117*5184Sek110237 	cwd = getcwd(dir, MAXPATHLEN);
1118*5184Sek110237 
1119*5184Sek110237 	while ((opt = getopt(argc, argv, cmd_options)) != (int)EOF) {
1120*5184Sek110237 
1121*5184Sek110237 		switch (opt) {
1122*5184Sek110237 		case 'h':
1123*5184Sek110237 			usage(2);
1124*5184Sek110237 			break;
1125*5184Sek110237 
1126*5184Sek110237 		case 'p':
1127*5184Sek110237 			noproc = 1;
1128*5184Sek110237 			break;
1129*5184Sek110237 
1130*5184Sek110237 		case 'f':
1131*5184Sek110237 			if (optarg == NULL)
1132*5184Sek110237 				usage(1);
1133*5184Sek110237 			if ((yyin = fopen(optarg, "r")) == NULL) {
1134*5184Sek110237 				(void) fprintf(stderr,
1135*5184Sek110237 				    "Cannot open file %s", optarg);
1136*5184Sek110237 				exit(1);
1137*5184Sek110237 			}
1138*5184Sek110237 			dofile = FS_TRUE;
1139*5184Sek110237 			fscriptname = optarg;
1140*5184Sek110237 
1141*5184Sek110237 			break;
1142*5184Sek110237 
1143*5184Sek110237 		case 'a':
1144*5184Sek110237 			if (optarg == NULL)
1145*5184Sek110237 				usage(1);
1146*5184Sek110237 			sscanf(optarg, "%s", &procname[0]);
1147*5184Sek110237 			break;
1148*5184Sek110237 
1149*5184Sek110237 		case 's':
1150*5184Sek110237 			if (optarg == NULL)
1151*5184Sek110237 				usage(1);
1152*5184Sek110237 #if defined(_LP64) || (__WORDSIZE == 64)
1153*5184Sek110237 			sscanf(optarg, "%llx", &shmaddr);
1154*5184Sek110237 #else
1155*5184Sek110237 			sscanf(optarg, "%x", &shmaddr);
1156*5184Sek110237 #endif
1157*5184Sek110237 			break;
1158*5184Sek110237 
1159*5184Sek110237 		case 'm':
1160*5184Sek110237 			if (optarg == NULL)
1161*5184Sek110237 				usage(1);
1162*5184Sek110237 			sscanf(optarg, "%s", shmpathtmp);
1163*5184Sek110237 			shmpath = shmpathtmp;
1164*5184Sek110237 			break;
1165*5184Sek110237 
1166*5184Sek110237 		case 'i':
1167*5184Sek110237 			if (optarg == NULL)
1168*5184Sek110237 				usage(1);
1169*5184Sek110237 			sscanf(optarg, "%d", &instance);
1170*5184Sek110237 			break;
1171*5184Sek110237 
1172*5184Sek110237 		case '?':
1173*5184Sek110237 		default:
1174*5184Sek110237 			usage(1);
1175*5184Sek110237 			break;
1176*5184Sek110237 		}
1177*5184Sek110237 	}
1178*5184Sek110237 
1179*5184Sek110237 #ifdef USE_PROCESS_MODEL
1180*5184Sek110237 	if (!(*procname))
1181*5184Sek110237 #endif
1182*5184Sek110237 	printf("FileBench Version %s\n", FILEBENCH_VERSION);
1183*5184Sek110237 	filebench_init();
1184*5184Sek110237 
1185*5184Sek110237 #ifdef USE_PROCESS_MODEL
1186*5184Sek110237 	if (*procname) {
1187*5184Sek110237 		pid = getpid();
1188*5184Sek110237 
1189*5184Sek110237 		if (ipc_attach(shmaddr) < 0) {
1190*5184Sek110237 			filebench_log(LOG_ERROR, "Cannot attach shm for %s",
1191*5184Sek110237 			    procname);
1192*5184Sek110237 			exit(1);
1193*5184Sek110237 		}
1194*5184Sek110237 
1195*5184Sek110237 		if (procflow_exec(procname, instance) < 0) {
1196*5184Sek110237 			filebench_log(LOG_ERROR, "Cannot startup process %s",
1197*5184Sek110237 			    procname);
1198*5184Sek110237 			exit(1);
1199*5184Sek110237 		}
1200*5184Sek110237 		exit(1);
1201*5184Sek110237 	}
1202*5184Sek110237 #endif
1203*5184Sek110237 
1204*5184Sek110237 	pid = getpid();
1205*5184Sek110237 	ipc_init();
1206*5184Sek110237 
1207*5184Sek110237 	if (fscriptname)
1208*5184Sek110237 		(void) strcpy(filebench_shm->fscriptname, fscriptname);
1209*5184Sek110237 
1210*5184Sek110237 	flowop_init();
1211*5184Sek110237 	stats_init();
1212*5184Sek110237 	eventgen_init();
1213*5184Sek110237 
1214*5184Sek110237 	signal(SIGINT, parser_abort);
1215*5184Sek110237 
1216*5184Sek110237 	if (dofile)
1217*5184Sek110237 		yyparse();
1218*5184Sek110237 	else {
1219*5184Sek110237 #ifdef HAVE_LIBTECLA
1220*5184Sek110237 		if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) {
1221*5184Sek110237 			filebench_log(LOG_ERROR,
1222*5184Sek110237 			    "Failed to create GetLine object");
1223*5184Sek110237 			filebench_shutdown(1);
1224*5184Sek110237 		}
1225*5184Sek110237 
1226*5184Sek110237 		if (gl_customize_completion(gl, NULL, command_complete)) {
1227*5184Sek110237 			filebench_log(LOG_ERROR,
1228*5184Sek110237 			    "Failed to register auto-completion function");
1229*5184Sek110237 			filebench_shutdown(1);
1230*5184Sek110237 		}
1231*5184Sek110237 
1232*5184Sek110237 		while (line = gl_get_line(gl, FILEBENCH_PROMPT, NULL, -1)) {
1233*5184Sek110237 			arg_parse(line);
1234*5184Sek110237 			yyparse();
1235*5184Sek110237 		}
1236*5184Sek110237 
1237*5184Sek110237 		del_GetLine(gl);
1238*5184Sek110237 #else
1239*5184Sek110237 		while (!feof(stdin)) {
1240*5184Sek110237 			printf(FILEBENCH_PROMPT);
1241*5184Sek110237 			fflush(stdout);
1242*5184Sek110237 			if (fgets(line, sizeof (line), stdin) == NULL) {
1243*5184Sek110237 				if (errno == EINTR)
1244*5184Sek110237 					continue;
1245*5184Sek110237 				else
1246*5184Sek110237 					break;
1247*5184Sek110237 			}
1248*5184Sek110237 			arg_parse(line);
1249*5184Sek110237 			yyparse();
1250*5184Sek110237 		}
1251*5184Sek110237 		printf("\n");
1252*5184Sek110237 #endif	/* HAVE_LIBTECLA */
1253*5184Sek110237 	}
1254*5184Sek110237 
1255*5184Sek110237 	parser_filebench_shutdown((cmd_t *)0);
1256*5184Sek110237 
1257*5184Sek110237 	return (0);
1258*5184Sek110237 }
1259*5184Sek110237 
1260*5184Sek110237 /*
1261*5184Sek110237  * arg_parse() puts the parser into command parsing mode. Create a tmpfile
1262*5184Sek110237  * and instruct the parser to read instructions from this location by setting
1263*5184Sek110237  * yyin to the value returned by tmpfile. Write the command into the file.
1264*5184Sek110237  * Then seek back to to the start of the file so that the parser can read
1265*5184Sek110237  * the instructions.
1266*5184Sek110237  */
1267*5184Sek110237 static void
1268*5184Sek110237 arg_parse(const char *command)
1269*5184Sek110237 {
1270*5184Sek110237 	if ((yyin = tmpfile()) == NULL)
1271*5184Sek110237 		filebench_log(LOG_FATAL,
1272*5184Sek110237 		    "Cannot create tmpfile: %s", strerror(errno));
1273*5184Sek110237 
1274*5184Sek110237 	if (fwrite(command, strlen(command), 1, yyin) != 1)
1275*5184Sek110237 		filebench_log(LOG_FATAL,
1276*5184Sek110237 		    "Cannot write tmpfile: %s", strerror(errno));
1277*5184Sek110237 
1278*5184Sek110237 	if (fseek(yyin, 0, SEEK_SET) != 0)
1279*5184Sek110237 		filebench_log(LOG_FATAL,
1280*5184Sek110237 		    "Cannot seek tmpfile: %s", strerror(errno));
1281*5184Sek110237 }
1282*5184Sek110237 
1283*5184Sek110237 /*
1284*5184Sek110237  * Converts a list of var_strings or ordinary strings to a single ordinary
1285*5184Sek110237  * string. It returns a pointer to the string (in malloc'd memory) if found,
1286*5184Sek110237  * or NULL otherwise.
1287*5184Sek110237  */
1288*5184Sek110237 char *
1289*5184Sek110237 parser_list2string(list_t *list)
1290*5184Sek110237 {
1291*5184Sek110237 	list_t *l;
1292*5184Sek110237 	char *string;
1293*5184Sek110237 	char *tmp;
1294*5184Sek110237 	vinteger_t *integer;
1295*5184Sek110237 
1296*5184Sek110237 	if ((string = malloc(MAXPATHLEN)) == NULL) {
1297*5184Sek110237 		filebench_log(LOG_ERROR, "Failed to allocate memory");
1298*5184Sek110237 		return (NULL);
1299*5184Sek110237 	}
1300*5184Sek110237 
1301*5184Sek110237 	*string = 0;
1302*5184Sek110237 
1303*5184Sek110237 
1304*5184Sek110237 	/* Format args */
1305*5184Sek110237 	for (l = list; l != NULL;
1306*5184Sek110237 	    l = l->list_next) {
1307*5184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT,
1308*5184Sek110237 		    "converting string '%s'", *l->list_string);
1309*5184Sek110237 
1310*5184Sek110237 		if ((tmp = var_to_string(*l->list_string)) != NULL) {
1311*5184Sek110237 			(void) strcat(string, tmp);
1312*5184Sek110237 			free(tmp);
1313*5184Sek110237 		} else {
1314*5184Sek110237 			(void) strcat(string, *l->list_string);
1315*5184Sek110237 		}
1316*5184Sek110237 	}
1317*5184Sek110237 	return (string);
1318*5184Sek110237 }
1319*5184Sek110237 
1320*5184Sek110237 /*
1321*5184Sek110237  * If the list just contains a single string starting with '$', then find
1322*5184Sek110237  * or create the named var and return the var's var_string component.
1323*5184Sek110237  * Otherwise, convert the list to a string, and allocate a var_string
1324*5184Sek110237  * containing a copy of that string. On failure either returns NULL
1325*5184Sek110237  * or shuts down the run.
1326*5184Sek110237  */
1327*5184Sek110237 var_string_t
1328*5184Sek110237 parser_list2varstring(list_t *list)
1329*5184Sek110237 {
1330*5184Sek110237 	/* Special case - variable name */
1331*5184Sek110237 	if ((list->list_next == NULL) && (*(*list->list_string) == '$'))
1332*5184Sek110237 		return (var_ref_string(*list->list_string));
1333*5184Sek110237 
1334*5184Sek110237 	return (string_alloc(parser_list2string(list)));
1335*5184Sek110237 }
1336*5184Sek110237 
1337*5184Sek110237 /*
1338*5184Sek110237  * Looks for the var named in list_string of the first element of the
1339*5184Sek110237  * supplied list. If found, returns the var_integer portion of the var.
1340*5184Sek110237  * If the var is not found, cannot be allocated, the supplied list is
1341*5184Sek110237  * NULL, or the list_string filed is empty, returns NULL.
1342*5184Sek110237  */
1343*5184Sek110237 var_integer_t
1344*5184Sek110237 parser_list2integer(list_t *list)
1345*5184Sek110237 {
1346*5184Sek110237 	var_integer_t v;
1347*5184Sek110237 
1348*5184Sek110237 	if (list && (*(list->list_string) != NULL)) {
1349*5184Sek110237 		v = var_ref_integer(*(list->list_string));
1350*5184Sek110237 		return (v);
1351*5184Sek110237 	}
1352*5184Sek110237 
1353*5184Sek110237 	return (NULL);
1354*5184Sek110237 }
1355*5184Sek110237 
1356*5184Sek110237 /*
1357*5184Sek110237  * Sets the event generator rate from the attribute supplied with the
1358*5184Sek110237  * command. If the attribute doesn't exist the routine does nothing.
1359*5184Sek110237  */
1360*5184Sek110237 static void
1361*5184Sek110237 parser_eventgen(cmd_t *cmd)
1362*5184Sek110237 {
1363*5184Sek110237 	attr_t *attr;
1364*5184Sek110237 	vinteger_t rate;
1365*5184Sek110237 
1366*5184Sek110237 	/* Get the rate from attribute */
1367*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_RATE)) {
1368*5184Sek110237 		if (attr->attr_integer) {
1369*5184Sek110237 			filebench_log(LOG_VERBOSE,
1370*5184Sek110237 			    "Eventgen: %lld per second",
1371*5184Sek110237 			    *attr->attr_integer);
1372*5184Sek110237 			eventgen_setrate(*attr->attr_integer);
1373*5184Sek110237 		}
1374*5184Sek110237 	}
1375*5184Sek110237 
1376*5184Sek110237 }
1377*5184Sek110237 
1378*5184Sek110237 /*
1379*5184Sek110237  * Assigns the designated integer variable successive values from the
1380*5184Sek110237  * supplied comma seperated integer list. After each successive integer
1381*5184Sek110237  * assignment, it executes the bracket enclosed list of commands. For
1382*5184Sek110237  * example, repeated runs of a workload with increasing io sizes can
1383*5184Sek110237  * be done using the following command line:
1384*5184Sek110237  * 	foreach $iosize in 2k, 4k, 8k {run 60}
1385*5184Sek110237  */
1386*5184Sek110237 static void
1387*5184Sek110237 parser_foreach_integer(cmd_t *cmd)
1388*5184Sek110237 {
1389*5184Sek110237 	list_t *list = cmd->cmd_param_list;
1390*5184Sek110237 	cmd_t *inner_cmd;
1391*5184Sek110237 
1392*5184Sek110237 	for (; list != NULL; list = list->list_next) {
1393*5184Sek110237 		var_assign_integer(cmd->cmd_tgt1, *list->list_integer);
1394*5184Sek110237 		filebench_log(LOG_VERBOSE, "Iterating %s=%lld",
1395*5184Sek110237 		    cmd->cmd_tgt1,
1396*5184Sek110237 		    *list->list_integer);
1397*5184Sek110237 		for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
1398*5184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
1399*5184Sek110237 			inner_cmd->cmd(inner_cmd);
1400*5184Sek110237 		}
1401*5184Sek110237 	}
1402*5184Sek110237 }
1403*5184Sek110237 
1404*5184Sek110237 /*
1405*5184Sek110237  * Similar to parser_foreach_integer(), except takes a list of strings after
1406*5184Sek110237  * the "in" token. For example, to run twice using a different directory,
1407*5184Sek110237  * perhaps using a different filesystem, the following command line
1408*5184Sek110237  * could be used:
1409*5184Sek110237  * 	foreach $dir in "/ufs_top/fbt", "/zfs_top/fbt" {run 60)
1410*5184Sek110237  */
1411*5184Sek110237 static void
1412*5184Sek110237 parser_foreach_string(cmd_t *cmd)
1413*5184Sek110237 {
1414*5184Sek110237 	list_t *list = cmd->cmd_param_list;
1415*5184Sek110237 	cmd_t *inner_cmd;
1416*5184Sek110237 
1417*5184Sek110237 	for (; list != NULL; list = list->list_next) {
1418*5184Sek110237 		var_assign_string(cmd->cmd_tgt1, *list->list_string);
1419*5184Sek110237 		filebench_log(LOG_VERBOSE, "Iterating %s=%s",
1420*5184Sek110237 		    cmd->cmd_tgt1,
1421*5184Sek110237 		    *list->list_string);
1422*5184Sek110237 		for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
1423*5184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
1424*5184Sek110237 			inner_cmd->cmd(inner_cmd);
1425*5184Sek110237 		}
1426*5184Sek110237 	}
1427*5184Sek110237 }
1428*5184Sek110237 
1429*5184Sek110237 /*
1430*5184Sek110237  * Lists the file name, path name and file size for all defined file objects.
1431*5184Sek110237  */
1432*5184Sek110237 static void
1433*5184Sek110237 parser_list(cmd_t *cmd)
1434*5184Sek110237 {
1435*5184Sek110237 	(void) fileobj_iter(fileobj_print);
1436*5184Sek110237 }
1437*5184Sek110237 
1438*5184Sek110237 /*
1439*5184Sek110237  * Calls procflow_define() to allocate "instances" number of  procflow(s)
1440*5184Sek110237  * (processes) with the supplied name. The default number of instances is
1441*5184Sek110237  * one. An optional priority level attribute can be supplied and is stored in
1442*5184Sek110237  * pf_nice. Finally the routine loops through the list of inner commands, if
1443*5184Sek110237  * any, which are defines for threadflows, and passes them one at a time to
1444*5184Sek110237  * parser_thread_define() to allocate threadflow entities for the process(es).
1445*5184Sek110237  */
1446*5184Sek110237 static void
1447*5184Sek110237 parser_proc_define(cmd_t *cmd)
1448*5184Sek110237 {
1449*5184Sek110237 	procflow_t *procflow, template;
1450*5184Sek110237 	char *name;
1451*5184Sek110237 	attr_t *attr;
1452*5184Sek110237 	var_integer_t instances = integer_alloc(1);
1453*5184Sek110237 	cmd_t *inner_cmd;
1454*5184Sek110237 
1455*5184Sek110237 	/* Get the name of the process */
1456*5184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
1457*5184Sek110237 		name = *attr->attr_string;
1458*5184Sek110237 	} else {
1459*5184Sek110237 		filebench_log(LOG_ERROR,
1460*5184Sek110237 		    "define proc: proc specifies no name");
1461*5184Sek110237 		filebench_shutdown(1);
1462*5184Sek110237 	}
1463*5184Sek110237 
1464*5184Sek110237 	/* Get the memory size from attribute */
1465*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
1466*5184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
1467*5184Sek110237 		    "Setting instances = %lld",
1468*5184Sek110237 		    *attr->attr_integer);
1469*5184Sek110237 		instances = attr->attr_integer;
1470*5184Sek110237 	}
1471*5184Sek110237 
1472*5184Sek110237 	if ((procflow = procflow_define(name, NULL, instances)) == NULL) {
1473*5184Sek110237 		filebench_log(LOG_ERROR,
1474*5184Sek110237 		    "Failed to instantiate %d %s process(es)\n",
1475*5184Sek110237 		    instances, name);
1476*5184Sek110237 		filebench_shutdown(1);
1477*5184Sek110237 	}
1478*5184Sek110237 
1479*5184Sek110237 	/* Get the pri from attribute */
1480*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_NICE)) {
1481*5184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Setting pri = %lld",
1482*5184Sek110237 		    *attr->attr_integer);
1483*5184Sek110237 		procflow->pf_nice = attr->attr_integer;
1484*5184Sek110237 	} else
1485*5184Sek110237 		procflow->pf_nice = integer_alloc(0);
1486*5184Sek110237 
1487*5184Sek110237 
1488*5184Sek110237 	/* Create the list of threads for this process  */
1489*5184Sek110237 	for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
1490*5184Sek110237 	    inner_cmd = inner_cmd->cmd_next) {
1491*5184Sek110237 		parser_thread_define(inner_cmd, procflow, *instances);
1492*5184Sek110237 	}
1493*5184Sek110237 }
1494*5184Sek110237 
1495*5184Sek110237 /*
1496*5184Sek110237  * Calls threadflow_define() to allocate "instances" number of  threadflow(s)
1497*5184Sek110237  * (threads) with the supplied name. The default number of instances is
1498*5184Sek110237  * one. Two other optional attributes may be supplied, one to set the memory
1499*5184Sek110237  * size, stored in tf_memsize, and to select the use of Interprocess Shared
1500*5184Sek110237  * Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally
1501*5184Sek110237  * the routine loops through the list of inner commands, if any, which are
1502*5184Sek110237  * defines for flowops, and passes them one at a time to
1503*5184Sek110237  * parser_flowop_define() to allocate flowop entities for the threadflows.
1504*5184Sek110237  */
1505*5184Sek110237 static void
1506*5184Sek110237 parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances)
1507*5184Sek110237 {
1508*5184Sek110237 	threadflow_t *threadflow, template;
1509*5184Sek110237 	attr_t *attr;
1510*5184Sek110237 	var_integer_t instances = integer_alloc(1);
1511*5184Sek110237 	cmd_t *inner_cmd;
1512*5184Sek110237 	char *name;
1513*5184Sek110237 
1514*5184Sek110237 	memset(&template, 0, sizeof (threadflow_t));
1515*5184Sek110237 
1516*5184Sek110237 	/* Get the name of the thread */
1517*5184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
1518*5184Sek110237 		name = *attr->attr_string;
1519*5184Sek110237 	} else {
1520*5184Sek110237 		filebench_log(LOG_ERROR,
1521*5184Sek110237 		    "define thread: thread in process %s specifies no name",
1522*5184Sek110237 		    procflow->pf_name);
1523*5184Sek110237 		filebench_shutdown(1);
1524*5184Sek110237 	}
1525*5184Sek110237 
1526*5184Sek110237 	/* Get the number of instances from attribute */
1527*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
1528*5184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
1529*5184Sek110237 		    "define thread: Setting instances = %lld",
1530*5184Sek110237 		    *attr->attr_integer);
1531*5184Sek110237 		instances = attr->attr_integer;
1532*5184Sek110237 	}
1533*5184Sek110237 
1534*5184Sek110237 	/* Get the memory size from attribute */
1535*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_MEMSIZE)) {
1536*5184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
1537*5184Sek110237 		    "define thread: Setting memsize = %lld",
1538*5184Sek110237 		    *attr->attr_integer);
1539*5184Sek110237 		template.tf_memsize = attr->attr_integer;
1540*5184Sek110237 	} else
1541*5184Sek110237 		template.tf_memsize = integer_alloc(0);
1542*5184Sek110237 
1543*5184Sek110237 	if ((threadflow = threadflow_define(procflow, name,
1544*5184Sek110237 	    &template, instances)) == NULL) {
1545*5184Sek110237 		filebench_log(LOG_ERROR,
1546*5184Sek110237 		    "define thread: Failed to instantiate thread\n");
1547*5184Sek110237 		filebench_shutdown(1);
1548*5184Sek110237 	}
1549*5184Sek110237 
1550*5184Sek110237 	/* Use ISM Memory? */
1551*5184Sek110237 	if (attr = get_attr(cmd, FSA_USEISM)) {
1552*5184Sek110237 		threadflow->tf_attrs |= THREADFLOW_USEISM;
1553*5184Sek110237 	}
1554*5184Sek110237 
1555*5184Sek110237 	/* Create the list of flowops */
1556*5184Sek110237 	for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
1557*5184Sek110237 	    inner_cmd = inner_cmd->cmd_next) {
1558*5184Sek110237 		parser_flowop_define(inner_cmd, threadflow);
1559*5184Sek110237 	}
1560*5184Sek110237 }
1561*5184Sek110237 
1562*5184Sek110237 /*
1563*5184Sek110237  * Calls flowop_define() to allocate a flowop with the supplied name.
1564*5184Sek110237  * The allocated flowop inherits attributes from a base flowop of the
1565*5184Sek110237  * same type.  If the new flowop has a file or fileset attribute specified,
1566*5184Sek110237  * it must specify a defined fileobj or fileset or an error will be logged.
1567*5184Sek110237  * The new flowop may  also have the following attributes set by
1568*5184Sek110237  * the program:
1569*5184Sek110237  *  - file size (fo_iosize)
1570*5184Sek110237  *  - working set size (fo_wss)
1571*5184Sek110237  *  - do random io (fo_random)
1572*5184Sek110237  *  - do synchronous io (fo_dsync)
1573*5184Sek110237  *  - perform each operation multiple times before advancing (fo_iter)
1574*5184Sek110237  *  - target name (fo_targetname)
1575*5184Sek110237  *  - An integer value (fo_value)
1576*5184Sek110237  *  - a file descriptor (fo_fd)
1577*5184Sek110237  *  - specify to rotate file descriptors (fo_rotatefd)
1578*5184Sek110237  *  - a source fd (fo_srcfdnumber)
1579*5184Sek110237  *  - specify a blocking operation (fo_blocking)
1580*5184Sek110237  *  - specify a highwater mark (fo_highwater)
1581*5184Sek110237  *
1582*5184Sek110237  * After all the supplied attributes are stored in their respective locations
1583*5184Sek110237  * in the flowop object, the flowop's init function is called. No errors are
1584*5184Sek110237  * returned, but the filebench run will be terminated if the flowtype is not
1585*5184Sek110237  * specified, a name for the new flowop is not supplied, the flowop_define
1586*5184Sek110237  * call fails, or a file or fileset name is supplied but the corresponding
1587*5184Sek110237  * fileobj or fileset cannot be located.
1588*5184Sek110237  */
1589*5184Sek110237 static void
1590*5184Sek110237 parser_flowop_define(cmd_t *cmd, threadflow_t *thread)
1591*5184Sek110237 {
1592*5184Sek110237 	flowop_t *flowop, *flowop_type;
1593*5184Sek110237 	fileobj_t *fileobj;
1594*5184Sek110237 	char *type = (char *)cmd->cmd_name;
1595*5184Sek110237 	char *name;
1596*5184Sek110237 	attr_t *attr;
1597*5184Sek110237 
1598*5184Sek110237 	/* Get the inherited flowop */
1599*5184Sek110237 	flowop_type = flowop_find(type);
1600*5184Sek110237 	if (flowop_type == NULL) {
1601*5184Sek110237 		filebench_log(LOG_ERROR,
1602*5184Sek110237 		    "define flowop: flowop type %s not found",
1603*5184Sek110237 		    type);
1604*5184Sek110237 		filebench_shutdown(1);
1605*5184Sek110237 	}
1606*5184Sek110237 
1607*5184Sek110237 	/* Get the name of the flowop */
1608*5184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
1609*5184Sek110237 		name = *attr->attr_string;
1610*5184Sek110237 	} else {
1611*5184Sek110237 		filebench_log(LOG_ERROR,
1612*5184Sek110237 		    "define flowop: flowop %s specifies no name",
1613*5184Sek110237 		    flowop_type->fo_name);
1614*5184Sek110237 		filebench_shutdown(1);
1615*5184Sek110237 	}
1616*5184Sek110237 
1617*5184Sek110237 	if ((flowop = flowop_define(thread, name,
1618*5184Sek110237 	    flowop_type, FLOW_MASTER, 0)) == NULL) {
1619*5184Sek110237 		filebench_log(LOG_ERROR,
1620*5184Sek110237 		    "define flowop: Failed to instantiate flowop %s\n",
1621*5184Sek110237 		    cmd->cmd_name);
1622*5184Sek110237 		filebench_shutdown(1);
1623*5184Sek110237 	}
1624*5184Sek110237 
1625*5184Sek110237 	/* Get the filename from attribute */
1626*5184Sek110237 	if (attr = get_attr(cmd, FSA_FILE)) {
1627*5184Sek110237 		flowop->fo_file = fileobj_find(*attr->attr_string);
1628*5184Sek110237 		flowop->fo_fileset = fileset_find(*attr->attr_string);
1629*5184Sek110237 
1630*5184Sek110237 		if ((flowop->fo_file == NULL) &&
1631*5184Sek110237 		    (flowop->fo_fileset == NULL)) {
1632*5184Sek110237 			filebench_log(LOG_ERROR,
1633*5184Sek110237 			    "define flowop: file %s not found",
1634*5184Sek110237 			    *attr->attr_string);
1635*5184Sek110237 			filebench_shutdown(1);
1636*5184Sek110237 		}
1637*5184Sek110237 	}
1638*5184Sek110237 
1639*5184Sek110237 	/* Get the iosize of the op */
1640*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_IOSIZE))
1641*5184Sek110237 		flowop->fo_iosize = attr->attr_integer;
1642*5184Sek110237 	else
1643*5184Sek110237 		flowop->fo_iosize = integer_alloc(0);
1644*5184Sek110237 
1645*5184Sek110237 	/* Get the working set size of the op */
1646*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_WSS))
1647*5184Sek110237 		flowop->fo_wss = attr->attr_integer;
1648*5184Sek110237 	else
1649*5184Sek110237 		flowop->fo_wss = integer_alloc(0);
1650*5184Sek110237 
1651*5184Sek110237 	/* Random I/O? */
1652*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_RANDOM))
1653*5184Sek110237 		flowop->fo_random = attr->attr_integer;
1654*5184Sek110237 	else
1655*5184Sek110237 		flowop->fo_random = integer_alloc(0);
1656*5184Sek110237 
1657*5184Sek110237 	/* Sync I/O? */
1658*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_DSYNC))
1659*5184Sek110237 		flowop->fo_dsync = attr->attr_integer;
1660*5184Sek110237 	else
1661*5184Sek110237 		flowop->fo_dsync = integer_alloc(0);
1662*5184Sek110237 
1663*5184Sek110237 	/* Iterations */
1664*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_ITERS))
1665*5184Sek110237 		flowop->fo_iters = attr->attr_integer;
1666*5184Sek110237 	else
1667*5184Sek110237 		flowop->fo_iters = integer_alloc(1);
1668*5184Sek110237 
1669*5184Sek110237 
1670*5184Sek110237 	/* Target, for wakeup etc */
1671*5184Sek110237 	if (attr = get_attr(cmd, FSA_TARGET))
1672*5184Sek110237 		(void) strcpy(flowop->fo_targetname, *attr->attr_string);
1673*5184Sek110237 
1674*5184Sek110237 	/* Value */
1675*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_VALUE))
1676*5184Sek110237 		flowop->fo_value = attr->attr_integer;
1677*5184Sek110237 	else
1678*5184Sek110237 		flowop->fo_value = integer_alloc(0);
1679*5184Sek110237 
1680*5184Sek110237 	/* FD */
1681*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_FD))
1682*5184Sek110237 		flowop->fo_fdnumber = *attr->attr_integer;
1683*5184Sek110237 
1684*5184Sek110237 	/* Rotatefd? */
1685*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_ROTATEFD))
1686*5184Sek110237 		flowop->fo_rotatefd = attr->attr_integer;
1687*5184Sek110237 	else
1688*5184Sek110237 		flowop->fo_rotatefd = integer_alloc(0);
1689*5184Sek110237 
1690*5184Sek110237 	/* SRC FD, for copies etc... */
1691*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_SRCFD))
1692*5184Sek110237 		flowop->fo_srcfdnumber = *attr->attr_integer;
1693*5184Sek110237 
1694*5184Sek110237 	/* Blocking operation? */
1695*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_BLOCKING))
1696*5184Sek110237 		flowop->fo_blocking = attr->attr_integer;
1697*5184Sek110237 	else
1698*5184Sek110237 		flowop->fo_blocking = integer_alloc(0);
1699*5184Sek110237 
1700*5184Sek110237 	/* Blocking operation? */
1701*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_DIRECTIO))
1702*5184Sek110237 		flowop->fo_directio = attr->attr_integer;
1703*5184Sek110237 	else
1704*5184Sek110237 		flowop->fo_directio = integer_alloc(0);
1705*5184Sek110237 
1706*5184Sek110237 	/* Highwater mark */
1707*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_HIGHWATER))
1708*5184Sek110237 		flowop->fo_highwater = attr->attr_integer;
1709*5184Sek110237 	else
1710*5184Sek110237 		flowop->fo_highwater = integer_alloc(1);
1711*5184Sek110237 }
1712*5184Sek110237 
1713*5184Sek110237 /*
1714*5184Sek110237  * Calls fileobj_define() to allocate a fileobj with the supplied name
1715*5184Sek110237  * and initializes the fileobj's pathname attribute, fo_path and fo_create,
1716*5184Sek110237  * and optionally the fo_prealloc, fo_paralloc, fo_reuse, fo_cached,
1717*5184Sek110237  * and fo_size attributes.
1718*5184Sek110237  */
1719*5184Sek110237 static void
1720*5184Sek110237 parser_file_define(cmd_t *cmd)
1721*5184Sek110237 {
1722*5184Sek110237 	fileobj_t *fileobj;
1723*5184Sek110237 	char *name;
1724*5184Sek110237 	attr_t *attr;
1725*5184Sek110237 	var_string_t pathname;
1726*5184Sek110237 
1727*5184Sek110237 	/* Get the name of the file */
1728*5184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
1729*5184Sek110237 		name = *attr->attr_string;
1730*5184Sek110237 	} else {
1731*5184Sek110237 		filebench_log(LOG_ERROR,
1732*5184Sek110237 		    "define file: file specifies no name");
1733*5184Sek110237 		return;
1734*5184Sek110237 	}
1735*5184Sek110237 
1736*5184Sek110237 	if ((fileobj = fileobj_define(name)) == NULL) {
1737*5184Sek110237 		filebench_log(LOG_ERROR,
1738*5184Sek110237 		    "define file: failed to instantiate file %s\n",
1739*5184Sek110237 		    cmd->cmd_name);
1740*5184Sek110237 		return;
1741*5184Sek110237 	}
1742*5184Sek110237 
1743*5184Sek110237 	/* Get the pathname from attribute */
1744*5184Sek110237 	if ((attr = get_attr(cmd, FSA_PATH)) == NULL) {
1745*5184Sek110237 		filebench_log(LOG_ERROR,
1746*5184Sek110237 		    "define file: no pathname specified");
1747*5184Sek110237 		return;
1748*5184Sek110237 	}
1749*5184Sek110237 
1750*5184Sek110237 	/* Expand variables in pathname */
1751*5184Sek110237 	if ((pathname = parser_list2varstring(attr->attr_param_list))
1752*5184Sek110237 	    == NULL) {
1753*5184Sek110237 		filebench_log(LOG_ERROR, "Cannot interpret path");
1754*5184Sek110237 		return;
1755*5184Sek110237 	}
1756*5184Sek110237 
1757*5184Sek110237 	fileobj->fo_path = pathname;
1758*5184Sek110237 
1759*5184Sek110237 	/* For now, all files are pre-created */
1760*5184Sek110237 	fileobj->fo_create = integer_alloc(1);
1761*5184Sek110237 
1762*5184Sek110237 	/* Should we preallocate? */
1763*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_PREALLOC)) {
1764*5184Sek110237 		fileobj->fo_prealloc = attr->attr_integer;
1765*5184Sek110237 	} else
1766*5184Sek110237 		fileobj->fo_prealloc = integer_alloc(0);
1767*5184Sek110237 
1768*5184Sek110237 	/* Should we prealloc in parallel? */
1769*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_PARALLOC)) {
1770*5184Sek110237 		fileobj->fo_paralloc = attr->attr_integer;
1771*5184Sek110237 	} else
1772*5184Sek110237 		fileobj->fo_paralloc = integer_alloc(0);
1773*5184Sek110237 
1774*5184Sek110237 	/* Should we reuse the existing file? */
1775*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_REUSE)) {
1776*5184Sek110237 		fileobj->fo_reuse = attr->attr_integer;
1777*5184Sek110237 	} else
1778*5184Sek110237 		fileobj->fo_reuse = integer_alloc(0);
1779*5184Sek110237 
1780*5184Sek110237 	/* Should we leave in cache? */
1781*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_CACHED)) {
1782*5184Sek110237 		fileobj->fo_cached = attr->attr_integer;
1783*5184Sek110237 	} else
1784*5184Sek110237 		fileobj->fo_cached = integer_alloc(0);
1785*5184Sek110237 
1786*5184Sek110237 	/* Get the size of the file */
1787*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_SIZE)) {
1788*5184Sek110237 		fileobj->fo_size = attr->attr_integer;
1789*5184Sek110237 	} else
1790*5184Sek110237 		fileobj->fo_size = integer_alloc(0);
1791*5184Sek110237 
1792*5184Sek110237 }
1793*5184Sek110237 
1794*5184Sek110237 /*
1795*5184Sek110237  * Calls fileset_define() to allocate a fileset with the supplied name and
1796*5184Sek110237  * initializes the fileset's pathname attribute, and optionally the fs_cached,
1797*5184Sek110237  * fs_reuse, fs_preallocpercent, fs_prealloc, fs_entries, fs_dirwidth,
1798*5184Sek110237  * fs_size, fs_dirgamma, and fs_sizegamma attributes.
1799*5184Sek110237  */
1800*5184Sek110237 static void
1801*5184Sek110237 parser_fileset_define(cmd_t *cmd)
1802*5184Sek110237 {
1803*5184Sek110237 	fileset_t *fileset;
1804*5184Sek110237 	char *name;
1805*5184Sek110237 	attr_t *attr;
1806*5184Sek110237 	var_string_t pathname;
1807*5184Sek110237 
1808*5184Sek110237 	/* Get the name of the file */
1809*5184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
1810*5184Sek110237 		name = *attr->attr_string;
1811*5184Sek110237 	} else {
1812*5184Sek110237 		filebench_log(LOG_ERROR,
1813*5184Sek110237 		    "define file: file specifies no name");
1814*5184Sek110237 		return;
1815*5184Sek110237 	}
1816*5184Sek110237 
1817*5184Sek110237 	if ((fileset = fileset_define(name)) == NULL) {
1818*5184Sek110237 		filebench_log(LOG_ERROR,
1819*5184Sek110237 		    "define file: failed to instantiate file %s\n",
1820*5184Sek110237 		    cmd->cmd_name);
1821*5184Sek110237 		return;
1822*5184Sek110237 	}
1823*5184Sek110237 
1824*5184Sek110237 	/* Get the pathname from attribute */
1825*5184Sek110237 	if ((attr = get_attr(cmd, FSA_PATH)) == NULL) {
1826*5184Sek110237 		filebench_log(LOG_ERROR, "define file: no pathname specified");
1827*5184Sek110237 		return;
1828*5184Sek110237 	}
1829*5184Sek110237 
1830*5184Sek110237 	/* Expand variables in pathname */
1831*5184Sek110237 	if ((pathname = parser_list2varstring(attr->attr_param_list)) == NULL) {
1832*5184Sek110237 		filebench_log(LOG_ERROR, "Cannot interpret path");
1833*5184Sek110237 		return;
1834*5184Sek110237 	}
1835*5184Sek110237 
1836*5184Sek110237 	fileset->fs_path = pathname;
1837*5184Sek110237 
1838*5184Sek110237 	/* Should we leave in cache? */
1839*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_CACHED)) {
1840*5184Sek110237 		fileset->fs_cached = attr->attr_integer;
1841*5184Sek110237 	} else
1842*5184Sek110237 		fileset->fs_cached = integer_alloc(0);
1843*5184Sek110237 
1844*5184Sek110237 	/* Should we reuse the existing file? */
1845*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_REUSE)) {
1846*5184Sek110237 		fileset->fs_reuse = attr->attr_integer;
1847*5184Sek110237 	} else
1848*5184Sek110237 		fileset->fs_reuse = integer_alloc(0);
1849*5184Sek110237 
1850*5184Sek110237 	/* How much should we prealloc */
1851*5184Sek110237 	if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) &&
1852*5184Sek110237 	    attr->attr_integer) {
1853*5184Sek110237 		fileset->fs_preallocpercent = attr->attr_integer;
1854*5184Sek110237 	} else if (attr && !attr->attr_integer) {
1855*5184Sek110237 		fileset->fs_preallocpercent = integer_alloc(100);
1856*5184Sek110237 	} else {
1857*5184Sek110237 		fileset->fs_preallocpercent = integer_alloc(0);
1858*5184Sek110237 	}
1859*5184Sek110237 
1860*5184Sek110237 	/* Should we preallocate? */
1861*5184Sek110237 	if (attr = get_attr_bool(cmd, FSA_PREALLOC)) {
1862*5184Sek110237 		fileset->fs_prealloc = attr->attr_integer;
1863*5184Sek110237 	} else
1864*5184Sek110237 		fileset->fs_prealloc = integer_alloc(0);
1865*5184Sek110237 
1866*5184Sek110237 	/* Get the size of the fileset */
1867*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_ENTRIES)) {
1868*5184Sek110237 		fileset->fs_entries = attr->attr_integer;
1869*5184Sek110237 	} else {
1870*5184Sek110237 		filebench_log(LOG_ERROR, "Fileset has zero entries");
1871*5184Sek110237 		fileset->fs_entries = integer_alloc(0);
1872*5184Sek110237 	}
1873*5184Sek110237 
1874*5184Sek110237 	/* Get the mean dir width of the fileset */
1875*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) {
1876*5184Sek110237 		fileset->fs_dirwidth = attr->attr_integer;
1877*5184Sek110237 	} else {
1878*5184Sek110237 		filebench_log(LOG_ERROR, "Fileset has zero directory width");
1879*5184Sek110237 		fileset->fs_dirwidth = integer_alloc(0);
1880*5184Sek110237 	}
1881*5184Sek110237 
1882*5184Sek110237 	/* Get the mean or absolute size of the file */
1883*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_SIZE)) {
1884*5184Sek110237 		fileset->fs_size = attr->attr_integer;
1885*5184Sek110237 	} else
1886*5184Sek110237 		fileset->fs_size = integer_alloc(0);
1887*5184Sek110237 
1888*5184Sek110237 	/* Get the gamma value for dir width distributions */
1889*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) {
1890*5184Sek110237 		fileset->fs_dirgamma = attr->attr_integer;
1891*5184Sek110237 	} else
1892*5184Sek110237 		fileset->fs_dirgamma = integer_alloc(1500);
1893*5184Sek110237 
1894*5184Sek110237 	/* Get the gamma value for dir width distributions */
1895*5184Sek110237 	if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) {
1896*5184Sek110237 		fileset->fs_sizegamma = attr->attr_integer;
1897*5184Sek110237 	} else
1898*5184Sek110237 		fileset->fs_sizegamma = integer_alloc(1500);
1899*5184Sek110237 }
1900*5184Sek110237 
1901*5184Sek110237 /*
1902*5184Sek110237  * Creates and starts all defined procflow processes. The call to
1903*5184Sek110237  * procflow_init() results in creation of the requested number of
1904*5184Sek110237  * process instances for each previously defined procflow. The
1905*5184Sek110237  * child processes exec() a new instance of filebench, passing it
1906*5184Sek110237  * the instance number and address of the shared memory region.
1907*5184Sek110237  * The child processes will then create their threads and flowops.
1908*5184Sek110237  * The routine then unlocks the run_lock to allow all the processes'
1909*5184Sek110237  * threads to start and  waits for all of them to begin execution.
1910*5184Sek110237  * Finally, it records the start time and resets the event generation
1911*5184Sek110237  * system.
1912*5184Sek110237  */
1913*5184Sek110237 static void
1914*5184Sek110237 parser_proc_create(cmd_t *cmd)
1915*5184Sek110237 {
1916*5184Sek110237 	if (procflow_init() != 0) {
1917*5184Sek110237 		filebench_log(LOG_ERROR, "Failed to create processes\n");
1918*5184Sek110237 		filebench_shutdown(1);
1919*5184Sek110237 	}
1920*5184Sek110237 
1921*5184Sek110237 	/* Release the read lock, allowing threads to start */
1922*5184Sek110237 	(void) pthread_rwlock_unlock(&filebench_shm->run_lock);
1923*5184Sek110237 
1924*5184Sek110237 	/* Wait for all threads to start */
1925*5184Sek110237 	if (procflow_allstarted() != 0) {
1926*5184Sek110237 		filebench_log(LOG_ERROR, "Could not start run");
1927*5184Sek110237 		return;
1928*5184Sek110237 	}
1929*5184Sek110237 
1930*5184Sek110237 
1931*5184Sek110237 	if (filebench_shm->shm_required &&
1932*5184Sek110237 	    (ipc_ismcreate(filebench_shm->shm_required) < 0)) {
1933*5184Sek110237 		filebench_log(LOG_ERROR, "Could not allocate shared memory");
1934*5184Sek110237 		return;
1935*5184Sek110237 	}
1936*5184Sek110237 
1937*5184Sek110237 	filebench_shm->starttime = gethrtime();
1938*5184Sek110237 	eventgen_reset();
1939*5184Sek110237 }
1940*5184Sek110237 
1941*5184Sek110237 /*
1942*5184Sek110237  * Calls fileobj_init() to create  and optionally pre fill files
1943*5184Sek110237  * for all fileobjs on the master list of fileobjs (filelist).
1944*5184Sek110237  * If errors are encountered, calls filebench_shutdown()
1945*5184Sek110237  * to exit filebench.
1946*5184Sek110237  */
1947*5184Sek110237 static void
1948*5184Sek110237 parser_file_create(cmd_t *cmd)
1949*5184Sek110237 {
1950*5184Sek110237 	fileobj_t *fileobj;
1951*5184Sek110237 
1952*5184Sek110237 	if (fileobj_init() != 0) {
1953*5184Sek110237 		filebench_log(LOG_ERROR, "Failed to create files");
1954*5184Sek110237 		filebench_shutdown(1);
1955*5184Sek110237 	}
1956*5184Sek110237 }
1957*5184Sek110237 
1958*5184Sek110237 /*
1959*5184Sek110237  * Calls fileset_createset() to populate all filesets and create all
1960*5184Sek110237  * associated, initially existant,  files and subdirectories.
1961*5184Sek110237  * If errors are encountered, calls filebench_shutdown()
1962*5184Sek110237  * to exit filebench.
1963*5184Sek110237  */
1964*5184Sek110237 static void
1965*5184Sek110237 parser_fileset_create(cmd_t *cmd)
1966*5184Sek110237 {
1967*5184Sek110237 	fileset_t *fileset;
1968*5184Sek110237 
1969*5184Sek110237 	if (fileset_createset(NULL) != 0) {
1970*5184Sek110237 		filebench_log(LOG_ERROR, "Failed to create filesets");
1971*5184Sek110237 		filebench_shutdown(1);
1972*5184Sek110237 	}
1973*5184Sek110237 }
1974*5184Sek110237 
1975*5184Sek110237 /*
1976*5184Sek110237  * Shuts down all processes and their associated threads. When finished
1977*5184Sek110237  * it deletes interprocess shared memory and resets the event generator.
1978*5184Sek110237  * It does not exit the filebench program though.
1979*5184Sek110237  */
1980*5184Sek110237 static void
1981*5184Sek110237 parser_proc_shutdown(cmd_t *cmd)
1982*5184Sek110237 {
1983*5184Sek110237 	filebench_log(LOG_INFO, "Shutting down processes");
1984*5184Sek110237 	procflow_shutdown();
1985*5184Sek110237 	if (filebench_shm->shm_required)
1986*5184Sek110237 		ipc_ismdelete();
1987*5184Sek110237 	eventgen_reset();
1988*5184Sek110237 }
1989*5184Sek110237 
1990*5184Sek110237 /*
1991*5184Sek110237  * Ends filebench run after first destoring any interprocess
1992*5184Sek110237  * shared memory. The call to filebench_shutdown()
1993*5184Sek110237  * also causes filebench to exit.
1994*5184Sek110237  */
1995*5184Sek110237 static void
1996*5184Sek110237 parser_filebench_shutdown(cmd_t *cmd)
1997*5184Sek110237 {
1998*5184Sek110237 	ipc_cleanup();
1999*5184Sek110237 	filebench_shutdown(1);
2000*5184Sek110237 }
2001*5184Sek110237 
2002*5184Sek110237 /*
2003*5184Sek110237  * Sleeps for cmd->cmd_qty seconds, one second at a time.
2004*5184Sek110237  */
2005*5184Sek110237 static void
2006*5184Sek110237 parser_sleep(cmd_t *cmd)
2007*5184Sek110237 {
2008*5184Sek110237 	int sleeptime;
2009*5184Sek110237 
2010*5184Sek110237 	/* check for startup errors */
2011*5184Sek110237 	if (filebench_shm->f_abort)
2012*5184Sek110237 		return;
2013*5184Sek110237 
2014*5184Sek110237 	sleeptime = cmd->cmd_qty;
2015*5184Sek110237 	filebench_log(LOG_INFO, "Running...");
2016*5184Sek110237 	while (sleeptime) {
2017*5184Sek110237 		(void) sleep(1);
2018*5184Sek110237 		sleeptime--;
2019*5184Sek110237 		if (filebench_shm->f_abort)
2020*5184Sek110237 			break;
2021*5184Sek110237 	}
2022*5184Sek110237 	filebench_log(LOG_INFO, "Run took %lld seconds...",
2023*5184Sek110237 	    cmd->cmd_qty - sleeptime);
2024*5184Sek110237 }
2025*5184Sek110237 
2026*5184Sek110237 /*
2027*5184Sek110237  * Do a file bench run. Calls routines to create file sets, files, and
2028*5184Sek110237  * processes. It resets the statistics counters, then sleeps for the runtime
2029*5184Sek110237  * passed as an argument to it on the command line in 1 second increments.
2030*5184Sek110237  * When it is finished sleeping, it collects a snapshot of the statistics
2031*5184Sek110237  * and ends the run.
2032*5184Sek110237  */
2033*5184Sek110237 static void
2034*5184Sek110237 parser_run(cmd_t *cmd)
2035*5184Sek110237 {
2036*5184Sek110237 	int runtime;
2037*5184Sek110237 
2038*5184Sek110237 	runtime = cmd->cmd_qty;
2039*5184Sek110237 	parser_fileset_create(cmd);
2040*5184Sek110237 	parser_file_create(cmd);
2041*5184Sek110237 	parser_proc_create(cmd);
2042*5184Sek110237 
2043*5184Sek110237 	/* check for startup errors */
2044*5184Sek110237 	if (filebench_shm->f_abort)
2045*5184Sek110237 		return;
2046*5184Sek110237 
2047*5184Sek110237 	filebench_log(LOG_INFO, "Running...");
2048*5184Sek110237 	stats_clear();
2049*5184Sek110237 	while (runtime) {
2050*5184Sek110237 		(void) sleep(1);
2051*5184Sek110237 		runtime--;
2052*5184Sek110237 		if (filebench_shm->f_abort)
2053*5184Sek110237 			break;
2054*5184Sek110237 	}
2055*5184Sek110237 	filebench_log(LOG_INFO, "Run took %lld seconds...",
2056*5184Sek110237 	    cmd->cmd_qty - runtime);
2057*5184Sek110237 	parser_statssnap(cmd);
2058*5184Sek110237 	parser_proc_shutdown(cmd);
2059*5184Sek110237 }
2060*5184Sek110237 
2061*5184Sek110237 /*
2062*5184Sek110237  * Similar to parser_run, but gets the sleep time from a variable
2063*5184Sek110237  * whose name is supplied as an argument to the command.
2064*5184Sek110237  */
2065*5184Sek110237 static void
2066*5184Sek110237 parser_run_variable(cmd_t *cmd)
2067*5184Sek110237 {
2068*5184Sek110237 	vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1);
2069*5184Sek110237 	int runtime;
2070*5184Sek110237 
2071*5184Sek110237 	if (integer == NULL) {
2072*5184Sek110237 		filebench_log(LOG_ERROR, "Unknown variable %s",
2073*5184Sek110237 		cmd->cmd_tgt1);
2074*5184Sek110237 		return;
2075*5184Sek110237 	}
2076*5184Sek110237 
2077*5184Sek110237 	runtime = *integer;
2078*5184Sek110237 
2079*5184Sek110237 	/* check for startup errors */
2080*5184Sek110237 	if (filebench_shm->f_abort)
2081*5184Sek110237 		return;
2082*5184Sek110237 
2083*5184Sek110237 	filebench_log(LOG_INFO, "Running...");
2084*5184Sek110237 	stats_clear();
2085*5184Sek110237 	while (runtime) {
2086*5184Sek110237 		(void) sleep(1);
2087*5184Sek110237 		runtime--;
2088*5184Sek110237 		if (filebench_shm->f_abort)
2089*5184Sek110237 			break;
2090*5184Sek110237 	}
2091*5184Sek110237 	filebench_log(LOG_INFO, "Run took %lld seconds...",
2092*5184Sek110237 	    *integer - runtime);
2093*5184Sek110237 	parser_statssnap(cmd);
2094*5184Sek110237 }
2095*5184Sek110237 
2096*5184Sek110237 char *usagestr = NULL;
2097*5184Sek110237 
2098*5184Sek110237 /*
2099*5184Sek110237  * Prints usage string if defined, else just a message requesting load of a
2100*5184Sek110237  * personality.
2101*5184Sek110237  */
2102*5184Sek110237 static void
2103*5184Sek110237 parser_help(cmd_t *cmd)
2104*5184Sek110237 {
2105*5184Sek110237 	int runtime;
2106*5184Sek110237 
2107*5184Sek110237 	if (usagestr) {
2108*5184Sek110237 		filebench_log(LOG_INFO, "%s", usagestr);
2109*5184Sek110237 	} else {
2110*5184Sek110237 		filebench_log(LOG_INFO,
2111*5184Sek110237 		    "load <personality> (ls "
2112*5184Sek110237 		    "/usr/benchmarks/filebench/workloads for list)");
2113*5184Sek110237 	}
2114*5184Sek110237 }
2115*5184Sek110237 
2116*5184Sek110237 char *varstr = NULL;
2117*5184Sek110237 
2118*5184Sek110237 /*
2119*5184Sek110237  * Prints the string of all var definitions, if there is one.
2120*5184Sek110237  */
2121*5184Sek110237 static void
2122*5184Sek110237 parser_printvars(cmd_t *cmd)
2123*5184Sek110237 {
2124*5184Sek110237 	int runtime;
2125*5184Sek110237 	char *str, *c;
2126*5184Sek110237 
2127*5184Sek110237 	if (varstr) {
2128*5184Sek110237 		str = strdup(varstr);
2129*5184Sek110237 		for (c = str; *c != '\0'; c++) {
2130*5184Sek110237 			if ((char)*c == '$')
2131*5184Sek110237 				*c = ' ';
2132*5184Sek110237 		}
2133*5184Sek110237 		filebench_log(LOG_INFO, "%s", str);
2134*5184Sek110237 		free(str);
2135*5184Sek110237 	}
2136*5184Sek110237 }
2137*5184Sek110237 
2138*5184Sek110237 /*
2139*5184Sek110237  * Used by the SET command to add a var and default value string to the
2140*5184Sek110237  * varstr string. It allocates a new, larger varstr string, copies the
2141*5184Sek110237  * old contents of varstr into it, then adds the new var string on the end.
2142*5184Sek110237  */
2143*5184Sek110237 static void
2144*5184Sek110237 parser_vars(cmd_t *cmd)
2145*5184Sek110237 {
2146*5184Sek110237 	char *string = cmd->cmd_tgt1;
2147*5184Sek110237 	char *newvars;
2148*5184Sek110237 
2149*5184Sek110237 	if (string == NULL)
2150*5184Sek110237 		return;
2151*5184Sek110237 
2152*5184Sek110237 	if (dofile)
2153*5184Sek110237 		return;
2154*5184Sek110237 
2155*5184Sek110237 	if (varstr == NULL) {
2156*5184Sek110237 		newvars = malloc(strlen(string) + 2);
2157*5184Sek110237 		*newvars = 0;
2158*5184Sek110237 	} else {
2159*5184Sek110237 		newvars = malloc(strlen(varstr) + strlen(string) + 2);
2160*5184Sek110237 		(void) strcpy(newvars, varstr);
2161*5184Sek110237 	}
2162*5184Sek110237 	(void) strcat(newvars, string);
2163*5184Sek110237 	(void) strcat(newvars, " ");
2164*5184Sek110237 
2165*5184Sek110237 	if (varstr)
2166*5184Sek110237 		free(varstr);
2167*5184Sek110237 
2168*5184Sek110237 	varstr = newvars;
2169*5184Sek110237 }
2170*5184Sek110237 
2171*5184Sek110237 /*
2172*5184Sek110237  * Same as parser_sleep, except the sleep time is obtained from a variable
2173*5184Sek110237  * whose name is passed to it as an argument on the command line.
2174*5184Sek110237  */
2175*5184Sek110237 static void
2176*5184Sek110237 parser_sleep_variable(cmd_t *cmd)
2177*5184Sek110237 {
2178*5184Sek110237 	vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1);
2179*5184Sek110237 	int sleeptime;
2180*5184Sek110237 
2181*5184Sek110237 	if (integer == NULL) {
2182*5184Sek110237 		filebench_log(LOG_ERROR, "Unknown variable %s",
2183*5184Sek110237 		cmd->cmd_tgt1);
2184*5184Sek110237 		return;
2185*5184Sek110237 	}
2186*5184Sek110237 
2187*5184Sek110237 	sleeptime = *integer;
2188*5184Sek110237 
2189*5184Sek110237 	/* check for startup errors */
2190*5184Sek110237 	if (filebench_shm->f_abort)
2191*5184Sek110237 		return;
2192*5184Sek110237 
2193*5184Sek110237 	filebench_log(LOG_INFO, "Running...");
2194*5184Sek110237 	while (sleeptime) {
2195*5184Sek110237 		(void) sleep(1);
2196*5184Sek110237 		sleeptime--;
2197*5184Sek110237 		if (filebench_shm->f_abort)
2198*5184Sek110237 			break;
2199*5184Sek110237 	}
2200*5184Sek110237 	filebench_log(LOG_INFO, "Run took %lld seconds...",
2201*5184Sek110237 	    *integer - sleeptime);
2202*5184Sek110237 }
2203*5184Sek110237 
2204*5184Sek110237 /*
2205*5184Sek110237  * Parser log prints the values of a list of variables to the log file.
2206*5184Sek110237  * The list of variables is placed on the command line, separated
2207*5184Sek110237  * by comas and the entire list is enclosed in quotes.
2208*5184Sek110237  * For example, if $dir contains "/export/home/tmp" and $filesize = 1048576,
2209*5184Sek110237  * then typing: log "$dir, $filesize" prints: log /export/home/tmp, 1048576
2210*5184Sek110237  */
2211*5184Sek110237 static void
2212*5184Sek110237 parser_log(cmd_t *cmd)
2213*5184Sek110237 {
2214*5184Sek110237 	char *string;
2215*5184Sek110237 
2216*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2217*5184Sek110237 		return;
2218*5184Sek110237 
2219*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2220*5184Sek110237 
2221*5184Sek110237 	if (string == NULL)
2222*5184Sek110237 		return;
2223*5184Sek110237 
2224*5184Sek110237 	filebench_log(LOG_VERBOSE, "log %s", string);
2225*5184Sek110237 	filebench_log(LOG_LOG, "%s", string);
2226*5184Sek110237 }
2227*5184Sek110237 
2228*5184Sek110237 /*
2229*5184Sek110237  * Implements the stats directory command. changes the directory for
2230*5184Sek110237  * dumping statistics to supplied directory path. For example:
2231*5184Sek110237  * 	stats directory /tmp
2232*5184Sek110237  * changes the stats directory to "/tmp".
2233*5184Sek110237  */
2234*5184Sek110237 static void
2235*5184Sek110237 parser_directory(cmd_t *cmd)
2236*5184Sek110237 {
2237*5184Sek110237 	char newdir[MAXPATHLEN];
2238*5184Sek110237 	char *dir;
2239*5184Sek110237 
2240*5184Sek110237 	if ((dir = parser_list2string(cmd->cmd_param_list)) == NULL) {
2241*5184Sek110237 		filebench_log(LOG_ERROR, "Cannot interpret directory");
2242*5184Sek110237 		return;
2243*5184Sek110237 	}
2244*5184Sek110237 
2245*5184Sek110237 	*newdir = 0;
2246*5184Sek110237 	/* Change dir relative to cwd if path not fully qualified */
2247*5184Sek110237 	if (*dir != '/') {
2248*5184Sek110237 		(void) strcat(newdir, cwd);
2249*5184Sek110237 		(void) strcat(newdir, "/");
2250*5184Sek110237 	}
2251*5184Sek110237 	(void) strcat(newdir, dir);
2252*5184Sek110237 	(void) mkdir(newdir, 0755);
2253*5184Sek110237 	filebench_log(LOG_VERBOSE, "Change dir to %s", newdir);
2254*5184Sek110237 	chdir(newdir);
2255*5184Sek110237 	free(dir);
2256*5184Sek110237 }
2257*5184Sek110237 
2258*5184Sek110237 #define	PIPE_PARENT 1
2259*5184Sek110237 #define	PIPE_CHILD  0
2260*5184Sek110237 
2261*5184Sek110237 /*
2262*5184Sek110237  * Runs the quoted unix command as a background process. Intended for
2263*5184Sek110237  * running statistics gathering utilities such as mpstat while the filebench
2264*5184Sek110237  * workload is running. Also records the pid's of the background processes
2265*5184Sek110237  * so that parser_statssnap() can terminate them when the run completes.
2266*5184Sek110237  */
2267*5184Sek110237 static void
2268*5184Sek110237 parser_statscmd(cmd_t *cmd)
2269*5184Sek110237 {
2270*5184Sek110237 	char *string;
2271*5184Sek110237 	pid_t pid;
2272*5184Sek110237 	pidlist_t *pidlistent;
2273*5184Sek110237 	int pipe_fd[2];
2274*5184Sek110237 	int newstdout;
2275*5184Sek110237 
2276*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2277*5184Sek110237 		return;
2278*5184Sek110237 
2279*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2280*5184Sek110237 
2281*5184Sek110237 	if (string == NULL)
2282*5184Sek110237 		return;
2283*5184Sek110237 
2284*5184Sek110237 	if ((pipe(pipe_fd)) < 0) {
2285*5184Sek110237 		filebench_log(LOG_ERROR, "statscmd pipe failed");
2286*5184Sek110237 		return;
2287*5184Sek110237 	}
2288*5184Sek110237 
2289*5184Sek110237 #ifdef HAVE_FORK1
2290*5184Sek110237 	if ((pid = fork1()) < 0) {
2291*5184Sek110237 		filebench_log(LOG_ERROR, "statscmd fork failed");
2292*5184Sek110237 		return;
2293*5184Sek110237 	}
2294*5184Sek110237 #elif HAVE_FORK
2295*5184Sek110237 	if ((pid = fork()) < 0) {
2296*5184Sek110237 		filebench_log(LOG_ERROR, "statscmd fork failed");
2297*5184Sek110237 		return;
2298*5184Sek110237 	}
2299*5184Sek110237 #else
2300*5184Sek110237 	Crash! - Need code to deal with no fork1!
2301*5184Sek110237 #endif /* HAVE_FORK1 */
2302*5184Sek110237 
2303*5184Sek110237 	if (pid == 0) {
2304*5184Sek110237 
2305*5184Sek110237 		setsid();
2306*5184Sek110237 
2307*5184Sek110237 		filebench_log(LOG_VERBOSE,
2308*5184Sek110237 		    "Backgrounding %s", string);
2309*5184Sek110237 		/*
2310*5184Sek110237 		 * Child
2311*5184Sek110237 		 * - close stdout
2312*5184Sek110237 		 * - dup to create new stdout
2313*5184Sek110237 		 * - close pipe fds
2314*5184Sek110237 		 */
2315*5184Sek110237 		(void) close(1);
2316*5184Sek110237 
2317*5184Sek110237 		if ((newstdout = dup(pipe_fd[PIPE_CHILD])) < 0) {
2318*5184Sek110237 			filebench_log(LOG_ERROR,
2319*5184Sek110237 			    "statscmd dup failed: %s",
2320*5184Sek110237 			    strerror(errno));
2321*5184Sek110237 		}
2322*5184Sek110237 
2323*5184Sek110237 		(void) close(pipe_fd[PIPE_PARENT]);
2324*5184Sek110237 		(void) close(pipe_fd[PIPE_CHILD]);
2325*5184Sek110237 
2326*5184Sek110237 		if (system(string) < 0) {
2327*5184Sek110237 			filebench_log(LOG_ERROR,
2328*5184Sek110237 			    "statscmd exec failed: %s",
2329*5184Sek110237 			    strerror(errno));
2330*5184Sek110237 		}
2331*5184Sek110237 		/* Failed! */
2332*5184Sek110237 		exit(1);
2333*5184Sek110237 
2334*5184Sek110237 	} else {
2335*5184Sek110237 
2336*5184Sek110237 		/* Record pid in pidlist for subsequent reaping by stats snap */
2337*5184Sek110237 		if ((pidlistent = (pidlist_t *)malloc(sizeof (pidlist_t)))
2338*5184Sek110237 		    == NULL) {
2339*5184Sek110237 			filebench_log(LOG_ERROR, "pidlistent malloc failed");
2340*5184Sek110237 			return;
2341*5184Sek110237 		}
2342*5184Sek110237 
2343*5184Sek110237 		pidlistent->pl_pid = pid;
2344*5184Sek110237 		pidlistent->pl_fd = pipe_fd[PIPE_PARENT];
2345*5184Sek110237 		(void) close(pipe_fd[PIPE_CHILD]);
2346*5184Sek110237 
2347*5184Sek110237 		/* Add fileobj to global list */
2348*5184Sek110237 		if (pidlist == NULL) {
2349*5184Sek110237 			pidlist = pidlistent;
2350*5184Sek110237 			pidlistent->pl_next = NULL;
2351*5184Sek110237 		} else {
2352*5184Sek110237 			pidlistent->pl_next = pidlist;
2353*5184Sek110237 			pidlist = pidlistent;
2354*5184Sek110237 		}
2355*5184Sek110237 	}
2356*5184Sek110237 }
2357*5184Sek110237 
2358*5184Sek110237 /*
2359*5184Sek110237  * Launches a shell to run the unix command supplied in the argument.
2360*5184Sek110237  * The command should be enclosed in quotes, as in:
2361*5184Sek110237  * 	system "rm xyz"
2362*5184Sek110237  * which would run the "rm" utility to delete the file "xyz".
2363*5184Sek110237  */
2364*5184Sek110237 static void
2365*5184Sek110237 parser_system(cmd_t *cmd)
2366*5184Sek110237 {
2367*5184Sek110237 	char *string;
2368*5184Sek110237 
2369*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2370*5184Sek110237 		return;
2371*5184Sek110237 
2372*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2373*5184Sek110237 
2374*5184Sek110237 	if (string == NULL)
2375*5184Sek110237 		return;
2376*5184Sek110237 
2377*5184Sek110237 	filebench_log(LOG_VERBOSE,
2378*5184Sek110237 	    "Running '%s'", string);
2379*5184Sek110237 
2380*5184Sek110237 	if (system(string) < 0) {
2381*5184Sek110237 		filebench_log(LOG_ERROR,
2382*5184Sek110237 		    "system exec failed: %s",
2383*5184Sek110237 		    strerror(errno));
2384*5184Sek110237 	}
2385*5184Sek110237 	free(string);
2386*5184Sek110237 }
2387*5184Sek110237 
2388*5184Sek110237 /*
2389*5184Sek110237  * Echos string supplied with command to the log.
2390*5184Sek110237  */
2391*5184Sek110237 static void
2392*5184Sek110237 parser_echo(cmd_t *cmd)
2393*5184Sek110237 {
2394*5184Sek110237 	char *string;
2395*5184Sek110237 
2396*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2397*5184Sek110237 		return;
2398*5184Sek110237 
2399*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2400*5184Sek110237 
2401*5184Sek110237 	if (string == NULL)
2402*5184Sek110237 		return;
2403*5184Sek110237 
2404*5184Sek110237 	filebench_log(LOG_INFO, "%s", string);
2405*5184Sek110237 }
2406*5184Sek110237 
2407*5184Sek110237 
2408*5184Sek110237 /*
2409*5184Sek110237  * Adds the string supplied as the argument to the usage command
2410*5184Sek110237  * to the end of the string printed by the help command.
2411*5184Sek110237  */
2412*5184Sek110237 static void
2413*5184Sek110237 parser_usage(cmd_t *cmd)
2414*5184Sek110237 {
2415*5184Sek110237 	char *string;
2416*5184Sek110237 	char *newusage;
2417*5184Sek110237 
2418*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2419*5184Sek110237 		return;
2420*5184Sek110237 
2421*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2422*5184Sek110237 
2423*5184Sek110237 	if (string == NULL)
2424*5184Sek110237 		return;
2425*5184Sek110237 
2426*5184Sek110237 	if (dofile)
2427*5184Sek110237 		return;
2428*5184Sek110237 
2429*5184Sek110237 	if (usagestr == NULL) {
2430*5184Sek110237 		newusage = malloc(strlen(string) + 2);
2431*5184Sek110237 		*newusage = 0;
2432*5184Sek110237 	} else {
2433*5184Sek110237 		newusage = malloc(strlen(usagestr) + strlen(string) + 2);
2434*5184Sek110237 		(void) strcpy(newusage, usagestr);
2435*5184Sek110237 	}
2436*5184Sek110237 	(void) strcat(newusage, "\n");
2437*5184Sek110237 	(void) strcat(newusage, string);
2438*5184Sek110237 
2439*5184Sek110237 	if (usagestr)
2440*5184Sek110237 		free(usagestr);
2441*5184Sek110237 
2442*5184Sek110237 	usagestr = newusage;
2443*5184Sek110237 
2444*5184Sek110237 	filebench_log(LOG_INFO, "%s", string);
2445*5184Sek110237 }
2446*5184Sek110237 
2447*5184Sek110237 /*
2448*5184Sek110237  * Updates the global dump filename with the filename supplied
2449*5184Sek110237  * as the command's argument. Then dumps the statistics of each
2450*5184Sek110237  * worker flowop into the dump file, followed by a summary of
2451*5184Sek110237  * overall totals.
2452*5184Sek110237  */
2453*5184Sek110237 static void
2454*5184Sek110237 parser_statsdump(cmd_t *cmd)
2455*5184Sek110237 {
2456*5184Sek110237 	char *string;
2457*5184Sek110237 
2458*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2459*5184Sek110237 		return;
2460*5184Sek110237 
2461*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2462*5184Sek110237 
2463*5184Sek110237 	if (string == NULL)
2464*5184Sek110237 		return;
2465*5184Sek110237 
2466*5184Sek110237 	filebench_log(LOG_VERBOSE,
2467*5184Sek110237 	    "Stats dump to file '%s'", string);
2468*5184Sek110237 
2469*5184Sek110237 	stats_dump(string);
2470*5184Sek110237 
2471*5184Sek110237 	free(string);
2472*5184Sek110237 }
2473*5184Sek110237 
2474*5184Sek110237 /*
2475*5184Sek110237  * Same as parser_statsdump, but in xml format.
2476*5184Sek110237  */
2477*5184Sek110237 static void
2478*5184Sek110237 parser_statsxmldump(cmd_t *cmd)
2479*5184Sek110237 {
2480*5184Sek110237 	char *string;
2481*5184Sek110237 
2482*5184Sek110237 	if (cmd->cmd_param_list == NULL)
2483*5184Sek110237 		return;
2484*5184Sek110237 
2485*5184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
2486*5184Sek110237 
2487*5184Sek110237 	if (string == NULL)
2488*5184Sek110237 		return;
2489*5184Sek110237 
2490*5184Sek110237 	filebench_log(LOG_VERBOSE,
2491*5184Sek110237 	    "Stats dump to file '%s'", string);
2492*5184Sek110237 
2493*5184Sek110237 	stats_xmldump(string);
2494*5184Sek110237 
2495*5184Sek110237 	free(string);
2496*5184Sek110237 }
2497*5184Sek110237 
2498*5184Sek110237 /*
2499*5184Sek110237  * Kills off background statistics collection processes, then takes a snapshot
2500*5184Sek110237  * of the filebench run's collected statistics using stats_snap() from
2501*5184Sek110237  * stats.c.
2502*5184Sek110237  */
2503*5184Sek110237 static void
2504*5184Sek110237 parser_statssnap(cmd_t *cmd)
2505*5184Sek110237 {
2506*5184Sek110237 	pidlist_t *pidlistent;
2507*5184Sek110237 	int stat;
2508*5184Sek110237 	pid_t pid;
2509*5184Sek110237 
2510*5184Sek110237 	for (pidlistent = pidlist; pidlistent != NULL;
2511*5184Sek110237 	    pidlistent = pidlistent->pl_next) {
2512*5184Sek110237 		filebench_log(LOG_VERBOSE, "Killing session %d for pid %d",
2513*5184Sek110237 		    getsid(pidlistent->pl_pid),
2514*5184Sek110237 		    pidlistent->pl_pid);
2515*5184Sek110237 		if (pidlistent->pl_fd)
2516*5184Sek110237 			(void) close(pidlistent->pl_fd);
2517*5184Sek110237 #ifdef HAVE_SIGSEND
2518*5184Sek110237 		sigsend(P_SID, getsid(pidlistent->pl_pid), SIGTERM);
2519*5184Sek110237 #else
2520*5184Sek110237 		(void) kill(-1, SIGTERM);
2521*5184Sek110237 #endif
2522*5184Sek110237 
2523*5184Sek110237 		/* Close pipe */
2524*5184Sek110237 		if (pidlistent->pl_fd)
2525*5184Sek110237 			(void) close(pidlistent->pl_fd);
2526*5184Sek110237 
2527*5184Sek110237 		/* Wait for cmd and all its children */
2528*5184Sek110237 		while ((pid = waitpid(pidlistent->pl_pid * -1, &stat, 0)) > 0)
2529*5184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
2530*5184Sek110237 			"Waited for pid %lld", pid);
2531*5184Sek110237 	}
2532*5184Sek110237 
2533*5184Sek110237 	for (pidlistent = pidlist; pidlistent != NULL;
2534*5184Sek110237 	    pidlistent = pidlistent->pl_next) {
2535*5184Sek110237 		free(pidlistent);
2536*5184Sek110237 	}
2537*5184Sek110237 
2538*5184Sek110237 	pidlist = NULL;
2539*5184Sek110237 	stats_snap();
2540*5184Sek110237 }
2541*5184Sek110237 
2542*5184Sek110237 /*
2543*5184Sek110237  * Shutdown filebench.
2544*5184Sek110237  */
2545*5184Sek110237 static void
2546*5184Sek110237 parser_abort(int arg)
2547*5184Sek110237 {
2548*5184Sek110237 	(void) sigignore(SIGINT);
2549*5184Sek110237 	filebench_log(LOG_INFO, "Aborting...");
2550*5184Sek110237 	filebench_shutdown(1);
2551*5184Sek110237 }
2552*5184Sek110237 
2553*5184Sek110237 /*
2554*5184Sek110237  * alloc_cmd() allocates the required resources for a cmd_t. On failure, a
2555*5184Sek110237  * filebench_log is issued and NULL is returned.
2556*5184Sek110237  */
2557*5184Sek110237 static cmd_t *
2558*5184Sek110237 alloc_cmd(void)
2559*5184Sek110237 {
2560*5184Sek110237 	cmd_t *cmd;
2561*5184Sek110237 
2562*5184Sek110237 	if ((cmd = malloc(sizeof (cmd_t))) == NULL) {
2563*5184Sek110237 		filebench_log(LOG_ERROR, "Alloc cmd failed");
2564*5184Sek110237 		return (NULL);
2565*5184Sek110237 	}
2566*5184Sek110237 
2567*5184Sek110237 	(void) memset(cmd, 0, sizeof (cmd_t));
2568*5184Sek110237 
2569*5184Sek110237 	return (cmd);
2570*5184Sek110237 }
2571*5184Sek110237 
2572*5184Sek110237 /*
2573*5184Sek110237  * Frees the resources of a cmd_t and then the cmd_t "cmd" itself.
2574*5184Sek110237  */
2575*5184Sek110237 static void
2576*5184Sek110237 free_cmd(cmd_t *cmd)
2577*5184Sek110237 {
2578*5184Sek110237 	free((void *)cmd->cmd_tgt1);
2579*5184Sek110237 	free((void *)cmd->cmd_tgt2);
2580*5184Sek110237 	free(cmd);
2581*5184Sek110237 }
2582*5184Sek110237 
2583*5184Sek110237 /*
2584*5184Sek110237  * Allocates an attr_t structure and zeros it. Returns NULL on failure, or
2585*5184Sek110237  * a pointer to the attr_t.
2586*5184Sek110237  */
2587*5184Sek110237 static attr_t *
2588*5184Sek110237 alloc_attr()
2589*5184Sek110237 {
2590*5184Sek110237 	attr_t *attr;
2591*5184Sek110237 
2592*5184Sek110237 	if ((attr = malloc(sizeof (attr_t))) == NULL) {
2593*5184Sek110237 		return (NULL);
2594*5184Sek110237 	}
2595*5184Sek110237 
2596*5184Sek110237 	(void) memset(attr, 0, sizeof (attr_t));
2597*5184Sek110237 	return (attr);
2598*5184Sek110237 }
2599*5184Sek110237 
2600*5184Sek110237 /*
2601*5184Sek110237  * Searches the attribute list for the command for the named attribute type.
2602*5184Sek110237  * The attribute list is created by the parser from the list of attributes
2603*5184Sek110237  * supplied with certain commands, such as the define and flowop commands.
2604*5184Sek110237  * Returns a pointer to the attribute structure if the named attribute is
2605*5184Sek110237  * found, otherwise returns NULL. If the attribute includes a parameter list,
2606*5184Sek110237  * the list is converted to a string and stored in the attr_string field of
2607*5184Sek110237  * the returned attr_t struct.
2608*5184Sek110237  */
2609*5184Sek110237 static attr_t *
2610*5184Sek110237 get_attr(cmd_t *cmd, int64_t name)
2611*5184Sek110237 {
2612*5184Sek110237 	attr_t *attr;
2613*5184Sek110237 	attr_t *rtn = NULL;
2614*5184Sek110237 	char *string;
2615*5184Sek110237 
2616*5184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
2617*5184Sek110237 	    attr = attr->attr_next) {
2618*5184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
2619*5184Sek110237 		    "attr %d = %d %llx?",
2620*5184Sek110237 		    attr->attr_name,
2621*5184Sek110237 		    name,
2622*5184Sek110237 		    attr->attr_integer);
2623*5184Sek110237 
2624*5184Sek110237 		if (attr->attr_name == name)
2625*5184Sek110237 			rtn = attr;
2626*5184Sek110237 	}
2627*5184Sek110237 
2628*5184Sek110237 	if (rtn == NULL)
2629*5184Sek110237 		return (NULL);
2630*5184Sek110237 
2631*5184Sek110237 	if (rtn->attr_param_list) {
2632*5184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT, "attr is param list");
2633*5184Sek110237 		string = parser_list2string(rtn->attr_param_list);
2634*5184Sek110237 		if (string != NULL) {
2635*5184Sek110237 			rtn->attr_string = string_alloc(string);
2636*5184Sek110237 			filebench_log(LOG_DEBUG_SCRIPT,
2637*5184Sek110237 			    "attr string %s", string);
2638*5184Sek110237 		}
2639*5184Sek110237 	}
2640*5184Sek110237 
2641*5184Sek110237 	return (rtn);
2642*5184Sek110237 }
2643*5184Sek110237 
2644*5184Sek110237 /*
2645*5184Sek110237  * Similar to get_attr, but converts the parameter string supplied with the
2646*5184Sek110237  * named attribute to an integer and stores the integer in the attr_integer
2647*5184Sek110237  * portion of the returned attr_t struct.
2648*5184Sek110237  */
2649*5184Sek110237 static attr_t *
2650*5184Sek110237 get_attr_integer(cmd_t *cmd, int64_t name)
2651*5184Sek110237 {
2652*5184Sek110237 	attr_t *attr;
2653*5184Sek110237 	attr_t *rtn = NULL;
2654*5184Sek110237 
2655*5184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
2656*5184Sek110237 	    attr = attr->attr_next) {
2657*5184Sek110237 		if (attr->attr_name == name)
2658*5184Sek110237 			rtn = attr;
2659*5184Sek110237 	}
2660*5184Sek110237 
2661*5184Sek110237 	if (rtn == NULL)
2662*5184Sek110237 		return (NULL);
2663*5184Sek110237 
2664*5184Sek110237 	if (rtn->attr_param_list) {
2665*5184Sek110237 		rtn->attr_integer = parser_list2integer(rtn->attr_param_list);
2666*5184Sek110237 	}
2667*5184Sek110237 
2668*5184Sek110237 	return (rtn);
2669*5184Sek110237 }
2670*5184Sek110237 
2671*5184Sek110237 /*
2672*5184Sek110237  * Similar to get_attr, but converts the parameter string supplied with the
2673*5184Sek110237  * named attribute to an integer and stores the integer in the attr_integer
2674*5184Sek110237  * portion of the returned attr_t struct. If no parameter string is supplied
2675*5184Sek110237  * then it defaults to TRUE (1).
2676*5184Sek110237  */
2677*5184Sek110237 static attr_t *
2678*5184Sek110237 get_attr_bool(cmd_t *cmd, int64_t name)
2679*5184Sek110237 {
2680*5184Sek110237 	attr_t *attr;
2681*5184Sek110237 	attr_t *rtn = NULL;
2682*5184Sek110237 
2683*5184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
2684*5184Sek110237 	    attr = attr->attr_next) {
2685*5184Sek110237 		if (attr->attr_name == name)
2686*5184Sek110237 			rtn = attr;
2687*5184Sek110237 	}
2688*5184Sek110237 
2689*5184Sek110237 	if (rtn == NULL)
2690*5184Sek110237 		return (NULL);
2691*5184Sek110237 
2692*5184Sek110237 	if (rtn->attr_param_list) {
2693*5184Sek110237 		rtn->attr_integer = parser_list2integer(rtn->attr_param_list);
2694*5184Sek110237 	} else if (rtn->attr_integer == 0) {
2695*5184Sek110237 		rtn->attr_integer = integer_alloc(1);
2696*5184Sek110237 	}
2697*5184Sek110237 
2698*5184Sek110237 	return (rtn);
2699*5184Sek110237 }
2700*5184Sek110237 
2701*5184Sek110237 /*
2702*5184Sek110237  * Allocates memory for a list_t structure, initializes it to zero, and
2703*5184Sek110237  * returns a pointer to it. On failure, returns NULL.
2704*5184Sek110237  */
2705*5184Sek110237 static list_t *
2706*5184Sek110237 alloc_list()
2707*5184Sek110237 {
2708*5184Sek110237 	list_t *list;
2709*5184Sek110237 
2710*5184Sek110237 	if ((list = malloc(sizeof (list_t))) == NULL) {
2711*5184Sek110237 		return (NULL);
2712*5184Sek110237 	}
2713*5184Sek110237 
2714*5184Sek110237 	(void) memset(list, 0, sizeof (list_t));
2715*5184Sek110237 	return (list);
2716*5184Sek110237 }
2717*5184Sek110237 
2718*5184Sek110237 
2719*5184Sek110237 #define	USAGE1	\
2720*5184Sek110237 "Usage:\n" \
2721*5184Sek110237 "%s: interpret f script and generate file workload\n" \
2722*5184Sek110237 "Options:\n" \
2723*5184Sek110237 "   [-h] Display verbose help\n" \
2724*5184Sek110237 "   [-p] Disable opening /proc to set uacct to enable truss\n"
2725*5184Sek110237 
2726*5184Sek110237 #define	PARSER_CMDS \
2727*5184Sek110237 "create [files|filesets|processes]\n" \
2728*5184Sek110237 "stats [clear|snap]\n" \
2729*5184Sek110237 "stats command \"shell command $var1,$var2...\"\n" \
2730*5184Sek110237 "stats directory <directory>\n" \
2731*5184Sek110237 "sleep <sleep-value>\n" \
2732*5184Sek110237 "quit\n\n" \
2733*5184Sek110237 "Variables:\n" \
2734*5184Sek110237 "set $var = value\n" \
2735*5184Sek110237 "    $var   - regular variables\n" \
2736*5184Sek110237 "    ${var} - internal special variables\n" \
2737*5184Sek110237 "    $(var) - environment variables\n\n"
2738*5184Sek110237 
2739*5184Sek110237 #define	PARSER_EXAMPLE \
2740*5184Sek110237 "Example:\n\n" \
2741*5184Sek110237 "#!/usr/bin/filebench -f\n" \
2742*5184Sek110237 "\n" \
2743*5184Sek110237 "define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \
2744*5184Sek110237 "define process name=randomizer\n" \
2745*5184Sek110237 "{\n" \
2746*5184Sek110237 "  thread random-thread procname=randomizer\n"	\
2747*5184Sek110237 "  {\n" \
2748*5184Sek110237 "    flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \
2749*5184Sek110237 "  }\n" \
2750*5184Sek110237 "}\n" \
2751*5184Sek110237 "create files\n" \
2752*5184Sek110237 "create processes\n" \
2753*5184Sek110237 "stats clear\n" \
2754*5184Sek110237 "sleep 30\n" \
2755*5184Sek110237 "stats snap\n"
2756*5184Sek110237 
2757*5184Sek110237 /*
2758*5184Sek110237  * usage() display brief or verbose help for the filebench(1) command.
2759*5184Sek110237  */
2760*5184Sek110237 static void
2761*5184Sek110237 usage(int help)
2762*5184Sek110237 {
2763*5184Sek110237 	if (help >= 1)
2764*5184Sek110237 		(void) fprintf(stderr, USAGE1, cmdname);
2765*5184Sek110237 	if (help >= 2) {
2766*5184Sek110237 
2767*5184Sek110237 		(void) fprintf(stderr,
2768*5184Sek110237 		    "\n'f' language definition:\n\n");
2769*5184Sek110237 		fileobj_usage();
2770*5184Sek110237 		fileset_usage();
2771*5184Sek110237 		procflow_usage();
2772*5184Sek110237 		threadflow_usage();
2773*5184Sek110237 		flowoplib_usage();
2774*5184Sek110237 		eventgen_usage();
2775*5184Sek110237 		(void) fprintf(stderr, PARSER_CMDS);
2776*5184Sek110237 		(void) fprintf(stderr, PARSER_EXAMPLE);
2777*5184Sek110237 	}
2778*5184Sek110237 	exit(E_USAGE);
2779*5184Sek110237 }
2780*5184Sek110237 
2781*5184Sek110237 int
2782*5184Sek110237 yywrap()
2783*5184Sek110237 {
2784*5184Sek110237 	char buf[1024];
2785*5184Sek110237 
2786*5184Sek110237 	if (parentscript) {
2787*5184Sek110237 		yyin = parentscript;
2788*5184Sek110237 		yy_switchfilescript(yyin);
2789*5184Sek110237 		parentscript = NULL;
2790*5184Sek110237 		return (0);
2791*5184Sek110237 	} else
2792*5184Sek110237 		return (1);
2793*5184Sek110237 }
2794