@ai-ecoverse/slicc-kernel 1.51.0 → 1.52.0

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.
@@ -969,6 +969,10 @@ function kernelEntry() {
969
969
  function deviceEntry(meta) {
970
970
  return { type: "device", device: meta.device, ...meta.access ? { access: meta.access } : {} };
971
971
  }
972
+ function refuseWrite(s, oflags, rights) {
973
+ const writes = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
974
+ if (s?.readonly && writes) throw new WasiError("EROFS");
975
+ }
972
976
  function preopenOf(e) {
973
977
  return {
974
978
  ...e.preopen ? { preopen: e.preopen } : {},
@@ -1436,6 +1440,7 @@ var init_wasi_fds = __esm({
1436
1440
  return this.install({ type: "dir", path });
1437
1441
  }
1438
1442
  if (!s && !(oflags & OFLAGS.CREAT)) throw new WasiError("ENOENT");
1443
+ refuseWrite(s, oflags, rights);
1439
1444
  if (this.shared) return this.kernelFile(path, s, oflags, rights, fdflags);
1440
1445
  return this.install({ type: "file", file: this.file(path, s, oflags, rights, fdflags) });
1441
1446
  }
@@ -4444,10 +4449,25 @@ function ttyOps(kernel) {
4444
4449
  await kernel.call({ op: "tty-pgrp-set", fd, pgrp });
4445
4450
  }
4446
4451
  };
4452
+ const openOn = async (terminal, fd) => {
4453
+ const open = await kernel.json({ op: "fd-list" });
4454
+ const on = open.filter((entry) => entry.terminal === terminal);
4455
+ return (on.find((entry) => entry.fd === fd) ?? on[0])?.fd;
4456
+ };
4457
+ const reopened = async (terminal, termios) => {
4458
+ const fd = await kernel.json({ op: "fd-open-tty", name: terminal });
4459
+ try {
4460
+ await setAttr(fd, termios);
4461
+ } finally {
4462
+ await kernel.call({ op: "fd-close", fd });
4463
+ }
4464
+ };
4447
4465
  const restore = async () => {
4448
4466
  for (const [terminal, { fd, termios }] of [...saved].reverse()) {
4449
4467
  saved.delete(terminal);
4450
- await setAttr(fd, termios).catch(() => void 0);
4468
+ const at = await openOn(terminal, fd).catch(() => void 0);
4469
+ const back = at === void 0 ? reopened(terminal, termios) : setAttr(at, termios);
4470
+ await back.catch(() => void 0);
4451
4471
  }
4452
4472
  };
4453
4473
  return { tty, restore };
@@ -8625,6 +8645,191 @@ var init_wasi_module = __esm({
8625
8645
  }
8626
8646
  });
8627
8647
 
8648
+ // src/process/wasi/wasi-procfs.ts
8649
+ function inProc(path) {
8650
+ return path === "/proc" || path.startsWith("/proc/");
8651
+ }
8652
+ function procfsBridge(fs, tree) {
8653
+ const over = {
8654
+ readFile: (p) => inProc(p) ? tree.read(p) : fs.readFile(p),
8655
+ stat: (p) => inProc(p) ? tree.stat(p) : fs.stat(p),
8656
+ lstat: (p) => inProc(p) ? tree.stat(p, false) : fs.lstat(p),
8657
+ readdir: (p) => {
8658
+ if (inProc(p)) return tree.readdir(p);
8659
+ const names = fs.readdir(p);
8660
+ return p === "/" && !names.includes("proc") ? [...names, "proc"] : names;
8661
+ },
8662
+ exists: (p) => inProc(p) ? tree.exists(p) : fs.exists(p),
8663
+ readlink: (p) => inProc(p) ? tree.readlink(p) : fs.readlink(p),
8664
+ readdirStat: (p) => {
8665
+ if (!inProc(p)) {
8666
+ const listed = fs.readdirStat(p);
8667
+ if (p !== "/" || listed.some(([name2]) => name2 === "proc")) return listed;
8668
+ return [...listed, ["proc", tree.stat("/proc")]];
8669
+ }
8670
+ return tree.readdir(p).map((name2) => {
8671
+ try {
8672
+ return [name2, tree.stat(`${p}/${name2}`, false)];
8673
+ } catch {
8674
+ return [name2, null];
8675
+ }
8676
+ });
8677
+ },
8678
+ rename: (from, to) => {
8679
+ if (inProc(from) || inProc(to)) throw syncError("EROFS", from);
8680
+ fs.rename(from, to);
8681
+ },
8682
+ hold: (p, ...rest2) => inProc(p) ? void 0 : fs.hold?.(p, ...rest2),
8683
+ ...fs.pread ? {
8684
+ pread: (p, at, n, version) => inProc(p) ? tree.read(p).subarray(at, at + n) : fs.pread(p, at, n, version)
8685
+ } : {}
8686
+ };
8687
+ for (const name2 of READ_ONLY) {
8688
+ const fn = fs[name2];
8689
+ if (!fn) continue;
8690
+ over[name2] = (p, ...rest2) => {
8691
+ if (inProc(p)) throw syncError("EROFS", p);
8692
+ return fn.call(fs, p, ...rest2);
8693
+ };
8694
+ }
8695
+ return new Proxy(fs, {
8696
+ get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
8697
+ });
8698
+ }
8699
+ var DIR_MODE3, FILE_MODE2, LINK_MODE3, PID_NAMES, SYSTEM_NAMES, ProcTree, READ_ONLY;
8700
+ var init_wasi_procfs = __esm({
8701
+ "src/process/wasi/wasi-procfs.ts"() {
8702
+ "use strict";
8703
+ init_sync_fs_wire();
8704
+ init_process_fds();
8705
+ init_procfs();
8706
+ DIR_MODE3 = 16749;
8707
+ FILE_MODE2 = 33060;
8708
+ LINK_MODE3 = 41471;
8709
+ PID_NAMES = PID_FILES;
8710
+ SYSTEM_NAMES = SYSTEM_FILES;
8711
+ ProcTree = class {
8712
+ source;
8713
+ pid;
8714
+ memory;
8715
+ constructor(source, pid, memory = memorySource()) {
8716
+ this.source = source;
8717
+ this.pid = pid;
8718
+ this.memory = memory;
8719
+ }
8720
+ listing() {
8721
+ return this.source.procList();
8722
+ }
8723
+ alive(pid) {
8724
+ return this.listing().processes.some((p) => p.pid === pid);
8725
+ }
8726
+ node(parts) {
8727
+ const [top, leaf, ...rest2] = parts;
8728
+ if (top === void 0) {
8729
+ return {
8730
+ kind: "dir",
8731
+ names: () => [
8732
+ ...SYSTEM_NAMES,
8733
+ "mounts",
8734
+ "self",
8735
+ ...this.listing().processes.map((p) => String(p.pid))
8736
+ ]
8737
+ };
8738
+ }
8739
+ if (top === "self") {
8740
+ return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
8741
+ }
8742
+ if (leaf === void 0 && top === "mounts") {
8743
+ return { kind: "file", content: () => mountTable(this.source.mountList()) };
8744
+ }
8745
+ if (leaf === void 0 && SYSTEM_NAMES.includes(top)) {
8746
+ return {
8747
+ kind: "file",
8748
+ content: () => systemFile(top, this.listing(), Date.now(), this.memory)
8749
+ };
8750
+ }
8751
+ if (!/^[1-9]\d*$/.test(top) || rest2.length > 0 || !this.alive(Number(top))) return void 0;
8752
+ if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES] };
8753
+ if (!PID_NAMES.includes(leaf)) return void 0;
8754
+ return {
8755
+ kind: "file",
8756
+ content: () => {
8757
+ const listing = this.listing();
8758
+ const info = listing.processes.find((p) => p.pid === Number(top));
8759
+ if (!info) throw syncError("ENOENT", `/proc/${top}/${leaf}`);
8760
+ return pidFile(leaf, info, listing.boot);
8761
+ }
8762
+ };
8763
+ }
8764
+ parts(path, follow2) {
8765
+ const parts = path.split("/").filter((p) => p !== "").slice(1);
8766
+ if (parts[0] === "self" && (follow2 || parts.length > 1)) parts[0] = String(this.pid);
8767
+ return parts;
8768
+ }
8769
+ find(path, follow2) {
8770
+ const node = this.node(this.parts(path, follow2));
8771
+ if (!node) throw syncError("ENOENT", path);
8772
+ return node;
8773
+ }
8774
+ stat(path, follow2 = true) {
8775
+ const node = this.find(path, follow2);
8776
+ const base = {
8777
+ isFile: false,
8778
+ isDirectory: false,
8779
+ size: 0,
8780
+ mtimeMs: Date.now(),
8781
+ readonly: true
8782
+ };
8783
+ if (node.kind === "dir") return { ...base, isDirectory: true, mode: DIR_MODE3 };
8784
+ if (node.kind === "link") {
8785
+ return { ...base, isSymbolicLink: true, mode: LINK_MODE3, size: node.target.length };
8786
+ }
8787
+ return { ...base, isFile: true, mode: FILE_MODE2, size: this.bytes(node).length };
8788
+ }
8789
+ bytes(node) {
8790
+ return new TextEncoder().encode(node.kind === "file" ? node.content() : "");
8791
+ }
8792
+ read(path) {
8793
+ const node = this.find(path, true);
8794
+ if (node.kind !== "file") throw syncError("EISDIR", path);
8795
+ return this.bytes(node);
8796
+ }
8797
+ readdir(path) {
8798
+ const node = this.find(path, true);
8799
+ if (node.kind !== "dir") throw syncError("ENOTDIR", path);
8800
+ return node.names();
8801
+ }
8802
+ readlink(path) {
8803
+ const node = this.find(path, false);
8804
+ if (node.kind !== "link") throw syncError("EINVAL", path);
8805
+ return node.target;
8806
+ }
8807
+ exists(path) {
8808
+ try {
8809
+ this.find(path, true);
8810
+ return true;
8811
+ } catch {
8812
+ return false;
8813
+ }
8814
+ }
8815
+ };
8816
+ READ_ONLY = [
8817
+ "writeFile",
8818
+ "mkdir",
8819
+ "rm",
8820
+ "unlink",
8821
+ "rmdir",
8822
+ "symlink",
8823
+ "chmod",
8824
+ "utimes",
8825
+ "lutimes",
8826
+ "create",
8827
+ "pwrite",
8828
+ "truncate"
8829
+ ];
8830
+ }
8831
+ });
8832
+
8628
8833
  // src/process/wasi/wasi-signals.ts
