static int wait_badstatus(void *ptr, const char *desc) { pid_t pid, rv; int x; int result; report_begin(desc); pid = fork(); if (pid<0) { report_warn("fork failed"); report_aborted(&result); return result; } if (pid==0) { exit(0); } rv = waitpid(pid, ptr, 0); result = report_check(rv, errno, EFAULT); waitpid(pid, &x, 0); return result; }
static int wait_parent(void) { pid_t mypid, childpid, rv; int x; int result; report_begin("wait for parent"); report_hassubs(); mypid = getpid(); childpid = fork(); if (childpid<0) { report_warn("can't fork"); report_aborted(&result); return result; } if (childpid==0) { /* Child. Wait for parent. */ rv = waitpid(mypid, &x, 0); report_beginsub("from child:"); report_survival(rv, errno, &result); _exit(0); } rv = waitpid(mypid, &x, 0); report_beginsub("from parent:"); report_survival(rv, errno, &result); return result; }
static int wait_nullstatus(void) { pid_t pid, rv; int x; int result; report_begin("wait with NULL status"); pid = fork(); if (pid<0) { report_warn("fork failed"); report_aborted(&result); return result; } if (pid==0) { exit(0); } /* POSIX explicitly says passing NULL for status is allowed */ rv = waitpid(pid, NULL, 0); result = report_check(rv, errno, 0); waitpid(pid, &x, 0); return result; }
static int wait_unaligned(void) { pid_t pid, rv; int x; int status[2]; /* will have integer alignment */ char *ptr; int result; report_begin("wait with unaligned status"); pid = fork(); if (pid<0) { report_warn("fork failed"); report_aborted(&result); return result; } if (pid==0) { exit(0); } /* start with proper integer alignment */ ptr = (char *)(&status[0]); /* generate improper alignment on platforms with restrictions */ ptr++; rv = waitpid(pid, (int *)ptr, 0); report_survival(rv, errno, &result); if (rv<0) { waitpid(pid, &x, 0); } return result; }
static int wait_badflags(void) { pid_t pid, rv; int x; int result; report_begin("wait with bad flags"); pid = fork(); if (pid<0) { report_warn("fork failed"); report_aborted(&result); return result; } if (pid==0) { exit(0); } rv = waitpid(pid, &x, 309429); result = report_check(rv, errno, EINVAL); waitpid(pid, &x, 0); return result; }
int create_testlink(void) { int rv; rv = symlink("blahblah", TESTLINK); if (rv<0) { report_warn("making symlink %s failed", TESTLINK); return -1; } return 0; }
int reopen_testfile(int openflags) { int fd; fd = open(TESTFILE, openflags, 0664); if (fd < 0) { report_warn("reopening %s: failed", TESTFILE); return -1; } return fd; }
int open_testfile(const char *string) { int fd, rv; size_t len; fd = open(TESTFILE, O_RDWR|O_CREAT|O_TRUNC, 0664); if (fd<0) { report_warn("creating %s: failed", TESTFILE); return -1; } if (string) { len = strlen(string); rv = write(fd, string, len); if (rv<0) { report_warn("write to %s failed", TESTFILE); close(fd); remove(TESTFILE); return -1; } if ((unsigned)rv != len) { report_warn("write to %s got short count", TESTFILE); close(fd); remove(TESTFILE); return -1; } rv = lseek(fd, 0, SEEK_SET); if (rv<0) { report_warn("rewind of %s failed", TESTFILE); close(fd); remove(TESTFILE); return -1; } } return fd; }
int create_testfile(void) { int fd, rv; fd = open_testfile(NULL); if (fd<0) { return -1; } rv = close(fd); if (rv<0) { report_warn("closing %s failed", TESTFILE); return -1; } return 0; }
/* * Note: unlike everything else this calls skipped/aborted, because * otherwise it has to communicate to the caller which to call and * that's a pain. */ int create_testdir(void) { int rv; rv = mkdir(TESTDIR, 0775); if (rv<0) { if (errno == ENOSYS) { report_saw_enosys(); report_warnx("mkdir unimplemented; cannot run test"); report_skipped(); } else { report_warn("mkdir %s failed", TESTDIR); report_aborted(); } return -1; } return 0; }
static int lseek_fd_device(void) { int fd, rv; int result; report_begin("lseek on device"); fd = open("null:", O_RDONLY); if (fd<0) { report_warn("opening null: failed"); report_aborted(&result); return result; } rv = lseek(fd, 309, SEEK_SET); result = report_check(rv, errno, ESPIPE); close(fd); return result; }
static int lseek_file_stdin(void) { int fd, fd2, rv, status; const char slogan[] = "There ain't no such thing as a free lunch"; size_t len = strlen(slogan); pid_t pid; int result = 0; report_begin("lseek stdin when open on file"); /* fork so we don't affect our own stdin */ pid = fork(); if (pid<0) { report_warn("fork failed"); report_aborted(&result); return result; } else if (pid!=0) { /* parent */ rv = waitpid(pid, &status, 0); if (rv<0) { report_warn("waitpid failed"); report_aborted(&result); } if (WIFSIGNALED(status)) { report_warnx("subprocess exited with signal %d", WTERMSIG(status)); report_aborted(&result); } else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { report_warnx("subprocess exited with code %d", WEXITSTATUS(status)); report_aborted(&result); } return result; } /* child */ fd = open_testfile(NULL); if (fd<0) { _exit(0); } /* * Move file to stdin. * Use stdin (rather than stdout or stderr) to maximize the * chances of detecting any special-case handling of fds 0-2. * (Writing to stdin is fine as long as it's open for write, * and it will be.) */ fd2 = dup2(fd, STDIN_FILENO); if (fd2<0) { report_warn("dup2 to stdin failed"); close(fd); remove(TESTFILE); _exit(1); } if (fd2 != STDIN_FILENO) { report_warn("dup2 returned wrong file handle"); close(fd); remove(TESTFILE); _exit(1); } close(fd); rv = write(STDIN_FILENO, slogan, len); if (rv<0) { report_warn("write to %s (via stdin) failed", TESTFILE); remove(TESTFILE); _exit(1); } if ((unsigned)rv != len) { report_warnx("write to %s (via stdin) got short count", TESTFILE); remove(TESTFILE); _exit(1); } /* blah */ report_skipped(&result); rv = lseek(STDIN_FILENO, 0, SEEK_SET); report_begin("try 1: SEEK_SET"); result = report_check(rv, errno, 0); rv = lseek(STDIN_FILENO, 0, SEEK_END); report_begin("try 2: SEEK_END"); result = report_check(rv, errno, 0); remove(TESTFILE); _exit(0); }
static int lseek_loc_pasteof(void) { const char *message = "blahblah"; int fd; off_t pos; int result; report_begin("seek past/to EOF"); fd = open_testfile(message); if (fd<0) { report_aborted(&result); return result; } pos = lseek(fd, 5340, SEEK_SET); if (pos == -1) { report_warn("lseek past EOF failed"); report_failure(&result); goto out; } if (pos != 5340) { report_warnx("lseek to 5340 got offset %lld", (long long) pos); report_failure(&result); goto out; } pos = lseek(fd, -50, SEEK_CUR); if (pos == -1) { report_warn("small seek beyond EOF failed"); report_failure(&result); goto out; } if (pos != 5290) { report_warnx("SEEK_CUR to 5290 got offset %lld", (long long) pos); report_failure(&result); goto out; } pos = lseek(fd, 0, SEEK_END); if (pos == -1) { report_warn("seek to EOF failed"); report_failure(&result); goto out; } if (pos != (off_t) strlen(message)) { report_warnx("seek to EOF got %lld (should be %zu)", (long long) pos, strlen(message)); report_failure(&result); goto out; } report_passed(&result); out: close(fd); remove(TESTFILE); return result; }
static int wait_siblings(void) { pid_t pids[2]; int rv, fd, semfd, x; int bad = 0; char semname[32]; int result; /* This test may also blow up if FS synchronization is substandard */ report_begin("siblings wait for each other"); report_hassubs(); snprintf(semname, sizeof(semname), "sem:badcall.%d", (int)getpid()); semfd = open(semname, O_WRONLY|O_CREAT|O_TRUNC, 0664); if (semfd < 0) { report_warn("can't make semaphore"); report_aborted(&result); return result; } fd = open_testfile(NULL); if (fd<0) { report_aborted(&result); close(semfd); remove(semname); return result; } pids[0] = fork(); if (pids[0]<0) { report_warn("can't fork"); report_aborted(&result); close(fd); close(semfd); remove(semname); return result; } if (pids[0]==0) { close(fd); close(semfd); wait_siblings_child(semname); _exit(0); } pids[1] = fork(); if (pids[1]<0) { report_warn("can't fork"); report_aborted(&result); /* abandon the other child process :( */ close(fd); close(semfd); remove(semname); return result; } if (pids[1]==0) { close(fd); close(semfd); wait_siblings_child(semname); _exit(0); } rv = write(fd, pids, sizeof(pids)); if (rv < 0) { report_warn("write error on %s", TESTFILE); report_aborted(&result); /* abandon child procs :( */ close(fd); close(semfd); remove(semname); return result; } if (rv != (int)sizeof(pids)) { report_warnx("write error on %s: short count", TESTFILE); report_aborted(&result); /* abandon child procs :( */ close(fd); close(semfd); remove(semname); return result; } /* gate the child procs */ rv = write(semfd, " ", 2); if (rv < 0) { report_warn("%s: write", semname); bad = 1; } report_beginsub("overall"); rv = waitpid(pids[0], &x, 0); if (rv<0) { report_warn("error waiting for child 0 (pid %d)", pids[0]); bad = 1; } rv = waitpid(pids[1], &x, 0); if (rv<0) { report_warn("error waiting for child 1 (pid %d)", pids[1]); bad = 1; } if (bad) { /* XXX: aborted, or failure, or what? */ report_aborted(&result); } else { report_passed(&result); } close(fd); close(semfd); remove(semname); remove(TESTFILE); return result; }
static int wait_siblings_child(const char *semname) { pid_t pids[2], mypid, otherpid; int rv, fd, semfd, x; char c; int result; mypid = getpid(); /* * Get our own handle for the semaphore, in case naive * file-level synchronization causes concurrent use to * deadlock. */ semfd = open(semname, O_RDONLY); if (semfd < 0) { report_warn("child process (pid %d) can't open %s", mypid, semname); } else { if (read(semfd, &c, 1) < 0) { report_warn("in pid %d: %s: read", mypid, semname); } close(semfd); } fd = open(TESTFILE, O_RDONLY); if (fd<0) { report_warn("child process (pid %d) can't open %s", mypid, TESTFILE); return FAILED; } /* * In case the semaphore above didn't work, as a backup * busy-wait until the parent writes the pids into the * file. If the semaphore did work, this shouldn't loop. */ do { rv = lseek(fd, 0, SEEK_SET); if (rv<0) { report_warn("child process (pid %d) lseek error", mypid); return FAILED; } rv = read(fd, pids, sizeof(pids)); if (rv<0) { report_warn("child process (pid %d) read error", mypid); return FAILED; } } while (rv < (int)sizeof(pids)); if (mypid==pids[0]) { otherpid = pids[1]; } else if (mypid==pids[1]) { otherpid = pids[0]; } else { report_warn("child process (pid %d) got garbage in comm file", mypid); return FAILED; } close(fd); rv = waitpid(otherpid, &x, 0); report_beginsub("sibling (pid %d)", mypid); report_survival(rv, errno, &result); return result; }