The Pedigree Project 0.1
system-status-contract-test/main.c
1/* Copyright (c) 2026, Pedigree Developers. */
2#define _GNU_SOURCE
3#include <dirent.h>
4#include <errno.h>
5#include <fcntl.h>
6#include <limits.h>
7#include <sched.h>
8#include <stdint.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13
14#include <pedigree/log.h>
15#include <sys/mman.h>
16#include <sys/stat.h>
17#include <sys/syscall.h>
18
19#define CHECK(expression) \
20 do { \
21 if (!(expression)) { \
22 fprintf(stderr, "SYSTEM-STATUS-CONTRACT: FAIL line=%d errno=%d\n", __LINE__, errno); \
23 return 1; \
24 } \
25 } while (0)
26
27static int memory_status(void) {
28 int fd = open("/proc/meminfo", O_RDONLY);
29 CHECK(fd >= 0);
30 unsigned char guarded[16];
31 memset(guarded, 0xa5, sizeof(guarded));
32 CHECK(pread(fd, guarded + 1, 1, 0) == 1 && guarded[1] == 'M');
33 CHECK(guarded[0] == 0xa5 && guarded[2] == 0xa5);
34 CHECK(pread(fd, guarded + 1, 5, 4) == 5 && !memcmp(guarded + 1, "otal:", 5));
35 CHECK(guarded[0] == 0xa5 && guarded[6] == 0xa5);
36 CHECK(pread(fd, guarded, sizeof(guarded), LLONG_MAX - sizeof(guarded)) == 0);
37
38 char contents[512];
39 ssize_t bytes = pread(fd, contents, sizeof(contents) - 1, 0);
40 CHECK(bytes > 0);
41 contents[bytes] = 0;
42 unsigned long long total = 0, freeKb = 0;
43 CHECK(sscanf(contents, "MemTotal: %llu kB\nMemFree: %llu kB", &total, &freeKb) == 2);
44 CHECK(total > 0 && freeKb <= total);
45 CHECK(close(fd) == 0);
46 puts("SYSTEM-STATUS-CONTRACT: MEMORY PASS");
47 return 0;
48}
49
50static ssize_t read_status_file(const char* path, char* contents, size_t capacity) {
51 int fd = open(path, O_RDONLY);
52 if (fd < 0)
53 return -1;
54 ssize_t bytes = read(fd, contents, capacity - 1);
55 int saved = errno;
56 close(fd);
57 errno = saved;
58 if (bytes >= 0)
59 contents[bytes] = 0;
60 return bytes;
61}
62
63static unsigned long long metrics_yields(const char* contents, size_t* rows) {
64 unsigned long long total = 0;
65 *rows = 0;
66 for (const char* line = contents; line && *line; line = strchr(line, '\n')) {
67 if (*line == '\n') {
68 ++line;
69 }
70 unsigned cpu;
71 unsigned long long value;
72 if (sscanf(line, "pedigree_scheduler_yields_total{cpu=\"%u\"} %llu", &cpu, &value) == 2) {
73 total += value;
74 ++*rows;
75 }
76 }
77 return total;
78}
79
80static int metrics_status(void) {
81 int fd = open("/proc/metrics", O_RDONLY);
82 CHECK(fd >= 0);
83 struct stat status;
84 CHECK(!fstat(fd, &status) && status.st_size > 0 && status.st_size < 1024 * 1024);
85 CHECK((status.st_mode & 0444) == 0444 && !(status.st_mode & 0222));
86 const size_t length = (size_t)status.st_size;
87 char* expected = malloc(length + 1);
88 char* contents = malloc(length + 1);
89 CHECK(expected && contents);
90 CHECK(pread(fd, expected, length, 0) == (ssize_t)length);
91 expected[length] = 0;
92 CHECK(length >= 6 && !strcmp(expected + length - 6, "# EOF\n"));
93 CHECK(strstr(expected, "# TYPE pedigree_metrics_enabled gauge\n"));
94 CHECK(strstr(expected, "# TYPE pedigree_cpus gauge\n"));
95 CHECK(strstr(expected, "# TYPE pedigree_uptime_seconds gauge\n"));
96 CHECK(strstr(expected, "# TYPE pedigree_memory_managed_bytes gauge\n"));
97 CHECK(strstr(expected, "# TYPE pedigree_memory_free_bytes gauge\n"));
98 CHECK(strstr(expected, "# TYPE pedigree_threads gauge\n"));
99 CHECK(strstr(expected, "# TYPE pedigree_runnable_threads gauge\n"));
100 unsigned long long managed = 0, free_bytes = 0, threads = 0, runnable = 0;
101 const char* managed_line = strstr(expected, "\npedigree_memory_managed_bytes ");
102 const char* free_line = strstr(expected, "\npedigree_memory_free_bytes ");
103 const char* threads_line = strstr(expected, "\npedigree_threads ");
104 const char* runnable_line = strstr(expected, "\npedigree_runnable_threads ");
105 CHECK(managed_line &&
106 sscanf(managed_line, "\npedigree_memory_managed_bytes %llu", &managed) == 1);
107 CHECK(free_line && sscanf(free_line, "\npedigree_memory_free_bytes %llu", &free_bytes) == 1);
108 CHECK(threads_line && sscanf(threads_line, "\npedigree_threads %llu", &threads) == 1);
109 CHECK(runnable_line && sscanf(runnable_line, "\npedigree_runnable_threads %llu", &runnable) == 1);
110 CHECK(managed > 0 && free_bytes <= managed && threads > 0 && runnable <= threads);
111 const char* enabled_line = strstr(expected, "\npedigree_metrics_enabled ");
112 unsigned enabled;
113 CHECK(enabled_line && sscanf(enabled_line, "\npedigree_metrics_enabled %u", &enabled) == 1 &&
114 enabled <= 1);
115
116 int alias = dup(fd);
117 CHECK(alias >= 0);
118 size_t offset = 0;
119 while (offset < length) {
120 size_t chunk = (offset % 11) + 1;
121 if (chunk > length - offset) {
122 chunk = length - offset;
123 }
124 // Aliases share their position and frozen bytes, even when splitting a number.
125 CHECK(read(offset & 1 ? alias : fd, contents + offset, chunk) == (ssize_t)chunk);
126 offset += chunk;
127 }
128 contents[length] = 0;
129 CHECK(!memcmp(contents, expected, length) && read(alias, contents, 1) == 0);
130 CHECK(pread(fd, contents, 1, LLONG_MAX - 1) == 0);
131
132 size_t before_rows;
133 const unsigned long long before = metrics_yields(expected, &before_rows);
134 if (enabled) {
135 unsigned long cpus;
136 const char* cpu_line = strstr(expected, "\npedigree_cpus ");
137 CHECK(cpu_line && sscanf(cpu_line, "\npedigree_cpus %lu", &cpus) == 1 && cpus > 0 &&
138 before_rows == cpus);
139 CHECK(strstr(expected, "# TYPE pedigree_scheduler_yields_total counter\n"));
140 CHECK(strstr(expected, "# TYPE pedigree_spinlock_acquires_total counter\n"));
141 CHECK(strstr(expected, "# TYPE pedigree_physical_page_allocations_total counter\n"));
142 CHECK(strstr(expected, "# TYPE pedigree_wait_queue_waits_total counter\n"));
143 CHECK(strstr(expected, "# TYPE pedigree_network_rx_packets_total counter\n"));
144 CHECK(strstr(expected, "# TYPE pedigree_file_read_bytes_total counter\n"));
145 CHECK(strstr(expected, "policy=\"no_irq\""));
146 } else {
147 CHECK(!before_rows && !strstr(expected, "_total"));
148 }
149
150 for (unsigned i = 0; i < 16; ++i) {
151 CHECK(sched_yield() == 0);
152 }
153 int next = open("/proc/metrics", O_RDONLY);
154 CHECK(next >= 0 && !fstat(next, &status) && status.st_size > 0 && status.st_size < 1024 * 1024);
155 char* later = malloc((size_t)status.st_size + 1);
156 CHECK(later && read(next, later, status.st_size) == status.st_size);
157 later[status.st_size] = 0;
158 if (enabled) {
159 size_t after_rows;
160 CHECK(metrics_yields(later, &after_rows) > before && after_rows == before_rows);
161 } else {
162 CHECK(strstr(later, "\npedigree_metrics_enabled 0\n") && !strstr(later, "_total"));
163 }
164 CHECK(close(next) == 0);
165 free(later);
166
167 CHECK(lseek(alias, 0, SEEK_SET) == 0);
168 CHECK(read(fd, contents, length) == (ssize_t)length && !memcmp(contents, expected, length));
169 CHECK(close(fd) == 0 && lseek(alias, 0, SEEK_SET) == 0);
170 CHECK(read(alias, contents, length) == (ssize_t)length && !memcmp(contents, expected, length));
171 CHECK(close(alias) == 0);
172 free(contents);
173 free(expected);
174
175 // UID 0 bypasses mode bits; exercise permission rejection after snapshot creation.
176 const uid_t saved_uid = geteuid();
177 if (!saved_uid) {
178 CHECK(seteuid(65534) == 0);
179 }
180 errno = 0;
181 int writable = open("/proc/metrics", O_WRONLY);
182 const int open_error = errno;
183 if (!saved_uid) {
184 CHECK(seteuid(saved_uid) == 0);
185 }
186 CHECK(writable == -1 && open_error == EACCES);
187 puts("SYSTEM-STATUS-CONTRACT: METRICS PASS");
188 return 0;
189}
190
191static int process_status(void) {
192 char contents[2048];
193 unsigned long long uptime = 0, uptime_hundredths = 0, idle = 0, idle_hundredths = 0;
194 CHECK(read_status_file("/proc/uptime", contents, sizeof(contents)) > 0);
195 CHECK(sscanf(contents, "%llu.%llu %llu.%llu", &uptime, &uptime_hundredths, &idle,
196 &idle_hundredths) == 4);
197 CHECK(uptime_hundredths < 100 && idle_hundredths < 100);
198
199 CHECK(read_status_file("/proc/stat", contents, sizeof(contents)) > 0);
200 unsigned long long user = 0, kernel = 0, idle_ticks = 0;
201 CHECK(sscanf(contents, "cpu %llu %*u %llu %llu", &user, &kernel, &idle_ticks) == 3);
202 CHECK(strstr(contents, "\nbtime ") && strstr(contents, "\nprocs_running "));
203
204 CHECK(read_status_file("/proc/loadavg", contents, sizeof(contents)) > 0);
205 unsigned long long running = 0, tasks = 0, last_pid = 0;
206 CHECK(sscanf(contents, "%*u.%*u %*u.%*u %*u.%*u %llu/%llu %llu", &running, &tasks, &last_pid) ==
207 3);
208 CHECK(tasks > 0 && running <= tasks && last_pid >= (unsigned long long)getpid());
209
210 CHECK(read_status_file("/proc/cpuinfo", contents, sizeof(contents)) > 0);
211 CHECK(strstr(contents, "processor\t: 0") && strstr(contents, "vendor_id\t: Pedigree"));
212 CHECK(read_status_file("/proc/partitions", contents, sizeof(contents)) > 0);
213 CHECK(strstr(contents, "major minor") && strstr(contents, "disk"));
214
215 CHECK(read_status_file("/proc/self/status", contents, sizeof(contents)) > 0);
216 char pid_line[64];
217 snprintf(pid_line, sizeof(pid_line), "Pid:\t%ld\n", (long)getpid());
218 CHECK(strstr(contents, "Name:\t") && strstr(contents, pid_line) && strstr(contents, "VmRSS:\t"));
219
220 CHECK(read_status_file("/proc/self/stat", contents, sizeof(contents)) > 0);
221 unsigned long long stat_pid = 0;
222 CHECK(sscanf(contents, "%llu (", &stat_pid) == 1 && stat_pid == (unsigned long long)getpid());
223 char* stat_field = strrchr(contents, ')');
224 CHECK(stat_field);
225 size_t stat_fields = 2;
226 while (*++stat_field) {
227 while (*stat_field == ' ' || *stat_field == '\n')
228 ++stat_field;
229 if (!*stat_field)
230 break;
231 ++stat_fields;
232 while (*stat_field && *stat_field != ' ' && *stat_field != '\n')
233 ++stat_field;
234 --stat_field;
235 }
236 CHECK(stat_fields == 52);
237
238 CHECK(read_status_file("/proc/self/statm", contents, sizeof(contents)) > 0);
239 unsigned long long size = 0, resident = 0, shared = 0;
240 CHECK(sscanf(contents, "%llu %llu %llu", &size, &resident, &shared) == 3);
241 CHECK(resident <= size && shared <= resident);
242
243 ssize_t command_bytes = read_status_file("/proc/self/cmdline", contents, sizeof(contents));
244 CHECK(command_bytes > 1 && contents[command_bytes - 1] == 0);
245 CHECK(strstr(contents, "system-status-contract-test"));
246
247 struct stat expected, proc_path;
248 CHECK(!stat(".", &expected) && !stat("/proc/self/cwd", &proc_path));
249 CHECK(expected.st_dev == proc_path.st_dev && expected.st_ino == proc_path.st_ino);
250 CHECK(!stat("/", &expected) && !stat("/proc/self/root", &proc_path));
251 CHECK(expected.st_dev == proc_path.st_dev && expected.st_ino == proc_path.st_ino);
252 char executable[PATH_MAX] = {};
253 ssize_t executable_length = readlink("/proc/self/exe", executable, sizeof(executable) - 1);
254 CHECK(executable_length > 0 && strstr(executable, "system-status-contract-test"));
255 puts("SYSTEM-STATUS-CONTRACT: PROCFS PASS");
256 return 0;
257}
258
259static int first_entry(const char* path, char* name, size_t capacity) {
260 DIR* directory = opendir(path);
261 if (!directory)
262 return -1;
263 struct dirent* entry;
264 int found = 0;
265 while ((entry = readdir(directory))) {
266 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
267 continue;
268 snprintf(name, capacity, "%s", entry->d_name);
269 found = 1;
270 break;
271 }
272 closedir(directory);
273 return found;
274}
275
276static int sysfs_status(void) {
277 struct stat status;
278 CHECK(!stat("/sys/class", &status) && S_ISDIR(status.st_mode));
279 CHECK(!stat("/sys/bus/pci/devices", &status) && S_ISDIR(status.st_mode));
280 CHECK(!stat("/sys/firmware/efi", &status) && S_ISDIR(status.st_mode));
281
282 char entry[128], path[256], contents[512];
283 CHECK(first_entry("/sys/bus/pci/devices", entry, sizeof(entry)) == 1);
284 snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/vendor", entry);
285 CHECK(read_status_file(path, contents, sizeof(contents)) > 0 && !strncmp(contents, "0x", 2));
286 snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/device", entry);
287 CHECK(read_status_file(path, contents, sizeof(contents)) > 0 && !strncmp(contents, "0x", 2));
288
289 int block = first_entry("/sys/class/block", entry, sizeof(entry));
290 CHECK(block >= 0);
291 if (block) {
292 snprintf(path, sizeof(path), "/sys/class/block/%s/size", entry);
293 CHECK(read_status_file(path, contents, sizeof(contents)) > 0);
294 }
295
296 int network = first_entry("/sys/class/net", entry, sizeof(entry));
297 CHECK(network >= 0);
298 if (network) {
299 snprintf(path, sizeof(path), "/sys/class/net/%s/operstate", entry);
300 CHECK(read_status_file(path, contents, sizeof(contents)) > 0);
301 }
302 puts("SYSTEM-STATUS-CONTRACT: SYSFS PASS");
303 return 0;
304}
305
306static int device_status(void) {
307 struct stat status;
308 CHECK(!stat("/dev/disk/by-uuid", &status) && S_ISDIR(status.st_mode));
309 CHECK(!stat("/dev/disk/by-label", &status) && S_ISDIR(status.st_mode));
310 CHECK(!stat("/dev/disk/by-partuuid", &status) && S_ISDIR(status.st_mode));
311 CHECK(!stat("/dev/disk/by-partlabel", &status) && S_ISDIR(status.st_mode));
312
313 char entry[128], path[256];
314 CHECK(first_entry("/dev/disk/by-uuid", entry, sizeof(entry)) == 1);
315 snprintf(path, sizeof(path), "/dev/disk/by-uuid/%s", entry);
316 char target[64] = {};
317 ssize_t length = readlink(path, target, sizeof(target) - 1);
318 CHECK(length > 0 && !strncmp(target, "/dev/block/", 11));
319 CHECK(!stat(path, &status) && S_ISBLK(status.st_mode));
320 CHECK(!stat("/dev/disk/by-label/pedigree", &status) && S_ISBLK(status.st_mode));
321
322 unsigned char byte = 0xa5;
323 int fd = open("/dev/full", O_RDWR);
324 CHECK(fd >= 0);
325 CHECK(read(fd, &byte, 1) == 1 && byte == 0);
326 errno = 0;
327 CHECK(write(fd, "x", 1) == -1 && errno == ENOSPC);
328 CHECK(close(fd) == 0);
329
330 memset(target, 0, sizeof(target));
331 length = readlink("/dev/stdin", target, sizeof(target) - 1);
332 CHECK(length > 0 && !strcmp(target, "/proc/self/fd/0"));
333 length = readlink("/dev/stdout", target, sizeof(target) - 1);
334 CHECK(length > 0 && !strcmp(target, "/proc/self/fd/1"));
335 length = readlink("/dev/stderr", target, sizeof(target) - 1);
336 CHECK(length > 0 && !strcmp(target, "/proc/self/fd/2"));
337
338 fd = open("/dev/shm/system-status-contract", O_CREAT | O_EXCL | O_RDWR, 0600);
339 CHECK(fd >= 0 && write(fd, "shm", 3) == 3 && close(fd) == 0);
340 CHECK(unlink("/dev/shm/system-status-contract") == 0);
341 fd = open("/run/lock/system-status-contract", O_CREAT | O_EXCL | O_RDWR, 0600);
342 CHECK(fd >= 0 && close(fd) == 0);
343 CHECK(unlink("/run/lock/system-status-contract") == 0);
344 puts("SYSTEM-STATUS-CONTRACT: DEVFS PASS");
345 return 0;
346}
347
348static int network_status(void) {
349 int fd = open("/proc/net/interfaces", O_RDONLY);
350 CHECK(fd >= 0);
351 char contents[8192];
352 ssize_t bytes = read(fd, contents, sizeof(contents) - 1);
353 CHECK(bytes > 0);
354 contents[bytes] = 0;
355 CHECK(strstr(contents, " Device:") || !strcmp(contents, "No network devices.\n"));
356 if (strstr(contents, " Device:")) {
357 CHECK(strstr(contents, " MAC:") && strstr(contents, " IPv4:") &&
358 strstr(contents, " Netmask:") && strstr(contents, " Gateway:"));
359 }
360 CHECK(close(fd) == 0);
361 fd = open("/proc/net/dev", O_RDONLY);
362 CHECK(fd >= 0);
363 bytes = read(fd, contents, sizeof(contents) - 1);
364 CHECK(bytes > 0);
365 contents[bytes] = 0;
366 CHECK(strstr(contents, "Inter-") && strstr(contents, "Transmit"));
367 CHECK(close(fd) == 0);
368 fd = open("/proc/resolv.conf", O_RDONLY);
369 CHECK(fd >= 0);
370 bytes = read(fd, contents, sizeof(contents) - 1);
371 CHECK(bytes >= 0);
372 contents[bytes] = 0;
373 CHECK(!bytes || strstr(contents, "nameserver "));
374 CHECK(close(fd) == 0);
375 puts("SYSTEM-STATUS-CONTRACT: NETWORK PASS");
376 return 0;
377}
378
379static int kernel_log(void) {
380 CHECK(syscall(SYS_syslog, 0, NULL, 0) == 0);
381 CHECK(syscall(SYS_syslog, 1, NULL, 0) == 0);
382 long capacity = syscall(SYS_syslog, 10, NULL, 0);
383 CHECK(capacity > 0 && capacity < INT_MAX);
384 CHECK(syscall(SYS_syslog, 3, NULL, 0) == 0);
385 errno = 0;
386 CHECK(syscall(SYS_syslog, 3, NULL, -1) == -1 && errno == EINVAL);
387 errno = 0;
388 CHECK(syscall(SYS_syslog, 3, (void*)(uintptr_t)1, 1) == -1 && errno == EFAULT);
389 errno = 0;
390 CHECK(syscall(SYS_syslog, 42, NULL, 0) == -1 && errno == EINVAL);
391 void* readonly = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
392 CHECK(readonly != MAP_FAILED);
393 errno = 0;
394 CHECK(syscall(SYS_syslog, 3, readonly, 1) == -1 && errno == EFAULT);
395 CHECK(munmap(readonly, 4096) == 0);
396
397 char marker[80];
398 snprintf(marker, sizeof(marker), "SYSTEM-STATUS-KLOG-%ld", (long)getpid());
399 CHECK(pedigree_log(LOG_NOTICE, "%s", marker) == 0);
400 char* buffer = malloc((size_t)capacity + 2);
401 CHECK(buffer);
402 for (int pass = 0; pass < 3; ++pass) {
403 memset(buffer, 0xa5, (size_t)capacity + 2);
404 long count = syscall(SYS_syslog, 3, buffer + 1, capacity);
405 CHECK(count > 0 && count <= capacity);
406 CHECK((unsigned char)buffer[0] == 0xa5 && (unsigned char)buffer[capacity + 1] == 0xa5);
407 buffer[count + 1] = 0;
408 CHECK(strstr(buffer + 1, marker));
409 if (pass == 1) {
410 errno = 0;
411 CHECK(syscall(SYS_syslog, 4, buffer + 1, capacity) == -1 && errno == ENOSYS);
412 errno = 0;
413 CHECK(syscall(SYS_syslog, 5, NULL, 0) == -1 && errno == ENOSYS);
414 }
415 }
416 unsigned char tail[3] = {0xa5, 0xa5, 0xa5};
417 CHECK(syscall(SYS_syslog, 3, tail + 1, 1) == 1 && tail[1] == '\n');
418 CHECK(tail[0] == 0xa5 && tail[2] == 0xa5);
419 free(buffer);
420 puts("SYSTEM-STATUS-CONTRACT: KERNEL-LOG PASS");
421 return 0;
422}
423
424int main(void) {
425 if (memory_status() || process_status() || metrics_status() || sysfs_status() ||
426 device_status() || network_status() || kernel_log())
427 return 1;
428 puts("SYSTEM-STATUS-CONTRACT: PASS");
429 return 0;
430}