@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.
@@ -988,6 +988,7 @@ var S_IFDIR = 16384;
988
988
  var S_IFREG = 32768;
989
989
  var S_IFLNK = 40960;
990
990
  var S_IFSOCK = 49152;
991
+ var S_IFIFO = 4096;
991
992
  var PERM_MASK = 4095;
992
993
  var S_ISGID2 = 1024;
993
994
  var READ_ATTEMPTS = 3;
@@ -1271,7 +1272,10 @@ var OpfsFs = class {
1271
1272
  }
1272
1273
  async stampNew(path, owner, directory) {
1273
1274
  const owned4 = await this.newFields(path, owner, directory);
1274
- const fields = owner?.socket && !directory ? { ...owned4, socket: true } : owned4;
1275
+ if (owner?.socket && owner.fifo) throw new Error("a new node is a socket or a FIFO, not both");
1276
+ const kind = directory ? void 0 : owner?.socket ? "socket" : owner?.fifo ? "fifo" : void 0;
1277
+ const unique = kind === "fifo" ? { ino: inodeOf(`${path}\0${crypto.randomUUID()}`) } : {};
1278
+ const fields = kind ? { ...owned4, ...unique, [kind]: true } : owned4;
1275
1279
  if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
1276
1280
  }
1277
1281
  guarded = [];
@@ -1513,7 +1517,7 @@ var OpfsFs = class {
1513
1517
  }
1514
1518
  mode(path, directory, meta) {
1515
1519
  const fallback = directory || EXECUTABLE.test(path) ? 493 : 420;
1516
- const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : S_IFREG;
1520
+ const type = directory ? S_IFDIR : meta?.socket ? S_IFSOCK : meta?.fifo ? S_IFIFO : S_IFREG;
1517
1521
  return type | (meta?.mode ?? fallback);
1518
1522
  }
1519
1523
  id = crypto.randomUUID();
