mirror of
				https://git.proxmox.com/git/mirror_spl-debian
				synced 2025-10-31 23:31:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			837 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			837 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*****************************************************************************\
 | |
|  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
 | |
|  *  Copyright (C) 2007 The Regents of the University of California.
 | |
|  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 | |
|  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
 | |
|  *  UCRL-CODE-235197
 | |
|  *
 | |
|  *  This file is part of the SPL, Solaris Porting Layer.
 | |
|  *  For details, see <http://zfsonlinux.org/>.
 | |
|  *
 | |
|  *  The SPL is free software; you can redistribute it and/or modify it
 | |
|  *  under the terms of the GNU General Public License as published by the
 | |
|  *  Free Software Foundation; either version 2 of the License, or (at your
 | |
|  *  option) any later version.
 | |
|  *
 | |
|  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
 | |
|  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 | |
|  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 | |
|  *  for more details.
 | |
|  *
 | |
|  *  You should have received a copy of the GNU General Public License along
 | |
|  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  *****************************************************************************
 | |
|  *  Solaris Porting LAyer Tests (SPLAT) User Space Interface.
 | |
| \*****************************************************************************/
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stddef.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <errno.h>
 | |
| #include <getopt.h>
 | |
| #include <assert.h>
 | |
| #include <fcntl.h>
 | |
| #include <sys/ioctl.h>
 | |
| #include <sys/stat.h>
 | |
| #include <sys/types.h>
 | |
| #include <unistd.h>
 | |
| #include "splat.h"
 | |
| 
 | |
| #undef ioctl
 | |
| 
 | |
| static const char shortOpts[] = "hvlat:xc";
 | |
| static const struct option longOpts[] = {
 | |
| 	{ "help",            no_argument,       0, 'h' },
 | |
| 	{ "verbose",         no_argument,       0, 'v' },
 | |
| 	{ "list",            no_argument,       0, 'l' },
 | |
| 	{ "all",             no_argument,       0, 'a' },
 | |
| 	{ "test",            required_argument, 0, 't' },
 | |
| 	{ "exit",            no_argument,       0, 'x' },
 | |
| 	{ "nocolor",         no_argument,       0, 'c' },
 | |
| 	{ 0,                 0,                 0, 0   }
 | |
| };
 | |
| 
 | |
| #define VERSION_SIZE	64
 | |
| 
 | |
| static List subsystems;				/* Subsystem/tests */
 | |
| static int splatctl_fd;				/* Control file descriptor */
 | |
| static char splat_version[VERSION_SIZE];	/* Kernel version string */
 | |
| static char *splat_buffer = NULL;		/* Scratch space area */
 | |
| static int splat_buffer_size = 0;		/* Scratch space size */
 | |
| 
 | |
| 
 | |
| static void test_list(List, int);
 | |
| static int dev_clear(void);
 | |
| static void subsystem_fini(subsystem_t *);
 | |
| static void test_fini(test_t *);
 | |
| 
 | |
| 
 | |
