17#define CHECK(expression) \
19 if (!(expression)) { \
20 fprintf(stderr, "GLOBAL-SYNC-CONTRACT: FAIL line=%d errno=%d\n", __LINE__, errno); \
25static const char closedContents[] =
"closed file and namespace metadata";
27static unsigned char pattern(
size_t offset) {
28 return (
unsigned char)((offset * 17 + offset / 4096 * 31 + 43) & 255);
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);
37 CHECK(syncfs(-1) == -1 && errno == EBADF);
39 CHECK(syncfs(path) == -1 && errno == EBADF);
40 CHECK(syncfs(root) == 0 && syncfs(ram) == 0);
47 if (setuid(65534) || syncfs(root))
53 CHECK(child > 0 && waitpid(child, &status, 0) == child && WIFEXITED(status) &&
54 WEXITSTATUS(status) == 0);
58 puts(
"GLOBAL-SYNC-CONTRACT: BASIC PASS");
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);
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);
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));
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);
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);
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);
121 int root = open(
"/", O_RDONLY | O_DIRECTORY);
123 if (!strcmp(mode,
"syncfs"))
124 CHECK(syncfs(root) == 0);
128 printf(
"GLOBAL-SYNC-CONTRACT: COLD-READY %s\n", mode);
133int main(
int argc,
char** argv) {
134 setvbuf(stdout, NULL, _IONBF, 0);
136 if (argc == 1 || (argc == 2 && !strcmp(argv[1],
"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"));