@@ -1614,11 +1618,13 @@ var OpfsFs = class {
1614
1618
  const kept = meta?.mtimeMs !== void 0 && meta.mtimeFor === modified ? meta.mtimeMs : modified;
1615
1619
  const mtime = touched ?? kept;
1616
1620
  const socket = !directory && meta?.socket === true;
1621
+ const fifo = !directory && meta?.fifo === true;
1617
1622
  return {
1618
- isFile: !directory && !socket,
1623
+ isFile: !directory && !socket && !fifo,
1619
1624
  isDirectory: directory,
1620
1625
  isSymbolicLink: false,
1621
1626
  ...socket ? { isSocket: true } : {},
1627
+ ...fifo ? { isFifo: true } : {},
1622
1628
  size: file?.size ?? 0,
1623
1629
  mode: this.mode(path, directory, meta),
1624
1630
  mtime: new Date(mtime),
@@ -3310,8 +3316,8 @@ async function access(fs, cred, path, want, options = {}) {
3310
3316
  if (await present(fs, walked.path, false)) return { ...walked, denied: walked.path };
3311
3317
  return { ...walked, missing: true };
3312
3318
  }
3313
- function refused(path, errno2 = "EACCES") {
3314
- return fsError(errno2, path);
3319
+ function refused(path, errno3 = "EACCES") {
3320
+ return fsError(errno3, path);
3315
3321
  }
3316
3322
 
3317
3323
  // src/fs/dac.ts
@@ -3371,9 +3377,9 @@ var Created = class {
3371
3377
  function linked(g, options) {
3372
3378
  return g.links === void 0 ? options : { ...options, links: g.links };
3373
3379
  }
3374
- function deny(g, op, path, errno2 = "EACCES") {
3380
+ function deny(g, op, path, errno3 = "EACCES") {
3375
3381
  const tag = g.tag === void 0 ? {} : { tag: g.tag };
3376
- g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno2, ...tag });
3382
+ g.dac.denied({ pid: g.pid, uid: g.cred.euid, op, path, errno: errno3, ...tag });
3377
3383
  }
3378
3384
  var TTY_MODE = 400;
3379
3385
  function ttyOpenable(g, tty) {
@@ -4086,7 +4092,7 @@ var WASI_SIGNAL_TO_POSIX = Object.fromEntries(
4086
4092
 
4087
4093
  // src/process/wasi-errno.ts
4088
4094
  var WASI_ERRNO = {
4089
- ...Object.fromEntries(Object.entries(E).map(([name2, errno2]) => [`E${name2}`, errno2])),
4095
+ ...Object.fromEntries(Object.entries(E).map(([name2, errno3]) => [`E${name2}`, errno3])),
4090
4096
  EWOULDBLOCK: E.AGAIN,
4091
4097
  ENOTSUP: 138,
4092
4098
  EOPNOTSUPP: 138,
@@ -4326,7 +4332,7 @@ function dialError(e, timedOut, closed) {
4326
4332
  if (timedOut) return new KernelError("ETIMEDOUT");
4327
4333
  if (closed) return new KernelError("ECONNABORTED");
4328
4334
  const code = e?.code;
4329
- const known = DIAL_ERRORS.find((errno2) => errno2 === code);
4335
+ const known = DIAL_ERRORS.find((errno3) => errno3 === code);
4330
4336
  return new KernelError(known ?? "EHOSTUNREACH");
4331
4337
  }
4332
4338
  function isLoopback(host) {
@@ -4962,6 +4968,14 @@ var SIGNAL_BY_NAME = {
4962
4968
  SIGSTOP: SIG.STOP,
4963
4969
  SIGCONT: SIG.CONT
4964
4970
  };
4971
+ var SI = { USER: 0, QUEUE: -1, TIMER: -2, TKILL: -6, KERNEL: 128 };
4972
+ var CLD = { EXITED: 1, KILLED: 2, DUMPED: 3, STOPPED: 5, CONTINUED: 6 };
4973
+ var KERNEL_SIGINFO = Object.freeze({
4974
+ code: SI.KERNEL,
4975
+ pid: 0,
4976
+ uid: 0,
4977
+ status: 0
4978
+ });
4965
4979
 
4966
4980
  // src/body-idle.ts
4967
4981
  var BODY_IDLE_MS = 5 * 60 * 1e3;
@@ -6213,7 +6227,7 @@ function satisfies(version, range2) {
6213
6227
  }
6214
6228
 
6215
6229
  // src/version.ts
6216
- var KERNEL_VERSION = true ? "1.113.0" : "0.0.0-dev";
6230
+ var KERNEL_VERSION = true ? "1.115.0" : "0.0.0-dev";
6217
6231
  var OS_RELEASE = "6.0.0-slicc";
6218
6232
  function procVersion() {
6219
6233
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -9089,8 +9103,16 @@ var ChildTable = class {
9089
9103
  void handle.exited.then((code) => {
9090
9104
  child.code = code;
9091
9105
  this.watchers.delete(handle.pid);
9106
+ const termsig = handle.termsig?.();
9092
9107
  if (!this.kept.delete(handle.pid) && this.autoReap?.()) this.reap(handle.pid, code);
9093
- this.onChildState?.();
9108
+ const uid = handle.uid?.();
9109
+ this.onChildState?.({
9110
+ pid: handle.pid,
9111
+ state: "exited",
9112
+ status: termsig ?? code,
9113
+ termsig,
9114
+ uid
9115
+ });
9094
9116
  });
9095
9117
  handle.onState?.((state, sig) => {
9096
9118
  child.stopReport = state === "stopped" ? sig : void 0;
@@ -9100,7 +9122,7 @@ var ChildTable = class {
9100
9122
  const waiters = this.stateChanged;
9101
9123
  this.stateChanged = [];
9102
9124
  for (const wake of waiters) wake();
9103
- this.onChildState?.();
9125
+ this.onChildState?.({ pid: handle.pid, state, status: sig, uid: handle.uid?.() });
9104
9126
  });
9105
9127
  this.children.set(handle.pid, child);
9106
9128
  return handle.pid;
@@ -9430,6 +9452,139 @@ var TicketBook = class {
9430
9452
  }
9431
9453
  };
9432
9454
 
9455
+ // src/kernel/fifo.ts
9456
+ function errno(e) {
9457
+ return e instanceof KernelError ? e : new KernelError(e.code ?? "EIO");
9458
+ }
9459
+ var FifoTable = class {
9460
+ fifos = /* @__PURE__ */ new Map();
9461
+ size() {
9462
+ return this.fifos.size;
9463
+ }
9464
+ async open(key, path, access2, nonblock, signal) {
9465
+ const fifo = this.entry(key);
9466
+ if (access2 === "write" && nonblock && fifo.readers === 0) {
9467
+ this.drop(key, fifo);
9468
+ throw new KernelError("ENXIO");
9469
+ }
9470
+ const reads = access2 !== "write";
9471
+ const writes = access2 !== "read";
9472
+ const seen = { readOpens: fifo.readOpens, writeOpens: fifo.writeOpens };
9473
+ if (reads) this.count(fifo, "readers", 1);
9474
+ if (writes) this.count(fifo, "writers", 1);
9475
+ this.notify(fifo);
9476
+ try {
9477
+ if (!nonblock && access2 === "read") {
9478
+ while (fifo.writers === 0 && fifo.writeOpens === seen.writeOpens) {
9479
+ await this.changed(fifo, signal);
9480
+ }
9481
+ }
9482
+ if (!nonblock && access2 === "write") {
9483
+ while (fifo.readers === 0 && fifo.readOpens === seen.readOpens) {
9484
+ await this.changed(fifo, signal);
9485
+ }
9486
+ }
9487
+ } catch (e) {
9488
+ this.release(key, fifo, reads, writes);
9489
+ throw errno(e);
9490
+ }
9491
+ return this.end(key, path, fifo, reads, writes);
9492
+ }
9493
+ entry(key) {
9494
+ let fifo = this.fifos.get(key);
9495
+ if (!fifo) {
9496
+ fifo = {
9497
+ pipe: new KernelPipe(),
9498
+ readers: 0,
9499
+ writers: 0,
9500
+ readOpens: 0,
9501
+ writeOpens: 0,
9502
+ waiters: []
9503
+ };
9504
+ this.fifos.set(key, fifo);
9505
+ }
9506
+ return fifo;
9507
+ }
9508
+ count(fifo, side, by) {
9509
+ fifo[side] += by;
9510
+ if (side === "readers") {
9511
+ if (by > 0) {
9512
+ fifo.readOpens += 1;
9513
+ fifo.pipe.openRead();
9514
+ } else fifo.pipe.closeRead();
9515
+ } else if (by > 0) {
9516
+ fifo.writeOpens += 1;
9517
+ fifo.pipe.openWrite();
9518
+ } else fifo.pipe.closeWrite();
9519
+ }
9520
+ notify(fifo) {
9521
+ const waiters = fifo.waiters;
9522
+ fifo.waiters = [];
9523
+ for (const wake of waiters) wake();
9524
+ }
9525
+ changed(fifo, signal) {
9526
+ if (signal.aborted) return Promise.reject(new KernelError("EINTR"));
9527
+ return new Promise((resolve2, reject) => {
9528
+ const onAbort = () => {
9529
+ fifo.waiters = fifo.waiters.filter((w) => w !== wake);
9530
+ reject(new KernelError("EINTR"));
9531
+ };
9532
+ const wake = () => {
9533
+ signal.removeEventListener("abort", onAbort);
9534
+ resolve2();
9535
+ };
9536
+ fifo.waiters.push(wake);
9537
+ signal.addEventListener("abort", onAbort, { once: true });
9538
+ });
9539
+ }
9540
+ release(key, fifo, reads, writes) {
9541
+ if (reads) this.count(fifo, "readers", -1);
9542
+ if (writes) this.count(fifo, "writers", -1);
9543
+ this.notify(fifo);
9544
+ this.drop(key, fifo);
9545
+ }
9546
+ drop(key, fifo) {
9547
+ const idle = fifo.readers === 0 && fifo.writers === 0 && fifo.waiters.length === 0;
9548
+ if (idle && this.fifos.get(key) === fifo) this.fifos.delete(key);
9549
+ }
9550
+ end(key, path, fifo, reads, writes) {
9551
+ const { pipe } = fifo;
9552
+ let open = true;
9553
+ return new OpenFile({
9554
+ fifo: path,
9555
+ ...reads ? {
9556
+ read: async (max, signal) => {
9557
+ try {
9558
+ return await pipe.read(max, signal);
9559
+ } catch (e) {
9560
+ throw errno(e);
9561
+ }
9562
+ }
9563
+ } : {},
9564
+ ...writes ? {
9565
+ write: async (bytes, signal) => {
9566
+ try {
9567
+ return await pipe.write(bytes, signal);
9568
+ } catch (e) {
9569
+ throw errno(e);
9570
+ }
9571
+ }
9572
+ } : {},
9573
+ close: () => {
9574
+ if (!open) return;
9575
+ open = false;
9576
+ this.release(key, fifo, reads, writes);
9577
+ },
9578
+ poll: () => ({
9579
+ readable: reads && pipe.readReady,
9580
+ writable: writes && pipe.writeReady,
9581
+ hangup: reads ? pipe.writersGone : pipe.readersGone
9582
+ }),
9583
+ changed: (signal) => pipe.changed(signal)
9584
+ });
9585
+ }
9586
+ };
9587
+
9433
9588
  // src/mount/protocol.ts
9434
9589
  var DRIVER_PROTOCOL = [1, 2];
9435
9590
  function driverVersionError(theirs) {
@@ -10290,6 +10445,7 @@ var MountFs = class _MountFs {
10290
10445
  }
10291
10446
  const { mount, rel: rel2 } = found;
10292
10447
  this.writable(mount, real);
10448
+ if (owner?.fifo) throw errnoError("EPERM", `${real}: this mount has no FIFOs`);
10293
10449
  const bytes = typeof content === "string" ? new TextEncoder().encode(content) : content;
10294
10450
  if (mount.maxFile > 0 && bytes.length > mount.maxFile) {
10295
10451
  throw errnoError(
@@ -10895,6 +11051,7 @@ var SYNC_FS_OPS = [
10895
11051
  "statfs",
10896
11052
  "hold",
10897
11053
  "create",
11054
+ "mkfifo",
10898
11055
  "kept",
10899
11056
  "pread",
10900
11057
  "pwrite",
@@ -10927,6 +11084,7 @@ function statJson(s) {
10927
11084
  isFile: s.isFile,
10928
11085
  isSymbolicLink: s.isSymbolicLink,
10929
11086
  ...s.isSocket ? { isSocket: true } : {},
11087
+ ...s.isFifo ? { isFifo: true } : {},
10930
11088
  size: s.size,
10931
11089
  mode: s.mode,
10932
11090
  mtimeMs: s.mtime.getTime(),
@@ -11076,6 +11234,12 @@ async function run(entry, path, req) {
11076
11234
  case "symlink":
11077
11235
  await fs.symlink(req.arg2 ?? "", path, ownerFor2(entry));
11078
11236
  return done;
11237
+ case "mkfifo": {
11238
+ const owner = ownerFor2(entry, req.mode ?? 438) ?? { uid: 0, gid: 0 };
11239
+ await createExclusive(fs, path, { ...owner, fifo: true });
11240
+ entry.fresh?.(path);
11241
+ return done;
11242
+ }
11079
11243
  case "create":
11080
11244
  await createExclusive(fs, path, ownerFor2(entry, req.mode ?? 438));
11081
11245
  if (req.opening) entry.created?.add(path);
@@ -11154,9 +11318,10 @@ async function guard(g, path, req, cwd) {
11154
11318
  return { path: await walkSafe(g, path, false) };
11155
11319
  }
11156
11320
  case "create":
11321
+ case "mkfifo":
11157
11322
  case "symlink":
11158
11323
  await inParent(g, op, path);
11159
- return { path: await walkSafe(g, path, op === "create") };
11324
+ return { path: await walkSafe(g, path, op !== "symlink") };
11160
11325
  case "unlink":
11161
11326
  case "rmdir": {
11162
11327
  await inParent(g, op, path, true);
@@ -11244,6 +11409,7 @@ async function accessOp(entry, path, req) {
11244
11409
  var CHANGING = /* @__PURE__ */ new Set([
11245
11410
  "mkdir",
11246
11411
  "create",
11412
+ "mkfifo",
11247
11413
  "symlink",
11248
11414
  "unlink",
11249
11415
  "rmdir",
@@ -11438,7 +11604,13 @@ async function guardAndResolve(entry, path, req) {
11438
11604
  };
11439
11605
  }
11440
11606
  var REMOVALS = /* @__PURE__ */ new Set(["unlink", "rmdir", "rm"]);
11441
- var CREATIONS = /* @__PURE__ */ new Set(["write", "mkdir", "symlink", "create"]);
11607
+ var CREATIONS = /* @__PURE__ */ new Set([
11608
+ "write",
11609
+ "mkdir",
11610
+ "symlink",
11611
+ "create",
11612
+ "mkfifo"
11613
+ ]);
11442
11614
  var NAMING = /* @__PURE__ */ new Set(["link", "rename"]);
11443
11615
  async function newDevName(entry, path, req) {
11444
11616
  const named = NAMING.has(req.op);
@@ -13185,16 +13357,16 @@ var TOKEN3 = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
13185
13357
  var SAFE_VALUE = /^[^\r\n\0]*$/;
13186
13358
  var CLOSE_WAIT_MS3 = 5e3;
13187
13359
  var MAX_UNREAD = 16 * 1024 * 1024;
13188
- function errno(code, message3) {
13360
+ function errno2(code, message3) {
13189
13361
  return Object.assign(new Error(`${code}: ${message3}`), { code });
13190
13362
  }
13191
13363
  function requestHead(method, url, headers, extra, first = []) {
13192
- if (!TOKEN3.test(method)) throw errno("EINVAL", `method ${method}`);
13364
+ if (!TOKEN3.test(method)) throw errno2("EINVAL", `method ${method}`);
13193
13365
  const lines2 = [`${method} ${url.pathname}${url.search} HTTP/1.1`, `host: ${url.host}`];
13194
13366
  for (const [name2, value2] of first) lines2.push(`${name2}: ${value2}`);
13195
13367
  for (const [name2, value2] of headers) {
13196
13368
  if (OWN_HEADERS.has(name2.toLowerCase())) continue;
13197
- if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno("EINVAL", `header ${name2}`);
13369
+ if (!TOKEN3.test(name2) || !SAFE_VALUE.test(value2)) throw errno2("EINVAL", `header ${name2}`);
13198
13370
  lines2.push(`${name2}: ${value2}`);
13199
13371
  }
13200
13372
  for (const [name2, value2] of extra) lines2.push(`${name2}: ${value2}`);
@@ -13205,7 +13377,7 @@ function requestHead(method, url, headers, extra, first = []) {
13205
13377
  function parseHead(bytes) {
13206
13378
  const [statusLine = "", ...lines2] = latin1(bytes).split(/\r?\n/);
13207
13379
  const match = /^HTTP\/1\.[01] (\d{3})(?: (.*))?$/.exec(statusLine);
13208
- if (!match) throw errno("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13380
+ if (!match) throw errno2("EPROTO", `not an HTTP/1.x response: ${statusLine.slice(0, 80)}`);
13209
13381
  const headers = [];
13210
13382
  for (const line of lines2) {
13211
13383
  const colon = line.indexOf(":");
@@ -13220,9 +13392,9 @@ async function readHead(incoming, signal) {
13220
13392
  raw = await incoming.head(MAX_HEAD2, signal);
13221
13393
  } catch (err) {
13222
13394
  if (err instanceof KernelError) throw err;
13223
- throw errno("EPROTO", "the response head is malformed or too large");
13395
+ throw errno2("EPROTO", "the response head is malformed or too large");
13224
13396
  }
13225
- if (!raw) throw errno("ECONNRESET", "the connection closed before a response");
13397
+ if (!raw) throw errno2("ECONNRESET", "the connection closed before a response");
13226
13398
  const head = parseHead(raw);
13227
13399
  if (head.status < 100 || head.status >= 200 || head.status === 101) return head;
13228
13400
  }
@@ -13231,20 +13403,20 @@ async function* chunked(incoming, signal) {
13231
13403
  for (; ; ) {
13232
13404
  const line = await incoming.line(4096, signal);
13233
13405
  const size = /^([0-9A-Fa-f]{1,12})[ \t]*(;.*)?$/.exec(line);
13234
- if (!size) throw errno("EPROTO", "a malformed chunk size");
13406
+ if (!size) throw errno2("EPROTO", "a malformed chunk size");
13235
13407
  const n = Number.parseInt(size[1], 16);
13236
13408
  if (n === 0) {
13237
13409
  while (await incoming.line(MAX_HEAD2, signal) !== "") ;
13238
13410
  return;
13239
13411
  }
13240
13412
  yield await incoming.exactly(n, signal);
13241
- if (await incoming.line(2, signal) !== "") throw errno("EPROTO", "a malformed chunk");
13413
+ if (await incoming.line(2, signal) !== "") throw errno2("EPROTO", "a malformed chunk");
13242
13414
  }
13243
13415
  }
13244
13416
  async function* counted(incoming, length2, signal) {
13245
13417
  for (let left = length2; left > 0; ) {
13246
13418
  const data = await incoming.some(Math.min(left, 64 * 1024), signal);
13247
- if (data.length === 0) throw errno("EPROTO", "the body ended early");
13419
+ if (data.length === 0) throw errno2("EPROTO", "the body ended early");
13248
13420
  left -= data.length;
13249
13421
  yield data;
13250
13422
  }
@@ -13265,7 +13437,7 @@ function bodyOf(incoming, head, method, signal) {
13265
13437
  if (lengths.length === 0) return untilClose(incoming, signal);
13266
13438
  const length2 = lengths[0]?.trim() ?? "";
13267
13439
  if (!/^\d{1,15}$/.test(length2) || lengths.some((l) => l.trim() !== length2)) {
13268
- throw errno("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13440
+ throw errno2("EPROTO", `a malformed Content-Length: ${lengths.join(", ")}`);
13269
13441
  }
13270
13442
  return counted(incoming, Number(length2), signal);
13271
13443
  }
@@ -13283,7 +13455,7 @@ var KernelLoopback = class {
13283
13455
  }
13284
13456
  async connect(url, port, signal) {
13285
13457
  if (url.protocol === "https:" || url.protocol === "wss:") {
13286
- throw errno("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13458
+ throw errno2("ENOTSUP", `TLS to the kernel's loopback is not supported: ${url.origin}`);
13287
13459
  }
13288
13460
  signal.throwIfAborted();
13289
13461
  const socket = this.net.socket("inet");
@@ -13298,7 +13470,7 @@ var KernelLoopback = class {
13298
13470
  } catch (err) {
13299
13471
  socket.close();
13300
13472
  const refused2 = err instanceof KernelError && err.code === "ECONNREFUSED";
13301
- throw refused2 ? errno("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13473
+ throw refused2 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
13302
13474
  }
13303
13475
  signal.addEventListener("abort", () => socket.close(), { once: true });
13304
13476
  return socket;
@@ -13344,7 +13516,7 @@ var KernelLoopback = class {
13344
13516
  const incoming = new Incoming(socket);
13345
13517
  const head = await readHead(incoming, req.signal);
13346
13518
  if (head.status !== 101) {
13347
- throw errno(
13519
+ throw errno2(
13348
13520
  "EPROTO",
13349
13521
  `the server answered the upgrade with ${head.status}${head.statusText ? ` ${head.statusText}` : ""}`
13350
13522
  );
@@ -13352,10 +13524,10 @@ var KernelLoopback = class {
13352
13524
  const upgraded = fieldTokens(head.headers, "upgrade").includes("websocket") && fieldTokens(head.headers, "connection").includes("upgrade");
13353
13525
  const accept2 = fieldValues(head.headers, "sec-websocket-accept")[0];
13354
13526
  if (!upgraded || accept2 !== await acceptFor(key)) {
13355
- throw errno("EPROTO", "the server did not accept the WebSocket key");
13527
+ throw errno2("EPROTO", "the server did not accept the WebSocket key");
13356
13528
  }
13357
13529
  if (fieldValues(head.headers, "sec-websocket-extensions").length > 0) {
13358
- throw errno("EPROTO", "the server offered an unsolicited extension");
13530
+ throw errno2("EPROTO", "the server offered an unsolicited extension");
13359
13531
  }
13360
13532
  const protocol = fieldValues(head.headers, "sec-websocket-protocol")[0] ?? "";
13361
13533
  return new LoopbackWebSocket(socket, incoming, protocol);
@@ -13373,7 +13545,7 @@ async function* closing(chunks, socket) {
13373
13545
  yield* chunks;
13374
13546
  } catch (err) {
13375
13547
  if (typeof err?.code === "string") throw err;
13376
- throw errno("EPROTO", err instanceof Error ? err.message : String(err));
13548
+ throw errno2("EPROTO", err instanceof Error ? err.message : String(err));
13377
13549
  } finally {
13378
13550
  socket.close();
13379
13551
  }
@@ -13502,7 +13674,7 @@ var LoopbackWebSocket = class {
13502
13674
  this.write(clientFrame(OP_CLOSE, payload));
13503
13675
  }
13504
13676
  send(data) {
13505
- if (this.sentClose) throw errno("EPIPE", "the websocket is closing");
13677
+ if (this.sentClose) throw errno2("EPIPE", "the websocket is closing");
13506
13678
  const text = typeof data === "string";
13507
13679
  const payload = text ? new TextEncoder().encode(data) : data;
13508
13680
  this.write(clientFrame(text ? OP_TEXT : OP_BINARY, payload));
@@ -14242,8 +14414,8 @@ function errnoOf(e) {
14242
14414
  const code = e?.code;
14243
14415
  return typeof code === "string" && ERRNO.test(code) ? code : "ECONNREFUSED";
14244
14416
  }
14245
- function fail(errno2, text) {
14246
- return { ok: false, errno: errno2, message: text };
14417
+ function fail(errno3, text) {
14418
+ return { ok: false, errno: errno3, message: text };
14247
14419
  }
14248
14420
  var WsHandles = class {
14249
14421
  transport;
@@ -14517,8 +14689,8 @@ var HttpHandles = class {
14517
14689
  const status = e.status;
14518
14690
  if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
14519
14691
  const code = codeOf2(e);
14520
- const errno2 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14521
- return { ok: false, errno: errno2, message: text };
14692
+ const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
14693
+ return { ok: false, errno: errno3, message: text };
14522
14694
  }
14523
14695
  entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
14524
14696
  return this.headOf(handle, req.url, {
@@ -15723,7 +15895,7 @@ var UNREACHABLE = ["EACCES", "ENETUNREACH", "EHOSTUNREACH"];
15723
15895
  function sendError(e) {
15724
15896
  if (e instanceof KernelError) return e;
15725
15897
  const code = e?.code;
15726
- return new KernelError(SEND_ERRORS.find((errno2) => errno2 === code) ?? "EHOSTUNREACH");
15898
+ return new KernelError(SEND_ERRORS.find((errno3) => errno3 === code) ?? "EHOSTUNREACH");
15727
15899
  }
15728
15900
  function sameAddr(a, b) {
15729
15901
  return a.port === b.port && canonicalHost(a.host) === canonicalHost(b.host);
@@ -15852,7 +16024,7 @@ var KernelDgram = class {
15852
16024
  }
15853
16025
  unreachable(error, from) {
15854
16026
  if (!this.peer || !sameAddr(this.peer, from)) return;
15855
- this.pending = UNREACHABLE.find((errno2) => errno2 === error) ?? "EHOSTUNREACH";
16027
+ this.pending = UNREACHABLE.find((errno3) => errno3 === error) ?? "EHOSTUNREACH";
15856
16028
  this.changes.wake();
15857
16029
  }
15858
16030
  deliver(datagram2) {
@@ -17170,6 +17342,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
17170
17342
  "sig-mask",
17171
17343
  "sig-inherited",
17172
17344
  "sig-waiting",
17345
+ "sig-info",
17173
17346
  "sig-pause",
17174
17347
  ...SOCKET_OPS,
17175
17348
  ...EPOLL_OPS,
@@ -17183,6 +17356,7 @@ function isWasmSyscall(req) {
17183
17356
  return typeof op === "string" && SYSCALL_OPS.has(op);
17184
17357
  }
17185
17358
  var MAX_READ = 1024 * 1024;
17359
+ var O_NONBLOCK = 2048;
17186
17360
  var WRITE_ACCESS = 3;
17187
17361
  var KEYBOARD = /* @__PURE__ */ new Set([SIG.INT, SIG.QUIT, SIG.TSTP]);
17188
17362
  var DEFAULT_UMASK2 = 18;
@@ -17251,7 +17425,7 @@ var WasmProcess = class {
17251
17425
  this.children = new ChildTable(fds, options.spawner, options.forker);
17252
17426
  this.nodes = options.nodes ?? new VfsNodes(options.fs);
17253
17427
  if (!options.nodes) options.openFiles?.add(this.nodes);
17254
- this.children.onChildState = () => this.signal(SIG.CHLD);
17428
+ this.children.onChildState = (child) => this.signal(SIG.CHLD, child && this.childInfo(child));
17255
17429
  this.children.autoReap = () => this.reapsChildren();
17256
17430
  this.seedDl(options.dl);
17257
17431
  this.children.onReap = (pid2) => {
@@ -17268,10 +17442,43 @@ var WasmProcess = class {
17268
17442
  inheritable(fork = false) {
17269
17443
  return ((fork ? 0 : this.ignored) | this.inherited) & ~this.caught;
17270
17444
  }
17271
- signal(sig) {
17445
+ sigInfos = /* @__PURE__ */ new Map();
17446
+ signal(sig, info) {
17447
+ const pending = ((this.options.pendingBits?.() ?? 0) & sigbit(sig)) !== 0;
17448
+ const outcome = this.signalOutcome(sig, info);
17449
+ if (outcome === "deliver" && !(pending && this.sigInfos.has(`0:${sig}`))) {
17450
+ this.sigInfos.set(`0:${sig}`, info ?? KERNEL_SIGINFO);
17451
+ }
17452
+ return outcome;
17453
+ }
17454
+ async threadKill(tid, sig) {
17455
+ const info = await this.threadSender(sig);
17456
+ if (this.options.threadKill?.(tid, sig)) this.sigInfos.set(`${tid}:${sig}`, info);
17457
+ else this.options.raise?.(sig, info);
17458
+ }
17459
+ async threadSender(sig) {
17460
+ const pid = (await this.options.identity?.())?.pid ?? this.pid;
17461
+ const code = sig === SIG.PIPE ? SI.USER : SI.TKILL;
17462
+ return { code, pid, uid: this.cred.ruid, status: 0 };
17463
+ }
17464
+ childInfo(child) {
17465
+ const code = child.state === "stopped" ? CLD.STOPPED : child.state === "continued" ? CLD.CONTINUED : child.termsig ? CLD.KILLED : CLD.EXITED;
17466
+ return { code, pid: child.pid, uid: child.uid ?? this.cred.ruid, status: child.status };
17467
+ }
17468
+ takeSigInfo(sig, tid) {
17469
+ for (const key of [`${tid}:${sig}`, `0:${sig}`]) {
17470
+ const info = this.sigInfos.get(key);
17471
+ if (info) {
17472
+ this.sigInfos.delete(key);
17473
+ return info;
17474
+ }
17475
+ }
17476
+ return null;
17477
+ }
17478
+ signalOutcome(sig, info) {
17272
17479
  if (this.execChild !== void 0) {
17273
17480
  if (sig === SIG.CONT) this.cont();
17274
- void Promise.resolve(this.options.kill?.(this.execChild, sig)).catch(() => void 0);
17481
+ void Promise.resolve(this.options.kill?.(this.execChild, sig, info)).catch(() => void 0);
17275
17482
  if (sig !== SIG.KILL) return "forward";
17276
17483
  if (!this.options.writesBack?.(this.execChild)) return "terminate";
17277
17484
  this.wake?.();
@@ -17647,7 +17854,7 @@ var WasmProcess = class {
17647
17854
  this.options.hasPending?.() ? AbortSignal.abort() : this.cancelSignal(cancelled)
17648
17855
  );
17649
17856
  }
17650
- async openVfs(req) {
17857
+ async openVfs(req, cancelled) {
17651
17858
  if (inProc(req.path)) return this.openProc(req, req.path);
17652
17859
  const device = req.orphan ? void 0 : deviceAt(req.path);
17653
17860
  if (device) return this.openDevice(req, device);
@@ -17658,6 +17865,10 @@ var WasmProcess = class {
17658
17865
  await refuseReadonly(this.options.fs, req.path, req.flags, req);
17659
17866
  if (this.writesAt(req)) await this.options.fs.mayChange?.(req.path, !req.exclusive);
17660
17867
  await this.mayOpen(req);
17868
+ if (req.fifo && !req.exclusive) {
17869
+ const opened2 = await this.openFifo(req, cancelled);
17870
+ if (opened2 !== void 0) return opened2;
17871
+ }
17661
17872
  const marked = await this.markedPath(req);
17662
17873
  await this.sourceOpen(marked === void 0 ? req : { ...req, path: marked });
17663
17874
  const fs = marked === void 0 ? this.options.fs : this.options.noLinks;
@@ -17699,6 +17910,19 @@ var WasmProcess = class {
17699
17910
  }
17700
17911
  return fd;
17701
17912
  }
17913
+ async openFifo(req, cancelled) {
17914
+ const fifos = this.options.fifos;
17915
+ const path = await this.nodes.targetKey(req.path);
17916
+ const st = await this.heldFs().stat(path);
17917
+ if (!st.isFifo) return void 0;
17918
+ if (!fifos) throw new KernelError("ENXIO");
17919
+ const access2 = openAccess(req.flags);
17920
+ const nonblock = (req.flags & O_NONBLOCK) !== 0;
17921
+ const blocks = !nonblock && access2 !== "both";
17922
+ const signal = blocks ? this.blockingSignal(cancelled) : cancelled;
17923
+ const end = await fifos.open(`${st.dev ?? 0}:${st.ino}`, path, access2, nonblock, signal);
17924
+ return this.fds.install(end, 3);
17925
+ }
17702
17926
  openDevice(req, device) {
17703
17927
  if (req.exclusive) throw Object.assign(new Error(req.path), { code: "EEXIST" });
17704
17928
  const access2 = req.flags & WRITE_ACCESS;
@@ -17898,7 +18122,7 @@ var WasmProcess = class {
17898
18122
  case "fd-poll":
17899
18123
  return { ok: true, kind: "json", json: pollFile(this.fds.get(req.fd).file) };
17900
18124
  case "fd-open-vfs":
17901
- return { ok: true, kind: "json", json: await this.openVfs(req) };
18125
+ return { ok: true, kind: "json", json: await this.openVfs(req, cancelled) };
17902
18126
  case "fd-info":
17903
18127
  return { ok: true, kind: "json", json: this.fdInfo(req.fd) };
17904
18128
  case "fd-list":
@@ -18332,8 +18556,10 @@ var WasmProcess = class {
18332
18556
  case "sig-pause":
18333
18557
  return this.pause(cancelled);
18334
18558
  case "thread-kill":
18335
- if (!this.options.threadKill?.(req.tid, req.sig)) this.options.raise?.(req.sig);
18559
+ await this.threadKill(req.tid, req.sig);
18336
18560
  return { ok: true, kind: "void" };
18561
+ case "sig-info":
18562
+ return { ok: true, kind: "json", json: this.takeSigInfo(req.sig, req.tid ?? 0) };
18337
18563
  case "proc-captured":
18338
18564
  return { ok: true, kind: "bytes", bytes: this.children.captured(req.pid, req.slot) };
18339
18565
  case "proc-sudo":
@@ -18556,7 +18782,8 @@ function inheritedFds(fds) {
18556
18782
  ...kind === "device" && meta && "device" in meta ? { device: meta } : {},
18557
18783
  ...flags2 !== void 0 ? { flags: flags2 } : {},
18558
18784
  ...fds.closesOnExec(fd) ? { cloexec: true } : {},
18559
- ...kind === "stream" ? { desc: descId(open) } : {}
18785
+ ...kind === "stream" ? { desc: descId(open) } : {},
18786
+ ...open.file.fifo ? { fifo: open.file.fifo } : {}
18560
18787
  };
18561
18788
  });
18562
18789
  }
@@ -18762,6 +18989,7 @@ function processOptions(opts, header3, hooks, created3) {
18762
18989
  net: opts.net,
18763
18990
  http: opts.http,
18764
18991
  locks: opts.locks,
18992
+ fifos: opts.fifos,
18765
18993
  ...opts.sems ? { sems: opts.sems } : {},
18766
18994
  onReap: opts.onReap,
18767
18995
  resolver: opts.resolver,
@@ -18812,7 +19040,7 @@ function spawnWasmProcess(opts) {
18812
19040
  opts,
18813
19041
  header3,
18814
19042
  {
18815
- raise: (sig) => signal(sig),
19043
+ raise: (sig, info) => signal(sig, info),
18816
19044
  threadKill: (tid, sig) => killThread(threadSignals.get(tid), process.signalMasks().caught, sig),
18817
19045
  unblockedThread: (sig) => unblockedThread(threadSignals, sig),
18818
19046
  ...opts.program.abi === "js" ? {
@@ -18934,8 +19162,9 @@ function spawnWasmProcess(opts) {
18934
19162
  if (opts.program.abi !== "wasi" || done4) finish(code, sig);
18935
19163
  else dying.start(code, sig, header3, process, () => finish(code, sig));
18936
19164
  };
18937
- const signal = (sig) => {
18938
- if (process.signal(sig) === "terminate") terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
19165
+ const signal = (sig, info) => {
19166
+ if (process.signal(sig, info) === "terminate")
19167
+ terminate(sig === SIG.KILL ? 137 : 128 + sig, sig);
18939
19168
  };
18940
19169
  const kill = (code = 137) => finish(code, code > 128 && code < 160 ? code - 128 : void 0);
18941
19170
  return {
@@ -19105,14 +19334,14 @@ var JobTable = class {
19105
19334
  this.foreground.set(tty, member.pgid);
19106
19335
  return true;
19107
19336
  }
19108
- killGroup(pgid, sig, may = () => true) {
19337
+ killGroup(pgid, sig, may = () => true, info) {
19109
19338
  const group = [...this.members.values()].filter((m) => m.pgid === pgid);
19110
19339
  const targets = group.filter((m) => may(m.pid));
19111
19340
  if (targets.length === 0 && group.length > 0) throw new KernelError("EPERM");
19112
19341
  const pids = new Set(targets.map((m) => m.pid));
19113
19342
  if (sig !== 0) {
19114
19343
  for (const m of targets)
19115
- if (m.execParent === void 0 || !pids.has(m.execParent)) m.signal(sig);
19344
+ if (m.execParent === void 0 || !pids.has(m.execParent)) m.signal(sig, info);
19116
19345
  }
19117
19346
  return targets.length > 0;
19118
19347
  }
@@ -20699,9 +20928,9 @@ var HostfsClient = class {
20699
20928
  throw fsError2("ESTALE", "the folder was granted again, so its open files are gone");
20700
20929
  return this.send(path, init, false, true);
20701
20930
  }
20702
- const errno2 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20931
+ const errno3 = response.headers.get("X-Hostfs-Errno") ?? "EIO";
20703
20932
  const body = await response.json().catch(() => ({}));
20704
- throw fsError2(errno2, typeof body.message === "string" ? body.message : errno2);
20933
+ throw fsError2(errno3, typeof body.message === "string" ? body.message : errno3);
20705
20934
  }
20706
20935
  async call(op, body = {}, handle = false) {
20707
20936
  const response = await this.send(
@@ -21786,8 +22015,8 @@ var RULE = new RegExp(
21786
22015
  var TERM = /^[A-Za-z0-9._+-]+$/;
21787
22016
  var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
21788
22017
  var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
21789
- function failed2(errno2, error) {
21790
- return { error, errno: errno2 };
22018
+ function failed2(errno3, error) {
22019
+ return { error, errno: errno3 };
21791
22020
  }
21792
22021
  function unescaped(double) {
21793
22022
  return double.replace(/\\(["\\$`])/g, "$1");
@@ -22383,7 +22612,8 @@ function childHandle(handle) {
22383
22612
  pid: handle.pid,
22384
22613
  exited: handle.exited,
22385
22614
  termsig: handle.termsig,
22386
- onState: (listener) => handle.onState(listener)
22615
+ onState: (listener) => handle.onState(listener),
22616
+ uid: () => handle.cred?.().ruid
22387
22617
  };
22388
22618
  }
22389
22619
  function concat7(chunks) {
@@ -22447,6 +22677,7 @@ var Launcher = class {
22447
22677
  sudoer;
22448
22678
  jobs = new JobTable();
22449
22679
  locks = new LockTable();
22680
+ fifos = new FifoTable();
22450
22681
  sems = new SemTable();
22451
22682
  settling = new SettlingChildren((pid) => this.jobs.pgidOf(pid));
22452
22683
  ptys = new PtyTable(
@@ -23421,7 +23652,7 @@ var Launcher = class {
23421
23652
  onError: req.report,
23422
23653
  spawner: this.spawner(pid, req.report),
23423
23654
  forker: this.forker(pid, req),
23424
- kill: (target, sig) => this.kill(target, sig, this.credOf(pid), pid),
23655
+ kill: (target, sig, info) => this.kill(target, sig, this.credOf(pid), pid, info),
23425
23656
  writesBack: (target) => this.processes.get(target)?.writesBack() === true,
23426
23657
  processes: () => ({
23427
23658
  boot: this.boot,
@@ -23444,6 +23675,7 @@ var Launcher = class {
23444
23675
  net: this.net,
23445
23676
  http: new HttpHandles(this.transport, pid, this.loopbackFor(pid)),
23446
23677
  locks: this.locks,
23678
+ fifos: this.fifos,
23447
23679
  sems: this.sems,
23448
23680
  resolver: this.resolver,
23449
23681
  onReap: (child) => this.reaped(child, pid),
@@ -23456,7 +23688,7 @@ var Launcher = class {
23456
23688
  this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
23457
23689
  this.marks(pid, req);
23458
23690
  if (req.ppid !== void 0 && this.controlsJobs(req.ppid)) this.settling.started(pid, req.ppid);
23459
- this.jobs.add(pid, req.ppid, (sig) => handle.signal(sig), terminal);
23691
+ this.jobs.add(pid, req.ppid, (sig, info) => handle.signal(sig, info), terminal);
23460
23692
  if (req.exec && req.ppid !== void 0) this.jobs.exec(req.ppid, pid, true);
23461
23693
  if (req.pgid !== void 0) this.jobs.join(pid, req.pgid);
23462
23694
  if (req.group === "lead") this.jobs.lead(pid);
@@ -23837,21 +24069,26 @@ var Launcher = class {
23837
24069
  ignoredBy(pid, fork = false) {
23838
24070
  return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
23839
24071
  }
23840
- kill(pid, sig, sender, from) {
24072
+ kill(pid, sig, sender, from, forwarded) {
24073
+ const info = forwarded ?? this.senderInfo(sender, from);
23841
24074
  const session = from === void 0 ? void 0 : this.jobs.sidOf(from);
23842
24075
  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;
23843
24076
  if (pid === -1) {
23844
24077
  const sender2 = from === void 0 ? void 0 : this.imageOf(from);
23845
- return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may);
24078
+ return this.killAll(sig, (member) => this.imageOf(member) !== sender2, may, info);
23846
24079
  }
23847
- if (pid < 0) return this.jobs.killGroup(-pid, sig, (member) => may(this.imageOf(member)));
24080
+ if (pid < 0) return this.jobs.killGroup(-pid, sig, (member) => may(this.imageOf(member)), info);
23848
24081
  const handle = this.processes.get(pid);
23849
24082
  if (!handle) return false;
23850
24083
  if (!may(this.imageOf(pid))) throw fsError("EPERM", `pid ${pid}`);
23851
- if (sig !== 0) handle.signal(sig);
24084
+ if (sig !== 0) handle.signal(sig, info);
23852
24085
  return true;
23853
24086
  }
23854
- killAll(sig, other, may) {
24087
+ senderInfo(sender, from) {
24088
+ if (from === void 0) return void 0;
24089
+ return { code: SI.USER, pid: this.jobs.shown(from), uid: sender?.ruid ?? 0, status: 0 };
24090
+ }
24091
+ killAll(sig, other, may, info) {
23855
24092
  const candidates = [...this.processes].filter(([pid]) => pid !== 1 && other(pid));
23856
24093
  const targets = candidates.filter(([pid]) => may(this.imageOf(pid)));
23857
24094
  if (targets.length === 0 && candidates.length > 0) throw fsError("EPERM", "kill -1");
@@ -23859,7 +24096,7 @@ var Launcher = class {
23859
24096
  const parents = new Map(this.jobs.list().map((m) => [m.pid, m.execParent]));
23860
24097
  for (const [pid, handle] of targets) {
23861
24098
  const parent = parents.get(pid);
23862
- if (sig !== 0 && (parent === void 0 || !pids.has(parent))) handle.signal(sig);
24099
+ if (sig !== 0 && (parent === void 0 || !pids.has(parent))) handle.signal(sig, info);
23863
24100
  }
23864
24101
  return targets.length > 0;
23865
24102
  }