Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Create, read, edit, and manipulate Word (.docx) documents with formatting, tables, and tracked changes
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
scripts/office/soffice.py
1"""2Helper for running LibreOffice (soffice) in environments where AF_UNIX3sockets may be blocked (e.g., sandboxed VMs). Detects the restriction4at runtime and applies an LD_PRELOAD shim if needed.56Usage:7from office.soffice import run_soffice, get_soffice_env89# Option 1 – run soffice directly10result = run_soffice(["--headless", "--convert-to", "pdf", "input.docx"])1112# Option 2 – get env dict for your own subprocess calls13env = get_soffice_env()14subprocess.run(["soffice", ...], env=env)15"""1617import os18import socket19import subprocess20import tempfile21from pathlib import Path222324def get_soffice_env() -> dict:25env = os.environ.copy()26env["SAL_USE_VCLPLUGIN"] = "svp"2728if _needs_shim():29shim = _ensure_shim()30env["LD_PRELOAD"] = str(shim)3132return env333435def run_soffice(args: list[str], **kwargs) -> subprocess.CompletedProcess:36env = get_soffice_env()37return subprocess.run(["soffice"] + args, env=env, **kwargs)38394041_SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so"424344def _needs_shim() -> bool:45try:46s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)47s.close()48return False49except OSError:50return True515253def _ensure_shim() -> Path:54if _SHIM_SO.exists():55return _SHIM_SO5657src = Path(tempfile.gettempdir()) / "lo_socket_shim.c"58src.write_text(_SHIM_SOURCE)59subprocess.run(60["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"],61check=True,62capture_output=True,63)64src.unlink()65return _SHIM_SO66676869_SHIM_SOURCE = r"""70#define _GNU_SOURCE71#include <dlfcn.h>72#include <errno.h>73#include <signal.h>74#include <stdio.h>75#include <stdlib.h>76#include <sys/socket.h>77#include <unistd.h>7879static int (*real_socket)(int, int, int);80static int (*real_socketpair)(int, int, int, int[2]);81static int (*real_listen)(int, int);82static int (*real_accept)(int, struct sockaddr *, socklen_t *);83static int (*real_close)(int);84static int (*real_read)(int, void *, size_t);8586/* Per-FD bookkeeping (FDs >= 1024 are passed through unshimmed). */87static int is_shimmed[1024];88static int peer_of[1024];89static int wake_r[1024]; /* accept() blocks reading this */90static int wake_w[1024]; /* close() writes to this */91static int listener_fd = -1; /* FD that received listen() */9293__attribute__((constructor))94static void init(void) {95real_socket = dlsym(RTLD_NEXT, "socket");96real_socketpair = dlsym(RTLD_NEXT, "socketpair");97real_listen = dlsym(RTLD_NEXT, "listen");98real_accept = dlsym(RTLD_NEXT, "accept");99real_close = dlsym(RTLD_NEXT, "close");100real_read = dlsym(RTLD_NEXT, "read");101for (int i = 0; i < 1024; i++) {102peer_of[i] = -1;103wake_r[i] = -1;104wake_w[i] = -1;105}106}107108/* ---- socket ---------------------------------------------------------- */109int socket(int domain, int type, int protocol) {110if (domain == AF_UNIX) {111int fd = real_socket(domain, type, protocol);112if (fd >= 0) return fd;113/* socket(AF_UNIX) blocked – fall back to socketpair(). */114int sv[2];115if (real_socketpair(domain, type, protocol, sv) == 0) {116if (sv[0] >= 0 && sv[0] < 1024) {117is_shimmed[sv[0]] = 1;118peer_of[sv[0]] = sv[1];119int wp[2];120if (pipe(wp) == 0) {121wake_r[sv[0]] = wp[0];122wake_w[sv[0]] = wp[1];123}124}125return sv[0];126}127errno = EPERM;128return -1;129}130return real_socket(domain, type, protocol);131}132133/* ---- listen ---------------------------------------------------------- */134int listen(int sockfd, int backlog) {135if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {136listener_fd = sockfd;137return 0;138}139return real_listen(sockfd, backlog);140}141142/* ---- accept ---------------------------------------------------------- */143int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {144if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {145/* Block until close() writes to the wake pipe. */146if (wake_r[sockfd] >= 0) {147char buf;148real_read(wake_r[sockfd], &buf, 1);149}150errno = ECONNABORTED;151return -1;152}153return real_accept(sockfd, addr, addrlen);154}155156/* ---- close ----------------------------------------------------------- */157int close(int fd) {158if (fd >= 0 && fd < 1024 && is_shimmed[fd]) {159int was_listener = (fd == listener_fd);160is_shimmed[fd] = 0;161162if (wake_w[fd] >= 0) { /* unblock accept() */163char c = 0;164write(wake_w[fd], &c, 1);165real_close(wake_w[fd]);166wake_w[fd] = -1;167}168if (wake_r[fd] >= 0) { real_close(wake_r[fd]); wake_r[fd] = -1; }169if (peer_of[fd] >= 0) { real_close(peer_of[fd]); peer_of[fd] = -1; }170171if (was_listener)172_exit(0); /* conversion done – exit */173}174return real_close(fd);175}176"""177178179180if __name__ == "__main__":181import sys182result = run_soffice(sys.argv[1:])183sys.exit(result.returncode)184