/* * Copyright (C) 2014 Philippe Gerum . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include int smokey_int(const char *s, struct smokey_arg *arg) { char *name, *p; int ret; ret = sscanf(s, "%m[_a-z]=%m[^\n]", &name, &p); if (ret != 2 || !(isdigit(*p) || *p == '-')) return 0; ret = !strcmp(name, arg->name); if (ret) arg->u.n_val = atoi(p); free(p); free(name); return ret; } int smokey_bool(const char *s, struct smokey_arg *arg) { int ret; ret = smokey_int(s, arg); if (ret) { arg->u.n_val = !!arg->u.n_val; return 1; } if (strcmp(s, arg->name) == 0) { arg->u.n_val = 1; return 1; } return 0; } int smokey_string(const char *s, struct smokey_arg *arg) { char *name, *p; int ret; ret = sscanf(s, "%m[_a-z]=%m[^\n]", &name, &p); if (ret != 2) return 0; ret = !strcmp(name, arg->name); if (ret) arg->u.s_val = p; else free(p); free(name); return ret; } int smokey_size(const char *s, struct smokey_arg *arg) { char *name, *p; int ret; ret = sscanf(s, "%m[_a-z]=%m[^\n]", &name, &p); if (ret != 2) return 0; ret = !strcmp(name, arg->name); if (ret) { arg->u.l_val = get_mem_size(p); if (arg->u.l_val == 0) ret = 0; } free(p); free(name); return ret; } int smokey_parse_args(struct smokey_test *t, int argc, char *const argv[]) { int matched = 0, n, ac; struct smokey_arg *arg; for (arg = t->args, ac = 0; arg->name && ac < t->nargs; arg++, ac++) { for (n = 1; n < argc; n++) { arg->matched = !!arg->parser(argv[n], arg); if (arg->matched) { matched++; break; } } } return matched; } struct smokey_arg *smokey_lookup_arg(struct smokey_test *t, const char *name) { struct smokey_arg *arg = NULL; int ac; for (arg = t->args, ac = 0; arg->name && ac < t->nargs; arg++, ac++) { if (strcmp(arg->name, name) == 0) return arg; } /* Assume this is fatal. */ panic("test %s has no argument \"%s\"", t->name, name); } void smokey_note(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (smokey_verbose_mode) { __RT(vfprintf(stdout, fmt, ap)); __RT(fprintf(stdout, "\n")); } va_end(ap); } void smokey_vatrace(const char *fmt, va_list ap) { if (smokey_verbose_mode > 1) { __RT(vfprintf(stdout, fmt, ap)); __RT(fprintf(stdout, "\n")); } } void smokey_trace(const char *fmt, ...) { va_list ap; va_start(ap, fmt); smokey_vatrace(fmt, ap); va_end(ap); } void __smokey_warning(const char *file, int lineno, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (smokey_verbose_mode) { __RT(fprintf(stderr, "%s:%d, ", basename(file), lineno)); __RT(vfprintf(stderr, fmt, ap)); __RT(fprintf(stderr, "\n")); } va_end(ap); } int smokey_barrier_init(struct smokey_barrier *b) { pthread_mutexattr_t mattr; pthread_condattr_t cattr; int ret; b->signaled = 0; pthread_mutexattr_init(&mattr); pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL); pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE); pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_NONE); ret = __RT(pthread_mutex_init(&b->lock, &mattr)); pthread_mutexattr_destroy(&mattr); if (ret) return ret; pthread_condattr_init(&cattr); pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE); ret = __RT(pthread_cond_init(&b->barrier, &cattr)); pthread_condattr_destroy(&cattr); if (ret) __RT(pthread_mutex_destroy(&b->lock)); return ret; } void smokey_barrier_destroy(struct smokey_barrier *b) { __RT(pthread_cond_destroy(&b->barrier)); __RT(pthread_mutex_destroy(&b->lock)); } int smokey_barrier_wait(struct smokey_barrier *b) { int ret = 0; __RT(pthread_mutex_lock(&b->lock)); while (!b->signaled) { ret = __RT(pthread_cond_wait(&b->barrier, &b->lock)); if (ret) break; } __RT(pthread_mutex_unlock(&b->lock)); return ret; } int smokey_barrier_timedwait(struct smokey_barrier *b, struct timespec *ts) { int ret = 0; __RT(pthread_mutex_lock(&b->lock)); while (!b->signaled) { ret = __RT(pthread_cond_timedwait(&b->barrier, &b->lock, ts)); if (ret) break; } __RT(pthread_mutex_unlock(&b->lock)); return ret; } void smokey_barrier_release(struct smokey_barrier *b) { __RT(pthread_mutex_lock(&b->lock)); b->signaled = 1; __RT(pthread_cond_broadcast(&b->barrier)); __RT(pthread_mutex_unlock(&b->lock)); } int smokey_fork_exec(const char *path, const char *arg) { int wstatus = 0; pid_t pid; pid = do_fork(); switch (pid) { case -1: error(1, errno, "fork/vfork"); case 0: execlp(path, arg, NULL); error(1, errno, "execl %s", path); default: waitpid(pid, &wstatus, 0); } if WIFEXITED(wstatus) return WEXITSTATUS(wstatus); if WIFSIGNALED(wstatus) fprintf(stderr, "%s %s\n", strsignal(WTERMSIG(wstatus)), WCOREDUMP(wstatus) ? "(core dumped)" : ""); return 1; } #define SMOKEY_MOD_NUM 32 static char *smokey_modules[SMOKEY_MOD_NUM]; int smokey_modprobe(const char *name, bool silent) { char buffer[128]; int err, len, i, midx = -1; FILE *fp; if (!name) return -EINVAL; fp = fopen("/proc/modules", "r"); if (fp == NULL) return -errno; len = strlen(name); while (fgets(buffer, sizeof(buffer), fp)) { if (strncmp(buffer, name, len) == 0 && len < sizeof(buffer) && buffer[len] == ' ') { smokey_trace("%s module already loaded", name); fclose(fp); return 0; } } fclose(fp); for (i = 0; i < SMOKEY_MOD_NUM; i++) { if (!smokey_modules[i]) { midx = i; break; } } if (midx < 0) return -EFAULT; smokey_trace("%s module not there: modprobing", name); err = smokey_check_errno( snprintf(buffer, sizeof(buffer), "modprobe %s %s", name, silent ? "2>/dev/null" : "")); if (err < 0) return err; err = smokey_check_errno(system(buffer)); if (err < 0) return err; if (!WIFEXITED(err) || WEXITSTATUS(err) != 0) { if (!silent) smokey_warning("%s: abnormal exit", buffer); return -EINVAL; } smokey_modules[midx] = strdup(name); return err; } int smokey_rmmod(const char *name) { char buffer[128]; int i, midx = -1, err; if (!name) return -EINVAL; for (i = 0; i < SMOKEY_MOD_NUM; i++) { if (smokey_modules[i] && !strcmp(smokey_modules[i], name)) { midx = i; break; } } if (midx < 0) { smokey_trace("%s module was there on entry, keeping it", name); return 0; } smokey_trace("unloading %s module", name); err = smokey_check_errno( snprintf(buffer, sizeof(buffer), "rmmod %s", name)); if (err < 0) return err; err = smokey_check_errno(system(buffer)); if (err < 0) return err; if (!WIFEXITED(err) || WEXITSTATUS(err) != 0) { smokey_warning("%s: abnormal exit", buffer); return -EINVAL; } free(smokey_modules[midx]); smokey_modules[midx] = NULL; return err; }