#include #include #include #include #include #include #include pid_t pid; int fds[2]; int *status; int nfailed = 0; int nskipped = 0; int npassed = 0; char *readbuf = NULL; int readbuf_sz = 0, readbuf_used = 0; int die = 0; #define PASSED 0 #define SKIPPED 1 #define FAILED 2 void handler( int s ) { signal( s, SIG_DFL ); kill( pid, s ); die = s; } void dump() { write(1, readbuf, readbuf_used); } void clear() { readbuf_used = 0; } void drain() { int sz; char buf[2048]; while (1) { sz = read(fds[1], buf, 2048); if (sz <= 0) return; if (readbuf_used + sz >= readbuf_sz) { readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096; readbuf = realloc(readbuf, readbuf_sz); } if (!readbuf) exit(205); memcpy(readbuf + readbuf_used, buf, sz); readbuf_used += sz; } } void passed(int i, char *f) { ++ npassed; status[i] = PASSED; printf("passed.\n"); } void skipped(int i, char *f) { ++ nskipped; status[i] = SKIPPED; printf("skipped.\n"); } void failed(int i, char *f, int st) { ++ nfailed; status[i] = FAILED; if(die == 2) { printf("interrupted.\n"); return; } printf("FAILED.\n"); printf("-- FAILED %s ------------------------------------\n", f); dump(); printf("-- FAILED %s (end) ------------------------------\n", f); } void run(int i, char *f) { pid = fork(); if (pid < 0) { perror("Fork failed."); exit(201); } else if (pid == 0) { close(0); dup2(fds[0], 1); dup2(fds[0], 2); execlp("bash", "bash", f, NULL); perror("execlp"); fflush(stderr); _exit(202); } else { char buf[128]; snprintf(buf, 128, "%s ...", f); buf[127] = 0; printf("Running %-40s ", buf); fflush(stdout); int st, w; while ((w = waitpid(pid, &st, WNOHANG)) == 0) { drain(); usleep(20000); } if (w != pid) { perror("waitpid"); exit(206); } drain(); if (WIFEXITED(st)) { if (WEXITSTATUS(st) == 0) { passed(i, f); } else if (WEXITSTATUS(st) == 200) { skipped(i, f); } else { failed(i, f, st); } } else { failed(i, f, st); } clear(); } } int main(int argc, char **argv) { int i; status = alloca(sizeof(int)*argc); if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) { perror("socketpair"); return 201; } if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) { perror("fcntl on socket"); return 202; } /* set up signal handlers */ for (i = 0; i <= 32; ++i) { if (i == SIGCHLD || i == SIGWINCH || i == SIGURG) continue; signal(i, handler); } /* run the tests */ for (i = 1; i < argc; ++ i) { run(i, argv[i]); if (die) break; } printf("\n## %d tests: %d OK, %d failed, %d skipped\n", npassed + nfailed + nskipped, npassed, nfailed, nskipped); /* print out a summary */ if (nfailed || nskipped) { for (i = 1; i < argc; ++ i) { switch (status[i]) { case FAILED: printf("FAILED: %s\n", argv[i]); break; case SKIPPED: printf("skipped: %s\n", argv[i]); break; } } printf("\n"); return nfailed > 0 || die; } return !die; }