X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fliblustre%2Ftests%2Fsanity.c;h=814a75fe1fd1324b96964a1f497e8f26ca19faf8;hp=39e45c0799edb9f504d18347bfcdfa1adf02eb6b;hb=725f3f8eb96203b5679da46bfc4e6d22bf1cdf9c;hpb=6d835462ce75edb92cc1d010bdcd9bc0bf296681 diff --git a/lustre/liblustre/tests/sanity.c b/lustre/liblustre/tests/sanity.c index 39e45c0..814a75f 100644 --- a/lustre/liblustre/tests/sanity.c +++ b/lustre/liblustre/tests/sanity.c @@ -1,24 +1,39 @@ -/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- - * vim:expandtab:shiftwidth=8:tabstop=8: +/* + * GPL HEADER START * - * Lustre Light user test program + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. * - * Copyright (c) 2002, 2003 Cluster File Systems, Inc. + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). * - * This file is part of Lustre, http://www.lustre.org. + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf * - * Lustre is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + * GPL HEADER END + */ +/* + * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * Lustre is a trademark of Sun Microsystems, Inc. * - * Lustre is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * lustre/liblustre/tests/sanity.c * - * You should have received a copy of the GNU General Public License - * along with Lustre; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Lustre Light user test program */ #define _BSD_SOURCE @@ -41,7 +56,7 @@ #include #include "test_common.h" -#include +#include #define _npages (2048) @@ -56,7 +71,9 @@ extern char *lustre_path; do { \ char buf[100]; \ int len; \ - sprintf(buf, "===== START %s: %s ", __FUNCTION__, (str)); \ + gettimeofday(&start, NULL); \ + sprintf(buf, "===== START %s: %s %ld", __FUNCTION__, \ + (str), (long)start.tv_sec); \ len = strlen(buf); \ if (len < 79) { \ memset(buf+len, '=', 100-len); \ @@ -64,7 +81,6 @@ extern char *lustre_path; buf[80] = 0; \ } \ printf("%s", buf); \ - gettimeofday(&start, NULL); \ } while (0) #define LEAVE() \ @@ -94,6 +110,7 @@ int t1(char *name) { char path[MAX_PATH_LENGTH] = ""; + ENTER("touch+unlink"); snprintf(path, MAX_PATH_LENGTH, "%s/test_t1", lustre_path); if (opt_verbose) @@ -377,7 +394,7 @@ int t14(char *name) char buf[1024]; const int nfiles = 256; char *prefix = "test14_filename_long_prefix_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA___"; - struct dirent64 *ent; + struct dirent64 *ent; int fd, i, rc, pos, index; loff_t base = 0; ENTER(">1 block(4k) directory readdir"); @@ -401,7 +418,7 @@ int t14(char *name) while (pos < rc) { char *item; - ent = (struct dirent64 *) ((char*) buf + pos); + ent = (void *) buf + pos; item = (char *) ent->d_name; if (!strcmp(item, ".") || !strcmp(item, "..")) goto iter; @@ -409,12 +426,13 @@ int t14(char *name) printf("found bad name %s\n", item); return(-1); } - printf("[%03d]: %s\n", + printf("[%03d]: %s\t", index++, item + strlen(prefix)); iter: pos += ent->d_reclen; } } + printf("\n"); if (rc < 0) { printf("getdents error %d\n", rc); return(-1); @@ -558,7 +576,8 @@ static int check_file_size(char *file, long long size) return(1); } if (statbuf.st_size != size) { - printf("size of %s: %ld != %lld\n", file, statbuf.st_size, size); + printf("size of %s: %lld != %lld\n", file, + (long long)statbuf.st_size, (long long )size); return(-1); } return 0; @@ -593,7 +612,7 @@ int t20(char *name) int fd; struct iovec iov[2]; char buf[100]; - ssize_t ret; + long ret; ENTER("trap app's general bad pointer for file i/o"); snprintf(file, MAX_PATH_LENGTH, "%s/test_t20_file", lustre_path); @@ -605,12 +624,12 @@ int t20(char *name) ret = write(fd, NULL, 20); if (ret != -1 || errno != EFAULT) { - printf("write 1: ret %ld, errno %d\n", ret, errno); + printf("write 1: ret %lld, errno %d\n", (long long)ret, errno); return(1); } ret = write(fd, (void *)-1, 20); if (ret != -1 || errno != EFAULT) { - printf("write 2: ret %ld, errno %d\n", ret, errno); + printf("write 2: ret %lld, errno %d\n", (long long)ret, errno); return(1); } iov[0].iov_base = NULL; @@ -619,7 +638,7 @@ int t20(char *name) iov[1].iov_len = 10; ret = writev(fd, iov, 2); if (ret != -1 || errno != EFAULT) { - printf("writev 1: ret %ld, errno %d\n", ret, errno); + printf("writev 1: ret %lld, errno %d\n", (long long)ret, errno); return(1); } iov[0].iov_base = NULL; @@ -628,19 +647,19 @@ int t20(char *name) iov[1].iov_len = sizeof(buf); ret = writev(fd, iov, 2); if (ret != sizeof(buf)) { - printf("write 3 ret %ld, error %d\n", ret, errno); + printf("writev 2: ret %lld, error %d\n", (long long)ret, errno); return(1); } lseek(fd, 0, SEEK_SET); ret = read(fd, NULL, 20); if (ret != -1 || errno != EFAULT) { - printf("read 1: ret %ld, errno %d\n", ret, errno); + printf("read 1: ret %lld, errno %d\n", (long long)ret, errno); return(1); } ret = read(fd, (void *)-1, 20); if (ret != -1 || errno != EFAULT) { - printf("read 2: ret %ld, errno %d\n", ret, errno); + printf("read 2: ret %lld, error %d\n", (long long)ret, errno); return(1); } iov[0].iov_base = NULL; @@ -649,7 +668,7 @@ int t20(char *name) iov[1].iov_len = 10; ret = readv(fd, iov, 2); if (ret != -1 || errno != EFAULT) { - printf("readv 1: ret %ld, errno %d\n", ret, errno); + printf("readv 1: ret %lld, error %d\n", (long long)ret, errno); return(1); } iov[0].iov_base = NULL; @@ -658,7 +677,7 @@ int t20(char *name) iov[1].iov_len = sizeof(buf); ret = readv(fd, iov, 2); if (ret != sizeof(buf)) { - printf("read 3 ret %ld, error %d\n", ret, errno); + printf("readv 2: ret %lld, error %d\n", (long long)ret, errno); return(1); } @@ -686,8 +705,9 @@ int t21(char *name) } t_fcntl(fd, F_SETFL, O_APPEND); - if (!(ret = t_fcntl(fd, F_GETFL)) & O_APPEND) { - printf("error get flag: ret %x\n", ret); + ret = t_fcntl(fd, F_GETFL); + if ((ret & O_APPEND) == 0) { + printf("error get flag: ret %o\n", ret); return(-1); } @@ -710,11 +730,11 @@ int t22(char *name) int fd; char *str = "1234567890"; char buf[100]; - ssize_t ret; + long ret; ENTER("make sure O_APPEND take effect"); snprintf(file, MAX_PATH_LENGTH, "%s/test_t22_file", lustre_path); - fd = open(file, O_RDWR|O_CREAT|O_APPEND, (mode_t)0666); + fd = open(file, O_TRUNC|O_RDWR|O_CREAT|O_APPEND, (mode_t)0666); if (fd < 0) { printf("error open file: %s\n", strerror(errno)); return(-1); @@ -723,14 +743,14 @@ int t22(char *name) lseek(fd, 100, SEEK_SET); ret = write(fd, str, strlen(str)); if (ret != strlen(str)) { - printf("write 1: ret %ld, errno %d\n", ret, errno); + printf("write 1: ret %lld, errno %d\n", (long long)ret, errno); return(1); } lseek(fd, 0, SEEK_SET); ret = read(fd, buf, sizeof(buf)); if (ret != strlen(str)) { - printf("read 1 got %ld\n", ret); + printf("read 1: ret %lld\n", (long long)ret); return(1); } @@ -747,14 +767,14 @@ int t22(char *name) lseek(fd, 100, SEEK_SET); ret = write(fd, str, strlen(str)); if (ret != strlen(str)) { - printf("write 2: ret %ld, errno %d\n", ret, errno); + printf("write 2: ret %lld, errno %d\n", (long long)ret, errno); return(1); } lseek(fd, 100, SEEK_SET); ret = read(fd, buf, sizeof(buf)); if (ret != strlen(str)) { - printf("read 2 got %ld\n", ret); + printf("read 2: ret %lld\n", (long long)ret); return(1); } @@ -773,7 +793,7 @@ int t23(char *name) char path[MAX_PATH_LENGTH]; int fd; long long ret; - long long off; + loff_t off; ENTER("handle seek > 2GB"); snprintf(path, MAX_PATH_LENGTH, "%s/f%s", lustre_path, name); @@ -822,7 +842,7 @@ int t23(char *name) ret = lseek(fd, -buf_size + 2, SEEK_CUR); if (ret != off) { printf("relative seek error for %d %llu != %llu\n", - -buf_size + 2, ret, off); + -buf_size + 2, ret, (unsigned long long) off); if (ret == -1) perror("relative seek"); return -1; @@ -848,7 +868,7 @@ int t23(char *name) off = 2048ULL * 1024 * 1024, SEEK_SET; ret = lseek(fd, off, SEEK_SET); if (ret != off) { - printf("seek 2GB error for %llu != %llu\n", ret, off); + printf("seek 2GB error for %llu != %llu\n", ret, (unsigned long long) off); if (ret == -1) perror("seek 2GB"); return -1; @@ -878,14 +898,14 @@ static int pages_io(int xfer, loff_t pos) /* create sample data */ for (i = 0, buf = buf_alloc; i < _npages; i++) { - for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) { + for (j = 0; j < CFS_PAGE_SIZE/sizeof(int); j++, buf++) { *buf = rand(); } } /* compute checksum */ for (i = 0, buf = buf_alloc; i < _npages; i++) { - for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) { + for (j = 0; j < CFS_PAGE_SIZE/sizeof(int); j++, buf++) { check_sum[i] += *buf; } } @@ -903,9 +923,9 @@ static int pages_io(int xfer, loff_t pos) } gettimeofday(&tw1, NULL); for (i = 0, buf = buf_alloc; i < _npages; - i += xfer, buf += xfer * PAGE_SIZE / sizeof(int)) { - rc = write(fd, buf, PAGE_SIZE * xfer); - if (rc != PAGE_SIZE * xfer) { + i += xfer, buf += xfer * CFS_PAGE_SIZE / sizeof(int)) { + rc = write(fd, buf, CFS_PAGE_SIZE * xfer); + if (rc != CFS_PAGE_SIZE * xfer) { printf("write error (i %d, rc %d): %s\n", i, rc, strerror(errno)); return(1); @@ -923,9 +943,9 @@ static int pages_io(int xfer, loff_t pos) } gettimeofday(&tr1, NULL); for (i = 0, buf = buf_alloc; i < _npages; - i += xfer, buf += xfer * PAGE_SIZE / sizeof(int)) { - rc = read(fd, buf, PAGE_SIZE * xfer); - if (rc != PAGE_SIZE * xfer) { + i += xfer, buf += xfer * CFS_PAGE_SIZE / sizeof(int)) { + rc = read(fd, buf, CFS_PAGE_SIZE * xfer); + if (rc != CFS_PAGE_SIZE * xfer) { printf("read error (i %d, rc %d): %s\n", i, rc, strerror(errno)); return(1); @@ -936,7 +956,7 @@ static int pages_io(int xfer, loff_t pos) /* compute checksum */ for (i = 0, buf = buf_alloc; i < _npages; i++) { int sum = 0; - for (j = 0; j < PAGE_SIZE/sizeof(int); j++, buf++) { + for (j = 0; j < CFS_PAGE_SIZE/sizeof(int); j++, buf++) { sum += *buf; } if (sum != check_sum[i]) { @@ -951,8 +971,8 @@ static int pages_io(int xfer, loff_t pos) tw = (tw2.tv_sec - tw1.tv_sec) * 1000000 + (tw2.tv_usec - tw1.tv_usec); tr = (tr2.tv_sec - tr1.tv_sec) * 1000000 + (tr2.tv_usec - tr1.tv_usec); printf(" (R:%.3fM/s, W:%.3fM/s)\n", - (_npages * PAGE_SIZE) / (tw / 1000000.0) / (1024 * 1024), - (_npages * PAGE_SIZE) / (tr / 1000000.0) / (1024 * 1024)); + (_npages * CFS_PAGE_SIZE) / (tw / 1000000.0) / (1024 * 1024), + (_npages * CFS_PAGE_SIZE) / (tr / 1000000.0) / (1024 * 1024)); if (data_error) return 1; @@ -1072,8 +1092,14 @@ int t52(char *name) printf("st_atime=%s", ctime(&statbuf.st_atime)); atime = statbuf.st_atime; for (i = 0; i < 3; i++) { + ssize_t num_read; sleep(2); - read(fd, buf, sizeof(buf)); + /* should not ignore read(2)'s return value */ + num_read = read(fd, buf, sizeof(buf)); + if (num_read < 0 ) { + printf("read from %s: %s\n", file, strerror(errno)); + return -1; + } stat(file, &statbuf); printf("st_atime=%s", ctime(&statbuf.st_atime)); diff = statbuf.st_atime - atime; @@ -1082,8 +1108,8 @@ int t52(char *name) close(fd); t_unlink(file); return -1; - } - atime = statbuf.st_atime; + } + atime = statbuf.st_atime; } close(fd); t_unlink(file); @@ -1097,26 +1123,26 @@ int t53(char *name) struct utimbuf times; /* struct. buffer for utime() */ struct stat stat_buf; /* struct buffer to hold file info. */ time_t mtime, atime; - + ENTER("mtime/atime should be updated by utime() call"); snprintf(file, MAX_PATH_LENGTH, "%s/test_t53_file", lustre_path); t_echo_create(file, "check mtime/atime update by utime() call"); - + /* Initialize the modification and access time in the times arg */ times.actime = NEW_TIME+10; times.modtime = NEW_TIME; - + /* file modification/access time */ utime(file, ×); - + if (stat(file, &stat_buf) < 0) { printf("stat(2) of %s failed, error:%d %s\n", - file, errno, strerror(errno)); + file, errno, strerror(errno)); } mtime = stat_buf.st_mtime; atime = stat_buf.st_atime; - + if ((mtime == NEW_TIME) && (atime == NEW_TIME + 10)) { t_unlink(file); LEAVE(); @@ -1124,7 +1150,7 @@ int t53(char *name) printf("mod time %ld, expected %ld\n", mtime, (long)NEW_TIME); printf("acc time %ld, expected %ld\n", atime, (long)NEW_TIME + 10); - + t_unlink(file); return (-1); } @@ -1150,7 +1176,7 @@ int t54(char *name) lock.l_whence = 0; lock.l_len = 1; if ((err = t_fcntl(fd, F_SETLKW, &lock)) != 0) { - fprintf(stderr, "fcntl returned: %d (%s)\n", + fprintf(stderr, "fcntl returned: %d (%s)\n", err, strerror(err)); close(fd); t_unlink(file); @@ -1183,7 +1209,7 @@ int t55(char *name) ENTER("setstripe/getstripe"); snprintf(path, MAX_PATH_LENGTH, "%s/test_t55", lustre_path); snprintf(file, MAX_PATH_LENGTH, "%s/test_t55/file_t55", lustre_path); - + buflen = sizeof(struct lov_user_md); buflen += STRIPE_COUNT * sizeof(struct lov_user_ost_data); lum = (struct lov_user_md *)malloc(buflen); @@ -1212,7 +1238,7 @@ int t55(char *name) free(lum); return -1; } - + lum->lmm_magic = LOV_USER_MAGIC; lum->lmm_stripe_count = STRIPE_COUNT; rc = ioctl(fd, LL_IOC_LOV_GETSTRIPE, lum); @@ -1229,21 +1255,23 @@ int t55(char *name) close(fd); if (opt_verbose) { - printf("lmm_magic: 0x%08X\n", lum->lmm_magic); - printf("lmm_object_id: "LPX64"\n", lum->lmm_object_id); - printf("lmm_object_gr: "LPX64"\n", lum->lmm_object_gr); - printf("lmm_stripe_count: %u\n", (int)lum->lmm_stripe_count); - printf("lmm_stripe_size: %u\n", lum->lmm_stripe_size); - printf("lmm_stripe_pattern: %x\n", lum->lmm_pattern); - - for (index = 0; index < lum->lmm_stripe_count; index++) { - lo = lum->lmm_objects + index; - printf("object %d:\n", index); - printf("\tobject_gr: "LPX64"\n", lo->l_object_gr); - printf("\tobject_id: "LPX64"\n", lo->l_object_id); - printf("\tost_gen: %#x\n", lo->l_ost_gen); - printf("\tost_idx: %u\n", lo->l_ost_idx); - } + printf("lmm_magic: 0x%08X\n", lum->lmm_magic); + printf("lmm_object_id: "LPX64"\n", + lmm_oi_id(&lum->lmm_oi)); + printf("lmm_object_seq: "LPX64"\n", + lmm_oi_seq(&lum->lmm_oi)); + printf("lmm_stripe_count: %u\n", (int)lum->lmm_stripe_count); + printf("lmm_stripe_size: %u\n", lum->lmm_stripe_size); + printf("lmm_stripe_pattern: %x\n", lum->lmm_pattern); + + for (index = 0; index < lum->lmm_stripe_count; index++) { + lo = lum->lmm_objects + index; + printf("object %d:\n", index); + printf("\tobject_oid: "DOSTID"\n", + POSTID(&lo->l_ost_oi)); + printf("\tost_gen: %#x\n", lo->l_ost_gen); + printf("\tost_idx: %u\n", lo->l_ost_idx); + } } if (lum->lmm_magic != LOV_USER_MAGIC || @@ -1272,7 +1300,7 @@ int t55(char *name) } fd = open(file, O_RDWR, 0644); if (fd < 0) { - printf("failed to open(%s): rc = %d (%s)\n", + printf("failed to open(%s): rc = %d (%s)\n", file, fd, strerror(errno)); t_unlink(file); t_rmdir(path); @@ -1294,22 +1322,24 @@ int t55(char *name) } close(fd); - if (opt_verbose) { - printf("lmm_magic: 0x%08X\n", lum->lmm_magic); - printf("lmm_object_id: "LPX64"\n", lum->lmm_object_id); - printf("lmm_object_gr: "LPX64"\n", lum->lmm_object_gr); - printf("lmm_stripe_count: %u\n", (int)lum->lmm_stripe_count); - printf("lmm_stripe_size: %u\n", lum->lmm_stripe_size); - printf("lmm_stripe_pattern: %x\n", lum->lmm_pattern); - - for (index = 0; index < lum->lmm_stripe_count; index++) { - lo = lum->lmm_objects + index; - printf("object %d:\n", index); - printf("\tobject_gr: "LPX64"\n", lo->l_object_gr); - printf("\tobject_id: "LPX64"\n", lo->l_object_id); - printf("\tost_gen: %#x\n", lo->l_ost_gen); - printf("\tost_idx: %u\n", lo->l_ost_idx); - } + if (opt_verbose) { + printf("lmm_magic: 0x%08X\n", lum->lmm_magic); + printf("lmm_object_id: "LPX64"\n", + lmm_oi_id(&lum->lmm_oi)); + printf("lmm_object_seq: "LPX64"\n", + lmm_oi_seq(&lum->lmm_oi)); + printf("lmm_stripe_count: %u\n", (int)lum->lmm_stripe_count); + printf("lmm_stripe_size: %u\n", lum->lmm_stripe_size); + printf("lmm_stripe_pattern: %x\n", lum->lmm_pattern); + + for (index = 0; index < lum->lmm_stripe_count; index++) { + lo = lum->lmm_objects + index; + printf("object %d:\n", index); + printf("\tobject_oid: "DOSTID"\n", + POSTID(&lo->l_ost_oi)); + printf("\tost_gen: %#x\n", lo->l_ost_gen); + printf("\tost_idx: %u\n", lo->l_ost_idx); + } } if (lum->lmm_magic != LOV_USER_MAGIC || @@ -1337,11 +1367,11 @@ int t55(char *name) */ int t56(char *name) { - int fd; - size_t nbytes; - off_t basep = 0; - ssize_t rc = 0; - struct dirent dir; + int fd; + size_t nbytes; + off_t basep = 0; + long rc = 0; + struct dirent64 dir; ENTER("getdirentries should fail if nbytes is too small"); @@ -1354,13 +1384,14 @@ int t56(char *name) rc = getdirentries(fd, (char *)&dir, nbytes, &basep); if (rc != -1) { - printf("Test failed: getdirentries returned %ld\n", rc); + printf("Test failed: getdirentries returned %lld\n", + (long long)rc); t_close(fd); return -1; } if (errno != EINVAL) { - printf("Test failed: getdirentries returned %ld but errno is set" - " to %d (should be EINVAL)\n", rc, errno); + printf("Test failed: getdirentries returned %lld but errno is " + "set to %d (should be EINVAL)\n", (long long)rc, errno); t_close(fd); return -1; } @@ -1376,8 +1407,8 @@ extern void __liblustre_cleanup_(void); void usage(char *cmd) { printf("\n" - "usage: %s [--only {test}] --target mgsnid:/fsname\n", - cmd); + "usage: %s [-o test][-e test][-v] --target mgsnid:/fsname\n", + cmd); printf(" %s --dumpfile dumpfile\n", cmd); exit(-1); } @@ -1423,21 +1454,28 @@ struct testlist { int main(int argc, char * const argv[]) { struct testlist *test; - int opt_index, c, rc = 0, numonly = 0; - char *only[100]; + int opt_index, c, rc = 0, numonly = 0, numexcept = 0; + char *only[100], *except[100]; static struct option long_opts[] = { {"dumpfile", 1, 0, 'd'}, {"only", 1, 0, 'o'}, + {"except", 1, 0, 'e'}, {"target", 1, 0, 't'}, {"verbose", 1, 0, 'v'}, {0, 0, 0, 0} }; - while ((c = getopt_long(argc, argv, "d:o:t:v", long_opts, &opt_index)) != -1) { + while ((c = getopt_long(argc, argv, "d:e:o:t:v", long_opts, &opt_index)) != -1) { switch (c) { case 'd': setenv(ENV_LUSTRE_DUMPFILE, optarg, 1); break; + case 'e': + if (numexcept == 0) + printf("Not running test(s): "); + printf("%s ", optarg); + except[numexcept++] = optarg; + break; case 'o': if (numonly == 0) printf("Only running test(s): "); @@ -1467,7 +1505,7 @@ int main(int argc, char * const argv[]) __liblustre_setup_(); - buf_size = _npages * PAGE_SIZE; + buf_size = _npages * CFS_PAGE_SIZE; if (opt_verbose) printf("allocating %d bytes buffer\n", buf_size); buf_alloc = calloc(1, buf_size); @@ -1478,14 +1516,35 @@ int main(int argc, char * const argv[]) for (test = testlist; test->test != NULL; test++) { int run = 1, i; + int len, olen; - if (numonly > 0) { - int len; + if (numexcept > 0) { + len = strlen(test->name); + for (i = 0; i < numexcept; i++) { + olen = strlen(except[i]); + + if (len < olen) + continue; + if (strncmp(except[i], test->name, olen) == 0) { + switch(test->name[olen]) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + break; + default: + run = 0; + break; + } + } + } + } + + if (numonly > 0) { run = 0; len = strlen(test->name); for (i = 0; i < numonly; i++) { - int olen = strlen(only[i]); + olen = strlen(only[i]); if (len < olen) continue;