The Pedigree Project 0.1
global-sync-contract-test/main.c
1/* Copyright (c) 2026, Pedigree Developers. */
2#define _GNU_SOURCE
3#include <errno.h>
4#include <fcntl.h>
5#include <signal.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#include <sys/mman.h>
13#include <sys/stat.h>
14#include <sys/wait.h>
15#include <sys/xattr.h>
16
17#define CHECK(expression) \
18 do { \
19 if (!(expression)) { \
20 fprintf(stderr, "GLOBAL-SYNC-CONTRACT: FAIL line=%d errno=%d\n", __LINE__, errno); \
21 return 1; \
22 } \
23 } while (0)
24
25static const char closedContents[] = "closed file and namespace metadata";
26
27static unsigned char pattern(size_t offset) {
28 return (unsigned char)((offset * 17 + offset / 4096 * 31 + 43) & 255);
29}
30
31static int basic(void) {
32 int root = open("/", O_RDONLY | O_DIRECTORY);
33 int path = open("/", O_PATH);
34 int ram = open("/tmp", O_RDONLY | O_DIRECTORY);
35 CHECK(root >= 0 && path >= 0 && ram >= 0);
36 errno = 0;
37 CHECK(syncfs(-1) == -1 && errno == EBADF);
38 errno = 0;
39 CHECK(syncfs(path) == -1 && errno == EBADF);
40 CHECK(syncfs(root) == 0 && syncfs(ram) == 0);
41 errno = EDOM;
42 sync();
43 CHECK(errno == EDOM);
44
45 pid_t child = fork();
46 if (!child) {
47 if (setuid(65534) || syncfs(root))
48 _exit(2);
49 sync();
50 _exit(0);
51 }
52 int status = 0;
53 CHECK(child > 0 && waitpid(child, &status, 0) == child && WIFEXITED(status) &&
54 WEXITSTATUS(status) == 0);
55 close(root);
56 close(path);
57 close(ram);
58 puts("GLOBAL-SYNC-CONTRACT: BASIC PASS");
59 return 0;
60}
61
62static int cold(const char* mode, int verify) {
63 char directory[128], source[160], alias[160], nested[160], final[192], closed[160], removed[160];
64 snprintf(directory, sizeof(directory), "/global-sync-contract-%s", mode);
65 snprintf(source, sizeof(source), "%s/source", directory);
66 snprintf(alias, sizeof(alias), "%s/alias", directory);
67 snprintf(nested, sizeof(nested), "%s/nested", directory);
68 snprintf(final, sizeof(final), "%s/final", nested);
69 snprintf(closed, sizeof(closed), "%s/closed", directory);
70 snprintf(removed, sizeof(removed), "%s/removed", directory);
71 const size_t bytes = 4 * 4096;
72 unsigned char attribute[256];
73 for (size_t i = 0; i < sizeof(attribute); ++i)
74 attribute[i] = pattern(i + 71);
75
76 if (verify) {
77 struct stat first, second;
78 CHECK(stat(final, &first) == 0 && stat(alias, &second) == 0);
79 CHECK(first.st_ino == second.st_ino && first.st_nlink == 2 && first.st_size == (off_t)bytes);
80 CHECK(access(source, F_OK) == -1 && errno == ENOENT);
81 CHECK(access(removed, F_OK) == -1 && errno == ENOENT);
82 unsigned char copiedAttribute[256];
83 CHECK(getxattr(alias, "user.global-sync", copiedAttribute, sizeof(copiedAttribute)) ==
84 sizeof(copiedAttribute));
85 CHECK(!memcmp(attribute, copiedAttribute, sizeof(attribute)));
86 int fd = open(final, O_RDONLY);
87 CHECK(fd >= 0);
88 unsigned char buffer[4096];
89 for (size_t offset = 0; offset < bytes; offset += sizeof(buffer)) {
90 CHECK(read(fd, buffer, sizeof(buffer)) == sizeof(buffer));
91 for (size_t i = 0; i < sizeof(buffer); ++i)
92 CHECK(buffer[i] == pattern(offset + i));
93 }
94 CHECK(close(fd) == 0);
95 fd = open(closed, O_RDONLY);
96 CHECK(fd >= 0 && read(fd, buffer, sizeof(buffer)) == sizeof(closedContents));
97 CHECK(!memcmp(buffer, closedContents, sizeof(closedContents)));
98 CHECK(close(fd) == 0);
99 printf("GLOBAL-SYNC-CONTRACT: COLD-VERIFIED %s\n", mode);
100 return 0;
101 }
102
103 CHECK(mkdir(directory, 0700) == 0 && mkdir(nested, 0700) == 0);
104 int fd = open(source, O_CREAT | O_EXCL | O_RDWR, 0600);
105 CHECK(fd >= 0 && ftruncate(fd, bytes) == 0);
106 CHECK(link(source, alias) == 0 && rename(source, final) == 0);
107 CHECK(setxattr(final, "user.global-sync", attribute, sizeof(attribute), 0) == 0);
108 unsigned char* mapping = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
109 CHECK(mapping != MAP_FAILED && close(fd) == 0);
110 for (size_t i = 0; i < bytes; ++i)
111 mapping[i] = pattern(i);
112
113 fd = open(closed, O_CREAT | O_EXCL | O_WRONLY, 0600);
114 CHECK(fd >= 0 && write(fd, closedContents, sizeof(closedContents)) == sizeof(closedContents));
115 CHECK(close(fd) == 0);
116 fd = open(removed, O_CREAT | O_EXCL | O_WRONLY, 0600);
117 CHECK(fd >= 0 && write(fd, "discard", 7) == 7 && close(fd) == 0 && unlink(removed) == 0);
118
119 // The only supplied descriptor names a directory. The dirty file has no
120 // numeric descriptor; keep its mapping alive across the external VM stop.
121 int root = open("/", O_RDONLY | O_DIRECTORY);
122 CHECK(root >= 0);
123 if (!strcmp(mode, "syncfs"))
124 CHECK(syncfs(root) == 0);
125 else
126 sync();
127 alarm(0);
128 printf("GLOBAL-SYNC-CONTRACT: COLD-READY %s\n", mode);
129 for (;;)
130 pause();
131}
132
133int main(int argc, char** argv) {
134 setvbuf(stdout, NULL, _IONBF, 0);
135 alarm(90);
136 if (argc == 1 || (argc == 2 && !strcmp(argv[1], "basic")))
137 return basic();
138 CHECK(argc == 3 && (!strcmp(argv[1], "prepare") || !strcmp(argv[1], "verify")) &&
139 (!strcmp(argv[2], "sync") || !strcmp(argv[2], "syncfs")));
140 return cold(argv[2], !strcmp(argv[1], "verify"));
141}