]>
Commit | Line | Data |
---|---|---|
716154c5 BB |
1 | /*****************************************************************************\ |
2 | * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC. | |
3 | * Copyright (C) 2007 The Regents of the University of California. | |
4 | * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | |
5 | * Written by Brian Behlendorf <behlendorf1@llnl.gov>. | |
715f6251 | 6 | * UCRL-CODE-235197 |
7 | * | |
716154c5 | 8 | * This file is part of the SPL, Solaris Porting Layer. |
3d6af2dd | 9 | * For details, see <http://zfsonlinux.org/>. |
716154c5 BB |
10 | * |
11 | * The SPL is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2 of the License, or (at your | |
14 | * option) any later version. | |
715f6251 | 15 | * |
716154c5 | 16 | * The SPL is distributed in the hope that it will be useful, but WITHOUT |
715f6251 | 17 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
18 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
19 | * for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License along | |
716154c5 BB |
22 | * with the SPL. If not, see <http://www.gnu.org/licenses/>. |
23 | ***************************************************************************** | |
24 | * Solaris Porting LAyer Tests (SPLAT) User Space Interface. | |
25 | \*****************************************************************************/ | |
f1ca4da6 | 26 | |
27 | #include <stdlib.h> | |
28 | #include <stddef.h> | |
29 | #include <stdio.h> | |
30 | #include <string.h> | |
31 | #include <errno.h> | |
32 | #include <getopt.h> | |
33 | #include <assert.h> | |
34 | #include <fcntl.h> | |
f1ca4da6 | 35 | #include <sys/ioctl.h> |
36 | #include <sys/stat.h> | |
37 | #include <sys/types.h> | |
38 | #include <unistd.h> | |
39 | #include "splat.h" | |
40 | ||
41 | #undef ioctl | |
42 | ||
43 | static const char shortOpts[] = "hvlat:xc"; | |
44 | static const struct option longOpts[] = { | |
45 | { "help", no_argument, 0, 'h' }, | |
46 | { "verbose", no_argument, 0, 'v' }, | |
47 | { "list", no_argument, 0, 'l' }, | |
48 | { "all", no_argument, 0, 'a' }, | |
49 | { "test", required_argument, 0, 't' }, | |
50 | { "exit", no_argument, 0, 'x' }, | |
51 | { "nocolor", no_argument, 0, 'c' }, | |
52 | { 0, 0, 0, 0 } | |
53 | }; | |
54 | ||
7c50328b | 55 | #define VERSION_SIZE 64 |
56 | ||
564f6d15 | 57 | static List subsystems; /* Subsystem/tests */ |
7c50328b | 58 | static int splatctl_fd; /* Control file descriptor */ |
59 | static char splat_version[VERSION_SIZE]; /* Kernel version string */ | |
60 | static char *splat_buffer = NULL; /* Scratch space area */ | |
61 | static int splat_buffer_size = 0; /* Scratch space size */ | |
f1ca4da6 | 62 | |
63 | ||
564f6d15 | 64 | static void test_list(List, int); |
f1ca4da6 | 65 | static int dev_clear(void); |
564f6d15 | 66 | static void subsystem_fini(subsystem_t *); |
67 | static void test_fini(test_t *); | |
f1ca4da6 | 68 | |
69 | ||
70 | static int usage(void) { | |
7c50328b | 71 | fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n"); |
f1ca4da6 | 72 | fprintf(stderr, |
73 | " --help -h This help\n" | |
74 | " --verbose -v Increase verbosity\n" | |
75 | " --list -l List all tests in all subsystems\n" | |
76 | " --all -a Run all tests in all subsystems\n" | |
77 | " --test -t <sub:test> Run 'test' in subsystem 'sub'\n" | |
78 | " --exit -x Exit on first test error\n" | |
79 | " --nocolor -c Do not colorize output\n"); | |
80 | fprintf(stderr, "\n" | |
81 | "Examples:\n" | |
7c50328b | 82 | " splat -t kmem:all # Runs all kmem tests\n" |
83 | " splat -t taskq:0x201 # Run taskq test 0x201\n"); | |
f1ca4da6 | 84 | |
85 | return 0; | |
86 | } | |
87 | ||
7c50328b | 88 | static subsystem_t *subsystem_init(splat_user_t *desc) |
f1ca4da6 | 89 | { |
90 | subsystem_t *sub; | |
91 | ||
92 | sub = (subsystem_t *)malloc(sizeof(*sub)); | |
93 | if (sub == NULL) | |
94 | return NULL; | |
95 | ||
96 | memcpy(&sub->sub_desc, desc, sizeof(*desc)); | |
f1ca4da6 | 97 | |
564f6d15 | 98 | sub->sub_tests = list_create((ListDelF)test_fini); |
f1ca4da6 | 99 | if (sub->sub_tests == NULL) { |
100 | free(sub); | |
101 | return NULL; | |
102 | } | |
103 | ||
104 | return sub; | |
105 | } | |
106 | ||
107 | static void subsystem_fini(subsystem_t *sub) | |
108 | { | |
109 | assert(sub != NULL); | |
f1ca4da6 | 110 | free(sub); |
111 | } | |
112 | ||
113 | static int subsystem_setup(void) | |
114 | { | |
7c50328b | 115 | splat_cfg_t *cfg; |
f1ca4da6 | 116 | int i, rc, size, cfg_size; |
117 | subsystem_t *sub; | |
7c50328b | 118 | splat_user_t *desc; |
f1ca4da6 | 119 | |
120 | /* Aquire the number of registered subsystems */ | |
121 | cfg_size = sizeof(*cfg); | |
7c50328b | 122 | cfg = (splat_cfg_t *)malloc(cfg_size); |
f1ca4da6 | 123 | if (cfg == NULL) |
124 | return -ENOMEM; | |
125 | ||
126 | memset(cfg, 0, cfg_size); | |
7c50328b | 127 | cfg->cfg_magic = SPLAT_CFG_MAGIC; |
128 | cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_COUNT; | |
f1ca4da6 | 129 | |
7c50328b | 130 | rc = ioctl(splatctl_fd, SPLAT_CFG, cfg); |
f1ca4da6 | 131 | if (rc) { |
e554dffa BB |
132 | fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n", |
133 | (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno); | |
f1ca4da6 | 134 | free(cfg); |
135 | return rc; | |
136 | } | |
137 | ||
138 | size = cfg->cfg_rc1; | |
139 | free(cfg); | |
140 | ||
e554dffa | 141 | /* Based on the newly acquired number of subsystems allocate |
f1ca4da6 | 142 | * memory to get the descriptive information for them all. */ |
7c50328b | 143 | cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t); |
144 | cfg = (splat_cfg_t *)malloc(cfg_size); | |
f1ca4da6 | 145 | if (cfg == NULL) |
146 | return -ENOMEM; | |
147 | ||
148 | memset(cfg, 0, cfg_size); | |
7c50328b | 149 | cfg->cfg_magic = SPLAT_CFG_MAGIC; |
150 | cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_LIST; | |
151 | cfg->cfg_data.splat_subsystems.size = size; | |
f1ca4da6 | 152 | |
7c50328b | 153 | rc = ioctl(splatctl_fd, SPLAT_CFG, cfg); |
f1ca4da6 | 154 | if (rc) { |
155 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
7c50328b | 156 | (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno); |
f1ca4da6 | 157 | free(cfg); |
158 | return rc; | |
159 | } | |
160 | ||
161 | /* Add the new subsystems in to the global list */ | |
162 | size = cfg->cfg_rc1; | |
163 | for (i = 0; i < size; i++) { | |
7c50328b | 164 | desc = &(cfg->cfg_data.splat_subsystems.descs[i]); |
f1ca4da6 | 165 | |
166 | sub = subsystem_init(desc); | |
167 | if (sub == NULL) { | |
168 | fprintf(stderr, "Error initializing subsystem: %s\n", | |
169 | desc->name); | |
170 | free(cfg); | |
171 | return -ENOMEM; | |
172 | } | |
173 | ||
564f6d15 | 174 | list_append(subsystems, sub); |
f1ca4da6 | 175 | } |
176 | ||
177 | free(cfg); | |
178 | return 0; | |
179 | } | |
180 | ||
564f6d15 | 181 | static void subsystem_list(List l, int indent) |
f1ca4da6 | 182 | { |
564f6d15 | 183 | ListIterator i; |
f1ca4da6 | 184 | subsystem_t *sub; |
185 | ||
186 | fprintf(stdout, | |
7c50328b | 187 | "------------------------------ " |
188 | "Available SPLAT Tests " | |
189 | "------------------------------\n"); | |
f1ca4da6 | 190 | |
564f6d15 | 191 | i = list_iterator_create(l); |
192 | ||
193 | while ((sub = list_next(i))) { | |
f1ca4da6 | 194 | fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n", |
195 | indent, "", | |
196 | 4, sub->sub_desc.id, | |
7c50328b | 197 | SPLAT_NAME_SIZE + 7, sub->sub_desc.name, |
f1ca4da6 | 198 | sub->sub_desc.desc); |
199 | test_list(sub->sub_tests, indent + 7); | |
200 | } | |
564f6d15 | 201 | |
202 | list_iterator_destroy(i); | |
f1ca4da6 | 203 | } |
204 | ||
7c50328b | 205 | static test_t *test_init(subsystem_t *sub, splat_user_t *desc) |
f1ca4da6 | 206 | { |
207 | test_t *test; | |
208 | ||
209 | test = (test_t *)malloc(sizeof(*test)); | |
210 | if (test == NULL) | |
211 | return NULL; | |
212 | ||
213 | test->test_sub = sub; | |
214 | memcpy(&test->test_desc, desc, sizeof(*desc)); | |
f1ca4da6 | 215 | |
216 | return test; | |
217 | } | |
218 | ||
219 | static void test_fini(test_t *test) | |
220 | { | |
221 | assert(test != NULL); | |
f1ca4da6 | 222 | free(test); |
223 | } | |
224 | ||
225 | static int test_setup(subsystem_t *sub) | |
226 | { | |
7c50328b | 227 | splat_cfg_t *cfg; |
f1ca4da6 | 228 | int i, rc, size; |
229 | test_t *test; | |
7c50328b | 230 | splat_user_t *desc; |
f1ca4da6 | 231 | |
232 | /* Aquire the number of registered tests for the give subsystem */ | |
7c50328b | 233 | cfg = (splat_cfg_t *)malloc(sizeof(*cfg)); |
f1ca4da6 | 234 | if (cfg == NULL) |
235 | return -ENOMEM; | |
236 | ||
237 | memset(cfg, 0, sizeof(*cfg)); | |
7c50328b | 238 | cfg->cfg_magic = SPLAT_CFG_MAGIC; |
239 | cfg->cfg_cmd = SPLAT_CFG_TEST_COUNT; | |
f1ca4da6 | 240 | cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */ |
241 | ||
7c50328b | 242 | rc = ioctl(splatctl_fd, SPLAT_CFG, cfg); |
f1ca4da6 | 243 | if (rc) { |
244 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
7c50328b | 245 | (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno); |
f1ca4da6 | 246 | free(cfg); |
247 | return rc; | |
248 | } | |
249 | ||
250 | size = cfg->cfg_rc1; | |
251 | free(cfg); | |
252 | ||
253 | /* Based on the newly aquired number of tests allocate enough | |
254 | * memory to get the descriptive information for them all. */ | |
e554dffa | 255 | cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t)); |
f1ca4da6 | 256 | if (cfg == NULL) |
257 | return -ENOMEM; | |
258 | ||
7c50328b | 259 | memset(cfg, 0, sizeof(*cfg) + size * sizeof(splat_user_t)); |
260 | cfg->cfg_magic = SPLAT_CFG_MAGIC; | |
261 | cfg->cfg_cmd = SPLAT_CFG_TEST_LIST; | |
f1ca4da6 | 262 | cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */ |
7c50328b | 263 | cfg->cfg_data.splat_tests.size = size; |
f1ca4da6 | 264 | |
7c50328b | 265 | rc = ioctl(splatctl_fd, SPLAT_CFG, cfg); |
f1ca4da6 | 266 | if (rc) { |
267 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
7c50328b | 268 | (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno); |
f1ca4da6 | 269 | free(cfg); |
270 | return rc; | |
271 | } | |
272 | ||
273 | /* Add the new tests in to the relevant subsystems */ | |
274 | size = cfg->cfg_rc1; | |
275 | for (i = 0; i < size; i++) { | |
7c50328b | 276 | desc = &(cfg->cfg_data.splat_tests.descs[i]); |
f1ca4da6 | 277 | |
278 | test = test_init(sub, desc); | |
279 | if (test == NULL) { | |
280 | fprintf(stderr, "Error initializing test: %s\n", | |
281 | desc->name); | |
282 | free(cfg); | |
283 | return -ENOMEM; | |
284 | } | |
285 | ||
564f6d15 | 286 | list_append(sub->sub_tests, test); |
f1ca4da6 | 287 | } |
288 | ||
289 | free(cfg); | |
290 | return 0; | |
291 | } | |
292 | ||
f1ca4da6 | 293 | static test_t *test_copy(test_t *test) |
294 | { | |
295 | return test_init(test->test_sub, &test->test_desc); | |
296 | } | |
297 | ||
564f6d15 | 298 | static void test_list(List l, int indent) |
f1ca4da6 | 299 | { |
564f6d15 | 300 | ListIterator i; |
f1ca4da6 | 301 | test_t *test; |
302 | ||
564f6d15 | 303 | i = list_iterator_create(l); |
304 | ||
305 | while ((test = list_next(i))) | |
c388a3ab BB |
306 | fprintf(stdout, "%*s0x%0*x %-*s %s\n", |
307 | indent, "", 04, test->test_desc.id, | |
7c50328b | 308 | SPLAT_NAME_SIZE, test->test_desc.name, |
c388a3ab | 309 | test->test_desc.desc); |
564f6d15 | 310 | |
311 | list_iterator_destroy(i); | |
f1ca4da6 | 312 | } |
313 | ||
314 | static test_t *test_find(char *sub_str, char *test_str) | |
315 | { | |
564f6d15 | 316 | ListIterator si, ti; |
f1ca4da6 | 317 | subsystem_t *sub; |
318 | test_t *test; | |
849c50e7 | 319 | __u32 sub_num, test_num; |
f1ca4da6 | 320 | |
849c50e7 BB |
321 | /* |
322 | * No error checking here because it may not be a number, it's | |
f1ca4da6 | 323 | * perfectly OK for it to be a string. Since we're just using |
324 | * it for comparison purposes this is all very safe. | |
325 | */ | |
849c50e7 BB |
326 | sub_num = strtoul(sub_str, NULL, 0); |
327 | test_num = strtoul(test_str, NULL, 0); | |
f1ca4da6 | 328 | |
564f6d15 | 329 | si = list_iterator_create(subsystems); |
330 | ||
331 | while ((sub = list_next(si))) { | |
f1ca4da6 | 332 | |
7c50328b | 333 | if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) && |
f1ca4da6 | 334 | sub->sub_desc.id != sub_num) |
335 | continue; | |
336 | ||
564f6d15 | 337 | ti = list_iterator_create(sub->sub_tests); |
338 | ||
339 | while ((test = list_next(ti))) { | |
f1ca4da6 | 340 | |
341 | if (!strncmp(test->test_desc.name, test_str, | |
e554dffa | 342 | SPLAT_NAME_SIZE) || test->test_desc.id==test_num) { |
564f6d15 | 343 | list_iterator_destroy(ti); |
344 | list_iterator_destroy(si); | |
f1ca4da6 | 345 | return test; |
564f6d15 | 346 | } |
f1ca4da6 | 347 | } |
564f6d15 | 348 | |
349 | list_iterator_destroy(ti); | |
f1ca4da6 | 350 | } |
351 | ||
564f6d15 | 352 | list_iterator_destroy(si); |
353 | ||
f1ca4da6 | 354 | return NULL; |
355 | } | |
356 | ||
357 | static int test_add(cmd_args_t *args, test_t *test) | |
358 | { | |
359 | test_t *tmp; | |
360 | ||
361 | tmp = test_copy(test); | |
362 | if (tmp == NULL) | |
363 | return -ENOMEM; | |
364 | ||
564f6d15 | 365 | list_append(args->args_tests, tmp); |
f1ca4da6 | 366 | return 0; |
367 | } | |
368 | ||
369 | static int test_add_all(cmd_args_t *args) | |
370 | { | |
564f6d15 | 371 | ListIterator si, ti; |
f1ca4da6 | 372 | subsystem_t *sub; |
373 | test_t *test; | |
374 | int rc; | |
375 | ||
564f6d15 | 376 | si = list_iterator_create(subsystems); |
f1ca4da6 | 377 | |
564f6d15 | 378 | while ((sub = list_next(si))) { |
379 | ti = list_iterator_create(sub->sub_tests); | |
f1ca4da6 | 380 | |
564f6d15 | 381 | while ((test = list_next(ti))) { |
382 | if ((rc = test_add(args, test))) { | |
383 | list_iterator_destroy(ti); | |
384 | list_iterator_destroy(si); | |
f1ca4da6 | 385 | return rc; |
564f6d15 | 386 | } |
f1ca4da6 | 387 | } |
564f6d15 | 388 | |
389 | list_iterator_destroy(ti); | |
f1ca4da6 | 390 | } |
391 | ||
564f6d15 | 392 | list_iterator_destroy(si); |
393 | ||
f1ca4da6 | 394 | return 0; |
395 | } | |
396 | ||
397 | static int test_run(cmd_args_t *args, test_t *test) | |
398 | { | |
399 | subsystem_t *sub = test->test_sub; | |
7c50328b | 400 | splat_cmd_t *cmd; |
f1ca4da6 | 401 | int rc, cmd_size; |
402 | ||
403 | dev_clear(); | |
404 | ||
405 | cmd_size = sizeof(*cmd); | |
7c50328b | 406 | cmd = (splat_cmd_t *)malloc(cmd_size); |
f1ca4da6 | 407 | if (cmd == NULL) |
408 | return -ENOMEM; | |
409 | ||
410 | memset(cmd, 0, cmd_size); | |
7c50328b | 411 | cmd->cmd_magic = SPLAT_CMD_MAGIC; |
f1ca4da6 | 412 | cmd->cmd_subsystem = sub->sub_desc.id; |
413 | cmd->cmd_test = test->test_desc.id; | |
414 | cmd->cmd_data_size = 0; /* Unused feature */ | |
415 | ||
416 | fprintf(stdout, "%*s:%-*s ", | |
7c50328b | 417 | SPLAT_NAME_SIZE, sub->sub_desc.name, |
418 | SPLAT_NAME_SIZE, test->test_desc.name); | |
f1ca4da6 | 419 | fflush(stdout); |
7c50328b | 420 | rc = ioctl(splatctl_fd, SPLAT_CMD, cmd); |
f1ca4da6 | 421 | if (args->args_do_color) { |
422 | fprintf(stdout, "%s %s\n", rc ? | |
423 | COLOR_RED "Fail" COLOR_RESET : | |
424 | COLOR_GREEN "Pass" COLOR_RESET, | |
425 | rc ? strerror(errno) : ""); | |
426 | } else { | |
427 | fprintf(stdout, "%s %s\n", rc ? | |
428 | "Fail" : "Pass", | |
429 | rc ? strerror(errno) : ""); | |
430 | } | |
431 | fflush(stdout); | |
432 | free(cmd); | |
433 | ||
576ec6aa BB |
434 | if ((args->args_verbose == 1 && rc) || |
435 | (args->args_verbose >= 2)) { | |
e554dffa BB |
436 | if ((rc = read(splatctl_fd, splat_buffer, |
437 | splat_buffer_size - 1)) < 0) { | |
f1ca4da6 | 438 | fprintf(stdout, "Error reading results: %d\n", rc); |
439 | } else { | |
7c50328b | 440 | fprintf(stdout, "\n%s\n", splat_buffer); |
f1ca4da6 | 441 | fflush(stdout); |
442 | } | |
443 | } | |
444 | ||
445 | return rc; | |
446 | } | |
447 | ||
448 | static int tests_run(cmd_args_t *args) | |
449 | { | |
564f6d15 | 450 | ListIterator i; |
f1ca4da6 | 451 | test_t *test; |
452 | int rc; | |
453 | ||
454 | fprintf(stdout, | |
7c50328b | 455 | "------------------------------ " |
456 | "Running SPLAT Tests " | |
457 | "------------------------------\n"); | |
f1ca4da6 | 458 | |
564f6d15 | 459 | i = list_iterator_create(args->args_tests); |
f1ca4da6 | 460 | |
564f6d15 | 461 | while ((test = list_next(i))) { |
f1ca4da6 | 462 | rc = test_run(args, test); |
564f6d15 | 463 | if (rc && args->args_exit_on_error) { |
464 | list_iterator_destroy(i); | |
f1ca4da6 | 465 | return rc; |
564f6d15 | 466 | } |
f1ca4da6 | 467 | } |
468 | ||
564f6d15 | 469 | list_iterator_destroy(i); |
f1ca4da6 | 470 | return 0; |
471 | } | |
472 | ||
473 | static int args_parse_test(cmd_args_t *args, char *str) | |
474 | { | |
564f6d15 | 475 | ListIterator si, ti; |
f1ca4da6 | 476 | subsystem_t *s; |
477 | test_t *t; | |
478 | char *sub_str, *test_str; | |
479 | int sub_num, test_num; | |
480 | int sub_all = 0, test_all = 0; | |
481 | int rc, flag = 0; | |
482 | ||
483 | test_str = strchr(str, ':'); | |
484 | if (test_str == NULL) { | |
485 | fprintf(stderr, "Test must be of the " | |
486 | "form <subsystem:test>\n"); | |
487 | return -EINVAL; | |
488 | } | |
489 | ||
490 | sub_str = str; | |
491 | test_str[0] = '\0'; | |
492 | test_str = test_str + 1; | |
493 | ||
494 | sub_num = strtol(sub_str, NULL, 0); | |
495 | test_num = strtol(test_str, NULL, 0); | |
496 | ||
497 | if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1)) | |
498 | sub_all = 1; | |
499 | ||
e554dffa | 500 | if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1)) |
f1ca4da6 | 501 | test_all = 1; |
502 | ||
564f6d15 | 503 | si = list_iterator_create(subsystems); |
504 | ||
f1ca4da6 | 505 | if (sub_all) { |
506 | if (test_all) { | |
507 | /* Add all tests from all subsystems */ | |
564f6d15 | 508 | while ((s = list_next(si))) { |
509 | ti = list_iterator_create(s->sub_tests); | |
510 | while ((t = list_next(ti))) { | |
511 | if ((rc = test_add(args, t))) { | |
512 | list_iterator_destroy(ti); | |
f1ca4da6 | 513 | goto error_run; |
564f6d15 | 514 | } |
515 | } | |
516 | list_iterator_destroy(ti); | |
517 | } | |
f1ca4da6 | 518 | } else { |
519 | /* Add a specific test from all subsystems */ | |
564f6d15 | 520 | while ((s = list_next(si))) { |
e554dffa | 521 | if ((t=test_find(s->sub_desc.name,test_str))) { |
564f6d15 | 522 | if ((rc = test_add(args, t))) |
f1ca4da6 | 523 | goto error_run; |
524 | ||
525 | flag = 1; | |
526 | } | |
527 | } | |
528 | ||
529 | if (!flag) | |
530 | fprintf(stderr, "No tests '%s:%s' could be " | |
531 | "found\n", sub_str, test_str); | |
532 | } | |
533 | } else { | |
534 | if (test_all) { | |
535 | /* Add all tests from a specific subsystem */ | |
564f6d15 | 536 | while ((s = list_next(si))) { |
f1ca4da6 | 537 | if (strncasecmp(sub_str, s->sub_desc.name, |
538 | strlen(sub_str))) | |
539 | continue; | |
540 | ||
564f6d15 | 541 | ti = list_iterator_create(s->sub_tests); |
542 | while ((t = list_next(ti))) { | |
543 | if ((rc = test_add(args, t))) { | |
544 | list_iterator_destroy(ti); | |
f1ca4da6 | 545 | goto error_run; |
564f6d15 | 546 | } |
547 | } | |
548 | list_iterator_destroy(ti); | |
f1ca4da6 | 549 | } |
550 | } else { | |
551 | /* Add a specific test from a specific subsystem */ | |
564f6d15 | 552 | if ((t = test_find(sub_str, test_str))) { |
553 | if ((rc = test_add(args, t))) | |
f1ca4da6 | 554 | goto error_run; |
555 | } else { | |
556 | fprintf(stderr, "Test '%s:%s' could not be " | |
557 | "found\n", sub_str, test_str); | |
558 | return -EINVAL; | |
559 | } | |
560 | } | |
561 | } | |
562 | ||
564f6d15 | 563 | list_iterator_destroy(si); |
564 | ||
f1ca4da6 | 565 | return 0; |
566 | ||
567 | error_run: | |
564f6d15 | 568 | list_iterator_destroy(si); |
569 | ||
f1ca4da6 | 570 | fprintf(stderr, "Test '%s:%s' not added to run list: %d\n", |
571 | sub_str, test_str, rc); | |
564f6d15 | 572 | |
f1ca4da6 | 573 | return rc; |
574 | } | |
575 | ||
576 | static void args_fini(cmd_args_t *args) | |
577 | { | |
f1ca4da6 | 578 | assert(args != NULL); |
579 | ||
564f6d15 | 580 | if (args->args_tests != NULL) |
581 | list_destroy(args->args_tests); | |
f1ca4da6 | 582 | |
583 | free(args); | |
584 | } | |
585 | ||
586 | static cmd_args_t * | |
587 | args_init(int argc, char **argv) | |
588 | { | |
589 | cmd_args_t *args; | |
590 | int c, rc; | |
591 | ||
592 | if (argc == 1) { | |
593 | usage(); | |
594 | return (cmd_args_t *) NULL; | |
595 | } | |
596 | ||
597 | /* Configure and populate the args structures */ | |
598 | args = malloc(sizeof(*args)); | |
599 | if (args == NULL) | |
600 | return NULL; | |
601 | ||
602 | memset(args, 0, sizeof(*args)); | |
603 | args->args_verbose = 0; | |
604 | args->args_do_list = 0; | |
605 | args->args_do_all = 0; | |
606 | args->args_do_color = 1; | |
607 | args->args_exit_on_error = 0; | |
564f6d15 | 608 | args->args_tests = list_create((ListDelF)test_fini); |
f1ca4da6 | 609 | if (args->args_tests == NULL) { |
610 | args_fini(args); | |
611 | return NULL; | |
612 | } | |
613 | ||
614 | while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){ | |
615 | switch (c) { | |
616 | case 'v': args->args_verbose++; break; | |
617 | case 'l': args->args_do_list = 1; break; | |
618 | case 'a': args->args_do_all = 1; break; | |
619 | case 'c': args->args_do_color = 0; break; | |
620 | case 'x': args->args_exit_on_error = 1; break; | |
621 | case 't': | |
622 | if (args->args_do_all) { | |
623 | fprintf(stderr, "Option -t <subsystem:test> is " | |
624 | "useless when used with -a\n"); | |
625 | args_fini(args); | |
626 | return NULL; | |
627 | } | |
628 | ||
629 | rc = args_parse_test(args, argv[optind - 1]); | |
630 | if (rc) { | |
631 | args_fini(args); | |
632 | return NULL; | |
633 | } | |
634 | break; | |
635 | case 'h': | |
636 | case '?': | |
637 | usage(); | |
638 | args_fini(args); | |
639 | return NULL; | |
640 | default: | |
641 | fprintf(stderr, "Unknown option '%s'\n", | |
642 | argv[optind - 1]); | |
643 | break; | |
644 | } | |
645 | } | |
646 | ||
647 | return args; | |
648 | } | |
649 | ||
650 | static int | |
651 | dev_clear(void) | |
652 | { | |
7c50328b | 653 | splat_cfg_t cfg; |
f1ca4da6 | 654 | int rc; |
655 | ||
656 | memset(&cfg, 0, sizeof(cfg)); | |
7c50328b | 657 | cfg.cfg_magic = SPLAT_CFG_MAGIC; |
658 | cfg.cfg_cmd = SPLAT_CFG_BUFFER_CLEAR; | |
f1ca4da6 | 659 | cfg.cfg_arg1 = 0; |
660 | ||
7c50328b | 661 | rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg); |
f1ca4da6 | 662 | if (rc) |
663 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
7c50328b | 664 | (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno); |
f1ca4da6 | 665 | |
7c50328b | 666 | lseek(splatctl_fd, 0, SEEK_SET); |
f1ca4da6 | 667 | |
668 | return rc; | |
669 | } | |
670 | ||
671 | static int | |
672 | dev_size(int size) | |
673 | { | |
7c50328b | 674 | splat_cfg_t cfg; |
f1ca4da6 | 675 | int rc; |
676 | ||
677 | memset(&cfg, 0, sizeof(cfg)); | |
7c50328b | 678 | cfg.cfg_magic = SPLAT_CFG_MAGIC; |
679 | cfg.cfg_cmd = SPLAT_CFG_BUFFER_SIZE; | |
f1ca4da6 | 680 | cfg.cfg_arg1 = size; |
681 | ||
7c50328b | 682 | rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg); |
f1ca4da6 | 683 | if (rc) { |
684 | fprintf(stderr, "Ioctl() error %lu / %d: %d\n", | |
7c50328b | 685 | (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno); |
f1ca4da6 | 686 | return rc; |
687 | } | |
688 | ||
689 | return cfg.cfg_rc1; | |
690 | } | |
691 | ||
692 | static void | |
693 | dev_fini(void) | |
694 | { | |
7c50328b | 695 | if (splat_buffer) |
696 | free(splat_buffer); | |
f1ca4da6 | 697 | |
7c50328b | 698 | if (splatctl_fd != -1) { |
699 | if (close(splatctl_fd) == -1) { | |
f1ca4da6 | 700 | fprintf(stderr, "Unable to close %s: %d\n", |
7c50328b | 701 | SPLAT_DEV, errno); |
f1ca4da6 | 702 | } |
703 | } | |
704 | } | |
705 | ||
706 | static int | |
707 | dev_init(void) | |
708 | { | |
564f6d15 | 709 | ListIterator i; |
f1ca4da6 | 710 | subsystem_t *sub; |
711 | int rc; | |
712 | ||
7c50328b | 713 | splatctl_fd = open(SPLAT_DEV, O_RDONLY); |
714 | if (splatctl_fd == -1) { | |
f1ca4da6 | 715 | fprintf(stderr, "Unable to open %s: %d\n" |
7c50328b | 716 | "Is the splat module loaded?\n", SPLAT_DEV, errno); |
f1ca4da6 | 717 | rc = errno; |
718 | goto error; | |
719 | } | |
720 | ||
721 | /* Determine kernel module version string */ | |
7c50328b | 722 | memset(splat_version, 0, VERSION_SIZE); |
723 | if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1) | |
f1ca4da6 | 724 | goto error; |
725 | ||
564f6d15 | 726 | if ((rc = dev_clear())) |
f1ca4da6 | 727 | goto error; |
728 | ||
729 | if ((rc = dev_size(0)) < 0) | |
730 | goto error; | |
731 | ||
7c50328b | 732 | splat_buffer_size = rc; |
733 | splat_buffer = (char *)malloc(splat_buffer_size); | |
734 | if (splat_buffer == NULL) { | |
f1ca4da6 | 735 | rc = -ENOMEM; |
736 | goto error; | |
737 | } | |
738 | ||
7c50328b | 739 | memset(splat_buffer, 0, splat_buffer_size); |
f1ca4da6 | 740 | |
741 | /* Determine available subsystems */ | |
742 | if ((rc = subsystem_setup()) != 0) | |
743 | goto error; | |
744 | ||
745 | /* Determine available tests for all subsystems */ | |
564f6d15 | 746 | i = list_iterator_create(subsystems); |
747 | ||
748 | while ((sub = list_next(i))) { | |
749 | if ((rc = test_setup(sub)) != 0) { | |
750 | list_iterator_destroy(i); | |
f1ca4da6 | 751 | goto error; |
564f6d15 | 752 | } |
753 | } | |
f1ca4da6 | 754 | |
564f6d15 | 755 | list_iterator_destroy(i); |
f1ca4da6 | 756 | return 0; |
757 | ||
758 | error: | |
7c50328b | 759 | if (splatctl_fd != -1) { |
760 | if (close(splatctl_fd) == -1) { | |
f1ca4da6 | 761 | fprintf(stderr, "Unable to close %s: %d\n", |
7c50328b | 762 | SPLAT_DEV, errno); |
f1ca4da6 | 763 | } |
764 | } | |
765 | ||
766 | return rc; | |
767 | } | |
768 | ||
769 | int | |
770 | init(void) | |
771 | { | |
564f6d15 | 772 | int rc = 0; |
f1ca4da6 | 773 | |
774 | /* Allocate the subsystem list */ | |
564f6d15 | 775 | subsystems = list_create((ListDelF)subsystem_fini); |
776 | if (subsystems == NULL) | |
777 | rc = ENOMEM; | |
f1ca4da6 | 778 | |
564f6d15 | 779 | return rc; |
f1ca4da6 | 780 | } |
781 | ||
782 | void | |
783 | fini(void) | |
784 | { | |
564f6d15 | 785 | list_destroy(subsystems); |
f1ca4da6 | 786 | } |
787 | ||
788 | ||
789 | int | |
790 | main(int argc, char **argv) | |
791 | { | |
792 | cmd_args_t *args = NULL; | |
793 | int rc = 0; | |
794 | ||
795 | /* General init */ | |
564f6d15 | 796 | if ((rc = init())) |
f1ca4da6 | 797 | return rc; |
798 | ||
799 | /* Device specific init */ | |
564f6d15 | 800 | if ((rc = dev_init())) |
f1ca4da6 | 801 | goto out; |
802 | ||
803 | /* Argument init and parsing */ | |
804 | if ((args = args_init(argc, argv)) == NULL) { | |
805 | rc = -1; | |
806 | goto out; | |
807 | } | |
808 | ||
809 | /* Generic kernel version string */ | |
810 | if (args->args_verbose) | |
7c50328b | 811 | fprintf(stdout, "%s", splat_version); |
f1ca4da6 | 812 | |
813 | /* Print the available test list and exit */ | |
814 | if (args->args_do_list) { | |
815 | subsystem_list(subsystems, 0); | |
816 | goto out; | |
817 | } | |
818 | ||
819 | /* Add all available test to the list of tests to run */ | |
820 | if (args->args_do_all) { | |
564f6d15 | 821 | if ((rc = test_add_all(args))) |
f1ca4da6 | 822 | goto out; |
823 | } | |
824 | ||
825 | /* Run all the requested tests */ | |
564f6d15 | 826 | if ((rc = tests_run(args))) |
f1ca4da6 | 827 | goto out; |
828 | ||
829 | out: | |
830 | if (args != NULL) | |
831 | args_fini(args); | |
832 | ||
833 | dev_fini(); | |
834 | fini(); | |
835 | return rc; | |
836 | } |