]> git.proxmox.com Git - mirror_spl-debian.git/blob - cmd/splat/splat.c
New upstream version 0.7.2
[mirror_spl-debian.git] / cmd / splat / splat.c
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>.
6 * UCRL-CODE-235197
7 *
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://zfsonlinux.org/>.
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.
15 *
16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
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
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) User Space Interface.
25 \*****************************************************************************/
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>
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
55 #define VERSION_SIZE 64
56
57 static List subsystems; /* Subsystem/tests */
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 */
62
63
64 static void test_list(List, int);
65 static int dev_clear(void);
66 static void subsystem_fini(subsystem_t *);
67 static void test_fini(test_t *);
68
69
70 static int usage(void) {
71 fprintf(stderr, "usage: splat [hvla] [-t <subsystem:<tests>>]\n");
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"
82 " splat -t kmem:all # Runs all kmem tests\n"
83 " splat -t taskq:0x201 # Run taskq test 0x201\n");
84
85 return 0;
86 }
87
88 static subsystem_t *subsystem_init(splat_user_t *desc)
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));
97
98 sub->sub_tests = list_create((ListDelF)test_fini);
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);
110 free(sub);
111 }
112
113 static int subsystem_setup(void)
114 {
115 splat_cfg_t *cfg;
116 int i, rc, size, cfg_size;
117 subsystem_t *sub;
118 splat_user_t *desc;
119
120 /* Aquire the number of registered subsystems */
121 cfg_size = sizeof(*cfg);
122 cfg = (splat_cfg_t *)malloc(cfg_size);
123 if (cfg == NULL)
124 return -ENOMEM;
125
126 memset(cfg, 0, cfg_size);
127 cfg->cfg_magic = SPLAT_CFG_MAGIC;
128 cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_COUNT;
129
130 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
131 if (rc) {
132 fprintf(stderr, "Ioctl() error 0x%lx / %d: %d\n",
133 (unsigned long)SPLAT_CFG, cfg->cfg_cmd, errno);
134 free(cfg);
135 return rc;
136 }
137
138 size = cfg->cfg_rc1;
139 free(cfg);
140
141 /* Based on the newly acquired number of subsystems allocate
142 * memory to get the descriptive information for them all. */
143 cfg_size = sizeof(*cfg) + size * sizeof(splat_user_t);
144 cfg = (splat_cfg_t *)malloc(cfg_size);
145 if (cfg == NULL)
146 return -ENOMEM;
147
148 memset(cfg, 0, cfg_size);
149 cfg->cfg_magic = SPLAT_CFG_MAGIC;
150 cfg->cfg_cmd = SPLAT_CFG_SUBSYSTEM_LIST;
151 cfg->cfg_data.splat_subsystems.size = size;
152
153 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
154 if (rc) {
155 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
156 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
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++) {
164 desc = &(cfg->cfg_data.splat_subsystems.descs[i]);
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
174 list_append(subsystems, sub);
175 }
176
177 free(cfg);
178 return 0;
179 }
180
181 static void subsystem_list(List l, int indent)
182 {
183 ListIterator i;
184 subsystem_t *sub;
185
186 fprintf(stdout,
187 "------------------------------ "
188 "Available SPLAT Tests "
189 "------------------------------\n");
190
191 i = list_iterator_create(l);
192
193 while ((sub = list_next(i))) {
194 fprintf(stdout, "%*s0x%0*x %-*s ---- %s ----\n",
195 indent, "",
196 4, sub->sub_desc.id,
197 SPLAT_NAME_SIZE + 7, sub->sub_desc.name,
198 sub->sub_desc.desc);
199 test_list(sub->sub_tests, indent + 7);
200 }
201
202 list_iterator_destroy(i);
203 }
204
205 static test_t *test_init(subsystem_t *sub, splat_user_t *desc)
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));
215
216 return test;
217 }
218
219 static void test_fini(test_t *test)
220 {
221 assert(test != NULL);
222 free(test);
223 }
224
225 static int test_setup(subsystem_t *sub)
226 {
227 splat_cfg_t *cfg;
228 int i, rc, size;
229 test_t *test;
230 splat_user_t *desc;
231
232 /* Aquire the number of registered tests for the give subsystem */
233 cfg = (splat_cfg_t *)malloc(sizeof(*cfg));
234 if (cfg == NULL)
235 return -ENOMEM;
236
237 memset(cfg, 0, sizeof(*cfg));
238 cfg->cfg_magic = SPLAT_CFG_MAGIC;
239 cfg->cfg_cmd = SPLAT_CFG_TEST_COUNT;
240 cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */
241
242 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
243 if (rc) {
244 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
245 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
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. */
255 cfg = (splat_cfg_t *)malloc(sizeof(*cfg) + size*sizeof(splat_user_t));
256 if (cfg == NULL)
257 return -ENOMEM;
258
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;
262 cfg->cfg_arg1 = sub->sub_desc.id; /* Subsystem of interest */
263 cfg->cfg_data.splat_tests.size = size;
264
265 rc = ioctl(splatctl_fd, SPLAT_CFG, cfg);
266 if (rc) {
267 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
268 (unsigned long) SPLAT_CFG, cfg->cfg_cmd, errno);
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++) {
276 desc = &(cfg->cfg_data.splat_tests.descs[i]);
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
286 list_append(sub->sub_tests, test);
287 }
288
289 free(cfg);
290 return 0;
291 }
292
293 static test_t *test_copy(test_t *test)
294 {
295 return test_init(test->test_sub, &test->test_desc);
296 }
297
298 static void test_list(List l, int indent)
299 {
300 ListIterator i;
301 test_t *test;
302
303 i = list_iterator_create(l);
304
305 while ((test = list_next(i)))
306 fprintf(stdout, "%*s0x%0*x %-*s %s\n",
307 indent, "", 04, test->test_desc.id,
308 SPLAT_NAME_SIZE, test->test_desc.name,
309 test->test_desc.desc);
310
311 list_iterator_destroy(i);
312 }
313
314 static test_t *test_find(char *sub_str, char *test_str)
315 {
316 ListIterator si, ti;
317 subsystem_t *sub;
318 test_t *test;
319 __u32 sub_num, test_num;
320
321 /*
322 * No error checking here because it may not be a number, it's
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 */
326 sub_num = strtoul(sub_str, NULL, 0);
327 test_num = strtoul(test_str, NULL, 0);
328
329 si = list_iterator_create(subsystems);
330
331 while ((sub = list_next(si))) {
332
333 if (strncmp(sub->sub_desc.name, sub_str, SPLAT_NAME_SIZE) &&
334 sub->sub_desc.id != sub_num)
335 continue;
336
337 ti = list_iterator_create(sub->sub_tests);
338
339 while ((test = list_next(ti))) {
340
341 if (!strncmp(test->test_desc.name, test_str,
342 SPLAT_NAME_SIZE) || test->test_desc.id==test_num) {
343 list_iterator_destroy(ti);
344 list_iterator_destroy(si);
345 return test;
346 }
347 }
348
349 list_iterator_destroy(ti);
350 }
351
352 list_iterator_destroy(si);
353
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
365 list_append(args->args_tests, tmp);
366 return 0;
367 }
368
369 static int test_add_all(cmd_args_t *args)
370 {
371 ListIterator si, ti;
372 subsystem_t *sub;
373 test_t *test;
374 int rc;
375
376 si = list_iterator_create(subsystems);
377
378 while ((sub = list_next(si))) {
379 ti = list_iterator_create(sub->sub_tests);
380
381 while ((test = list_next(ti))) {
382 if ((rc = test_add(args, test))) {
383 list_iterator_destroy(ti);
384 list_iterator_destroy(si);
385 return rc;
386 }
387 }
388
389 list_iterator_destroy(ti);
390 }
391
392 list_iterator_destroy(si);
393
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;
400 splat_cmd_t *cmd;
401 int rc, cmd_size;
402
403 dev_clear();
404
405 cmd_size = sizeof(*cmd);
406 cmd = (splat_cmd_t *)malloc(cmd_size);
407 if (cmd == NULL)
408 return -ENOMEM;
409
410 memset(cmd, 0, cmd_size);
411 cmd->cmd_magic = SPLAT_CMD_MAGIC;
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 ",
417 SPLAT_NAME_SIZE, sub->sub_desc.name,
418 SPLAT_NAME_SIZE, test->test_desc.name);
419 fflush(stdout);
420 rc = ioctl(splatctl_fd, SPLAT_CMD, cmd);
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
434 if ((args->args_verbose == 1 && rc) ||
435 (args->args_verbose >= 2)) {
436 if ((rc = read(splatctl_fd, splat_buffer,
437 splat_buffer_size - 1)) < 0) {
438 fprintf(stdout, "Error reading results: %d\n", rc);
439 } else {
440 fprintf(stdout, "\n%s\n", splat_buffer);
441 fflush(stdout);
442 }
443 }
444
445 return rc;
446 }
447
448 static int tests_run(cmd_args_t *args)
449 {
450 ListIterator i;
451 test_t *test;
452 int rc;
453
454 fprintf(stdout,
455 "------------------------------ "
456 "Running SPLAT Tests "
457 "------------------------------\n");
458
459 i = list_iterator_create(args->args_tests);
460
461 while ((test = list_next(i))) {
462 rc = test_run(args, test);
463 if (rc && args->args_exit_on_error) {
464 list_iterator_destroy(i);
465 return rc;
466 }
467 }
468
469 list_iterator_destroy(i);
470 return 0;
471 }
472
473 static int args_parse_test(cmd_args_t *args, char *str)
474 {
475 ListIterator si, ti;
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
500 if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
501 test_all = 1;
502
503 si = list_iterator_create(subsystems);
504
505 if (sub_all) {
506 if (test_all) {
507 /* Add all tests from all subsystems */
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);
513 goto error_run;
514 }
515 }
516 list_iterator_destroy(ti);
517 }
518 } else {
519 /* Add a specific test from all subsystems */
520 while ((s = list_next(si))) {
521 if ((t=test_find(s->sub_desc.name,test_str))) {
522 if ((rc = test_add(args, t)))
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 */
536 while ((s = list_next(si))) {
537 if (strncasecmp(sub_str, s->sub_desc.name,
538 strlen(sub_str)))
539 continue;
540
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);
545 goto error_run;
546 }
547 }
548 list_iterator_destroy(ti);
549 }
550 } else {
551 /* Add a specific test from a specific subsystem */
552 if ((t = test_find(sub_str, test_str))) {
553 if ((rc = test_add(args, t)))
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
563 list_iterator_destroy(si);
564
565 return 0;
566
567 error_run:
568 list_iterator_destroy(si);
569
570 fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
571 sub_str, test_str, rc);
572
573 return rc;
574 }
575
576 static void args_fini(cmd_args_t *args)
577 {
578 assert(args != NULL);
579
580 if (args->args_tests != NULL)
581 list_destroy(args->args_tests);
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;
608 args->args_tests = list_create((ListDelF)test_fini);
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 {
653 splat_cfg_t cfg;
654 int rc;
655
656 memset(&cfg, 0, sizeof(cfg));
657 cfg.cfg_magic = SPLAT_CFG_MAGIC;
658 cfg.cfg_cmd = SPLAT_CFG_BUFFER_CLEAR;
659 cfg.cfg_arg1 = 0;
660
661 rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
662 if (rc)
663 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
664 (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
665
666 lseek(splatctl_fd, 0, SEEK_SET);
667
668 return rc;
669 }
670
671 static int
672 dev_size(int size)
673 {
674 splat_cfg_t cfg;
675 int rc;
676
677 memset(&cfg, 0, sizeof(cfg));
678 cfg.cfg_magic = SPLAT_CFG_MAGIC;
679 cfg.cfg_cmd = SPLAT_CFG_BUFFER_SIZE;
680 cfg.cfg_arg1 = size;
681
682 rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
683 if (rc) {
684 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
685 (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
686 return rc;
687 }
688
689 return cfg.cfg_rc1;
690 }
691
692 static void
693 dev_fini(void)
694 {
695 if (splat_buffer)
696 free(splat_buffer);
697
698 if (splatctl_fd != -1) {
699 if (close(splatctl_fd) == -1) {
700 fprintf(stderr, "Unable to close %s: %d\n",
701 SPLAT_DEV, errno);
702 }
703 }
704 }
705
706 static int
707 dev_init(void)
708 {
709 ListIterator i;
710 subsystem_t *sub;
711 int rc;
712
713 splatctl_fd = open(SPLAT_DEV, O_RDONLY);
714 if (splatctl_fd == -1) {
715 fprintf(stderr, "Unable to open %s: %d\n"
716 "Is the splat module loaded?\n", SPLAT_DEV, errno);
717 rc = errno;
718 goto error;
719 }
720
721 /* Determine kernel module version string */
722 memset(splat_version, 0, VERSION_SIZE);
723 if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
724 goto error;
725
726 if ((rc = dev_clear()))
727 goto error;
728
729 if ((rc = dev_size(0)) < 0)
730 goto error;
731
732 splat_buffer_size = rc;
733 splat_buffer = (char *)malloc(splat_buffer_size);
734 if (splat_buffer == NULL) {
735 rc = -ENOMEM;
736 goto error;
737 }
738
739 memset(splat_buffer, 0, splat_buffer_size);
740
741 /* Determine available subsystems */
742 if ((rc = subsystem_setup()) != 0)
743 goto error;
744
745 /* Determine available tests for all subsystems */
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);
751 goto error;
752 }
753 }
754
755 list_iterator_destroy(i);
756 return 0;
757
758 error:
759 if (splatctl_fd != -1) {
760 if (close(splatctl_fd) == -1) {
761 fprintf(stderr, "Unable to close %s: %d\n",
762 SPLAT_DEV, errno);
763 }
764 }
765
766 return rc;
767 }
768
769 int
770 init(void)
771 {
772 int rc = 0;
773
774 /* Allocate the subsystem list */
775 subsystems = list_create((ListDelF)subsystem_fini);
776 if (subsystems == NULL)
777 rc = ENOMEM;
778
779 return rc;
780 }
781
782 void
783 fini(void)
784 {
785 list_destroy(subsystems);
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 */
796 if ((rc = init()))
797 return rc;
798
799 /* Device specific init */
800 if ((rc = dev_init()))
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)
811 fprintf(stdout, "%s", splat_version);
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) {
821 if ((rc = test_add_all(args)))
822 goto out;
823 }
824
825 /* Run all the requested tests */
826 if ((rc = tests_run(args)))
827 goto out;
828
829 out:
830 if (args != NULL)
831 args_fini(args);
832
833 dev_fini();
834 fini();
835 return rc;
836 }