@ai-ecoverse/slicc-kernel 1.51.1 → 1.53.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.
@@ -4770,6 +4770,10 @@ function kernelEntry2() {
4770
4770
  function deviceEntry(meta) {
4771
4771
  return { type: "device", device: meta.device, ...meta.access ? { access: meta.access } : {} };
4772
4772
  }
4773
+ function refuseWrite(s, oflags, rights) {
4774
+ const writes = (rights & RIGHTS.FD_WRITE) !== 0n || (oflags & OFLAGS.TRUNC) !== 0;
4775
+ if (s?.readonly && writes) throw new WasiError("EROFS");
4776
+ }
4773
4777
  function preopenOf(e) {
4774
4778
  return {
4775
4779
  ...e.preopen ? { preopen: e.preopen } : {},
@@ -5237,6 +5241,7 @@ var init_wasi_fds = __esm({
5237
5241
  return this.install({ type: "dir", path });
5238
5242
  }
5239
5243
  if (!s && !(oflags & OFLAGS.CREAT)) throw new WasiError("ENOENT");
5244
+ refuseWrite(s, oflags, rights);
5240
5245
  if (this.shared) return this.kernelFile(path, s, oflags, rights, fdflags);
5241
5246
  return this.install({ type: "file", file: this.file(path, s, oflags, rights, fdflags) });
5242
5247
  }
@@ -6748,6 +6753,191 @@ var init_wasi_module = __esm({
6748
6753
  }
6749
6754
  });
6750
6755
 
6756
+ // src/process/wasi/wasi-procfs.ts
6757
+ function inProc(path) {
6758
+ return path === "/proc" || path.startsWith("/proc/");
6759
+ }
6760
+ function procfsBridge(fs, tree) {
6761
+ const over = {
6762
+ readFile: (p) => inProc(p) ? tree.read(p) : fs.readFile(p),
6763
+ stat: (p) => inProc(p) ? tree.stat(p) : fs.stat(p),
6764
+ lstat: (p) => inProc(p) ? tree.stat(p, false) : fs.lstat(p),
6765
+ readdir: (p) => {
6766
+ if (inProc(p)) return tree.readdir(p);
6767
+ const names = fs.readdir(p);
6768
+ return p === "/" && !names.includes("proc") ? [...names, "proc"] : names;
6769
+ },
6770
+ exists: (p) => inProc(p) ? tree.exists(p) : fs.exists(p),
6771
+ readlink: (p) => inProc(p) ? tree.readlink(p) : fs.readlink(p),
6772
+ readdirStat: (p) => {
6773
+ if (!inProc(p)) {
6774
+ const listed = fs.readdirStat(p);
6775
+ if (p !== "/" || listed.some(([name2]) => name2 === "proc")) return listed;
6776
+ return [...listed, ["proc", tree.stat("/proc")]];
6777
+ }
6778
+ return tree.readdir(p).map((name2) => {
6779
+ try {
6780
+ return [name2, tree.stat(`${p}/${name2}`, false)];
6781
+ } catch {
6782
+ return [name2, null];
6783
+ }
6784
+ });
6785
+ },
6786
+ rename: (from, to) => {
6787
+ if (inProc(from) || inProc(to)) throw syncError("EROFS", from);
6788
+ fs.rename(from, to);
6789
+ },
6790
+ hold: (p, ...rest2) => inProc(p) ? void 0 : fs.hold?.(p, ...rest2),
6791
+ ...fs.pread ? {
6792
+ pread: (p, at, n, version) => inProc(p) ? tree.read(p).subarray(at, at + n) : fs.pread(p, at, n, version)
6793
+ } : {}
6794
+ };
6795
+ for (const name2 of READ_ONLY) {
6796
+ const fn = fs[name2];
6797
+ if (!fn) continue;
6798
+ over[name2] = (p, ...rest2) => {
6799
+ if (inProc(p)) throw syncError("EROFS", p);
6800
+ return fn.call(fs, p, ...rest2);
6801
+ };
6802
+ }
6803
+ return new Proxy(fs, {
6804
+ get: (target, key, receiver) => key in over ? over[key] : Reflect.get(target, key, receiver)
6805
+ });
6806
+ }
6807
+ var DIR_MODE3, FILE_MODE2, LINK_MODE3, PID_NAMES, SYSTEM_NAMES, ProcTree, READ_ONLY;
6808
+ var init_wasi_procfs = __esm({
6809
+ "src/process/wasi/wasi-procfs.ts"() {
6810
+ "use strict";
6811
+ init_sync_fs_wire();
6812
+ init_process_fds();
6813
+ init_procfs();
6814
+ DIR_MODE3 = 16749;
6815
+ FILE_MODE2 = 33060;
6816
+ LINK_MODE3 = 41471;
6817
+ PID_NAMES = PID_FILES;
6818
+ SYSTEM_NAMES = SYSTEM_FILES;
6819
+ ProcTree = class {
6820
+ source;
6821
+ pid;
6822
+ memory;
6823
+ constructor(source, pid, memory = memorySource()) {
6824
+ this.source = source;
6825
+ this.pid = pid;
6826
+ this.memory = memory;
6827
+ }
6828
+ listing() {
6829
+ return this.source.procList();
6830
+ }
6831
+ alive(pid) {
6832
+ return this.listing().processes.some((p) => p.pid === pid);
6833
+ }
6834
+ node(parts) {
6835
+ const [top, leaf, ...rest2] = parts;
6836
+ if (top === void 0) {
6837
+ return {
6838
+ kind: "dir",
6839
+ names: () => [
6840
+ ...SYSTEM_NAMES,
6841
+ "mounts",
6842
+ "self",
6843
+ ...this.listing().processes.map((p) => String(p.pid))
6844
+ ]
6845
+ };
6846
+ }
6847
+ if (top === "self") {
6848
+ return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
6849
+ }
6850
+ if (leaf === void 0 && top === "mounts") {
6851
+ return { kind: "file", content: () => mountTable(this.source.mountList()) };
6852
+ }
6853
+ if (leaf === void 0 && SYSTEM_NAMES.includes(top)) {
6854
+ return {
6855
+ kind: "file",
6856
+ content: () => systemFile(top, this.listing(), Date.now(), this.memory)
6857
+ };
6858
+ }
6859
+ if (!/^[1-9]\d*$/.test(top) || rest2.length > 0 || !this.alive(Number(top))) return void 0;
6860
+ if (leaf === void 0) return { kind: "dir", names: () => [...PID_NAMES] };
6861
+ if (!PID_NAMES.includes(leaf)) return void 0;
6862
+ return {
6863
+ kind: "file",
6864
+ content: () => {
6865
+ const listing = this.listing();
6866
+ const info = listing.processes.find((p) => p.pid === Number(top));
6867
+ if (!info) throw syncError("ENOENT", `/proc/${top}/${leaf}`);
6868
+ return pidFile(leaf, info, listing.boot);
6869
+ }
6870
+ };
6871
+ }
6872
+ parts(path, follow2) {
6873
+ const parts = path.split("/").filter((p) => p !== "").slice(1);
6874
+ if (parts[0] === "self" && (follow2 || parts.length > 1)) parts[0] = String(this.pid);
6875
+ return parts;
6876
+ }
6877
+ find(path, follow2) {
6878
+ const node = this.node(this.parts(path, follow2));
6879
+ if (!node) throw syncError("ENOENT", path);
6880
+ return node;
6881
+ }
6882
+ stat(path, follow2 = true) {
6883
+ const node = this.find(path, follow2);
6884
+ const base = {
6885
+ isFile: false,
6886
+ isDirectory: false,
6887
+ size: 0,
6888
+ mtimeMs: Date.now(),
6889
+ readonly: true
6890
+ };
6891
+ if (node.kind === "dir") return { ...base, isDirectory: true, mode: DIR_MODE3 };
6892
+ if (node.kind === "link") {
6893
+ return { ...base, isSymbolicLink: true, mode: LINK_MODE3, size: node.target.length };
6894
+ }
6895
+ return { ...base, isFile: true, mode: FILE_MODE2, size: this.bytes(node).length };
6896
+ }
6897
+ bytes(node) {
6898
+ return new TextEncoder().encode(node.kind === "file" ? node.content() : "");
6899
+ }
6900
+ read(path) {
6901
+ const node = this.find(path, true);
6902
+ if (node.kind !== "file") throw syncError("EISDIR", path);
6903
+ return this.bytes(node);
6904
+ }
6905
+ readdir(path) {
6906
+ const node = this.find(path, true);
6907
+ if (node.kind !== "dir") throw syncError("ENOTDIR", path);
6908
+ return node.names();
6909
+ }
6910
+ readlink(path) {
6911
+ const node = this.find(path, false);
6912
+ if (node.kind !== "link") throw syncError("EINVAL", path);
6913
+ return node.target;
6914
+ }
6915
+ exists(path) {
6916
+ try {
6917
+ this.find(path, true);
6918
+ return true;
6919
+ } catch {
6920
+ return false;
6921
+ }
6922
+ }
6923
+ };
6924
+ READ_ONLY = [
6925
+ "writeFile",
6926
+ "mkdir",
6927
+ "rm",
6928
+ "unlink",
6929
+ "rmdir",
6930
+ "symlink",
6931
+ "chmod",
6932
+ "utimes",
6933
+ "lutimes",
6934
+ "create",
6935
+ "pwrite",
6936
+ "truncate"
6937
+ ];
6938
+ }
6939
+ });
6940
+
6751
6941
  // src/process/wasi/wasi-signals.ts
6752
6942
  var DELIVERED_MASK, KERNEL_DEFAULTS, LIBC_DEFAULT_EXIT, SA_RESTART, DISPOSITION_IGNORE, DISPOSITION_HANDLER, withBit, WASIX_LIBC_DEFAULT_LINE, WasiSignals;
6753
6943
  var init_wasi_signals = __esm({
@@ -8891,6 +9081,15 @@ async function instantiate(host, module, memory, threads, {
8891
9081
  }
8892
9082
  return { instance, driver };
8893
9083
  }
9084
+ function procTree(call2, pid) {
9085
+ return new ProcTree(
9086
+ {
9087
+ procList: () => call2({ op: "proc-list" }),
9088
+ mountList: () => call2({ op: "mount-list" })
9089
+ },
9090
+ pid
9091
+ );
9092
+ }
8894
9093
  function exportedTable(instance) {
8895
9094
  const table = instance.exports.__indirect_function_table;
8896
9095
  return table instanceof WebAssembly.Table ? table : void 0;
@@ -8962,7 +9161,10 @@ async function runWasiProcess(init, port2) {
8962
9161
  ppid: id.ppid,
8963
9162
  parent: () => identify(transport, init).ppid,
8964
9163
  kernel: { sys: traced(stats, "kernel", sys), call: call2 },
8965
- fs: cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
9164
+ fs: procfsBridge(
9165
+ cachingBridge(traced(stats, "fs", createSyncFsSabBridge(transport))),
9166
+ procTree(call2, id.pid)
9167
+ ),
8966
9168
  ...descriptors(init, fork, threads)
8967
9169
  });
8968
9170
  if (threads) {
@@ -9053,7 +9255,7 @@ async function runWasiThread(init, port2) {
9053
9255
  ppid: id.ppid,
9054
9256
  parent: () => identify(transport, init).ppid,
9055
9257
  kernel: { sys, call: call2 },
9056
- fs: cachingBridge(createSyncFsSabBridge(transport)),
9258
+ fs: procfsBridge(cachingBridge(createSyncFsSabBridge(transport)), procTree(call2, id.pid)),
9057
9259
  shared: threads.ids
9058
9260
  });
9059
9261
  const program = await programImports(init.program, host, transport, thread.tid);
@@ -9108,6 +9310,7 @@ var init_wasi_runtime = __esm({
9108
9310
  init_wasi_host();
9109
9311
  init_wasi_imports();
9110
9312
  init_wasi_module();
9313
+ init_wasi_procfs();
9111
9314
  init_wasi_signals();
9112
9315
  init_wasi_stats();
9113
9316
  init_wasi_threads();
@@ -10370,10 +10573,25 @@ function ttyOps(kernel) {
10370
10573
  await kernel.call({ op: "tty-pgrp-set", fd, pgrp });
10371
10574
  }
10372
10575
  };
10576
+ const openOn = async (terminal, fd) => {
10577
+ const open = await kernel.json({ op: "fd-list" });
10578
+ const on = open.filter((entry) => entry.terminal === terminal);
10579
+ return (on.find((entry) => entry.fd === fd) ?? on[0])?.fd;
10580
+ };
10581
+ const reopened = async (terminal, termios) => {
10582
+ const fd = await kernel.json({ op: "fd-open-tty", name: terminal });
10583
+ try {
10584
+ await setAttr(fd, termios);
10585
+ } finally {
10586
+ await kernel.call({ op: "fd-close", fd });
10587
+ }
10588
+ };
10373
10589
  const restore = async () => {
10374
10590
  for (const [terminal, { fd, termios }] of [...saved].reverse()) {
10375
10591
  saved.delete(terminal);
10376
- await setAttr(fd, termios).catch(() => void 0);
10592
+ const at = await openOn(terminal, fd).catch(() => void 0);
10593
+ const back = at === void 0 ? reopened(terminal, termios) : setAttr(at, termios);
10594
+ await back.catch(() => void 0);
10377
10595
  }
10378
10596
  };
10379
10597
  return { tty, restore };
@@ -10910,19 +11128,35 @@ function hide(target, names) {
10910
11128
  }
10911
11129
  }
10912
11130
  }
11131
+ function vacate(target, names) {
11132
+ for (const name2 of names) {
11133
+ for (let at = target; at && at !== Object.prototype; ) {
11134
+ if (Object.getOwnPropertyDescriptor(at, name2)?.configurable) Reflect.deleteProperty(at, name2);
11135
+ at = Object.getPrototypeOf(at);
11136
+ }
11137
+ Reflect.defineProperty(target, name2, {
11138
+ value: void 0,
11139
+ writable: true,
11140
+ enumerable: false,
11141
+ configurable: true
11142
+ });
11143
+ if (Reflect.get(target, name2) !== void 0) {
11144
+ throw new Error(`slicc-kernel: cannot withhold ${name2} from a JS program`);
11145
+ }
11146
+ }
11147
+ }
10913
11148
  function lockdown(scope2 = globalThis) {
10914
11149
  hide(scope2, BLOCKED_GLOBALS);
11150
+ vacate(scope2, OPEN_SLOTS);
10915
11151
  const navigator = scope2.navigator;
10916
11152
  if (navigator && typeof navigator === "object") hide(navigator, BLOCKED_NAVIGATOR);
10917
11153
  }
10918
- var BLOCKED_GLOBALS, BLOCKED_NAVIGATOR;
11154
+ var BLOCKED_GLOBALS, BLOCKED_NAVIGATOR, OPEN_SLOTS;
10919
11155
  var init_lockdown = __esm({
10920
11156
  "src/process/js/lockdown.ts"() {
10921
11157
  "use strict";
10922
11158
  BLOCKED_GLOBALS = [
10923
- "fetch",
10924
11159
  "XMLHttpRequest",
10925
- "WebSocket",
10926
11160
  "WebSocketStream",
10927
11161
  "WebTransport",
10928
11162
  "EventSource",
@@ -10937,6 +11171,7 @@ var init_lockdown = __esm({
10937
11171
  "close"
10938
11172
  ];
10939
11173
  BLOCKED_NAVIGATOR = ["storage", "locks", "serviceWorker"];
11174
+ OPEN_SLOTS = ["fetch", "WebSocket"];
10940
11175
  }
10941
11176
  });
10942
11177