#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include "live.h" enum { Failtimeout = 4000, }; static int waitfailed(Daemon *d, char *badmap) { struct pollfd pfd; int n, status; int64_t deadline; status = 0; deadline = nowms() + Failtimeout; for(;;){ n = waitpid(d->pid, &status, WNOHANG); if(n == d->pid){ d->pid = -1; readerrors(d); break; } if(n < 0 && errno == EINTR) continue; if(n < 0){ if(errno == ECHILD) d->pid = -1; return fail("waitpid: %s", strerror(errno)); } n = leftms(deadline); if(n == 0) return fail("daemon did not exit after map initialization failure"); pfd.fd = d->errfd; pfd.events = POLLIN|POLLHUP; pfd.revents = 0; n = poll(&pfd, 1, n); if(n < 0 && errno == EINTR) continue; if(n < 0) return fail("poll daemon: %s", strerror(errno)); if(n > 0) readerrors(d); } if(!WIFEXITED(status) || WEXITSTATUS(status) == 0) return fail("daemon map failure had wait status %#x", status); if(strstr(d->err, "can't open") == NULL || strstr(d->err, badmap) == NULL) return fail("daemon did not report the missing map directory"); return 1; } static int emptydir(char *path) { DIR *dir; struct dirent *de; int empty; dir = opendir(path); if(dir == NULL) return fail("open %s: %s", path, strerror(errno)); empty = 1; errno = 0; while((de = readdir(dir)) != NULL) if(strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0){ fail("unexpected endpoint %s/%s", path, de->d_name); empty = 0; } if(errno != 0){ fail("read %s: %s", path, strerror(errno)); empty = 0; } if(closedir(dir) < 0){ fail("close %s: %s", path, strerror(errno)); empty = 0; } return empty; } static int checkendpoints(Live *l) { struct stat st; if(lstat(l->socket, &st) == 0) return fail("IPC endpoint exists after failed startup: %s", l->socket); if(errno != ENOENT) return fail("lstat IPC endpoint: %s", strerror(errno)); return emptydir(l->runtime) && emptydir(l->bus); } int main(int argc, char **argv) { Daemon daemon; Live live; char badmap[320]; int ok; testname = "daemon_failure_test"; if(argc != 2){ fprintf(stderr, "usage: daemon_failure_test strans\n"); return 2; } daemoninit(&daemon, "daemon"); ok = livesetup(&live, "failure"); if(ok && snprintf(badmap, sizeof badmap, "%s/missing-map", live.root) >= (int)sizeof badmap) ok = fail("temporary path is too long"); if(ok) ok = startdaemon(&live, &daemon, argv[1], badmap); if(ok) ok = waitfailed(&daemon, badmap) && checkendpoints(&live); if(!killdaemon(&daemon, NULL)) ok = 0; if(!closeerrors(&daemon)) ok = 0; if(!liveclean(&live)) ok = 0; if(!ok){ showerrors(&daemon); return 1; } printf("failed daemon startup leaves no endpoints: ok\n"); return 0; }