]>
Commit | Line | Data |
---|---|---|
70e083d2 TG |
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 | } |