==> tests/loader.c <==1/* loader.rs's tests (names_only, confined_and_catalog) and the hashes. */
2#include "mesh/check.h"
3#include "mesh/loader.h"
4
5#include "mesh/abi/fnv.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <sys/stat.h>
11#include <sys/wait.h>
12#include <unistd.h>
13
14static void write_file(const char *path, const char *s) {
15 FILE *f = fopen(path, "w");
16 fputs(s, f);
17 fclose(f);
18}
19
20static void rm_rf(const char *dir) {
21 char *cmd[] = {"rm", "-rf", (char *)dir, NULL};
22 pid_t p = fork();
23 if (p == 0) {
24 execvp("rm", cmd);
25 _exit(127);
26 }
27 int st;
28 waitpid(p, &st, 0);
29}
30
31int main(void) {
32 /* names_only */
33 const char *good[][2] = {{"hello", "hello"}, {"hello/program.toml", "hello"}, {"hello-v2/", "hello-v2"}};
34 for (size_t i = 0; i < 3; i++) {
35 char *n = mesh_catalog_name(good[i][0], NULL);
36 CHECK_S(n, good[i][1]);
37 free(n);
38 }
39 const char *bad[] = {"", "../etc", "/etc/passwd", "a/b", "Hello", "a b", "x/program.toml/..", ".", "hello/../x"};
40 for (size_t i = 0; i < sizeof bad / sizeof *bad; i++) CHECK(mesh_catalog_name(bad[i], NULL) == NULL);
41 char *err = NULL;
42 CHECK(!mesh_catalog_name("../etc", &err));
43 CHECK_S(err, "manifest: \"../etc\": programs are named [a-z0-9-] under --programs (no paths)");
44 free(err);
45 err = NULL;
46
47 /* confined_and_catalog */
48 char root[] = "/tmp/meshd-loader-XXXXXX";
49 CHECK(mkdtemp(root) != NULL);
50 char *p = mesh_fmt("%s/progs", root);
51 char *a = mesh_fmt("%s/progs/a", root), *b = mesh_fmt("%s/progs/b", root), *out = mesh_fmt("%s/outside", root);
52 mkdir(p, 0755);
53 mkdir(a, 0755);
54 mkdir(b, 0755);
55 mkdir(out, 0755);
56 char *toml = mesh_fmt("%s/program.toml", a);
57 write_file(toml, "name = \"a\"\nabi = 6\n");
58 char *esc = mesh_fmt("%s/progs/esc", root);
59 CHECK(symlink(out, esc) == 0);
60 char *r = mesh_loader_resolve(p, "a", &err);
61 CHECK(r != NULL);
62 free(r);
63 CHECK(mesh_loader_resolve(p, "esc", &err) == NULL);
64 CHECK(err && strstr(err, "not a program dir"));
65 free(err);
66 err = NULL;
67 CHECK(mesh_loader_resolve(p, "nope", &err) == NULL);
68 CHECK_S(err, "manifest: nope: No such file or directory (os error 2)");
69 free(err);
70 err = NULL;
71 char **names;
72 size_t n;
73 CHECK(mesh_catalog(p, &names, &n, &err));
74 CHECK_U(n, 1);
75 if (n == 1) CHECK_S(names[0], "a");
76 for (size_t i = 0; i < n; i++) free(names[i]);
77 free(names);
78
79 /* read: a CUDA load needs the PTX; without need_ptx it is left empty. */
80 mesh_payload pl;
81 CHECK(!mesh_loader_read(p, "a", true, &pl, &err));
82 char *want = mesh_fmt("manifest: %s/a.ptx (a): No such file or directory (os error 2)", a);
83 char real[4096];
84 if (realpath(a, real)) {
85 free(want);
86 want = mesh_fmt("manifest: %s/a.ptx (a): No such file or directory (os error 2)", real);
87 }
88 CHECK_S(err, want);
89 free(want);
90 free(err);
91 err = NULL;
92 CHECK(mesh_loader_read(p, "a", false, &pl, &err));
93 CHECK_S(pl.dir, "a");
94 CHECK_U(pl.ptx_len, 0);
95 CHECK_S(pl.manifest, "name = \"a\"\nabi = 6\n");
96 mesh_payload_free(&pl);
97 char *ptx = mesh_fmt("%s/a.ptx", a);
98 write_file(ptx, ".version 8.8\n");
99 CHECK(mesh_loader_read(p, "a/program.toml", true, &pl, &err));
100 CHECK_U(pl.ptx_len, 13);
101 mesh_manifest m;
102 uint64_t h;
103 mesh_payload_free(&pl);
104 CHECK(mesh_loader_identity(p, "a", &pl, &m, &h, &err));
105 CHECK_U(h, mesh_fnv1a64((const uint8_t *)".version 8.8\n", 13));
106 mesh_manifest_free(&m);
107 mesh_payload_free(&pl);
108
109 /* Hashes: param folded in; the native identity trims source.hash. */
110 const uint8_t code[] = "code";
111 CHECK_U(mesh_image_hash(code, 4, 0), mesh_fnv1a64(code, 4));
112 const uint8_t with[] = {'c', 'o', 'd', 'e', 0, 'p', 'a', 'r', 'a', 'm', '=', 14, 0, 0, 0};
113 CHECK_U(mesh_image_hash(code, 4, 14), mesh_fnv1a64(with, sizeof with));
114 uint64_t ida = mesh_native_identity("name = \"g\"\nabi = 2\n", "00ff", 0);
115 CHECK_U(ida, mesh_native_identity("name = \"g\"\nabi = 2\n", "00ff\n", 0));
116 CHECK(ida != mesh_native_identity("name = \"g\"\nabi = 2\n", "00fe", 0));
117 CHECK(ida != mesh_native_identity("name = \"g\"\nabi = 2\nnodes = 2\n", "00ff", 0));
118 CHECK(ida != mesh_native_identity("name = \"g\"\nabi = 2\n", "00ff", 1));
119 uint64_t e = 5;
120 CHECK(mesh_check_hash("x", "PTX", 5, &e, &err));
121 CHECK(mesh_check_hash("x", "PTX", 5, NULL, &err));
122 e = 6;
123 CHECK(!mesh_check_hash("x", "PTX", 5, &e, &err));
124 CHECK_S(err, "peer: x: the PTX received hashes to 0000000000000005, the peer announced 0000000000000006");
125 free(err);
126
127 rm_rf(root);
128 free(p);
129 free(a);
130 free(b);
131 free(out);
132 free(toml);
133 free(esc);
134 free(ptx);
135 return mesh_check_done();
136}