nbos

nbos

https://git.tonybtw.com/nbos.git git://git.tonybtw.com/nbos.git
3,843 bytes raw
1
#define _GNU_SOURCE
2
#include "build.h"
3
4
#include <errno.h>
5
#include <stdio.h>
6
#include <string.h>
7
#include <sys/stat.h>
8
#include <sys/types.h>
9
#include <unistd.h>
10
11
#include "fetch.h"
12
#include "run.h"
13
#include "sandbox.h"
14
#include "store.h"
15
16
#define WORK_ROOT "/var/lib/nb/work"
17
18
/**
19
 * build_pkg() - Realize one package into the store.
20
 * @a: Arena for path scratch space.
21
 * @p: Package to build.
22
 * @all_pkgs: Full package list for the system (currently unused).
23
 * @resolved_pkgs: Topologically-sorted resolved entries.
24
 * @pkg_idx: Index of @p within @resolved_pkgs.
25
 *
26
 * Idempotent: returns success immediately if the store path already
27
 * exists. Otherwise fetches the source tarball, extracts it, sets up
28
 * a sandbox containing the resolved deps, runs the build, and atomically
29
 * moves the output into the store.
30
 *
31
 * Return: REALIZE_OK_VAL on success, a tagged error otherwise.
32
 */
33
realize_error build_pkg(
34
    arena              *a,
35
    const pkg          *p,
36
    const pkg_refs     *all_pkgs,
37
    const resolved     *resolved_pkgs,
38
    size_t              pkg_idx)
39
{
40
    (void)all_pkgs;
41
42
    const char *store_path = resolved_pkgs[pkg_idx].store_path;
43
44
    if (store_path_exists(store_path)) {
45
        return REALIZE_OK_VAL;
46
    }
47
48
    const char *base = strrchr(store_path, '/');
49
    base = (base != nullptr) ? base + 1 : store_path;
50
51
    char *work_dir     = arena_sprintf(a, "%s/%s", WORK_ROOT, base);
52
    char *src_tarball  = arena_sprintf(a, "%s/source", work_dir);
53
    char *src_dir      = arena_sprintf(a, "%s/build", work_dir);
54
    char *sandbox_root = arena_sprintf(a, "%s/sandbox", work_dir);
55
    char *log_path     = arena_sprintf(a, "%s/build.log", work_dir);
56
    char *out_dir      = arena_sprintf(a, "%s/out", work_dir);
57
58
    if (work_dir == nullptr || src_tarball == nullptr || src_dir == nullptr || sandbox_root == nullptr || log_path == nullptr || out_dir == nullptr) {
59
        return (realize_error){
60
            .kind = REALIZE_E_STORE,
61
            .pkg_name = p->name,
62
            .errno_val = ENOMEM,
63
        };
64
    }
65
66
    if (mkdir(WORK_ROOT, 0755) < 0 && errno != EEXIST) {
67
        return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name,
68
                                .errno_val = errno };
69
    }
70
    if (mkdir(work_dir, 0755) < 0 && errno != EEXIST) {
71
        return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name,
72
                                .errno_val = errno };
73
    }
74
75
    fetch_error ferr = fetch(p, src_tarball);
76
    if (ferr.kind != FETCH_OK) {
77
        return (realize_error){
78
            .kind = REALIZE_E_FETCH,
79
            .pkg_name = p->name,
80
            .fetch = ferr,
81
        };
82
    }
83
84
    if (mkdir(src_dir, 0755) < 0 && errno != EEXIST) {
85
        return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name,
86
                                .errno_val = errno };
87
    }
88
89
    char *const tar_argv[] = {
90
        "/usr/bin/tar", "-xf", src_tarball, "-C", src_dir, "--strip-components=1",
91
        nullptr,
92
    };
93
    char *const tar_envp[] = { nullptr };
94
95
    run_error tar_err = run("/usr/bin/tar", tar_argv, tar_envp, nullptr, log_path);
96
    if (tar_err.kind != RUN_OK) {
97
        return (realize_error){
98
            .kind = REALIZE_E_BUILD,
99
            .pkg_name = p->name,
100
            .run = tar_err,
101
        };
102
    }
103
104
    int src = sandbox_setup(sandbox_root, &p->deps, resolved_pkgs, src_dir);
105
    if (src != 0) {
106
        return (realize_error){
107
            .kind = REALIZE_E_SANDBOX,
108
            .pkg_name = p->name,
109
            .errno_val = src,
110
        };
111
    }
112
113
    sandbox_teardown(sandbox_root);
114
115
    int rc = store_install(out_dir, store_path);
116
    if (rc != 0) {
117
        return (realize_error){
118
            .kind = REALIZE_E_STORE,
119
            .pkg_name = p->name,
120
            .errno_val = rc,
121
        };
122
    }
123
124
    return REALIZE_OK_VAL;
125
}