mirror of
https://github.com/jamesstringer90/appsandbox.git
synced 2026-10-19 01:31:28 -05:00
Fix Ubuntu ISO build dependency version selection
This commit is contained in:
1 parent
abbbdae31f
commit
6d2e10fd0b
5 files changed
+263
-81
No files matched your search
@@ -1971,7 +1971,8 @@ static int generate_vhdx_manifest_ubuntu(const wchar_t *manifest_path,
|
||||
* Output buffers should be at least 64 wchars each. */
|
||||
static int detect_iso_kernel(const wchar_t *iso_path,
|
||||
wchar_t *codename_out, size_t codename_cap,
|
||||
wchar_t *kver_out, size_t kver_cap)
|
||||
wchar_t *kver_out, size_t kver_cap,
|
||||
HANDLE *iso_out, wchar_t *drive_out)
|
||||
{
|
||||
HANDLE iso_handle = INVALID_HANDLE_VALUE;
|
||||
DWORD cdrom_before, cdrom_after, newly;
|
||||
@@ -1980,6 +1981,8 @@ static int detect_iso_kernel(const wchar_t *iso_path,
|
||||
|
||||
codename_out[0] = 0;
|
||||
kver_out[0] = 0;
|
||||
*iso_out = INVALID_HANDLE_VALUE;
|
||||
*drive_out = 0;
|
||||
|
||||
/* Snapshot current CD-ROM drive letters before mount. */
|
||||
cdrom_before = 0;
|
||||
@@ -2128,6 +2131,9 @@ static int detect_iso_kernel(const wchar_t *iso_path,
|
||||
}
|
||||
|
||||
asb_log(L"detect_iso_kernel: codename=%s kver=%s", codename_out, kver_out);
|
||||
*iso_out = iso_handle;
|
||||
*drive_out = iso_drive;
|
||||
iso_handle = INVALID_HANDLE_VALUE;
|
||||
rc = 0;
|
||||
|
||||
cleanup:
|
||||
@@ -2383,17 +2389,22 @@ static DWORD WINAPI linux_create_thread(LPVOID param)
|
||||
Needs (codename, kernel) detected from the ISO. */
|
||||
asb_log(L"Prefetch 2/3: apt build-deps closure...");
|
||||
wchar_t codename[64] = L"", kver[64] = L"";
|
||||
HANDLE iso_handle = INVALID_HANDLE_VALUE;
|
||||
wchar_t iso_drive = 0;
|
||||
if (detect_iso_kernel(args->config.image_path,
|
||||
codename, ARRAYSIZE(codename),
|
||||
kver, ARRAYSIZE(kver)) == 0) {
|
||||
kver, ARRAYSIZE(kver),
|
||||
&iso_handle, &iso_drive) == 0) {
|
||||
wchar_t apt_out[MAX_PATH];
|
||||
swprintf_s(apt_out, MAX_PATH, L"%s\\local-apt-extras", extras);
|
||||
swprintf_s(args_buf, 2048,
|
||||
L"--prefetch-build-deps --codename \"%s\" --kernel \"%s\" "
|
||||
L"--out-dir \"%s\"",
|
||||
codename, kver, apt_out);
|
||||
L"--out-dir \"%s\" --iso-root \"%c:\"",
|
||||
codename, kver, apt_out, iso_drive);
|
||||
if (spawn_iso_patch_prefetch(args_buf) != 0)
|
||||
asb_log(L"WARN: prefetch-build-deps failed");
|
||||
DetachVirtualDisk(iso_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);
|
||||
CloseHandle(iso_handle);
|
||||
} else {
|
||||
asb_log(L"WARN: could not detect ISO kernel — skipping build-deps");
|
||||
}
|
||||
|
||||
@@ -2922,7 +2922,7 @@ int wmain(int argc, wchar_t *argv[])
|
||||
|
||||
if (_wcsicmp(argv[1], L"--prefetch-build-deps") == 0) {
|
||||
const wchar_t *codename = NULL, *kver = NULL;
|
||||
const wchar_t *out_dir = NULL, *mirror = NULL;
|
||||
const wchar_t *out_dir = NULL, *mirror = NULL, *iso_root = NULL;
|
||||
for (int i = 2; i < argc; i++) {
|
||||
if (_wcsicmp(argv[i], L"--codename") == 0 && i + 1 < argc) {
|
||||
codename = argv[++i];
|
||||
@@ -2932,13 +2932,15 @@ int wmain(int argc, wchar_t *argv[])
|
||||
out_dir = argv[++i];
|
||||
} else if (_wcsicmp(argv[i], L"--mirror") == 0 && i + 1 < argc) {
|
||||
mirror = argv[++i];
|
||||
} else if (_wcsicmp(argv[i], L"--iso-root") == 0 && i + 1 < argc) {
|
||||
iso_root = argv[++i];
|
||||
}
|
||||
}
|
||||
if (!codename || !kver || !out_dir) {
|
||||
log_err(L"--prefetch-build-deps requires --codename, --kernel, --out-dir");
|
||||
if (!codename || !kver || !out_dir || !iso_root) {
|
||||
log_err(L"--prefetch-build-deps requires --codename, --kernel, --out-dir, --iso-root");
|
||||
return 1;
|
||||
}
|
||||
return do_prefetch_build_deps(codename, kver, out_dir, mirror);
|
||||
return do_prefetch_build_deps(codename, kver, out_dir, mirror, iso_root);
|
||||
}
|
||||
|
||||
if (_wcsicmp(argv[1], L"--ubuntu-to-vhdx") == 0) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/* prefetch_build_deps.c - see header for design.
|
||||
*
|
||||
* Pipeline:
|
||||
* 1. WinHTTP-download Packages.xz for <codename>/main/binary-<arch>
|
||||
* 1. WinHTTP-download main/binary-<arch>/Packages.xz for the release,
|
||||
* updates and security pockets.
|
||||
* 2. Decompress it in-process with the vendored xz-embedded decoder
|
||||
* (xz_decompress_file_to_file below; Packages.gz is raw-gzipped
|
||||
* text that tar.exe rejects, so we target the .xz instead).
|
||||
@@ -9,7 +10,7 @@
|
||||
* Package name. Each stanza is stored verbatim so we can write
|
||||
* it back into the synthetic Packages we ship.
|
||||
* 4. BFS the Depends:/Pre-Depends: closure from seed packages.
|
||||
* Disjunctions ("a | b"): take the first alternative that exists.
|
||||
* Match source versions to the ISO; leave dependency resolution to APT.
|
||||
* 5. For each pkg in closure: WinHTTP-download the .deb, verify
|
||||
* its SHA256 against the Packages metadata.
|
||||
* 6. Write synthetic Packages with the closure stanzas, but
|
||||
@@ -27,6 +28,7 @@
|
||||
#include "prefetch_build_deps.h"
|
||||
#include "iso_patch_log.h"
|
||||
#include "target_arch.h"
|
||||
#include "engine/squashfs.h"
|
||||
#include "engine/xz/xz.h"
|
||||
|
||||
#include <windows.h>
|
||||
@@ -378,6 +380,14 @@ cleanup:
|
||||
typedef struct pkg_record {
|
||||
const char *name; /* not null-terminated; use name_len */
|
||||
size_t name_len;
|
||||
const char *version;
|
||||
size_t version_len;
|
||||
const char *source;
|
||||
size_t source_len;
|
||||
const char *source_version;
|
||||
size_t source_version_len;
|
||||
const char *status;
|
||||
size_t status_len;
|
||||
const char *filename;
|
||||
size_t filename_len;
|
||||
const char *sha256_hex;
|
||||
@@ -390,6 +400,7 @@ typedef struct pkg_record {
|
||||
size_t stanza_len; /* length of the stanza (no trailing blank) */
|
||||
int in_closure; /* set during BFS */
|
||||
struct pkg_record *bucket_next;
|
||||
struct pkg_record *source_next;
|
||||
} pkg_record_t;
|
||||
|
||||
#define PKG_HASH_BUCKETS 4096 /* >> 4500 packages */
|
||||
@@ -400,6 +411,7 @@ typedef struct {
|
||||
pkg_record_t *records;
|
||||
size_t n_records;
|
||||
pkg_record_t *buckets[PKG_HASH_BUCKETS];
|
||||
pkg_record_t *sources[PKG_HASH_BUCKETS];
|
||||
} pkg_table_t;
|
||||
|
||||
static size_t hash_name(const char *s, size_t len)
|
||||
@@ -436,6 +448,78 @@ static pkg_record_t *lookup_pkg(pkg_table_t *t, const char *name, size_t len)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static pkg_record_t *lookup_source(pkg_table_t *t, const char *name, size_t len)
|
||||
{
|
||||
for (pkg_record_t *r = t->sources[hash_name(name, len)]; r; r = r->source_next) {
|
||||
if (name_eq(r->source, r->source_len, name, len)) return r;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mark_packages(pkg_table_t *t, pkg_table_t *installed, pkg_table_t *iso,
|
||||
const char *name, size_t len)
|
||||
{
|
||||
if (lookup_pkg(installed, name, len)) return 0;
|
||||
pkg_record_t *local = lookup_pkg(iso, name, len);
|
||||
if (local) {
|
||||
if (local->in_closure) return 0;
|
||||
local->in_closure = 1;
|
||||
return 1;
|
||||
}
|
||||
int added = 0, matched = 0;
|
||||
for (pkg_record_t *r = t->buckets[hash_name(name, len)]; r; r = r->bucket_next) {
|
||||
if (!name_eq(r->name, r->name_len, name, len)) continue;
|
||||
pkg_record_t *pin = lookup_source(installed, r->source, r->source_len);
|
||||
if (!pin) pin = lookup_source(iso, r->source, r->source_len);
|
||||
if (pin && (pin->source_version_len != r->source_version_len ||
|
||||
memcmp(pin->source_version, r->source_version,
|
||||
r->source_version_len) != 0)) continue;
|
||||
matched = 1;
|
||||
if (!r->in_closure) {
|
||||
r->in_closure = 1;
|
||||
added++;
|
||||
}
|
||||
}
|
||||
if (!matched && lookup_pkg(t, name, len)) return -1;
|
||||
return added;
|
||||
}
|
||||
|
||||
static void index_package(pkg_table_t *t, pkg_record_t *r)
|
||||
{
|
||||
if (r->status && (r->status_len < 13 ||
|
||||
memcmp(r->status + r->status_len - 13, " ok installed", 13) != 0)) return;
|
||||
r->source_version = r->version;
|
||||
r->source_version_len = r->version_len;
|
||||
if (!r->source) {
|
||||
r->source = r->name;
|
||||
r->source_len = r->name_len;
|
||||
} else {
|
||||
const char *end = r->source + r->source_len;
|
||||
const char *p = r->source;
|
||||
while (p < end && *p != ' ' && *p != '(') p++;
|
||||
r->source_len = (size_t)(p - r->source);
|
||||
while (p < end && *p != '(') p++;
|
||||
if (p < end) {
|
||||
r->source_version = ++p;
|
||||
while (p < end && *p != ')') p++;
|
||||
r->source_version_len = (size_t)(p - r->source_version);
|
||||
}
|
||||
}
|
||||
size_t h = hash_name(r->name, r->name_len);
|
||||
for (pkg_record_t *p = t->buckets[h]; p; p = p->bucket_next) {
|
||||
if (r->filename && p->filename && r->sha256_hex && p->sha256_hex &&
|
||||
r->filename_len == p->filename_len && r->sha256_len == p->sha256_len &&
|
||||
memcmp(r->filename, p->filename, r->filename_len) == 0 &&
|
||||
memcmp(r->sha256_hex, p->sha256_hex, r->sha256_len) == 0)
|
||||
return;
|
||||
}
|
||||
r->bucket_next = t->buckets[h];
|
||||
t->buckets[h] = r;
|
||||
h = hash_name(r->source, r->source_len);
|
||||
r->source_next = t->sources[h];
|
||||
t->sources[h] = r;
|
||||
}
|
||||
|
||||
/* For a "Key: value" line, return (key, val) views or NULL if not a
|
||||
* "Key:" line. Continuation lines (leading whitespace) are not
|
||||
* handled here — the parser skips them. */
|
||||
@@ -507,9 +591,7 @@ static int parse_packages(pkg_table_t *t)
|
||||
(cur->stanza_start[cur->stanza_len - 1] == '\n' ||
|
||||
cur->stanza_start[cur->stanza_len - 1] == '\r'))
|
||||
cur->stanza_len--;
|
||||
size_t h = hash_name(cur->name, cur->name_len);
|
||||
cur->bucket_next = t->buckets[h];
|
||||
t->buckets[h] = cur;
|
||||
index_package(t, cur);
|
||||
ri++;
|
||||
}
|
||||
cur = NULL;
|
||||
@@ -522,6 +604,12 @@ static int parse_packages(pkg_table_t *t)
|
||||
if (cur) {
|
||||
if (kl == 7 && memcmp(k, "Package", 7) == 0) {
|
||||
cur->name = v; cur->name_len = vl;
|
||||
} else if (kl == 7 && memcmp(k, "Version", 7) == 0) {
|
||||
cur->version = v; cur->version_len = vl;
|
||||
} else if (kl == 6 && memcmp(k, "Source", 6) == 0) {
|
||||
cur->source = v; cur->source_len = vl;
|
||||
} else if (kl == 6 && memcmp(k, "Status", 6) == 0) {
|
||||
cur->status = v; cur->status_len = vl;
|
||||
} else if (kl == 8 && memcmp(k, "Filename", 8) == 0) {
|
||||
cur->filename = v; cur->filename_len = vl;
|
||||
} else if (kl == 6 && memcmp(k, "SHA256", 6) == 0) {
|
||||
@@ -542,16 +630,15 @@ static int parse_packages(pkg_table_t *t)
|
||||
if (cur && cur->name && !cur->stanza_start) {
|
||||
cur->stanza_start = stanza_start;
|
||||
cur->stanza_len = (size_t)(end - stanza_start);
|
||||
size_t h = hash_name(cur->name, cur->name_len);
|
||||
cur->bucket_next = t->buckets[h];
|
||||
t->buckets[h] = cur;
|
||||
index_package(t, cur);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* BFS one pass: for each pkg already in_closure, walk Depends + Pre-Depends.
|
||||
* Returns count of NEW pkgs added in this pass. */
|
||||
static int bfs_add_deps(pkg_table_t *t, pkg_record_t *r, int *added_count)
|
||||
static int bfs_add_deps(pkg_table_t *t, pkg_table_t *installed, pkg_table_t *iso,
|
||||
pkg_record_t *r, int *added_count)
|
||||
{
|
||||
const char *fields[2] = { r->depends, r->predepends };
|
||||
size_t lens[2] = { r->depends_len, r->predepends_len };
|
||||
@@ -561,28 +648,44 @@ static int bfs_add_deps(pkg_table_t *t, pkg_record_t *r, int *added_count)
|
||||
if (!p || n == 0) continue;
|
||||
const char *q = p;
|
||||
size_t i = 0;
|
||||
int available = 0;
|
||||
while (i <= n) {
|
||||
/* Walk to next ',' or end -> one Depends element. */
|
||||
if (i == n || p[i] == ',') {
|
||||
size_t elen = (size_t)(p + i - q);
|
||||
/* Take first alternative (split on '|'). */
|
||||
const char *alt_end = q;
|
||||
while (alt_end < q + elen && *alt_end != '|') alt_end++;
|
||||
size_t alen = (size_t)(alt_end - q);
|
||||
if (i == n || p[i] == ',' || p[i] == '|') {
|
||||
size_t alen = (size_t)(p + i - q);
|
||||
/* Trim trailing/leading WS. */
|
||||
while (alen > 0 && (q[0] == ' ' || q[0] == '\t')) { q++; alen--; }
|
||||
while (alen > 0 && (q[alen - 1] == ' ' || q[alen - 1] == '\t' ||
|
||||
q[alen - 1] == '\n')) alen--;
|
||||
/* Strip version constraint "(...)" */
|
||||
const char *paren = q;
|
||||
while (paren < q + alen && *paren != ' ' && *paren != '(') paren++;
|
||||
while (paren < q + alen && *paren != ' ' && *paren != '\t' &&
|
||||
*paren != '(' && *paren != ':') paren++;
|
||||
size_t name_len = (size_t)(paren - q);
|
||||
if (paren < q + alen && *paren == ':') {
|
||||
const char *arch = paren + 1, *end = arch;
|
||||
while (end < q + alen && *end != ' ' && *end != '\t' && *end != '(') end++;
|
||||
size_t arch_len = (size_t)(end - arch);
|
||||
if (!name_eq(arch, arch_len, "any", 3) &&
|
||||
!name_eq(arch, arch_len, "native", 6) &&
|
||||
!name_eq(arch, arch_len, IP_DEB_ARCH_A, strlen(IP_DEB_ARCH_A)))
|
||||
name_len = 0;
|
||||
}
|
||||
if (name_len > 0) {
|
||||
pkg_record_t *dep = lookup_pkg(t, q, name_len);
|
||||
if (dep && !dep->in_closure) {
|
||||
dep->in_closure = 1;
|
||||
(*added_count)++;
|
||||
int added = mark_packages(t, installed, iso, q, name_len);
|
||||
if (added >= 0) {
|
||||
available = 1;
|
||||
*added_count += added;
|
||||
}
|
||||
} else {
|
||||
available = 1;
|
||||
}
|
||||
if (i == n || p[i] == ',') {
|
||||
if (!available) {
|
||||
log_err(L"prefetch: no ISO-compatible dependency '%.*hs' for '%.*hs'",
|
||||
(int)name_len, q, (int)r->name_len, r->name);
|
||||
return -1;
|
||||
}
|
||||
available = 0;
|
||||
}
|
||||
q = p + i + 1;
|
||||
}
|
||||
@@ -683,10 +786,53 @@ static int write_closure_json(pkg_table_t *t,
|
||||
* Main entry point
|
||||
* ==================================================================== */
|
||||
|
||||
static int append_package_file(pkg_table_t *t, const wchar_t *path)
|
||||
{
|
||||
HANDLE h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) return -1;
|
||||
LARGE_INTEGER sz;
|
||||
if (!GetFileSizeEx(h, &sz) || sz.QuadPart < 0 || sz.QuadPart > 64 * 1024 * 1024) {
|
||||
CloseHandle(h);
|
||||
return -1;
|
||||
}
|
||||
char *buf = (char *)realloc(t->buf, t->buf_len + (size_t)sz.QuadPart + 3);
|
||||
if (!buf) { CloseHandle(h); return -1; }
|
||||
t->buf = buf;
|
||||
DWORD br = 0;
|
||||
BOOL ok = ReadFile(h, buf + t->buf_len, (DWORD)sz.QuadPart, &br, NULL);
|
||||
CloseHandle(h);
|
||||
if (!ok || br != sz.QuadPart) return -1;
|
||||
t->buf_len += br;
|
||||
t->buf[t->buf_len++] = '\n';
|
||||
t->buf[t->buf_len++] = '\n';
|
||||
t->buf[t->buf_len] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
sqfs_ctx_t *sq;
|
||||
pkg_table_t *packages;
|
||||
} installed_packages_t;
|
||||
|
||||
static int read_installed_packages(const sqfs_entry_t *entry, void *user)
|
||||
{
|
||||
if (strcmp(entry->path, "/var/lib/dpkg/status") != 0) return 0;
|
||||
installed_packages_t *ctx = (installed_packages_t *)user;
|
||||
void *data = NULL;
|
||||
size_t size = 0;
|
||||
if (sqfs_read_file(ctx->sq, entry, &data, &size) == 0) {
|
||||
ctx->packages->buf = (char *)data;
|
||||
ctx->packages->buf_len = size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_prefetch_build_deps(const wchar_t *codename,
|
||||
const wchar_t *kernel_ver,
|
||||
const wchar_t *out_dir,
|
||||
const wchar_t *mirror_arg)
|
||||
const wchar_t *mirror_arg,
|
||||
const wchar_t *iso_root)
|
||||
{
|
||||
const wchar_t *mirror = mirror_arg ? mirror_arg
|
||||
: L"http://archive.ubuntu.com/ubuntu";
|
||||
@@ -699,57 +845,69 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
u_mkdir_p(out_dir);
|
||||
const wchar_t *staging = out_dir;
|
||||
|
||||
/* ---- 1. Download Packages.xz ---- */
|
||||
int rc = -1;
|
||||
pkg_table_t T = { 0 }, installed = { 0 }, iso = { 0 };
|
||||
wchar_t pkgs_xz[MAX_PATH], pkgs[MAX_PATH];
|
||||
swprintf_s(pkgs_xz, MAX_PATH, L"%s\\Packages.xz", staging);
|
||||
swprintf_s(pkgs, MAX_PATH, L"%s\\Packages", staging);
|
||||
|
||||
wchar_t path[MAX_PATH];
|
||||
swprintf_s(path, MAX_PATH, L"%s\\casper\\minimal.squashfs", iso_root);
|
||||
sqfs_ctx_t *sq = sqfs_open(path);
|
||||
if (!sq) goto cleanup;
|
||||
installed_packages_t ctx = { sq, &installed };
|
||||
sqfs_walk(sq, read_installed_packages, &ctx);
|
||||
sqfs_close(sq);
|
||||
if (!installed.buf || parse_packages(&installed) != 0) goto cleanup;
|
||||
|
||||
swprintf_s(path, MAX_PATH, L"%s\\dists\\%s\\main\\binary-" IP_DEB_ARCH L"\\Packages",
|
||||
iso_root, codename);
|
||||
if (append_package_file(&iso, path) != 0 || parse_packages(&iso) != 0) goto cleanup;
|
||||
|
||||
const wchar_t *pockets[] = { L"", L"-updates", L"-security" };
|
||||
wchar_t url[1024];
|
||||
swprintf_s(url, 1024, L"%s/dists/%s/main/binary-" IP_DEB_ARCH L"/Packages.xz",
|
||||
mirror, codename);
|
||||
log_msg(L"prefetch: GET %s", url);
|
||||
if (http_download(url, pkgs_xz) != 0) {
|
||||
log_err(L"prefetch: download Packages.xz failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 2. In-process xz decompression via vendored xz-embedded ---- */
|
||||
if (xz_decompress_file_to_file(pkgs_xz, pkgs) != 0) {
|
||||
log_err(L"prefetch: xz decompress failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ---- 3. Slurp Packages into memory + parse ---- */
|
||||
pkg_table_t T = { 0 };
|
||||
{
|
||||
HANDLE h = CreateFileW(pkgs, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (h == INVALID_HANDLE_VALUE) { log_err(L"prefetch: open Packages failed"); return -1; }
|
||||
LARGE_INTEGER sz; GetFileSizeEx(h, &sz);
|
||||
T.buf_len = (size_t)sz.QuadPart;
|
||||
T.buf = (char *)malloc(T.buf_len + 1);
|
||||
if (!T.buf) { CloseHandle(h); return -1; }
|
||||
DWORD br = 0;
|
||||
if (!ReadFile(h, T.buf, (DWORD)T.buf_len, &br, NULL) || br != T.buf_len) {
|
||||
log_err(L"prefetch: read Packages failed"); CloseHandle(h); return -1;
|
||||
for (size_t i = 0; i < ARRAYSIZE(pockets); i++) {
|
||||
swprintf_s(url, 1024, L"%s/dists/%s%s/main/binary-" IP_DEB_ARCH L"/Packages.xz",
|
||||
mirror, codename, pockets[i]);
|
||||
log_msg(L"prefetch: GET %s", url);
|
||||
if (http_download(url, pkgs_xz) != 0) {
|
||||
log_err(L"prefetch: download Packages.xz failed");
|
||||
goto cleanup;
|
||||
}
|
||||
T.buf[T.buf_len] = 0;
|
||||
CloseHandle(h);
|
||||
if (xz_decompress_file_to_file(pkgs_xz, pkgs) != 0) {
|
||||
log_err(L"prefetch: xz decompress failed");
|
||||
goto cleanup;
|
||||
}
|
||||
if (append_package_file(&T, pkgs) != 0) {
|
||||
log_err(L"prefetch: read Packages failed");
|
||||
goto cleanup;
|
||||
}
|
||||
DeleteFileW(pkgs);
|
||||
}
|
||||
if (parse_packages(&T) != 0) { log_err(L"prefetch: parse failed"); return -1; }
|
||||
if (parse_packages(&T) != 0) { log_err(L"prefetch: parse failed"); goto cleanup; }
|
||||
log_msg(L"prefetch: parsed %zu package records", T.n_records);
|
||||
|
||||
/* ---- 4. Mark seeds in_closure ---- */
|
||||
const char *seeds[] = {
|
||||
"libasound2-dev", "libxcb1-dev", "libxcb-xfixes0-dev",
|
||||
"libdrm-dev", "libsystemd-dev", "pkg-config",
|
||||
"build-essential", "dkms", "zstd",
|
||||
"openssh-server" /* for ssh_enabled VMs; firstboot installs conditionally */
|
||||
};
|
||||
int closure_count = 0;
|
||||
for (size_t i = 0; i < sizeof(seeds) / sizeof(seeds[0]); i++) {
|
||||
pkg_record_t *r = lookup_pkg(&T, seeds[i], strlen(seeds[i]));
|
||||
if (!r) { log_msg(L"prefetch: WARN seed '%hs' not in archive", seeds[i]); continue; }
|
||||
if (!r->in_closure) { r->in_closure = 1; closure_count++; }
|
||||
int added = mark_packages(&T, &installed, &iso, seeds[i], strlen(seeds[i]));
|
||||
if (added < 0) {
|
||||
log_err(L"prefetch: no ISO-compatible package for '%hs'", seeds[i]);
|
||||
goto cleanup;
|
||||
}
|
||||
if (added == 0 && !lookup_pkg(&installed, seeds[i], strlen(seeds[i])) &&
|
||||
!lookup_pkg(&iso, seeds[i], strlen(seeds[i])) &&
|
||||
!lookup_pkg(&T, seeds[i], strlen(seeds[i]))) {
|
||||
log_msg(L"prefetch: WARN seed '%hs' not in archive", seeds[i]);
|
||||
continue;
|
||||
}
|
||||
closure_count += added;
|
||||
}
|
||||
/* Also linux-headers-<kver>. */
|
||||
{
|
||||
@@ -757,18 +915,24 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
char kver_utf8[64];
|
||||
WideCharToMultiByte(CP_UTF8, 0, kernel_ver, -1, kver_utf8, sizeof(kver_utf8), NULL, NULL);
|
||||
snprintf(hdr, sizeof(hdr), "linux-headers-%s", kver_utf8);
|
||||
pkg_record_t *r = lookup_pkg(&T, hdr, strlen(hdr));
|
||||
if (r && !r->in_closure) { r->in_closure = 1; closure_count++; }
|
||||
int added = mark_packages(&T, &installed, &iso, hdr, strlen(hdr));
|
||||
if (added < 0) goto cleanup;
|
||||
closure_count += added;
|
||||
}
|
||||
|
||||
/* ---- 5. BFS until stable ---- */
|
||||
int total_added = closure_count;
|
||||
for (int iter = 0; iter < 32; iter++) {
|
||||
int added = 0;
|
||||
for (size_t i = 0; i < iso.n_records; i++) {
|
||||
pkg_record_t *r = &iso.records[i];
|
||||
if (r->in_closure && bfs_add_deps(&T, &installed, &iso, r, &added) != 0)
|
||||
goto cleanup;
|
||||
}
|
||||
for (size_t i = 0; i < T.n_records; i++) {
|
||||
pkg_record_t *r = &T.records[i];
|
||||
if (!r->in_closure) continue;
|
||||
bfs_add_deps(&T, r, &added);
|
||||
if (bfs_add_deps(&T, &installed, &iso, r, &added) != 0) goto cleanup;
|
||||
}
|
||||
if (added == 0) break;
|
||||
total_added += added;
|
||||
@@ -787,7 +951,7 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
if (r->filename_len >= sizeof(fn_utf8)) {
|
||||
log_err(L"prefetch: Filename too long (%zu) for %.*hs",
|
||||
r->filename_len, (int)r->name_len, r->name);
|
||||
return -1;
|
||||
goto cleanup;
|
||||
}
|
||||
memcpy(fn_utf8, r->filename, r->filename_len); fn_utf8[r->filename_len] = 0;
|
||||
if (r->sha256_hex && r->sha256_len < sizeof(sha_utf8)) {
|
||||
@@ -806,18 +970,18 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
log_msg(L"prefetch: GET %s", basename);
|
||||
if (http_download(url2, dst) != 0) {
|
||||
log_err(L"prefetch: download %ls failed", basename);
|
||||
return -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (sha_utf8[0]) {
|
||||
char actual[65];
|
||||
if (sha256_file(dst, actual) != 0) {
|
||||
log_err(L"prefetch: SHA256 hash compute failed for %ls", basename);
|
||||
return -1;
|
||||
goto cleanup;
|
||||
}
|
||||
if (_stricmp(actual, sha_utf8) != 0) {
|
||||
log_err(L"prefetch: SHA256 mismatch for %ls (got %hs, want %hs)",
|
||||
basename, actual, sha_utf8);
|
||||
return -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
downloaded++;
|
||||
@@ -832,7 +996,7 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
DeleteFileW(synth);
|
||||
if (write_synth_packages(&T, synth) != 0) {
|
||||
log_err(L"prefetch: write synthetic Packages failed");
|
||||
return -1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -841,12 +1005,16 @@ int do_prefetch_build_deps(const wchar_t *codename,
|
||||
write_closure_json(&T, cj, codename, kernel_ver);
|
||||
}
|
||||
|
||||
/* Clean up Packages.xz — we don't ship it (we wrote our own
|
||||
synthetic Packages with closure entries only). */
|
||||
rc = 0;
|
||||
cleanup:
|
||||
DeleteFileW(pkgs_xz);
|
||||
|
||||
if (rc != 0) DeleteFileW(pkgs);
|
||||
free(T.buf);
|
||||
free(T.records);
|
||||
log_msg(L"prefetch: OK -> %s", out_dir);
|
||||
return 0;
|
||||
free(installed.buf);
|
||||
free(installed.records);
|
||||
free(iso.buf);
|
||||
free(iso.records);
|
||||
if (rc == 0) log_msg(L"prefetch: OK -> %s", out_dir);
|
||||
return rc;
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
int do_prefetch_build_deps(const wchar_t *codename,
|
||||
const wchar_t *kernel_ver,
|
||||
const wchar_t *out_dir,
|
||||
const wchar_t *mirror);
|
||||
const wchar_t *mirror,
|
||||
const wchar_t *iso_root);
|
||||
|
||||
#endif /* PREFETCH_BUILD_DEPS_H */
|
||||
@@ -1305,7 +1305,7 @@ static void plant_firstboot_service(ext4_writer_t *ew)
|
||||
"\n"
|
||||
"# All apt operations in firstboot use this APT_OPTS to force\n"
|
||||
"# apt to read ONLY our local sources (no network).\n"
|
||||
"APT_OPTS=\"-o Dir::Etc::sourcelist=/dev/null -o Dir::Etc::sourceparts=$APT_SOURCES_DIR\"\n"
|
||||
"APT_OPTS=\"-o Dir::Etc::sourcelist=/dev/null -o Dir::Etc::sourceparts=$APT_SOURCES_DIR -o APT::Install-Recommends=false -o APT::Install-Suggests=false\"\n"
|
||||
"\n"
|
||||
"# Offline apt update.\n"
|
||||
"if apt-get update $APT_OPTS 2>&1 | tail -10; then\n"
|
||||
@@ -1375,7 +1375,7 @@ static void plant_firstboot_service(ext4_writer_t *ew)
|
||||
" # Build, capturing log; pipefail propagates make's rc.\n"
|
||||
" if make -j$(nproc) 2>&1 | tail -20; then\n"
|
||||
" echo \"OK: make\"\n"
|
||||
" if make install PREFIX=/usr/local 2>&1 | tail -5; then\n"
|
||||
" if make install PREFIX=/usr/local SYSTEM_UNITS= USER_UNITS= 2>&1 | tail -5; then\n"
|
||||
" echo \"OK: make install\"\n"
|
||||
" else\n"
|
||||
" echo \"FAIL: make install (rc=$?)\"\n"
|
||||
@@ -1482,7 +1482,7 @@ static void plant_firstboot_service(ext4_writer_t *ew)
|
||||
"echo \"==== STEP 13: wsl-mesa ====\"\n"
|
||||
"if [ -f \"$EXTRAS/wsl-mesa.tar.zst\" ]; then\n"
|
||||
" if ! command -v zstd >/dev/null 2>&1; then\n"
|
||||
" DEBIAN_FRONTEND=noninteractive apt-get install -y zstd 2>&1 | tail -3\n"
|
||||
" DEBIAN_FRONTEND=noninteractive apt-get install -y $APT_OPTS zstd 2>&1 | tail -3\n"
|
||||
" fi\n"
|
||||
" if command -v zstd >/dev/null 2>&1; then\n"
|
||||
" zstd -d \"$EXTRAS/wsl-mesa.tar.zst\" -c | tar -C / -x \\\n"
|
||||
|
||||
Reference in new issue
Block a user