The Pedigree Project 0.1
ptrace-contract-test/main.c
1#define _GNU_SOURCE
2#include <limits.h>
3#include <stdlib.h>
4#include <string.h>
5#include <unistd.h>
6
7#include "contract.h"
8
9static int number(const char* text) {
10 char* end;
11 errno = 0;
12 long value = strtol(text, &end, 10);
13 return errno || !*text || *end || value < 0 || value > INT_MAX ? -1 : (int)value;
14}
15
16int main(int argc, char** argv) {
17 setvbuf(stdout, NULL, _IONBF, 0);
18 if (argc == 3 && !strcmp(argv[1], "--exec-child")) {
19 int report = number(argv[2]);
20 return report < 0 ? 2 : tc_exec_child(report);
21 }
22 if (argc == 5 && !strcmp(argv[1], "--exec-tracer")) {
23 int child = number(argv[2]), command = number(argv[3]), report = number(argv[4]);
24 return child <= 0 || command < 0 || report < 0 ? 2 : tc_exec_tracer(child, command, report);
25 }
26 if (argc > 2)
27 return 2;
28 tc_page = (size_t)sysconf(_SC_PAGESIZE);
29 if (!tc_page || tc_page > 65536)
30 return 2;
31 const struct {
32 const char* name;
33 int (*run)(void);
34 } families[] = {{"registers", tc_registers}, {"inspect", tc_inspect}, {"signals", tc_signals},
35 {"ownership", tc_ownership}, {"lifecycle", tc_lifecycle}, {"errors", tc_errors}};
36 int selected = 0;
37 for (size_t i = 0; i < sizeof(families) / sizeof(families[0]); ++i) {
38 if (argc == 2 && strcmp(argv[1], "all") && strcmp(argv[1], families[i].name))
39 continue;
40 ++selected;
41 printf("PTRACE-CONTRACT: BEGIN %s\n", families[i].name);
42 pid_t family = fork();
43 if (!family) {
44 if (setpgid(0, 0))
45 _exit(120);
46 alarm(50);
47 int failed = families[i].run();
48 fflush(stderr);
49 _exit(failed ? 1 : 0);
50 }
51 if (family < 0)
52 return 1;
53 int status = 0;
54 int result = tc_wait(family, &status, 55000);
55 if (result || !WIFEXITED(status) || WEXITSTATUS(status)) {
56 // The family group includes its tracees even when a tracer times out.
57 kill(-family, SIGKILL);
58 if (result || (!WIFEXITED(status) && !WIFSIGNALED(status)))
59 tc_cleanup(&family);
60 printf("PTRACE-CONTRACT: FAIL %s result=%d status=%#x errno=%d\n", families[i].name, result,
61 status, errno);
62 return 1;
63 }
64 printf("PTRACE-CONTRACT: PASS %s\n", families[i].name);
65 }
66 if (!selected)
67 return 2;
68 puts("PTRACE-CONTRACT: END PASS");
69 return 0;
70}