@ai-ecoverse/slicc-kernel 1.32.0 → 1.32.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -781,6 +781,7 @@ function createNodeOps(h) {
781
781
  }
782
782
  const path = liveNodePath(node);
783
783
  if (attr2.mode !== void 0 && attr2.mode !== null) {
784
+ if (Fs.isLink(node.mode)) throw new Fs.ErrnoError(wasiErrno("EOPNOTSUPP"));
784
785
  const perm = attr2.mode & PERM_MASK;
785
786
  if (perm !== (node.mode & PERM_MASK)) {
786
787
  metadataCall(() => bridgeOf(node).chmod(path, perm));
@@ -1593,6 +1594,8 @@ var init_kernel_streams = __esm({
1593
1594
  refs = /* @__PURE__ */ new Map();
1594
1595
  socketRoot;
1595
1596
  sockets = 0;
1597
+ descriptions = /* @__PURE__ */ new Map();
1598
+ described = 0;
1596
1599
  Fs;
1597
1600
  sys;
1598
1601
  options;
@@ -1673,6 +1676,32 @@ var init_kernel_streams = __esm({
1673
1676
  })
1674
1677
  };
1675
1678
  }
1679
+ sizeFromKernel(stream, kfd) {
1680
+ const { size } = this.sys;
1681
+ if (!size) return;
1682
+ const node = stream.node;
1683
+ this.describe(stream, `${stream.path ?? ""}:${++this.described}`, () => ({
1684
+ ...node.node_ops?.getattr?.(node),
1685
+ size: this.call(() => size.call(this.sys, kfd))
1686
+ }));
1687
+ }
1688
+ describe(stream, name, getattr) {
1689
+ if (this.descriptions.size === 0) this.useDescriptions();
1690
+ this.descriptions.set(name, getattr);
1691
+ stream.path = name;
1692
+ stream.stream_ops = { ...stream.stream_ops, getattr };
1693
+ }
1694
+ useDescriptions() {
1695
+ const fs = this.Fs;
1696
+ for (const name of ["stat", "lstat"]) {
1697
+ const original = fs[name];
1698
+ if (typeof original !== "function") continue;
1699
+ fs[name] = (path, ...rest) => {
1700
+ const getattr = this.descriptions.get(path);
1701
+ return getattr ? getattr() : original.call(fs, path, ...rest);
1702
+ };
1703
+ }
1704
+ }
1676
1705
  useControllingTerminal() {
1677
1706
  if (typeof this.Fs.open !== "function") return;
1678
1707
  this.usePtyPaths();
@@ -1868,252 +1897,6 @@ var init_kernel_streams = __esm({
1868
1897
  }
1869
1898
  });
1870
1899
 
1871
- // src/process/process-children.ts
1872
- function status(r) {
1873
- return r.ok ? 0 : -wasiErrno(r.errno);
1874
- }
1875
- function number(r) {
1876
- if (!r.ok) return -wasiErrno(r.errno);
1877
- return r.kind === "json" && typeof r.json === "number" ? r.json : -wasiErrno("EIO");
1878
- }
1879
- function flushed(beforeSpawn) {
1880
- try {
1881
- beforeSpawn();
1882
- return 0;
1883
- } catch (err) {
1884
- const errno2 = err?.errno;
1885
- if (typeof errno2 !== "number") throw err;
1886
- return -errno2;
1887
- }
1888
- }
1889
- function drain(Fs, stream) {
1890
- const chunks = [];
1891
- const buffer = new Uint8Array(65536);
1892
- try {
1893
- for (let n = Fs.read(stream, buffer, 0, buffer.length); n > 0; ) {
1894
- chunks.push(buffer.slice(0, n));
1895
- n = Fs.read(stream, buffer, 0, buffer.length);
1896
- }
1897
- } catch {
1898
- }
1899
- const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
1900
- let offset = 0;
1901
- for (const chunk of chunks) {
1902
- out.set(chunk, offset);
1903
- offset += chunk.length;
1904
- }
1905
- return out;
1906
- }
1907
- function kernelSelect(Fs, transport, read, write, timeoutMs) {
1908
- const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
1909
- const kr = read.map(kernel);
1910
- const kw = write.map(kernel);
1911
- const r = transport.call({ op: "fd-select", read: kr, write: kw, timeoutMs }, Infinity, "select");
1912
- if (!r.ok) return -wasiErrno(r.errno);
1913
- const got = r.kind === "json" ? r.json : { read: [], write: [] };
1914
- return {
1915
- read: read.filter((_, i) => got.read.includes(kr[i])),
1916
- write: write.filter((_, i) => got.write.includes(kw[i]))
1917
- };
1918
- }
1919
- function ownReady(Fs, read, write) {
1920
- const flags = (fd) => {
1921
- const stream = Fs.getStream(fd);
1922
- if (!stream) return POLLNVAL;
1923
- return stream.stream_ops.poll ? stream.stream_ops.poll(stream) : POLLIN2 | POLLOUT2;
1924
- };
1925
- return {
1926
- read: read.filter((fd) => flags(fd) & (POLLIN2 | POLLHUP2 | POLLERR2 | POLLNVAL)),
1927
- write: write.filter((fd) => flags(fd) & (POLLOUT2 | POLLERR2 | POLLNVAL))
1928
- };
1929
- }
1930
- function anySelect(Fs, transport, read, write, timeoutMs) {
1931
- const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
1932
- const own = (fd) => kernel(fd) === void 0;
1933
- if (![...read, ...write].some(own)) return kernelSelect(Fs, transport, read, write, timeoutMs);
1934
- const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
1935
- const kernelRead = read.filter((fd) => !own(fd));
1936
- const kernelWrite = write.filter((fd) => !own(fd));
1937
- for (; ; ) {
1938
- const local = ownReady(Fs, read.filter(own), write.filter(own));
1939
- const pending = local.read.length > 0 || local.write.length > 0;
1940
- const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
1941
- const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
1942
- if (typeof got === "number") return got;
1943
- const ready = { read: [...local.read, ...got.read], write: [...local.write, ...got.write] };
1944
- if (ready.read.length > 0 || ready.write.length > 0 || Date.now() >= deadline) {
1945
- return ready;
1946
- }
1947
- }
1948
- }
1949
- function createProcessKernel(deps) {
1950
- const { transport, Fs } = deps;
1951
- const reaped = /* @__PURE__ */ new Map();
1952
- const call2 = (req, label) => transport.call(req, Infinity, label);
1953
- const at = (path) => path === "" || path.startsWith("/") ? path : `${Fs.cwd()}/${path}`;
1954
- const slot = (fd, n, promote) => {
1955
- const stream = fd >= 0 ? Fs.getStream(fd) : null;
1956
- if (!stream) return { none: true };
1957
- promote?.(stream);
1958
- if (stream.sliccKernelFd !== void 0) return { fd: stream.sliccKernelFd };
1959
- if (stream.path === "/dev/null") return { none: true };
1960
- return n === 0 ? { input: drain(Fs, stream) } : { capture: true };
1961
- };
1962
- const kernelWait = (pid, nohang, options = 0) => {
1963
- const req = {
1964
- op: "proc-wait",
1965
- pid,
1966
- nohang,
1967
- ...options & WUNTRACED ? { untraced: true } : {},
1968
- ...options & WCONTINUED ? { continued: true } : {}
1969
- };
1970
- let r = transport.call(req, Infinity, `proc-wait ${pid}`);
1971
- while (!r.ok && r.errno === "EINTR" && deps.restartable?.()) {
1972
- r = transport.call(req, Infinity, `proc-wait ${pid}`);
1973
- }
1974
- if (!r.ok) return -wasiErrno(r.errno);
1975
- const waited = r.kind === "json" ? r.json : [0, 0];
1976
- if (waited[0] > 0) deps.afterChild();
1977
- return [waited[0], waited[1]];
1978
- };
1979
- const deliver = (pid, n, fd) => {
1980
- const r = transport.call(
1981
- { op: "proc-captured", pid, slot: n },
1982
- Infinity,
1983
- `proc-captured ${pid}`
1984
- );
1985
- const stream = Fs.getStream(fd);
1986
- if (r.ok && r.kind === "bytes" && r.bytes.length > 0 && stream) {
1987
- Fs.write(stream, r.bytes, 0, r.bytes.length);
1988
- }
1989
- };
1990
- const execCaptures = /* @__PURE__ */ new Map();
1991
- const execWait = (pid) => {
1992
- const r = transport.call({ op: "proc-exec", pid }, Infinity, `exec ${pid}`);
1993
- if (!r.ok) return -wasiErrno(r.errno);
1994
- deps.afterChild();
1995
- return r.kind === "json" ? r.json[1] : 0;
1996
- };
1997
- const spawnChild = (file, argv, env, cwd, fds, actions, exec) => {
1998
- const unflushed = flushed(deps.beforeSpawn);
1999
- if (unflushed < 0) return unflushed;
2000
- const promote = deps.stdioPromoter?.();
2001
- const stdio = [0, 1, 2].map((n) => slot(fds[n] ?? -1, n, promote));
2002
- const inherit = deps.inherit?.(actions) ?? [];
2003
- const r = transport.call(
2004
- {
2005
- op: "proc-spawn",
2006
- file,
2007
- argv,
2008
- env: env ?? deps.env,
2009
- cwd: cwd ?? Fs.cwd(),
2010
- stdio,
2011
- ...inherit.length > 0 ? { inherit } : {},
2012
- ...exec ? { exec } : {}
2013
- },
2014
- Infinity,
2015
- `proc-spawn ${file}`
2016
- );
2017
- if (!r.ok) return -wasiErrno(r.errno);
2018
- const pid = r.kind === "json" ? r.json : 0;
2019
- const captures = [1, 2].filter((n) => "capture" in stdio[n]);
2020
- if (captures.length === 0) return pid;
2021
- if (exec) {
2022
- execCaptures.set(pid, () => {
2023
- for (const n of captures) deliver(pid, n, fds[n]);
2024
- });
2025
- return pid;
2026
- }
2027
- const waited = kernelWait(pid, false);
2028
- if (typeof waited === "number") return waited;
2029
- for (const n of captures) deliver(pid, n, fds[n]);
2030
- reaped.set(pid, waited[1]);
2031
- return pid;
2032
- };
2033
- return {
2034
- spawn(file, argv, env, cwd, fds, actions) {
2035
- return spawnChild(file, argv, env, cwd, fds, actions, false);
2036
- },
2037
- fork(state) {
2038
- const unflushed = flushed(deps.beforeSpawn);
2039
- if (unflushed < 0) return unflushed;
2040
- const streams = deps.describeFork();
2041
- const r = transport.call(
2042
- { op: "proc-fork", state: { ...state, streams, cwd: Fs.cwd() } },
2043
- Infinity,
2044
- "proc-fork"
2045
- );
2046
- if (!r.ok) return -wasiErrno(r.errno);
2047
- return r.kind === "json" ? r.json : -wasiErrno("EIO");
2048
- },
2049
- select: (read, write, timeoutMs) => anySelect(Fs, transport, read, write, timeoutMs),
2050
- execWait,
2051
- execve(file, argv, env, cwd) {
2052
- const pid = spawnChild(file, argv, env, cwd, [0, 1, 2], void 0, true);
2053
- if (pid < 0) return pid;
2054
- const status2 = execWait(pid);
2055
- execCaptures.get(pid)?.();
2056
- execCaptures.delete(pid);
2057
- return status2;
2058
- },
2059
- pause() {
2060
- return status(call2({ op: "sig-pause" }, "pause"));
2061
- },
2062
- mount(source, target, type, flags, data) {
2063
- const req = { op: "mount", source, target: at(target), type, flags, data };
2064
- return status(call2(req, `mount ${target}`));
2065
- },
2066
- umount2(target, flags) {
2067
- return status(call2({ op: "umount", target: at(target), flags }, `umount ${target}`));
2068
- },
2069
- kill(pid, sig) {
2070
- if (pid === deps.pid) {
2071
- if (sig !== 0) deps.raise?.(sig);
2072
- return 0;
2073
- }
2074
- return status(call2({ op: "proc-kill", pid, sig }, `kill ${pid}`));
2075
- },
2076
- setpgid: (pid, pgid) => status(call2({ op: "proc-setpgid", pid, pgid }, "setpgid")),
2077
- setsid: () => number(call2({ op: "proc-setsid" }, "setsid")),
2078
- getpgid: (pid) => number(call2({ op: "proc-getpgid", pid }, "getpgid")),
2079
- getsid: (pid) => number(call2({ op: "proc-getsid", pid }, "getsid")),
2080
- tcgetpgrp(fd) {
2081
- const kfd = Fs.getStream(fd)?.sliccKernelFd;
2082
- if (kfd === void 0) return -wasiErrno("ENOTTY");
2083
- return number(call2({ op: "tty-pgrp-get", fd: kfd }, "tcgetpgrp"));
2084
- },
2085
- tcsetpgrp(fd, pgrp) {
2086
- const kfd = Fs.getStream(fd)?.sliccKernelFd;
2087
- if (kfd === void 0) return -wasiErrno("ENOTTY");
2088
- return status(call2({ op: "tty-pgrp-set", fd: kfd, pgrp }, "tcsetpgrp"));
2089
- },
2090
- wait(pid, nohang, options) {
2091
- const key = pid > 0 ? reaped.has(pid) ? pid : void 0 : reaped.keys().next().value;
2092
- if (key !== void 0) {
2093
- const status2 = reaped.get(key);
2094
- reaped.delete(key);
2095
- return [key, status2];
2096
- }
2097
- return kernelWait(pid, nohang, options);
2098
- }
2099
- };
2100
- }
2101
- var POLLIN2, POLLOUT2, POLLERR2, POLLHUP2, POLLNVAL, SELECT_SLICE_MS, WUNTRACED, WCONTINUED;
2102
- var init_process_children = __esm({
2103
- "src/process/process-children.ts"() {
2104
- "use strict";
2105
- init_wasi_errno();
2106
- POLLIN2 = 1;
2107
- POLLOUT2 = 4;
2108
- POLLERR2 = 8;
2109
- POLLHUP2 = 16;
2110
- POLLNVAL = 32;
2111
- SELECT_SLICE_MS = 20;
2112
- WUNTRACED = 2;
2113
- WCONTINUED = 8;
2114
- }
2115
- });
2116
-
2117
1900
  // src/process/process-pty.ts
2118
1901
  function failed(e) {
2119
1902
  const code2 = e?.code;
@@ -2304,6 +2087,12 @@ function wrapCloexecSyscalls(imports, glue, deps) {
2304
2087
  }
2305
2088
  }
2306
2089
  }
2090
+ function pathOpensLinks(Fs) {
2091
+ const fs = Fs;
2092
+ const { mayOpen, isLink } = fs;
2093
+ if (!mayOpen || !isLink) return;
2094
+ fs.mayOpen = (node, flags) => flags & O_PATH && isLink.call(fs, node.mode) ? 0 : mayOpen.call(fs, node, flags);
2095
+ }
2307
2096
  function noFollowUtimes(imports, fs, glue) {
2308
2097
  for (const namespace of namespaces(imports)) {
2309
2098
  const key = Object.keys(namespace).find(
@@ -2487,7 +2276,46 @@ function describeFdDir(Fs) {
2487
2276
  };
2488
2277
  return entry;
2489
2278
  }
2490
- };
2279
+ };
2280
+ }
2281
+ function useZeroDevices(Fs) {
2282
+ const { analyzePath, registerDevice, mkdev, makedev } = Fs;
2283
+ if (!analyzePath || !registerDevice || !mkdev || !makedev) return;
2284
+ const zeros = (_s, buffer, offset, length) => {
2285
+ buffer.fill(0, offset, offset + length);
2286
+ return length;
2287
+ };
2288
+ const devices = [
2289
+ ["/dev/zero", 5, (_s, _b, _o, length) => length],
2290
+ [
2291
+ "/dev/full",
2292
+ 7,
2293
+ (_s, _b, _o, length) => {
2294
+ if (length > 0) throw new Fs.ErrnoError(wasiErrno("ENOSPC"));
2295
+ return 0;
2296
+ }
2297
+ ]
2298
+ ];
2299
+ for (const [path, minor, write] of devices) {
2300
+ if (analyzePath.call(Fs, path).exists) continue;
2301
+ const dev = makedev.call(Fs, 1, minor);
2302
+ registerDevice.call(Fs, dev, { read: zeros, write, llseek: () => 0 });
2303
+ mkdev.call(Fs, path, CHAR_DEVICE, dev);
2304
+ }
2305
+ }
2306
+ function linkStdio(Fs) {
2307
+ const { unlink, symlink } = Fs;
2308
+ if (!unlink || !symlink) return;
2309
+ for (const [fd, name] of ["stdin", "stdout", "stderr"].entries()) {
2310
+ try {
2311
+ unlink.call(Fs, `/dev/${name}`);
2312
+ } catch {
2313
+ }
2314
+ try {
2315
+ symlink.call(Fs, `/proc/self/fd/${fd}`, `/dev/${name}`);
2316
+ } catch {
2317
+ }
2318
+ }
2491
2319
  }
