@ai-ecoverse/slicc-kernel 1.94.4 → 1.95.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
@@ -567,8 +567,8 @@ async function inParent(g, op, path, old = false) {
567
567
  const dir = await access(g.fs, g.cred, parentOf(path), W_OK | X_OK, linked(g, DIR));
568
568
  if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
569
569
  if (dir.link) return deny(g, op, dir.denied);
570
- const lookup3 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
571
- if (!lookup3 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
570
+ const lookup4 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
571
+ if (!lookup4 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
572
572
  }
573
573
  async function makeIn(g, op, path) {
574
574
  for (let dir = parentOf(path); ; dir = parentOf(dir)) {
@@ -888,6 +888,7 @@ function pollFile(file) {
888
888
  }
889
889
  var OpenFile = class {
890
890
  refs = 1;
891
+ closers;
891
892
  file;
892
893
  constructor(file) {
893
894
  this.file = file;
@@ -896,9 +897,18 @@ var OpenFile = class {
896
897
  this.refs += 1;
897
898
  return this;
898
899
  }
900
+ onClose(fn) {
901
+ this.closers ??= /* @__PURE__ */ new Set();
902
+ this.closers.add(fn);
903
+ return () => void this.closers?.delete(fn);
904
+ }
899
905
  release() {
900
906
  this.refs -= 1;
901
- if (this.refs === 0) return this.file.close();
907
+ if (this.refs !== 0) return;
908
+ const closers = this.closers;
909
+ this.closers = void 0;
910
+ for (const fn of closers ?? []) fn();
911
+ return this.file.close();
902
912
  }
903
913
  };
904
914
  function openPipe(capacity) {
@@ -1446,7 +1456,8 @@ var KernelSocket = class _KernelSocket {
1446
1456
  return {
1447
1457
  readable: this.readShut || rx.readReady,
1448
1458
  writable: this.writeShut || tx.writeReady,
1449
- hangup: rx.writersGone && tx.readersGone
1459
+ hangup: rx.writersGone && tx.readersGone,
1460
+ rdhup: rx.writersGone
1450
1461
  };
1451
1462
  }
1452
1463
  changed(signal) {
@@ -10643,7 +10654,7 @@ function mountTable(mounts = []) {
10643
10654
  }
10644
10655
 
10645
10656
  // src/version.ts
10646
- var KERNEL_VERSION = true ? "1.94.4" : "0.0.0-dev";
10657
+ var KERNEL_VERSION = true ? "1.95.0" : "0.0.0-dev";
10647
10658
  var OS_RELEASE = "6.0.0-slicc";
10648
10659
  function procVersion() {
10649
10660
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -11030,6 +11041,295 @@ async function procAlias(fs, path, follow2) {
11030
11041
  return step.value;
11031
11042
  }
11032
11043
 
11044
+ // src/kernel/eventfd.ts
11045
+ var EVENTFD_MAX = 0xfffffffffffffffen;
11046
+ var Notifier = class {
11047
+ waiters = [];
11048
+ wait(signal) {
11049
+ if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
11050
+ return new Promise((resolve2, reject) => {
11051
+ const onAbort = () => {
11052
+ this.waiters = this.waiters.filter((w) => w !== waiter);
11053
+ reject(new KernelError("EINTR"));
11054
+ };
11055
+ const waiter = () => {
11056
+ signal?.removeEventListener("abort", onAbort);
11057
+ resolve2();
11058
+ };
11059
+ this.waiters.push(waiter);
11060
+ signal?.addEventListener("abort", onAbort, { once: true });
11061
+ });
11062
+ }
11063
+ wake() {
11064
+ const waiters = this.waiters;
11065
+ this.waiters = [];
11066
+ for (const resolve2 of waiters) resolve2();
11067
+ }
11068
+ };
11069
+ function blocked(signal) {
11070
+ if (signal?.aborted) throw new KernelError("EAGAIN");
11071
+ }
11072
+ var EventFd = class _EventFd {
11073
+ static SIZE = 8;
11074
+ count;
11075
+ semaphore;
11076
+ changes = new Notifier();
11077
+ constructor(initial, semaphore) {
11078
+ this.count = initial;
11079
+ this.semaphore = semaphore;
11080
+ }
11081
+ async read(max, signal) {
11082
+ if (max < _EventFd.SIZE) throw new KernelError("EINVAL");
11083
+ while (this.count === 0n) {
11084
+ blocked(signal);
11085
+ await this.changes.wait(signal);
11086
+ }
11087
+ const value = this.semaphore ? 1n : this.count;
11088
+ this.count -= value;
11089
+ this.changes.wake();
11090
+ const out = new Uint8Array(_EventFd.SIZE);
11091
+ new DataView(out.buffer).setBigUint64(0, value, true);
11092
+ return out;
11093
+ }
11094
+ async write(bytes, signal) {
11095
+ if (bytes.length < _EventFd.SIZE) throw new KernelError("EINVAL");
11096
+ const value = new DataView(bytes.buffer, bytes.byteOffset, _EventFd.SIZE).getBigUint64(0, true);
11097
+ if (value > EVENTFD_MAX) throw new KernelError("EINVAL");
11098
+ while (EVENTFD_MAX - this.count < value) {
11099
+ blocked(signal);
11100
+ await this.changes.wait(signal);
11101
+ }
11102
+ this.count += value;
11103
+ if (value > 0n) this.changes.wake();
11104
+ return _EventFd.SIZE;
11105
+ }
11106
+ poll() {
11107
+ return { readable: this.count > 0n, writable: this.count < EVENTFD_MAX, hangup: false };
11108
+ }
11109
+ changed(signal) {
11110
+ return this.changes.wait(signal);
11111
+ }
11112
+ close() {
11113
+ this.changes.wake();
11114
+ }
11115
+ };
11116
+
11117
+ // src/kernel/epoll.ts
11118
+ var EPOLL = {
11119
+ IN: 1,
11120
+ OUT: 2,
11121
+ RDHUP: 4,
11122
+ PRI: 8,
11123
+ ERR: 16,
11124
+ HUP: 32,
11125
+ ET: 64,
11126
+ ONESHOT: 128
11127
+ };
11128
+ var ALWAYS = EPOLL.ERR | EPOLL.HUP;
11129
+ var ASKED = EPOLL.IN | EPOLL.OUT | EPOLL.RDHUP;
11130
+ var RETRY_MS = 50;
11131
+ var UNPOLLABLE = /* @__PURE__ */ new Set(["file", "held", "device"]);
11132
+ var EPOLL_OPS = [
11133
+ "epoll-create",
11134
+ "epoll-ctl",
11135
+ "epoll-wait",
11136
+ "eventfd-open"
11137
+ ];
11138
+ function levelOf(file) {
11139
+ const state = pollFile(file);
11140
+ let bits2 = 0;
11141
+ if (state.readable) bits2 |= EPOLL.IN;
11142
+ if (state.writable) bits2 |= EPOLL.OUT;
11143
+ if (state.rdhup) bits2 |= EPOLL.RDHUP;
11144
+ if (state.hangup) bits2 |= file.read ? EPOLL.HUP : EPOLL.ERR;
11145
+ return bits2;
11146
+ }
11147
+ function due(interest, level) {
11148
+ if (!interest.armed) return 0;
11149
+ const ready2 = level & (interest.events & ASKED | ALWAYS);
11150
+ if (ready2 === 0) return 0;
11151
+ if ((interest.events & EPOLL.ET) !== 0 && interest.reported === interest.gen) return 0;
11152
+ return ready2;
11153
+ }
11154
+ function consume(interest) {
11155
+ interest.reported = interest.gen;
11156
+ if ((interest.events & EPOLL.ONESHOT) !== 0) interest.armed = false;
11157
+ }
11158
+ function lookup(fds, fd) {
11159
+ try {
11160
+ return fds.get(fd);
11161
+ } catch {
11162
+ return void 0;
11163
+ }
11164
+ }
11165
+ function pause(ms, signal) {
11166
+ return new Promise((resolve2) => {
11167
+ const timer = setTimeout(resolve2, ms);
11168
+ signal.addEventListener(
11169
+ "abort",
11170
+ () => {
11171
+ clearTimeout(timer);
11172
+ resolve2();
11173
+ },
11174
+ { once: true }
11175
+ );
11176
+ });
11177
+ }
11178
+ var EpollFile = class _EpollFile {
11179
+ regs = /* @__PURE__ */ new Map();
11180
+ changes = new Notifier();
11181
+ cursor = 0;
11182
+ ctl(fds, how, fd, events, data) {
11183
+ const open = fds.get(fd);
11184
+ if (open.file === this) throw new KernelError("EINVAL");
11185
+ const known = this.regs.get(fd);
11186
+ const current = known?.open === open ? known : void 0;
11187
+ if (how === "add" || how === "set" && !current) {
11188
+ if (current) throw new KernelError("EEXIST");
11189
+ if (UNPOLLABLE.has(kernelFdKind(open.file))) throw new KernelError("EPERM");
11190
+ if (open.file instanceof _EpollFile && open.file.reaches(this)) throw new KernelError("ELOOP");
11191
+ if (known) this.drop(known);
11192
+ this.register(fd, open, events, data);
11193
+ } else if (!current) {
11194
+ throw new KernelError("ENOENT");
11195
+ } else if (how === "del") {
11196
+ this.drop(current);
11197
+ } else {
11198
+ current.events = events;
11199
+ current.data = data;
11200
+ current.armed = true;
11201
+ current.gen++;
11202
+ }
11203
+ this.changes.wake();
11204
+ }
11205
+ reaches(target) {
11206
+ if (this === target) return true;
11207
+ return [...this.regs.values()].some(
11208
+ (reg) => reg.open.file instanceof _EpollFile && reg.open.file.reaches(target)
11209
+ );
11210
+ }
11211
+ collect(fds, max) {
11212
+ const list = [...this.regs.values()];
11213
+ const out = [];
11214
+ const start2 = list.length === 0 ? 0 : this.cursor % list.length;
11215
+ for (let i = 0; i < list.length && out.length < max; i++) {
11216
+ const reg = list[(start2 + i) % list.length];
11217
+ if (lookup(fds, reg.fd) !== reg.open) {
11218
+ this.drop(reg);
11219
+ continue;
11220
+ }
11221
+ const bits2 = due(reg, levelOf(reg.open.file));
11222
+ if (bits2 === 0) continue;
11223
+ consume(reg);
11224
+ out.push({ events: bits2, data: reg.data });
11225
+ this.cursor = start2 + i + 1;
11226
+ }
11227
+ return out;
11228
+ }
11229
+ async wait(fds, max, timeoutMs, signal) {
11230
+ const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
11231
+ for (; ; ) {
11232
+ const events = this.collect(fds, max);
11233
+ if (events.length > 0 || Date.now() >= deadline) return events;
11234
+ const round = new AbortController();
11235
+ const woken = this.changes.wait(AbortSignal.any([round.signal, signal]));
11236
+ woken.catch(() => void 0);
11237
+ let timer;
11238
+ const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
11239
+ try {
11240
+ await Promise.race([woken, ...expiry]);
11241
+ } finally {
11242
+ round.abort();
11243
+ clearTimeout(timer);
11244
+ }
11245
+ }
11246
+ }
11247
+ poll() {
11248
+ const ready2 = [...this.regs.values()].some((reg) => due(reg, levelOf(reg.open.file)) !== 0);
11249
+ return { readable: ready2, writable: false, hangup: false };
11250
+ }
11251
+ changed(signal) {
11252
+ return this.changes.wait(signal);
11253
+ }
11254
+ close() {
11255
+ for (const reg of [...this.regs.values()]) this.drop(reg);
11256
+ this.changes.wake();
11257
+ }
11258
+ register(fd, open, events, data) {
11259
+ const stop = new AbortController();
11260
+ const unhook = open.onClose(() => {
11261
+ this.drop(reg);
11262
+ this.changes.wake();
11263
+ });
11264
+ const reg = {
11265
+ fd,
11266
+ open,
11267
+ events,
11268
+ data,
11269
+ gen: 1,
11270
+ reported: 0,
11271
+ armed: true,
11272
+ stop,
11273
+ unhook
11274
+ };
11275
+ this.regs.set(fd, reg);
11276
+ void this.watch(reg);
11277
+ }
11278
+ drop(reg) {
11279
+ reg.stop.abort();
11280
+ reg.unhook();
11281
+ if (this.regs.get(reg.fd) === reg) this.regs.delete(reg.fd);
11282
+ }
11283
+ async watch(reg) {
11284
+ const file = reg.open.file;
11285
+ const { signal } = reg.stop;
11286
+ while (file.changed && !signal.aborted) {
11287
+ const round = new AbortController();
11288
+ const stop = () => round.abort();
11289
+ signal.addEventListener("abort", stop, { once: true });
11290
+ let failed3 = false;
11291
+ try {
11292
+ await file.changed(round.signal);
11293
+ } catch {
11294
+ failed3 = true;
11295
+ } finally {
11296
+ round.abort();
11297
+ signal.removeEventListener("abort", stop);
11298
+ }
11299
+ if (signal.aborted) return;
11300
+ reg.gen++;
11301
+ this.changes.wake();
11302
+ if (failed3) await pause(RETRY_MS, signal);
11303
+ }
11304
+ }
11305
+ };
11306
+ function epollAt(fds, fd) {
11307
+ const file = fds.get(fd).file;
11308
+ if (!(file instanceof EpollFile)) throw new KernelError("EINVAL");
11309
+ return file;
11310
+ }
11311
+ var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
11312
+ async function epollSyscall(req, proc) {
11313
+ const { fds } = proc;
11314
+ switch (req.op) {
11315
+ case "epoll-create":
11316
+ return ok(fds.install(new OpenFile(new EpollFile()), 3));
11317
+ case "eventfd-open":
11318
+ return ok(fds.install(new OpenFile(new EventFd(BigInt(req.initial), req.semaphore)), 3));
11319
+ case "epoll-ctl":
11320
+ epollAt(fds, req.epfd).ctl(fds, req.how, req.fd, req.events, req.data);
11321
+ return ok();
11322
+ case "epoll-wait": {
11323
+ const ep = epollAt(fds, req.epfd);
11324
+ if (req.timeoutMs === 0 || proc.owed()) {
11325
+ const now = ep.collect(fds, req.max);
11326
+ if (req.timeoutMs === 0 || now.length > 0) return ok(now);
11327
+ }
11328
+ return ok(await ep.wait(fds, req.max, req.timeoutMs, proc.blocking()));
11329
+ }
11330
+ }
11331
+ }
11332
+
11033
11333
  // src/kernel/host-ops.ts
11034
11334
  var HOST_OPS = [
11035
11335
  "lock",
@@ -12684,14 +12984,14 @@ var Resolver = class {
12684
12984
  if (hit && hit.expires > this.now()) return hit.addresses;
12685
12985
  const signal = blocking?.();
12686
12986
  if (signal?.aborted) throw new KernelError("EINTR");
12687
- let lookup3 = this.pending.get(id2);
12688
- if (!lookup3) {
12987
+ let lookup4 = this.pending.get(id2);
12988
+ if (!lookup4) {
12689
12989
  const abort = new AbortController();
12690
- lookup3 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
12691
- this.pending.set(id2, lookup3);
12692
- void lookup3.work.then(() => this.pending.delete(id2));
12990
+ lookup4 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
12991
+ this.pending.set(id2, lookup4);
12992
+ void lookup4.work.then(() => this.pending.delete(id2));
12693
12993
  }
12694
- return waitFor(lookup3, signal);
12994
+ return waitFor(lookup4, signal);
12695
12995
  }
12696
12996
  async lookup(name2, family, id2, abandoned) {
12697
12997
  const uplink = this.uplink;
@@ -12732,17 +13032,17 @@ var Resolver = class {
12732
13032
  }
12733
13033
  }
12734
13034
  };
12735
- function waitFor(lookup3, signal) {
12736
- lookup3.waiters++;
13035
+ function waitFor(lookup4, signal) {
13036
+ lookup4.waiters++;
12737
13037
  return new Promise((resolve2, reject) => {
12738
13038
  const abort = () => {
12739
- if (--lookup3.waiters === 0) lookup3.abort.abort(new KernelError("EINTR"));
13039
+ if (--lookup4.waiters === 0) lookup4.abort.abort(new KernelError("EINTR"));
12740
13040
  reject(new KernelError("EINTR"));
12741
13041
  };
12742
13042
  signal?.addEventListener("abort", abort, { once: true });
12743
- void lookup3.work.then((value) => {
13043
+ void lookup4.work.then((value) => {
12744
13044
  if (signal?.aborted) return;
12745
- lookup3.waiters--;
13045
+ lookup4.waiters--;
12746
13046
  signal?.removeEventListener("abort", abort);
12747
13047
  resolve2(value);
12748
13048
  });
@@ -13389,17 +13689,17 @@ function socketAt(fds, fd) {
13389
13689
  if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
13390
13690
  return file;
13391
13691
  }
13392
- var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
13692
+ var ok2 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
13393
13693
  async function socketSyscall(req, proc) {
13394
13694
  const { fds, net } = proc;
13395
13695
  switch (req.op) {
13396
13696
  case "sock-open":
13397
- return ok(fds.install(new OpenFile(net.socket(req.domain)), 3));
13697
+ return ok2(fds.install(new OpenFile(net.socket(req.domain)), 3));
13398
13698
  case "sock-pair": {
13399
13699
  const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
13400
13700
  const first = fds.install(new OpenFile(a), 3);
13401
13701
  try {
13402
- return ok([first, fds.install(new OpenFile(b), 3)]);
13702
+ return ok2([first, fds.install(new OpenFile(b), 3)]);
13403
13703
  } catch (e) {
13404
13704
  await Promise.resolve(fds.close(first));
13405
13705
  throw e;
@@ -13407,12 +13707,12 @@ async function socketSyscall(req, proc) {
13407
13707
  }
13408
13708
  case "sock-bind":
13409
13709
  socketAt(fds, req.fd).bind(req.addr);
13410
- return ok();
13710
+ return ok2();
13411
13711
  case "sock-listen":
13412
13712
  socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
13413
- return ok();
13713
+ return ok2();
13414
13714
  case "sock-accept":
13415
- return ok(await accept(proc, req.fd, req.nonblock));
13715
+ return ok2(await accept(proc, req.fd, req.nonblock));
13416
13716
  case "sock-connect": {
13417
13717
  const socket = socketAt(fds, req.fd);
13418
13718
  const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
@@ -13422,26 +13722,26 @@ async function socketSyscall(req, proc) {
13422
13722
  throw new KernelError("EINPROGRESS");
13423
13723
  }
13424
13724
  if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
13425
- return ok();
13725
+ return ok2();
13426
13726
  }
13427
13727
  case "sock-shutdown":
13428
13728
  socketAt(fds, req.fd).shutdown(req.how);
13429
- return ok();
13729
+ return ok2();
13430
13730
  case "sock-name": {
13431
13731
  const socket = socketAt(fds, req.fd);
13432
13732
  const addr = req.peer ? socket.peer : socket.local;
13433
13733
  if (req.peer && !addr) throw new KernelError("ENOTCONN");
13434
- return ok(addr ?? unnamed(socket.domain));
13734
+ return ok2(addr ?? unnamed(socket.domain));
13435
13735
  }
13436
13736
  case "sock-getopt":
13437
- return ok(socketAt(fds, req.fd).getOption(req.level, req.name));
13737
+ return ok2(socketAt(fds, req.fd).getOption(req.level, req.name));
13438
13738
  case "sock-setopt":
13439
13739
  socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
13440
- return ok();
13740
+ return ok2();
13441
13741
  case "sock-resolve": {
13442
13742
  const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
13443
13743
  if (addresses.length === 0) throw new KernelError("ENOENT");
13444
- return ok(addresses);
13744
+ return ok2(addresses);
13445
13745
  }
13446
13746
  }
13447
13747
  }
@@ -14142,6 +14442,9 @@ function isHttpSyscall(req) {
14142
14442
  function isSocketSyscall(req) {
14143
14443
  return req.op.startsWith("sock-");
14144
14444
  }
14445
+ function isEpollSyscall(req) {
14446
+ return EPOLL_OPS.includes(req.op);
14447
+ }
14145
14448
  function isHostSyscall(req) {
14146
14449
  return HOST_OPS.includes(req.op);
14147
14450
  }
@@ -14232,6 +14535,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
14232
14535
  "sig-mask",
14233
14536
  "sig-pause",
14234
14537
  ...SOCKET_OPS,
14538
+ ...EPOLL_OPS,
14235
14539
  ...HTTP_OPS,
14236
14540
  ...PTY_OPS,
14237
14541
  ...HOST_OPS
@@ -14346,9 +14650,9 @@ var WasmProcess = class {
14346
14650
  this.options.onPending?.(sig);
14347
14651
  if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
14348
14652
  this.owed = true;
14349
- const blocked = this.interrupt;
14653
+ const blocked2 = this.interrupt;
14350
14654
  this.interrupt = new AbortController();
14351
- blocked.abort();
14655
+ blocked2.abort();
14352
14656
  return "deliver";
14353
14657
  }
14354
14658
  async spawn(req) {
@@ -14407,9 +14711,9 @@ var WasmProcess = class {
14407
14711
  this.stopped = sig;
14408
14712
  this.stops++;
14409
14713
  this.resumed = new Promise((resolve2) => this.wake = resolve2);
14410
- const blocked = this.interrupt;
14714
+ const blocked2 = this.interrupt;
14411
14715
  this.interrupt = new AbortController();
14412
- blocked.abort();
14716
+ blocked2.abort();
14413
14717
  for (const listener of this.stateListeners) listener("stopped", sig);
14414
14718
  return "stop";
14415
14719
  }
@@ -14459,6 +14763,13 @@ var WasmProcess = class {
14459
14763
  if (isTtySyscall(req)) return this.ttySyscall(req);
14460
14764
  if (isJobSyscall(req)) return this.jobSyscall(req);
14461
14765
  if (isSocketSyscall(req)) return await this.socketSyscall(req, cancelled);
14766
+ if (isEpollSyscall(req)) {
14767
+ return await epollSyscall(req, {
14768
+ fds: this.fds,
14769
+ blocking: () => this.blockingSignal(cancelled),
14770
+ owed: () => this.owed
14771
+ });
14772
+ }
14462
14773
  if (isHttpSyscall(req)) return await this.httpSyscall(req);
14463
14774
  if (isHostSyscall(req)) {
14464
14775
  return await hostSyscall(req, {
@@ -14525,6 +14836,7 @@ var WasmProcess = class {
14525
14836
  if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
14526
14837
  if (file.tty) this.checkForeground(file.tty);
14527
14838
  if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
14839
+ if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
14528
14840
  if (req.max <= 0) return new Uint8Array(0);
14529
14841
  if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
14530
14842
  const ready2 = pollFile(file).readable;
@@ -15372,9 +15684,9 @@ var WasmProcess = class {
15372
15684
  }
15373
15685
  timerExpired(which) {
15374
15686
  this.options.onTimer?.(which);
15375
- const blocked = this.interrupt;
15687
+ const blocked2 = this.interrupt;
15376
15688
  this.interrupt = new AbortController();
15377
- blocked.abort();
15689
+ blocked2.abort();
15378
15690
  }
15379
15691
  clearAlarm() {
15380
15692
  clearTimeout(this.alarm);
@@ -15478,9 +15790,9 @@ function killThread(thread, caught, sig) {
15478
15790
  Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
15479
15791
  if (held) return true;
15480
15792
  Atomics.notify(thread.header, SAB_I_SIGNALS);
15481
- const blocked = thread.interrupt;
15793
+ const blocked2 = thread.interrupt;
15482
15794
  thread.interrupt = new AbortController();
15483
- blocked.abort();
15795
+ blocked2.abort();
15484
15796
  return true;
15485
15797
  }
15486
15798
  function unblocked(header4) {
@@ -15659,8 +15971,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
15659
15971
  function spawnWasmProcess(opts) {
15660
15972
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
15661
15973
  const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
15662
- const blocked = opts.fork?.wasi?.blocked ?? opts.blocked;
15663
- if (blocked && anyBlocked(blocked) && opts.program.abi === "wasi") storeBlocked(header4, blocked);
15974
+ const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
15975
+ if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
15664
15976
  const threadSignals = /* @__PURE__ */ new Map();
15665
15977
  const created3 = new Created();
15666
15978
  const process2 = new WasmProcess(
@@ -19618,6 +19930,8 @@ var Launcher = class {
19618
19930
  const head = await this.head(glue);
19619
19931
  if (!head) return void 0;
19620
19932
  if (isWasm(head)) {
19933
+ const owner2 = await this.wasmOwner(glue, baseName(file).replace(/\.wasm$/, ""), scope);
19934
+ if (owner2) return { ...targetOf(owner2), ...asked };
19621
19935
  return {
19622
19936
  abi: "wasi",
19623
19937
  glue,
@@ -19640,6 +19954,17 @@ var Launcher = class {
19640
19954
  );
19641
19955
  return owners.find((c) => c.name === name2) ?? owners[0];
19642
19956
  }
19957
+ async wasmOwner(wasm, name2, scope) {
19958
+ const leaf = baseName(wasm);
19959
+ const real = await physicalPathAsync(this.base, wasm);
19960
+ const owners = [];
19961
+ for (const command of (await this.commands(scope)).values()) {
19962
+ if (command.abi !== "wasi" || command.script || baseName(command.wasm) !== leaf) continue;
19963
+ if (command.wasm === wasm || await physicalPathAsync(this.base, command.wasm) === real)
19964
+ owners.push(command);
19965
+ }
19966
+ return owners.find((c) => c.name === name2) ?? owners[0];
19967
+ }
19643
19968
  async head(path) {
19644
19969
  try {
19645
19970
  return (await this.base.readFileBuffer(path)).subarray(0, SHEBANG_MAX);
@@ -19727,16 +20052,29 @@ var Launcher = class {
19727
20052
  for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
19728
20053
  }
19729
20054
  async checkedPlan(req, { ppid, cred, scope }, fds) {
19730
- const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
19731
- try {
19732
- await this.mayExec(cred, { ...req, pid: ppid }, planned);
19733
- } catch (err) {
20055
+ const refused2 = async (err) => {
19734
20056
  await fds.closeAll();
19735
20057
  throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
19736
- }
20058
+ };
20059
+ const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused2);
20060
+ const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
20061
+ await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused2);
19737
20062
  if (planned) return planned;
19738
20063
  await fds.closeAll();
19739
- throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
20064
+ throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
20065
+ }
20066
+ execGuard(cred, pid, tag) {
20067
+ const { dac } = this;
20068
+ return dac && { fs: this.fs, cred, pid, dac, tag, links: this.links.get(pid) };
20069
+ }
20070
+ async execFile(file, cwd, g) {
20071
+ if (!file.split("/").includes("..")) return file;
20072
+ const path = file.startsWith("/") ? file : `${cwd}/${file}`;
20073
+ const slash = path.lastIndexOf("/");
20074
+ const dir = path.slice(0, slash);
20075
+ const walked = g && await need(g, "exec", dir, X_OK, { directory: true });
20076
+ const real = walked && walked.denied === void 0 ? walked.path : await physicalPathAsync(this.base, dir);
20077
+ return joinName(real, path.slice(slash + 1));
19740
20078
  }
19741
20079
  async ticketFile(req, fds) {
19742
20080
  if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
@@ -19835,7 +20173,8 @@ var Launcher = class {
19835
20173
  }
19836
20174
  return manifests;
19837
20175
  }
19838
- async backing(file, cwd) {
20176
+ async backing(asked, cwd) {
20177
+ const file = await this.execFile(asked, cwd);
19839
20178
  const planned = await this.plan(file, [file], cwd, "");
19840
20179
  return planned && this.backingOf(planned, file, cwd, "");
19841
20180
  }
@@ -20472,8 +20811,8 @@ var Launcher = class {
20472
20811
  }
20473
20812
  signalMasksOf(pid) {
20474
20813
  const masks = this.processes.get(pid)?.signalMasks?.();
20475
- const [blocked] = this.blockedBy(pid);
20476
- const sigBlk = blocked ? { sigBlk: blocked } : {};
20814
+ const [blocked2] = this.blockedBy(pid);
20815
+ const sigBlk = blocked2 ? { sigBlk: blocked2 } : {};
20477
20816
  return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
20478
20817
  }
20479
20818
  controlsJobs(pid) {
@@ -20921,7 +21260,7 @@ var Launcher = class {
20921
21260
  const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
20922
21261
  const start2 = dir ?? "/";
20923
21262
  const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
20924
- const [file = ""] = argv;
21263
+ const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
20925
21264
  if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
20926
21265
  const planned = await this.plan(file, argv, cwd, scope);
20927
21266
  await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
@@ -21024,11 +21363,11 @@ var Launcher = class {
21024
21363
  // src/node/loopback.ts
21025
21364
  import { AsyncLocalStorage } from "node:async_hooks";
21026
21365
  import { subscribe } from "node:diagnostics_channel";
21027
- import { lookup } from "node:dns/promises";
21366
+ import { lookup as lookup2 } from "node:dns/promises";
21028
21367
  import { isIP } from "node:net";
21029
21368
  var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
21030
21369
  var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
21031
- var resolveHost = async (host) => (await lookup(host, { all: true, verbatim: true })).map((a) => a.address);
21370
+ var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
21032
21371
  function ipv4Place(address) {
21033
21372
  const [a, b] = address.split(".").map(Number);
21034
21373
  if (a === 127 || a === 0) return "loopback";
@@ -21423,7 +21762,7 @@ function isMemoryRoot(handle) {
21423
21762
  }
21424
21763
 
21425
21764
  // src/node/ws-diagnose.ts
21426
- import { lookup as lookup2 } from "node:dns/promises";
21765
+ import { lookup as lookup3 } from "node:dns/promises";
21427
21766
  import { isIP as isIP2, connect as tcp } from "node:net";
21428
21767
  import { connect as tls } from "node:tls";
21429
21768
  var PROBE_MS = 3e3;
@@ -21455,7 +21794,7 @@ async function diagnose(url, ms = PROBE_MS) {
21455
21794
  const secure = at.protocol === "wss:";
21456
21795
  const port = Number(at.port) || (secure ? 443 : 80);
21457
21796
  try {
21458
- await lookup2(host);
21797
+ await lookup3(host);
21459
21798
  } catch (e) {
21460
21799
  return NO_NAME.has(codeOf6(e) ?? "") ? "EAI_NONAME" : void 0;
21461
21800
  }