xref: /onnv-gate/usr/src/cmd/filebench/common/parser_gram.y (revision 6084:d5f45b4dae7e)
15184Sek110237 
25184Sek110237 /*
35184Sek110237  * CDDL HEADER START
45184Sek110237  *
55184Sek110237  * The contents of this file are subject to the terms of the
65184Sek110237  * Common Development and Distribution License (the "License").
75184Sek110237  * You may not use this file except in compliance with the License.
85184Sek110237  *
95184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
105184Sek110237  * or http://www.opensolaris.org/os/licensing.
115184Sek110237  * See the License for the specific language governing permissions
125184Sek110237  * and limitations under the License.
135184Sek110237  *
145184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
155184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
165184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
175184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
185184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
195184Sek110237  *
205184Sek110237  * CDDL HEADER END
215184Sek110237  */
225184Sek110237 /*
23*6084Saw148015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
245184Sek110237  * Use is subject to license terms.
255184Sek110237  */
265184Sek110237 
275184Sek110237 %{
285184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
295184Sek110237 %}
305184Sek110237 
315184Sek110237 %{
325184Sek110237 
335184Sek110237 #include <stdlib.h>
345184Sek110237 #include <stdio.h>
355184Sek110237 #include <string.h>
365184Sek110237 #include <signal.h>
375184Sek110237 #include <errno.h>
385184Sek110237 #include <sys/types.h>
395184Sek110237 #include <locale.h>
405184Sek110237 #include <sys/utsname.h>
415184Sek110237 #ifdef HAVE_STDINT_H
425184Sek110237 #include <stdint.h>
435184Sek110237 #endif
445184Sek110237 #include <fcntl.h>
455184Sek110237 #include <sys/mman.h>
465184Sek110237 #include <sys/wait.h>
475184Sek110237 #ifdef HAVE_LIBTECLA
485184Sek110237 #include <libtecla.h>
495184Sek110237 #endif
505184Sek110237 #include "parsertypes.h"
515184Sek110237 #include "filebench.h"
525184Sek110237 #include "utils.h"
535184Sek110237 #include "stats.h"
545184Sek110237 #include "vars.h"
555184Sek110237 #include "eventgen.h"
565184Sek110237 #ifdef HAVE_LIBTECLA
575184Sek110237 #include "auto_comp.h"
585184Sek110237 #endif
595184Sek110237 
605184Sek110237 int dofile = FS_FALSE;
615184Sek110237 static const char cmdname[] = "filebench";
625184Sek110237 static const char cmd_options[] = "pa:f:hi:s:m:";
635184Sek110237 static void usage(int);
645184Sek110237 
655184Sek110237 static cmd_t *cmd = NULL;		/* Command being processed */
665184Sek110237 #ifdef HAVE_LIBTECLA
675184Sek110237 static GetLine *gl;			/* GetLine resource object */
685184Sek110237 #endif
695184Sek110237 
705184Sek110237 char *execname;
715184Sek110237 char *fscriptname;
725184Sek110237 int noproc = 0;
735184Sek110237 var_t *var_list = NULL;
745184Sek110237 pidlist_t *pidlist = NULL;
755184Sek110237 char *cwd = NULL;
765184Sek110237 FILE *parentscript = NULL;
775673Saw148015 
785673Saw148015 static int filecreate_done = 0;
795673Saw148015 
805184Sek110237 /* yacc externals */
815184Sek110237 extern FILE *yyin;
825184Sek110237 extern int yydebug;
835184Sek110237 extern void yyerror(char *s);
845184Sek110237 
855184Sek110237 /* utilities */
865184Sek110237 static void terminate(void);
875184Sek110237 static cmd_t *alloc_cmd(void);
885184Sek110237 static attr_t *alloc_attr(void);
895184Sek110237 static attr_t *get_attr(cmd_t *cmd, int64_t name);
905184Sek110237 static attr_t *get_attr_integer(cmd_t *cmd, int64_t name);
915184Sek110237 static attr_t *get_attr_bool(cmd_t *cmd, int64_t name);
925184Sek110237 static var_t *alloc_var(void);
935184Sek110237 static var_t *get_var(cmd_t *cmd, int64_t name);
945184Sek110237 static list_t *alloc_list();
955184Sek110237 
965184Sek110237 /* Info Commands */
975184Sek110237 static void parser_list(cmd_t *);
985184Sek110237 
995184Sek110237 /* Define Commands */
1005184Sek110237 static void parser_proc_define(cmd_t *);
1015184Sek110237 static void parser_thread_define(cmd_t *, procflow_t *, int instances);
1025184Sek110237 static void parser_flowop_define(cmd_t *, threadflow_t *);
1035184Sek110237 static void parser_file_define(cmd_t *);
1045184Sek110237 static void parser_fileset_define(cmd_t *);
1055184Sek110237 
1065184Sek110237 /* Create Commands */
1075184Sek110237 static void parser_proc_create(cmd_t *);
1085184Sek110237 static void parser_thread_create(cmd_t *);
1095184Sek110237 static void parser_flowop_create(cmd_t *);
1105184Sek110237 static void parser_fileset_create(cmd_t *);
1115184Sek110237 
1125184Sek110237 /* Shutdown Commands */
1135184Sek110237 static void parser_proc_shutdown(cmd_t *);
1145184Sek110237 static void parser_filebench_shutdown(cmd_t *cmd);
1155184Sek110237 
1165184Sek110237 /* Other Commands */
1175184Sek110237 static void parser_foreach_integer(cmd_t *cmd);
1185184Sek110237 static void parser_foreach_string(cmd_t *cmd);
1195184Sek110237 static void parser_sleep(cmd_t *cmd);
1205184Sek110237 static void parser_sleep_variable(cmd_t *cmd);
1215184Sek110237 static void parser_log(cmd_t *cmd);
1225184Sek110237 static void parser_statscmd(cmd_t *cmd);
1235184Sek110237 static void parser_statsdump(cmd_t *cmd);
1245184Sek110237 static void parser_statsxmldump(cmd_t *cmd);
1255184Sek110237 static void parser_echo(cmd_t *cmd);
1265184Sek110237 static void parser_usage(cmd_t *cmd);
1275184Sek110237 static void parser_vars(cmd_t *cmd);
1285184Sek110237 static void parser_printvars(cmd_t *cmd);
1295184Sek110237 static void parser_system(cmd_t *cmd);
1305184Sek110237 static void parser_statssnap(cmd_t *cmd);
1315184Sek110237 static void parser_directory(cmd_t *cmd);
1325184Sek110237 static void parser_eventgen(cmd_t *cmd);
1335184Sek110237 static void parser_run(cmd_t *cmd);
1345184Sek110237 static void parser_run_variable(cmd_t *cmd);
1355184Sek110237 static void parser_help(cmd_t *cmd);
1365184Sek110237 static void arg_parse(const char *command);
1375184Sek110237 static void parser_abort(int arg);
1385184Sek110237 
1395184Sek110237 %}
1405184Sek110237 
1415184Sek110237 %union {
1425184Sek110237 	int64_t	 ival;
1435184Sek110237 	uchar_t  bval;
1445184Sek110237 	char *	 sval;
1455184Sek110237 	fs_u	 val;
1465184Sek110237 	cmd_t	 *cmd;
1475184Sek110237 	attr_t	 *attr;
1485184Sek110237 	list_t	 *list;
1495184Sek110237 }
1505184Sek110237 
1515184Sek110237 %start commands
1525184Sek110237 
1535184Sek110237 %token FSC_LIST FSC_DEFINE FSC_EXEC FSC_QUIT FSC_DEBUG FSC_CREATE
1545184Sek110237 %token FSC_SLEEP FSC_STATS FSC_FOREACH FSC_SET FSC_SHUTDOWN FSC_LOG
1555184Sek110237 %token FSC_SYSTEM FSC_FLOWOP FSC_EVENTGEN FSC_ECHO FSC_LOAD FSC_RUN
1565184Sek110237 %token FSC_USAGE FSC_HELP FSC_VARS
1575184Sek110237 %token FSV_STRING FSV_VAL_INT FSV_VAL_BOOLEAN FSV_VARIABLE FSV_WHITESTRING
1585184Sek110237 %token FST_INT FST_BOOLEAN
1595184Sek110237 %token FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSE_ALL FSE_SNAP FSE_DUMP
160*6084Saw148015 %token FSE_DIRECTORY FSE_COMMAND FSE_FILESET FSE_XMLDUMP FSE_MODE
1615184Sek110237 %token FSK_SEPLST FSK_OPENLST FSK_CLOSELST FSK_ASSIGN FSK_IN FSK_QUOTE
1625184Sek110237 %token FSK_DIRSEPLST
1635184Sek110237 %token FSA_SIZE FSA_PREALLOC FSA_PARALLOC FSA_PATH FSA_REUSE
1645184Sek110237 %token FSA_PROCESS FSA_MEMSIZE FSA_RATE FSA_CACHED
1655184Sek110237 %token FSA_IOSIZE FSA_FILE FSA_WSS FSA_NAME FSA_RANDOM FSA_INSTANCES
1665184Sek110237 %token FSA_DSYNC FSA_TARGET FSA_ITERS FSA_NICE FSA_VALUE FSA_BLOCKING
1675184Sek110237 %token FSA_HIGHWATER FSA_DIRECTIO FSA_DIRWIDTH FSA_FD FSA_SRCFD FSA_ROTATEFD
1685184Sek110237 %token FSA_NAMELENGTH FSA_FILESIZE FSA_ENTRIES FSA_FILESIZEGAMMA
169*6084Saw148015 %token FSA_DIRGAMMA FSA_USEISM FSA_ALLDONE FSA_FIRSTDONE FSA_TIMEOUT
1705184Sek110237 
1715184Sek110237 %type <ival> FSV_VAL_INT
1725184Sek110237 %type <bval> FSV_VAL_BOOLEAN
1735184Sek110237 %type <sval> FSV_STRING
1745184Sek110237 %type <sval> FSV_WHITESTRING
1755184Sek110237 %type <sval> FSV_VARIABLE
1765184Sek110237 %type <sval> FSK_ASSIGN
1775184Sek110237 
1785184Sek110237 %type <ival> FSC_LIST FSC_DEFINE FSC_SET FSC_LOAD FSC_RUN
1795184Sek110237 %type <ival> FSE_FILE FSE_PROC FSE_THREAD FSE_CLEAR FSC_HELP
1805184Sek110237 
1815184Sek110237 %type <sval> name
1825184Sek110237 %type <ival> entity
1835184Sek110237 %type <val>  value
1845184Sek110237 
1855184Sek110237 %type <cmd> command inner_commands load_command run_command
1865184Sek110237 %type <cmd> list_command define_command debug_command create_command
1875184Sek110237 %type <cmd> sleep_command stats_command set_command shutdown_command
1885184Sek110237 %type <cmd> foreach_command log_command system_command flowop_command
1895184Sek110237 %type <cmd> eventgen_command quit_command flowop_list thread_list
1905184Sek110237 %type <cmd> thread echo_command usage_command help_command vars_command
1915184Sek110237 
1925184Sek110237 %type <attr> attr_op attr_ops
1935184Sek110237 %type <attr> attr_value
1945184Sek110237 %type <list> integer_seplist string_seplist string_list var_string_list var_string
1955184Sek110237 %type <list> whitevar_string whitevar_string_list
1965184Sek110237 %type <ival> attrs_define_file attrs_define_thread attrs_flowop attrs_define_fileset
1975184Sek110237 %type <ival> attrs_define_proc attrs_eventgen
1985184Sek110237 %type <ival> attr_name
1995184Sek110237 
2005184Sek110237 %%
2015184Sek110237 
2025184Sek110237 commands: commands command
2035184Sek110237 {
2045184Sek110237 	list_t *list = NULL;
2055184Sek110237 	list_t *list_end = NULL;
2065184Sek110237 
2075184Sek110237 	if ($2->cmd != NULL)
2085184Sek110237 		$2->cmd($2);
2095184Sek110237 
2105184Sek110237 	free($2);
2115184Sek110237 }
2125184Sek110237 | commands error
2135184Sek110237 {
2145184Sek110237 	if (dofile)
2155184Sek110237 		YYABORT;
2165184Sek110237 }
2175184Sek110237 |;
2185184Sek110237 
2195184Sek110237 inner_commands: command
2205184Sek110237 {
2215184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "inner_command %zx", $1);
2225184Sek110237 	$$ = $1;
2235184Sek110237 }
2245184Sek110237 | inner_commands command
2255184Sek110237 {
2265184Sek110237 	cmd_t *list = NULL;
2275184Sek110237 	cmd_t *list_end = NULL;
2285184Sek110237 
2295184Sek110237 	/* Find end of list */
2305184Sek110237 	for (list = $1; list != NULL;
2315184Sek110237 	    list = list->cmd_next)
2325184Sek110237 		list_end = list;
2335184Sek110237 
2345184Sek110237 	list_end->cmd_next = $2;
2355184Sek110237 
2365184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
2375184Sek110237 	    "inner_commands adding cmd %zx to list %zx", $2, $1);
2385184Sek110237 
2395184Sek110237 	$$ = $1;
2405184Sek110237 };
2415184Sek110237 
2425184Sek110237 command:
2435184Sek110237   define_command
2445184Sek110237 | debug_command
2455184Sek110237 | eventgen_command
2465184Sek110237 | create_command
2475184Sek110237 | echo_command
2485184Sek110237 | usage_command
2495184Sek110237 | vars_command
2505184Sek110237 | foreach_command
2515184Sek110237 | help_command
2525184Sek110237 | list_command
2535184Sek110237 | load_command
2545184Sek110237 | log_command
2555184Sek110237 | run_command
2565184Sek110237 | set_command
2575184Sek110237 | shutdown_command
2585184Sek110237 | sleep_command
2595184Sek110237 | stats_command
2605184Sek110237 | system_command
2615184Sek110237 | quit_command;
2625184Sek110237 
2635184Sek110237 foreach_command: FSC_FOREACH
2645184Sek110237 {
2655184Sek110237 	if (($$ = alloc_cmd()) == NULL)
2665184Sek110237 		YYERROR;
2675184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "foreach_command %zx", $$);
2685184Sek110237 }
2695184Sek110237 | foreach_command FSV_VARIABLE FSK_IN integer_seplist FSK_OPENLST inner_commands FSK_CLOSELST
2705184Sek110237 {
2715184Sek110237 	cmd_t *cmd, *inner_cmd;
2725184Sek110237 	list_t *list;
2735184Sek110237 
2745184Sek110237 	$$ = $1;
2755184Sek110237 	$$->cmd_list = $6;
2765184Sek110237 	$$->cmd_tgt1 = $2;
2775184Sek110237 	$$->cmd_param_list = $4;
2785184Sek110237 	$$->cmd = parser_foreach_integer;
2795184Sek110237 
2805184Sek110237 	for (list = $$->cmd_param_list; list != NULL;
2815184Sek110237 	    list = list->list_next) {
2825184Sek110237 		for (inner_cmd = $$->cmd_list;
2835184Sek110237 		    inner_cmd != NULL;
2845184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
2855184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
2865184Sek110237 			    "packing foreach: %zx %s=%lld, cmd %zx",
2875184Sek110237 			    $$,
2885184Sek110237 			    $$->cmd_tgt1,
2895184Sek110237 			    *list->list_integer, inner_cmd);
2905184Sek110237 		}
2915184Sek110237 	}
2925184Sek110237 }| foreach_command FSV_VARIABLE FSK_IN string_seplist FSK_OPENLST inner_commands FSK_CLOSELST
2935184Sek110237 {
2945184Sek110237 	cmd_t *cmd, *inner_cmd;
2955184Sek110237 	list_t *list;
2965184Sek110237 
2975184Sek110237 	$$ = $1;
2985184Sek110237 	$$->cmd_list = $6;
2995184Sek110237 	$$->cmd_tgt1 = $2;
3005184Sek110237 	$$->cmd_param_list = $4;
3015184Sek110237 	$$->cmd = parser_foreach_string;
3025184Sek110237 
3035184Sek110237 	for (list = $$->cmd_param_list; list != NULL;
3045184Sek110237 	    list = list->list_next) {
3055184Sek110237 		for (inner_cmd = $$->cmd_list;
3065184Sek110237 		    inner_cmd != NULL;
3075184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
3085184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
3095184Sek110237 			    "packing foreach: %zx %s=%s, cmd %zx",
3105184Sek110237 			    $$,
3115184Sek110237 			    $$->cmd_tgt1,
3125184Sek110237 			    *list->list_string, inner_cmd);
3135184Sek110237 		}
3145184Sek110237 	}
3155184Sek110237 };
3165184Sek110237 
3175184Sek110237 integer_seplist: FSV_VAL_INT
3185184Sek110237 {
3195184Sek110237 	if (($$ = alloc_list()) == NULL)
3205184Sek110237 		YYERROR;
3215184Sek110237 
3225184Sek110237 	$$->list_integer = integer_alloc($1);
3235184Sek110237 }
3245184Sek110237 | integer_seplist FSK_SEPLST FSV_VAL_INT
3255184Sek110237 {
3265184Sek110237 	list_t *list = NULL;
3275184Sek110237 	list_t *list_end = NULL;
3285184Sek110237 
3295184Sek110237 	if (($$ = alloc_list()) == NULL)
3305184Sek110237 		YYERROR;
3315184Sek110237 
3325184Sek110237 	$$->list_integer = integer_alloc($3);
3335184Sek110237 
3345184Sek110237 	/* Find end of list */
3355184Sek110237 	for (list = $1; list != NULL;
3365184Sek110237 	    list = list->list_next)
3375184Sek110237 		list_end = list;
3385184Sek110237 	list_end->list_next = $$;
3395184Sek110237 	$$ = $1;
3405184Sek110237 };
3415184Sek110237 
3425184Sek110237 string_seplist: FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
3435184Sek110237 {
3445184Sek110237 	if (($$ = alloc_list()) == NULL)
3455184Sek110237 		YYERROR;
3465184Sek110237 
3475184Sek110237 	$$->list_string = string_alloc($2);
3485184Sek110237 }
3495184Sek110237 | string_seplist FSK_SEPLST FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
3505184Sek110237 {
3515184Sek110237 	list_t *list = NULL;
3525184Sek110237 	list_t *list_end = NULL;
3535184Sek110237 
3545184Sek110237 	if (($$ = alloc_list()) == NULL)
3555184Sek110237 			YYERROR;
3565184Sek110237 
3575184Sek110237 	$$->list_string = string_alloc($4);
3585184Sek110237 
3595184Sek110237 	/* Find end of list */
3605184Sek110237 	for (list = $1; list != NULL;
3615184Sek110237 	    list = list->list_next)
3625184Sek110237 		list_end = list;
3635184Sek110237 	list_end->list_next = $$;
3645184Sek110237 	$$ = $1;
3655184Sek110237 };
3665184Sek110237 
3675184Sek110237 eventgen_command: FSC_EVENTGEN
3685184Sek110237 {
3695184Sek110237 	if (($$ = alloc_cmd()) == NULL)
3705184Sek110237 		YYERROR;
3715184Sek110237 	$$->cmd = &parser_eventgen;
3725184Sek110237 }
3735184Sek110237 | eventgen_command attr_ops
3745184Sek110237 {
3755184Sek110237 	$1->cmd_attr_list = $2;
3765184Sek110237 };
3775184Sek110237 
3785184Sek110237 system_command: FSC_SYSTEM whitevar_string_list
3795184Sek110237 {
3805184Sek110237 	if (($$ = alloc_cmd()) == NULL)
3815184Sek110237 		YYERROR;
3825184Sek110237 
3835184Sek110237 	$$->cmd_param_list = $2;
3845184Sek110237 	$$->cmd = parser_system;
3855184Sek110237 };
3865184Sek110237 
3875184Sek110237 echo_command: FSC_ECHO whitevar_string_list
3885184Sek110237 {
3895184Sek110237 	if (($$ = alloc_cmd()) == NULL)
3905184Sek110237 		YYERROR;
3915184Sek110237 
3925184Sek110237 	$$->cmd_param_list = $2;
3935184Sek110237 	$$->cmd = parser_echo;
3945184Sek110237 };
3955184Sek110237 
3965184Sek110237 usage_command: FSC_USAGE whitevar_string_list
3975184Sek110237 {
3985184Sek110237 	if (($$ = alloc_cmd()) == NULL)
3995184Sek110237 		YYERROR;
4005184Sek110237 
4015184Sek110237 	$$->cmd_param_list = $2;
4025184Sek110237 	$$->cmd = parser_usage;
4035184Sek110237 };
4045184Sek110237 
4055184Sek110237 vars_command: FSC_VARS
4065184Sek110237 {
4075184Sek110237 	if (($$ = alloc_cmd()) == NULL)
4085184Sek110237 		YYERROR;
4095184Sek110237 
4105184Sek110237 	$$->cmd = parser_printvars;
4115184Sek110237 };
4125184Sek110237 
4135184Sek110237 string_list: FSV_VARIABLE
4145184Sek110237 {
4155184Sek110237 	if (($$ = alloc_list()) == NULL)
4165184Sek110237 			YYERROR;
4175184Sek110237 
4185184Sek110237 	$$->list_string = string_alloc($1);
4195184Sek110237 }
4205184Sek110237 | string_list FSK_SEPLST FSV_VARIABLE
4215184Sek110237 {
4225184Sek110237 	list_t *list = NULL;
4235184Sek110237 	list_t *list_end = NULL;
4245184Sek110237 
4255184Sek110237 	if (($$ = alloc_list()) == NULL)
4265184Sek110237 		YYERROR;
4275184Sek110237 
4285184Sek110237 	$$->list_string = string_alloc($3);
4295184Sek110237 
4305184Sek110237 	/* Find end of list */
4315184Sek110237 	for (list = $1; list != NULL;
4325184Sek110237 	    list = list->list_next)
4335184Sek110237 		list_end = list;
4345184Sek110237 	list_end->list_next = $$;
4355184Sek110237 	$$ = $1;
4365184Sek110237 };
4375184Sek110237 
4385184Sek110237 var_string: FSV_VARIABLE
4395184Sek110237 {
4405184Sek110237 	if (($$ = alloc_list()) == NULL)
4415184Sek110237 			YYERROR;
4425184Sek110237 
4435184Sek110237 	$$->list_string = string_alloc($1);
4445184Sek110237 }
4455184Sek110237 | FSV_STRING
4465184Sek110237 {
4475184Sek110237 	if (($$ = alloc_list()) == NULL)
4485184Sek110237 			YYERROR;
4495184Sek110237 
4505184Sek110237 	$$->list_string = string_alloc($1);
4515184Sek110237 };
4525184Sek110237 
4535184Sek110237 var_string_list: var_string
4545184Sek110237 {
4555184Sek110237 	$$ = $1;
4565184Sek110237 }| var_string FSV_STRING
4575184Sek110237 {
4585184Sek110237 	list_t *list = NULL;
4595184Sek110237 	list_t *list_end = NULL;
4605184Sek110237 
4615184Sek110237 	/* Add string */
4625184Sek110237 	if (($$ = alloc_list()) == NULL)
4635184Sek110237 		YYERROR;
4645184Sek110237 
4655184Sek110237 	$$->list_string = string_alloc($2);
4665184Sek110237 
4675184Sek110237 	/* Find end of list */
4685184Sek110237 	for (list = $1; list != NULL;
4695184Sek110237 	    list = list->list_next)
4705184Sek110237 		list_end = list;
4715184Sek110237 	list_end->list_next = $$;
4725184Sek110237 	$$ = $1;
4735184Sek110237 
4745184Sek110237 }| var_string FSV_VARIABLE
4755184Sek110237 {
4765184Sek110237 	list_t *list = NULL;
4775184Sek110237 	list_t *list_end = NULL;
4785184Sek110237 
4795184Sek110237 	/* Add variable */
4805184Sek110237 	if (($$ = alloc_list()) == NULL)
4815184Sek110237 		YYERROR;
4825184Sek110237 
4835184Sek110237 	$$->list_string = string_alloc($2);
4845184Sek110237 
4855184Sek110237 	/* Find end of list */
4865184Sek110237 	for (list = $1; list != NULL;
4875184Sek110237 	    list = list->list_next)
4885184Sek110237 		list_end = list;
4895184Sek110237 	list_end->list_next = $$;
4905184Sek110237 	$$ = $1;
4915184Sek110237 } |var_string_list FSV_STRING
4925184Sek110237 {
4935184Sek110237 	list_t *list = NULL;
4945184Sek110237 	list_t *list_end = NULL;
4955184Sek110237 
4965184Sek110237 	/* Add string */
4975184Sek110237 	if (($$ = alloc_list()) == NULL)
4985184Sek110237 		YYERROR;
4995184Sek110237 
5005184Sek110237 	$$->list_string = string_alloc($2);
5015184Sek110237 
5025184Sek110237 	/* Find end of list */
5035184Sek110237 	for (list = $1; list != NULL;
5045184Sek110237 	    list = list->list_next)
5055184Sek110237 		list_end = list;
5065184Sek110237 	list_end->list_next = $$;
5075184Sek110237 	$$ = $1;
5085184Sek110237 
5095184Sek110237 }| var_string_list FSV_VARIABLE
5105184Sek110237 {
5115184Sek110237 	list_t *list = NULL;
5125184Sek110237 	list_t *list_end = NULL;
5135184Sek110237 
5145184Sek110237 	/* Add variable */
5155184Sek110237 	if (($$ = alloc_list()) == NULL)
5165184Sek110237 		YYERROR;
5175184Sek110237 
5185184Sek110237 	$$->list_string = string_alloc($2);
5195184Sek110237 
5205184Sek110237 	/* Find end of list */
5215184Sek110237 	for (list = $1; list != NULL;
5225184Sek110237 	    list = list->list_next)
5235184Sek110237 		list_end = list;
5245184Sek110237 	list_end->list_next = $$;
5255184Sek110237 	$$ = $1;
5265184Sek110237 };
5275184Sek110237 
5285184Sek110237 whitevar_string: FSK_QUOTE FSV_VARIABLE
5295184Sek110237 {
5305184Sek110237 	if (($$ = alloc_list()) == NULL)
5315184Sek110237 			YYERROR;
5325184Sek110237 
5335184Sek110237 	$$->list_string = string_alloc($2);
5345184Sek110237 }
5355184Sek110237 | FSK_QUOTE FSV_WHITESTRING
5365184Sek110237 {
5375184Sek110237 	if (($$ = alloc_list()) == NULL)
5385184Sek110237 			YYERROR;
5395184Sek110237 
5405184Sek110237 	$$->list_string = string_alloc($2);
5415184Sek110237 };
5425184Sek110237 
5435184Sek110237 whitevar_string_list: whitevar_string FSV_WHITESTRING
5445184Sek110237 {
5455184Sek110237 	list_t *list = NULL;
5465184Sek110237 	list_t *list_end = NULL;
5475184Sek110237 
5485184Sek110237 	/* Add string */
5495184Sek110237 	if (($$ = alloc_list()) == NULL)
5505184Sek110237 		YYERROR;
5515184Sek110237 
5525184Sek110237 	$$->list_string = string_alloc($2);
5535184Sek110237 
5545184Sek110237 	/* Find end of list */
5555184Sek110237 	for (list = $1; list != NULL;
5565184Sek110237 	    list = list->list_next)
5575184Sek110237 		list_end = list;
5585184Sek110237 	list_end->list_next = $$;
5595184Sek110237 	$$ = $1;
5605184Sek110237 
5615184Sek110237 }| whitevar_string FSV_VARIABLE
5625184Sek110237 {
5635184Sek110237 	list_t *list = NULL;
5645184Sek110237 	list_t *list_end = NULL;
5655184Sek110237 
5665184Sek110237 	/* Add variable */
5675184Sek110237 	if (($$ = alloc_list()) == NULL)
5685184Sek110237 		YYERROR;
5695184Sek110237 
5705184Sek110237 	$$->list_string = string_alloc($2);
5715184Sek110237 
5725184Sek110237 	/* Find end of list */
5735184Sek110237 	for (list = $1; list != NULL;
5745184Sek110237 	    list = list->list_next)
5755184Sek110237 		list_end = list;
5765184Sek110237 	list_end->list_next = $$;
5775184Sek110237 	$$ = $1;
5785184Sek110237 } |whitevar_string_list FSV_WHITESTRING
5795184Sek110237 {
5805184Sek110237 	list_t *list = NULL;
5815184Sek110237 	list_t *list_end = NULL;
5825184Sek110237 
5835184Sek110237 	/* Add string */
5845184Sek110237 	if (($$ = alloc_list()) == NULL)
5855184Sek110237 		YYERROR;
5865184Sek110237 
5875184Sek110237 	$$->list_string = string_alloc($2);
5885184Sek110237 
5895184Sek110237 	/* Find end of list */
5905184Sek110237 	for (list = $1; list != NULL;
5915184Sek110237 	    list = list->list_next)
5925184Sek110237 		list_end = list;
5935184Sek110237 	list_end->list_next = $$;
5945184Sek110237 	$$ = $1;
5955184Sek110237 
5965184Sek110237 }| whitevar_string_list FSV_VARIABLE
5975184Sek110237 {
5985184Sek110237 	list_t *list = NULL;
5995184Sek110237 	list_t *list_end = NULL;
6005184Sek110237 
6015184Sek110237 	/* Add variable */
6025184Sek110237 	if (($$ = alloc_list()) == NULL)
6035184Sek110237 		YYERROR;
6045184Sek110237 
6055184Sek110237 	$$->list_string = string_alloc($2);
6065184Sek110237 
6075184Sek110237 	/* Find end of list */
6085184Sek110237 	for (list = $1; list != NULL;
6095184Sek110237 	    list = list->list_next)
6105184Sek110237 		list_end = list;
6115184Sek110237 	list_end->list_next = $$;
6125184Sek110237 	$$ = $1;
6135184Sek110237 }| whitevar_string_list FSK_QUOTE
6145184Sek110237 {
6155184Sek110237 	$$ = $1;
6165184Sek110237 }| whitevar_string FSK_QUOTE
6175184Sek110237 {
6185184Sek110237 	$$ = $1;
6195184Sek110237 };
6205184Sek110237 
6215184Sek110237 list_command: FSC_LIST
6225184Sek110237 {
6235184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6245184Sek110237 		YYERROR;
6255184Sek110237 	$$->cmd = &parser_list;
6265184Sek110237 };
6275184Sek110237 
6285184Sek110237 log_command: FSC_LOG whitevar_string_list
6295184Sek110237 {
6305184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6315184Sek110237 		YYERROR;
6325184Sek110237 	$$->cmd = &parser_log;
6335184Sek110237 	$$->cmd_param_list = $2;
6345184Sek110237 };
6355184Sek110237 
6365184Sek110237 debug_command: FSC_DEBUG FSV_VAL_INT
6375184Sek110237 {
6385184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6395184Sek110237 		YYERROR;
6405184Sek110237 	$$->cmd = NULL;
6415184Sek110237 	filebench_shm->debug_level = $2;
6425184Sek110237 	if (filebench_shm->debug_level > 9)
6435184Sek110237 		yydebug = 1;
6445184Sek110237 };
6455184Sek110237 
6465184Sek110237 set_command: FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VAL_INT
6475184Sek110237 {
6485184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6495184Sek110237 		YYERROR;
6505184Sek110237 	var_assign_integer($2, $4);
6515184Sek110237 	if (parentscript) {
6525184Sek110237 		$$->cmd_tgt1 = $2;
6535184Sek110237 		parser_vars($$);
6545184Sek110237 	}
6555184Sek110237 	$$->cmd = NULL;
6565184Sek110237 }
6575184Sek110237 | FSC_SET FSV_VARIABLE FSK_ASSIGN FSK_QUOTE FSV_WHITESTRING FSK_QUOTE
6585184Sek110237 {
6595184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6605184Sek110237 		YYERROR;
6615184Sek110237 	var_assign_string($2, $5);
6625184Sek110237 	if (parentscript) {
6635184Sek110237 		$$->cmd_tgt1 = $2;
6645184Sek110237 		parser_vars($$);
6655184Sek110237 	}
6665184Sek110237 	$$->cmd = NULL;
6675184Sek110237 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_STRING
6685184Sek110237 {
6695184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6705184Sek110237 		YYERROR;
6715184Sek110237 	var_assign_string($2, $4);
6725184Sek110237 	if (parentscript) {
6735184Sek110237 		$$->cmd_tgt1 = $2;
6745184Sek110237 		parser_vars($$);
6755184Sek110237 	}
6765184Sek110237 	$$->cmd = NULL;
6775184Sek110237 }| FSC_SET FSV_VARIABLE FSK_ASSIGN FSV_VARIABLE
6785184Sek110237 {
6795184Sek110237 	if (($$ = alloc_cmd()) == NULL)
6805184Sek110237 		YYERROR;
6815184Sek110237 	var_assign_var($2, $4);
6825184Sek110237 	if (parentscript) {
6835184Sek110237 		$$->cmd_tgt1 = $2;
6845184Sek110237 		parser_vars($$);
6855184Sek110237 	}
6865184Sek110237 	$$->cmd = NULL;
687*6084Saw148015 } | FSC_SET FSE_MODE FSC_QUIT FSA_TIMEOUT
688*6084Saw148015 {
689*6084Saw148015 	filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT;
690*6084Saw148015 	if (($$ = alloc_cmd()) == NULL)
691*6084Saw148015 		YYERROR;
692*6084Saw148015 	$$->cmd = NULL;
693*6084Saw148015 } | FSC_SET FSE_MODE FSC_QUIT FSA_ALLDONE
694*6084Saw148015 {
695*6084Saw148015 	filebench_shm->shm_rmode = FILEBENCH_MODE_QALLDONE;
696*6084Saw148015 	if (($$ = alloc_cmd()) == NULL)
697*6084Saw148015 		YYERROR;
698*6084Saw148015 	$$->cmd = NULL;
699*6084Saw148015 } | FSC_SET FSE_MODE FSC_QUIT FSA_FIRSTDONE
700*6084Saw148015 {
701*6084Saw148015 	filebench_shm->shm_rmode = FILEBENCH_MODE_Q1STDONE;
702*6084Saw148015 	if (($$ = alloc_cmd()) == NULL)
703*6084Saw148015 		YYERROR;
704*6084Saw148015 	$$->cmd = NULL;
7055184Sek110237 };
7065184Sek110237 
7075184Sek110237 stats_command: FSC_STATS FSE_SNAP
7085184Sek110237 {
7095184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7105184Sek110237 		YYERROR;
7115184Sek110237 	$$->cmd = (void (*)(struct cmd *))&parser_statssnap;
7125184Sek110237 	break;
7135184Sek110237 
7145184Sek110237 }
7155184Sek110237 | FSC_STATS FSE_CLEAR
7165184Sek110237 {
7175184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7185184Sek110237 		YYERROR;
7195184Sek110237 	$$->cmd = (void (*)(struct cmd *))&stats_clear;
7205184Sek110237 
7215184Sek110237 }
7225184Sek110237 | FSC_STATS FSE_DIRECTORY var_string_list
7235184Sek110237 {
7245184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7255184Sek110237 		YYERROR;
7265184Sek110237 	$$->cmd_param_list = $3;
7275184Sek110237 	$$->cmd = (void (*)(struct cmd *))&parser_directory;
7285184Sek110237 
7295184Sek110237 }
7305184Sek110237 | FSC_STATS FSE_COMMAND whitevar_string_list
7315184Sek110237 {
7325184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7335184Sek110237 		YYERROR;
7345184Sek110237 
7355184Sek110237 	$$->cmd_param_list = $3;
7365184Sek110237 	$$->cmd = parser_statscmd;
7375184Sek110237 
7385184Sek110237 }| FSC_STATS FSE_DUMP whitevar_string_list
7395184Sek110237 {
7405184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7415184Sek110237 		YYERROR;
7425184Sek110237 
7435184Sek110237 	$$->cmd_param_list = $3;
7445184Sek110237 	$$->cmd = parser_statsdump;
7455184Sek110237 }| FSC_STATS FSE_XMLDUMP whitevar_string_list
7465184Sek110237 {
7475184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7485184Sek110237 		YYERROR;
7495184Sek110237 
7505184Sek110237 	$$->cmd_param_list = $3;
7515184Sek110237 	$$->cmd = parser_statsxmldump;
7525184Sek110237 };
7535184Sek110237 
7545184Sek110237 quit_command: FSC_QUIT
7555184Sek110237 {
7565184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7575184Sek110237 		YYERROR;
7585184Sek110237 	$$->cmd = parser_filebench_shutdown;
7595184Sek110237 };
7605184Sek110237 
7615184Sek110237 flowop_list: flowop_command
7625184Sek110237 {
7635184Sek110237 	$$ = $1;
7645184Sek110237 }| flowop_list flowop_command
7655184Sek110237 {
7665184Sek110237 	cmd_t *list = NULL;
7675184Sek110237 	cmd_t *list_end = NULL;
7685184Sek110237 
7695184Sek110237 	/* Find end of list */
7705184Sek110237 	for (list = $1; list != NULL;
7715184Sek110237 	    list = list->cmd_next)
7725184Sek110237 		list_end = list;
7735184Sek110237 
7745184Sek110237 	list_end->cmd_next = $2;
7755184Sek110237 
7765184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
7775184Sek110237 	    "flowop_list adding cmd %zx to list %zx", $2, $1);
7785184Sek110237 
7795184Sek110237 	$$ = $1;
7805184Sek110237 };
7815184Sek110237 
7825184Sek110237 thread: FSE_THREAD attr_ops FSK_OPENLST flowop_list FSK_CLOSELST
7835184Sek110237 {
7845184Sek110237 	/*
7855184Sek110237 	 * Allocate a cmd node per thread, with a
7865184Sek110237 	 * list of flowops attached to the cmd_list
7875184Sek110237 	 */
7885184Sek110237 	if (($$ = alloc_cmd()) == NULL)
7895184Sek110237 		YYERROR;
7905184Sek110237 	$$->cmd_list = $4;
7915184Sek110237 	$$->cmd_attr_list = $2;
7925184Sek110237 };
7935184Sek110237 
7945184Sek110237 thread_list: thread
7955184Sek110237 {
7965184Sek110237 	$$ = $1;
7975184Sek110237 }| thread_list thread
7985184Sek110237 {
7995184Sek110237 	cmd_t *list = NULL;
8005184Sek110237 	cmd_t *list_end = NULL;
8015184Sek110237 
8025184Sek110237 	/* Find end of list */
8035184Sek110237 	for (list = $1; list != NULL;
8045184Sek110237 	    list = list->cmd_next)
8055184Sek110237 		list_end = list;
8065184Sek110237 
8075184Sek110237 	list_end->cmd_next = $2;
8085184Sek110237 
8095184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
8105184Sek110237 	    "thread_list adding cmd %zx to list %zx", $2, $1);
8115184Sek110237 
8125184Sek110237 	$$ = $1;
8135184Sek110237 };
8145184Sek110237 
8155184Sek110237 define_command: FSC_DEFINE FSE_PROC attr_ops FSK_OPENLST thread_list FSK_CLOSELST
8165184Sek110237 {
8175184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8185184Sek110237 		YYERROR;
8195184Sek110237 	$$->cmd = &parser_proc_define;
8205184Sek110237 	$$->cmd_list = $5;
8215184Sek110237 	$$->cmd_attr_list = $3;
8225184Sek110237 
8235184Sek110237 }| FSC_DEFINE FSE_FILE
8245184Sek110237 {
8255184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8265184Sek110237 		YYERROR;
8275184Sek110237 	$$->cmd = &parser_file_define;
8285184Sek110237 }| FSC_DEFINE FSE_FILESET
8295184Sek110237 {
8305184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8315184Sek110237 		YYERROR;
8325184Sek110237 	$$->cmd = &parser_fileset_define;
8335184Sek110237 }
8345184Sek110237 | define_command attr_ops
8355184Sek110237 {
8365184Sek110237 	$1->cmd_attr_list = $2;
8375184Sek110237 };
8385184Sek110237 
8395184Sek110237 create_command: FSC_CREATE entity
8405184Sek110237 {
8415184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8425184Sek110237 		YYERROR;
8435184Sek110237 	switch ($2) {
8445184Sek110237 	case FSE_PROC:
8455184Sek110237 		$$->cmd = &parser_proc_create;
8465184Sek110237 		break;
8475673Saw148015 	case FSE_FILESET:
8485184Sek110237 	case FSE_FILE:
8495184Sek110237 		$$->cmd = &parser_fileset_create;
8505184Sek110237 		break;
8515184Sek110237 	default:
8525184Sek110237 		filebench_log(LOG_ERROR, "unknown entity", $2);
8535184Sek110237 		YYERROR;
8545184Sek110237 	}
8555184Sek110237 
8565184Sek110237 };
8575184Sek110237 
8585184Sek110237 shutdown_command: FSC_SHUTDOWN entity
8595184Sek110237 {
8605184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8615184Sek110237 		YYERROR;
8625184Sek110237 	switch ($2) {
8635184Sek110237 	case FSE_PROC:
8645184Sek110237 		$$->cmd = &parser_proc_shutdown;
8655184Sek110237 		break;
8665184Sek110237 	default:
8675184Sek110237 		filebench_log(LOG_ERROR, "unknown entity", $2);
8685184Sek110237 		YYERROR;
8695184Sek110237 	}
8705184Sek110237 
8715184Sek110237 };
8725184Sek110237 
8735184Sek110237 sleep_command: FSC_SLEEP FSV_VAL_INT
8745184Sek110237 {
8755184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8765184Sek110237 		YYERROR;
8775184Sek110237 	$$->cmd = parser_sleep;
8785184Sek110237 	$$->cmd_qty = $2;
8795184Sek110237 }
8805184Sek110237 | FSC_SLEEP FSV_VARIABLE
8815184Sek110237 {
8825184Sek110237 	vinteger_t *integer;
8835184Sek110237 
8845184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8855184Sek110237 		YYERROR;
8865184Sek110237 	$$->cmd = parser_sleep_variable;
8875184Sek110237 	$$->cmd_tgt1 = fb_stralloc($2);
8885184Sek110237 };
8895184Sek110237 
8905184Sek110237 run_command: FSC_RUN FSV_VAL_INT
8915184Sek110237 {
8925184Sek110237 	if (($$ = alloc_cmd()) == NULL)
8935184Sek110237 		YYERROR;
8945184Sek110237 	$$->cmd = parser_run;
8955184Sek110237 	$$->cmd_qty = $2;
8965184Sek110237 }
8975184Sek110237 | FSC_RUN FSV_VARIABLE
8985184Sek110237 {
8995184Sek110237 	vinteger_t *integer;
9005184Sek110237 
9015184Sek110237 	if (($$ = alloc_cmd()) == NULL)
9025184Sek110237 		YYERROR;
9035184Sek110237 	$$->cmd = parser_run_variable;
9045184Sek110237 	$$->cmd_tgt1 = fb_stralloc($2);
9055184Sek110237 }
9065184Sek110237 | FSC_RUN
9075184Sek110237 {
9085184Sek110237 	vinteger_t *integer;
9095184Sek110237 
9105184Sek110237 	if (($$ = alloc_cmd()) == NULL)
9115184Sek110237 		YYERROR;
9125184Sek110237 	$$->cmd = parser_run;
9135184Sek110237 	$$->cmd_qty = 60UL;
9145184Sek110237 };
9155184Sek110237 
9165184Sek110237 help_command: FSC_HELP
9175184Sek110237 {
9185184Sek110237 	if (($$ = alloc_cmd()) == NULL)
9195184Sek110237 		YYERROR;
9205184Sek110237 	$$->cmd = parser_help;
9215184Sek110237 };
9225184Sek110237 
9235184Sek110237 flowop_command: FSC_FLOWOP name
9245184Sek110237 {
9255184Sek110237 	if (($$ = alloc_cmd()) == NULL)
9265184Sek110237 		YYERROR;
9275184Sek110237 	$$->cmd_name = fb_stralloc($2);
9285184Sek110237 }
9295184Sek110237 | flowop_command attr_ops
9305184Sek110237 {
9315184Sek110237 	$1->cmd_attr_list = $2;
9325184Sek110237 };
9335184Sek110237 
9345184Sek110237 load_command: FSC_LOAD FSV_STRING
9355184Sek110237 {
9365184Sek110237 	FILE *newfile;
9375184Sek110237 	char loadfile[128];
9385184Sek110237 
9395184Sek110237 	if (($$ = alloc_cmd()) == NULL)
9405184Sek110237 		YYERROR;
9415184Sek110237 
9425184Sek110237 	(void) strcpy(loadfile, $2);
9435184Sek110237 	(void) strcat(loadfile, ".f");
9445184Sek110237 
9455184Sek110237 	if ((newfile = fopen(loadfile, "r")) == NULL) {
9465184Sek110237 		(void) strcpy(loadfile, FILEBENCHDIR);
9475184Sek110237 		(void) strcat(loadfile, "/workloads/");
9485184Sek110237 		(void) strcat(loadfile, $2);
9495184Sek110237 		(void) strcat(loadfile, ".f");
9505184Sek110237 		if ((newfile = fopen(loadfile, "r")) == NULL) {
9515184Sek110237 			filebench_log(LOG_ERROR, "Cannot open %s", loadfile);
9525184Sek110237 			YYERROR;
9535184Sek110237 		}
9545184Sek110237 	}
9555184Sek110237 
9565184Sek110237 	parentscript = yyin;
9575184Sek110237 	yyin = newfile;
9585184Sek110237 	yy_switchfileparent(yyin);
9595184Sek110237 };
9605184Sek110237 
9615184Sek110237 entity: FSE_PROC {$$ = FSE_PROC;}
9625184Sek110237 | FSE_THREAD {$$ = FSE_THREAD;}
9635184Sek110237 | FSE_FILESET {$$ = FSE_FILESET;}
9645184Sek110237 | FSE_FILE {$$ = FSE_FILE;};
9655184Sek110237 
9665184Sek110237 value: FSV_VAL_INT { $$.i = $1;}
9675184Sek110237 | FSV_STRING { $$.s = $1;}
9685184Sek110237 | FSV_VAL_BOOLEAN { $$.b = $1;};
9695184Sek110237 
9705184Sek110237 name: FSV_STRING;
9715184Sek110237 
9725184Sek110237 attr_ops: attr_op
9735184Sek110237 {
9745184Sek110237 	$$ = $1;
9755184Sek110237 }
9765184Sek110237 | attr_ops FSK_SEPLST attr_op
9775184Sek110237 {
9785184Sek110237 	attr_t *attr = NULL;
9795184Sek110237 	attr_t *list_end = NULL;
9805184Sek110237 
9815184Sek110237 	for (attr = $1; attr != NULL;
9825184Sek110237 	    attr = attr->attr_next)
9835184Sek110237 		list_end = attr; /* Find end of list */
9845184Sek110237 
9855184Sek110237 	list_end->attr_next = $3;
9865184Sek110237 
9875184Sek110237 	$$ = $1;
9885184Sek110237 };
9895184Sek110237 
9905184Sek110237 attr_op: attr_name FSK_ASSIGN attr_value
9915184Sek110237 {
9925184Sek110237 	$$ = $3;
9935184Sek110237 	$$->attr_name = $1;
9945184Sek110237 }
9955184Sek110237 | attr_name
9965184Sek110237 {
9975184Sek110237 	if (($$ = alloc_attr()) == NULL)
9985184Sek110237 		YYERROR;
9995184Sek110237 	$$->attr_name = $1;
10005184Sek110237 }
10015184Sek110237 
10025184Sek110237 attr_name: attrs_define_file
10035184Sek110237 |attrs_define_fileset
10045184Sek110237 |attrs_define_thread
10055184Sek110237 |attrs_define_proc
10065184Sek110237 |attrs_flowop
10075184Sek110237 |attrs_eventgen;
10085184Sek110237 
10095184Sek110237 attrs_define_proc:
10105184Sek110237 FSA_NICE { $$ = FSA_NICE;}
10115184Sek110237 |FSA_INSTANCES { $$ = FSA_INSTANCES;};
10125184Sek110237 
10135184Sek110237 attrs_define_file:
10145184Sek110237 FSA_SIZE { $$ = FSA_SIZE;}
10155184Sek110237 | FSA_PATH { $$ = FSA_PATH;}
10165184Sek110237 | FSA_REUSE { $$ = FSA_REUSE;}
10175184Sek110237 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
10185184Sek110237 | FSA_PARALLOC { $$ = FSA_PARALLOC;};
10195184Sek110237 
10205184Sek110237 attrs_define_fileset:
10215184Sek110237 FSA_SIZE { $$ = FSA_SIZE;}
10225184Sek110237 | FSA_PATH { $$ = FSA_PATH;}
10235184Sek110237 | FSA_DIRWIDTH { $$ = FSA_DIRWIDTH;}
10245184Sek110237 | FSA_PREALLOC { $$ = FSA_PREALLOC;}
10255184Sek110237 | FSA_FILESIZEGAMMA { $$ = FSA_FILESIZEGAMMA;}
10265184Sek110237 | FSA_DIRGAMMA { $$ = FSA_DIRGAMMA;}
10275184Sek110237 | FSA_CACHED { $$ = FSA_CACHED;}
10285184Sek110237 | FSA_ENTRIES { $$ = FSA_ENTRIES;};
10295184Sek110237 
10305184Sek110237 attrs_define_thread:
10315184Sek110237 FSA_PROCESS { $$ = FSA_PROCESS;}
10325184Sek110237 |FSA_MEMSIZE { $$ = FSA_MEMSIZE;}
10335184Sek110237 |FSA_USEISM { $$ = FSA_USEISM;}
10345184Sek110237 |FSA_INSTANCES { $$ = FSA_INSTANCES;};
10355184Sek110237 
10365184Sek110237 attrs_flowop:
10375184Sek110237 FSA_WSS { $$ = FSA_WSS;}
10385184Sek110237 |FSA_FILE { $$ = FSA_FILE;}
10395184Sek110237 |FSA_NAME { $$ = FSA_NAME;}
10405184Sek110237 |FSA_RANDOM { $$ = FSA_RANDOM;}
10415184Sek110237 |FSA_FD { $$ = FSA_FD;}
10425184Sek110237 |FSA_SRCFD { $$ = FSA_SRCFD;}
10435184Sek110237 |FSA_ROTATEFD { $$ = FSA_ROTATEFD;}
10445184Sek110237 |FSA_DSYNC { $$ = FSA_DSYNC;}
10455184Sek110237 |FSA_DIRECTIO { $$ = FSA_DIRECTIO;}
10465184Sek110237 |FSA_TARGET { $$ = FSA_TARGET;}
10475184Sek110237 |FSA_ITERS { $$ = FSA_ITERS;}
10485184Sek110237 |FSA_VALUE { $$ = FSA_VALUE;}
10495184Sek110237 |FSA_BLOCKING { $$ = FSA_BLOCKING;}
10505184Sek110237 |FSA_HIGHWATER { $$ = FSA_HIGHWATER;}
10515184Sek110237 |FSA_IOSIZE { $$ = FSA_IOSIZE;};
10525184Sek110237 
10535184Sek110237 attrs_eventgen:
10545184Sek110237 FSA_RATE { $$ = FSA_RATE;};
10555184Sek110237 
10565184Sek110237 attr_value: var_string_list {
10575184Sek110237 	if (($$ = alloc_attr()) == NULL)
10585184Sek110237 		YYERROR;
10595184Sek110237 	$$->attr_param_list = $1;
10605184Sek110237 } | FSV_STRING
10615184Sek110237 {
10625184Sek110237 	if (($$ = alloc_attr()) == NULL)
10635184Sek110237 		YYERROR;
10645184Sek110237 	$$->attr_string = string_alloc($1);
10655184Sek110237 } | FSV_VAL_INT {
10665184Sek110237 	if (($$ = alloc_attr()) == NULL)
10675184Sek110237 		YYERROR;
10685184Sek110237 	$$->attr_integer = integer_alloc($1);
10695184Sek110237 } | FSV_VARIABLE {
10705184Sek110237 	if (($$ = alloc_attr()) == NULL)
10715184Sek110237 		YYERROR;
10725184Sek110237 	$$->attr_integer = var_ref_integer($1);
10735184Sek110237 	$$->attr_string = var_ref_string($1);
10745184Sek110237 };
10755184Sek110237 
10765184Sek110237 %%
10775184Sek110237 
10785184Sek110237 /*
10795184Sek110237  *  The following 'c' routines implement the various commands defined in the
10805184Sek110237  * above yacc parser code. The yacc portion checks the syntax of the commands
10815184Sek110237  * found in a workload file, or typed on interactive command lines, parsing
10825184Sek110237  * the commands' parameters into lists. The lists are then passed in a cmd_t
10835184Sek110237  * struct for each command to its related routine in the following section
10845184Sek110237  * for actual execution. This section also includes a few utility routines
10855184Sek110237  * and the main entry point for the program.
10865184Sek110237  */
10875184Sek110237 
10885184Sek110237 /*
10895184Sek110237  * Entry point for filebench. Processes command line arguements. The -f
10905184Sek110237  * option will read in a workload file (the full name and extension must
10915184Sek110237  * must be given). The -a, -s, -m and -i options are used by worker process
10925184Sek110237  * to receive their name, the base address of shared memory, its path, and
10935184Sek110237  * the process' instance number, respectively. This information is supplied
10945184Sek110237  * by the master process when it execs worker processes under the process
10955184Sek110237  * model of execution. If the worker process arguments are passed then main
10965184Sek110237  * will call the procflow_exec routine which creates worker threadflows and
10975184Sek110237  * flowops and executes the procflow's portion of the workload model until
10985184Sek110237  * completion. If worker process arguments are not passed to the process,
10995184Sek110237  * then it becomes the master process for a filebench run. It initializes
11005184Sek110237  * the various filebench components and either executes the supplied workload
11015184Sek110237  * file, or enters interactive mode.
11025184Sek110237  */
11035184Sek110237 
11045184Sek110237 int
11055184Sek110237 main(int argc, char *argv[])
11065184Sek110237 {
11075184Sek110237 	int opt;
11085184Sek110237 	int docmd = FS_FALSE;
11095184Sek110237 	int instance;
11105184Sek110237 	char procname[128];
11115184Sek110237 	caddr_t shmaddr;
11125184Sek110237 	char dir[MAXPATHLEN];
11135184Sek110237 #ifdef HAVE_SETRLIMIT
11145184Sek110237 	struct rlimit rlp;
11155184Sek110237 #endif
11165184Sek110237 #ifdef HAVE_LIBTECLA
11175184Sek110237 	char *line;
11185184Sek110237 #else
11195184Sek110237 	char line[1024];
11205184Sek110237 #endif
11215184Sek110237 	char shmpathtmp[1024];
11225184Sek110237 
11235184Sek110237 #ifdef HAVE_SETRLIMIT
11245184Sek110237 	/* Set resource limits */
11255184Sek110237 	(void) getrlimit(RLIMIT_NOFILE, &rlp);
11265184Sek110237 	rlp.rlim_cur = rlp.rlim_max;
11275184Sek110237 	setrlimit(RLIMIT_NOFILE, &rlp);
11285184Sek110237 #endif
11295184Sek110237 
11305184Sek110237 	yydebug = 0;
11315184Sek110237 	execname = argv[0];
11325184Sek110237 	*procname = 0;
11335184Sek110237 	cwd = getcwd(dir, MAXPATHLEN);
11345184Sek110237 
11355184Sek110237 	while ((opt = getopt(argc, argv, cmd_options)) != (int)EOF) {
11365184Sek110237 
11375184Sek110237 		switch (opt) {
11385184Sek110237 		case 'h':
11395184Sek110237 			usage(2);
11405184Sek110237 			break;
11415184Sek110237 
11425184Sek110237 		case 'p':
11435184Sek110237 			noproc = 1;
11445184Sek110237 			break;
11455184Sek110237 
11465184Sek110237 		case 'f':
11475184Sek110237 			if (optarg == NULL)
11485184Sek110237 				usage(1);
11495184Sek110237 			if ((yyin = fopen(optarg, "r")) == NULL) {
11505184Sek110237 				(void) fprintf(stderr,
11515184Sek110237 				    "Cannot open file %s", optarg);
11525184Sek110237 				exit(1);
11535184Sek110237 			}
11545184Sek110237 			dofile = FS_TRUE;
11555184Sek110237 			fscriptname = optarg;
11565184Sek110237 
11575184Sek110237 			break;
11585184Sek110237 
11595184Sek110237 		case 'a':
11605184Sek110237 			if (optarg == NULL)
11615184Sek110237 				usage(1);
11625184Sek110237 			sscanf(optarg, "%s", &procname[0]);
11635184Sek110237 			break;
11645184Sek110237 
11655184Sek110237 		case 's':
11665184Sek110237 			if (optarg == NULL)
11675184Sek110237 				usage(1);
11685184Sek110237 #if defined(_LP64) || (__WORDSIZE == 64)
11695184Sek110237 			sscanf(optarg, "%llx", &shmaddr);
11705184Sek110237 #else
11715184Sek110237 			sscanf(optarg, "%x", &shmaddr);
11725184Sek110237 #endif
11735184Sek110237 			break;
11745184Sek110237 
11755184Sek110237 		case 'm':
11765184Sek110237 			if (optarg == NULL)
11775184Sek110237 				usage(1);
11785184Sek110237 			sscanf(optarg, "%s", shmpathtmp);
11795184Sek110237 			shmpath = shmpathtmp;
11805184Sek110237 			break;
11815184Sek110237 
11825184Sek110237 		case 'i':
11835184Sek110237 			if (optarg == NULL)
11845184Sek110237 				usage(1);
11855184Sek110237 			sscanf(optarg, "%d", &instance);
11865184Sek110237 			break;
11875184Sek110237 
11885184Sek110237 		case '?':
11895184Sek110237 		default:
11905184Sek110237 			usage(1);
11915184Sek110237 			break;
11925184Sek110237 		}
11935184Sek110237 	}
11945184Sek110237 
11955184Sek110237 #ifdef USE_PROCESS_MODEL
11965184Sek110237 	if (!(*procname))
11975184Sek110237 #endif
11985184Sek110237 	printf("FileBench Version %s\n", FILEBENCH_VERSION);
11995184Sek110237 	filebench_init();
12005184Sek110237 
1201*6084Saw148015 	/* get process pid for use with message logging */
1202*6084Saw148015 	my_pid = getpid();
1203*6084Saw148015 
12045184Sek110237 #ifdef USE_PROCESS_MODEL
12055184Sek110237 	if (*procname) {
1206*6084Saw148015 		/* A child FileBench instance */
12075184Sek110237 		if (ipc_attach(shmaddr) < 0) {
12085184Sek110237 			filebench_log(LOG_ERROR, "Cannot attach shm for %s",
12095184Sek110237 			    procname);
12105184Sek110237 			exit(1);
12115184Sek110237 		}
12125184Sek110237 
1213*6084Saw148015 		if (procflow_exec(procname, instance) < 0)
12145184Sek110237 			exit(1);
1215*6084Saw148015 
1216*6084Saw148015 		exit(0);
12175184Sek110237 	}
12185184Sek110237 #endif
12195184Sek110237 
1220*6084Saw148015 	/* master (or only) process */
12215184Sek110237 	ipc_init();
12225184Sek110237 
12235184Sek110237 	if (fscriptname)
12245184Sek110237 		(void) strcpy(filebench_shm->fscriptname, fscriptname);
12255184Sek110237 
12265184Sek110237 	flowop_init();
12275184Sek110237 	stats_init();
12285184Sek110237 	eventgen_init();
12295184Sek110237 
12305184Sek110237 	signal(SIGINT, parser_abort);
12315184Sek110237 
12325184Sek110237 	if (dofile)
12335184Sek110237 		yyparse();
12345184Sek110237 	else {
12355184Sek110237 #ifdef HAVE_LIBTECLA
12365184Sek110237 		if ((gl = new_GetLine(MAX_LINE_LEN, MAX_CMD_HIST)) == NULL) {
12375184Sek110237 			filebench_log(LOG_ERROR,
12385184Sek110237 			    "Failed to create GetLine object");
12395184Sek110237 			filebench_shutdown(1);
12405184Sek110237 		}
12415184Sek110237 
12425184Sek110237 		if (gl_customize_completion(gl, NULL, command_complete)) {
12435184Sek110237 			filebench_log(LOG_ERROR,
12445184Sek110237 			    "Failed to register auto-completion function");
12455184Sek110237 			filebench_shutdown(1);
12465184Sek110237 		}
12475184Sek110237 
12485184Sek110237 		while (line = gl_get_line(gl, FILEBENCH_PROMPT, NULL, -1)) {
12495184Sek110237 			arg_parse(line);
12505184Sek110237 			yyparse();
12515184Sek110237 		}
12525184Sek110237 
12535184Sek110237 		del_GetLine(gl);
12545184Sek110237 #else
12555184Sek110237 		while (!feof(stdin)) {
12565184Sek110237 			printf(FILEBENCH_PROMPT);
12575184Sek110237 			fflush(stdout);
12585184Sek110237 			if (fgets(line, sizeof (line), stdin) == NULL) {
12595184Sek110237 				if (errno == EINTR)
12605184Sek110237 					continue;
12615184Sek110237 				else
12625184Sek110237 					break;
12635184Sek110237 			}
12645184Sek110237 			arg_parse(line);
12655184Sek110237 			yyparse();
12665184Sek110237 		}
12675184Sek110237 		printf("\n");
12685184Sek110237 #endif	/* HAVE_LIBTECLA */
12695184Sek110237 	}
12705184Sek110237 
12715184Sek110237 	parser_filebench_shutdown((cmd_t *)0);
12725184Sek110237 
12735184Sek110237 	return (0);
12745184Sek110237 }
12755184Sek110237 
12765184Sek110237 /*
12775184Sek110237  * arg_parse() puts the parser into command parsing mode. Create a tmpfile
12785184Sek110237  * and instruct the parser to read instructions from this location by setting
12795184Sek110237  * yyin to the value returned by tmpfile. Write the command into the file.
12805184Sek110237  * Then seek back to to the start of the file so that the parser can read
12815184Sek110237  * the instructions.
12825184Sek110237  */
12835184Sek110237 static void
12845184Sek110237 arg_parse(const char *command)
12855184Sek110237 {
12865184Sek110237 	if ((yyin = tmpfile()) == NULL)
12875184Sek110237 		filebench_log(LOG_FATAL,
12885184Sek110237 		    "Cannot create tmpfile: %s", strerror(errno));
12895184Sek110237 
12905184Sek110237 	if (fwrite(command, strlen(command), 1, yyin) != 1)
12915184Sek110237 		filebench_log(LOG_FATAL,
12925184Sek110237 		    "Cannot write tmpfile: %s", strerror(errno));
12935184Sek110237 
12945184Sek110237 	if (fseek(yyin, 0, SEEK_SET) != 0)
12955184Sek110237 		filebench_log(LOG_FATAL,
12965184Sek110237 		    "Cannot seek tmpfile: %s", strerror(errno));
12975184Sek110237 }
12985184Sek110237 
12995184Sek110237 /*
13005184Sek110237  * Converts a list of var_strings or ordinary strings to a single ordinary
13015184Sek110237  * string. It returns a pointer to the string (in malloc'd memory) if found,
13025184Sek110237  * or NULL otherwise.
13035184Sek110237  */
13045184Sek110237 char *
13055184Sek110237 parser_list2string(list_t *list)
13065184Sek110237 {
13075184Sek110237 	list_t *l;
13085184Sek110237 	char *string;
13095184Sek110237 	char *tmp;
13105184Sek110237 	vinteger_t *integer;
13115184Sek110237 
13125184Sek110237 	if ((string = malloc(MAXPATHLEN)) == NULL) {
13135184Sek110237 		filebench_log(LOG_ERROR, "Failed to allocate memory");
13145184Sek110237 		return (NULL);
13155184Sek110237 	}
13165184Sek110237 
13175184Sek110237 	*string = 0;
13185184Sek110237 
13195184Sek110237 
13205184Sek110237 	/* Format args */
13215184Sek110237 	for (l = list; l != NULL;
13225184Sek110237 	    l = l->list_next) {
13235184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT,
13245184Sek110237 		    "converting string '%s'", *l->list_string);
13255184Sek110237 
13265184Sek110237 		if ((tmp = var_to_string(*l->list_string)) != NULL) {
13275184Sek110237 			(void) strcat(string, tmp);
13285184Sek110237 			free(tmp);
13295184Sek110237 		} else {
13305184Sek110237 			(void) strcat(string, *l->list_string);
13315184Sek110237 		}
13325184Sek110237 	}
13335184Sek110237 	return (string);
13345184Sek110237 }
13355184Sek110237 
13365184Sek110237 /*
13375184Sek110237  * If the list just contains a single string starting with '$', then find
13385184Sek110237  * or create the named var and return the var's var_string component.
13395184Sek110237  * Otherwise, convert the list to a string, and allocate a var_string
13405184Sek110237  * containing a copy of that string. On failure either returns NULL
13415184Sek110237  * or shuts down the run.
13425184Sek110237  */
13435184Sek110237 var_string_t
13445184Sek110237 parser_list2varstring(list_t *list)
13455184Sek110237 {
13465184Sek110237 	/* Special case - variable name */
13475184Sek110237 	if ((list->list_next == NULL) && (*(*list->list_string) == '$'))
13485184Sek110237 		return (var_ref_string(*list->list_string));
13495184Sek110237 
13505184Sek110237 	return (string_alloc(parser_list2string(list)));
13515184Sek110237 }
13525184Sek110237 
13535184Sek110237 /*
13545184Sek110237  * Looks for the var named in list_string of the first element of the
13555184Sek110237  * supplied list. If found, returns the var_integer portion of the var.
13565184Sek110237  * If the var is not found, cannot be allocated, the supplied list is
13575184Sek110237  * NULL, or the list_string filed is empty, returns NULL.
13585184Sek110237  */
13595184Sek110237 var_integer_t
13605184Sek110237 parser_list2integer(list_t *list)
13615184Sek110237 {
13625184Sek110237 	var_integer_t v;
13635184Sek110237 
13645184Sek110237 	if (list && (*(list->list_string) != NULL)) {
13655184Sek110237 		v = var_ref_integer(*(list->list_string));
13665184Sek110237 		return (v);
13675184Sek110237 	}
13685184Sek110237 
13695184Sek110237 	return (NULL);
13705184Sek110237 }
13715184Sek110237 
13725184Sek110237 /*
13735184Sek110237  * Sets the event generator rate from the attribute supplied with the
13745184Sek110237  * command. If the attribute doesn't exist the routine does nothing.
13755184Sek110237  */
13765184Sek110237 static void
13775184Sek110237 parser_eventgen(cmd_t *cmd)
13785184Sek110237 {
13795184Sek110237 	attr_t *attr;
13805184Sek110237 	vinteger_t rate;
13815184Sek110237 
13825184Sek110237 	/* Get the rate from attribute */
13835184Sek110237 	if (attr = get_attr_integer(cmd, FSA_RATE)) {
13845184Sek110237 		if (attr->attr_integer) {
13855184Sek110237 			filebench_log(LOG_VERBOSE,
13865184Sek110237 			    "Eventgen: %lld per second",
13875184Sek110237 			    *attr->attr_integer);
13885184Sek110237 			eventgen_setrate(*attr->attr_integer);
13895184Sek110237 		}
13905184Sek110237 	}
13915184Sek110237 
13925184Sek110237 }
13935184Sek110237 
13945184Sek110237 /*
13955184Sek110237  * Assigns the designated integer variable successive values from the
13965184Sek110237  * supplied comma seperated integer list. After each successive integer
13975184Sek110237  * assignment, it executes the bracket enclosed list of commands. For
13985184Sek110237  * example, repeated runs of a workload with increasing io sizes can
13995184Sek110237  * be done using the following command line:
14005184Sek110237  * 	foreach $iosize in 2k, 4k, 8k {run 60}
14015184Sek110237  */
14025184Sek110237 static void
14035184Sek110237 parser_foreach_integer(cmd_t *cmd)
14045184Sek110237 {
14055184Sek110237 	list_t *list = cmd->cmd_param_list;
14065184Sek110237 	cmd_t *inner_cmd;
14075184Sek110237 
14085184Sek110237 	for (; list != NULL; list = list->list_next) {
14095184Sek110237 		var_assign_integer(cmd->cmd_tgt1, *list->list_integer);
14105184Sek110237 		filebench_log(LOG_VERBOSE, "Iterating %s=%lld",
14115184Sek110237 		    cmd->cmd_tgt1,
14125184Sek110237 		    *list->list_integer);
14135184Sek110237 		for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
14145184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
14155184Sek110237 			inner_cmd->cmd(inner_cmd);
14165184Sek110237 		}
14175184Sek110237 	}
14185184Sek110237 }
14195184Sek110237 
14205184Sek110237 /*
14215184Sek110237  * Similar to parser_foreach_integer(), except takes a list of strings after
14225184Sek110237  * the "in" token. For example, to run twice using a different directory,
14235184Sek110237  * perhaps using a different filesystem, the following command line
14245184Sek110237  * could be used:
14255184Sek110237  * 	foreach $dir in "/ufs_top/fbt", "/zfs_top/fbt" {run 60)
14265184Sek110237  */
14275184Sek110237 static void
14285184Sek110237 parser_foreach_string(cmd_t *cmd)
14295184Sek110237 {
14305184Sek110237 	list_t *list = cmd->cmd_param_list;
14315184Sek110237 	cmd_t *inner_cmd;
14325184Sek110237 
14335184Sek110237 	for (; list != NULL; list = list->list_next) {
14345184Sek110237 		var_assign_string(cmd->cmd_tgt1, *list->list_string);
14355184Sek110237 		filebench_log(LOG_VERBOSE, "Iterating %s=%s",
14365184Sek110237 		    cmd->cmd_tgt1,
14375184Sek110237 		    *list->list_string);
14385184Sek110237 		for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
14395184Sek110237 		    inner_cmd = inner_cmd->cmd_next) {
14405184Sek110237 			inner_cmd->cmd(inner_cmd);
14415184Sek110237 		}
14425184Sek110237 	}
14435184Sek110237 }
14445184Sek110237 
14455184Sek110237 /*
14465673Saw148015  * Lists the fileset name, path name and average size for all defined
14475673Saw148015  * filesets.
14485184Sek110237  */
14495184Sek110237 static void
14505184Sek110237 parser_list(cmd_t *cmd)
14515184Sek110237 {
14525673Saw148015 	(void) fileset_iter(fileset_print);
14535184Sek110237 }
14545184Sek110237 
14555184Sek110237 /*
14565184Sek110237  * Calls procflow_define() to allocate "instances" number of  procflow(s)
14575184Sek110237  * (processes) with the supplied name. The default number of instances is
14585184Sek110237  * one. An optional priority level attribute can be supplied and is stored in
14595184Sek110237  * pf_nice. Finally the routine loops through the list of inner commands, if
14605184Sek110237  * any, which are defines for threadflows, and passes them one at a time to
14615184Sek110237  * parser_thread_define() to allocate threadflow entities for the process(es).
14625184Sek110237  */
14635184Sek110237 static void
14645184Sek110237 parser_proc_define(cmd_t *cmd)
14655184Sek110237 {
14665184Sek110237 	procflow_t *procflow, template;
14675184Sek110237 	char *name;
14685184Sek110237 	attr_t *attr;
14695184Sek110237 	var_integer_t instances = integer_alloc(1);
14705184Sek110237 	cmd_t *inner_cmd;
14715184Sek110237 
14725184Sek110237 	/* Get the name of the process */
14735184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
14745184Sek110237 		name = *attr->attr_string;
14755184Sek110237 	} else {
14765184Sek110237 		filebench_log(LOG_ERROR,
14775184Sek110237 		    "define proc: proc specifies no name");
14785184Sek110237 		filebench_shutdown(1);
14795184Sek110237 	}
14805184Sek110237 
14815184Sek110237 	/* Get the memory size from attribute */
14825184Sek110237 	if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
14835184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
14845184Sek110237 		    "Setting instances = %lld",
14855184Sek110237 		    *attr->attr_integer);
14865184Sek110237 		instances = attr->attr_integer;
14875184Sek110237 	}
14885184Sek110237 
14895184Sek110237 	if ((procflow = procflow_define(name, NULL, instances)) == NULL) {
14905184Sek110237 		filebench_log(LOG_ERROR,
14915184Sek110237 		    "Failed to instantiate %d %s process(es)\n",
14925184Sek110237 		    instances, name);
14935184Sek110237 		filebench_shutdown(1);
14945184Sek110237 	}
14955184Sek110237 
14965184Sek110237 	/* Get the pri from attribute */
14975184Sek110237 	if (attr = get_attr_integer(cmd, FSA_NICE)) {
14985184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Setting pri = %lld",
14995184Sek110237 		    *attr->attr_integer);
15005184Sek110237 		procflow->pf_nice = attr->attr_integer;
15015184Sek110237 	} else
15025184Sek110237 		procflow->pf_nice = integer_alloc(0);
15035184Sek110237 
15045184Sek110237 
15055184Sek110237 	/* Create the list of threads for this process  */
15065184Sek110237 	for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
15075184Sek110237 	    inner_cmd = inner_cmd->cmd_next) {
15085184Sek110237 		parser_thread_define(inner_cmd, procflow, *instances);
15095184Sek110237 	}
15105184Sek110237 }
15115184Sek110237 
15125184Sek110237 /*
15135184Sek110237  * Calls threadflow_define() to allocate "instances" number of  threadflow(s)
15145184Sek110237  * (threads) with the supplied name. The default number of instances is
15155184Sek110237  * one. Two other optional attributes may be supplied, one to set the memory
15165184Sek110237  * size, stored in tf_memsize, and to select the use of Interprocess Shared
15175184Sek110237  * Memory, which sets the THREADFLOW_USEISM flag in tf_attrs. Finally
15185184Sek110237  * the routine loops through the list of inner commands, if any, which are
15195184Sek110237  * defines for flowops, and passes them one at a time to
15205184Sek110237  * parser_flowop_define() to allocate flowop entities for the threadflows.
15215184Sek110237  */
15225184Sek110237 static void
15235184Sek110237 parser_thread_define(cmd_t *cmd, procflow_t *procflow, int procinstances)
15245184Sek110237 {
15255184Sek110237 	threadflow_t *threadflow, template;
15265184Sek110237 	attr_t *attr;
15275184Sek110237 	var_integer_t instances = integer_alloc(1);
15285184Sek110237 	cmd_t *inner_cmd;
15295184Sek110237 	char *name;
15305184Sek110237 
15315184Sek110237 	memset(&template, 0, sizeof (threadflow_t));
15325184Sek110237 
15335184Sek110237 	/* Get the name of the thread */
15345184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
15355184Sek110237 		name = *attr->attr_string;
15365184Sek110237 	} else {
15375184Sek110237 		filebench_log(LOG_ERROR,
15385184Sek110237 		    "define thread: thread in process %s specifies no name",
15395184Sek110237 		    procflow->pf_name);
15405184Sek110237 		filebench_shutdown(1);
15415184Sek110237 	}
15425184Sek110237 
15435184Sek110237 	/* Get the number of instances from attribute */
15445184Sek110237 	if (attr = get_attr_integer(cmd, FSA_INSTANCES)) {
15455184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
15465184Sek110237 		    "define thread: Setting instances = %lld",
15475184Sek110237 		    *attr->attr_integer);
15485184Sek110237 		instances = attr->attr_integer;
15495184Sek110237 	}
15505184Sek110237 
15515184Sek110237 	/* Get the memory size from attribute */
15525184Sek110237 	if (attr = get_attr_integer(cmd, FSA_MEMSIZE)) {
15535184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
15545184Sek110237 		    "define thread: Setting memsize = %lld",
15555184Sek110237 		    *attr->attr_integer);
15565184Sek110237 		template.tf_memsize = attr->attr_integer;
15575184Sek110237 	} else
15585184Sek110237 		template.tf_memsize = integer_alloc(0);
15595184Sek110237 
15605184Sek110237 	if ((threadflow = threadflow_define(procflow, name,
15615184Sek110237 	    &template, instances)) == NULL) {
15625184Sek110237 		filebench_log(LOG_ERROR,
15635184Sek110237 		    "define thread: Failed to instantiate thread\n");
15645184Sek110237 		filebench_shutdown(1);
15655184Sek110237 	}
15665184Sek110237 
15675184Sek110237 	/* Use ISM Memory? */
15685184Sek110237 	if (attr = get_attr(cmd, FSA_USEISM)) {
15695184Sek110237 		threadflow->tf_attrs |= THREADFLOW_USEISM;
15705184Sek110237 	}
15715184Sek110237 
15725184Sek110237 	/* Create the list of flowops */
15735184Sek110237 	for (inner_cmd = cmd->cmd_list; inner_cmd != NULL;
15745184Sek110237 	    inner_cmd = inner_cmd->cmd_next) {
15755184Sek110237 		parser_flowop_define(inner_cmd, threadflow);
15765184Sek110237 	}
15775184Sek110237 }
15785184Sek110237 
15795184Sek110237 /*
15805184Sek110237  * Calls flowop_define() to allocate a flowop with the supplied name.
15815184Sek110237  * The allocated flowop inherits attributes from a base flowop of the
15825184Sek110237  * same type.  If the new flowop has a file or fileset attribute specified,
15835184Sek110237  * it must specify a defined fileobj or fileset or an error will be logged.
15845184Sek110237  * The new flowop may  also have the following attributes set by
15855184Sek110237  * the program:
15865184Sek110237  *  - file size (fo_iosize)
15875184Sek110237  *  - working set size (fo_wss)
15885184Sek110237  *  - do random io (fo_random)
15895184Sek110237  *  - do synchronous io (fo_dsync)
15905184Sek110237  *  - perform each operation multiple times before advancing (fo_iter)
15915184Sek110237  *  - target name (fo_targetname)
15925184Sek110237  *  - An integer value (fo_value)
15935184Sek110237  *  - a file descriptor (fo_fd)
15945184Sek110237  *  - specify to rotate file descriptors (fo_rotatefd)
15955184Sek110237  *  - a source fd (fo_srcfdnumber)
15965184Sek110237  *  - specify a blocking operation (fo_blocking)
15975184Sek110237  *  - specify a highwater mark (fo_highwater)
15985184Sek110237  *
15995184Sek110237  * After all the supplied attributes are stored in their respective locations
16005184Sek110237  * in the flowop object, the flowop's init function is called. No errors are
16015184Sek110237  * returned, but the filebench run will be terminated if the flowtype is not
16025184Sek110237  * specified, a name for the new flowop is not supplied, the flowop_define
16035184Sek110237  * call fails, or a file or fileset name is supplied but the corresponding
16045184Sek110237  * fileobj or fileset cannot be located.
16055184Sek110237  */
16065184Sek110237 static void
16075184Sek110237 parser_flowop_define(cmd_t *cmd, threadflow_t *thread)
16085184Sek110237 {
16095184Sek110237 	flowop_t *flowop, *flowop_type;
16105184Sek110237 	char *type = (char *)cmd->cmd_name;
16115184Sek110237 	char *name;
16125184Sek110237 	attr_t *attr;
16135184Sek110237 
16145184Sek110237 	/* Get the inherited flowop */
16155184Sek110237 	flowop_type = flowop_find(type);
16165184Sek110237 	if (flowop_type == NULL) {
16175184Sek110237 		filebench_log(LOG_ERROR,
16185184Sek110237 		    "define flowop: flowop type %s not found",
16195184Sek110237 		    type);
16205184Sek110237 		filebench_shutdown(1);
16215184Sek110237 	}
16225184Sek110237 
16235184Sek110237 	/* Get the name of the flowop */
16245184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
16255184Sek110237 		name = *attr->attr_string;
16265184Sek110237 	} else {
16275184Sek110237 		filebench_log(LOG_ERROR,
16285184Sek110237 		    "define flowop: flowop %s specifies no name",
16295184Sek110237 		    flowop_type->fo_name);
16305184Sek110237 		filebench_shutdown(1);
16315184Sek110237 	}
16325184Sek110237 
16335184Sek110237 	if ((flowop = flowop_define(thread, name,
16345184Sek110237 	    flowop_type, FLOW_MASTER, 0)) == NULL) {
16355184Sek110237 		filebench_log(LOG_ERROR,
16365184Sek110237 		    "define flowop: Failed to instantiate flowop %s\n",
16375184Sek110237 		    cmd->cmd_name);
16385184Sek110237 		filebench_shutdown(1);
16395184Sek110237 	}
16405184Sek110237 
16415184Sek110237 	/* Get the filename from attribute */
16425184Sek110237 	if (attr = get_attr(cmd, FSA_FILE)) {
16435184Sek110237 		flowop->fo_fileset = fileset_find(*attr->attr_string);
16445184Sek110237 
16455673Saw148015 		if ((flowop->fo_fileset == NULL)) {
16465184Sek110237 			filebench_log(LOG_ERROR,
16475184Sek110237 			    "define flowop: file %s not found",
16485184Sek110237 			    *attr->attr_string);
16495184Sek110237 			filebench_shutdown(1);
16505184Sek110237 		}
16515184Sek110237 	}
16525184Sek110237 
16535184Sek110237 	/* Get the iosize of the op */
16545184Sek110237 	if (attr = get_attr_integer(cmd, FSA_IOSIZE))
16555184Sek110237 		flowop->fo_iosize = attr->attr_integer;
16565184Sek110237 	else
16575184Sek110237 		flowop->fo_iosize = integer_alloc(0);
16585184Sek110237 
16595184Sek110237 	/* Get the working set size of the op */
16605184Sek110237 	if (attr = get_attr_integer(cmd, FSA_WSS))
16615184Sek110237 		flowop->fo_wss = attr->attr_integer;
16625184Sek110237 	else
16635184Sek110237 		flowop->fo_wss = integer_alloc(0);
16645184Sek110237 
16655184Sek110237 	/* Random I/O? */
16665184Sek110237 	if (attr = get_attr_bool(cmd, FSA_RANDOM))
16675184Sek110237 		flowop->fo_random = attr->attr_integer;
16685184Sek110237 	else
16695184Sek110237 		flowop->fo_random = integer_alloc(0);
16705184Sek110237 
16715184Sek110237 	/* Sync I/O? */
16725184Sek110237 	if (attr = get_attr_bool(cmd, FSA_DSYNC))
16735184Sek110237 		flowop->fo_dsync = attr->attr_integer;
16745184Sek110237 	else
16755184Sek110237 		flowop->fo_dsync = integer_alloc(0);
16765184Sek110237 
16775184Sek110237 	/* Iterations */
16785184Sek110237 	if (attr = get_attr_integer(cmd, FSA_ITERS))
16795184Sek110237 		flowop->fo_iters = attr->attr_integer;
16805184Sek110237 	else
16815184Sek110237 		flowop->fo_iters = integer_alloc(1);
16825184Sek110237 
16835184Sek110237 
16845184Sek110237 	/* Target, for wakeup etc */
16855184Sek110237 	if (attr = get_attr(cmd, FSA_TARGET))
16865184Sek110237 		(void) strcpy(flowop->fo_targetname, *attr->attr_string);
16875184Sek110237 
16885184Sek110237 	/* Value */
16895184Sek110237 	if (attr = get_attr_integer(cmd, FSA_VALUE))
16905184Sek110237 		flowop->fo_value = attr->attr_integer;
16915184Sek110237 	else
16925184Sek110237 		flowop->fo_value = integer_alloc(0);
16935184Sek110237 
16945184Sek110237 	/* FD */
16955184Sek110237 	if (attr = get_attr_integer(cmd, FSA_FD))
16965184Sek110237 		flowop->fo_fdnumber = *attr->attr_integer;
16975184Sek110237 
16985184Sek110237 	/* Rotatefd? */
16995184Sek110237 	if (attr = get_attr_bool(cmd, FSA_ROTATEFD))
17005184Sek110237 		flowop->fo_rotatefd = attr->attr_integer;
17015184Sek110237 	else
17025184Sek110237 		flowop->fo_rotatefd = integer_alloc(0);
17035184Sek110237 
17045184Sek110237 	/* SRC FD, for copies etc... */
17055184Sek110237 	if (attr = get_attr_integer(cmd, FSA_SRCFD))
17065184Sek110237 		flowop->fo_srcfdnumber = *attr->attr_integer;
17075184Sek110237 
17085184Sek110237 	/* Blocking operation? */
17095184Sek110237 	if (attr = get_attr_bool(cmd, FSA_BLOCKING))
17105184Sek110237 		flowop->fo_blocking = attr->attr_integer;
17115184Sek110237 	else
17125184Sek110237 		flowop->fo_blocking = integer_alloc(0);
17135184Sek110237 
17145184Sek110237 	/* Blocking operation? */
17155184Sek110237 	if (attr = get_attr_bool(cmd, FSA_DIRECTIO))
17165184Sek110237 		flowop->fo_directio = attr->attr_integer;
17175184Sek110237 	else
17185184Sek110237 		flowop->fo_directio = integer_alloc(0);
17195184Sek110237 
17205184Sek110237 	/* Highwater mark */
17215184Sek110237 	if (attr = get_attr_integer(cmd, FSA_HIGHWATER))
17225184Sek110237 		flowop->fo_highwater = attr->attr_integer;
17235184Sek110237 	else
17245184Sek110237 		flowop->fo_highwater = integer_alloc(1);
17255184Sek110237 }
17265184Sek110237 
17275184Sek110237 /*
17285184Sek110237  * Calls fileset_define() to allocate a fileset with the supplied name and
17295184Sek110237  * initializes the fileset's pathname attribute, and optionally the fs_cached,
17305673Saw148015  * fs_reuse, fs_prealloc and fs_size attributes.
17315673Saw148015  *
17325184Sek110237  */
17335673Saw148015 static fileset_t *
17345673Saw148015 parser_fileset_define_common(cmd_t *cmd)
17355184Sek110237 {
17365184Sek110237 	fileset_t *fileset;
17375184Sek110237 	char *name;
17385184Sek110237 	attr_t *attr;
17395184Sek110237 	var_string_t pathname;
17405184Sek110237 
17415184Sek110237 	/* Get the name of the file */
17425184Sek110237 	if (attr = get_attr(cmd, FSA_NAME)) {
17435184Sek110237 		name = *attr->attr_string;
17445184Sek110237 	} else {
17455184Sek110237 		filebench_log(LOG_ERROR,
17465673Saw148015 		    "define fileset: file or fileset specifies no name");
17475673Saw148015 		return (NULL);
17485184Sek110237 	}
17495184Sek110237 
17505184Sek110237 	if ((fileset = fileset_define(name)) == NULL) {
17515184Sek110237 		filebench_log(LOG_ERROR,
17525184Sek110237 		    "define file: failed to instantiate file %s\n",
17535673Saw148015 		    name);
17545673Saw148015 		return (NULL);
17555184Sek110237 	}
17565184Sek110237 
17575184Sek110237 	/* Get the pathname from attribute */
17585184Sek110237 	if ((attr = get_attr(cmd, FSA_PATH)) == NULL) {
17595184Sek110237 		filebench_log(LOG_ERROR, "define file: no pathname specified");
17605673Saw148015 		return (NULL);
17615184Sek110237 	}
17625184Sek110237 
17635184Sek110237 	/* Expand variables in pathname */
17645673Saw148015 	if ((pathname = parser_list2varstring(attr->attr_param_list))
17655673Saw148015 	    == NULL) {
17665184Sek110237 		filebench_log(LOG_ERROR, "Cannot interpret path");
17675673Saw148015 		return (NULL);
17685184Sek110237 	}
17695184Sek110237 
17705184Sek110237 	fileset->fs_path = pathname;
17715184Sek110237 
17725673Saw148015 	/* Should we prealloc in parallel? */
17735673Saw148015 	if (attr = get_attr_bool(cmd, FSA_PARALLOC)) {
17745673Saw148015 		fileset->fs_paralloc = attr->attr_integer;
17755673Saw148015 	} else
17765673Saw148015 		fileset->fs_paralloc = integer_alloc(0);
17775673Saw148015 
17785673Saw148015 	/* Should we reuse the existing file? */
17795673Saw148015 	if (attr = get_attr_bool(cmd, FSA_REUSE)) {
17805673Saw148015 		fileset->fs_reuse = attr->attr_integer;
17815673Saw148015 	} else
17825673Saw148015 		fileset->fs_reuse = integer_alloc(0);
17835673Saw148015 
17845184Sek110237 	/* Should we leave in cache? */
17855184Sek110237 	if (attr = get_attr_bool(cmd, FSA_CACHED)) {
17865184Sek110237 		fileset->fs_cached = attr->attr_integer;
17875184Sek110237 	} else
17885184Sek110237 		fileset->fs_cached = integer_alloc(0);
17895184Sek110237 
17905673Saw148015 	/* Get the mean or absolute size of the file */
17915673Saw148015 	if (attr = get_attr_integer(cmd, FSA_SIZE)) {
17925673Saw148015 		fileset->fs_size = attr->attr_integer;
17935184Sek110237 	} else
17945673Saw148015 		fileset->fs_size = integer_alloc(0);
17955673Saw148015 
17965673Saw148015 	return (fileset);
17975673Saw148015 }
17985673Saw148015 
17995673Saw148015 /*
18005673Saw148015  * Calls parser_fileset_define_common() to allocate a fileset with
18015673Saw148015  * one entry and optionally the fs_prealloc. Sets the fs_preallocpercent,
18025673Saw148015  * fs_entries, fs_dirwidth, fs_dirgamma, and fs_sizegamma attributes
18035673Saw148015  * to appropriate values for emulating the old "fileobj" entity
18045673Saw148015  */
18055673Saw148015 static void
18065673Saw148015 parser_file_define(cmd_t *cmd)
18075673Saw148015 {
18085673Saw148015 	fileset_t *fileset;
18095673Saw148015 	attr_t *attr;
18105673Saw148015 
18115673Saw148015 	if ((fileset = parser_fileset_define_common(cmd)) == NULL) {
18125673Saw148015 		filebench_log(LOG_ERROR,
18135673Saw148015 		    "define file: failed to instantiate file");
18145673Saw148015 		filebench_shutdown(1);
18155673Saw148015 		return;
18165673Saw148015 	}
18175673Saw148015 
18185673Saw148015 	/* fileset is emulating a single file */
18195673Saw148015 	fileset->fs_attrs = FILESET_IS_FILE;
18205673Saw148015 
18215673Saw148015 	/* Set the size of the fileset to 1 */
18225673Saw148015 	fileset->fs_entries = integer_alloc(1);
18235673Saw148015 
18245673Saw148015 	/* Set the mean dir width to more than 1 */
18255673Saw148015 	fileset->fs_dirwidth = integer_alloc(10);
18265673Saw148015 
18275673Saw148015 	/* Set the dir and size gammas to 0 */
18285673Saw148015 	fileset->fs_dirgamma = integer_alloc(0);
18295673Saw148015 	fileset->fs_sizegamma = integer_alloc(0);
18305673Saw148015 
18315673Saw148015 	/* if a raw device, all done */
18325673Saw148015 	if (fileset_checkraw(fileset)) {
18335673Saw148015 		filebench_log(LOG_VERBOSE, "File %s/%s is RAW device",
18345673Saw148015 		    *fileset->fs_path, fileset->fs_name);
18355673Saw148015 		return;
18365673Saw148015 	}
18375673Saw148015 
18385673Saw148015 	/* Does file need to be preallocated? */
18395673Saw148015 	if (attr = get_attr_bool(cmd, FSA_PREALLOC)) {
18405673Saw148015 		/* yes */
18415673Saw148015 		fileset->fs_prealloc = attr->attr_integer;
18425673Saw148015 		fileset->fs_preallocpercent = integer_alloc(100);
18435673Saw148015 	} else {
18445673Saw148015 		/* no */
18455673Saw148015 		fileset->fs_prealloc = integer_alloc(0);
18465673Saw148015 		fileset->fs_preallocpercent = integer_alloc(0);
18475673Saw148015 	}
18485673Saw148015 }
18495673Saw148015 
18505673Saw148015 /*
18515673Saw148015  * Calls parser_fileset_define_common() to allocate a fileset with the
18525673Saw148015  * supplied name and initializes the fileset's fs_preallocpercent,
18535673Saw148015  * fs_prealloc, fs_entries, fs_dirwidth, fs_dirgamma, and fs_sizegamma
18545673Saw148015  * attributes.
18555673Saw148015  */
18565673Saw148015 static void
18575673Saw148015 parser_fileset_define(cmd_t *cmd)
18585673Saw148015 {
18595673Saw148015 	fileset_t *fileset;
18605673Saw148015 	attr_t *attr;
18615673Saw148015 
18625673Saw148015 	if ((fileset = parser_fileset_define_common(cmd)) == NULL) {
18635673Saw148015 		filebench_log(LOG_ERROR,
18645673Saw148015 		    "define fileset: failed to instantiate fileset");
18655673Saw148015 		filebench_shutdown(1);
18665673Saw148015 		return;
18675673Saw148015 	}
18685673Saw148015 
18695673Saw148015 	/* if a raw device, Error */
18705673Saw148015 	if (fileset_checkraw(fileset)) {
18715673Saw148015 		filebench_log(LOG_ERROR,
18725673Saw148015 		    "Fileset %s/%s: Cannot create a fileset on a RAW device",
18735673Saw148015 		    *fileset->fs_path, fileset->fs_name);
18745673Saw148015 		filebench_shutdown(0);
18755673Saw148015 		return;
18765673Saw148015 	}
18775673Saw148015 
18785673Saw148015 	/* How much should we preallocate? */
18795184Sek110237 	if ((attr = get_attr_integer(cmd, FSA_PREALLOC)) &&
18805184Sek110237 	    attr->attr_integer) {
18815184Sek110237 		fileset->fs_preallocpercent = attr->attr_integer;
18825184Sek110237 	} else if (attr && !attr->attr_integer) {
18835184Sek110237 		fileset->fs_preallocpercent = integer_alloc(100);
18845184Sek110237 	} else {
18855184Sek110237 		fileset->fs_preallocpercent = integer_alloc(0);
18865184Sek110237 	}
18875184Sek110237 
18885184Sek110237 	/* Should we preallocate? */
18895184Sek110237 	if (attr = get_attr_bool(cmd, FSA_PREALLOC)) {
18905184Sek110237 		fileset->fs_prealloc = attr->attr_integer;
18915184Sek110237 	} else
18925184Sek110237 		fileset->fs_prealloc = integer_alloc(0);
18935184Sek110237 
18945673Saw148015 	/* Get the number of files in the fileset */
18955184Sek110237 	if (attr = get_attr_integer(cmd, FSA_ENTRIES)) {
18965184Sek110237 		fileset->fs_entries = attr->attr_integer;
18975184Sek110237 	} else {
18985184Sek110237 		filebench_log(LOG_ERROR, "Fileset has zero entries");
18995184Sek110237 		fileset->fs_entries = integer_alloc(0);
19005184Sek110237 	}
19015184Sek110237 
19025184Sek110237 	/* Get the mean dir width of the fileset */
19035184Sek110237 	if (attr = get_attr_integer(cmd, FSA_DIRWIDTH)) {
19045184Sek110237 		fileset->fs_dirwidth = attr->attr_integer;
19055184Sek110237 	} else {
19065184Sek110237 		filebench_log(LOG_ERROR, "Fileset has zero directory width");
19075184Sek110237 		fileset->fs_dirwidth = integer_alloc(0);
19085184Sek110237 	}
19095184Sek110237 
19105184Sek110237 	/* Get the gamma value for dir width distributions */
19115184Sek110237 	if (attr = get_attr_integer(cmd, FSA_DIRGAMMA)) {
19125184Sek110237 		fileset->fs_dirgamma = attr->attr_integer;
19135184Sek110237 	} else
19145184Sek110237 		fileset->fs_dirgamma = integer_alloc(1500);
19155184Sek110237 
19165184Sek110237 	/* Get the gamma value for dir width distributions */
19175184Sek110237 	if (attr = get_attr_integer(cmd, FSA_FILESIZEGAMMA)) {
19185184Sek110237 		fileset->fs_sizegamma = attr->attr_integer;
19195184Sek110237 	} else
19205184Sek110237 		fileset->fs_sizegamma = integer_alloc(1500);
19215184Sek110237 }
19225184Sek110237 
19235184Sek110237 /*
19245184Sek110237  * Creates and starts all defined procflow processes. The call to
19255184Sek110237  * procflow_init() results in creation of the requested number of
19265184Sek110237  * process instances for each previously defined procflow. The
19275184Sek110237  * child processes exec() a new instance of filebench, passing it
19285184Sek110237  * the instance number and address of the shared memory region.
19295184Sek110237  * The child processes will then create their threads and flowops.
19305184Sek110237  * The routine then unlocks the run_lock to allow all the processes'
19315184Sek110237  * threads to start and  waits for all of them to begin execution.
19325184Sek110237  * Finally, it records the start time and resets the event generation
19335184Sek110237  * system.
19345184Sek110237  */
19355184Sek110237 static void
19365184Sek110237 parser_proc_create(cmd_t *cmd)
19375184Sek110237 {
1938*6084Saw148015 	filebench_shm->shm_1st_err = 0;
19395184Sek110237 	if (procflow_init() != 0) {
19405184Sek110237 		filebench_log(LOG_ERROR, "Failed to create processes\n");
19415184Sek110237 		filebench_shutdown(1);
19425184Sek110237 	}
19435184Sek110237 
19445184Sek110237 	/* Release the read lock, allowing threads to start */
19455184Sek110237 	(void) pthread_rwlock_unlock(&filebench_shm->run_lock);
19465184Sek110237 
19475184Sek110237 	/* Wait for all threads to start */
19485184Sek110237 	if (procflow_allstarted() != 0) {
19495184Sek110237 		filebench_log(LOG_ERROR, "Could not start run");
19505184Sek110237 		return;
19515184Sek110237 	}
19525184Sek110237 
19535184Sek110237 
19545184Sek110237 	if (filebench_shm->shm_required &&
19555184Sek110237 	    (ipc_ismcreate(filebench_shm->shm_required) < 0)) {
19565184Sek110237 		filebench_log(LOG_ERROR, "Could not allocate shared memory");
19575184Sek110237 		return;
19585184Sek110237 	}
19595184Sek110237 
19605184Sek110237 	filebench_shm->starttime = gethrtime();
19615184Sek110237 	eventgen_reset();
19625184Sek110237 }
19635184Sek110237 
19645184Sek110237 /*
19655673Saw148015  * Calls fileset_createset() to populate all files and filesets and
19665673Saw148015  * create all associated, initially existant,  files and subdirectories.
19675184Sek110237  * If errors are encountered, calls filebench_shutdown()
19685184Sek110237  * to exit filebench.
19695184Sek110237  */
19705184Sek110237 static void
19715184Sek110237 parser_fileset_create(cmd_t *cmd)
19725184Sek110237 {
19735673Saw148015 	if (!filecreate_done) {
19745673Saw148015 		filecreate_done = 1;
19755673Saw148015 		if (fileset_createset(NULL) != 0) {
19765673Saw148015 			filebench_log(LOG_ERROR, "Failed to create filesets");
19775673Saw148015 			filebench_shutdown(1);
19785673Saw148015 		}
19795673Saw148015 	} else {
19805673Saw148015 		filebench_log(LOG_INFO,
19815673Saw148015 		    "Attempting to create fileset more than once, ignoring");
19825184Sek110237 	}
19835673Saw148015 
19845184Sek110237 }
19855184Sek110237 
19865184Sek110237 /*
19875184Sek110237  * Shuts down all processes and their associated threads. When finished
19885184Sek110237  * it deletes interprocess shared memory and resets the event generator.
19895184Sek110237  * It does not exit the filebench program though.
19905184Sek110237  */
19915184Sek110237 static void
19925184Sek110237 parser_proc_shutdown(cmd_t *cmd)
19935184Sek110237 {
19945184Sek110237 	filebench_log(LOG_INFO, "Shutting down processes");
19955673Saw148015 	filecreate_done = 0;
19965184Sek110237 	procflow_shutdown();
19975184Sek110237 	if (filebench_shm->shm_required)
19985184Sek110237 		ipc_ismdelete();
19995184Sek110237 	eventgen_reset();
20005184Sek110237 }
20015184Sek110237 
20025184Sek110237 /*
20035184Sek110237  * Ends filebench run after first destoring any interprocess
20045184Sek110237  * shared memory. The call to filebench_shutdown()
20055184Sek110237  * also causes filebench to exit.
20065184Sek110237  */
20075184Sek110237 static void
20085184Sek110237 parser_filebench_shutdown(cmd_t *cmd)
20095184Sek110237 {
20105184Sek110237 	ipc_cleanup();
20115184Sek110237 	filebench_shutdown(1);
20125184Sek110237 }
20135184Sek110237 
20145184Sek110237 /*
2015*6084Saw148015  * This is Used for timing runs.Pauses the master thread in one second
2016*6084Saw148015  * intervals until the supplied ptime runs out or the f_abort flag
2017*6084Saw148015  * is raised. If given a time of zero or less, or the mode is stop on
2018*6084Saw148015  * lack of resources, it will pause until f_abort is raised.
20195184Sek110237  */
20205184Sek110237 static void
2021*6084Saw148015 parser_pause(int ptime)
20225184Sek110237 {
2023*6084Saw148015 	int timeslept = 0;
2024*6084Saw148015 
2025*6084Saw148015 	if ((filebench_shm->shm_rmode == FILEBENCH_MODE_TIMEOUT) &&
2026*6084Saw148015 	    (ptime > 0)) {
2027*6084Saw148015 		while (timeslept < ptime) {
2028*6084Saw148015 			(void) sleep(1);
2029*6084Saw148015 			timeslept++;
2030*6084Saw148015 			if (filebench_shm->f_abort)
2031*6084Saw148015 				break;
2032*6084Saw148015 		}
2033*6084Saw148015 	} else {
2034*6084Saw148015 		/* initial runtime of 0 means run till abort */
2035*6084Saw148015 		/* CONSTCOND */
2036*6084Saw148015 		while (1) {
2037*6084Saw148015 			(void) sleep(1);
2038*6084Saw148015 			timeslept++;
2039*6084Saw148015 			if (filebench_shm->f_abort)
2040*6084Saw148015 				break;
2041*6084Saw148015 		}
20425184Sek110237 	}
2043*6084Saw148015 
2044*6084Saw148015 	filebench_log(LOG_INFO, "Run took %lld seconds...", timeslept);
20455184Sek110237 }
20465184Sek110237 
20475184Sek110237 /*
20485184Sek110237  * Do a file bench run. Calls routines to create file sets, files, and
20495184Sek110237  * processes. It resets the statistics counters, then sleeps for the runtime
20505184Sek110237  * passed as an argument to it on the command line in 1 second increments.
20515184Sek110237  * When it is finished sleeping, it collects a snapshot of the statistics
20525184Sek110237  * and ends the run.
20535184Sek110237  */
20545184Sek110237 static void
20555184Sek110237 parser_run(cmd_t *cmd)
20565184Sek110237 {
20575184Sek110237 	int runtime;
20585184Sek110237 
20595184Sek110237 	runtime = cmd->cmd_qty;
2060*6084Saw148015 
20615184Sek110237 	parser_fileset_create(cmd);
20625184Sek110237 	parser_proc_create(cmd);
20635184Sek110237 
20645184Sek110237 	/* check for startup errors */
20655184Sek110237 	if (filebench_shm->f_abort)
20665184Sek110237 		return;
20675184Sek110237 
20685184Sek110237 	filebench_log(LOG_INFO, "Running...");
20695184Sek110237 	stats_clear();
2070*6084Saw148015 
2071*6084Saw148015 	parser_pause(runtime);
2072*6084Saw148015 
20735184Sek110237 	parser_statssnap(cmd);
20745184Sek110237 	parser_proc_shutdown(cmd);
20755184Sek110237 }
20765184Sek110237 
20775184Sek110237 /*
20785184Sek110237  * Similar to parser_run, but gets the sleep time from a variable
20795184Sek110237  * whose name is supplied as an argument to the command.
20805184Sek110237  */
20815184Sek110237 static void
20825184Sek110237 parser_run_variable(cmd_t *cmd)
20835184Sek110237 {
20845184Sek110237 	vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1);
20855184Sek110237 	int runtime;
20865184Sek110237 
20875184Sek110237 	if (integer == NULL) {
20885184Sek110237 		filebench_log(LOG_ERROR, "Unknown variable %s",
20895184Sek110237 		cmd->cmd_tgt1);
20905184Sek110237 		return;
20915184Sek110237 	}
20925184Sek110237 
20935184Sek110237 	runtime = *integer;
20945184Sek110237 
20955184Sek110237 	/* check for startup errors */
20965184Sek110237 	if (filebench_shm->f_abort)
20975184Sek110237 		return;
20985184Sek110237 
20995184Sek110237 	filebench_log(LOG_INFO, "Running...");
21005184Sek110237 	stats_clear();
2101*6084Saw148015 
2102*6084Saw148015 	parser_pause(runtime);
2103*6084Saw148015 
21045184Sek110237 	parser_statssnap(cmd);
2105*6084Saw148015 	parser_proc_shutdown(cmd);
21065184Sek110237 }
21075184Sek110237 
21085184Sek110237 char *usagestr = NULL;
21095184Sek110237 
21105184Sek110237 /*
21115184Sek110237  * Prints usage string if defined, else just a message requesting load of a
21125184Sek110237  * personality.
21135184Sek110237  */
21145184Sek110237 static void
21155184Sek110237 parser_help(cmd_t *cmd)
21165184Sek110237 {
21175184Sek110237 	int runtime;
21185184Sek110237 
21195184Sek110237 	if (usagestr) {
21205184Sek110237 		filebench_log(LOG_INFO, "%s", usagestr);
21215184Sek110237 	} else {
21225184Sek110237 		filebench_log(LOG_INFO,
21235184Sek110237 		    "load <personality> (ls "
21245184Sek110237 		    "/usr/benchmarks/filebench/workloads for list)");
21255184Sek110237 	}
21265184Sek110237 }
21275184Sek110237 
21285184Sek110237 char *varstr = NULL;
21295184Sek110237 
21305184Sek110237 /*
21315184Sek110237  * Prints the string of all var definitions, if there is one.
21325184Sek110237  */
21335184Sek110237 static void
21345184Sek110237 parser_printvars(cmd_t *cmd)
21355184Sek110237 {
21365184Sek110237 	int runtime;
21375184Sek110237 	char *str, *c;
21385184Sek110237 
21395184Sek110237 	if (varstr) {
21405184Sek110237 		str = strdup(varstr);
21415184Sek110237 		for (c = str; *c != '\0'; c++) {
21425184Sek110237 			if ((char)*c == '$')
21435184Sek110237 				*c = ' ';
21445184Sek110237 		}
21455184Sek110237 		filebench_log(LOG_INFO, "%s", str);
21465184Sek110237 		free(str);
21475184Sek110237 	}
21485184Sek110237 }
21495184Sek110237 
21505184Sek110237 /*
21515184Sek110237  * Used by the SET command to add a var and default value string to the
21525184Sek110237  * varstr string. It allocates a new, larger varstr string, copies the
21535184Sek110237  * old contents of varstr into it, then adds the new var string on the end.
21545184Sek110237  */
21555184Sek110237 static void
21565184Sek110237 parser_vars(cmd_t *cmd)
21575184Sek110237 {
21585184Sek110237 	char *string = cmd->cmd_tgt1;
21595184Sek110237 	char *newvars;
21605184Sek110237 
21615184Sek110237 	if (string == NULL)
21625184Sek110237 		return;
21635184Sek110237 
21645184Sek110237 	if (dofile)
21655184Sek110237 		return;
21665184Sek110237 
21675184Sek110237 	if (varstr == NULL) {
21685184Sek110237 		newvars = malloc(strlen(string) + 2);
21695184Sek110237 		*newvars = 0;
21705184Sek110237 	} else {
21715184Sek110237 		newvars = malloc(strlen(varstr) + strlen(string) + 2);
21725184Sek110237 		(void) strcpy(newvars, varstr);
21735184Sek110237 	}
21745184Sek110237 	(void) strcat(newvars, string);
21755184Sek110237 	(void) strcat(newvars, " ");
21765184Sek110237 
21775184Sek110237 	if (varstr)
21785184Sek110237 		free(varstr);
21795184Sek110237 
21805184Sek110237 	varstr = newvars;
21815184Sek110237 }
21825184Sek110237 
21835184Sek110237 /*
2184*6084Saw148015  * Sleeps for cmd->cmd_qty seconds, one second at a time.
2185*6084Saw148015  */
2186*6084Saw148015 static void
2187*6084Saw148015 parser_sleep(cmd_t *cmd)
2188*6084Saw148015 {
2189*6084Saw148015 	int sleeptime;
2190*6084Saw148015 
2191*6084Saw148015 	/* check for startup errors */
2192*6084Saw148015 	if (filebench_shm->f_abort)
2193*6084Saw148015 		return;
2194*6084Saw148015 
2195*6084Saw148015 	sleeptime = cmd->cmd_qty;
2196*6084Saw148015 	filebench_log(LOG_INFO, "Running...");
2197*6084Saw148015 
2198*6084Saw148015 	parser_pause(sleeptime);
2199*6084Saw148015 }
2200*6084Saw148015 
2201*6084Saw148015 /*
22025184Sek110237  * Same as parser_sleep, except the sleep time is obtained from a variable
22035184Sek110237  * whose name is passed to it as an argument on the command line.
22045184Sek110237  */
22055184Sek110237 static void
22065184Sek110237 parser_sleep_variable(cmd_t *cmd)
22075184Sek110237 {
22085184Sek110237 	vinteger_t *integer = var_ref_integer(cmd->cmd_tgt1);
22095184Sek110237 	int sleeptime;
22105184Sek110237 
22115184Sek110237 	if (integer == NULL) {
22125184Sek110237 		filebench_log(LOG_ERROR, "Unknown variable %s",
22135184Sek110237 		cmd->cmd_tgt1);
22145184Sek110237 		return;
22155184Sek110237 	}
22165184Sek110237 
22175184Sek110237 	sleeptime = *integer;
22185184Sek110237 
22195184Sek110237 	/* check for startup errors */
22205184Sek110237 	if (filebench_shm->f_abort)
22215184Sek110237 		return;
22225184Sek110237 
22235184Sek110237 	filebench_log(LOG_INFO, "Running...");
2224*6084Saw148015 
2225*6084Saw148015 	parser_pause(sleeptime);
22265184Sek110237 }
22275184Sek110237 
22285184Sek110237 /*
22295184Sek110237  * Parser log prints the values of a list of variables to the log file.
22305184Sek110237  * The list of variables is placed on the command line, separated
22315184Sek110237  * by comas and the entire list is enclosed in quotes.
22325184Sek110237  * For example, if $dir contains "/export/home/tmp" and $filesize = 1048576,
22335184Sek110237  * then typing: log "$dir, $filesize" prints: log /export/home/tmp, 1048576
22345184Sek110237  */
22355184Sek110237 static void
22365184Sek110237 parser_log(cmd_t *cmd)
22375184Sek110237 {
22385184Sek110237 	char *string;
22395184Sek110237 
22405184Sek110237 	if (cmd->cmd_param_list == NULL)
22415184Sek110237 		return;
22425184Sek110237 
22435184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
22445184Sek110237 
22455184Sek110237 	if (string == NULL)
22465184Sek110237 		return;
22475184Sek110237 
22485184Sek110237 	filebench_log(LOG_VERBOSE, "log %s", string);
22495184Sek110237 	filebench_log(LOG_LOG, "%s", string);
22505184Sek110237 }
22515184Sek110237 
22525184Sek110237 /*
22535184Sek110237  * Implements the stats directory command. changes the directory for
22545184Sek110237  * dumping statistics to supplied directory path. For example:
22555184Sek110237  * 	stats directory /tmp
22565184Sek110237  * changes the stats directory to "/tmp".
22575184Sek110237  */
22585184Sek110237 static void
22595184Sek110237 parser_directory(cmd_t *cmd)
22605184Sek110237 {
22615184Sek110237 	char newdir[MAXPATHLEN];
22625184Sek110237 	char *dir;
22635184Sek110237 
22645184Sek110237 	if ((dir = parser_list2string(cmd->cmd_param_list)) == NULL) {
22655184Sek110237 		filebench_log(LOG_ERROR, "Cannot interpret directory");
22665184Sek110237 		return;
22675184Sek110237 	}
22685184Sek110237 
22695184Sek110237 	*newdir = 0;
22705184Sek110237 	/* Change dir relative to cwd if path not fully qualified */
22715184Sek110237 	if (*dir != '/') {
22725184Sek110237 		(void) strcat(newdir, cwd);
22735184Sek110237 		(void) strcat(newdir, "/");
22745184Sek110237 	}
22755184Sek110237 	(void) strcat(newdir, dir);
22765184Sek110237 	(void) mkdir(newdir, 0755);
22775184Sek110237 	filebench_log(LOG_VERBOSE, "Change dir to %s", newdir);
22785184Sek110237 	chdir(newdir);
22795184Sek110237 	free(dir);
22805184Sek110237 }
22815184Sek110237 
22825184Sek110237 #define	PIPE_PARENT 1
22835184Sek110237 #define	PIPE_CHILD  0
22845184Sek110237 
22855184Sek110237 /*
22865184Sek110237  * Runs the quoted unix command as a background process. Intended for
22875184Sek110237  * running statistics gathering utilities such as mpstat while the filebench
22885184Sek110237  * workload is running. Also records the pid's of the background processes
22895184Sek110237  * so that parser_statssnap() can terminate them when the run completes.
22905184Sek110237  */
22915184Sek110237 static void
22925184Sek110237 parser_statscmd(cmd_t *cmd)
22935184Sek110237 {
22945184Sek110237 	char *string;
22955184Sek110237 	pid_t pid;
22965184Sek110237 	pidlist_t *pidlistent;
22975184Sek110237 	int pipe_fd[2];
22985184Sek110237 	int newstdout;
22995184Sek110237 
23005184Sek110237 	if (cmd->cmd_param_list == NULL)
23015184Sek110237 		return;
23025184Sek110237 
23035184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
23045184Sek110237 
23055184Sek110237 	if (string == NULL)
23065184Sek110237 		return;
23075184Sek110237 
23085184Sek110237 	if ((pipe(pipe_fd)) < 0) {
23095184Sek110237 		filebench_log(LOG_ERROR, "statscmd pipe failed");
23105184Sek110237 		return;
23115184Sek110237 	}
23125184Sek110237 
23135184Sek110237 #ifdef HAVE_FORK1
23145184Sek110237 	if ((pid = fork1()) < 0) {
23155184Sek110237 		filebench_log(LOG_ERROR, "statscmd fork failed");
23165184Sek110237 		return;
23175184Sek110237 	}
23185184Sek110237 #elif HAVE_FORK
23195184Sek110237 	if ((pid = fork()) < 0) {
23205184Sek110237 		filebench_log(LOG_ERROR, "statscmd fork failed");
23215184Sek110237 		return;
23225184Sek110237 	}
23235184Sek110237 #else
23245184Sek110237 	Crash! - Need code to deal with no fork1!
23255184Sek110237 #endif /* HAVE_FORK1 */
23265184Sek110237 
23275184Sek110237 	if (pid == 0) {
23285184Sek110237 
23295184Sek110237 		setsid();
23305184Sek110237 
23315184Sek110237 		filebench_log(LOG_VERBOSE,
23325184Sek110237 		    "Backgrounding %s", string);
23335184Sek110237 		/*
23345184Sek110237 		 * Child
23355184Sek110237 		 * - close stdout
23365184Sek110237 		 * - dup to create new stdout
23375184Sek110237 		 * - close pipe fds
23385184Sek110237 		 */
23395184Sek110237 		(void) close(1);
23405184Sek110237 
23415184Sek110237 		if ((newstdout = dup(pipe_fd[PIPE_CHILD])) < 0) {
23425184Sek110237 			filebench_log(LOG_ERROR,
23435184Sek110237 			    "statscmd dup failed: %s",
23445184Sek110237 			    strerror(errno));
23455184Sek110237 		}
23465184Sek110237 
23475184Sek110237 		(void) close(pipe_fd[PIPE_PARENT]);
23485184Sek110237 		(void) close(pipe_fd[PIPE_CHILD]);
23495184Sek110237 
23505184Sek110237 		if (system(string) < 0) {
23515184Sek110237 			filebench_log(LOG_ERROR,
23525184Sek110237 			    "statscmd exec failed: %s",
23535184Sek110237 			    strerror(errno));
23545184Sek110237 		}
23555184Sek110237 		/* Failed! */
23565184Sek110237 		exit(1);
23575184Sek110237 
23585184Sek110237 	} else {
23595184Sek110237 
23605184Sek110237 		/* Record pid in pidlist for subsequent reaping by stats snap */
23615184Sek110237 		if ((pidlistent = (pidlist_t *)malloc(sizeof (pidlist_t)))
23625184Sek110237 		    == NULL) {
23635184Sek110237 			filebench_log(LOG_ERROR, "pidlistent malloc failed");
23645184Sek110237 			return;
23655184Sek110237 		}
23665184Sek110237 
23675184Sek110237 		pidlistent->pl_pid = pid;
23685184Sek110237 		pidlistent->pl_fd = pipe_fd[PIPE_PARENT];
23695184Sek110237 		(void) close(pipe_fd[PIPE_CHILD]);
23705184Sek110237 
23715184Sek110237 		/* Add fileobj to global list */
23725184Sek110237 		if (pidlist == NULL) {
23735184Sek110237 			pidlist = pidlistent;
23745184Sek110237 			pidlistent->pl_next = NULL;
23755184Sek110237 		} else {
23765184Sek110237 			pidlistent->pl_next = pidlist;
23775184Sek110237 			pidlist = pidlistent;
23785184Sek110237 		}
23795184Sek110237 	}
23805184Sek110237 }
23815184Sek110237 
23825184Sek110237 /*
23835184Sek110237  * Launches a shell to run the unix command supplied in the argument.
23845184Sek110237  * The command should be enclosed in quotes, as in:
23855184Sek110237  * 	system "rm xyz"
23865184Sek110237  * which would run the "rm" utility to delete the file "xyz".
23875184Sek110237  */
23885184Sek110237 static void
23895184Sek110237 parser_system(cmd_t *cmd)
23905184Sek110237 {
23915184Sek110237 	char *string;
23925184Sek110237 
23935184Sek110237 	if (cmd->cmd_param_list == NULL)
23945184Sek110237 		return;
23955184Sek110237 
23965184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
23975184Sek110237 
23985184Sek110237 	if (string == NULL)
23995184Sek110237 		return;
24005184Sek110237 
24015184Sek110237 	filebench_log(LOG_VERBOSE,
24025184Sek110237 	    "Running '%s'", string);
24035184Sek110237 
24045184Sek110237 	if (system(string) < 0) {
24055184Sek110237 		filebench_log(LOG_ERROR,
24065184Sek110237 		    "system exec failed: %s",
24075184Sek110237 		    strerror(errno));
24085184Sek110237 	}
24095184Sek110237 	free(string);
24105184Sek110237 }
24115184Sek110237 
24125184Sek110237 /*
24135184Sek110237  * Echos string supplied with command to the log.
24145184Sek110237  */
24155184Sek110237 static void
24165184Sek110237 parser_echo(cmd_t *cmd)
24175184Sek110237 {
24185184Sek110237 	char *string;
24195184Sek110237 
24205184Sek110237 	if (cmd->cmd_param_list == NULL)
24215184Sek110237 		return;
24225184Sek110237 
24235184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
24245184Sek110237 
24255184Sek110237 	if (string == NULL)
24265184Sek110237 		return;
24275184Sek110237 
24285184Sek110237 	filebench_log(LOG_INFO, "%s", string);
24295184Sek110237 }
24305184Sek110237 
24315184Sek110237 
24325184Sek110237 /*
24335184Sek110237  * Adds the string supplied as the argument to the usage command
24345184Sek110237  * to the end of the string printed by the help command.
24355184Sek110237  */
24365184Sek110237 static void
24375184Sek110237 parser_usage(cmd_t *cmd)
24385184Sek110237 {
24395184Sek110237 	char *string;
24405184Sek110237 	char *newusage;
24415184Sek110237 
24425184Sek110237 	if (cmd->cmd_param_list == NULL)
24435184Sek110237 		return;
24445184Sek110237 
24455184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
24465184Sek110237 
24475184Sek110237 	if (string == NULL)
24485184Sek110237 		return;
24495184Sek110237 
24505184Sek110237 	if (dofile)
24515184Sek110237 		return;
24525184Sek110237 
24535184Sek110237 	if (usagestr == NULL) {
24545184Sek110237 		newusage = malloc(strlen(string) + 2);
24555184Sek110237 		*newusage = 0;
24565184Sek110237 	} else {
24575184Sek110237 		newusage = malloc(strlen(usagestr) + strlen(string) + 2);
24585184Sek110237 		(void) strcpy(newusage, usagestr);
24595184Sek110237 	}
24605184Sek110237 	(void) strcat(newusage, "\n");
24615184Sek110237 	(void) strcat(newusage, string);
24625184Sek110237 
24635184Sek110237 	if (usagestr)
24645184Sek110237 		free(usagestr);
24655184Sek110237 
24665184Sek110237 	usagestr = newusage;
24675184Sek110237 
24685184Sek110237 	filebench_log(LOG_INFO, "%s", string);
24695184Sek110237 }
24705184Sek110237 
24715184Sek110237 /*
24725184Sek110237  * Updates the global dump filename with the filename supplied
24735184Sek110237  * as the command's argument. Then dumps the statistics of each
24745184Sek110237  * worker flowop into the dump file, followed by a summary of
24755184Sek110237  * overall totals.
24765184Sek110237  */
24775184Sek110237 static void
24785184Sek110237 parser_statsdump(cmd_t *cmd)
24795184Sek110237 {
24805184Sek110237 	char *string;
24815184Sek110237 
24825184Sek110237 	if (cmd->cmd_param_list == NULL)
24835184Sek110237 		return;
24845184Sek110237 
24855184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
24865184Sek110237 
24875184Sek110237 	if (string == NULL)
24885184Sek110237 		return;
24895184Sek110237 
24905184Sek110237 	filebench_log(LOG_VERBOSE,
24915184Sek110237 	    "Stats dump to file '%s'", string);
24925184Sek110237 
24935184Sek110237 	stats_dump(string);
24945184Sek110237 
24955184Sek110237 	free(string);
24965184Sek110237 }
24975184Sek110237 
24985184Sek110237 /*
24995184Sek110237  * Same as parser_statsdump, but in xml format.
25005184Sek110237  */
25015184Sek110237 static void
25025184Sek110237 parser_statsxmldump(cmd_t *cmd)
25035184Sek110237 {
25045184Sek110237 	char *string;
25055184Sek110237 
25065184Sek110237 	if (cmd->cmd_param_list == NULL)
25075184Sek110237 		return;
25085184Sek110237 
25095184Sek110237 	string = parser_list2string(cmd->cmd_param_list);
25105184Sek110237 
25115184Sek110237 	if (string == NULL)
25125184Sek110237 		return;
25135184Sek110237 
25145184Sek110237 	filebench_log(LOG_VERBOSE,
25155184Sek110237 	    "Stats dump to file '%s'", string);
25165184Sek110237 
25175184Sek110237 	stats_xmldump(string);
25185184Sek110237 
25195184Sek110237 	free(string);
25205184Sek110237 }
25215184Sek110237 
25225184Sek110237 /*
25235184Sek110237  * Kills off background statistics collection processes, then takes a snapshot
25245184Sek110237  * of the filebench run's collected statistics using stats_snap() from
25255184Sek110237  * stats.c.
25265184Sek110237  */
25275184Sek110237 static void
25285184Sek110237 parser_statssnap(cmd_t *cmd)
25295184Sek110237 {
25305184Sek110237 	pidlist_t *pidlistent;
25315184Sek110237 	int stat;
25325184Sek110237 	pid_t pid;
25335184Sek110237 
25345184Sek110237 	for (pidlistent = pidlist; pidlistent != NULL;
25355184Sek110237 	    pidlistent = pidlistent->pl_next) {
25365184Sek110237 		filebench_log(LOG_VERBOSE, "Killing session %d for pid %d",
25375184Sek110237 		    getsid(pidlistent->pl_pid),
25385184Sek110237 		    pidlistent->pl_pid);
25395184Sek110237 		if (pidlistent->pl_fd)
25405184Sek110237 			(void) close(pidlistent->pl_fd);
25415184Sek110237 #ifdef HAVE_SIGSEND
25425184Sek110237 		sigsend(P_SID, getsid(pidlistent->pl_pid), SIGTERM);
25435184Sek110237 #else
25445184Sek110237 		(void) kill(-1, SIGTERM);
25455184Sek110237 #endif
25465184Sek110237 
25475184Sek110237 		/* Close pipe */
25485184Sek110237 		if (pidlistent->pl_fd)
25495184Sek110237 			(void) close(pidlistent->pl_fd);
25505184Sek110237 
25515184Sek110237 		/* Wait for cmd and all its children */
25525184Sek110237 		while ((pid = waitpid(pidlistent->pl_pid * -1, &stat, 0)) > 0)
25535184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
25545184Sek110237 			"Waited for pid %lld", pid);
25555184Sek110237 	}
25565184Sek110237 
25575184Sek110237 	for (pidlistent = pidlist; pidlistent != NULL;
25585184Sek110237 	    pidlistent = pidlistent->pl_next) {
25595184Sek110237 		free(pidlistent);
25605184Sek110237 	}
25615184Sek110237 
25625184Sek110237 	pidlist = NULL;
25635184Sek110237 	stats_snap();
25645184Sek110237 }
25655184Sek110237 
25665184Sek110237 /*
25675184Sek110237  * Shutdown filebench.
25685184Sek110237  */
25695184Sek110237 static void
25705184Sek110237 parser_abort(int arg)
25715184Sek110237 {
25725184Sek110237 	(void) sigignore(SIGINT);
25735184Sek110237 	filebench_log(LOG_INFO, "Aborting...");
25745184Sek110237 	filebench_shutdown(1);
25755184Sek110237 }
25765184Sek110237 
25775184Sek110237 /*
25785184Sek110237  * alloc_cmd() allocates the required resources for a cmd_t. On failure, a
25795184Sek110237  * filebench_log is issued and NULL is returned.
25805184Sek110237  */
25815184Sek110237 static cmd_t *
25825184Sek110237 alloc_cmd(void)
25835184Sek110237 {
25845184Sek110237 	cmd_t *cmd;
25855184Sek110237 
25865184Sek110237 	if ((cmd = malloc(sizeof (cmd_t))) == NULL) {
25875184Sek110237 		filebench_log(LOG_ERROR, "Alloc cmd failed");
25885184Sek110237 		return (NULL);
25895184Sek110237 	}
25905184Sek110237 
25915184Sek110237 	(void) memset(cmd, 0, sizeof (cmd_t));
25925184Sek110237 
25935184Sek110237 	return (cmd);
25945184Sek110237 }
25955184Sek110237 
25965184Sek110237 /*
25975184Sek110237  * Frees the resources of a cmd_t and then the cmd_t "cmd" itself.
25985184Sek110237  */
25995184Sek110237 static void
26005184Sek110237 free_cmd(cmd_t *cmd)
26015184Sek110237 {
26025184Sek110237 	free((void *)cmd->cmd_tgt1);
26035184Sek110237 	free((void *)cmd->cmd_tgt2);
26045184Sek110237 	free(cmd);
26055184Sek110237 }
26065184Sek110237 
26075184Sek110237 /*
26085184Sek110237  * Allocates an attr_t structure and zeros it. Returns NULL on failure, or
26095184Sek110237  * a pointer to the attr_t.
26105184Sek110237  */
26115184Sek110237 static attr_t *
26125184Sek110237 alloc_attr()
26135184Sek110237 {
26145184Sek110237 	attr_t *attr;
26155184Sek110237 
26165184Sek110237 	if ((attr = malloc(sizeof (attr_t))) == NULL) {
26175184Sek110237 		return (NULL);
26185184Sek110237 	}
26195184Sek110237 
26205184Sek110237 	(void) memset(attr, 0, sizeof (attr_t));
26215184Sek110237 	return (attr);
26225184Sek110237 }
26235184Sek110237 
26245184Sek110237 /*
26255184Sek110237  * Searches the attribute list for the command for the named attribute type.
26265184Sek110237  * The attribute list is created by the parser from the list of attributes
26275184Sek110237  * supplied with certain commands, such as the define and flowop commands.
26285184Sek110237  * Returns a pointer to the attribute structure if the named attribute is
26295184Sek110237  * found, otherwise returns NULL. If the attribute includes a parameter list,
26305184Sek110237  * the list is converted to a string and stored in the attr_string field of
26315184Sek110237  * the returned attr_t struct.
26325184Sek110237  */
26335184Sek110237 static attr_t *
26345184Sek110237 get_attr(cmd_t *cmd, int64_t name)
26355184Sek110237 {
26365184Sek110237 	attr_t *attr;
26375184Sek110237 	attr_t *rtn = NULL;
26385184Sek110237 	char *string;
26395184Sek110237 
26405184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
26415184Sek110237 	    attr = attr->attr_next) {
26425184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
26435184Sek110237 		    "attr %d = %d %llx?",
26445184Sek110237 		    attr->attr_name,
26455184Sek110237 		    name,
26465184Sek110237 		    attr->attr_integer);
26475184Sek110237 
26485184Sek110237 		if (attr->attr_name == name)
26495184Sek110237 			rtn = attr;
26505184Sek110237 	}
26515184Sek110237 
26525184Sek110237 	if (rtn == NULL)
26535184Sek110237 		return (NULL);
26545184Sek110237 
26555184Sek110237 	if (rtn->attr_param_list) {
26565184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT, "attr is param list");
26575184Sek110237 		string = parser_list2string(rtn->attr_param_list);
26585184Sek110237 		if (string != NULL) {
26595184Sek110237 			rtn->attr_string = string_alloc(string);
26605184Sek110237 			filebench_log(LOG_DEBUG_SCRIPT,
26615184Sek110237 			    "attr string %s", string);
26625184Sek110237 		}
26635184Sek110237 	}
26645184Sek110237 
26655184Sek110237 	return (rtn);
26665184Sek110237 }
26675184Sek110237 
26685184Sek110237 /*
26695184Sek110237  * Similar to get_attr, but converts the parameter string supplied with the
26705184Sek110237  * named attribute to an integer and stores the integer in the attr_integer
26715184Sek110237  * portion of the returned attr_t struct.
26725184Sek110237  */
26735184Sek110237 static attr_t *
26745184Sek110237 get_attr_integer(cmd_t *cmd, int64_t name)
26755184Sek110237 {
26765184Sek110237 	attr_t *attr;
26775184Sek110237 	attr_t *rtn = NULL;
26785184Sek110237 
26795184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
26805184Sek110237 	    attr = attr->attr_next) {
26815184Sek110237 		if (attr->attr_name == name)
26825184Sek110237 			rtn = attr;
26835184Sek110237 	}
26845184Sek110237 
26855184Sek110237 	if (rtn == NULL)
26865184Sek110237 		return (NULL);
26875184Sek110237 
26885184Sek110237 	if (rtn->attr_param_list) {
26895184Sek110237 		rtn->attr_integer = parser_list2integer(rtn->attr_param_list);
26905184Sek110237 	}
26915184Sek110237 
26925184Sek110237 	return (rtn);
26935184Sek110237 }
26945184Sek110237 
26955184Sek110237 /*
26965184Sek110237  * Similar to get_attr, but converts the parameter string supplied with the
26975184Sek110237  * named attribute to an integer and stores the integer in the attr_integer
26985184Sek110237  * portion of the returned attr_t struct. If no parameter string is supplied
26995184Sek110237  * then it defaults to TRUE (1).
27005184Sek110237  */
27015184Sek110237 static attr_t *
27025184Sek110237 get_attr_bool(cmd_t *cmd, int64_t name)
27035184Sek110237 {
27045184Sek110237 	attr_t *attr;
27055184Sek110237 	attr_t *rtn = NULL;
27065184Sek110237 
27075184Sek110237 	for (attr = cmd->cmd_attr_list; attr != NULL;
27085184Sek110237 	    attr = attr->attr_next) {
27095184Sek110237 		if (attr->attr_name == name)
27105184Sek110237 			rtn = attr;
27115184Sek110237 	}
27125184Sek110237 
27135184Sek110237 	if (rtn == NULL)
27145184Sek110237 		return (NULL);
27155184Sek110237 
27165184Sek110237 	if (rtn->attr_param_list) {
27175184Sek110237 		rtn->attr_integer = parser_list2integer(rtn->attr_param_list);
27185184Sek110237 	} else if (rtn->attr_integer == 0) {
27195184Sek110237 		rtn->attr_integer = integer_alloc(1);
27205184Sek110237 	}
27215184Sek110237 
27225184Sek110237 	return (rtn);
27235184Sek110237 }
27245184Sek110237 
27255184Sek110237 /*
27265184Sek110237  * Allocates memory for a list_t structure, initializes it to zero, and
27275184Sek110237  * returns a pointer to it. On failure, returns NULL.
27285184Sek110237  */
27295184Sek110237 static list_t *
27305184Sek110237 alloc_list()
27315184Sek110237 {
27325184Sek110237 	list_t *list;
27335184Sek110237 
27345184Sek110237 	if ((list = malloc(sizeof (list_t))) == NULL) {
27355184Sek110237 		return (NULL);
27365184Sek110237 	}
27375184Sek110237 
27385184Sek110237 	(void) memset(list, 0, sizeof (list_t));
27395184Sek110237 	return (list);
27405184Sek110237 }
27415184Sek110237 
27425184Sek110237 
27435184Sek110237 #define	USAGE1	\
27445184Sek110237 "Usage:\n" \
27455184Sek110237 "%s: interpret f script and generate file workload\n" \
27465184Sek110237 "Options:\n" \
27475184Sek110237 "   [-h] Display verbose help\n" \
27485184Sek110237 "   [-p] Disable opening /proc to set uacct to enable truss\n"
27495184Sek110237 
27505184Sek110237 #define	PARSER_CMDS \
27515184Sek110237 "create [files|filesets|processes]\n" \
27525184Sek110237 "stats [clear|snap]\n" \
27535184Sek110237 "stats command \"shell command $var1,$var2...\"\n" \
27545184Sek110237 "stats directory <directory>\n" \
27555184Sek110237 "sleep <sleep-value>\n" \
27565184Sek110237 "quit\n\n" \
27575184Sek110237 "Variables:\n" \
27585184Sek110237 "set $var = value\n" \
27595184Sek110237 "    $var   - regular variables\n" \
27605184Sek110237 "    ${var} - internal special variables\n" \
27615184Sek110237 "    $(var) - environment variables\n\n"
27625184Sek110237 
27635184Sek110237 #define	PARSER_EXAMPLE \
27645184Sek110237 "Example:\n\n" \
27655184Sek110237 "#!/usr/bin/filebench -f\n" \
27665184Sek110237 "\n" \
27675184Sek110237 "define file name=bigfile,path=bigfile,size=1g,prealloc,reuse\n" \
27685184Sek110237 "define process name=randomizer\n" \
27695184Sek110237 "{\n" \
27705184Sek110237 "  thread random-thread procname=randomizer\n"	\
27715184Sek110237 "  {\n" \
27725184Sek110237 "    flowop read name=random-read,filename=bigfile,iosize=16k,random\n" \
27735184Sek110237 "  }\n" \
27745184Sek110237 "}\n" \
27755184Sek110237 "create files\n" \
27765184Sek110237 "create processes\n" \
27775184Sek110237 "stats clear\n" \
27785184Sek110237 "sleep 30\n" \
27795184Sek110237 "stats snap\n"
27805184Sek110237 
27815184Sek110237 /*
27825184Sek110237  * usage() display brief or verbose help for the filebench(1) command.
27835184Sek110237  */
27845184Sek110237 static void
27855184Sek110237 usage(int help)
27865184Sek110237 {
27875184Sek110237 	if (help >= 1)
27885184Sek110237 		(void) fprintf(stderr, USAGE1, cmdname);
27895184Sek110237 	if (help >= 2) {
27905184Sek110237 
27915184Sek110237 		(void) fprintf(stderr,
27925184Sek110237 		    "\n'f' language definition:\n\n");
27935184Sek110237 		fileset_usage();
27945184Sek110237 		procflow_usage();
27955184Sek110237 		threadflow_usage();
27965184Sek110237 		flowoplib_usage();
27975184Sek110237 		eventgen_usage();
27985184Sek110237 		(void) fprintf(stderr, PARSER_CMDS);
27995184Sek110237 		(void) fprintf(stderr, PARSER_EXAMPLE);
28005184Sek110237 	}
28015184Sek110237 	exit(E_USAGE);
28025184Sek110237 }
28035184Sek110237 
28045184Sek110237 int
28055184Sek110237 yywrap()
28065184Sek110237 {
28075184Sek110237 	char buf[1024];
28085184Sek110237 
28095184Sek110237 	if (parentscript) {
28105184Sek110237 		yyin = parentscript;
28115184Sek110237 		yy_switchfilescript(yyin);
28125184Sek110237 		parentscript = NULL;
28135184Sek110237 		return (0);
28145184Sek110237 	} else
28155184Sek110237 		return (1);
28165184Sek110237 }
2817