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