summaryrefslogtreecommitdiff
path: root/usr/src/cmd/filebench/common/vars.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/filebench/common/vars.c')
-rw-r--r--usr/src/cmd/filebench/common/vars.c547
1 files changed, 547 insertions, 0 deletions
diff --git a/usr/src/cmd/filebench/common/vars.c b/usr/src/cmd/filebench/common/vars.c
new file mode 100644
index 0000000000..6145547cff
--- /dev/null
+++ b/usr/src/cmd/filebench/common/vars.c
@@ -0,0 +1,547 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "vars.h"
+#include "misc.h"
+#include "utils.h"
+#include "stats.h"
+#include "eventgen.h"
+#include "filebench.h"
+
+static var_t *var_find_dynamic(char *name);
+
+/*
+ * The filebench variables consist of var_integers (var_integer_t)
+ * and var_strings (var_string_t), which are pointers to integers and
+ * strings respectively, and vars (var_t), which are named, typed
+ * entities which contain either an integer or a string and can be
+ * placed on a linked list. All three of these objects are allocated
+ * from interprocess shared memory space.
+ *
+ * The routines in this module are used to allocate, locate, and
+ * manipulate the var_integers, var_strings, and vars. Routines are
+ * also included to convert between the component strings and integers
+ * of vars, and var_strings and var_integers.
+ */
+
+/*
+ * Returns the int pointed to by the supplied var_integer_t "v".
+ */
+int
+integer_isset(var_integer_t v)
+{
+ if (v == NULL)
+ return (0);
+
+ return (*v);
+}
+
+/*
+ * Allocates a var_integer_t from ipc memory space and
+ * pre-loads it with the vinteger_t "integer". Returns
+ * the var_integer_t on success, NULL on failure.
+ */
+var_integer_t
+integer_alloc(vinteger_t integer)
+{
+ var_integer_t rtn;
+
+ if ((rtn = (vinteger_t *)ipc_malloc(FILEBENCH_INTEGER)) == NULL) {
+ filebench_log(LOG_ERROR, "Alloc integer failed");
+ return (NULL);
+ }
+
+ *rtn = integer;
+
+ filebench_log(LOG_DEBUG_IMPL, "Alloc integer %lld", integer);
+
+ return (rtn);
+}
+
+/*
+ * Allocates a string pointer in interprocess shared memory,
+ * then allocates and initializes a piece of shared string memory,
+ * putting the pointer to it into the just allocated string
+ * pointer location. The routine returns a pointer to the
+ * string pointer location or returns NULL on error.
+ */
+var_string_t
+string_alloc(char *string)
+{
+ char **rtn;
+
+ if ((rtn = (char **)ipc_malloc(FILEBENCH_STRING)) == NULL) {
+ filebench_log(LOG_ERROR, "Alloc string failed");
+ return (NULL);
+ }
+
+ *rtn = ipc_stralloc(string);
+
+ filebench_log(LOG_DEBUG_IMPL,
+ "Alloc string %s ptr %zx",
+ string, rtn);
+
+ return (rtn);
+}
+
+
+/*
+ * Allocates a var (var_t) from interprocess shared memory.
+ * Places the allocated var on the end of the globally shared
+ * var_list. Finally, the routine allocates a string containing
+ * a copy of the supplied "name" string. If any allocations
+ * fails, returns NULL, otherwise it returns a pointer to the
+ * newly allocated var.
+ */
+static var_t *
+var_alloc(char *name)
+{
+ var_t *var = NULL;
+ var_t *prev = NULL;
+ var_t *newvar;
+
+ if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) {
+ filebench_log(LOG_ERROR, "Out of memory for variables");
+ return (NULL);
+ }
+ (void) memset(newvar, 0, sizeof (newvar));
+
+ for (var = filebench_shm->var_list; var != NULL; var = var->var_next)
+ prev = var; /* Find end of list */
+ if (prev != NULL)
+ prev->var_next = newvar;
+ else
+ filebench_shm->var_list = newvar;
+
+ if ((newvar->var_name = ipc_stralloc(name)) == NULL) {
+ filebench_log(LOG_ERROR, "Out of memory for variables");
+ return (NULL);
+ }
+
+ return (newvar);
+}
+
+/*
+ * Allocates a var (var_t) from interprocess shared memory.
+ * Places the allocated var on the end of the globally shared
+ * var_dyn_list. Finally, the routine allocates a string
+ * containing a copy of the supplied "name" string. If any
+ * allocations fails, returns NULL, otherwise it returns a
+ * pointer to the newly allocated var.
+ */
+static var_t *
+var_alloc_dynamic(char *name)
+{
+ var_t *var = NULL;
+ var_t *prev = NULL;
+ var_t *newvar;
+
+ if ((newvar = (var_t *)ipc_malloc(FILEBENCH_VARIABLE)) == NULL) {
+ filebench_log(LOG_ERROR, "Out of memory for variables");
+ return (NULL);
+ }
+ (void) memset(newvar, 0, sizeof (newvar));
+
+ for (var = filebench_shm->var_dyn_list; var != NULL;
+ var = var->var_next)
+ prev = var; /* Find end of list */
+ if (prev != NULL)
+ prev->var_next = newvar;
+ else
+ filebench_shm->var_dyn_list = newvar;
+
+ if ((newvar->var_name = ipc_stralloc(name)) == NULL) {
+ filebench_log(LOG_ERROR, "Out of memory for variables");
+ return (NULL);
+ }
+
+ return (newvar);
+}
+
+/*
+ * Searches for var_t with name "name" in the master var_list.
+ * If successful, returns a pointer to the var_t, otherwise
+ * returns NULL.
+ */
+static var_t *
+var_find(char *name)
+{
+ var_t *var;
+
+ for (var = filebench_shm->var_list; var != NULL; var = var->var_next) {
+ if (strcmp(var->var_name, name) == 0)
+ return (var);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Searches for the named var, and, if found, sets its
+ * var_integer's value to that of the supplied integer.
+ * If not found, the routine allocates a new var and sets
+ * its var_integers's value to that of the supplied
+ * integer. If the named var cannot be found or allocated
+ * the routine returns -1, otherwise it returns 0.
+ */
+int
+var_assign_integer(char *name, vinteger_t integer)
+{
+ var_t *var;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_alloc(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (-1);
+ }
+
+ var->var_integer = integer;
+
+ filebench_log(LOG_DEBUG_SCRIPT, "Assign integer %s=%lld",
+ name, integer);
+
+ return (0);
+}
+
+/*
+ * Searches for the named var, and if found returns a pointer
+ * to the var's var_integer. If not found, attempts to allocate
+ * a var named "name" and returns a pointer to it's (zeroed)
+ * var_integer. If the var cannot be found or allocated, an
+ * error is logged and the run is terminated.
+ */
+vinteger_t *
+var_ref_integer(char *name)
+{
+ var_t *var;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_find_dynamic(name);
+
+ if (var == NULL)
+ var = var_alloc(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Invalid variable $%s",
+ name);
+ filebench_shutdown(1);
+ }
+
+ return (&var->var_integer);
+
+}
+
+/*
+ * Searches for the named var, and if found copies the var_string,
+ * if it exists, or a decimal number string representation of
+ * var_integer, into a malloc'd bit of memory using fb_stralloc().
+ * Returns a pointer to the created string, or NULL on failure.
+ */
+char *
+var_to_string(char *name)
+{
+ var_t *var;
+ char tmp[128];
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_find_dynamic(name);
+
+ if (var == NULL)
+ return (NULL);
+
+ if (var->var_string)
+ return (fb_stralloc(var->var_string));
+
+ (void) snprintf(tmp, sizeof (tmp), "%lld", var->var_integer);
+
+ return (fb_stralloc(tmp));
+}
+
+/*
+ * Searches for the named var, and if found returns the value,
+ * of var_integer. If the var is not found, or the var_integer's
+ * value is 0, logs an error and returns 0.
+ */
+vinteger_t
+var_to_integer(char *name)
+{
+ var_t *var;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_find_dynamic(name);
+
+ if ((var != NULL) && (var->var_integer))
+ return (var->var_integer);
+
+ filebench_log(LOG_ERROR,
+ "Variable %s referenced before set", name);
+
+ return (0);
+}
+
+/*
+ * Searches for the var named "name", and if not found
+ * allocates it. The then extracts the var_string from
+ * the var named "string" and copies it into the var_string
+ * of the var "name", after first allocating a piece of
+ * interprocess shared string memory. If the var "name"
+ * cannot be found or allocated, or the var "string" cannot
+ * be found, the routine returns -1, otherwise it returns 0.
+ */
+int
+var_assign_var(char *name, char *string)
+{
+ var_t *var;
+ var_string_t str;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_alloc(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (-1);
+ }
+
+ if ((str = var_ref_string(string)) == NULL)
+ return (-1);
+
+ if ((var->var_string = ipc_stralloc(*str)) == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (-1);
+ }
+ filebench_log(LOG_VERBOSE, "Assign string %s=%s", name, string);
+ return (0);
+}
+
+/*
+ * Like var_assign_integer, only this routine copies the
+ * supplied "string" into the var named "name". If the var
+ * named "name" cannot be found then it is first allocated
+ * before the copy. Space for the string in the var comes
+ * from interprocess shared memory. If the var "name"
+ * cannot be found or allocated, or the memory for the
+ * var_string copy of "string" cannot be allocated, the
+ * routine returns -1, otherwise it returns 0.
+ */
+int
+var_assign_string(char *name, char *string)
+{
+ var_t *var;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_alloc(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (-1);
+ }
+
+ if ((var->var_string = ipc_stralloc(string)) == NULL) {
+ filebench_log(LOG_ERROR, "Cannot assign variable %s",
+ name);
+ return (-1);
+ }
+
+ filebench_log(LOG_DEBUG_SCRIPT, "Assign string %s=%s", name, string);
+
+ return (0);
+}
+
+/*
+ * Searches for the named var, and if found returns a pointer
+ * to the var's var_string. If not found, attempts to allocate
+ * a var named "name" and returns a pointer to it's (empty)
+ * var_string. If the var cannot be found or allocated, an
+ * error is logged and the run is terminated.
+ */
+char **
+var_ref_string(char *name)
+{
+ var_t *var;
+
+ name += 1;
+
+ if ((var = var_find(name)) == NULL)
+ var = var_find_dynamic(name);
+
+ if (var == NULL)
+ var = var_alloc(name);
+
+ if (var == NULL) {
+ filebench_log(LOG_ERROR, "Cannot reference variable %s",
+ name);
+ filebench_shutdown(1);
+ }
+
+ return (&var->var_string);
+}
+
+/*
+ * Implements a simple path name like scheme for finding values
+ * to place in certain specially named vars. The first part of
+ * the name is interpreted as a category of either: stats,
+ * eventgen, date, script, or host var. If a match is found,
+ * the appropriate routine is called to fill in the requested
+ * value in the provided var_t, and a pointer to the supplied
+ * var_t is returned. If the requested value is not found, NULL
+ * is returned.
+ */
+static var_t *
+var_find_internal(var_t *var)
+{
+ char *n = fb_stralloc(var->var_name);
+ char *name = n;
+ var_t *rtn = NULL;
+
+ name++;
+ if (name[strlen(name) - 1] != '}')
+ return (NULL);
+ name[strlen(name) - 1] = 0;
+
+ if (strncmp(name, STATS_VAR, strlen(STATS_VAR)) == 0)
+ rtn = stats_findvar(var, name + strlen(STATS_VAR));
+
+ if (strcmp(name, EVENTGEN_VAR) == 0)
+ rtn = eventgen_ratevar(var);
+
+ if (strcmp(name, DATE_VAR) == 0)
+ rtn = date_var(var);
+
+ if (strcmp(name, SCRIPT_VAR) == 0)
+ rtn = script_var(var);
+
+ if (strcmp(name, HOST_VAR) == 0)
+ rtn = host_var(var);
+
+ free(n);
+
+ return (rtn);
+}
+
+/*
+ * Calls the C library routine getenv() to obtain the value
+ * for the environment variable specified by var->var_name.
+ * If found, the value string is returned in var->var_string.
+ * If the requested value is not found, NULL is returned.
+ */
+static var_t *
+var_find_environment(var_t *var)
+{
+ char *n = fb_stralloc(var->var_name);
+ char *name = n;
+
+ name++;
+ if (name[strlen(name) - 1] != ')')
+ return (NULL);
+ name[strlen(name) - 1] = 0;
+
+ if ((var->var_string = getenv(name)) != NULL) {
+ free(n);
+ return (var);
+ } else {
+ free(n);
+ return (NULL);
+ }
+}
+
+/*
+ * Look up special variables. The "name" argument is used to find
+ * the desired special var and fill it with an appropriate string
+ * value. Looks for an already allocated var of the same name on
+ * the var_dyn_list. If not found a new dynamic var is allocated.
+ * if the name begins with '{', it is an internal variable, and
+ * var_find_internal() is called. If the name begins with '(' it
+ * is an environment varable, and var_find_environment() is
+ * called. On success, a pointer to the var_t is returned,
+ * otherwise, NULL is returned.
+ */
+static var_t *
+var_find_dynamic(char *name)
+{
+ var_t *var = NULL;
+ var_t *v = filebench_shm->var_dyn_list;
+ var_t *rtn;
+
+ /*
+ * Lookup a reference to the var handle for this
+ * special var
+ */
+ for (v = filebench_shm->var_dyn_list; v != NULL; v = v->var_next) {
+ if (strcmp(v->var_name, name) == 0) {
+ var = v;
+ break;
+ }
+ }
+
+ if (var == NULL)
+ var = var_alloc_dynamic(name);
+
+ /* Internal system control variable */
+ if (*name == '{') {
+ rtn = var_find_internal(var);
+ if (rtn == NULL)
+ filebench_log(LOG_ERROR,
+ "Cannot find internal variable %s",
+ var->var_name);
+ return (rtn);
+ }
+
+ /* Lookup variable in environment */
+ if (*name == '(') {
+ rtn = var_find_environment(var);
+ if (rtn == NULL)
+ filebench_log(LOG_ERROR,
+ "Cannot find environment variable %s",
+ var->var_name);
+ return (rtn);
+ }
+
+ return (NULL);
+}