@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/README.md +85 -3
- package/dist/kernel-worker.js +403 -59
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +109 -22
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +401 -57
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +109 -22
- package/dist/process-worker.js.map +4 -4
- package/package.json +1 -1
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
|
|
571
|
-
if (!
|
|
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
|
|
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)
|
|
9339
|
-
|
|
9340
|
-
|
|
9341
|
-
|
|
9342
|
-
|
|
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.
|
|
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
|
|
12688
|
-
if (!
|
|
12992
|
+
let lookup4 = this.pending.get(id2);
|
|
12993
|
+
if (!lookup4) {
|
|
12689
12994
|
const abort = new AbortController();
|
|
12690
|
-
|
|
12691
|
-
this.pending.set(id2,
|
|
12692
|
-
void
|
|
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(
|
|
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(
|
|
12736
|
-
|
|
13040
|
+
function waitFor(lookup4, signal) {
|
|
13041
|
+
lookup4.waiters++;
|
|
12737
13042
|
return new Promise((resolve2, reject) => {
|
|
12738
13043
|
const abort = () => {
|
|
12739
|
-
if (--
|
|
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
|
|
13048
|
+
void lookup4.work.then((value) => {
|
|
12744
13049
|
if (signal?.aborted) return;
|
|
12745
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
13715
|
+
return ok2();
|
|
13411
13716
|
case "sock-listen":
|
|
13412
13717
|
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
13413
|
-
return
|
|
13718
|
+
return ok2();
|
|
13414
13719
|
case "sock-accept":
|
|
13415
|
-
return
|
|
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
|
|
13730
|
+
return ok2();
|
|
13426
13731
|
}
|
|
13427
13732
|
case "sock-shutdown":
|
|
13428
13733
|
socketAt(fds, req.fd).shutdown(req.how);
|
|
13429
|
-
return
|
|
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
|
|
13739
|
+
return ok2(addr ?? unnamed(socket.domain));
|
|
13435
13740
|
}
|
|
13436
13741
|
case "sock-getopt":
|
|
13437
|
-
return
|
|
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
|
|
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
|
|
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
|
|
14658
|
+
const blocked2 = this.interrupt;
|
|
14350
14659
|
this.interrupt = new AbortController();
|
|
14351
|
-
|
|
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
|
|
14719
|
+
const blocked2 = this.interrupt;
|
|
14411
14720
|
this.interrupt = new AbortController();
|
|
14412
|
-
|
|
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
|
|
15692
|
+
const blocked2 = this.interrupt;
|
|
15376
15693
|
this.interrupt = new AbortController();
|
|
15377
|
-
|
|
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
|
|
15798
|
+
const blocked2 = thread.interrupt;
|
|
15482
15799
|
thread.interrupt = new AbortController();
|
|
15483
|
-
|
|
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
|
|
15663
|
-
if (
|
|
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
|
|
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(
|
|
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(
|
|
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 [
|
|
20476
|
-
const sigBlk =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
21802
|
+
await lookup3(host);
|
|
21459
21803
|
} catch (e) {
|
|
21460
21804
|
return NO_NAME.has(codeOf6(e) ?? "") ? "EAI_NONAME" : void 0;
|
|
21461
21805
|
}
|