#define _GNU_SOURCE
#include "test-common.h"
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <unistd.h>
int test_mknod(const char *base_path) {
char path[512];
struct stat st;
int result;
snprintf(path, sizeof(path), "%s/test_fifo_mknod", base_path);
unlink(path);
result = mknod(path, S_IFIFO | 0644, 0);
TEST_ASSERT_ERRNO(result == 0, "mknod FIFO creation should succeed");
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on FIFO should succeed");
TEST_ASSERT(S_ISFIFO(st.st_mode), "created node should be a FIFO");
TEST_ASSERT((st.st_mode & 0777) == 0644, "FIFO should have correct permissions");
unlink(path);
snprintf(path, sizeof(path), "%s/test_file_mknod", base_path);
unlink(path);
result = mknod(path, S_IFREG | 0600, 0);
TEST_ASSERT_ERRNO(result == 0, "mknod regular file creation should succeed");
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on regular file should succeed");
TEST_ASSERT(S_ISREG(st.st_mode), "created node should be a regular file");
TEST_ASSERT((st.st_mode & 0777) == 0600, "regular file should have correct permissions");
unlink(path);
snprintf(path, sizeof(path), "%s/test.txt", base_path);
result = mknod(path, S_IFREG | 0644, 0);
TEST_ASSERT(result < 0, "mknod on existing file should fail");
TEST_ASSERT(errno == EEXIST, "errno should be EEXIST for existing path");
snprintf(path, sizeof(path), "%s/nonexistent_dir/test_mknod", base_path);
result = mknod(path, S_IFREG | 0644, 0);
TEST_ASSERT(result < 0, "mknod in non-existent directory should fail");
TEST_ASSERT(errno == ENOENT, "errno should be ENOENT for non-existent directory");
snprintf(path, sizeof(path), "%s/test_fifo_perms", base_path);
unlink(path);
result = mknod(path, S_IFIFO | 0755, 0);
TEST_ASSERT_ERRNO(result == 0, "mknod FIFO with 0755 should succeed");
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on FIFO should succeed");
TEST_ASSERT((st.st_mode & 0777) == 0755, "FIFO should have 0755 permissions");
unlink(path);
char subdir_path[512];
snprintf(subdir_path, sizeof(subdir_path), "%s/subdir", base_path);
mkdir(subdir_path, 0755);
snprintf(path, sizeof(path), "%s/subdir/test_fifo_subdir", base_path);
unlink(path);
result = mknod(path, S_IFIFO | 0644, 0);
TEST_ASSERT_ERRNO(result == 0, "mknod FIFO in subdirectory should succeed");
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on FIFO in subdirectory should succeed");
TEST_ASSERT(S_ISFIFO(st.st_mode), "created node in subdir should be a FIFO");
unlink(path);
snprintf(path, sizeof(path), "%s/test_chrdev", base_path);
unlink(path);
result = mknod(path, S_IFCHR | 0666, makedev(1, 3));
if (result < 0 && (errno == EPERM || errno == EACCES)) {
printf(" (Skipping device node tests - requires CAP_MKNOD)\n");
} else if (result == 0) {
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on character device should succeed");
TEST_ASSERT(S_ISCHR(st.st_mode), "created node should be a character device");
TEST_ASSERT(major(st.st_rdev) == 1, "character device should have correct major number");
TEST_ASSERT(minor(st.st_rdev) == 3, "character device should have correct minor number");
unlink(path);
}
snprintf(path, sizeof(path), "%s/test_blkdev", base_path);
unlink(path);
result = mknod(path, S_IFBLK | 0666, makedev(7, 0));
if (result < 0 && (errno == EPERM || errno == EACCES)) {
} else if (result == 0) {
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on block device should succeed");
TEST_ASSERT(S_ISBLK(st.st_mode), "created node should be a block device");
TEST_ASSERT(major(st.st_rdev) == 7, "block device should have correct major number");
TEST_ASSERT(minor(st.st_rdev) == 0, "block device should have correct minor number");
unlink(path);
}
snprintf(path, sizeof(path), "%s/test_socket_mknod", base_path);
unlink(path);
result = mknod(path, S_IFSOCK | 0644, 0);
if (result == 0) {
result = stat(path, &st);
TEST_ASSERT_ERRNO(result == 0, "stat on socket should succeed");
TEST_ASSERT(S_ISSOCK(st.st_mode), "created node should be a socket");
unlink(path);
} else {
printf(" (Socket creation via mknod returned errno=%d: %s - this is acceptable)\n",
errno, strerror(errno));
}
snprintf(path, sizeof(path), "%s/", base_path);
result = mknod(path, S_IFREG | 0644, 0);
TEST_ASSERT(result < 0, "mknod with empty filename should fail");
return 0;
}