Mercurial
diff mrjunejune/latex_renderer.c @ 247:70f2a3dafc1c
[build] Bundle offline Tectonic runtime
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 03 Aug 2026 20:20:06 -0700 |
| parents | b8aa08503378 |
| children | b8b6e726964a |
line wrap: on
line diff
--- a/mrjunejune/latex_renderer.c Mon Aug 03 18:30:45 2026 -0700 +++ b/mrjunejune/latex_renderer.c Mon Aug 03 20:20:06 2026 -0700 @@ -44,6 +44,10 @@ #define LATEX_DIAGNOSTICS_MAX_BYTES (16 * 1024) #define LATEX_CPU_TIMEOUT_SECONDS 5 #define LATEX_WALL_TIMEOUT_SECONDS 8 +#define TECTONIC_BUNDLE_URL "https://data1.fullyjustified.net/tlextras-2022.0r0.tar" +#define TECTONIC_CACHE_PATH "third_party/tectonic/runtime/cache" +#define TECTONIC_COMPILER_PATH "third_party/tectonic/runtime/bin/tectonic" +#define TECTONIC_FONTCONFIG_SYSROOT_PATH "third_party/tectonic/runtime/sysroot" static char *duplicate_message(const char *message) { @@ -166,7 +170,56 @@ return ok; } -static bool apply_filesystem_sandbox(const char *job_directory) +static bool add_landlock_tree_rules( + int ruleset_fd, + const char *path, + uint64_t access, + unsigned depth) +{ + if (depth > 32 || + !add_landlock_path_rule(ruleset_fd, path, access, true)) + return false; + + struct stat status; + if (lstat(path, &status) != 0) + return false; + if (!S_ISDIR(status.st_mode)) + return true; + + DIR *directory = opendir(path); + if (!directory) + return false; + bool ok = true; + struct dirent *entry; + while (ok && (entry = readdir(directory)) != NULL) + { + if (strcmp(entry->d_name, ".") == 0 || + strcmp(entry->d_name, "..") == 0) + continue; + char child[PATH_MAX]; + int length = snprintf( + child, + sizeof(child), + "%s/%s", + path, + entry->d_name); + ok = length >= 0 && + (size_t)length < sizeof(child) && + add_landlock_tree_rules( + ruleset_fd, + child, + access, + depth + 1); + } + closedir(directory); + return ok; +} + +static bool apply_filesystem_sandbox( + const char *job_directory, + const char *compiler, + const char *cache_directory, + const char *fontconfig_sysroot) { int abi = syscall( SYS_landlock_create_ruleset, @@ -207,32 +260,25 @@ if (ruleset_fd < 0) return false; - const char *read_only_directories[] = { - "/usr", - "/lib", - "/lib64", - "/bin", - "/var/lib/texmf", - "/etc/texmf", - "/etc/fonts", - }; bool ok = true; - for (size_t i = 0; - ok && i < sizeof(read_only_directories) / sizeof(read_only_directories[0]); - i++) - { - ok = add_landlock_path_rule( - ruleset_fd, - read_only_directories[i], - read_access, - false); - } if (ok) ok = add_landlock_path_rule( ruleset_fd, - "/etc/ld.so.cache", - LANDLOCK_ACCESS_FS_READ_FILE, - false); + compiler, + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_READ_FILE, + true); + if (ok) + ok = add_landlock_tree_rules( + ruleset_fd, + cache_directory, + read_access | LANDLOCK_ACCESS_FS_MAKE_DIR, + 0); + if (ok) + ok = add_landlock_tree_rules( + ruleset_fd, + fontconfig_sysroot, + read_access, + 0); if (ok) ok = add_landlock_path_rule( ruleset_fd, @@ -310,17 +356,28 @@ return prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &program) == 0; } -static void configure_child_environment(const char *job_directory) +static void configure_child_environment( + const char *job_directory, + const char *cache_directory, + const char *fontconfig_sysroot) { clearenv(); setenv("HOME", job_directory, 1); setenv("TMPDIR", job_directory, 1); - setenv("TEXMFVAR", job_directory, 1); - setenv("TEXMFCONFIG", job_directory, 1); - setenv("openin_any", "p", 1); - setenv("openout_any", "p", 1); - setenv("shell_escape", "0", 1); + setenv("XDG_CACHE_HOME", job_directory, 1); + char tectonic_cache[PATH_MAX]; + snprintf( + tectonic_cache, + sizeof(tectonic_cache), + "%s/tectonic", + cache_directory); + setenv("TECTONIC_CACHE_DIR", tectonic_cache, 1); + setenv("FONTCONFIG_FILE", "fonts.conf", 1); + setenv("FONTCONFIG_PATH", "/etc/fonts", 1); + setenv("FONTCONFIG_SYSROOT", fontconfig_sysroot, 1); + setenv("TECTONIC_UNTRUSTED_MODE", "1", 1); setenv("SOURCE_DATE_EPOCH", "0", 1); + setenv("TZ", "UTC", 1); setenv("LANG", "C.UTF-8", 1); } @@ -342,6 +399,8 @@ static void run_compiler_child( const char *compiler, + const char *cache_directory, + const char *fontconfig_sysroot, const char *job_directory, int output_fd) { @@ -358,24 +417,38 @@ if (chdir(job_directory) != 0) _exit(121); - configure_child_environment(job_directory); + configure_child_environment( + job_directory, + cache_directory, + fontconfig_sysroot); if (!set_limit(RLIMIT_CPU, LATEX_CPU_TIMEOUT_SECONDS) || !set_limit(RLIMIT_AS, 768 * 1024 * 1024) || !set_limit(RLIMIT_FSIZE, LATEX_PDF_MAX_BYTES) || !set_limit(RLIMIT_NOFILE, 64) || !set_limit(RLIMIT_NPROC, 1)) _exit(122); - if (!apply_filesystem_sandbox(job_directory) || + if (!apply_filesystem_sandbox( + job_directory, + compiler, + cache_directory, + fontconfig_sysroot) || !apply_network_sandbox()) _exit(123); char *const arguments[] = { (char *)compiler, - "-interaction=nonstopmode", - "-halt-on-error", - "-no-shell-escape", - "-file-line-error", - "-output-directory=.", + "--untrusted", + "--only-cached", + "--chatter", + "minimal", + "--color", + "never", + "--reruns", + "1", + "--outdir", + ".", + "--bundle", + TECTONIC_BUNDLE_URL, "document.tex", NULL, }; @@ -518,6 +591,71 @@ return true; } +static bool resolve_runtime_path( + const char *relative_path, + char resolved[PATH_MAX]) +{ + if (realpath(relative_path, resolved)) + return true; + + const char *runfiles = getenv("RUNFILES_DIR"); + const char *workspace = getenv("TEST_WORKSPACE"); + char candidate[PATH_MAX]; + if (runfiles && workspace) + { + int length = snprintf( + candidate, + sizeof(candidate), + "%s/%s/%s", + runfiles, + workspace, + relative_path); + if (length >= 0 && + (size_t)length < sizeof(candidate) && + realpath(candidate, resolved)) + return true; + } + + char executable[PATH_MAX]; + ssize_t executable_length = readlink( + "/proc/self/exe", + executable, + sizeof(executable) - 1); + if (executable_length <= 0) + return false; + executable[executable_length] = '\0'; + + char *last_slash = strrchr(executable, '/'); + if (last_slash) + { + *last_slash = '\0'; + int length = snprintf( + candidate, + sizeof(candidate), + "%s/%s", + executable, + relative_path); + if (length >= 0 && + (size_t)length < sizeof(candidate) && + realpath(candidate, resolved)) + return true; + } + + char *package = strstr(executable, "/mrjunejune/"); + if (!package) + return false; + *package = '\0'; + int length = snprintf( + candidate, + sizeof(candidate), + "%s/%s", + executable, + relative_path); + return length >= 0 && + (size_t)length < sizeof(candidate) && + realpath(candidate, resolved) != NULL; +} + Latex_Render_Result Latex_Render(const uint8_t *source, size_t source_size) { if (!source || source_size == 0) @@ -533,11 +671,18 @@ LATEX_RENDER_INVALID_INPUT, "LaTeX source cannot contain NUL bytes."); - const char *compiler = "/usr/bin/pdflatex"; - if (access(compiler, X_OK) != 0) + char compiler[PATH_MAX]; + char cache_directory[PATH_MAX]; + char fontconfig_sysroot[PATH_MAX]; + if (!resolve_runtime_path(TECTONIC_COMPILER_PATH, compiler) || + !resolve_runtime_path(TECTONIC_CACHE_PATH, cache_directory) || + !resolve_runtime_path( + TECTONIC_FONTCONFIG_SYSROOT_PATH, + fontconfig_sysroot) || + access(compiler, X_OK) != 0) return result_with_message( LATEX_RENDER_COMPILER_UNAVAILABLE, - "The server LaTeX compiler is unavailable."); + "The Bazel Tectonic runtime is unavailable."); char job_directory[] = "/tmp/mrjunejune-latex-XXXXXX"; if (!mkdtemp(job_directory)) @@ -588,7 +733,12 @@ if (child == 0) { close(output_pipe[0]); - run_compiler_child(compiler, job_directory, output_pipe[1]); + run_compiler_child( + compiler, + cache_directory, + fontconfig_sysroot, + job_directory, + output_pipe[1]); } setpgid(child, child);