@ai-ecoverse/slicc-kernel 1.94.4 → 1.95.1

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) {
@@ -9335,11 +9346,16 @@ var MountFs = class _MountFs {
9335
9346
  }
9336
9347
  async realpath(path, follow2) {
9337
9348
  const { realpath: realpath2 } = this.base;
9338
- if (this.at(path) || !realpath2) throw errnoError("ENOSYS", path);
9339
- const real = await realpath2.call(this.base, path, follow2).catch((err) => {
9340
- throw redirectOf(err) ? errnoError("ENOSYS", path) : err;
9341
- });
9342
- if (this.at(real)) throw errnoError("ENOSYS", path);
9349
+ if (!this.at(path) && realpath2) {
9350
+ const real2 = await realpath2.call(this.base, path, follow2).catch((err) => {
9351
+ if (redirectOf(err)) return void 0;
9352
+ throw err;
9353
+ });
9354
+ if (real2 !== void 0 && !this.at(real2)) return real2;
9355
+ }
9356
+ const real = follow2 ? await realTarget(this, normalizePath(path)) : await this.named(path);
9357
+ if (this.rejectLinks && real !== normalizePath(path)) throw errnoError("ELOOP", path);
9358
+ await this.lstat(real);
9343
9359
  return real;
9344
9360
  }
9345
9361
  async hasOwner(path) {
@@ -10643,7 +10659,7 @@ function mountTable(mounts = []) {
10643
10659
  }
10644
10660
 
10645
10661
  // src/version.ts
10646
- var KERNEL_VERSION = true ? "1.94.4" : "0.0.0-dev";
10662
+ var KERNEL_VERSION = true ? "1.95.1" : "0.0.0-dev";
10647
10663
  var OS_RELEASE = "6.0.0-slicc";
10648
10664
  function procVersion() {
10649
10665
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -11030,6 +11046,295 @@ async function procAlias(fs, path, follow2) {
11030
11046
  return step.value;
11031
11047
  }
11032
11048
 
11049
+ // src/kernel/eventfd.ts
11050
+ var EVENTFD_MAX = 0xfffffffffffffffen;
11051
+ var Notifier = class {
11052
+ waiters = [];
11053
+ wait(signal) {
11054
+ if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
11055
+ return new Promise((resolve2, reject) => {
11056
+ const onAbort = () => {
11057
+ this.waiters = this.waiters.filter((w) => w !== waiter);
11058
+ reject(new KernelError("EINTR"));
11059
+ };
11060
+ const waiter = () => {
11061
+ signal?.removeEventListener("abort", onAbort);
11062
+ resolve2();
11063
+ };
11064
+ this.waiters.push(waiter);
11065
+ signal?.addEventListener("abort", onAbort, { once: true });
11066
+ });
11067
+ }
11068
+ wake() {
11069
+ const waiters = this.waiters;
11070
+ this.waiters = [];
11071
+ for (const resolve2 of waiters) resolve2();
11072
+ }
11073
+ };
11074
+ function blocked(signal) {
11075
+ if (signal?.aborted) throw new KernelError("EAGAIN");
11076
+ }
11077
+ var EventFd = class _EventFd {
11078
+ static SIZE = 8;
11079
+ count;
11080
+ semaphore;
11081
+ changes = new Notifier();
11082
+ constructor(initial, semaphore) {
11083
+ this.count = initial;
11084
+ this.semaphore = semaphore;
11085
+ }
11086
+ async read(max, signal) {
11087
+ if (max < _EventFd.SIZE) throw new KernelError("EINVAL");
11088
+ while (this.count === 0n) {
11089
+ blocked(signal);
11090
+ await this.changes.wait(signal);
11091
+ }
11092
+ const value = this.semaphore ? 1n : this.count;
11093
+ this.count -= value;
11094
+ this.changes.wake();
11095
+ const out = new Uint8Array(_EventFd.SIZE);
11096
+ new DataView(out.buffer).setBigUint64(0, value, true);
11097
+ return out;
11098
+ }
11099
+ async write(bytes, signal) {
11100
+ if (bytes.length < _EventFd.SIZE) throw new KernelError("EINVAL");
11101
+ const value = new DataView(bytes.buffer, bytes.byteOffset, _EventFd.SIZE).getBigUint64(0, true);
11102
+ if (value > EVENTFD_MAX) throw new KernelError("EINVAL");
11103
+ while (EVENTFD_MAX - this.count < value) {
11104
+ blocked(signal);
11105
+ await this.changes.wait(signal);
11106
+ }
11107
+ this.count += value;
11108
+ if (value > 0n) this.changes.wake();
11109
+ return _EventFd.SIZE;
11110
+ }
11111
+ poll() {
11112
+ return { readable: this.count > 0n, writable: this.count < EVENTFD_MAX, hangup: false };
11113
+ }
11114
+ changed(signal) {
11115
+ return this.changes.wait(signal);
11116
+ }
11117
+ close() {
11118
+ this.changes.wake();
11119
+ }
11120
+ };
11121
+
11122
+ // src/kernel/epoll.ts
11123
+ var EPOLL = {
11124
+ IN: 1,
11125
+ OUT: 2,
11126
+ RDHUP: 4,
11127
+ PRI: 8,
11128
+ ERR: 16,
11129
+ HUP: 32,
11130
+ ET: 64,
11131
+ ONESHOT: 128
11132
+ };
11133
+ var ALWAYS = EPOLL.ERR | EPOLL.HUP;
11134
+ var ASKED = EPOLL.IN | EPOLL.OUT | EPOLL.RDHUP;
11135
+ var RETRY_MS = 50;
11136
+ var UNPOLLABLE = /* @__PURE__ */ new Set(["file", "held", "device"]);
11137
+ var EPOLL_OPS = [
11138
+ "epoll-create",
11139
+ "epoll-ctl",
11140
+ "epoll-wait",
11141
+ "eventfd-open"
11142
+ ];
11143
+ function levelOf(file) {
11144
+ const state = pollFile(file);
11145
+ let bits2 = 0;
11146
+ if (state.readable) bits2 |= EPOLL.IN;
11147
+ if (state.writable) bits2 |= EPOLL.OUT;
11148
+ if (state.rdhup) bits2 |= EPOLL.RDHUP;
11149
+ if (state.hangup) bits2 |= file.read ? EPOLL.HUP : EPOLL.ERR;
11150
+ return bits2;
11151
+ }
11152
+ function due(interest, level) {
11153
+ if (!interest.armed) return 0;
11154
+ const ready2 = level & (interest.events & ASKED | ALWAYS);
11155
+ if (ready2 === 0) return 0;
11156
+ if ((interest.events & EPOLL.ET) !== 0 && interest.reported === interest.gen) return 0;
11157
+ return ready2;
11158
+ }
11159
+ function consume(interest) {
11160
+ interest.reported = interest.gen;
11161
+ if ((interest.events & EPOLL.ONESHOT) !== 0) interest.armed = false;
11162
+ }
11163
+ function lookup(fds, fd) {
11164
+ try {
11165
+ return fds.get(fd);
11166
+ } catch {
11167
+ return void 0;
11168
+ }
11169
+ }
11170
+ function pause(ms, signal) {
11171
+ return new Promise((resolve2) => {
11172
+ const timer = setTimeout(resolve2, ms);
11173
+ signal.addEventListener(
11174
+ "abort",
11175
+ () => {
11176
+ clearTimeout(timer);
11177
+ resolve2();
11178
+ },
11179
+ { once: true }
11180
+ );
11181
+ });
11182
+ }
11183
+ var EpollFile = class _EpollFile {
11184
+ regs = /* @__PURE__ */ new Map();
11185
+ changes = new Notifier();
11186
+ cursor = 0;
11187
+ ctl(fds, how, fd, events, data) {
11188
+ const open = fds.get(fd);
11189
+ if (open.file === this) throw new KernelError("EINVAL");
11190
+ const known = this.regs.get(fd);
11191
+ const current = known?.open === open ? known : void 0;
11192
+ if (how === "add" || how === "set" && !current) {
11193
+ if (current) throw new KernelError("EEXIST");
11194
+ if (UNPOLLABLE.has(kernelFdKind(open.file))) throw new KernelError("EPERM");
11195
+ if (open.file instanceof _EpollFile && open.file.reaches(this)) throw new KernelError("ELOOP");
11196
+ if (known) this.drop(known);
11197
+ this.register(fd, open, events, data);
11198
+ } else if (!current) {
11199
+ throw new KernelError("ENOENT");
11200
+ } else if (how === "del") {
11201
+ this.drop(current);
11202
+ } else {
11203
+ current.events = events;
11204
+ current.data = data;
11205
+ current.armed = true;
11206
+ current.gen++;
11207
+ }
11208
+ this.changes.wake();
11209
+ }
11210
+ reaches(target) {
11211
+ if (this === target) return true;
11212
+ return [...this.regs.values()].some(
11213
+ (reg) => reg.open.file instanceof _EpollFile && reg.open.file.reaches(target)
11214
+ );
11215
+ }
11216
+ collect(fds, max) {
11217
+ const list = [...this.regs.values()];
11218
+ const out = [];
11219
+ const start2 = list.length === 0 ? 0 : this.cursor % list.length;
11220
+ for (let i = 0; i < list.length && out.length < max; i++) {
11221
+ const reg = list[(start2 + i) % list.length];
11222
+ if (lookup(fds, reg.fd) !== reg.open) {
11223
+ this.drop(reg);
11224
+ continue;
11225
+ }
11226
+ const bits2 = due(reg, levelOf(reg.open.file));
11227
+ if (bits2 === 0) continue;
11228
+ consume(reg);
11229
+ out.push({ events: bits2, data: reg.data });
11230
+ this.cursor = start2 + i + 1;
11231
+ }
11232
+ return out;
11233
+ }
11234
+ async wait(fds, max, timeoutMs, signal) {
11235
+ const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
11236
+ for (; ; ) {
11237
+ const events = this.collect(fds, max);
11238
+ if (events.length > 0 || Date.now() >= deadline) return events;
11239
+ const round = new AbortController();
11240
+ const woken = this.changes.wait(AbortSignal.any([round.signal, signal]));
11241
+ woken.catch(() => void 0);
11242
+ let timer;
11243
+ const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
11244
+ try {
11245
+ await Promise.race([woken, ...expiry]);
11246
+ } finally {
11247
+ round.abort();
11248
+ clearTimeout(timer);
11249
+ }
11250
+ }
11251
+ }
11252
+ poll() {
11253
+ const ready2 = [...this.regs.values()].some((reg) => due(reg, levelOf(reg.open.file)) !== 0);
11254
+ return { readable: ready2, writable: false, hangup: false };
11255
+ }
11256
+ changed(signal) {
11257
+ return this.changes.wait(signal);
11258
+ }
11259
+ close() {
11260
+ for (const reg of [...this.regs.values()]) this.drop(reg);
11261
+ this.changes.wake();
11262
+ }
11263
+ register(fd, open, events, data) {
11264
+ const stop = new AbortController();
11265
+ const unhook = open.onClose(() => {
11266
+ this.drop(reg);
11267
+ this.changes.wake();
11268
+ });
11269
+ const reg = {
11270
+ fd,
11271
+ open,
11272
+ events,
11273
+ data,
11274
+ gen: 1,
11275
+ reported: 0,
11276
+ armed: true,
11277
+ stop,
11278
+ unhook
11279
+ };
11280
+ this.regs.set(fd, reg);
11281
+ void this.watch(reg);
11282
+ }
11283
+ drop(reg) {
11284
+ reg.stop.abort();
11285
+ reg.unhook();
11286
+ if (this.regs.get(reg.fd) === reg) this.regs.delete(reg.fd);
11287
+ }
11288
+ async watch(reg) {
11289
+ const file = reg.open.file;
11290
+ const { signal } = reg.stop;
11291
+ while (file.changed && !signal.aborted) {
11292
+ const round = new AbortController();
11293
+ const stop = () => round.abort();
11294
+ signal.addEventListener("abort", stop, { once: true });
11295
+ let failed3 = false;
11296
+ try {
11297
+ await file.changed(round.signal);
11298
+ } catch {
11299
+ failed3 = true;
11300
+ } finally {
11301
+ round.abort();
11302
+ signal.removeEventListener("abort", stop);
11303
+ }
11304
+ if (signal.aborted) return;
11305
+ reg.gen++;
11306
+ this.changes.wake();
11307
+ if (failed3) await pause(RETRY_MS, signal);
11308
+ }
11309
+ }
11310
+ };
11311
+ function epollAt(fds, fd) {
11312
+ const file = fds.get(fd).file;
11313
+ if (!(file instanceof EpollFile)) throw new KernelError("EINVAL");
11314
+ return file;
11315
+ }
11316
+ var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
11317
+ async function epollSyscall(req, proc) {
11318
+ const { fds } = proc;
11319
+ switch (req.op) {
11320
+ case "epoll-create":
11321
+ return ok(fds.install(new OpenFile(new EpollFile()), 3));
11322
+ case "eventfd-open":
11323
+ return ok(fds.install(new OpenFile(new EventFd(BigInt(req.initial), req.semaphore)), 3));
11324
+ case "epoll-ctl":
11325
+ epollAt(fds, req.epfd).ctl(fds, req.how, req.fd, req.events, req.data);
11326
+ return ok();
11327
+ case "epoll-wait": {
11328
+ const ep = epollAt(fds, req.epfd);
11329
+ if (req.timeoutMs === 0 || proc.owed()) {
11330
+ const now = ep.collect(fds, req.max);
11331
+ if (req.timeoutMs === 0 || now.length > 0) return ok(now);
11332
+ }
11333
+ return ok(await ep.wait(fds, req.max, req.timeoutMs, proc.blocking()));
11334
+ }
11335
+ }
11336
+ }
11337
+
11033
11338
  // src/kernel/host-ops.ts
11034
11339
  var HOST_OPS = [
11035
11340
  "lock",
@@ -12684,14 +12989,14 @@ var Resolver = class {
12684
12989
  if (hit && hit.expires > this.now()) return hit.addresses;
12685
12990
  const signal = blocking?.();
12686
12991
  if (signal?.aborted) throw new KernelError("EINTR");
12687
- let lookup3 = this.pending.get(id2);
12688
- if (!lookup3) {
12992
+ let lookup4 = this.pending.get(id2);
12993
+ if (!lookup4) {
12689
12994
  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));
12995
+ lookup4 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
12996
+ this.pending.set(id2, lookup4);
12997
+ void lookup4.work.then(() => this.pending.delete(id2));
12693
12998
  }
12694
- return waitFor(lookup3, signal);
12999
+ return waitFor(lookup4, signal);
12695
13000
  }
12696
13001
  async lookup(name2, family, id2, abandoned) {
12697
13002
  const uplink = this.uplink;
@@ -12732,17 +13037,17 @@ var Resolver = class {
12732
13037
  }
12733
13038
  }
12734
13039
  };
12735
- function waitFor(lookup3, signal) {
12736
- lookup3.waiters++;
13040
+ function waitFor(lookup4, signal) {
13041
+ lookup4.waiters++;
12737
13042
  return new Promise((resolve2, reject) => {
12738
13043
  const abort = () => {
12739
- if (--lookup3.waiters === 0) lookup3.abort.abort(new KernelError("EINTR"));
13044
+ if (--lookup4.waiters === 0) lookup4.abort.abort(new KernelError("EINTR"));
12740
13045
  reject(new KernelError("EINTR"));
12741
13046
  };
12742
13047
  signal?.addEventListener("abort", abort, { once: true });
12743
- void lookup3.work.then((value) => {
13048
+ void lookup4.work.then((value) => {
12744
13049
  if (signal?.aborted) return;
12745
- lookup3.waiters--;
13050
+ lookup4.waiters--;
12746
13051
  signal?.removeEventListener("abort", abort);
12747
13052
  resolve2(value);
12748
13053
  });
@@ -13389,17 +13694,17 @@ function socketAt(fds, fd) {
13389
13694
  if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
13390
13695
  return file;
13391
13696
  }
13392
- var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
13697
+ var ok2 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
13393
13698
  async function socketSyscall(req, proc) {
13394
13699
  const { fds, net } = proc;
13395
13700
  switch (req.op) {
13396
13701
  case "sock-open":
13397
- return ok(fds.install(new OpenFile(net.socket(req.domain)), 3));
13702
+ return ok2(fds.install(new OpenFile(net.socket(req.domain)), 3));
13398
13703
  case "sock-pair": {
13399
13704
  const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
13400
13705
  const first = fds.install(new OpenFile(a), 3);
13401
13706
  try {
13402
- return ok([first, fds.install(new OpenFile(b), 3)]);
13707
+ return ok2([first, fds.install(new OpenFile(b), 3)]);
13403
13708
  } catch (e) {
13404
13709
  await Promise.resolve(fds.close(first));
13405
13710
  throw e;
@@ -13407,12 +13712,12 @@ async function socketSyscall(req, proc) {
13407
13712
  }
13408
13713
  case "sock-bind":
13409
13714
  socketAt(fds, req.fd).bind(req.addr);
13410
- return ok();
13715
+ return ok2();
13411
13716
  case "sock-listen":
13412
13717
  socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
13413
- return ok();
13718
+ return ok2();
13414
13719
  case "sock-accept":
13415
- return ok(await accept(proc, req.fd, req.nonblock));
13720
+ return ok2(await accept(proc, req.fd, req.nonblock));
13416
13721
  case "sock-connect": {
13417
13722
  const socket = socketAt(fds, req.fd);
13418
13723
  const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
@@ -13422,26 +13727,26 @@ async function socketSyscall(req, proc) {
13422
13727
  throw new KernelError("EINPROGRESS");
13423
13728
  }
13424
13729
  if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
13425
- return ok();
13730
+ return ok2();
13426
13731
  }
13427
13732
  case "sock-shutdown":
13428
13733
  socketAt(fds, req.fd).shutdown(req.how);
13429
- return ok();
13734
+ return ok2();
13430
13735
  case "sock-name": {
13431
13736
  const socket = socketAt(fds, req.fd);
13432
13737
  const addr = req.peer ? socket.peer : socket.local;
13433
13738
  if (req.peer && !addr) throw new KernelError("ENOTCONN");
13434
- return ok(addr ?? unnamed(socket.domain));
13739
+ return ok2(addr ?? unnamed(socket.domain));
13435
13740
  }
13436
13741
  case "sock-getopt":
13437
- return ok(socketAt(fds, req.fd).getOption(req.level, req.name));
13742
+ return ok2(socketAt(fds, req.fd).getOption(req.level, req.name));
13438
13743
  case "sock-setopt":
13439
13744
  socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
13440
- return ok();
13745
+ return ok2();
13441
13746
  case "sock-resolve": {
13442
13747
  const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
13443
13748
  if (addresses.length === 0) throw new KernelError("ENOENT");
13444
- return ok(addresses);
13749
+ return ok2(addresses);
13445
13750
  }
13446
13751
  }
13447
13752
  }
@@ -14142,6 +14447,9 @@ function isHttpSyscall(req) {
14142
14447
  function isSocketSyscall(req) {
14143
14448
  return req.op.startsWith("sock-");
14144
14449
  }
14450
+ function isEpollSyscall(req) {
14451
+ return EPOLL_OPS.includes(req.op);
14452
+ }
14145
14453
  function isHostSyscall(req) {
14146
14454
  return HOST_OPS.includes(req.op);
14147
14455
  }
@@ -14232,6 +14540,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
14232
14540
  "sig-mask",
14233
14541
  "sig-pause",
14234
14542
  ...SOCKET_OPS,
14543
+ ...EPOLL_OPS,
14235
14544
  ...HTTP_OPS,
14236
14545
  ...PTY_OPS,
14237
14546
  ...HOST_OPS
@@ -14346,9 +14655,9 @@ var WasmProcess = class {
14346
14655
  this.options.onPending?.(sig);
14347
14656
  if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
14348
14657
  this.owed = true;
14349
- const blocked = this.interrupt;
14658
+ const blocked2 = this.interrupt;
14350
14659
  this.interrupt = new AbortController();
14351
- blocked.abort();
14660
+ blocked2.abort();
14352
14661
  return "deliver";
14353
14662
  }
14354
14663
  async spawn(req) {
@@ -14407,9 +14716,9 @@ var WasmProcess = class {
14407
14716
  this.stopped = sig;
14408
14717
  this.stops++;
14409
14718
  this.resumed = new Promise((resolve2) => this.wake = resolve2);
14410
- const blocked = this.interrupt;
14719
+ const blocked2 = this.interrupt;
14411
14720
  this.interrupt = new AbortController();
14412
- blocked.abort();
14721
+ blocked2.abort();
14413
14722
  for (const listener of this.stateListeners) listener("stopped", sig);
14414
14723
  return "stop";
14415
14724
  }
@@ -14459,6 +14768,13 @@ var WasmProcess = class {
14459
14768
  if (isTtySyscall(req)) return this.ttySyscall(req);
14460
14769
  if (isJobSyscall(req)) return this.jobSyscall(req);
14461
14770
  if (isSocketSyscall(req)) return await this.socketSyscall(req, cancelled);
14771
+ if (isEpollSyscall(req)) {
14772
+ return await epollSyscall(req, {
14773
+ fds: this.fds,
14774
+ blocking: () => this.blockingSignal(cancelled),
14775
+ owed: () => this.owed
14776
+ });
14777
+ }
14462
14778
  if (isHttpSyscall(req)) return await this.httpSyscall(req);
14463
14779
  if (isHostSyscall(req)) {
14464
14780
  return await hostSyscall(req, {
@@ -14525,6 +14841,7 @@ var WasmProcess = class {
14525
14841
  if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
14526
14842
  if (file.tty) this.checkForeground(file.tty);
14527
14843
  if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
14844
+ if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
14528
14845
  if (req.max <= 0) return new Uint8Array(0);
14529
14846
  if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
14530
14847
  const ready2 = pollFile(file).readable;
@@ -15372,9 +15689,9 @@ var WasmProcess = class {
15372
15689
  }
15373
15690
  timerExpired(which) {
15374
15691
  this.options.onTimer?.(which);
15375
- const blocked = this.interrupt;
15692
+ const blocked2 = this.interrupt;
15376
15693
  this.interrupt = new AbortController();
15377
- blocked.abort();
15694
+ blocked2.abort();
15378
15695
  }
15379
15696
  clearAlarm() {
15380
15697
  clearTimeout(this.alarm);
@@ -15478,9 +15795,9 @@ function killThread(thread, caught, sig) {
15478
15795
  Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
15479
15796
  if (held) return true;
15480
15797
  Atomics.notify(thread.header, SAB_I_SIGNALS);
15481
- const blocked = thread.interrupt;
15798
+ const blocked2 = thread.interrupt;
15482
15799
  thread.interrupt = new AbortController();
15483
- blocked.abort();
15800
+ blocked2.abort();
15484
15801
  return true;
15485
15802
  }
15486
15803
  function unblocked(header4) {
@@ -15659,8 +15976,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
15659
15976
  function spawnWasmProcess(opts) {
15660
15977
  const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
15661
15978
  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);
15979
+ const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
15980
+ if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header4, blocked2);
15664
15981
  const threadSignals = /* @__PURE__ */ new Map();
15665
15982
  const created3 = new Created();
15666
15983
  const process2 = new WasmProcess(
@@ -19618,6 +19935,8 @@ var Launcher = class {
19618
19935
  const head = await this.head(glue);
19619
19936
  if (!head) return void 0;
19620
19937
  if (isWasm(head)) {
19938
+ const owner2 = await this.wasmOwner(glue, baseName(file).replace(/\.wasm$/, ""), scope);
19939
+ if (owner2) return { ...targetOf(owner2), ...asked };
19621
19940
  return {
19622
19941
  abi: "wasi",
19623
19942
  glue,
@@ -19640,6 +19959,17 @@ var Launcher = class {
19640
19959
  );
19641
19960
  return owners.find((c) => c.name === name2) ?? owners[0];
19642
19961
  }
19962
+ async wasmOwner(wasm, name2, scope) {
19963
+ const leaf = baseName(wasm);
19964
+ const real = await physicalPathAsync(this.base, wasm);
19965
+ const owners = [];
19966
+ for (const command of (await this.commands(scope)).values()) {
19967
+ if (command.abi !== "wasi" || command.script || baseName(command.wasm) !== leaf) continue;
19968
+ if (command.wasm === wasm || await physicalPathAsync(this.base, command.wasm) === real)
19969
+ owners.push(command);
19970
+ }
19971
+ return owners.find((c) => c.name === name2) ?? owners[0];
19972
+ }
19643
19973
  async head(path) {
19644
19974
  try {
19645
19975
  return (await this.base.readFileBuffer(path)).subarray(0, SHEBANG_MAX);
@@ -19727,16 +20057,29 @@ var Launcher = class {
19727
20057
  for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
19728
20058
  }
19729
20059
  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) {
20060
+ const refused2 = async (err) => {
19734
20061
  await fds.closeAll();
19735
20062
  throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
19736
- }
20063
+ };
20064
+ const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused2);
20065
+ const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
20066
+ await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused2);
19737
20067
  if (planned) return planned;
19738
20068
  await fds.closeAll();
19739
- throw new SpawnError(await this.unrunnable(req.file, req.cwd, scope));
20069
+ throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
20070
+ }
20071
+ execGuard(cred, pid, tag) {
20072
+ const { dac } = this;
20073
+ return dac && { fs: this.fs, cred, pid, dac, tag, links: this.links.get(pid) };
20074
+ }
20075
+ async execFile(file, cwd, g) {
20076
+ if (!file.split("/").includes("..")) return file;
20077
+ const path = file.startsWith("/") ? file : `${cwd}/${file}`;
20078
+ const slash = path.lastIndexOf("/");
20079
+ const dir = path.slice(0, slash);
20080
+ const walked = g && await need(g, "exec", dir, X_OK, { directory: true });
20081
+ const real = walked && walked.denied === void 0 ? walked.path : await physicalPathAsync(this.base, dir);
20082
+ return joinName(real, path.slice(slash + 1));
19740
20083
  }
19741
20084
  async ticketFile(req, fds) {
19742
20085
  if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
@@ -19835,7 +20178,8 @@ var Launcher = class {
19835
20178
  }
19836
20179
  return manifests;
19837
20180
  }
19838
- async backing(file, cwd) {
20181
+ async backing(asked, cwd) {
20182
+ const file = await this.execFile(asked, cwd);
19839
20183
  const planned = await this.plan(file, [file], cwd, "");
19840
20184
  return planned && this.backingOf(planned, file, cwd, "");
19841
20185
  }
@@ -20472,8 +20816,8 @@ var Launcher = class {
20472
20816
  }
20473
20817
  signalMasksOf(pid) {
20474
20818
  const masks = this.processes.get(pid)?.signalMasks?.();
20475
- const [blocked] = this.blockedBy(pid);
20476
- const sigBlk = blocked ? { sigBlk: blocked } : {};
20819
+ const [blocked2] = this.blockedBy(pid);
20820
+ const sigBlk = blocked2 ? { sigBlk: blocked2 } : {};
20477
20821
  return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
20478
20822
  }
20479
20823
  controlsJobs(pid) {
@@ -20921,7 +21265,7 @@ var Launcher = class {
20921
21265
  const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
20922
21266
  const start2 = dir ?? "/";
20923
21267
  const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
20924
- const [file = ""] = argv;
21268
+ const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
20925
21269
  if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
20926
21270
  const planned = await this.plan(file, argv, cwd, scope);
20927
21271
  await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
@@ -21024,11 +21368,11 @@ var Launcher = class {
21024
21368
  // src/node/loopback.ts
21025
21369
  import { AsyncLocalStorage } from "node:async_hooks";
21026
21370
  import { subscribe } from "node:diagnostics_channel";
21027
- import { lookup } from "node:dns/promises";
21371
+ import { lookup as lookup2 } from "node:dns/promises";
21028
21372
  import { isIP } from "node:net";
21029
21373
  var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
21030
21374
  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);
21375
+ var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
21032
21376
  function ipv4Place(address) {
21033
21377
  const [a, b] = address.split(".").map(Number);
21034
21378
  if (a === 127 || a === 0) return "loopback";
@@ -21423,7 +21767,7 @@ function isMemoryRoot(handle) {
21423
21767
  }
21424
21768
 
21425
21769
  // src/node/ws-diagnose.ts
21426
- import { lookup as lookup2 } from "node:dns/promises";
21770
+ import { lookup as lookup3 } from "node:dns/promises";
21427
21771
  import { isIP as isIP2, connect as tcp } from "node:net";
21428
21772
  import { connect as tls } from "node:tls";
21429
21773
  var PROBE_MS = 3e3;
@@ -21455,7 +21799,7 @@ async function diagnose(url, ms = PROBE_MS) {
21455
21799
  const secure = at.protocol === "wss:";
21456
21800
  const port = Number(at.port) || (secure ? 443 : 80);
21457
21801
  try {
21458
- await lookup2(host);
21802
+ await lookup3(host);
21459
21803
  } catch (e) {
21460
21804
  return NO_NAME.has(codeOf6(e) ?? "") ? "EAI_NONAME" : void 0;
21461
21805
  }