]> granicus.if.org Git - zfs/blob - cmd/splat.c
Fix two minor compiler warnings
[zfs] / cmd / 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://github.com/behlendorf/spl/>.
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) {
435                 if ((rc = read(splatctl_fd, splat_buffer,
436                                splat_buffer_size - 1)) < 0) {
437                         fprintf(stdout, "Error reading results: %d\n", rc);
438                 } else {
439                         fprintf(stdout, "\n%s\n", splat_buffer);
440                         fflush(stdout);
441                 }
442         }
443
444         return rc;
445 }
446
447 static int tests_run(cmd_args_t *args)
448 {
449         ListIterator i;
450         test_t *test;
451         int rc;
452
453         fprintf(stdout,
454                 "------------------------------ "
455                 "Running SPLAT Tests "
456                 "------------------------------\n");
457
458         i = list_iterator_create(args->args_tests);
459
460         while ((test = list_next(i))) {
461                 rc = test_run(args, test);
462                 if (rc && args->args_exit_on_error) {
463                         list_iterator_destroy(i);
464                         return rc;
465                 }
466         }
467
468         list_iterator_destroy(i);
469         return 0;
470 }
471
472 static int args_parse_test(cmd_args_t *args, char *str)
473 {
474         ListIterator si, ti;
475         subsystem_t *s;
476         test_t *t;
477         char *sub_str, *test_str;
478         int sub_num, test_num;
479         int sub_all = 0, test_all = 0;
480         int rc, flag = 0;
481
482         test_str = strchr(str, ':');
483         if (test_str == NULL) {
484                 fprintf(stderr, "Test must be of the "
485                         "form <subsystem:test>\n");
486                 return -EINVAL;
487         }
488
489         sub_str = str;
490         test_str[0] = '\0';
491         test_str = test_str + 1;
492
493         sub_num = strtol(sub_str, NULL, 0);
494         test_num = strtol(test_str, NULL, 0);
495
496         if (!strncasecmp(sub_str, "all", strlen(sub_str)) || (sub_num == -1))
497                 sub_all = 1;
498
499         if (!strncasecmp(test_str,"all",strlen(test_str)) || (test_num == -1))
500                 test_all = 1;
501
502         si = list_iterator_create(subsystems);
503
504         if (sub_all) {
505                 if (test_all) {
506                         /* Add all tests from all subsystems */
507                         while ((s = list_next(si))) {
508                                 ti = list_iterator_create(s->sub_tests);
509                                 while ((t = list_next(ti))) {
510                                         if ((rc = test_add(args, t))) {
511                                                 list_iterator_destroy(ti);
512                                                 goto error_run;
513                                         }
514                                 }
515                                 list_iterator_destroy(ti);
516                         }
517                 } else {
518                         /* Add a specific test from all subsystems */
519                         while ((s = list_next(si))) {
520                                 if ((t=test_find(s->sub_desc.name,test_str))) {
521                                         if ((rc = test_add(args, t)))
522                                                 goto error_run;
523
524                                         flag = 1;
525                                 }
526                         }
527
528                         if (!flag)
529                                 fprintf(stderr, "No tests '%s:%s' could be "
530                                         "found\n", sub_str, test_str);
531                 }
532         } else {
533                 if (test_all) {
534                         /* Add all tests from a specific subsystem */
535                         while ((s = list_next(si))) {
536                                 if (strncasecmp(sub_str, s->sub_desc.name,
537                                     strlen(sub_str)))
538                                         continue;
539
540                                 ti = list_iterator_create(s->sub_tests);
541                                 while ((t = list_next(ti))) {
542                                         if ((rc = test_add(args, t))) {
543                                                 list_iterator_destroy(ti);
544                                                 goto error_run;
545                                         }
546                                 }
547                                 list_iterator_destroy(ti);
548                         }
549                 } else {
550                         /* Add a specific test from a specific subsystem */
551                         if ((t = test_find(sub_str, test_str))) {
552                                 if ((rc = test_add(args, t)))
553                                         goto error_run;
554                         } else {
555                                 fprintf(stderr, "Test '%s:%s' could not be "
556                                         "found\n", sub_str, test_str);
557                                 return -EINVAL;
558                         }
559                 }
560         }
561
562         list_iterator_destroy(si);
563
564         return 0;
565
566 error_run:
567         list_iterator_destroy(si);
568
569         fprintf(stderr, "Test '%s:%s' not added to run list: %d\n",
570                 sub_str, test_str, rc);
571
572         return rc;
573 }
574
575 static void args_fini(cmd_args_t *args)
576 {
577         assert(args != NULL);
578
579         if (args->args_tests != NULL)
580                 list_destroy(args->args_tests);
581
582         free(args);
583 }
584
585 static cmd_args_t *
586 args_init(int argc, char **argv)
587 {
588         cmd_args_t *args;
589         int c, rc;
590
591         if (argc == 1) {
592                 usage();
593                 return (cmd_args_t *) NULL;
594         }
595
596         /* Configure and populate the args structures */
597         args = malloc(sizeof(*args));
598         if (args == NULL)
599                 return NULL;
600
601         memset(args, 0, sizeof(*args));
602         args->args_verbose = 0;
603         args->args_do_list = 0;
604         args->args_do_all  = 0;
605         args->args_do_color = 1;
606         args->args_exit_on_error = 0;
607         args->args_tests = list_create((ListDelF)test_fini);
608         if (args->args_tests == NULL) {
609                 args_fini(args);
610                 return NULL;
611         }
612
613         while ((c = getopt_long(argc, argv, shortOpts, longOpts, NULL)) != -1){
614                 switch (c) {
615                 case 'v':  args->args_verbose++;                        break;
616                 case 'l':  args->args_do_list = 1;                      break;
617                 case 'a':  args->args_do_all = 1;                       break;
618                 case 'c':  args->args_do_color = 0;                     break;
619                 case 'x':  args->args_exit_on_error = 1;                break;
620                 case 't':
621                         if (args->args_do_all) {
622                                 fprintf(stderr, "Option -t <subsystem:test> is "
623                                         "useless when used with -a\n");
624                                 args_fini(args);
625                                 return NULL;
626                         }
627
628                         rc = args_parse_test(args, argv[optind - 1]);
629                         if (rc) {
630                                 args_fini(args);
631                                 return NULL;
632                         }
633                         break;
634                 case 'h':
635                 case '?':
636                         usage();
637                         args_fini(args);
638                         return NULL;
639                 default:
640                         fprintf(stderr, "Unknown option '%s'\n",
641                                 argv[optind - 1]);
642                         break;
643                 }
644         }
645
646         return args;
647 }
648
649 static int
650 dev_clear(void)
651 {
652         splat_cfg_t cfg;
653         int rc;
654
655         memset(&cfg, 0, sizeof(cfg));
656         cfg.cfg_magic = SPLAT_CFG_MAGIC;
657         cfg.cfg_cmd   = SPLAT_CFG_BUFFER_CLEAR;
658         cfg.cfg_arg1  = 0;
659
660         rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
661         if (rc)
662                 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
663                         (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
664
665         lseek(splatctl_fd, 0, SEEK_SET);
666
667         return rc;
668 }
669
670 static int
671 dev_size(int size)
672 {
673         splat_cfg_t cfg;
674         int rc;
675
676         memset(&cfg, 0, sizeof(cfg));
677         cfg.cfg_magic = SPLAT_CFG_MAGIC;
678         cfg.cfg_cmd   = SPLAT_CFG_BUFFER_SIZE;
679         cfg.cfg_arg1  = size;
680
681         rc = ioctl(splatctl_fd, SPLAT_CFG, &cfg);
682         if (rc) {
683                 fprintf(stderr, "Ioctl() error %lu / %d: %d\n",
684                         (unsigned long) SPLAT_CFG, cfg.cfg_cmd, errno);
685                 return rc;
686         }
687
688         return cfg.cfg_rc1;
689 }
690
691 static void
692 dev_fini(void)
693 {
694         if (splat_buffer)
695                 free(splat_buffer);
696
697         if (splatctl_fd != -1) {
698                 if (close(splatctl_fd) == -1) {
699                         fprintf(stderr, "Unable to close %s: %d\n",
700                                 SPLAT_DEV, errno);
701                 }
702         }
703 }
704
705 static int
706 dev_init(void)
707 {
708         ListIterator i;
709         subsystem_t *sub;
710         int rc;
711
712         splatctl_fd = open(SPLAT_DEV, O_RDONLY);
713         if (splatctl_fd == -1) {
714                 fprintf(stderr, "Unable to open %s: %d\n"
715                         "Is the splat module loaded?\n", SPLAT_DEV, errno);
716                 rc = errno;
717                 goto error;
718         }
719
720         /* Determine kernel module version string */
721         memset(splat_version, 0, VERSION_SIZE);
722         if ((rc = read(splatctl_fd, splat_version, VERSION_SIZE - 1)) == -1)
723                 goto error;
724
725         if ((rc = dev_clear()))
726                 goto error;
727
728         if ((rc = dev_size(0)) < 0)
729                 goto error;
730
731         splat_buffer_size = rc;
732         splat_buffer = (char *)malloc(splat_buffer_size);
733         if (splat_buffer == NULL) {
734                 rc = -ENOMEM;
735                 goto error;
736         }
737
738         memset(splat_buffer, 0, splat_buffer_size);
739
740         /* Determine available subsystems */
741         if ((rc = subsystem_setup()) != 0)
742                 goto error;
743
744         /* Determine available tests for all subsystems */
745         i = list_iterator_create(subsystems);
746
747         while ((sub = list_next(i))) {
748                 if ((rc = test_setup(sub)) != 0) {
749                         list_iterator_destroy(i);
750                         goto error;
751                 }
752         }
753
754         list_iterator_destroy(i);
755         return 0;
756
757 error:
758         if (splatctl_fd != -1) {
759                 if (close(splatctl_fd) == -1) {
760                         fprintf(stderr, "Unable to close %s: %d\n",
761                                 SPLAT_DEV, errno);
762                 }
763         }
764
765         return rc;
766 }
767
768 int
769 init(void)
770 {
771         int rc = 0;
772
773         /* Allocate the subsystem list */
774         subsystems = list_create((ListDelF)subsystem_fini);
775         if (subsystems == NULL)
776                 rc = ENOMEM;
777
778         return rc;
779 }
780
781 void
782 fini(void)
783 {
784         list_destroy(subsystems);
785 }
786
787
788 int
789 main(int argc, char **argv)
790 {
791         cmd_args_t *args = NULL;
792         int rc = 0;
793
794         /* General init */
795         if ((rc = init()))
796                 return rc;
797
798         /* Device specific init */
799         if ((rc = dev_init()))
800                 goto out;
801
802         /* Argument init and parsing */
803         if ((args = args_init(argc, argv)) == NULL) {
804                 rc = -1;
805                 goto out;
806         }
807
808         /* Generic kernel version string */
809         if (args->args_verbose)
810                 fprintf(stdout, "%s", splat_version);
811
812         /* Print the available test list and exit */
813         if (args->args_do_list) {
814                 subsystem_list(subsystems, 0);
815                 goto out;
816         }
817
818         /* Add all available test to the list of tests to run */
819         if (args->args_do_all) {
820                 if ((rc = test_add_all(args)))
821                         goto out;
822         }
823
824         /* Run all the requested tests */
825         if ((rc = tests_run(args)))
826                 goto out;
827
828 out:
829         if (args != NULL)
830                 args_fini(args);
831
832         dev_fini();
833         fini();
834         return rc;
835 }