Add regression tests
This commit is contained in:
parent
138401b0ab
commit
4a88b6aa86
|
|
@ -0,0 +1,59 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include "pseudo_file_create.h"
|
||||
|
||||
static int readlink_check(int fd, const char *expect_prefix, int check_ino)
|
||||
{
|
||||
char path[64];
|
||||
char buf[256];
|
||||
struct stat st;
|
||||
|
||||
fd_path(fd, path, sizeof(path));
|
||||
ssize_t len = readlink(path, buf, sizeof(buf) - 1);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
buf[len] = '\0';
|
||||
|
||||
size_t prefix_len = strlen(expect_prefix);
|
||||
if (strncmp(buf, expect_prefix, prefix_len) != 0)
|
||||
return -1;
|
||||
|
||||
if (check_ino) {
|
||||
const char *ino_p = buf + prefix_len;
|
||||
char *end = NULL;
|
||||
|
||||
unsigned long ino = strtoul(ino_p, &end, 10);
|
||||
if (end == ino_p || *end != ']' || *(end + 1) != '\0')
|
||||
return -1;
|
||||
if (fstat(fd, &st) < 0 || st.st_ino != ino)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FN_TEST(pseudo_dentry)
|
||||
{
|
||||
TEST_RES(readlink_check(pipe_1[0], "pipe:[", 1), _ret == 0);
|
||||
TEST_RES(readlink_check(pipe_1[1], "pipe:[", 1), _ret == 0);
|
||||
|
||||
TEST_RES(readlink_check(sock[0], "socket:[", 1), _ret == 0);
|
||||
TEST_RES(readlink_check(sock[1], "socket:[", 1), _ret == 0);
|
||||
|
||||
TEST_RES(readlink_check(epoll_fd, "anon_inode:[eventpoll]", 0),
|
||||
_ret == 0);
|
||||
TEST_RES(readlink_check(event_fd, "anon_inode:[eventfd]", 0),
|
||||
_ret == 0);
|
||||
TEST_RES(readlink_check(timer_fd, "anon_inode:[timerfd]", 0),
|
||||
_ret == 0);
|
||||
TEST_RES(readlink_check(signal_fd, "anon_inode:[signalfd]", 0),
|
||||
_ret == 0);
|
||||
TEST_RES(readlink_check(inotify_fd, "anon_inode:inotify", 0),
|
||||
_ret == 0);
|
||||
TEST_RES(readlink_check(pid_fd, "anon_inode:[pidfd]", 0), _ret == 0);
|
||||
|
||||
TEST_RES(readlink_check(mem_fd, "/memfd:test_memfd", 0), _ret == 0);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
#include "pseudo_file_cleanup.h"
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
FN_SETUP(cleanup)
|
||||
{
|
||||
CHECK(close(pipe_1[0]));
|
||||
CHECK(close(pipe_1[1]));
|
||||
CHECK(close(pipe_2[0]));
|
||||
CHECK(close(pipe_2[1]));
|
||||
CHECK(close(sock[0]));
|
||||
CHECK(close(sock[1]));
|
||||
CHECK(close(epoll_fd));
|
||||
CHECK(close(event_fd));
|
||||
CHECK(close(timer_fd));
|
||||
CHECK(close(signal_fd));
|
||||
CHECK(close(inotify_fd));
|
||||
CHECK(close(pid_fd));
|
||||
CHECK(close(mem_fd));
|
||||
CHECK(kill(child, SIGKILL));
|
||||
CHECK(waitpid(child, NULL, 0));
|
||||
}
|
||||
END_SETUP()
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "../test.h"
|
||||
|
||||
int pipe_1[2], pipe_2[2];
|
||||
int sock[2];
|
||||
int epoll_fd, event_fd, timer_fd, signal_fd, inotify_fd, pid_fd, mem_fd;
|
||||
pid_t child;
|
||||
|
||||
FN_SETUP(create)
|
||||
{
|
||||
CHECK(pipe(pipe_1));
|
||||
CHECK(pipe(pipe_2));
|
||||
CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
|
||||
|
||||
epoll_fd = CHECK(epoll_create1(EPOLL_CLOEXEC));
|
||||
event_fd = CHECK(eventfd(0, EFD_CLOEXEC));
|
||||
timer_fd = CHECK(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC));
|
||||
inotify_fd = CHECK(inotify_init1(0));
|
||||
mem_fd = CHECK(memfd_create("test_memfd", MFD_CLOEXEC));
|
||||
|
||||
sigset_t mask;
|
||||
CHECK(sigemptyset(&mask));
|
||||
CHECK(sigaddset(&mask, SIGUSR1));
|
||||
signal_fd = CHECK(signalfd(-1, &mask, SFD_CLOEXEC));
|
||||
|
||||
child = CHECK(fork());
|
||||
if (child == 0) {
|
||||
pause();
|
||||
exit(-1);
|
||||
}
|
||||
pid_fd = CHECK(syscall(SYS_pidfd_open, child, 0));
|
||||
}
|
||||
END_SETUP()
|
||||
|
||||
static void __attribute__((unused)) fd_path(int fd, char *buf, size_t buflen)
|
||||
{
|
||||
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fd/%d", fd),
|
||||
_ret > 0 && _ret < buflen);
|
||||
}
|
||||
|
||||
static void __attribute__((unused))
|
||||
fdinfo_path(int fd, char *buf, size_t buflen)
|
||||
{
|
||||
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fdinfo/%d", fd),
|
||||
_ret > 0 && _ret < buflen);
|
||||
}
|
||||
|
|
@ -1,28 +1,6 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "../test.h"
|
||||
|
||||
static void fd_path(int fd, char *buf, size_t buflen)
|
||||
{
|
||||
CHECK_WITH(snprintf(buf, buflen, "/proc/self/fd/%d", fd),
|
||||
_ret > 0 && _ret < buflen);
|
||||
}
|
||||
#include "pseudo_file_create.h"
|
||||
|
||||
static int get_mode(int fd)
|
||||
{
|
||||
|
|
@ -46,29 +24,22 @@ static int set_mode(int fd, int mode)
|
|||
|
||||
FN_TEST(pipe_ends_share_inode)
|
||||
{
|
||||
int pipe1[2], pipe2[2];
|
||||
TEST_SUCC(pipe(pipe1));
|
||||
TEST_SUCC(pipe(pipe2));
|
||||
TEST_RES(get_mode(pipe_1[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe_1[1]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe_2[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe_2[1]), _ret == 0600);
|
||||
|
||||
TEST_RES(get_mode(pipe1[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe1[1]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe2[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe2[1]), _ret == 0600);
|
||||
TEST_SUCC(set_mode(pipe_1[0], 0000));
|
||||
|
||||
TEST_SUCC(set_mode(pipe1[0], 0000));
|
||||
|
||||
TEST_RES(get_mode(pipe1[0]), _ret == 0000);
|
||||
TEST_RES(get_mode(pipe1[1]), _ret == 0000);
|
||||
TEST_RES(get_mode(pipe2[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe2[1]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe_1[0]), _ret == 0000);
|
||||
TEST_RES(get_mode(pipe_1[1]), _ret == 0000);
|
||||
TEST_RES(get_mode(pipe_2[0]), _ret == 0600);
|
||||
TEST_RES(get_mode(pipe_2[1]), _ret == 0600);
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
FN_TEST(sockets_do_not_share_inode)
|
||||
{
|
||||
int sock[2];
|
||||
TEST_SUCC(socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
|
||||
|
||||
TEST_RES(get_mode(sock[0]), _ret == 0777);
|
||||
TEST_RES(get_mode(sock[1]), _ret == 0777);
|
||||
|
||||
|
|
@ -81,37 +52,23 @@ END_TEST()
|
|||
|
||||
FN_TEST(anon_inodefs_share_inode)
|
||||
{
|
||||
int fd;
|
||||
struct fd_mode {
|
||||
int fd;
|
||||
mode_t modes[2];
|
||||
};
|
||||
|
||||
// eventfd
|
||||
fd = TEST_SUCC(eventfd(0, EFD_CLOEXEC));
|
||||
TEST_RES(get_mode(fd), _ret == 0600);
|
||||
TEST_SUCC(set_mode(fd, 0000));
|
||||
TEST_RES(get_mode(fd), _ret == 0000);
|
||||
TEST_SUCC(close(fd));
|
||||
struct fd_mode fds[] = {
|
||||
{ epoll_fd, { 0600, 0000 } }, { event_fd, { 0000, 0111 } },
|
||||
{ timer_fd, { 0111, 0222 } }, { signal_fd, { 0222, 0333 } },
|
||||
{ inotify_fd, { 0333, 0444 } }, { pid_fd, { 0444, 0600 } },
|
||||
};
|
||||
|
||||
// timerfd
|
||||
fd = TEST_SUCC(timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC));
|
||||
TEST_RES(get_mode(fd), _ret == 0000);
|
||||
TEST_SUCC(set_mode(fd, 0111));
|
||||
TEST_RES(get_mode(fd), _ret == 0111);
|
||||
TEST_SUCC(close(fd));
|
||||
|
||||
// signalfd
|
||||
sigset_t mask;
|
||||
TEST_SUCC(sigemptyset(&mask));
|
||||
TEST_SUCC(sigaddset(&mask, SIGUSR1));
|
||||
fd = TEST_SUCC(signalfd(-1, &mask, SFD_CLOEXEC));
|
||||
TEST_RES(get_mode(fd), _ret == 0111);
|
||||
TEST_SUCC(set_mode(fd, 0222));
|
||||
TEST_RES(get_mode(fd), _ret == 0222);
|
||||
TEST_SUCC(close(fd));
|
||||
|
||||
// epollfd
|
||||
fd = TEST_SUCC(epoll_create1(EPOLL_CLOEXEC));
|
||||
TEST_RES(get_mode(fd), _ret == 0222);
|
||||
TEST_SUCC(set_mode(fd, 0600));
|
||||
TEST_RES(get_mode(fd), _ret == 0600);
|
||||
TEST_SUCC(close(fd));
|
||||
for (size_t i = 0; i < sizeof(fds) / sizeof(fds[0]); i++) {
|
||||
TEST_RES(get_mode(fds[i].fd), _ret == fds[i].modes[0]);
|
||||
TEST_SUCC(set_mode(fds[i].fd, fds[i].modes[1]));
|
||||
TEST_RES(get_mode(fds[i].fd), _ret == fds[i].modes[1]);
|
||||
}
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
#include "pseudo_file_cleanup.h"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include "pseudo_file_create.h"
|
||||
|
||||
static int read_fdinfo_mnt_id(int fd)
|
||||
{
|
||||
char path[64], line[256];
|
||||
FILE *f;
|
||||
|
||||
fdinfo_path(fd, path, sizeof(path));
|
||||
f = fopen(path, "r");
|
||||
if (!f)
|
||||
return -1;
|
||||
|
||||
int mnt_id = -1;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (CHECK(sscanf(line, "mnt_id:\t%d", &mnt_id)) == 1)
|
||||
break;
|
||||
}
|
||||
CHECK(fclose(f));
|
||||
|
||||
return mnt_id;
|
||||
}
|
||||
|
||||
FN_TEST(pseudo_mount)
|
||||
{
|
||||
int anon[] = { epoll_fd, event_fd, timer_fd,
|
||||
signal_fd, inotify_fd, pid_fd };
|
||||
|
||||
struct fd_group {
|
||||
int *fds;
|
||||
int nr;
|
||||
int mnt_id;
|
||||
};
|
||||
|
||||
struct fd_group groups[] = {
|
||||
{ pipe_1, 2, -1 },
|
||||
{ sock, 2, -1 },
|
||||
{ anon, 6, -1 },
|
||||
{ &mem_fd, 1, -1 },
|
||||
};
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int base = TEST_SUCC(read_fdinfo_mnt_id(groups[i].fds[0]));
|
||||
for (int j = 1; j < groups[i].nr; j++) {
|
||||
TEST_RES(read_fdinfo_mnt_id(groups[i].fds[j]),
|
||||
_ret == base);
|
||||
}
|
||||
groups[i].mnt_id = base;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = i + 1; j < 4; j++) {
|
||||
TEST_RES(0, groups[i].mnt_id != groups[j].mnt_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST()
|
||||
|
||||
#include "pseudo_file_cleanup.h"
|
||||
|
|
@ -51,7 +51,9 @@ process/pidfd
|
|||
process/wait4
|
||||
procfs/dentry_cache
|
||||
procfs/pid_mem
|
||||
pseudofs/pseudo_dentry
|
||||
pseudofs/pseudo_inode
|
||||
pseudofs/pseudo_mount
|
||||
pseudofs/memfd_access_err
|
||||
pthread/pthread_test
|
||||
pty/close_pty
|
||||
|
|
|
|||
Loading…
Reference in New Issue