| static int usage(void) {
 | |
| 	fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
 | |
| 	fprintf(stderr,
 | |
| 	"  --help      -h               This help\n"
 | |
| 	"  --verbose   -v               Increase verbosity\n"
 | |
| 	"  --list      -l               List all tests in all subsystems\n"
 | |
| 	"  --all       -a               Run all tests in all subsystems\n"
 | |
| 	"  --test      -t <sub:test>    Run 'test' in subsystem 'sub'\n"
 | |
| 	"  --exit      -x               Exit on first test error\n"
 | |
| 	"  --nocolor   -c               Do not colorize output\n");
 | |
| 	fprintf(stderr, "\n"
 | |
| 	"Examples:\n"
 | |
| 	"  splat -t kmem:all     # Runs all kmem tests\n"
 | |
| 	"  splat -t taskq:0x201  # Run taskq test 0x201\n");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static subsystem_t *subsystem_init(splat_user_t *desc)
 | |
| {
 | |
| 	subsystem_t *sub;
 | |
| 
 | |
| 	sub = (subsystem_t *)malloc(sizeof(*sub));
 | |
| 	if (sub == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| 	memcpy(&sub->sub_desc, desc, sizeof(*desc));
 | |
| 
 | |
| 	sub->sub_tests = list_create((ListDelF)test_fini);
 | |
| 	if (sub->sub_tests == NULL) {
 | |
| 		free(sub);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	return sub;
 | |
| }
 | |
| 
 | |
| static void subsystem_fini(subsystem_t *sub)
 | |
| {
 | |
| 	assert(sub != NULL);
 | |
| 	free(sub);
 | |
| }
 | |
| 
 | |
| static int subsystem_setup(void)
 | |
| {
 | |
| 	splat_cfg_t *cfg;
 | |
| 	int i, rc, size, cfg_size;
 | |
| 	subsystem_t *sub;
 | |
| 	splat_user_t *desc;
 | |
| 
 | |
| 	/* Aquire the number of registered subsystems */
 | |
| 	cfg_size = sizeof(*cfg);
 | |
| 	cfg = (splat_cfg_t *)malloc(cfg_size);
 | |
| 	if (cfg == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	memset(cfg, 0, cfg_size);
 | |
| 	cfg->cfg_magic = SPLAT_CFG_MAGIC;
 | |
|         cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_COUNT;
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
 | |
| 	if (rc) {
 | |
| 		fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
 | |
| 		        (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
 | |
| 		free(cfg);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	size = cfg->cfg_rc1;
 | |
| 	free(cfg);
 | |
| 
 | |
| 	/* Based on the newly acquired number of subsystems allocate
 | |
| 	 * memory to get the descriptive information for them all. */
 | |
| 	cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
 | |
| 	cfg = (splat_cfg_t *)malloc(cfg_size);
 | |
| 	if (cfg == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	memset(cfg, 0, cfg_size);
 | |
| 	cfg->cfg_magic = SPLAT_CFG_MAGIC;
 | |
| 	cfg->cfg_cmd   = SPLAT_CFG_SUBSYSTEM_LIST;
 | |
| 	cfg->cfg_data.splat_subsystems.size = size;
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
 | |
| 	if (rc) {
 | |
| 		fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
 | |
| 		        (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
 | |
| 		free(cfg);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	/* Add the new subsystems in to the global list */
 | |
| 	size = cfg->cfg_rc1;
 | |
| 	for (i = 0; i < size; i++) {
 | |
| 		desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
 | |
| 
 | |
| 		sub = subsystem_init(desc);
 | |
| 		if (sub == NULL) {
 | |
| 			fprintf(stderr, "Error initializing subsystem: %s\n",
 | |
| 			        desc->name);
 | |
| 			free(cfg);
 | |
| 			return -ENOMEM;
 | |
| 		}
 | |
| 
 | |
| 		list_append(subsystems, sub);
 | |
| 	}
 | |
| 
 | |
| 	free(cfg);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void subsystem_list(List l, int indent)
 | |
| {
 | |
| 	ListIterator i;
 | |
| 	subsystem_t *sub;
 | |
| 
 | |
| 	fprintf(stdout,
 | |
| 	        "------------------------------ "
 | |
| 	        "Available SPLAT Tests "
 | |
| 	        "------------------------------\n");
 | |
| 
 | |
| 	i = list_iterator_create(l);
 | |
| 
 | |
| 	while ((sub = list_next(i))) {
 | |
| 		fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
 | |
| 		        indent, "",
 | |
| 		        4, sub->sub_desc.id,
 | |
| 		        SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
 | |
| 		        sub->sub_desc.desc);
 | |
| 		test_list(sub->sub_tests, indent + 7);
 | |
| 	}
 | |
| 
 | |
| 	list_iterator_destroy(i);
 | |
| }
 | |
| 
 | |
| static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
 | |
| {
 | |
| 	test_t *test;
 | |
| 
 | |
| 	test = (test_t *)malloc(sizeof(*test));
 | |
| 	if (test == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| 	test->test_sub = sub;
 | |
| 	memcpy(&test->test_desc, desc, sizeof(*desc));
 | |
| 
 | |
| 	return test;
 | |
| }
 | |
| 
 | |
| static void test_fini(test_t *test)
 | |
| {
 | |
| 	assert(test != NULL);
 | |
| 	free(test);
 | |
| }
 | |
| 
 | |
| static int test_setup(subsystem_t *sub)
 | |
| {
 | |
| 	splat_cfg_t *cfg;
 | |
| 	int i, rc, size;
 | |
| 	test_t *test;
 | |
| 	splat_user_t *desc;
 | |
| 
 | |
| 	/* Aquire the number of registered tests for the give subsystem */
 | |
| 	cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
 | |
| 	if (cfg == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	memset(cfg, 0, sizeof(*cfg));
 | |
| 	cfg->cfg_magic = SPLAT_CFG_MAGIC;
 | |
|         cfg->cfg_cmd   = SPLAT_CFG_TEST_COUNT;
 | |
| 	cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
 | |
| 	if (rc) {
 | |
| 		fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
 | |
| 		        (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
 | |
| 		free(cfg);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	size = cfg->cfg_rc1;
 | |
| 	free(cfg);
 | |
| 
 | |
| 	/* Based on the newly aquired number of tests allocate enough
 | |
| 	 * memory to get the descriptive information for them all. */
 | |
| 	cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
 | |
| 	if (cfg == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t));
 | |
| 	cfg->cfg_magic = SPLAT_CFG_MAGIC;
 | |
| 	cfg->cfg_cmd   = SPLAT_CFG_TEST_LIST;
 | |
| 	cfg->cfg_arg1  = sub->sub_desc.id; /* Subsystem of interest */
 | |
| 	cfg->cfg_data.splat_tests.size = size;
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
 | |
| 	if (rc) {
 | |
| 		fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
 | |
| 		        (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
 | |
| 		free(cfg);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	/* Add the new tests in to the relevant subsystems */
 | |
| 	size = cfg->cfg_rc1;
 | |
| 	for (i = 0; i < size; i++) {
 | |
| 		desc = &(cfg->cfg_data.splat_tests.descs[i]);
 | |
| 
 | |
| 		test = test_init(sub, desc);
 | |
| 		if (test == NULL) {
 | |
| 			fprintf(stderr, "Error initializing test: %s\n",
 | |
| 			        desc->name);
 | |
| 			free(cfg);
 | |
| 			return -ENOMEM;
 | |
| 		}
 | |
| 
 | |
| 		list_append(sub->sub_tests, test);
 | |
| 	}
 | |
| 
 | |
| 	free(cfg);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static test_t *test_copy(test_t *test)
 | |
| {
 | |
| 	return test_init(test->test_sub, &test->test_desc);
 | |
| }
 | |
| 
 | |
| static void test_list(List l, int indent)
 | |
| {
 | |
| 	ListIterator i;
 | |
| 	test_t *test;
 | |
| 
 | |
| 	i = list_iterator_create(l);
 | |
| 
 | |
| 	while ((test = list_next(i)))
 | |
| 		fprintf(stdout, "%*s0x%0*x %-*s %s\n",
 | |
| 		        indent, "", 04, test->test_desc.id,
 | |
| 		        SPLAT_NAME_SIZE, test->test_desc.name,
 | |
| 		        test->test_desc.desc);
 | |
| 
 | |
| 	list_iterator_destroy(i);
 | |
| }
 | |
| 
 | |
| static test_t *test_find(char *sub_str, char *test_str)
 | |
| {
 | |
| 	ListIterator si, ti;
 | |
| 	subsystem_t *sub;
 | |
| 	test_t *test;
 | |
| 	__u32 sub_num, test_num;
 | |
| 
 | |
| 	/*
 | |
| 	 * No error checking here because it may not be a number, it's
 | |
| 	 * perfectly OK for it to be a string.  Since we're just using
 | |
| 	 * it for comparison purposes this is all very safe.
 | |
| 	 */
 | |
| 	sub_num = strtoul(sub_str, NULL, 0);
 | |
| 	test_num = strtoul(test_str, NULL, 0);
 | |
| 
 | |
|         si = list_iterator_create(subsystems);
 | |
| 
 | |
|         while ((sub = list_next(si))) {
 | |
| 
 | |
| 		if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
 | |
| 		    sub->sub_desc.id != sub_num)
 | |
| 			continue;
 | |
| 
 | |
| 		ti = list_iterator_create(sub->sub_tests);
 | |
| 
 | |
| 		while ((test = list_next(ti))) {
 | |
| 
 | |
| 			if (!strncmp(test->test_desc.name, test_str,
 | |
| 		            SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
 | |
| 				list_iterator_destroy(ti);
 | |
| 			        list_iterator_destroy(si);
 | |
| 				return test;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	        list_iterator_destroy(ti);
 | |
|         }
 | |
| 
 | |
|         list_iterator_destroy(si);
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| static int test_add(cmd_args_t *args, test_t *test)
 | |
| {
 | |
| 	test_t *tmp;
 | |
| 
 | |
| 	tmp = test_copy(test);
 | |
| 	if (tmp == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	list_append(args->args_tests, tmp);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int test_add_all(cmd_args_t *args)
 | |
| {
 | |
| 	ListIterator si, ti;
 | |
| 	subsystem_t *sub;
 | |
| 	test_t *test;
 | |
| 	int rc;
 | |
| 
 | |
|         si = list_iterator_create(subsystems);
 | |
| 
 | |
|         while ((sub = list_next(si))) {
 | |
| 		ti = list_iterator_create(sub->sub_tests);
 | |
| 
 | |
| 		while ((test = list_next(ti))) {
 | |
| 			if ((rc = test_add(args, test))) {
 | |
| 			        list_iterator_destroy(ti);
 | |
| 			        list_iterator_destroy(si);
 | |
| 				return rc;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 	        list_iterator_destroy(ti);
 | |
|         }
 | |
| 
 | |
|         list_iterator_destroy(si);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int test_run(cmd_args_t *args, test_t *test)
 | |
| {
 | |
| 	subsystem_t *sub = test->test_sub;
 | |
| 	splat_cmd_t *cmd;
 | |
| 	int rc, cmd_size;
 | |
| 
 | |
| 	dev_clear();
 | |
| 
 | |
| 	cmd_size = sizeof(*cmd);
 | |
| 	cmd = (splat_cmd_t *)malloc(cmd_size);
 | |
| 	if (cmd == NULL)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	memset(cmd, 0, cmd_size);
 | |
| 	cmd->cmd_magic = SPLAT_CMD_MAGIC;
 | |
|         cmd->cmd_subsystem = sub->sub_desc.id;
 | |
| 	cmd->cmd_test = test->test_desc.id;
 | |
| 	cmd->cmd_data_size = 0; /* Unused feature */
 | |
| 
 | |
| 	fprintf(stdout, "%*s:%-*s ",
 | |
| 	        SPLAT_NAME_SIZE, sub->sub_desc.name,
 | |
| 	        SPLAT_NAME_SIZE, test->test_desc.name);
 | |
| 	fflush(stdout);
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
 | |
| 	if (args->args_do_color) {
 | |
| 		fprintf(stdout, "%s  %s\n", rc ?
 | |
| 		        COLOR_RED "Fail" COLOR_RESET :
 | |
| 		        COLOR_GREEN "Pass" COLOR_RESET,
 | |
| 			rc ? strerror(errno) : "");
 | |
| 	} else {
 | |
| 		fprintf(stdout, "%s  %s\n", rc ?
 | |
| 		        "Fail" : "Pass",
 | |
| 			rc ? strerror(errno) : "");
 | |
| 	}
 | |
| 	fflush(stdout);
 | |
| 	free(cmd);
 | |
| 
 | |
| 	if ((args->args_verbose == 1 && rc) ||
 | |
| 	    (args->args_verbose >= 2)) {
 | |
| 		if ((rc = read(splatctl_fd, splat_buffer,
 | |
| 			       splat_buffer_size - 1)) < 0) {
 | |
| 			fprintf(stdout, "Error reading results: %d\n", rc);
 | |
| 		} else {
 | |
| 			fprintf(stdout, "\n%s\n", splat_buffer);
 | |
| 			fflush(stdout);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int tests_run(cmd_args_t *args)
 | |
| {
 | |
|         ListIterator i;
 | |
| 	test_t *test;
 | |
| 	int rc;
 | |
| 
 | |
| 	fprintf(stdout,
 | |
| 	        "------------------------------ "
 | |
| 	        "Running SPLAT Tests "
 | |
| 	        "------------------------------\n");
 | |
| 
 | |
| 	i = list_iterator_create(args->args_tests);
 | |
| 
 | |
| 	while ((test = list_next(i))) {
 | |
| 		rc = test_run(args, test);
 | |
| 		if (rc && args->args_exit_on_error) {
 | |
| 			list_iterator_destroy(i);
 | |
| 			return rc;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	list_iterator_destroy(i);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int args_parse_test(cmd_args_t *args, char *str)
 | |
| {
 | |
|         ListIterator si, ti;
 | |
| 	subsystem_t *s;
 | |
| 	test_t *t;
 | |
| 	char *sub_str, *test_str;
 | |
| 	int sub_num, test_num;
 | |
| 	int sub_all = 0, test_all = 0;
 | |
| 	int rc, flag = 0;
 | |
| 
 | |
| 	test_str = strchr(str, ':');
 | |
| 	if (test_str == NULL) {
 | |
| 		fprintf(stderr, "Test must be of the "
 | |
| 		        "form <subsystem:test>\n");
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	sub_str = str;
 | |
| 	test_str[0] = '\0';
 | |
| 	test_str = test_str + 1;
 | |
| 
 | |
| 	sub_num = strtol(sub_str, NULL, 0);
 | |
| 	test_num = strtol(test_str, NULL, 0);
 | |
| 
 | |
| 	if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
 | |
| 		sub_all = 1;
 | |
| 
 | |
| 	if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
 | |
| 		test_all = 1;
 | |
| 
 | |
| 	si = list_iterator_create(subsystems);
 | |
| 
 | |
| 	if (sub_all) {
 | |
| 		if (test_all) {
 | |
| 			/* Add all tests from all subsystems */
 | |
| 			while ((s = list_next(si))) {
 | |
| 				ti = list_iterator_create(s->sub_tests);
 | |
| 				while ((t = list_next(ti))) {
 | |
| 					if ((rc = test_add(args, t))) {
 | |
| 						list_iterator_destroy(ti);
 | |
| 						goto error_run;
 | |
| 					}
 | |
| 				}
 | |
| 				list_iterator_destroy(ti);
 | |
| 			}
 | |
| 		} else {
 | |
| 			/* Add a specific test from all subsystems */
 | |
| 			while ((s = list_next(si))) {
 | |
| 				if ((t=test_find(s->sub_desc.name,test_str))) {
 | |
| 					if ((rc = test_add(args, t)))
 | |
| 						goto error_run;
 | |
| 
 | |
| 					flag = 1;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (!flag)
 | |
| 				fprintf(stderr, "No tests '%s:%s' could be "
 | |
| 				        "found\n", sub_str, test_str);
 | |
| 		}
 | |
| 	} else {
 | |
| 		if (test_all) {
 | |
| 			/* Add all tests from a specific subsystem */
 | |
| 			while ((s = list_next(si))) {
 | |
| 				if (strncasecmp(sub_str, s->sub_desc.name,
 | |
| 				    strlen(sub_str)))
 | |
| 					continue;
 | |
| 
 | |
| 				ti = list_iterator_create(s->sub_tests);
 | |
| 				while ((t = list_next(ti))) {
 | |
| 					if ((rc = test_add(args, t))) {
 | |
| 						list_iterator_destroy(ti);
 | |
| 						goto error_run;
 | |
| 					}
 | |
| 				}
 | |
| 				list_iterator_destroy(ti);
 | |
| 			}
 | |
| 		} else {
 | |
| 			/* Add a specific test from a specific subsystem */
 | |
| 			if ((t = test_find(sub_str, test_str))) {
 | |
| 				if ((rc = test_add(args, t)))
 | |
| 					goto error_run;
 | |
| 			} else {
 | |
| 				fprintf(stderr, "Test '%s:%s' could not be "
 | |
| 				        "found\n", sub_str, test_str);
 | |
| 				return -EINVAL;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	list_iterator_destroy(si);
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| error_run:
 | |
| 	list_iterator_destroy(si);
 | |
| 
 | |
| 	fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
 | |
| 	        sub_str, test_str, rc);
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static void args_fini(cmd_args_t *args)
 | |
| {
 | |
| 	assert(args != NULL);
 | |
| 
 | |
| 	if (args->args_tests != NULL)
 | |
| 		list_destroy(args->args_tests);
 | |
| 
 | |
| 	free(args);
 | |
| }
 | |
| 
 | |
| static cmd_args_t *
 | |
| args_init(int argc, char **argv)
 | |
| {
 | |
| 	cmd_args_t *args;
 | |
| 	int c, rc;
 | |
| 
 | |
| 	if (argc == 1) {
 | |
| 		usage();
 | |
| 		return (cmd_args_t *) NULL;
 | |
| 	}
 | |
| 
 | |
| 	/* Configure and populate the args structures */
 | |
| 	args = malloc(sizeof(*args));
 | |
| 	if (args == NULL)
 | |
| 		return NULL;
 | |
| 
 | |
| 	memset(args, 0, sizeof(*args));
 | |
| 	args->args_verbose = 0;
 | |
| 	args->args_do_list = 0;
 | |
| 	args->args_do_all  = 0;
 | |
| 	args->args_do_color = 1;
 | |
| 	args->args_exit_on_error = 0;
 | |
| 	args->args_tests = list_create((ListDelF)test_fini);
 | |
| 	if (args->args_tests == NULL) {
 | |
| 		args_fini(args);
 | |
| 		return NULL;
 | |
| 	}
 | |
| 
 | |
| 	while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
 | |
| 		switch (c) {
 | |
| 		case 'v':  args->args_verbose++;			break;
 | |
| 		case 'l':  args->args_do_list = 1;			break;
 | |
| 		case 'a':  args->args_do_all = 1;			break;
 | |
| 		case 'c':  args->args_do_color = 0;			break;
 | |
| 		case 'x':  args->args_exit_on_error = 1;		break;
 | |
| 		case 't':
 | |
| 			if (args->args_do_all) {
 | |
| 				fprintf(stderr, "Option -t <subsystem:test> is "
 | |
| 				        "useless when used with -a\n");
 | |
| 				args_fini(args);
 | |
| 				return NULL;
 | |
| 			}
 | |
| 
 | |
| 			rc = args_parse_test(args, argv[optind - 1]);
 | |
| 			if (rc) {
 | |
| 				args_fini(args);
 | |
| 				return NULL;
 | |
| 			}
 | |
| 			break;
 | |
| 		case 'h':
 | |
| 		case '?':
 | |
| 			usage();
 | |
| 			args_fini(args);
 | |
| 			return NULL;
 | |
| 		default:
 | |
| 			fprintf(stderr, "Unknown option '%s'\n",
 | |
| 			        argv[optind - 1]);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return args;
 | |
| }
 | |
| 
 | |
| static int
 | |
| dev_clear(void)
 | |
| {
 | |
| 	splat_cfg_t cfg;
 | |
| 	int rc;
 | |
| 
 | |
| 	memset(&cfg, 0, sizeof(cfg));
 | |
| 	cfg.cfg_magic = SPLAT_CFG_MAGIC;
 | |
|         cfg.cfg_cmd   = SPLAT_CFG_BUFFER_CLEAR;
 | |
| 	cfg.cfg_arg1  = 0;
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
 | |
| 	if (rc)
 | |
| 		fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
 | |
| 		        (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
 | |
| 
 | |
| 	lseek(splatctl_fd, 0, SEEK_SET);
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static int
 | |
| dev_size(int size)
 | |
| {
 | |
| 	splat_cfg_t cfg;
 | |
| 	int rc;
 | |
| 
 | |
| 	memset(&cfg, 0, sizeof(cfg));
 | |
| 	cfg.cfg_magic = SPLAT_CFG_MAGIC;
 | |
|         cfg.cfg_cmd   = SPLAT_CFG_BUFFER_SIZE;
 | |
| 	cfg.cfg_arg1  = size;
 | |
| 
 | |
| 	rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
 | |
| 	if (rc) {
 | |
| 		fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
 | |
| 		        (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	return cfg.cfg_rc1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| dev_fini(void)
 | |
| {
 | |
| 	if (splat_buffer)
 | |
| 		free(splat_buffer);
 | |
| 
 | |
| 	if (splatctl_fd != -1) {
 | |
| 		if (close(splatctl_fd) == -1) {
 | |
| 			fprintf(stderr, "Unable to close %s: %d\n",
 | |
| 		                SPLAT_DEV, errno);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int
 | |
| dev_init(void)
 | |
| {
 | |
| 	ListIterator i;
 | |
| 	subsystem_t *sub;
 | |
| 	int rc;
 | |
| 
 | |
| 	splatctl_fd = open(SPLAT_DEV, O_RDONLY);
 | |
| 	if (splatctl_fd == -1) {
 | |
| 		fprintf(stderr, "Unable to open %s: %d\n"
 | |
| 		        "Is the splat module loaded?\n", SPLAT_DEV, errno);
 | |
| 		rc = errno;
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	/* Determine kernel module version string */
 | |
| 	memset(splat_version, 0, VERSION_SIZE);
 | |
| 	if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
 | |
| 		goto error;
 | |
| 
 | |
| 	if ((rc = dev_clear()))
 | |
| 		goto error;
 | |
| 
 | |
| 	if ((rc = dev_size(0)) < 0)
 | |
| 		goto error;
 | |
| 
 | |
| 	splat_buffer_size = rc;
 | |
| 	splat_buffer = (char *)malloc(splat_buffer_size);
 | |
| 	if (splat_buffer == NULL) {
 | |
| 		rc = -ENOMEM;
 | |
| 		goto error;
 | |
| 	}
 | |
| 
 | |
| 	memset(splat_buffer, 0, splat_buffer_size);
 | |
| 
 | |
| 	/* Determine available subsystems */
 | |
| 	if ((rc = subsystem_setup()) != 0)
 | |
| 		goto error;
 | |
| 
 | |
| 	/* Determine available tests for all subsystems */
 | |
| 	i = list_iterator_create(subsystems);
 | |
| 
 | |
| 	while ((sub = list_next(i))) {
 | |
| 		if ((rc = test_setup(sub)) != 0) {
 | |
| 			list_iterator_destroy(i);
 | |
| 			goto error;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	list_iterator_destroy(i);
 | |
| 	return 0;
 | |
| 
 | |
| error:
 | |
| 	if (splatctl_fd != -1) {
 | |
| 		if (close(splatctl_fd) == -1) {
 | |
| 			fprintf(stderr, "Unable to close %s: %d\n",
 | |
| 		                SPLAT_DEV, errno);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| int
 | |
| init(void)
 | |
| {
 | |
| 	int rc = 0;
 | |
| 
 | |
| 	/* Allocate the subsystem list */
 | |
| 	subsystems = list_create((ListDelF)subsystem_fini);
 | |
| 	if (subsystems == NULL)
 | |
| 		rc = ENOMEM;
 | |
| 
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| void
 | |
| fini(void)
 | |
| {
 | |
| 	list_destroy(subsystems);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| main(int argc, char **argv)
 | |
| {
 | |
| 	cmd_args_t *args = NULL;
 | |
| 	int rc = 0;
 | |
| 
 | |
| 	/* General init */
 | |
| 	if ((rc = init()))
 | |
| 		return rc;
 | |
| 
 | |
| 	/* Device specific init */
 | |
| 	if ((rc = dev_init()))
 | |
| 		goto out;
 | |
| 
 | |
| 	/* Argument init and parsing */
 | |
| 	if ((args = args_init(argc, argv)) == NULL) {
 | |
| 		rc = -1;
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Generic kernel version string */
 | |
| 	if (args->args_verbose)
 | |
| 		fprintf(stdout, "%s", splat_version);
 | |
| 
 | |
| 	/* Print the available test list and exit */
 | |
| 	if (args->args_do_list) {
 | |
| 		subsystem_list(subsystems, 0);
 | |
| 		goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Add all available test to the list of tests to run */
 | |
| 	if (args->args_do_all) {
 | |
| 		if ((rc = test_add_all(args)))
 | |
| 			goto out;
 | |
| 	}
 | |
| 
 | |
| 	/* Run all the requested tests */
 | |
| 	if ((rc = tests_run(args)))
 | |
| 		goto out;
 | |
| 
 | |
| out:
 | |
| 	if (args != NULL)
 | |
| 		args_fini(args);
 | |
| 
 | |
| 	dev_fini();
 | |
| 	fini();
 | |
| 	return rc;
 | |
| }
 | 
