@ai-ecoverse/slicc-kernel 1.113.0 → 1.115.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.
package/dist/node.js CHANGED
@@ -473,8 +473,8 @@ async function access(fs, cred, path, want, options = {}) {
473
473
  if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
474
474
  return { ...walked, missing: true };
475
475
  }
476
- function refused(path, errno2 = "EACCES") {
477
- return fsError(errno2, path);
476
+ function refused(path, errno3 = "EACCES") {
477
+ return fsError(errno3, path);
478
478
  }
479
479
 
480
480
  // src/fs/dac.ts
@@ -534,9 +534,9 @@ var Created = class {
534
534
  function linked(g, options) {
535
535
  return g.links === void 0 ? options : { ...options, links: g.links };
536
536
  }
537
- function deny(g, op, path, errno2 = "EACCES") {
537
+ function deny(g, op, path, errno3 = "EACCES") {
538
538
  const tag = g.tag === void 0 ? {} : { tag: g.tag };
539
- g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno2, ...tag });
539
+ g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno3, ...tag });
540
540
  }
541
541
  var TTY_MODE = 400;
542
542
  function ttyOpenable(g, tty) {
@@ -1249,7 +1249,7 @@ var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
1249
1249
 
1250
1250
  // src/process/wasi-errno.ts
1251
1251
  var WASI_ERRNO = {
1252
- ...Object.fromEntries(Object.entries(E).map(([name2, errno2]) => [`E${name2}`, errno2])),
1252
+ ...Object.fromEntries(Object.entries(E).map(([name2, errno3]) => [`E${name2}`, errno3])),
1253
1253
  EWOULDBLOCK: E.AGAIN,
1254
1254
  ENOTSUP: 138,
1255
1255
  EOPNOTSUPP: 138,
@@ -1489,7 +1489,7 @@ function dialError(e, timedOut, closed) {
1489
1489
  if (timedOut) return new KernelError("ETIMEDOUT");
1490
1490
  if (closed) return new KernelError("ECONNABORTED");
1491
1491
  const code = e?.code;
1492
- const known = DIAL_ERRORS.find((errno2) => errno2 === code);
1492
+ const known = DIAL_ERRORS.find((errno3) => errno3 === code);
1493
1493
  return new KernelError(known ?? "EHOSTUNREACH");
1494
1494
  }
1495
1495
  function isLoopback(host) {
@@ -2129,6 +2129,14 @@ var SIGNAL_BY_NAME = {
2129
2129
  SIGSTOP: SIG.STOP,
2130
2130
  SIGCONT: SIG.CONT
2131
2131
  };
2132
+ var SI = { USER: 0, QUEUE: -1, TIMER: -2, TKILL: -6, KERNEL: 128 };
2133
+ var CLD = { EXITED: 1, KILLED: 2, DUMPED: 3, STOPPED: 5, CONTINUED: 6 };
2134
+ var KERNEL_SIGINFO = Object.freeze({
2135
+ code: SI.KERNEL,
2136
+ pid: 0,
2137
+ uid: 0,
2138
+ status: 0
2139
+ });
2132
2140
 
2133
2141
  // src/body-idle.ts
2134
2142
  var BODY_IDLE_MS = 5 * 60 * 1e3;
@@ -4094,6 +4102,7 @@ var S_IFDIR = 16384;
4094
4102
  var S_IFREG = 32768;
4095
4103
  var S_IFLNK = 40960;
4096
4104
  var S_IFSOCK = 49152;
4105
+ var S_IFIFO = 4096;
4097
4106
  var PERM_MASK = 4095;
4098
4107
  var S_ISGID3 = 1024;
4099
4108
  var READ_ATTEMPTS = 3;
@@ -4373,7 +4382,10 @@ var OpfsFs = class {
4373
4382
  }
4374
4383
  async stampNew(path, owner, directory) {
4375
4384
  const owned4 = await this.newFields(path, owner, directory);
4376
- const fields = owner?.socket && !directory ? { ...owned4, socket: true } : owned4;
4385
+ if (owner?.socket && owner.fifo) throw new Error("a new node is a socket or a FIFO, not both");
4386
+ const kind = directory ? void 0 : owner?.socket ? "socket" : owner?.fifo ? "fifo" : void 0;
4387
+ const unique = kind === "fifo" ? { ino: inodeOf(`${path}\0${crypto.randomUUID()}`) } : {};
4388
+ const fields = kind ? { ...owned4, ...unique, [kind]: true } : owned4;
4377
4389
  if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
4378
4390
  }
4379
4391
  guarded = [];
@@ -4615,7 +4627,7 @@ var OpfsFs = class {
4615
4627
  }
4616
4628
  mode(path, directory, meta) {
4617
4629
  const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
4618
- const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : S_IFREG;
4630
+ const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : meta?.fifo ? S_IFIFO : S_IFREG;
4619
4631
  return type | (meta?.mode ?? fallback);
4620
4632
  }
4621
4633
  id = crypto.randomUUID();
@@ -4716,11 +4728,13 @@ var OpfsFs = class {
4716
4728
  const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
4717
4729
  const mtime = touched ?? kept;
4718
4730
  const socket = !directory && meta?.socket === true;
4731
+ const fifo = !directory && meta?.fifo === true;
4719
4732
  return {
4720
- isFile: !directory && !socket,
4733
+ isFile: !directory && !socket && !fifo,
4721
4734
  isDirectory: directory,
4722
4735
  isSymbolicLink: false,
4723
4736
  ...socket ? { isSocket: true } : {},
4737
+ ...fifo ? { isFifo: true } : {},
4724
4738
  size: file?.size ?? 0,
4725
4739
  mode: this.mode(path, directory, meta),
4726
4740
  mtime: new Date(mtime),
@@ -6531,7 +6545,7 @@ function satisfies(version, range2) {
6531
6545
  }
6532
6546
 
6533
6547
  // src/version.ts
6534
- var KERNEL_VERSION = true ? "1.113.0" : "0.0.0-dev";
6548
+ var KERNEL_VERSION = true ? "1.115.0" : "0.0.0-dev";
6535
6549
  var OS_RELEASE = "6.0.0-slicc";
6536
6550
  function procVersion() {
6537
6551
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -9185,8 +9199,16 @@ var ChildTable = class {
9185
9199
  void handle.exited.then((code) => {
9186
9200
  child.code = code;
9187
9201
  this.watchers.delete(handle.pid);
9202
+ const termsig = handle.termsig?.();
9188
9203
  if (!this.kept.delete(handle.pid) && this.autoReap?.()) this.reap(handle.pid, code);
9189
- this.onChildState?.();
9204
+ const uid = handle.uid?.();
9205
+ this.onChildState?.({
9206
+ pid: handle.pid,
9207
+ state: "exited",
9208
+ status: termsig ?? code,
9209
+ termsig,
9210
+ uid
9211
+ });
9190
9212
  });
9191
9213
  handle.onState?.((state, sig) => {
9192
9214
  child.stopReport = state === "stopped" ? sig : void 0;
@@ -9196,7 +9218,7 @@ var ChildTable = class {
9196
9218
  const waiters = this.stateChanged;
9197
9219
  this.stateChanged = [];
9198
9220
  for (const wake of waiters) wake();
9199
- this.onChildState?.();
9221
+ this.onChildState?.({ pid: handle.pid, state, status: sig, uid: handle.uid?.() });
9200
9222
  });
9201
9223
  this.children.set(handle.pid, child);
9202
9224
  return handle.pid;
@@ -9526,6 +9548,139 @@ var TicketBook = class {
9526
9548
  }
9527
9549
  };
9528
9550
 
9551
+ // src/kernel/fifo.ts
9552
+ function errno(e) {
9553
+ return e instanceof KernelError ? e : new KernelError(e.code ?? "EIO");
9554
+ }
9555
+ var FifoTable = class {
9556
+ fifos = /* @__PURE__ */ new Map();
9557
+ size() {
9558
+ return this.fifos.size;
9559
+ }
9560
+ async open(key, path, access2, nonblock, signal) {
9561
+ const fifo = this.entry(key);
9562
+ if (access2 === "write" && nonblock && fifo.readers === 0) {
9563
+ this.drop(key, fifo);
9564
+ throw new KernelError("ENXIO");
9565
+ }
9566
+ const reads = access2 !== "write";
9567
+ const writes = access2 !== "read";
9568
+ const seen = { readOpens: fifo.readOpens, writeOpens: fifo.writeOpens };
9569
+ if (reads) this.count(fifo, "readers", 1);
9570
+ if (writes) this.count(fifo, "writers", 1);
9571
+ this.notify(fifo);
9572
+ try {
9573
+ if (!nonblock && access2 === "read") {
9574
+ while (fifo.writers === 0 && fifo.writeOpens === seen.writeOpens) {
9575
+ await this.changed(fifo, signal);
9576
+ }
9577
+ }
9578
+ if (!nonblock && access2 === "write") {
9579
+ while (fifo.readers === 0 && fifo.readOpens === seen.readOpens) {
9580
+ await this.changed(fifo, signal);
9581
+ }
9582
+ }
9583
+ } catch (e) {
9584
+ this.release(key, fifo, reads, writes);
9585
+ throw errno(e);
9586
+ }
9587
+ return this.end(key, path, fifo, reads, writes);
9588
+ }
9589
+ entry(key) {
9590
+ let fifo = this.fifos.get(key);
9591
+ if (!fifo) {
9592
+ fifo = {
9593
+ pipe: new KernelPipe(),
9594
+ readers: 0,
9595
+ writers: 0,
9596
+ readOpens: 0,
9597
+ writeOpens: 0,
9598
+ waiters: []
9599
+ };
9600
+ this.fifos.set(key, fifo);
9601
+ }
9602
+ return fifo;
9603
+ }
9604
+ count(fifo, side, by) {
9605
+ fifo[side] += by;
9606
+ if (side === "readers") {
9607
+ if (by > 0) {
9608
+ fifo.readOpens += 1;
9609
+ fifo.pipe.openRead();
9610
+ } else fifo.pipe.closeRead();
9611
+ } else if (by > 0) {
9612
+ fifo.writeOpens += 1;
9613
+ fifo.pipe.openWrite();
9614
+ } else fifo.pipe.closeWrite();
9615
+ }
9616
+ notify(fifo) {
9617
+ const waiters = fifo.waiters;
9618
+ fifo.waiters = [];
9619
+ for (const wake of waiters) wake();
9620
+ }
9621
+ changed(fifo, signal) {
9622
+ if (signal.aborted) return Promise.reject(new KernelError("EINTR"));
9623
+ return new Promise((resolve2, reject) => {
9624
+ const onAbort = () => {
9625
+ fifo.waiters = fifo.waiters.filter((w) => w !== wake);
9626
+ reject(new KernelError("EINTR"));
9627
+ };
9628
+ const wake = () => {
9629
+ signal.removeEventListener("abort", onAbort);
9630
+ resolve2();
9631
+ };
9632
+ fifo.waiters.push(wake);
9633
+ signal.addEventListener("abort", onAbort, { once: true });
9634
+ });
9635
+ }
9636
+ release(key, fifo, reads, writes) {
9637
+ if (reads) this.count(fifo, "readers", -1);
9638
+ if (writes) this.count(fifo, "writers", -1);
9639
+ this.notify(fifo);
9640
+ this.drop(key, fifo);
9641
+ }
9642
+ drop(key, fifo) {
9643
+ const idle = fifo.readers === 0 && fifo.writers === 0 && fifo.waiters.length === 0;
9644
+ if (idle && this.fifos.get(key) === fifo) this.fifos.delete(key);
9645
+ }
9646
+ end(key, path, fifo, reads, writes) {
9647
+ const { pipe } = fifo;
9648
+ let open = true;
9649
+ return new OpenFile({
9650
+ fifo: path,
9651
+ ...reads ? {
9652
+ read: async (max, signal) => {
9653
+ try {
9654
+ return await pipe.read(max, signal);
9655
+ } catch (e) {
9656
+ throw errno(e);
9657
+ }
9658
+ }
9659
+ } : {},
9660
+ ...writes ? {
9661
+ write: async (bytes, signal) => {
9662
+ try {
9663
+ return await pipe.write(bytes, signal);
9664
+ } catch (e) {
9665
+ throw errno(e);
9666
+ }
9667
+ }
9668
+ } : {},
9669
+ close: () => {
9670
+ if (!open) return;
9671
+ open = false;
9672
+ this.release(key, fifo, reads, writes);
9673
+ },
9674
+ poll: () => ({
9675
+ readable: reads && pipe.readReady,
9676
+ writable: writes && pipe.writeReady,
9677
+ hangup: reads ? pipe.writersGone : pipe.readersGone
9678
+ }),
9679
+ changed: (signal) => pipe.changed(signal)
9680
+ });
9681
+ }
9682
+ };
9683
+
9529
9684
  // src/mount/protocol.ts
9530
9685
  var DRIVER_PROTOCOL = [1, 2];
9531
9686
  function driverVersionError(theirs) {
@@ -10386,6 +10541,7 @@ var MountFs = class _MountFs {
10386
10541
  }
10387
10542
  const { mount, rel: rel2 } = found;
10388
10543
  this.writable(mount, real);
10544
+ if (owner?.fifo) throw errnoError("EPERM", `${real}: this mount has no FIFOs`);
10389
10545
  const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
10390
10546
  if (mount.maxFile > 0 && bytes.length > mount.maxFile) {
10391
10547
  throw errnoError(
@@ -10991,6 +11147,7 @@ var SYNC_FS_OPS = [
10991
11147
  "statfs",
10992
11148
  "hold",
10993
11149
  "create",
11150
+ "mkfifo",
10994
11151
  "kept",
10995
11152
  "pread",
10996
11153
  "pwrite",
@@ -11023,6 +11180,7 @@ function statJson(s) {
11023
11180
  isFile: s.isFile,
11024
11181
  isSymbolicLink: s.isSymbolicLink,
11025
11182
  ...s.isSocket ? { isSocket: true } : {},
11183
+ ...s.isFifo ? { isFifo: true } : {},
11026
11184
  size: s.size,
11027
11185
  mode: s.mode,
11028
11186
  mtimeMs: s.mtime.getTime(),
@@ -11172,6 +11330,12 @@ async function run(entry, path, req) {
11172
11330
  case "symlink":
11173
11331
  await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
11174
11332
  return done;
11333
+ case "mkfifo": {
11334
+ const owner = ownerFor2(entry, req.mode ?? 438) ?? { uid: 0, gid: 0 };
11335
+ await createExclusive(fs, path, { ...owner, fifo: true });
11336
+ entry.fresh?.(path);
11337
+ return done;
11338
+ }
11175
11339
  case "create":
11176
11340
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
11177
11341
  if (req.opening) entry.created?.add(path);
@@ -11250,9 +11414,10 @@ async function guard(g, path, req, cwd) {
11250
11414
  return { path: await walkSafe(g, path, false) };
11251
11415
  }
11252
11416
  case "create":
11417
+ case "mkfifo":
11253
11418
  case "symlink":
11254
11419
  await inParent(g, op, path);
11255
- return { path: await walkSafe(g, path, op === "create") };
11420
+ return { path: await walkSafe(g, path, op !== "symlink") };
11256
11421
  case "unlink":
11257
11422
  case "rmdir": {
11258
11423
  await inParent(g, op, path, true);
@@ -11340,6 +11505,7 @@ async function accessOp(entry, path, req) {
11340
11505
  var CHANGING = /* @__PURE__ */ new Set([
11341
11506
  "mkdir",
11342
11507
  "create",
11508
+ "mkfifo",
11343
11509
  "symlink",
11344
11510
  "unlink",
11345
11511
  "rmdir",
@@ -11534,7 +11700,13 @@ async function guardAndResolve(entry, path, req) {
11534
11700
  };
11535
11701
  }
11536
11702
  var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
11537
- var CREATIONS = /* @__PURE__ */ new Set(["write", "mkdir", "symlink", "create"]);
11703
+ var CREATIONS = /* @__PURE__ */ new Set([
11704
+ "write",
11705
+ "mkdir",
11706
+ "symlink",
11707
+ "create",
11708
+ "mkfifo"
11709
+ ]);
11538
11710
  var NAMING = /* @__PURE__ */ new Set(["link", "rename"]);
11539
11711
  async function newDevName(entry, path, req) {
11540
11712
  const named = NAMING.has(req.op);
@@ -13281,16 +13453,16 @@ var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
13281
13453
  var SAFE_VALUE = /^[^\r\n\0]*$/;
13282
13454
  var CLOSE_WAIT_MS3 = 5e3;
13283
13455
  var MAX_UNREAD = 16 * 1024 * 1024;
13284
- function errno(code, message3) {
13456
+ function errno2(code, message3) {
13285
13457
  return Object.assign(new Error(`${code}: ${message3}`), { code });
13286
13458
  }
13287
13459
  function requestHead(method, url, headers, extra, first = []) {
13288
- if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
13460
+ if (!TOKEN3.test(method)) throw errno2("EINVAL", `method ${method}`);
13289
13461
  const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
13290
13462
  for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
13291
13463
  for (const [name2, value2] of headers) {
13292
13464
  if (OWN_HEADERS.has(name2.toLowerCase())) continue;
13293
- if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno("EINVAL", `header ${name2}`);
13465
+ if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno2("EINVAL", `header ${name2}`);
13294
13466
  lines2.push(`${name2}: ${value2}`);
13295
13467
  }
13296
13468
  for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
@@ -13301,7 +13473,7 @@ function requestHead(method, url, headers, extra, first = []) {
13301
13473
  function parseHead(bytes) {
13302
13474
  const [statusLine = "", ...lines2] = latin1(bytes).split(/\r?\n/);
13303
13475
  const match = /^HTTP\/1\.[01] (\d{3})(?: (.*))?$/.exec(statusLine);
13304
- if (!match) throw errno("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13476
+ if (!match) throw errno2("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13305
13477
  const headers = [];
13306
13478
  for (const line of lines2) {
13307
13479
  const colon = line.indexOf(":");
@@ -13316,9 +13488,9 @@ async function readHead(incoming, signal) {
13316
13488
  raw = await incoming.head(MAX_HEAD2, signal);
13317
13489
  } catch (err) {
13318
13490
  if (err instanceof KernelError) throw err;
13319
- throw errno("EPROTO", "the response head is malformed or too large");
13491
+ throw errno2("EPROTO", "the response head is malformed or too large");
13320
13492
  }
13321
- if (!raw) throw errno("ECONNRESET", "the connection closed before a response");
13493
+ if (!raw) throw errno2("ECONNRESET", "the connection closed before a response");
13322
13494
  const head = parseHead(raw);
13323
13495
  if (head.status < 100 || head.status >= 200 || head.status === 101) return head;
13324
13496
  }
@@ -13327,20 +13499,20 @@ async function* chunked(incoming, signal) {
13327
13499
  for (; ; ) {
13328
13500
  const line = await incoming.line(4096, signal);
13329
13501
  const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(line);
13330
- if (!size) throw errno("EPROTO", "a malformed chunk size");
13502
+ if (!size) throw errno2("EPROTO", "a malformed chunk size");
13331
13503
  const n = Number.parseInt(size[1], 16);
13332
13504
  if (n === 0) {
13333
13505
  while (await incoming.line(MAX_HEAD2, signal) !== "") ;
13334
13506
  return;
13335
13507
  }
13336
13508
  yield await incoming.exactly(n, signal);
13337
- if (await incoming.line(2, signal) !== "") throw errno("EPROTO", "a malformed chunk");
13509
+ if (await incoming.line(2, signal) !== "") throw errno2("EPROTO", "a malformed chunk");
13338
13510
  }
13339
13511
  }
13340
13512
  async function* counted(incoming, length2, signal) {
13341
13513
  for (let left = length2; left > 0; ) {
13342
13514
  const data = await incoming.some(Math.min(left, 64 * 1024), signal);
13343
- if (data.length === 0) throw errno("EPROTO", "the body ended early");
13515
+ if (data.length === 0) throw errno2("EPROTO", "the body ended early");
13344
13516
  left -= data.length;
13345
13517
  yield data;
13346
13518
  }
@@ -13361,7 +13533,7 @@ function bodyOf(incoming, head, method, signal) {
13361
13533
  if (lengths.length === 0) return untilClose(incoming, signal);
13362
13534
  const length2 = lengths[0]?.trim() ?? "";
13363
13535
  if (!/^\d{1,15}$/.test(length2) || lengths.some((l) => l.trim() !== length2)) {
13364
- throw errno("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13536
+ throw errno2("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13365
13537
  }
13366
13538
  return counted(incoming, Number(length2), signal);
13367
13539
  }
@@ -13379,7 +13551,7 @@ var KernelLoopback = class {
13379
13551
  }
13380
13552
  async connect(url, port, signal) {
13381
13553
  if (url.protocol === "https:" || url.protocol === "wss:") {
13382
- throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13554
+ throw errno2("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13383
13555
  }
13384
13556
  signal.throwIfAborted();
13385
13557
  const socket = this.net.socket("inet");
@@ -13394,7 +13566,7 @@ var KernelLoopback = class {
13394
13566
  } catch (err) {
13395
13567
  socket.close();
13396
13568
  const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
13397
- throw refused2 ? errno("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13569
+ throw refused2 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13398
13570
  }
13399
13571
  signal.addEventListener("abort", () => socket.close(), { once: true });
13400
13572
  return socket;
@@ -13440,7 +13612,7 @@ var KernelLoopback = class {
13440
13612
  const incoming = new Incoming(socket);
13441
13613
  const head = await readHead(incoming, req.signal);
13442
13614
  if (head.status !== 101) {
13443
- throw errno(
13615
+ throw errno2(
13444
13616
  "EPROTO",
13445
13617
  `the server answered the upgrade with ${head.status}${head.statusText ? ` ${head.statusText}` : ""}`
13446
13618
  );
@@ -13448,10 +13620,10 @@ var KernelLoopback = class {
13448
13620
  const upgraded = fieldTokens(head.headers, "upgrade").includes("websocket") && fieldTokens(head.headers, "connection").includes("upgrade");
13449
13621
  const accept2 = fieldValues(head.headers, "sec-websocket-accept")[0];
13450
13622
  if (!upgraded || accept2 !== await acceptFor(key)) {
13451
- throw errno("EPROTO", "the server did not accept the WebSocket key");
13623
+ throw errno2("EPROTO", "the server did not accept the WebSocket key");
13452
13624
  }
13453
13625
  if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
13454
- throw errno("EPROTO", "the server offered an unsolicited extension");
13626
+ throw errno2("EPROTO", "the server offered an unsolicited extension");
13455
13627
  }
13456
13628
  const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
13457
13629
  return new LoopbackWebSocket(socket, incoming, protocol);
@@ -13469,7 +13641,7 @@ async function* closing(chunks2, socket) {
13469
13641
  yield* chunks2;
13470
13642
  } catch (err) {
13471
13643
  if (typeof err?.code === "string") throw err;
13472
- throw errno("EPROTO", err instanceof Error ? err.message : String(err));
13644
+ throw errno2("EPROTO", err instanceof Error ? err.message : String(err));
13473
13645
  } finally {
13474
13646
  socket.close();
13475
13647
  }
@@ -13598,7 +13770,7 @@ var LoopbackWebSocket = class {
13598
13770
  this.write(clientFrame(OP_CLOSE, payload));
13599
13771
  }
13600
13772
  send(data) {
13601
- if (this.sentClose) throw errno("EPIPE", "the websocket is closing");
13773
+ if (this.sentClose) throw errno2("EPIPE", "the websocket is closing");
13602
13774
  const text = typeof data === "string";
13603
13775
  const payload = text ? new TextEncoder().encode(data) : data;
13604
13776
  this.write(clientFrame(text ? OP_TEXT : OP_BINARY, payload));
@@ -14290,8 +14462,8 @@ function errnoOf(e) {
14290
14462
  const code = e?.code;
14291
14463
  return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
14292
14464
  }
14293
- function fail(errno2, text) {
14294
- return { ok: false, errno: errno2, message: text };
14465
+ function fail(errno3, text) {
14466
+ return { ok: false, errno: errno3, message: text };
14295
14467
  }
14296
14468
  var WsHandles = class {
14297
14469
  transport;
@@ -14565,8 +14737,8 @@ var HttpHandles = class {
14565
14737
  const status = e.status;
14566
14738
  if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
14567
14739
  const code = codeOf2(e);
14568
- const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14569
- return { ok: false, errno: errno2, message: text };
14740
+ const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14741
+ return { ok: false, errno: errno3, message: text };
14570
14742
  }
14571
14743
  entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
14572
14744
  return this.headOf(handle, req.url, {
@@ -15661,7 +15833,7 @@ var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
15661
15833
  function sendError(e) {
15662
15834
  if (e instanceof KernelError) return e;
15663
15835
  const code = e?.code;
15664
- return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
15836
+ return new KernelError(SEND_ERRORS.find((errno3) => errno3 === code) ?? "EHOSTUNREACH");
15665
15837
  }
15666
15838
  function sameAddr(a, b) {
15667
15839
  return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
@@ -15790,7 +15962,7 @@ var KernelDgram = class {
15790
15962
  }
15791
15963
  unreachable(error, from) {
15792
15964
  if (!this.peer || !sameAddr(this.peer, from)) return;
15793
- this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
15965
+ this.pending = UNREACHABLE.find((errno3) => errno3 === error) ?? "EHOSTUNREACH";
15794
15966
  this.changes.wake();
15795
15967
  }
15796
15968
  deliver(datagram2) {
@@ -17108,6 +17280,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
17108
17280
  "sig-mask",
17109
17281
  "sig-inherited",
17110
17282
  "sig-waiting",
17283
+ "sig-info",
17111
17284
  "sig-pause",
17112
17285
  ...SOCKET_OPS,
17113
17286
  ...EPOLL_OPS,
@@ -17121,6 +17294,7 @@ function isWasmSyscall(req) {
17121
17294
  return typeof op === "string" && SYSCALL_OPS.has(op);
17122
17295
  }
17123
17296
  var MAX_READ = 1024 * 1024;
17297
+ var O_NONBLOCK = 2048;
17124
17298
  var WRITE_ACCESS = 3;
17125
17299
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
17126
17300
  var DEFAULT_UMASK2 = 18;
@@ -17189,7 +17363,7 @@ var WasmProcess = class {
17189
17363
  this.children = new ChildTable(fds, options.spawner, options.forker);
17190
17364
  this.nodes = options.nodes ?? new VfsNodes(options.fs);
17191
17365
  if (!options.nodes) options.openFiles?.add(this.nodes);
17192
- this.children.onChildState = () => this.signal(SIG.CHLD);
17366
+ this.children.onChildState = (child) => this.signal(SIG.CHLD, child && this.childInfo(child));
17193
17367
  this.children.autoReap = () => this.reapsChildren();
17194
17368
  this.seedDl(options.dl);
17195
17369
  this.children.onReap = (pid2) => {
@@ -17206,10 +17380,43 @@ var WasmProcess = class {
17206
17380
  inheritable(fork = false) {
17207
17381
  return ((fork ? 0 : this.ignored) | this.inherited) & ~this.caught;
17208
17382
  }
17209
- signal(sig) {
17383
+ sigInfos = /* @__PURE__ */ new Map();
17384
+ signal(sig, info) {
17385
+ const pending = ((this.options.pendingBits?.() ?? 0) & sigbit(sig)) !== 0;
17386
+ const outcome = this.signalOutcome(sig, info);
17387
+ if (outcome === "deliver" && !(pending && this.sigInfos.has(`0:${sig}`))) {
17388
+ this.sigInfos.set(`0:${sig}`, info ?? KERNEL_SIGINFO);
17389
+ }
17390
+ return outcome;
17391
+ }
17392
+ async threadKill(tid, sig) {
17393
+ const info = await this.threadSender(sig);
17394
+ if (this.options.threadKill?.(tid, sig)) this.sigInfos.set(`${tid}:${sig}`, info);
17395
+ else this.options.raise?.(sig, info);
17396
+ }
17397
+ async threadSender(sig) {
17398
+ const pid = (await this.options.identity?.())?.pid ?? this.pid;
17399
+ const code = sig === SIG.PIPE ? SI.USER : SI.TKILL;
17400
+ return { code, pid, uid: this.cred.ruid, status: 0 };
17401
+ }
17402
+ childInfo(child) {
17403
+ const code = child.state === "stopped" ? CLD.STOPPED : child.state === "continued" ? CLD.CONTINUED : child.termsig ? CLD.KILLED : CLD.EXITED;
17404
+ return { code, pid: child.pid, uid: child.uid ?? this.cred.ruid, status: child.status };
17405
+ }
17406
+ takeSigInfo(sig, tid) {
17407
+ for (const key of [`${tid}:${sig}`, `0:${sig}`]) {
17408
+ const info = this.sigInfos.get(key);
17409
+ if (info) {
17410
+ this.sigInfos.delete(key);
17411
+ return info;
17412
+ }
17413
+ }
17414
+ return null;
17415
+ }
17416
+ signalOutcome(sig, info) {
17210
17417
  if (this.execChild !== void 0) {
17211
17418
  if (sig === SIG.CONT) this.cont();
17212
- void Promise.resolve(this.options.kill?.(this.execChild, sig)).catch(() => void 0);
17419
+ void Promise.resolve(this.options.kill?.(this.execChild, sig, info)).catch(() => void 0);
17213
17420
  if (sig !== SIG.KILL) return "forward";
17214
17421
  if (!this.options.writesBack?.(this.execChild)) return "terminate";
17215
17422
  this.wake?.();
@@ -17585,7 +17792,7 @@ var WasmProcess = class {
17585
17792
  this.options.hasPending?.() ? AbortSignal.abort() : this.cancelSignal(cancelled)
17586
17793
  );
17587
17794
  }
17588
- async openVfs(req) {
17795
+ async openVfs(req, cancelled) {
17589
17796
  if (inProc(req.path)) return this.openProc(req, req.path);
17590
17797
  const device = req.orphan ? void 0 : deviceAt(req.path);
17591
17798
  if (device) return this.openDevice(req, device);
@@ -17596,6 +17803,10 @@ var WasmProcess = class {
17596
17803
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
17597
17804
  if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
17598
17805
  await this.mayOpen(req);
17806
+ if (req.fifo && !req.exclusive) {
17807
+ const opened2 = await this.openFifo(req, cancelled);
17808
+ if (opened2 !== void 0) return opened2;
17809
+ }
17599
17810
  const marked = await this.markedPath(req);
17600
17811
  await this.sourceOpen(marked === void 0 ? req : { ...req, path: marked });
17601
17812
  const fs = marked === void 0 ? this.options.fs : this.options.noLinks;
@@ -17637,6 +17848,19 @@ var WasmProcess = class {
17637
17848
  }
17638
17849
  return fd;
17639
17850
  }
17851
+ async openFifo(req, cancelled) {
17852
+ const fifos = this.options.fifos;
17853
+ const path = await this.nodes.targetKey(req.path);
17854
+ const st = await this.heldFs().stat(path);
17855
+ if (!st.isFifo) return void 0;
17856
+ if (!fifos) throw new KernelError("ENXIO");
17857
+ const access2 = openAccess(req.flags);
17858
+ const nonblock = (req.flags & O_NONBLOCK) !== 0;
17859
+ const blocks = !nonblock && access2 !== "both";
17860
+ const signal = blocks ? this.blockingSignal(cancelled) : cancelled;
17861
+ const end = await fifos.open(`${st.dev ?? 0}:${st.ino}`, path, access2, nonblock, signal);
17862
+ return this.fds.install(end, 3);
17863
+ }
17640
17864
  openDevice(req, device) {
17641
17865
  if (req.exclusive) throw Object.assign(new Error(req.path), { code: "EEXIST" });
17642
17866
  const access2 = req.flags & WRITE_ACCESS;
@@ -17836,7 +18060,7 @@ var WasmProcess = class {
17836
18060
  case "fd-poll":
17837
18061
  return { ok: true, kind: "json", json: pollFile(this.fds.get(req.fd).file) };
17838
18062
  case "fd-open-vfs":
17839
- return { ok: true, kind: "json", json: await this.openVfs(req) };
18063
+ return { ok: true, kind: "json", json: await this.openVfs(req, cancelled) };
17840
18064
  case "fd-info":
17841
18065
  return { ok: true, kind: "json", json: this.fdInfo(req.fd) };
17842
18066
  case "fd-list":
@@ -18270,8 +18494,10 @@ var WasmProcess = class {
18270
18494
  case "sig-pause":
18271
18495
  return this.pause(cancelled);
18272
18496
  case "thread-kill":
18273
- if (!this.options.threadKill?.(req.tid, req.sig)) this.options.raise?.(req.sig);
18497
+ await this.threadKill(req.tid, req.sig);
18274
18498
  return { ok: true, kind: "void" };
18499
+ case "sig-info":
18500
+ return { ok: true, kind: "json", json: this.takeSigInfo(req.sig, req.tid ?? 0) };
18275
18501
  case "proc-captured":
18276
18502
  return { ok: true, kind: "bytes", bytes: this.children.captured(req.pid, req.slot) };
18277
18503
  case "proc-sudo":
@@ -18494,7 +18720,8 @@ function inheritedFds(fds) {
18494
18720
  ...kind === "device" && meta && "device" in meta ? { device: meta } : {},
18495
18721
  ...flags2 !== void 0 ? { flags: flags2 } : {},
18496
18722
  ...fds.closesOnExec(fd) ? { cloexec: true } : {},
18497
- ...kind === "stream" ? { desc: descId(open) } : {}
18723
+ ...kind === "stream" ? { desc: descId(open) } : {},
18724
+ ...open.file.fifo ? { fifo: open.file.fifo } : {}
18498
18725
  };
18499
18726
  });
18500
18727
  }
@@ -18700,6 +18927,7 @@ function processOptions(opts, header4, hooks, created3) {
18700
18927
  net: opts.net,
18701
18928
  http: opts.http,
18702
18929
  locks: opts.locks,
18930
+ fifos: opts.fifos,
18703
18931
  ...opts.sems ? { sems: opts.sems } : {},
18704
18932
  onReap: opts.onReap,
18705
18933
  resolver: opts.resolver,
@@ -18750,7 +18978,7 @@ function spawnWasmProcess(opts) {
18750
18978
  opts,
18751
18979
  header4,
18752
18980
  {
18753
- raise: (sig) => signal(sig),
18981
+ raise: (sig, info) => signal(sig, info),
18754
18982
  threadKill: (tid, sig) => killThread(threadSignals.get(tid), process2.signalMasks().caught, sig),
18755
18983
  unblockedThread: (sig) => unblockedThread(threadSignals, sig),
18756
18984
  ...opts.program.abi === "js" ? {
@@ -18872,8 +19100,9 @@ function spawnWasmProcess(opts) {
18872
19100
  if (opts.program.abi !== "wasi" || done4) finish(code, sig);
18873
19101
  else dying.start(code, sig, header4, process2, () => finish(code, sig));
18874
19102
  };
18875
- const signal = (sig) => {
18876
- if (process2.signal(sig) === "terminate") terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
19103
+ const signal = (sig, info) => {
19104
+ if (process2.signal(sig, info) === "terminate")
19105
+ terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
18877
19106
  };
18878
19107
  const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
18879
19108
  return {
@@ -19043,14 +19272,14 @@ var JobTable = class {
19043
19272
  this.foreground.set(tty, member.pgid);
19044
19273
  return true;
19045
19274
  }
19046
- killGroup(pgid, sig, may = () => true) {
19275
+ killGroup(pgid, sig, may = () => true, info) {
19047
19276
  const group = [...this.members.values()].filter((m) => m.pgid === pgid);
19048
19277
  const targets = group.filter((m) => may(m.pid));
19049
19278
  if (targets.length === 0 && group.length > 0) throw new KernelError("EPERM");
19050
19279
  const pids = new Set(targets.map((m) => m.pid));
19051
19280
  if (sig !== 0) {
19052
19281
  for (const m of targets)
19053
- if (m.execParent === void 0 || !pids.has(m.execParent)) m.signal(sig);
19282
+ if (m.execParent === void 0 || !pids.has(m.execParent)) m.signal(sig, info);
19054
19283
  }
19055
19284
  return targets.length > 0;
19056
19285
  }
@@ -20637,9 +20866,9 @@ var HostfsClient = class {
20637
20866
  throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
20638
20867
  return this.send(path, init, false, true);
20639
20868
  }
20640
- const errno2 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20869
+ const errno3 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20641
20870
  const body = await response.json().catch(() => ({}));
20642
- throw fsError2(errno2, typeof body.message === "string" ? body.message : errno2);
20871
+ throw fsError2(errno3, typeof body.message === "string" ? body.message : errno3);
20643
20872
  }
20644
20873
  async call(op, body = {}, handle = false) {
20645
20874
  const response = await this.send(
@@ -21796,8 +22025,8 @@ var RULE = new RegExp(
21796
22025
  var TERM = /^[A-Za-z0-9._+-]+$/;
21797
22026
  var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
21798
22027
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
21799
- function failed2(errno2, error) {
21800
- return { error, errno: errno2 };
22028
+ function failed2(errno3, error) {
22029
+ return { error, errno: errno3 };
21801
22030
  }
21802
22031
  function unescaped(double) {
21803
22032
  return double.replace(/\\(["\\$`])/g, "$1");
@@ -22389,7 +22618,8 @@ function childHandle(handle) {
22389
22618
  pid: handle.pid,
22390
22619
  exited: handle.exited,
22391
22620
  termsig: handle.termsig,
22392
- onState: (listener) => handle.onState(listener)
22621
+ onState: (listener) => handle.onState(listener),
22622
+ uid: () => handle.cred?.().ruid
22393
22623
  };
22394
22624
  }
22395
22625
  function concat7(chunks2) {
@@ -22453,6 +22683,7 @@ var Launcher = class {
22453
22683
  sudoer;
22454
22684
  jobs = new JobTable();
22455
22685
  locks = new LockTable();
22686
+ fifos = new FifoTable();
22456
22687
  sems = new SemTable();
22457
22688
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
22458
22689
  ptys = new PtyTable(
@@ -23427,7 +23658,7 @@ var Launcher = class {
23427
23658
  onError: req.report,
23428
23659
  spawner: this.spawner(pid, req.report),
23429
23660
  forker: this.forker(pid, req),
23430
- kill: (target, sig) => this.kill(target, sig, this.credOf(pid), pid),
23661
+ kill: (target, sig, info) => this.kill(target, sig, this.credOf(pid), pid, info),
23431
23662
  writesBack: (target) => this.processes.get(target)?.writesBack() === true,
23432
23663
  processes: () => ({
23433
23664
  boot: this.boot,
@@ -23450,6 +23681,7 @@ var Launcher = class {
23450
23681
  net: this.net,
23451
23682
  http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
23452
23683
  locks: this.locks,
23684
+ fifos: this.fifos,
23453
23685
  sems: this.sems,
23454
23686
  resolver: this.resolver,
23455
23687
  onReap: (child) => this.reaped(child, pid),
@@ -23462,7 +23694,7 @@ var Launcher = class {
23462
23694
  this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
23463
23695
  this.marks(pid, req);
23464
23696
  if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
23465
- this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
23697
+ this.jobs.add(pid, req.ppid, (sig, info) => handle.signal(sig, info), terminal);
23466
23698
  if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
23467
23699
  if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
23468
23700
  if (req.group === "lead") this.jobs.lead(pid);
@@ -23843,21 +24075,26 @@ var Launcher = class {
23843
24075
  ignoredBy(pid, fork = false) {
23844
24076
  return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
23845
24077
  }
23846
- kill(pid, sig, sender, from) {
24078
+ kill(pid, sig, sender, from, forwarded) {
24079
+ const info = forwarded ?? this.senderInfo(sender, from);
23847
24080
  const session = from === void 0 ? void 0 : this.jobs.sidOf(from);
23848
24081
  const may = (target) => !sender || maySignal(sender, this.credOf(target)) || sig === SIG.CONT && session !== void 0 && this.jobs.sidOf(target) === session || from !== void 0 && this.imageOf(from) === this.imageOf(target) || from !== void 0 && this.granted.get(this.jobs.shown(target)) === from || from !== void 0 && this.granted.get(this.jobs.pgidOf(target) ?? 0) === from;
23849
24082
  if (pid === -1) {
23850
24083
  const sender2 = from === void 0 ? void 0 : this.imageOf(from);
23851
- return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may);
24084
+ return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may, info);
23852
24085
  }
23853
- if (pid < 0) return this.jobs.killGroup(-pid, sig, (member) => may(this.imageOf(member)));
24086
+ if (pid < 0) return this.jobs.killGroup(-pid, sig, (member) => may(this.imageOf(member)), info);
23854
24087
  const handle = this.processes.get(pid);
23855
24088
  if (!handle) return false;
23856
24089
  if (!may(this.imageOf(pid))) throw fsError("EPERM", `pid ${pid}`);
23857
- if (sig !== 0) handle.signal(sig);
24090
+ if (sig !== 0) handle.signal(sig, info);
23858
24091
  return true;
23859
24092
  }
23860
- killAll(sig, other, may) {
24093
+ senderInfo(sender, from) {
24094
+ if (from === void 0) return void 0;
24095
+ return { code: SI.USER, pid: this.jobs.shown(from), uid: sender?.ruid ?? 0, status: 0 };
24096
+ }
24097
+ killAll(sig, other, may, info) {
23861
24098
  const candidates = [...this.processes].filter(([pid]) => pid !== 1 && other(pid));
23862
24099
  const targets = candidates.filter(([pid]) => may(this.imageOf(pid)));
23863
24100
  if (targets.length === 0 && candidates.length > 0) throw fsError("EPERM", "kill -1");
@@ -23865,7 +24102,7 @@ var Launcher = class {
23865
24102
  const parents = new Map(this.jobs.list().map((m) => [m.pid, m.execParent]));
23866
24103
  for (const [pid, handle] of targets) {
23867
24104
  const parent = parents.get(pid);
23868
- if (sig !== 0 && (parent === void 0 || !pids.has(parent))) handle.signal(sig);
24105
+ if (sig !== 0 && (parent === void 0 || !pids.has(parent))) handle.signal(sig, info);
23869
24106
  }
23870
24107
  return targets.length > 0;
23871
24108
  }