#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <spawn.h>
#include <spawn_private.h>
#include <sys/wait.h>
#include <unistd.h>
#include "subsystem_test.h"
#include <darwintest.h>
#include <darwintest_utils.h>
#define RANDOM_STRING_LEN 33
#define HELPER_PATH "./subsystem_test_helper"
static bool
_create_file(char * const filepath)
{
bool success = false;
int fd = open(filepath, O_CREAT | O_EXCL, 0666);
if (fd >= 0) {
close(fd);
success = true;
}
return success;
}
static void
_generate_random_string(char * buf, size_t buf_len)
{
static char _alphanumeric[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
size_t cur_byte = 0;
if (buf_len == 0) {
return;
}
for (cur_byte = 0; ((buf_len - cur_byte) > 1); cur_byte++) {
buf[cur_byte] = _alphanumeric[rand() % (sizeof(_alphanumeric) - 1)];
}
buf[cur_byte] = 0;
return;
}
static int
_check_file_contents(char * const filepath, char * const buf, size_t buf_len)
{
int result = 1;
int fd = -1;
char file_buf[buf_len];
fd = open(filepath, O_RDONLY);
if (fd >= 0) {
read(fd, file_buf, buf_len);
close(fd);
result = memcmp(buf, file_buf, buf_len);
}
return result;
}
static int
_spawn_and_wait(char ** args, posix_spawnattr_t *attr)
{
int pid;
int status;
if (posix_spawn(&pid, args[0], NULL, attr, args, NULL)) {
return -1;
}
if (waitpid(pid, &status, 0) < 0) {
return -1;
}
if (WIFEXITED(status) && (WEXITSTATUS(status) == 0)) {
return 0;
}
return -1;
}
T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
T_DECL(subsystem,
"Test the subsystem-related functions",
T_META_CHECK_LEAKS(false))
{
int result = 0;
int pid = 0;
posix_spawnattr_t attr = NULL;
char file_name[RANDOM_STRING_LEN];
char overflow_file_name[PATH_MAX - RANDOM_STRING_LEN];
char subsystem_name[RANDOM_STRING_LEN];
char file_path[PATH_MAX];
char subsystem_path[PATH_MAX];
char subsystem_tmp_path[PATH_MAX];
char subsystem_file_path[PATH_MAX];
char overflow_file_path[PATH_MAX];
char overflow_subsystem_file_path[PATH_MAX];
char * args[] = { HELPER_PATH, HELPER_BEHAVIOR_NOT_SET, overflow_file_path, "", NULL};
sranddev();
_generate_random_string(file_name, sizeof(file_name));
_generate_random_string(overflow_file_name, sizeof(overflow_file_name));
_generate_random_string(subsystem_name, sizeof(subsystem_name));
sprintf(file_path, "/tmp/%s", file_name);
sprintf(overflow_file_path, "/tmp/%s", overflow_file_name);
sprintf(subsystem_path, "/tmp/%s", subsystem_name);
sprintf(subsystem_tmp_path, "%s/tmp", subsystem_path);
sprintf(subsystem_file_path, "%s/%s", subsystem_path, file_path);
T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_path, 0777), "Create subsystem directory");
T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(subsystem_tmp_path, 0777), "Create subsystem /tmp/ directory");
T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_init(&attr), "posix_spawnattr_init");
args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no subsystem");
args[1] = HELPER_BEHAVIOR_STAT_NONE;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no subsystem");
T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_set_subsystem_root_path_np(&attr, subsystem_path), "Set subsystem root path");
args[1] = HELPER_BEHAVIOR_OPEN_OVERFLOW;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with overflow");
args[1] = HELPER_BEHAVIOR_STAT_OVERFLOW;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with overflow");
args[1] = HELPER_BEHAVIOR_OPEN_O_CREAT;
args[2] = file_path;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "open_with_subsystem with O_CREAT");
args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), -1, "open_with_subsystem with no file");
args[1] = HELPER_BEHAVIOR_STAT_NONE;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with no file");
T_QUIET; T_ASSERT_TRUE(_create_file(subsystem_file_path), "Create subsystem file");
args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
args[3] = "with subsystem file";
result = _spawn_and_wait(args, &attr);
if (!result) {
result = _check_file_contents(subsystem_file_path, args[3], strlen(args[3]));
}
T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with subsystem file");
args[1] = HELPER_BEHAVIOR_STAT_NOT_MAIN;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with subsystem file");
T_QUIET; T_ASSERT_TRUE(_create_file(file_path), "Create main file");
args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
args[3] = "with both files";
result = _spawn_and_wait(args, &attr);
if (!result) {
result = _check_file_contents(file_path, args[3], strlen(args[3]));
}
T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with both files");
args[1] = HELPER_BEHAVIOR_STAT_MAIN;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with both files");
T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(subsystem_file_path), "Delete subsystem file");
args[1] = HELPER_BEHAVIOR_OPEN_AND_WRITE;
args[3] = "with main file";
result = _spawn_and_wait(args, &attr);
if (!result) {
result = _check_file_contents(file_path, args[3], strlen(args[3]));
}
T_ASSERT_EQ_INT(result, 0, "open_with_subsystem with main file");
args[1] = HELPER_BEHAVIOR_STAT_MAIN;
T_ASSERT_EQ_INT(_spawn_and_wait(args, &attr), 0, "stat_with_subsystem with main file");
T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(file_path), "Delete main file");
T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_tmp_path), "Remove subsystem /tmp/ directory");
T_QUIET; T_EXPECT_POSIX_SUCCESS(rmdir(subsystem_path), "Remove subsystem directory");
T_QUIET; T_ASSERT_POSIX_SUCCESS(posix_spawnattr_destroy(&attr), "posix_spawnattr_destroy");
}