@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/kernel-worker.js
CHANGED
|
@@ -2581,8 +2581,8 @@ async function inParent(g, op, path, old = false) {
|
|
|
2581
2581
|
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, linked(g, DIR));
|
|
2582
2582
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
2583
2583
|
if (dir.link) return deny(g, op, dir.denied);
|
|
2584
|
-
const
|
|
2585
|
-
if (!
|
|
2584
|
+
const lookup2 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
2585
|
+
if (!lookup2 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
2586
2586
|
}
|
|
2587
2587
|
async function makeIn(g, op, path) {
|
|
2588
2588
|
for (let dir = parentOf4(path); ; dir = parentOf4(dir)) {
|
|
@@ -2902,6 +2902,7 @@ function pollFile(file) {
|
|
|
2902
2902
|
}
|
|
2903
2903
|
var OpenFile = class {
|
|
2904
2904
|
refs = 1;
|
|
2905
|
+
closers;
|
|
2905
2906
|
file;
|
|
2906
2907
|
constructor(file) {
|
|
2907
2908
|
this.file = file;
|
|
@@ -2910,9 +2911,18 @@ var OpenFile = class {
|
|
|
2910
2911
|
this.refs += 1;
|
|
2911
2912
|
return this;
|
|
2912
2913
|
}
|
|
2914
|
+
onClose(fn) {
|
|
2915
|
+
this.closers ??= /* @__PURE__ */ new Set();
|
|
2916
|
+
this.closers.add(fn);
|
|
2917
|
+
return () => void this.closers?.delete(fn);
|
|
2918
|
+
}
|
|
2913
2919
|
release() {
|
|
2914
2920
|
this.refs -= 1;
|
|
2915
|
-
if (this.refs
|
|
2921
|
+
if (this.refs !== 0) return;
|
|
2922
|
+
const closers = this.closers;
|
|
2923
|
+
this.closers = void 0;
|
|
2924
|
+
for (const fn of closers ?? []) fn();
|
|
2925
|
+
return this.file.close();
|
|
2916
2926
|
}
|
|
2917
2927
|
};
|
|
2918
2928
|
function openPipe(capacity) {
|
|
@@ -3460,7 +3470,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
3460
3470
|
return {
|
|
3461
3471
|
readable: this.readShut || rx.readReady,
|
|
3462
3472
|
writable: this.writeShut || tx.writeReady,
|
|
3463
|
-
hangup: rx.writersGone && tx.readersGone
|
|
3473
|
+
hangup: rx.writersGone && tx.readersGone,
|
|
3474
|
+
rdhup: rx.writersGone
|
|
3464
3475
|
};
|
|
3465
3476
|
}
|
|
3466
3477
|
changed(signal) {
|
|
@@ -5139,7 +5150,7 @@ function clipboardAsker(port) {
|
|
|
5139
5150
|
function integrityAsker(port) {
|
|
5140
5151
|
const asks = /* @__PURE__ */ new Map();
|
|
5141
5152
|
let next2 = 0;
|
|
5142
|
-
const
|
|
5153
|
+
const lookup2 = (path) => {
|
|
5143
5154
|
const id2 = ++next2;
|
|
5144
5155
|
const waiting = Promise.withResolvers();
|
|
5145
5156
|
asks.set(id2, waiting);
|
|
@@ -5153,7 +5164,7 @@ function integrityAsker(port) {
|
|
|
5153
5164
|
if (error !== void 0) waiting.reject(new Error(error));
|
|
5154
5165
|
else waiting.resolve(hash);
|
|
5155
5166
|
};
|
|
5156
|
-
return { lookup, answer };
|
|
5167
|
+
return { lookup: lookup2, answer };
|
|
5157
5168
|
}
|
|
5158
5169
|
|
|
5159
5170
|
// src/kernel/net/loopback-names.ts
|
|
@@ -10404,11 +10415,16 @@ var MountFs = class _MountFs {
|
|
|
10404
10415
|
}
|
|
10405
10416
|
async realpath(path, follow2) {
|
|
10406
10417
|
const { realpath: realpath2 } = this.base;
|
|
10407
|
-
if (this.at(path)
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10418
|
+
if (!this.at(path) && realpath2) {
|
|
10419
|
+
const real2 = await realpath2.call(this.base, path, follow2).catch((err) => {
|
|
10420
|
+
if (redirectOf(err)) return void 0;
|
|
10421
|
+
throw err;
|
|
10422
|
+
});
|
|
10423
|
+
if (real2 !== void 0 && !this.at(real2)) return real2;
|
|
10424
|
+
}
|
|
10425
|
+
const real = follow2 ? await realTarget(this, normalizePath(path)) : await this.named(path);
|
|
10426
|
+
if (this.rejectLinks && real !== normalizePath(path)) throw errnoError("ELOOP", path);
|
|
10427
|
+
await this.lstat(real);
|
|
10412
10428
|
return real;
|
|
10413
10429
|
}
|
|
10414
10430
|
async hasOwner(path) {
|
|
@@ -11712,7 +11728,7 @@ function mountTable(mounts = []) {
|
|
|
11712
11728
|
}
|
|
11713
11729
|
|
|
11714
11730
|
// src/version.ts
|
|
11715
|
-
var KERNEL_VERSION = true ? "1.
|
|
11731
|
+
var KERNEL_VERSION = true ? "1.95.1" : "0.0.0-dev";
|
|
11716
11732
|
var OS_RELEASE = "6.0.0-slicc";
|
|
11717
11733
|
function procVersion() {
|
|
11718
11734
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -12099,6 +12115,295 @@ async function procAlias(fs, path, follow2) {
|
|
|
12099
12115
|
return step.value;
|
|
12100
12116
|
}
|
|
12101
12117
|
|
|
12118
|
+
// src/kernel/eventfd.ts
|
|
12119
|
+
var EVENTFD_MAX = 0xfffffffffffffffen;
|
|
12120
|
+
var Notifier = class {
|
|
12121
|
+
waiters = [];
|
|
12122
|
+
wait(signal) {
|
|
12123
|
+
if (signal?.aborted) return Promise.reject(new KernelError("EINTR"));
|
|
12124
|
+
return new Promise((resolve2, reject) => {
|
|
12125
|
+
const onAbort = () => {
|
|
12126
|
+
this.waiters = this.waiters.filter((w) => w !== waiter);
|
|
12127
|
+
reject(new KernelError("EINTR"));
|
|
12128
|
+
};
|
|
12129
|
+
const waiter = () => {
|
|
12130
|
+
signal?.removeEventListener("abort", onAbort);
|
|
12131
|
+
resolve2();
|
|
12132
|
+
};
|
|
12133
|
+
this.waiters.push(waiter);
|
|
12134
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
12135
|
+
});
|
|
12136
|
+
}
|
|
12137
|
+
wake() {
|
|
12138
|
+
const waiters = this.waiters;
|
|
12139
|
+
this.waiters = [];
|
|
12140
|
+
for (const resolve2 of waiters) resolve2();
|
|
12141
|
+
}
|
|
12142
|
+
};
|
|
12143
|
+
function blocked(signal) {
|
|
12144
|
+
if (signal?.aborted) throw new KernelError("EAGAIN");
|
|
12145
|
+
}
|
|
12146
|
+
var EventFd = class _EventFd {
|
|
12147
|
+
static SIZE = 8;
|
|
12148
|
+
count;
|
|
12149
|
+
semaphore;
|
|
12150
|
+
changes = new Notifier();
|
|
12151
|
+
constructor(initial, semaphore) {
|
|
12152
|
+
this.count = initial;
|
|
12153
|
+
this.semaphore = semaphore;
|
|
12154
|
+
}
|
|
12155
|
+
async read(max, signal) {
|
|
12156
|
+
if (max < _EventFd.SIZE) throw new KernelError("EINVAL");
|
|
12157
|
+
while (this.count === 0n) {
|
|
12158
|
+
blocked(signal);
|
|
12159
|
+
await this.changes.wait(signal);
|
|
12160
|
+
}
|
|
12161
|
+
const value = this.semaphore ? 1n : this.count;
|
|
12162
|
+
this.count -= value;
|
|
12163
|
+
this.changes.wake();
|
|
12164
|
+
const out = new Uint8Array(_EventFd.SIZE);
|
|
12165
|
+
new DataView(out.buffer).setBigUint64(0, value, true);
|
|
12166
|
+
return out;
|
|
12167
|
+
}
|
|
12168
|
+
async write(bytes, signal) {
|
|
12169
|
+
if (bytes.length < _EventFd.SIZE) throw new KernelError("EINVAL");
|
|
12170
|
+
const value = new DataView(bytes.buffer, bytes.byteOffset, _EventFd.SIZE).getBigUint64(0, true);
|
|
12171
|
+
if (value > EVENTFD_MAX) throw new KernelError("EINVAL");
|
|
12172
|
+
while (EVENTFD_MAX - this.count < value) {
|
|
12173
|
+
blocked(signal);
|
|
12174
|
+
await this.changes.wait(signal);
|
|
12175
|
+
}
|
|
12176
|
+
this.count += value;
|
|
12177
|
+
if (value > 0n) this.changes.wake();
|
|
12178
|
+
return _EventFd.SIZE;
|
|
12179
|
+
}
|
|
12180
|
+
poll() {
|
|
12181
|
+
return { readable: this.count > 0n, writable: this.count < EVENTFD_MAX, hangup: false };
|
|
12182
|
+
}
|
|
12183
|
+
changed(signal) {
|
|
12184
|
+
return this.changes.wait(signal);
|
|
12185
|
+
}
|
|
12186
|
+
close() {
|
|
12187
|
+
this.changes.wake();
|
|
12188
|
+
}
|
|
12189
|
+
};
|
|
12190
|
+
|
|
12191
|
+
// src/kernel/epoll.ts
|
|
12192
|
+
var EPOLL = {
|
|
12193
|
+
IN: 1,
|
|
12194
|
+
OUT: 2,
|
|
12195
|
+
RDHUP: 4,
|
|
12196
|
+
PRI: 8,
|
|
12197
|
+
ERR: 16,
|
|
12198
|
+
HUP: 32,
|
|
12199
|
+
ET: 64,
|
|
12200
|
+
ONESHOT: 128
|
|
12201
|
+
};
|
|
12202
|
+
var ALWAYS = EPOLL.ERR | EPOLL.HUP;
|
|
12203
|
+
var ASKED = EPOLL.IN | EPOLL.OUT | EPOLL.RDHUP;
|
|
12204
|
+
var RETRY_MS = 50;
|
|
12205
|
+
var UNPOLLABLE = /* @__PURE__ */ new Set(["file", "held", "device"]);
|
|
12206
|
+
var EPOLL_OPS = [
|
|
12207
|
+
"epoll-create",
|
|
12208
|
+
"epoll-ctl",
|
|
12209
|
+
"epoll-wait",
|
|
12210
|
+
"eventfd-open"
|
|
12211
|
+
];
|
|
12212
|
+
function levelOf(file) {
|
|
12213
|
+
const state = pollFile(file);
|
|
12214
|
+
let bits2 = 0;
|
|
12215
|
+
if (state.readable) bits2 |= EPOLL.IN;
|
|
12216
|
+
if (state.writable) bits2 |= EPOLL.OUT;
|
|
12217
|
+
if (state.rdhup) bits2 |= EPOLL.RDHUP;
|
|
12218
|
+
if (state.hangup) bits2 |= file.read ? EPOLL.HUP : EPOLL.ERR;
|
|
12219
|
+
return bits2;
|
|
12220
|
+
}
|
|
12221
|
+
function due(interest, level) {
|
|
12222
|
+
if (!interest.armed) return 0;
|
|
12223
|
+
const ready2 = level & (interest.events & ASKED | ALWAYS);
|
|
12224
|
+
if (ready2 === 0) return 0;
|
|
12225
|
+
if ((interest.events & EPOLL.ET) !== 0 && interest.reported === interest.gen) return 0;
|
|
12226
|
+
return ready2;
|
|
12227
|
+
}
|
|
12228
|
+
function consume(interest) {
|
|
12229
|
+
interest.reported = interest.gen;
|
|
12230
|
+
if ((interest.events & EPOLL.ONESHOT) !== 0) interest.armed = false;
|
|
12231
|
+
}
|
|
12232
|
+
function lookup(fds, fd) {
|
|
12233
|
+
try {
|
|
12234
|
+
return fds.get(fd);
|
|
12235
|
+
} catch {
|
|
12236
|
+
return void 0;
|
|
12237
|
+
}
|
|
12238
|
+
}
|
|
12239
|
+
function pause(ms, signal) {
|
|
12240
|
+
return new Promise((resolve2) => {
|
|
12241
|
+
const timer = setTimeout(resolve2, ms);
|
|
12242
|
+
signal.addEventListener(
|
|
12243
|
+
"abort",
|
|
12244
|
+
() => {
|
|
12245
|
+
clearTimeout(timer);
|
|
12246
|
+
resolve2();
|
|
12247
|
+
},
|
|
12248
|
+
{ once: true }
|
|
12249
|
+
);
|
|
12250
|
+
});
|
|
12251
|
+
}
|
|
12252
|
+
var EpollFile = class _EpollFile {
|
|
12253
|
+
regs = /* @__PURE__ */ new Map();
|
|
12254
|
+
changes = new Notifier();
|
|
12255
|
+
cursor = 0;
|
|
12256
|
+
ctl(fds, how, fd, events, data) {
|
|
12257
|
+
const open = fds.get(fd);
|
|
12258
|
+
if (open.file === this) throw new KernelError("EINVAL");
|
|
12259
|
+
const known = this.regs.get(fd);
|
|
12260
|
+
const current = known?.open === open ? known : void 0;
|
|
12261
|
+
if (how === "add" || how === "set" && !current) {
|
|
12262
|
+
if (current) throw new KernelError("EEXIST");
|
|
12263
|
+
if (UNPOLLABLE.has(kernelFdKind(open.file))) throw new KernelError("EPERM");
|
|
12264
|
+
if (open.file instanceof _EpollFile && open.file.reaches(this)) throw new KernelError("ELOOP");
|
|
12265
|
+
if (known) this.drop(known);
|
|
12266
|
+
this.register(fd, open, events, data);
|
|
12267
|
+
} else if (!current) {
|
|
12268
|
+
throw new KernelError("ENOENT");
|
|
12269
|
+
} else if (how === "del") {
|
|
12270
|
+
this.drop(current);
|
|
12271
|
+
} else {
|
|
12272
|
+
current.events = events;
|
|
12273
|
+
current.data = data;
|
|
12274
|
+
current.armed = true;
|
|
12275
|
+
current.gen++;
|
|
12276
|
+
}
|
|
12277
|
+
this.changes.wake();
|
|
12278
|
+
}
|
|
12279
|
+
reaches(target) {
|
|
12280
|
+
if (this === target) return true;
|
|
12281
|
+
return [...this.regs.values()].some(
|
|
12282
|
+
(reg) => reg.open.file instanceof _EpollFile && reg.open.file.reaches(target)
|
|
12283
|
+
);
|
|
12284
|
+
}
|
|
12285
|
+
collect(fds, max) {
|
|
12286
|
+
const list = [...this.regs.values()];
|
|
12287
|
+
const out = [];
|
|
12288
|
+
const start2 = list.length === 0 ? 0 : this.cursor % list.length;
|
|
12289
|
+
for (let i = 0; i < list.length && out.length < max; i++) {
|
|
12290
|
+
const reg = list[(start2 + i) % list.length];
|
|
12291
|
+
if (lookup(fds, reg.fd) !== reg.open) {
|
|
12292
|
+
this.drop(reg);
|
|
12293
|
+
continue;
|
|
12294
|
+
}
|
|
12295
|
+
const bits2 = due(reg, levelOf(reg.open.file));
|
|
12296
|
+
if (bits2 === 0) continue;
|
|
12297
|
+
consume(reg);
|
|
12298
|
+
out.push({ events: bits2, data: reg.data });
|
|
12299
|
+
this.cursor = start2 + i + 1;
|
|
12300
|
+
}
|
|
12301
|
+
return out;
|
|
12302
|
+
}
|
|
12303
|
+
async wait(fds, max, timeoutMs, signal) {
|
|
12304
|
+
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
12305
|
+
for (; ; ) {
|
|
12306
|
+
const events = this.collect(fds, max);
|
|
12307
|
+
if (events.length > 0 || Date.now() >= deadline) return events;
|
|
12308
|
+
const round = new AbortController();
|
|
12309
|
+
const woken = this.changes.wait(AbortSignal.any([round.signal, signal]));
|
|
12310
|
+
woken.catch(() => void 0);
|
|
12311
|
+
let timer;
|
|
12312
|
+
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
12313
|
+
try {
|
|
12314
|
+
await Promise.race([woken, ...expiry]);
|
|
12315
|
+
} finally {
|
|
12316
|
+
round.abort();
|
|
12317
|
+
clearTimeout(timer);
|
|
12318
|
+
}
|
|
12319
|
+
}
|
|
12320
|
+
}
|
|
12321
|
+
poll() {
|
|
12322
|
+
const ready2 = [...this.regs.values()].some((reg) => due(reg, levelOf(reg.open.file)) !== 0);
|
|
12323
|
+
return { readable: ready2, writable: false, hangup: false };
|
|
12324
|
+
}
|
|
12325
|
+
changed(signal) {
|
|
12326
|
+
return this.changes.wait(signal);
|
|
12327
|
+
}
|
|
12328
|
+
close() {
|
|
12329
|
+
for (const reg of [...this.regs.values()]) this.drop(reg);
|
|
12330
|
+
this.changes.wake();
|
|
12331
|
+
}
|
|
12332
|
+
register(fd, open, events, data) {
|
|
12333
|
+
const stop = new AbortController();
|
|
12334
|
+
const unhook = open.onClose(() => {
|
|
12335
|
+
this.drop(reg);
|
|
12336
|
+
this.changes.wake();
|
|
12337
|
+
});
|
|
12338
|
+
const reg = {
|
|
12339
|
+
fd,
|
|
12340
|
+
open,
|
|
12341
|
+
events,
|
|
12342
|
+
data,
|
|
12343
|
+
gen: 1,
|
|
12344
|
+
reported: 0,
|
|
12345
|
+
armed: true,
|
|
12346
|
+
stop,
|
|
12347
|
+
unhook
|
|
12348
|
+
};
|
|
12349
|
+
this.regs.set(fd, reg);
|
|
12350
|
+
void this.watch(reg);
|
|
12351
|
+
}
|
|
12352
|
+
drop(reg) {
|
|
12353
|
+
reg.stop.abort();
|
|
12354
|
+
reg.unhook();
|
|
12355
|
+
if (this.regs.get(reg.fd) === reg) this.regs.delete(reg.fd);
|
|
12356
|
+
}
|
|
12357
|
+
async watch(reg) {
|
|
12358
|
+
const file = reg.open.file;
|
|
12359
|
+
const { signal } = reg.stop;
|
|
12360
|
+
while (file.changed && !signal.aborted) {
|
|
12361
|
+
const round = new AbortController();
|
|
12362
|
+
const stop = () => round.abort();
|
|
12363
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
12364
|
+
let failed3 = false;
|
|
12365
|
+
try {
|
|
12366
|
+
await file.changed(round.signal);
|
|
12367
|
+
} catch {
|
|
12368
|
+
failed3 = true;
|
|
12369
|
+
} finally {
|
|
12370
|
+
round.abort();
|
|
12371
|
+
signal.removeEventListener("abort", stop);
|
|
12372
|
+
}
|
|
12373
|
+
if (signal.aborted) return;
|
|
12374
|
+
reg.gen++;
|
|
12375
|
+
this.changes.wake();
|
|
12376
|
+
if (failed3) await pause(RETRY_MS, signal);
|
|
12377
|
+
}
|
|
12378
|
+
}
|
|
12379
|
+
};
|
|
12380
|
+
function epollAt(fds, fd) {
|
|
12381
|
+
const file = fds.get(fd).file;
|
|
12382
|
+
if (!(file instanceof EpollFile)) throw new KernelError("EINVAL");
|
|
12383
|
+
return file;
|
|
12384
|
+
}
|
|
12385
|
+
var ok = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
12386
|
+
async function epollSyscall(req, proc) {
|
|
12387
|
+
const { fds } = proc;
|
|
12388
|
+
switch (req.op) {
|
|
12389
|
+
case "epoll-create":
|
|
12390
|
+
return ok(fds.install(new OpenFile(new EpollFile()), 3));
|
|
12391
|
+
case "eventfd-open":
|
|
12392
|
+
return ok(fds.install(new OpenFile(new EventFd(BigInt(req.initial), req.semaphore)), 3));
|
|
12393
|
+
case "epoll-ctl":
|
|
12394
|
+
epollAt(fds, req.epfd).ctl(fds, req.how, req.fd, req.events, req.data);
|
|
12395
|
+
return ok();
|
|
12396
|
+
case "epoll-wait": {
|
|
12397
|
+
const ep = epollAt(fds, req.epfd);
|
|
12398
|
+
if (req.timeoutMs === 0 || proc.owed()) {
|
|
12399
|
+
const now = ep.collect(fds, req.max);
|
|
12400
|
+
if (req.timeoutMs === 0 || now.length > 0) return ok(now);
|
|
12401
|
+
}
|
|
12402
|
+
return ok(await ep.wait(fds, req.max, req.timeoutMs, proc.blocking()));
|
|
12403
|
+
}
|
|
12404
|
+
}
|
|
12405
|
+
}
|
|
12406
|
+
|
|
12102
12407
|
// src/kernel/host-ops.ts
|
|
12103
12408
|
var HOST_OPS = [
|
|
12104
12409
|
"lock",
|
|
@@ -12989,14 +13294,14 @@ var Resolver = class {
|
|
|
12989
13294
|
if (hit && hit.expires > this.now()) return hit.addresses;
|
|
12990
13295
|
const signal = blocking?.();
|
|
12991
13296
|
if (signal?.aborted) throw new KernelError("EINTR");
|
|
12992
|
-
let
|
|
12993
|
-
if (!
|
|
13297
|
+
let lookup2 = this.pending.get(id2);
|
|
13298
|
+
if (!lookup2) {
|
|
12994
13299
|
const abort = new AbortController();
|
|
12995
|
-
|
|
12996
|
-
this.pending.set(id2,
|
|
12997
|
-
void
|
|
13300
|
+
lookup2 = { work: this.lookup(key, asked, id2, abort.signal), abort, waiters: 0 };
|
|
13301
|
+
this.pending.set(id2, lookup2);
|
|
13302
|
+
void lookup2.work.then(() => this.pending.delete(id2));
|
|
12998
13303
|
}
|
|
12999
|
-
return waitFor(
|
|
13304
|
+
return waitFor(lookup2, signal);
|
|
13000
13305
|
}
|
|
13001
13306
|
async lookup(name2, family, id2, abandoned) {
|
|
13002
13307
|
const uplink = this.uplink;
|
|
@@ -13037,17 +13342,17 @@ var Resolver = class {
|
|
|
13037
13342
|
}
|
|
13038
13343
|
}
|
|
13039
13344
|
};
|
|
13040
|
-
function waitFor(
|
|
13041
|
-
|
|
13345
|
+
function waitFor(lookup2, signal) {
|
|
13346
|
+
lookup2.waiters++;
|
|
13042
13347
|
return new Promise((resolve2, reject) => {
|
|
13043
13348
|
const abort = () => {
|
|
13044
|
-
if (--
|
|
13349
|
+
if (--lookup2.waiters === 0) lookup2.abort.abort(new KernelError("EINTR"));
|
|
13045
13350
|
reject(new KernelError("EINTR"));
|
|
13046
13351
|
};
|
|
13047
13352
|
signal?.addEventListener("abort", abort, { once: true });
|
|
13048
|
-
void
|
|
13353
|
+
void lookup2.work.then((value) => {
|
|
13049
13354
|
if (signal?.aborted) return;
|
|
13050
|
-
|
|
13355
|
+
lookup2.waiters--;
|
|
13051
13356
|
signal?.removeEventListener("abort", abort);
|
|
13052
13357
|
resolve2(value);
|
|
13053
13358
|
});
|
|
@@ -13694,17 +13999,17 @@ function socketAt(fds, fd) {
|
|
|
13694
13999
|
if (!(file instanceof KernelSocket)) throw new KernelError("ENOTSOCK");
|
|
13695
14000
|
return file;
|
|
13696
14001
|
}
|
|
13697
|
-
var
|
|
14002
|
+
var ok2 = (json5) => json5 === void 0 ? { ok: true, kind: "void" } : { ok: true, kind: "json", json: json5 };
|
|
13698
14003
|
async function socketSyscall(req, proc) {
|
|
13699
14004
|
const { fds, net } = proc;
|
|
13700
14005
|
switch (req.op) {
|
|
13701
14006
|
case "sock-open":
|
|
13702
|
-
return
|
|
14007
|
+
return ok2(fds.install(new OpenFile(net.socket(req.domain)), 3));
|
|
13703
14008
|
case "sock-pair": {
|
|
13704
14009
|
const [a, b] = KernelSocket.pair(net, req.domain, proc.cred?.());
|
|
13705
14010
|
const first = fds.install(new OpenFile(a), 3);
|
|
13706
14011
|
try {
|
|
13707
|
-
return
|
|
14012
|
+
return ok2([first, fds.install(new OpenFile(b), 3)]);
|
|
13708
14013
|
} catch (e) {
|
|
13709
14014
|
await Promise.resolve(fds.close(first));
|
|
13710
14015
|
throw e;
|
|
@@ -13712,12 +14017,12 @@ async function socketSyscall(req, proc) {
|
|
|
13712
14017
|
}
|
|
13713
14018
|
case "sock-bind":
|
|
13714
14019
|
socketAt(fds, req.fd).bind(req.addr);
|
|
13715
|
-
return
|
|
14020
|
+
return ok2();
|
|
13716
14021
|
case "sock-listen":
|
|
13717
14022
|
socketAt(fds, req.fd).listen(req.backlog, proc.cred?.());
|
|
13718
|
-
return
|
|
14023
|
+
return ok2();
|
|
13719
14024
|
case "sock-accept":
|
|
13720
|
-
return
|
|
14025
|
+
return ok2(await accept(proc, req.fd, req.nonblock));
|
|
13721
14026
|
case "sock-connect": {
|
|
13722
14027
|
const socket = socketAt(fds, req.fd);
|
|
13723
14028
|
const stamp = net.facadeAt(req.addr) && await proc.stamp?.();
|
|
@@ -13727,26 +14032,26 @@ async function socketSyscall(req, proc) {
|
|
|
13727
14032
|
throw new KernelError("EINPROGRESS");
|
|
13728
14033
|
}
|
|
13729
14034
|
if (dialing !== void 0) await interruptible2(dialing, proc.blocking());
|
|
13730
|
-
return
|
|
14035
|
+
return ok2();
|
|
13731
14036
|
}
|
|
13732
14037
|
case "sock-shutdown":
|
|
13733
14038
|
socketAt(fds, req.fd).shutdown(req.how);
|
|
13734
|
-
return
|
|
14039
|
+
return ok2();
|
|
13735
14040
|
case "sock-name": {
|
|
13736
14041
|
const socket = socketAt(fds, req.fd);
|
|
13737
14042
|
const addr = req.peer ? socket.peer : socket.local;
|
|
13738
14043
|
if (req.peer && !addr) throw new KernelError("ENOTCONN");
|
|
13739
|
-
return
|
|
14044
|
+
return ok2(addr ?? unnamed(socket.domain));
|
|
13740
14045
|
}
|
|
13741
14046
|
case "sock-getopt":
|
|
13742
|
-
return
|
|
14047
|
+
return ok2(socketAt(fds, req.fd).getOption(req.level, req.name));
|
|
13743
14048
|
case "sock-setopt":
|
|
13744
14049
|
socketAt(fds, req.fd).setOption(req.level, req.name, req.value);
|
|
13745
|
-
return
|
|
14050
|
+
return ok2();
|
|
13746
14051
|
case "sock-resolve": {
|
|
13747
14052
|
const addresses = await proc.resolve(req.name, req.family, () => proc.blocking());
|
|
13748
14053
|
if (addresses.length === 0) throw new KernelError("ENOENT");
|
|
13749
|
-
return
|
|
14054
|
+
return ok2(addresses);
|
|
13750
14055
|
}
|
|
13751
14056
|
}
|
|
13752
14057
|
}
|
|
@@ -14447,6 +14752,9 @@ function isHttpSyscall(req) {
|
|
|
14447
14752
|
function isSocketSyscall(req) {
|
|
14448
14753
|
return req.op.startsWith("sock-");
|
|
14449
14754
|
}
|
|
14755
|
+
function isEpollSyscall(req) {
|
|
14756
|
+
return EPOLL_OPS.includes(req.op);
|
|
14757
|
+
}
|
|
14450
14758
|
function isHostSyscall(req) {
|
|
14451
14759
|
return HOST_OPS.includes(req.op);
|
|
14452
14760
|
}
|
|
@@ -14537,6 +14845,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
14537
14845
|
"sig-mask",
|
|
14538
14846
|
"sig-pause",
|
|
14539
14847
|
...SOCKET_OPS,
|
|
14848
|
+
...EPOLL_OPS,
|
|
14540
14849
|
...HTTP_OPS,
|
|
14541
14850
|
...PTY_OPS,
|
|
14542
14851
|
...HOST_OPS
|
|
@@ -14651,9 +14960,9 @@ var WasmProcess = class {
|
|
|
14651
14960
|
this.options.onPending?.(sig);
|
|
14652
14961
|
if (this.options.jobs?.keyboard && KEYBOARD.has(sig) && this.waiting.size === 0)
|
|
14653
14962
|
this.owed = true;
|
|
14654
|
-
const
|
|
14963
|
+
const blocked2 = this.interrupt;
|
|
14655
14964
|
this.interrupt = new AbortController();
|
|
14656
|
-
|
|
14965
|
+
blocked2.abort();
|
|
14657
14966
|
return "deliver";
|
|
14658
14967
|
}
|
|
14659
14968
|
async spawn(req) {
|
|
@@ -14712,9 +15021,9 @@ var WasmProcess = class {
|
|
|
14712
15021
|
this.stopped = sig;
|
|
14713
15022
|
this.stops++;
|
|
14714
15023
|
this.resumed = new Promise((resolve2) => this.wake = resolve2);
|
|
14715
|
-
const
|
|
15024
|
+
const blocked2 = this.interrupt;
|
|
14716
15025
|
this.interrupt = new AbortController();
|
|
14717
|
-
|
|
15026
|
+
blocked2.abort();
|
|
14718
15027
|
for (const listener of this.stateListeners) listener("stopped", sig);
|
|
14719
15028
|
return "stop";
|
|
14720
15029
|
}
|
|
@@ -14764,6 +15073,13 @@ var WasmProcess = class {
|
|
|
14764
15073
|
if (isTtySyscall(req)) return this.ttySyscall(req);
|
|
14765
15074
|
if (isJobSyscall(req)) return this.jobSyscall(req);
|
|
14766
15075
|
if (isSocketSyscall(req)) return await this.socketSyscall(req, cancelled);
|
|
15076
|
+
if (isEpollSyscall(req)) {
|
|
15077
|
+
return await epollSyscall(req, {
|
|
15078
|
+
fds: this.fds,
|
|
15079
|
+
blocking: () => this.blockingSignal(cancelled),
|
|
15080
|
+
owed: () => this.owed
|
|
15081
|
+
});
|
|
15082
|
+
}
|
|
14767
15083
|
if (isHttpSyscall(req)) return await this.httpSyscall(req);
|
|
14768
15084
|
if (isHostSyscall(req)) {
|
|
14769
15085
|
return await hostSyscall(req, {
|
|
@@ -14830,6 +15146,7 @@ var WasmProcess = class {
|
|
|
14830
15146
|
if (!read) throw new KernelError(req.peek && file.read ? "EOPNOTSUPP" : "EBADF");
|
|
14831
15147
|
if (file.tty) this.checkForeground(file.tty);
|
|
14832
15148
|
if (file.clipboard) return this.readClipboard(file.clipboard, req, cancelled);
|
|
15149
|
+
if (file instanceof EventFd && req.max < EventFd.SIZE) throw new KernelError("EINVAL");
|
|
14833
15150
|
if (req.max <= 0) return new Uint8Array(0);
|
|
14834
15151
|
if (file instanceof KernelSocket && file.unconnected) throw new KernelError("ENOTCONN");
|
|
14835
15152
|
const ready2 = pollFile(file).readable;
|
|
@@ -15677,9 +15994,9 @@ var WasmProcess = class {
|
|
|
15677
15994
|
}
|
|
15678
15995
|
timerExpired(which) {
|
|
15679
15996
|
this.options.onTimer?.(which);
|
|
15680
|
-
const
|
|
15997
|
+
const blocked2 = this.interrupt;
|
|
15681
15998
|
this.interrupt = new AbortController();
|
|
15682
|
-
|
|
15999
|
+
blocked2.abort();
|
|
15683
16000
|
}
|
|
15684
16001
|
clearAlarm() {
|
|
15685
16002
|
clearTimeout(this.alarm);
|
|
@@ -15783,9 +16100,9 @@ function killThread(thread, caught, sig) {
|
|
|
15783
16100
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
15784
16101
|
if (held) return true;
|
|
15785
16102
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
15786
|
-
const
|
|
16103
|
+
const blocked2 = thread.interrupt;
|
|
15787
16104
|
thread.interrupt = new AbortController();
|
|
15788
|
-
|
|
16105
|
+
blocked2.abort();
|
|
15789
16106
|
return true;
|
|
15790
16107
|
}
|
|
15791
16108
|
function unblocked(header3) {
|
|
@@ -15964,8 +16281,8 @@ function threadInit(opts, program, sab, cred, thread, main) {
|
|
|
15964
16281
|
function spawnWasmProcess(opts) {
|
|
15965
16282
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
15966
16283
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
15967
|
-
const
|
|
15968
|
-
if (
|
|
16284
|
+
const blocked2 = opts.fork?.wasi?.blocked ?? opts.blocked;
|
|
16285
|
+
if (blocked2 && anyBlocked(blocked2) && opts.program.abi === "wasi") storeBlocked(header3, blocked2);
|
|
15969
16286
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
15970
16287
|
const created3 = new Created();
|
|
15971
16288
|
const process = new WasmProcess(
|
|
@@ -19820,6 +20137,8 @@ var Launcher = class {
|
|
|
19820
20137
|
const head = await this.head(glue);
|
|
19821
20138
|
if (!head) return void 0;
|
|
19822
20139
|
if (isWasm(head)) {
|
|
20140
|
+
const owner2 = await this.wasmOwner(glue, baseName(file).replace(/\.wasm$/, ""), scope);
|
|
20141
|
+
if (owner2) return { ...targetOf(owner2), ...asked };
|
|
19823
20142
|
return {
|
|
19824
20143
|
abi: "wasi",
|
|
19825
20144
|
glue,
|
|
@@ -19842,6 +20161,17 @@ var Launcher = class {
|
|
|
19842
20161
|
);
|
|
19843
20162
|
return owners.find((c) => c.name === name2) ?? owners[0];
|
|
19844
20163
|
}
|
|
20164
|
+
async wasmOwner(wasm, name2, scope) {
|
|
20165
|
+
const leaf = baseName(wasm);
|
|
20166
|
+
const real = await physicalPathAsync(this.base, wasm);
|
|
20167
|
+
const owners = [];
|
|
20168
|
+
for (const command of (await this.commands(scope)).values()) {
|
|
20169
|
+
if (command.abi !== "wasi" || command.script || baseName(command.wasm) !== leaf) continue;
|
|
20170
|
+
if (command.wasm === wasm || await physicalPathAsync(this.base, command.wasm) === real)
|
|
20171
|
+
owners.push(command);
|
|
20172
|
+
}
|
|
20173
|
+
return owners.find((c) => c.name === name2) ?? owners[0];
|
|
20174
|
+
}
|
|
19845
20175
|
async head(path) {
|
|
19846
20176
|
try {
|
|
19847
20177
|
return (await this.base.readFileBuffer(path)).subarray(0, SHEBANG_MAX);
|
|
@@ -19929,16 +20259,29 @@ var Launcher = class {
|
|
|
19929
20259
|
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
19930
20260
|
}
|
|
19931
20261
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
19932
|
-
const
|
|
19933
|
-
try {
|
|
19934
|
-
await this.mayExec(cred, { ...req, pid: ppid }, planned);
|
|
19935
|
-
} catch (err) {
|
|
20262
|
+
const refused2 = async (err) => {
|
|
19936
20263
|
await fds.closeAll();
|
|
19937
20264
|
throw err.code === "EACCES" ? new SpawnError("EACCES") : err;
|
|
19938
|
-
}
|
|
20265
|
+
};
|
|
20266
|
+
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused2);
|
|
20267
|
+
const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0);
|
|
20268
|
+
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused2);
|
|
19939
20269
|
if (planned) return planned;
|
|
19940
20270
|
await fds.closeAll();
|
|
19941
|
-
throw new SpawnError(await this.unrunnable(
|
|
20271
|
+
throw new SpawnError(await this.unrunnable(file, req.cwd, scope));
|
|
20272
|
+
}
|
|
20273
|
+
execGuard(cred, pid, tag) {
|
|
20274
|
+
const { dac } = this;
|
|
20275
|
+
return dac && { fs: this.fs, cred, pid, dac, tag, links: this.links.get(pid) };
|
|
20276
|
+
}
|
|
20277
|
+
async execFile(file, cwd, g) {
|
|
20278
|
+
if (!file.split("/").includes("..")) return file;
|
|
20279
|
+
const path = file.startsWith("/") ? file : `${cwd}/${file}`;
|
|
20280
|
+
const slash = path.lastIndexOf("/");
|
|
20281
|
+
const dir = path.slice(0, slash);
|
|
20282
|
+
const walked = g && await need(g, "exec", dir, X_OK, { directory: true });
|
|
20283
|
+
const real = walked && walked.denied === void 0 ? walked.path : await physicalPathAsync(this.base, dir);
|
|
20284
|
+
return joinName(real, path.slice(slash + 1));
|
|
19942
20285
|
}
|
|
19943
20286
|
async ticketFile(req, fds) {
|
|
19944
20287
|
if (req.file.startsWith("/")) return physicalPathAsync(this.base, req.file);
|
|
@@ -20037,7 +20380,8 @@ var Launcher = class {
|
|
|
20037
20380
|
}
|
|
20038
20381
|
return manifests;
|
|
20039
20382
|
}
|
|
20040
|
-
async backing(
|
|
20383
|
+
async backing(asked, cwd) {
|
|
20384
|
+
const file = await this.execFile(asked, cwd);
|
|
20041
20385
|
const planned = await this.plan(file, [file], cwd, "");
|
|
20042
20386
|
return planned && this.backingOf(planned, file, cwd, "");
|
|
20043
20387
|
}
|
|
@@ -20674,8 +21018,8 @@ var Launcher = class {
|
|
|
20674
21018
|
}
|
|
20675
21019
|
signalMasksOf(pid) {
|
|
20676
21020
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
20677
|
-
const [
|
|
20678
|
-
const sigBlk =
|
|
21021
|
+
const [blocked2] = this.blockedBy(pid);
|
|
21022
|
+
const sigBlk = blocked2 ? { sigBlk: blocked2 } : {};
|
|
20679
21023
|
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
20680
21024
|
}
|
|
20681
21025
|
controlsJobs(pid) {
|
|
@@ -21123,7 +21467,7 @@ var Launcher = class {
|
|
|
21123
21467
|
const scope = account.uid === 0 ? "" : pnpmHomeOf(account, this.pnpmHome);
|
|
21124
21468
|
const start2 = dir ?? "/";
|
|
21125
21469
|
const cwd = await physicalPathAsync(this.base, start2.startsWith("/") ? start2 : `/${start2}`);
|
|
21126
|
-
const
|
|
21470
|
+
const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
|
|
21127
21471
|
if (!await this.base.exists(cwd)) await this.stackFor(tag).fs.mkdir(cwd, { recursive: true });
|
|
21128
21472
|
const planned = await this.plan(file, argv, cwd, scope);
|
|
21129
21473
|
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, planned);
|
|
@@ -21416,19 +21760,19 @@ function usersOp(l, req) {
|
|
|
21416
21760
|
if (req.op === "groups-remove-member") return l.users.removeMember(req.group, req.user);
|
|
21417
21761
|
return l.users.list();
|
|
21418
21762
|
}
|
|
21419
|
-
function hostOptions(req, port, sealed, clipboard,
|
|
21763
|
+
function hostOptions(req, port, sealed, clipboard, lookup2) {
|
|
21420
21764
|
return {
|
|
21421
21765
|
...req.hostname !== void 0 ? { hostname: req.hostname } : {},
|
|
21422
21766
|
...req.users !== void 0 ? { users: req.users } : {},
|
|
21423
21767
|
...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
|
|
21424
|
-
...req.protect ? { protect: hostProtect(req.protect,
|
|
21768
|
+
...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},
|
|
21425
21769
|
...req.sealed ? { sealed } : {},
|
|
21426
21770
|
...req.clipboard ? { clipboard } : {}
|
|
21427
21771
|
};
|
|
21428
21772
|
}
|
|
21429
|
-
function hostProtect(init,
|
|
21773
|
+
function hostProtect(init, lookup2) {
|
|
21430
21774
|
const { integrity, ...rest2 } = protectInit(init);
|
|
21431
|
-
return { ...rest2, ...integrity ? { integrity: { ...integrity, lookup } } : {} };
|
|
21775
|
+
return { ...rest2, ...integrity ? { integrity: { ...integrity, lookup: lookup2 } } : {} };
|
|
21432
21776
|
}
|
|
21433
21777
|
function policyAsker(port) {
|
|
21434
21778
|
const policies = /* @__PURE__ */ new Map();
|