skip to content
==> 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}