#include <stdlib.h>
#include <err.h>
#include <unistd.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/sysmacros.h>
#include <sys/debug.h>
#include <limits.h>
#include <port.h>
typedef struct syncfs_enosys {
int (*se_open)(const struct syncfs_enosys *);
const char *se_path;
} syncfs_enosys_t;
static int
syncfs_open_file(const syncfs_enosys_t *test)
{
int fd = open(test->se_path, O_RDONLY);
if (fd < 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to open file %s",
test->se_path);
}
return (fd);
}
static int
syncfs_open_socket(const syncfs_enosys_t *test)
{
struct sockaddr_in in;
int fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to create basic "
"socket");
}
(void) memset(&in, 0, sizeof (in));
if (bind(fd, (struct sockaddr *)&in, sizeof (in)) != 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to bind socket");
}
return (fd);
}
static int
syncfs_open_uds(const syncfs_enosys_t *test)
{
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to create UDS");
}
return (fd);
}
static int
syncfs_open_pipe(const syncfs_enosys_t *test)
{
int fds[2];
if (pipe(fds) != 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to create pipe");
}
VERIFY0(close(fds[1]));
return (fds[0]);
}
static int
syncfs_open_port(const syncfs_enosys_t *test)
{
int fd = port_create();
if (fd < 0) {
err(EXIT_FAILURE, "TEST FAILED: failed to create event port");
}
return (fd);
}
static const syncfs_enosys_t syncfs_enosys[] = {
{ syncfs_open_file, "/system/boot" },
{ syncfs_open_file, "/system/object" },
{ syncfs_open_file, "/proc/self/psinfo" },
{ syncfs_open_file, "/dev/tcp" },
{ syncfs_open_file, "/dev/null" },
{ syncfs_open_file, "/dev/net" },
{ syncfs_open_file, "/etc/dfs/sharetab" },
{ syncfs_open_socket, "localhost socket" },
{ syncfs_open_uds, "UDS socket" },
{ syncfs_open_pipe, "pipe" },
{ syncfs_open_file, "/var/run/name_service_door" },
{ syncfs_open_port, "event port" },
};
static const int syncfs_badfs[] = { -1, STDERR_FILENO + 1, INT_MAX - 1,
0x7777, -0x7777 };
static bool
syncfs_fail(const char *desc, int fd, int exp_err)
{
int ret = syncfs(fd);
if (ret != -1) {
warnx("TEST FAILED: %s: syncfs succeeded, but expected "
"failure", desc);
return (false);
}
if (errno != exp_err) {
warnx("TEST FAILED: %s: syncfs returned %s, expected %s",
desc, strerrorname_np(ret), strerrorname_np(exp_err));
return (false);
}
(void) printf("TEST PASSED: %s\n", desc);
return (true);
}
static bool
syncfs_pass(const char *path)
{
bool ret = true;
int fd = open(path, O_RDONLY);
if (fd < 0) {
err(EXIT_FAILURE, "failed to open %s", path);
}
if (syncfs(fd) != 0) {
warnx("TEST FAILED: syncfs failed with %s on %s",
strerrorname_np(errno), path);
ret = false;
} else {
(void) printf("TEST PASSED: syncfs returned 0 on %s\n", path);
}
VERIFY0(close(fd));
return (ret);
}
int
main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
closefrom(STDERR_FILENO + 1);
for (size_t i = 0; i < ARRAY_SIZE(syncfs_badfs); i++) {
char msg[PATH_MAX];
(void) snprintf(msg, sizeof (msg), "Invalid file descriptor "
"returns EBADF (%zu)", i);
if (!syncfs_fail(msg, syncfs_badfs[i], EBADF)) {
ret = EXIT_FAILURE;
}
}
for (size_t i = 0; i < ARRAY_SIZE(syncfs_enosys); i++) {
char msg[PATH_MAX];
int fd = syncfs_enosys[i].se_open(&syncfs_enosys[i]);
(void) snprintf(msg, sizeof (msg), "Unsupported fs returns "
"ENOSYS: %s", syncfs_enosys[i].se_path);
if (!syncfs_fail(msg, fd, ENOSYS)) {
ret = EXIT_FAILURE;
}
VERIFY0(close(fd));
}
if (!syncfs_pass("/var/run")) {
ret = EXIT_FAILURE;
}
for (int i = 1; i < argc; i++) {
if (!syncfs_pass(argv[i])) {
ret = EXIT_FAILURE;
}
}
if (ret == EXIT_SUCCESS) {
(void) printf("All tests completed successfully\n");
}
return (ret);
}