8629
8834
  var DELIVERED_MASK, KERNEL_DEFAULTS, LIBC_DEFAULT_EXIT, SA_RESTART, DISPOSITION_IGNORE, DISPOSITION_HANDLER, withBit, WASIX_LIBC_DEFAULT_LINE, WasiSignals;
8630
8835
  var init_wasi_signals = __esm({
@@ -10768,6 +10973,15 @@ async function instantiate(host, module, memory, threads, {
10768
10973
  }
10769
10974
  return { instance, driver };
10770
10975
  }
10976
+ function procTree(call2, pid) {
10977
+ return new ProcTree(
10978
+ {
10979
+ procList: () => call2({ op: "proc-list" }),
10980
+ mountList: () => call2({ op: "mount-list" })
10981
+ },
10982
+ pid
10983
+ );
10984
+ }
10771
10985
  function exportedTable(instance) {
10772
10986
  const table = instance.exports.__indirect_function_table;
10773
10987
  return table instanceof WebAssembly.Table ? table : void 0;
@@ -10839,7 +11053,10 @@ async function runWasiProcess(init, port3) {
10839
11053
  ppid: id.ppid,
10840
11054
  parent: () => identify(transport, init).ppid,
10841
11055
  kernel: { sys: traced(stats, "kernel", sys), call: call2 },
10842
- fs: cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
11056
+ fs: procfsBridge(
11057
+ cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
11058
+ procTree(call2, id.pid)
11059
+ ),
10843
11060
  ...descriptors(init, fork, threads)
10844
11061
  });
10845
11062
  if (threads) {
@@ -10930,7 +11147,7 @@ async function runWasiThread(init, port3) {
10930
11147
  ppid: id.ppid,
10931
11148
  parent: () => identify(transport, init).ppid,
10932
11149
  kernel: { sys, call: call2 },
10933
- fs: cachingBridge(createSyncFsSabBridge(transport)),
11150
+ fs: procfsBridge(cachingBridge(createSyncFsSabBridge(transport)), procTree(call2, id.pid)),
10934
11151
  shared: threads.ids
10935
11152
  });
10936
11153
  const program = await programImports(init.program, host, transport, thread.tid);
@@ -10985,6 +11202,7 @@ var init_wasi_runtime = __esm({
10985
11202
  init_wasi_host();
10986
11203
  init_wasi_imports();
10987
11204
  init_wasi_module();
11205
+ init_wasi_procfs();
10988
11206
  init_wasi_signals();
10989
11207
  init_wasi_stats();
10990
11208
  init_wasi_threads();