2492
2320
  function useDevFd(Fs) {
2493
2321
  if (typeof Fs.open !== "function") return;
@@ -2495,6 +2323,7 @@ function useDevFd(Fs) {
2495
2323
  Fs.symlink?.("/proc/self/fd", "/dev/fd");
2496
2324
  } catch {
2497
2325
  }
2326
+ linkStdio(Fs);
2498
2327
  describeFdDir(Fs);
2499
2328
  const fdOf = (path) => typeof path === "string" ? fdOfPath(path, Fs.cwd()) : void 0;
2500
2329
  const target = (fd) => {
@@ -2581,7 +2410,7 @@ function useMounts(Fs, env = {}, live = false) {
2581
2410
  }
2582
2411
  };
2583
2412
  }
2584
- var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, DIR_MODE, LINK_MODE, O_ACCMODE, O_CREAT2, field, NAME;
2413
+ var O_CLOEXEC, FD_CLOEXEC, F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_DUPFD_CLOEXEC, tracked, IMPORT_NAMES, EBADF, AT_SYMLINK_NOFOLLOW, EMSCRIPTEN_EPERM, O_PATH, DIR_MODE, LINK_MODE, CHAR_DEVICE, O_ACCMODE, O_CREAT2, field, NAME;
2585
2414
  var init_process_fds = __esm({
2586
2415
  "src/process/process-fds.ts"() {
2587
2416
  "use strict";
@@ -2608,8 +2437,10 @@ var init_process_fds = __esm({
2608
2437
  EBADF = 8;
2609
2438
  AT_SYMLINK_NOFOLLOW = 256;
2610
2439
  EMSCRIPTEN_EPERM = 63;
2440
+ O_PATH = 2097152;
2611
2441
  DIR_MODE = 16749;
2612
2442
  LINK_MODE = 41408;
2443
+ CHAR_DEVICE = 8630;
2613
2444
  O_ACCMODE = 3;
2614
2445
  O_CREAT2 = 64;
2615
2446
  field = (text) => (text || "none").replace(/[\s\\]/g, (c) => `\\${c.charCodeAt(0).toString(8).padStart(3, "0")}`);
@@ -2696,12 +2527,16 @@ function describeInherited(Fs, sys, streams, livePath, actions = []) {
2696
2527
  }
2697
2528
  return out;
2698
2529
  }
2530
+ function deviceOfStream(stream) {
2531
+ const device = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2532
+ if (!device || stream.sliccKernelFd !== void 0) return void 0;
2533
+ const access = ACCESS[stream.flags & O_ACCMODE2];
2534
+ return { device, ...access ? { access } : {} };
2535
+ }
2699
2536
  function inheritedSlot(fd, stream) {
2700
2537
  if (stream.sliccKernelFd === void 0) {
2701
- const device = stream.path === void 0 ? void 0 : DEVICES[stream.path];
2702
- if (!device) return void 0;
2703
- const access = ACCESS[stream.flags & O_ACCMODE2];
2704
- return { fd, device, ...access ? { access } : {} };
2538
+ const device = deviceOfStream(stream);
2539
+ return device ? { fd, ...device } : void 0;
2705
2540
  }
2706
2541
  const flags = stream.sliccKernelSocket ? { flags: stream.flags } : {};
2707
2542
  return { fd, kernel: stream.sliccKernelFd, ...flags };
@@ -2725,15 +2560,19 @@ function asFifo(stream, streams, identity) {
2725
2560
  const fixed = inos.get(identity) ?? nextStreamIno++;
2726
2561
  inos.set(identity, fixed);
2727
2562
  const node = stream.node;
2728
- stream.stream_ops = {
2729
- ...stream.stream_ops,
2730
- getattr: () => ({ ...node.node_ops?.getattr?.(node), mode: FIFO_MODE, ino: fixed, size: 0 })
2731
- };
2563
+ streams.describe(stream, `pipe:[${fixed}]`, () => ({
2564
+ ...node.node_ops?.getattr?.(node),
2565
+ mode: FIFO_MODE,
2566
+ ino: fixed,
2567
+ size: 0
2568
+ }));
2732
2569
  }
2733
2570
  function placeKernelStream(Fs, streams, entry) {
2734
2571
  const stream = place(Fs, placeholder(Fs, streams, entry), entry.fd);
2735
- if (entry.kind === "file") streams.attachFile(stream, entry.kernel);
2736
- else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
2572
+ if (entry.kind === "file") {
2573
+ streams.attachFile(stream, entry.kernel);
2574
+ streams.sizeFromKernel(stream, entry.kernel);
2575
+ } else if (entry.kind === "socket") streams.attachSocket(stream, entry.kernel);
2737
2576
  else streams.attach(stream, entry.kernel, entry.kind === "tty");
2738
2577
  if (entry.kind === "tty") streams.nameTerminal(stream);
2739
2578
  if (entry.kind === "stream") {
@@ -2775,6 +2614,7 @@ var init_process_fork = __esm({
2775
2614
  DEVICES = {
2776
2615
  "/dev/null": "null",
2777
2616
  "/dev/zero": "zero",
2617
+ "/dev/full": "full",
2778
2618
  "/dev/urandom": "urandom",
2779
2619
  "/dev/random": "urandom"
2780
2620
  };
@@ -2784,6 +2624,255 @@ var init_process_fork = __esm({
2784
2624
  }
2785
2625
  });
2786
2626
 
2627
+ // src/process/process-children.ts
2628
+ function status(r) {
2629
+ return r.ok ? 0 : -wasiErrno(r.errno);
2630
+ }
2631
+ function number(r) {
2632
+ if (!r.ok) return -wasiErrno(r.errno);
2633
+ return r.kind === "json" && typeof r.json === "number" ? r.json : -wasiErrno("EIO");
2634
+ }
2635
+ function flushed(beforeSpawn) {
2636
+ try {
2637
+ beforeSpawn();
2638
+ return 0;
2639
+ } catch (err) {
2640
+ const errno2 = err?.errno;
2641
+ if (typeof errno2 !== "number") throw err;
2642
+ return -errno2;
2643
+ }
2644
+ }
2645
+ function drain(Fs, stream) {
2646
+ const chunks = [];
2647
+ const buffer = new Uint8Array(65536);
2648
+ try {
2649
+ for (let n = Fs.read(stream, buffer, 0, buffer.length); n > 0; ) {
2650
+ chunks.push(buffer.slice(0, n));
2651
+ n = Fs.read(stream, buffer, 0, buffer.length);
2652
+ }
2653
+ } catch {
2654
+ }
2655
+ const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));
2656
+ let offset = 0;
2657
+ for (const chunk of chunks) {
2658
+ out.set(chunk, offset);
2659
+ offset += chunk.length;
2660
+ }
2661
+ return out;
2662
+ }
2663
+ function kernelSelect(Fs, transport, read, write, timeoutMs) {
2664
+ const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
2665
+ const kr = read.map(kernel);
2666
+ const kw = write.map(kernel);
2667
+ const r = transport.call({ op: "fd-select", read: kr, write: kw, timeoutMs }, Infinity, "select");
2668
+ if (!r.ok) return -wasiErrno(r.errno);
2669
+ const got = r.kind === "json" ? r.json : { read: [], write: [] };
2670
+ return {
2671
+ read: read.filter((_, i) => got.read.includes(kr[i])),
2672
+ write: write.filter((_, i) => got.write.includes(kw[i]))
2673
+ };
2674
+ }
2675
+ function ownReady(Fs, read, write) {
2676
+ const flags = (fd) => {
2677
+ const stream = Fs.getStream(fd);
2678
+ if (!stream) return POLLNVAL;
2679
+ return stream.stream_ops.poll ? stream.stream_ops.poll(stream) : POLLIN2 | POLLOUT2;
2680
+ };
2681
+ return {
2682
+ read: read.filter((fd) => flags(fd) & (POLLIN2 | POLLHUP2 | POLLERR2 | POLLNVAL)),
2683
+ write: write.filter((fd) => flags(fd) & (POLLOUT2 | POLLERR2 | POLLNVAL))
2684
+ };
2685
+ }
2686
+ function anySelect(Fs, transport, read, write, timeoutMs) {
2687
+ const kernel = (fd) => Fs.getStream(fd)?.sliccKernelFd;
2688
+ const own = (fd) => kernel(fd) === void 0;
2689
+ if (![...read, ...write].some(own)) return kernelSelect(Fs, transport, read, write, timeoutMs);
2690
+ const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
2691
+ const kernelRead = read.filter((fd) => !own(fd));
2692
+ const kernelWrite = write.filter((fd) => !own(fd));
2693
+ for (; ; ) {
2694
+ const local = ownReady(Fs, read.filter(own), write.filter(own));
2695
+ const pending = local.read.length > 0 || local.write.length > 0;
2696
+ const slice = pending ? 0 : Math.min(SELECT_SLICE_MS, Math.max(0, deadline - Date.now()));
2697
+ const got = kernelSelect(Fs, transport, kernelRead, kernelWrite, slice);
2698
+ if (typeof got === "number") return got;
2699
+ const ready = { read: [...local.read, ...got.read], write: [...local.write, ...got.write] };
2700
+ if (ready.read.length > 0 || ready.write.length > 0 || Date.now() >= deadline) {
2701
+ return ready;
2702
+ }
2703
+ }
2704
+ }
2705
+ function createProcessKernel(deps) {
2706
+ const { transport, Fs } = deps;
2707
+ const reaped = /* @__PURE__ */ new Map();
2708
+ const call2 = (req, label) => transport.call(req, Infinity, label);
2709
+ const at = (path) => path === "" || path.startsWith("/") ? path : `${Fs.cwd()}/${path}`;
2710
+ const slot = (fd, n, promote) => {
2711
+ const stream = fd >= 0 ? Fs.getStream(fd) : null;
2712
+ if (!stream) return { none: true };
2713
+ promote?.(stream);
2714
+ if (stream.sliccKernelFd !== void 0) return { fd: stream.sliccKernelFd };
2715
+ if (stream.path === "/dev/null") return { none: true };
2716
+ const device = deviceOfStream(stream);
2717
+ if (device) return device;
2718
+ return n === 0 ? { input: drain(Fs, stream) } : { capture: true };
2719
+ };
2720
+ const kernelWait = (pid, nohang, options = 0) => {
2721
+ const req = {
2722
+ op: "proc-wait",
2723
+ pid,
2724
+ nohang,
2725
+ ...options & WUNTRACED ? { untraced: true } : {},
2726
+ ...options & WCONTINUED ? { continued: true } : {}
2727
+ };
2728
+ let r = transport.call(req, Infinity, `proc-wait ${pid}`);
2729
+ while (!r.ok && r.errno === "EINTR" && deps.restartable?.()) {
2730
+ r = transport.call(req, Infinity, `proc-wait ${pid}`);
2731
+ }
2732
+ if (!r.ok) return -wasiErrno(r.errno);
2733
+ const waited = r.kind === "json" ? r.json : [0, 0];
2734
+ if (waited[0] > 0) deps.afterChild();
2735
+ return [waited[0], waited[1]];
2736
+ };
2737
+ const deliver = (pid, n, fd) => {
2738
+ const r = transport.call(
2739
+ { op: "proc-captured", pid, slot: n },
2740
+ Infinity,
2741
+ `proc-captured ${pid}`
2742
+ );
2743
+ const stream = Fs.getStream(fd);
2744
+ if (r.ok && r.kind === "bytes" && r.bytes.length > 0 && stream) {
2745
+ Fs.write(stream, r.bytes, 0, r.bytes.length);
2746
+ }
2747
+ };
2748
+ const execCaptures = /* @__PURE__ */ new Map();
2749
+ const execWait = (pid) => {
2750
+ const r = transport.call({ op: "proc-exec", pid }, Infinity, `exec ${pid}`);
2751
+ if (!r.ok) return -wasiErrno(r.errno);
2752
+ deps.afterChild();
2753
+ return r.kind === "json" ? r.json[1] : 0;
2754
+ };
2755
+ const spawnChild = (file, argv, env, cwd, fds, actions, exec) => {
2756
+ const unflushed = flushed(deps.beforeSpawn);
2757
+ if (unflushed < 0) return unflushed;
2758
+ const promote = deps.stdioPromoter?.();
2759
+ const stdio = [0, 1, 2].map((n) => slot(fds[n] ?? -1, n, promote));
2760
+ const inherit = deps.inherit?.(actions) ?? [];
2761
+ const r = transport.call(
2762
+ {
2763
+ op: "proc-spawn",
2764
+ file,
2765
+ argv,
2766
+ env: env ?? deps.env,
2767
+ cwd: cwd ?? Fs.cwd(),
2768
+ stdio,
2769
+ ...inherit.length > 0 ? { inherit } : {},
2770
+ ...exec ? { exec } : {}
2771
+ },
2772
+ Infinity,
2773
+ `proc-spawn ${file}`
2774
+ );
2775
+ if (!r.ok) return -wasiErrno(r.errno);
2776
+ const pid = r.kind === "json" ? r.json : 0;
2777
+ const captures = [1, 2].filter((n) => "capture" in stdio[n]);
2778
+ if (captures.length === 0) return pid;
2779
+ if (exec) {
2780
+ execCaptures.set(pid, () => {
2781
+ for (const n of captures) deliver(pid, n, fds[n]);
2782
+ });
2783
+ return pid;
2784
+ }
2785
+ const waited = kernelWait(pid, false);
2786
+ if (typeof waited === "number") return waited;
2787
+ for (const n of captures) deliver(pid, n, fds[n]);
2788
+ reaped.set(pid, waited[1]);
2789
+ return pid;
2790
+ };
2791
+ return {
2792
+ spawn(file, argv, env, cwd, fds, actions) {
2793
+ return spawnChild(file, argv, env, cwd, fds, actions, false);
2794
+ },
2795
+ fork(state) {
2796
+ const unflushed = flushed(deps.beforeSpawn);
2797
+ if (unflushed < 0) return unflushed;
2798
+ const streams = deps.describeFork();
2799
+ const r = transport.call(
2800
+ { op: "proc-fork", state: { ...state, streams, cwd: Fs.cwd() } },
2801
+ Infinity,
2802
+ "proc-fork"
2803
+ );
2804
+ if (!r.ok) return -wasiErrno(r.errno);
2805
+ return r.kind === "json" ? r.json : -wasiErrno("EIO");
2806
+ },
2807
+ select: (read, write, timeoutMs) => anySelect(Fs, transport, read, write, timeoutMs),
2808
+ execWait,
2809
+ execve(file, argv, env, cwd) {
2810
+ const pid = spawnChild(file, argv, env, cwd, [0, 1, 2], void 0, true);
2811
+ if (pid < 0) return pid;
2812
+ const status2 = execWait(pid);
2813
+ execCaptures.get(pid)?.();
2814
+ execCaptures.delete(pid);
2815
+ return status2;
2816
+ },
2817
+ pause() {
2818
+ return status(call2({ op: "sig-pause" }, "pause"));
2819
+ },
2820
+ mount(source, target, type, flags, data) {
2821
+ const req = { op: "mount", source, target: at(target), type, flags, data };
2822
+ return status(call2(req, `mount ${target}`));
2823
+ },
2824
+ umount2(target, flags) {
2825
+ return status(call2({ op: "umount", target: at(target), flags }, `umount ${target}`));
2826
+ },
2827
+ kill(pid, sig) {
2828
+ if (pid === deps.pid) {
2829
+ if (sig !== 0) deps.raise?.(sig);
2830
+ return 0;
2831
+ }
2832
+ return status(call2({ op: "proc-kill", pid, sig }, `kill ${pid}`));
2833
+ },
2834
+ setpgid: (pid, pgid) => status(call2({ op: "proc-setpgid", pid, pgid }, "setpgid")),
2835
+ setsid: () => number(call2({ op: "proc-setsid" }, "setsid")),
2836
+ getpgid: (pid) => number(call2({ op: "proc-getpgid", pid }, "getpgid")),
2837
+ getsid: (pid) => number(call2({ op: "proc-getsid", pid }, "getsid")),
2838
+ tcgetpgrp(fd) {
2839
+ const kfd = Fs.getStream(fd)?.sliccKernelFd;
2840
+ if (kfd === void 0) return -wasiErrno("ENOTTY");
2841
+ return number(call2({ op: "tty-pgrp-get", fd: kfd }, "tcgetpgrp"));
2842
+ },
2843
+ tcsetpgrp(fd, pgrp) {
2844
+ const kfd = Fs.getStream(fd)?.sliccKernelFd;
2845
+ if (kfd === void 0) return -wasiErrno("ENOTTY");
2846
+ return status(call2({ op: "tty-pgrp-set", fd: kfd, pgrp }, "tcsetpgrp"));
2847
+ },
2848
+ wait(pid, nohang, options) {
2849
+ const key = pid > 0 ? reaped.has(pid) ? pid : void 0 : reaped.keys().next().value;
2850
+ if (key !== void 0) {
2851
+ const status2 = reaped.get(key);
2852
+ reaped.delete(key);
2853
+ return [key, status2];
2854
+ }
2855
+ return kernelWait(pid, nohang, options);
2856
+ }
2857
+ };
2858
+ }
2859
+ var POLLIN2, POLLOUT2, POLLERR2, POLLHUP2, POLLNVAL, SELECT_SLICE_MS, WUNTRACED, WCONTINUED;
2860
+ var init_process_children = __esm({
2861
+ "src/process/process-children.ts"() {
2862
+ "use strict";
2863
+ init_process_fork();
2864
+ init_wasi_errno();
2865
+ POLLIN2 = 1;
2866
+ POLLOUT2 = 4;
2867
+ POLLERR2 = 8;
2868
+ POLLHUP2 = 16;
2869
+ POLLNVAL = 32;
2870
+ SELECT_SLICE_MS = 20;
2871
+ WUNTRACED = 2;
2872
+ WCONTINUED = 8;
2873
+ }
2874
+ });
2875
+
2787
2876
  // src/process/process-http.ts
2788
2877
  function createHttpKernel(transport) {
2789
2878
  const call2 = (req) => {
@@ -3468,6 +3557,12 @@ function kernelSys(transport) {
3468
3557
  ttyName(fd) {
3469
3558
  return json(call2({ op: "fd-info", fd }, `fd-info ${fd}`))?.name;
3470
3559
  },
3560
+ kind(fd) {
3561
+ return json(call2({ op: "fd-info", fd }, `fd-info ${fd}`))?.kind;
3562
+ },
3563
+ size(fd) {
3564
+ return json(call2({ op: "fd-vfs-stat", fd }, `fd-vfs-stat ${fd}`)).size;
3565
+ },
3471
3566
  openTty(name) {
3472
3567
  const req = name === void 0 ? { op: "fd-open-tty" } : { op: "fd-open-tty", name };
3473
3568
  return json(call2(req, `fd-open-tty ${name ?? ""}`));
@@ -3535,10 +3630,18 @@ function openDevice(Fs, fd, meta) {
3535
3630
  }
3536
3631
  return true;
3537
3632
  }
3538
- function wireKernelStdio(Fs, streams) {
3633
+ function wireKernelStdio(Fs, streams, sys) {
3539
3634
  for (const fd of [0, 1, 2]) {
3540
3635
  const stream = Fs.getStream(fd);
3541
3636
  if (!stream) continue;
3637
+ const kind = sys?.kind?.(fd);
3638
+ if (kind && PLACED.has(kind)) {
3639
+ const { flags } = stream;
3640
+ Fs.closeStream(fd);
3641
+ const kernel = { fd, kernel: fd, kind, flags };
3642
+ placeKernelStream(Fs, streams, kernel).flags = flags;
3643
+ continue;
3644
+ }
3542
3645
  streams.attach(stream, fd);
3543
3646
  streams.nameTerminal(stream);
3544
3647
  }
@@ -3655,6 +3758,7 @@ async function runWasmProcess(init, port, deps = {}) {
3655
3758
  if (!hasStreams(m)) return;
3656
3759
  const fs = m.FS;
3657
3760
  trackCloseOnExec(fs);
3761
+ pathOpensLinks(fs);
3658
3762
  try {
3659
3763
  fs.mkdirTree(init.cwd);
3660
3764
  fs.chdir(init.cwd);
@@ -3679,10 +3783,11 @@ async function runWasmProcess(init, port, deps = {}) {
3679
3783
  trackCloseOnExec(running.FS);
3680
3784
  quietQuit(running.FS);
3681
3785
  useMounts(running.FS, init.env, true);
3786
+ useZeroDevices(running.FS);
3682
3787
  useProcfs(running.FS, sys, init.pid);
3683
3788
  if (init.fork) restoreForkedStreams(running.FS, streams, init.fork.streams ?? []);
3684
3789
  else {
3685
- wireKernelStdio(running.FS, streams);
3790
+ wireKernelStdio(running.FS, streams, sys);
3686
3791
  for (const entry of init.fds ?? []) wireKernelFd(running.FS, streams, entry);
3687
3792
  }
3688
3793
  const pipefs = ownValue(running, "PIPEFS");
@@ -3760,7 +3865,7 @@ function runMain(running, init) {
3760
3865
  return status2;
3761
3866
  }
3762
3867
  }
3763
- var O_RDONLY, O_WRONLY2, O_RDWR3, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
3868
+ var O_RDONLY, O_WRONLY2, O_RDWR3, PLACED, GLUE_TRAILER, evaluateGlue, EVAL_BLOCKED;
3764
3869
  var init_process_runtime = __esm({
3765
3870
  "src/process/process-runtime.ts"() {
3766
3871
  "use strict";
@@ -3783,6 +3888,7 @@ var init_process_runtime = __esm({
3783
3888
  O_RDONLY = 0;
3784
3889
  O_WRONLY2 = 1;
3785
3890
  O_RDWR3 = 2;
3891
+ PLACED = /* @__PURE__ */ new Set(["stream", "file", "socket"]);
3786
3892
  GLUE_TRAILER = [
3787
3893
  "if (typeof ENV !== 'undefined') Object.assign(ENV, Module.sliccEnv);",
3788
3894
  "const __sliccTake = (name, value) => {",
@@ -4262,6 +4368,7 @@ var init_wasi_fds = __esm({
4262
4368
  DEVICES2 = {
4263
4369
  "/dev/null": "null",
4264
4370
  "/dev/zero": "zero",
4371
+ "/dev/full": "full",
4265
4372
  "/dev/urandom": "urandom",
4266
4373
  "/dev/random": "urandom"
4267
4374
  };
@@ -5299,6 +5406,7 @@ var init_wasi_host = __esm({
5299
5406
  }
5300
5407
  if (e.type === "device") {
5301
5408
  if (e.access === "read") throw new WasiError("EBADF");
5409
+ if (e.device === "full" && data.length > 0) throw new WasiError("ENOSPC");
5302
5410
  return data.length;
5303
5411
  }
5304
5412
  return this.file(fd, "write").write(data);
@@ -5312,7 +5420,7 @@ var init_wasi_host = __esm({
5312
5420
  if (e.access === "write") throw new WasiError("EBADF");
5313
5421
  if (e.device === "null") return new Uint8Array(0);
5314
5422
  const out = new Uint8Array(Math.min(max, 65536));
5315
- return e.device === "zero" ? out : crypto.getRandomValues(out);
5423
+ return e.device === "urandom" ? crypto.getRandomValues(out) : out;
5316
5424
  }
5317
5425
  return this.file(fd, "read").read(max);
5318
5426
  }