#define _GNU_SOURCE #include "build.h" #include #include #include #include #include #include #include "fetch.h" #include "run.h" #include "sandbox.h" #include "store.h" #define WORK_ROOT "/var/lib/nb/work" /** * build_pkg() - Realize one package into the store. * @a: Arena for path scratch space. * @p: Package to build. * @all_pkgs: Full package list for the system (currently unused). * @resolved_pkgs: Topologically-sorted resolved entries. * @pkg_idx: Index of @p within @resolved_pkgs. * * Idempotent: returns success immediately if the store path already * exists. Otherwise fetches the source tarball, extracts it, sets up * a sandbox containing the resolved deps, runs the build, and atomically * moves the output into the store. * * Return: REALIZE_OK_VAL on success, a tagged error otherwise. */ realize_error build_pkg( arena *a, const pkg *p, const pkg_refs *all_pkgs, const resolved *resolved_pkgs, size_t pkg_idx) { (void)all_pkgs; const char *store_path = resolved_pkgs[pkg_idx].store_path; if (store_path_exists(store_path)) { return REALIZE_OK_VAL; } const char *base = strrchr(store_path, '/'); base = (base != nullptr) ? base + 1 : store_path; char *work_dir = arena_sprintf(a, "%s/%s", WORK_ROOT, base); char *src_tarball = arena_sprintf(a, "%s/source", work_dir); char *src_dir = arena_sprintf(a, "%s/build", work_dir); char *sandbox_root = arena_sprintf(a, "%s/sandbox", work_dir); char *log_path = arena_sprintf(a, "%s/build.log", work_dir); char *out_dir = arena_sprintf(a, "%s/out", work_dir); if (work_dir == nullptr || src_tarball == nullptr || src_dir == nullptr || sandbox_root == nullptr || log_path == nullptr || out_dir == nullptr) { return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name, .errno_val = ENOMEM, }; } if (mkdir(WORK_ROOT, 0755) < 0 && errno != EEXIST) { return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name, .errno_val = errno }; } if (mkdir(work_dir, 0755) < 0 && errno != EEXIST) { return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name, .errno_val = errno }; } fetch_error ferr = fetch(p, src_tarball); if (ferr.kind != FETCH_OK) { return (realize_error){ .kind = REALIZE_E_FETCH, .pkg_name = p->name, .fetch = ferr, }; } if (mkdir(src_dir, 0755) < 0 && errno != EEXIST) { return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name, .errno_val = errno }; } char *const tar_argv[] = { "/usr/bin/tar", "-xf", src_tarball, "-C", src_dir, "--strip-components=1", nullptr, }; char *const tar_envp[] = { nullptr }; run_error tar_err = run("/usr/bin/tar", tar_argv, tar_envp, nullptr, log_path); if (tar_err.kind != RUN_OK) { return (realize_error){ .kind = REALIZE_E_BUILD, .pkg_name = p->name, .run = tar_err, }; } int src = sandbox_setup(sandbox_root, &p->deps, resolved_pkgs, src_dir); if (src != 0) { return (realize_error){ .kind = REALIZE_E_SANDBOX, .pkg_name = p->name, .errno_val = src, }; } sandbox_teardown(sandbox_root); int rc = store_install(out_dir, store_path); if (rc != 0) { return (realize_error){ .kind = REALIZE_E_STORE, .pkg_name = p->name, .errno_val = rc, }; } return REALIZE_OK_VAL; }