static int read_scoreboard_header(pr_scoreboard_header_t *sch) { int res = 0; /* No interruptions, please. */ pr_signals_block(); /* NOTE: reading a struct from a file using read(2) -- bad (in general). */ while ((res = read(scoreboard_fd, sch, sizeof(pr_scoreboard_header_t))) != sizeof(pr_scoreboard_header_t)) { int rd_errno = errno; if (res == 0) { pr_signals_unblock(); errno = EIO; return -1; } if (errno == EINTR) { pr_signals_handle(); continue; } pr_signals_unblock(); errno = rd_errno; return -1; } pr_signals_unblock(); /* Note: these errors will most likely occur only for inetd-run daemons. * Standalone daemons erase the scoreboard on startup. */ if (sch->sch_magic != PR_SCOREBOARD_MAGIC) { pr_close_scoreboard(); return PR_SCORE_ERR_BAD_MAGIC; } if (sch->sch_version < PR_SCOREBOARD_VERSION) { pr_close_scoreboard(); return PR_SCORE_ERR_OLDER_VERSION; } if (sch->sch_version > PR_SCOREBOARD_VERSION) { pr_close_scoreboard(); return PR_SCORE_ERR_NEWER_VERSION; } return 0; }
END_TEST START_TEST (scoreboard_open_close_test) { int res; const char *dir = "/tmp/prt-scoreboard/", *path = "/tmp/prt-scoreboard/test", *mutex_path = "/tmp/prt-scoreboard/test.lck", *symlink_path = "/tmp/prt-scoreboard/symlink"; res = mkdir(dir, 0775); fail_unless(res == 0, "Failed to create directory '%s': %s", dir, strerror(errno)); res = chmod(dir, 0775); if (res < 0) { int xerrno = errno; (void) rmdir(dir); fail("Failed to set perms on '%s' to 0775': %s", dir, strerror(xerrno)); } res = pr_set_scoreboard(path); if (res < 0) { int xerrno = errno; (void) rmdir(dir); fail("Failed to set scoreboard to '%s': %s", path, strerror(xerrno)); } (void) unlink(path); (void) unlink(mutex_path); if (symlink(symlink_path, path) == 0) { res = pr_open_scoreboard(O_RDWR); if (res == 0) { (void) unlink(path); (void) unlink(mutex_path); (void) unlink(symlink_path); (void) rmdir(dir); fail("Unexpectedly opened symlink scoreboard"); } if (errno != EPERM) { int xerrno = errno; (void) unlink(symlink_path); (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); fail("Failed to set errno to EPERM (got %d)", xerrno); } (void) unlink(path); (void) unlink(mutex_path); (void) unlink(symlink_path); } res = pr_open_scoreboard(O_RDONLY); if (res == 0) { (void) unlink(path); (void) unlink(mutex_path); (void) rmdir(dir); fail("Unexpectedly opened scoreboard using O_RDONLY"); } if (errno != EINVAL) { int xerrno = errno; (void) unlink(symlink_path); (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); fail("Failed to set errno to EINVAL (got %d)", xerrno); } res = pr_open_scoreboard(O_RDWR); if (res < 0) { int xerrno = errno; (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); fail("Failed to open scoreboard: %s", strerror(xerrno)); } /* Now that we have a scoreboard, try opening it again using O_RDONLY. */ pr_close_scoreboard(FALSE); res = pr_open_scoreboard(O_RDONLY); if (res == 0) { (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); fail("Unexpectedly opened scoreboard using O_RDONLY"); } if (errno != EINVAL) { int xerrno = errno; (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); fail("Failed to set errno to EINVAL (got %d)", xerrno); } (void) unlink(mutex_path); (void) unlink(path); (void) rmdir(dir); }
END_TEST START_TEST (scoreboard_disabled_test) { register unsigned int i = 0; const char *paths[4] = { "/dev/null", "none", "off", NULL }; const char *path; for (path = paths[i]; path != NULL; path = paths[i++]) { int res; const char *field, *ok; pid_t scoreboard_pid; time_t scoreboard_uptime; pr_scoreboard_entry_t *score; res = pr_set_scoreboard(path); fail_unless(res == 0, "Failed set to scoreboard to '%s': %s", path, strerror(errno)); ok = PR_RUN_DIR "/proftpd.scoreboard"; path = pr_get_scoreboard(); fail_unless(path != NULL, "Failed to get scoreboard path: %s", strerror(errno)); fail_unless(strcmp(path, ok) == 0, "Expected path '%s', got '%s'", ok, path); res = pr_open_scoreboard(O_RDONLY); fail_unless(res == 0, "Failed to open '%s' scoreboard: %s", path, strerror(errno)); res = pr_scoreboard_scrub(); fail_unless(res == 0, "Failed to scrub '%s' scoreboard: %s", path, strerror(errno)); scoreboard_pid = pr_scoreboard_get_daemon_pid(); fail_unless(scoreboard_pid == 0, "Expected to get scoreboard PID 0, got %lu", (unsigned long) scoreboard_pid); scoreboard_uptime = pr_scoreboard_get_daemon_uptime(); fail_unless(scoreboard_uptime == 0, "Expected to get scoreboard uptime 0, got %lu", (unsigned long) scoreboard_uptime); res = pr_scoreboard_entry_add(); fail_unless(res == 0, "Failed to add entry to '%s' scoreboard: %s", path, strerror(errno)); score = pr_scoreboard_entry_read(); fail_unless(score == NULL, "Expected null entry"); field = pr_scoreboard_entry_get(PR_SCORE_CMD_ARG); fail_unless(field == NULL, "Expected null CMD_ARG field"); res = pr_scoreboard_entry_update(getpid(), PR_SCORE_CWD, "foo", NULL); fail_unless(res == 0, "Failed to update CWD field: %s", strerror(errno)); res = pr_scoreboard_entry_del(FALSE); fail_unless(res == 0, "Failed to delete entry from '%s' scoreboard: %s", path, strerror(errno)); res = pr_close_scoreboard(FALSE); fail_unless(res == 0, "Failed to close '%s' scoreboard: %s", path, strerror(errno)); /* Internal hack: even calling pr_set_scoreboard() with a NULL * argument will set the Scoreboard API internal flag back to true. */ pr_set_scoreboard(NULL); } }