@ai-ecoverse/slicc-kernel 1.87.0 → 1.88.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 +13 -8
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +395 -103
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +6 -8
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +201 -39
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +389 -95
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +201 -39
- package/dist/process-worker.js.map +4 -4
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -3014,8 +3014,8 @@ var MemoryMeta = class {
|
|
|
3014
3014
|
async get(paths) {
|
|
3015
3015
|
return paths.map((path) => this.entries.get(path));
|
|
3016
3016
|
}
|
|
3017
|
-
async fresh(
|
|
3018
|
-
return this.
|
|
3017
|
+
async fresh(paths) {
|
|
3018
|
+
return this.get(paths);
|
|
3019
3019
|
}
|
|
3020
3020
|
async update(path, change) {
|
|
3021
3021
|
this.set(path, change(this.entries.get(path)));
|
|
@@ -3615,8 +3615,25 @@ var OpfsFs = class {
|
|
|
3615
3615
|
}
|
|
3616
3616
|
counted = [];
|
|
3617
3617
|
async stamp(path) {
|
|
3618
|
-
const
|
|
3619
|
-
|
|
3618
|
+
const paths = [path, "/"];
|
|
3619
|
+
const [entry, root] = this.meta.fresh ? await this.meta.fresh(paths) : await this.meta.get(paths);
|
|
3620
|
+
return `${entry?.writes ?? 0}:${root?.epoch ?? 0}`;
|
|
3621
|
+
}
|
|
3622
|
+
async epoch() {
|
|
3623
|
+
await this.meta.update("/", (entry) => ({
|
|
3624
|
+
...entry,
|
|
3625
|
+
path: "/",
|
|
3626
|
+
epoch: (entry?.epoch ?? 0) + 1
|
|
3627
|
+
}));
|
|
3628
|
+
}
|
|
3629
|
+
async entering(path, change) {
|
|
3630
|
+
if (!isProtected(this.counted, path) && !holdsProtected(this.counted, path)) return change();
|
|
3631
|
+
await this.epoch();
|
|
3632
|
+
try {
|
|
3633
|
+
await change();
|
|
3634
|
+
} finally {
|
|
3635
|
+
await this.epoch();
|
|
3636
|
+
}
|
|
3620
3637
|
}
|
|
3621
3638
|
async counting(target) {
|
|
3622
3639
|
if (!isProtected(this.counted, target)) return;
|
|
@@ -3687,9 +3704,9 @@ var OpfsFs = class {
|
|
|
3687
3704
|
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
3688
3705
|
}
|
|
3689
3706
|
guarded = [];
|
|
3690
|
-
protect(prefixes2) {
|
|
3707
|
+
protect(prefixes2, versions = false) {
|
|
3691
3708
|
this.guarded = prefixes2;
|
|
3692
|
-
this.counted = prefixes2;
|
|
3709
|
+
this.counted = versions ? prefixes2 : [];
|
|
3693
3710
|
}
|
|
3694
3711
|
unguarded() {
|
|
3695
3712
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -4269,6 +4286,9 @@ var OpfsFs = class {
|
|
|
4269
4286
|
const parent = await this.locate(parentOf4(to), true);
|
|
4270
4287
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
4271
4288
|
this.refuse(destination, true);
|
|
4289
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
4290
|
+
}
|
|
4291
|
+
async moveTo(source, parent, destination, to) {
|
|
4272
4292
|
const sourceStat = await this.describe(source);
|
|
4273
4293
|
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
4274
4294
|
const target = await this.locate(destination, false).catch((err) => {
|
|
@@ -4376,15 +4396,18 @@ var OpfsFs = class {
|
|
|
4376
4396
|
}
|
|
4377
4397
|
const now = Date.now();
|
|
4378
4398
|
const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
|
|
4379
|
-
await this.
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4399
|
+
await this.entering(
|
|
4400
|
+
at,
|
|
4401
|
+
() => this.meta.update(at, () => ({
|
|
4402
|
+
path: at,
|
|
4403
|
+
link: target,
|
|
4404
|
+
dir: parent.path,
|
|
4405
|
+
ino: inodeOf(at),
|
|
4406
|
+
mtimeMs: now,
|
|
4407
|
+
ctimeMs: now,
|
|
4408
|
+
...fields
|
|
4409
|
+
}))
|
|
4410
|
+
);
|
|
4388
4411
|
this.touch(parent.path);
|
|
4389
4412
|
}
|
|
4390
4413
|
async realpath(path, follow2) {
|
|
@@ -5480,8 +5503,12 @@ function closeAll(entry) {
|
|
|
5480
5503
|
|
|
5481
5504
|
// src/commands.ts
|
|
5482
5505
|
var NAME2 = /^[A-Za-z0-9._+-]+$/;
|
|
5506
|
+
var COMMAND_NAME = /^[^/\s\p{Cc}]+$/u;
|
|
5483
5507
|
var ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5484
5508
|
var PACKAGE = /\$\{package\}/g;
|
|
5509
|
+
function commandName(name2) {
|
|
5510
|
+
return COMMAND_NAME.test(name2) && name2.isWellFormed() && name2 !== "." && name2 !== "..";
|
|
5511
|
+
}
|
|
5485
5512
|
function inside(pkg, rel2) {
|
|
5486
5513
|
if (typeof rel2 !== "string" || rel2 === "") return void 0;
|
|
5487
5514
|
const clean = rel2.replace(/^\.\//, "");
|
|
@@ -5571,7 +5598,7 @@ function commandsOf(pkg, manifest) {
|
|
|
5571
5598
|
const shared = envOf(pkg, slicc.env);
|
|
5572
5599
|
const out = [];
|
|
5573
5600
|
for (const [name2, raw] of Object.entries(entries)) {
|
|
5574
|
-
if (!
|
|
5601
|
+
if (!commandName(name2) || !raw || typeof raw !== "object") {
|
|
5575
5602
|
continue;
|
|
5576
5603
|
}
|
|
5577
5604
|
const command = commandOf(pkg, name2, raw, packageAbi, shared);
|
|
@@ -5623,18 +5650,86 @@ async function packagesIn(fs, roots) {
|
|
|
5623
5650
|
dirs.push(...await packages(fs, root));
|
|
5624
5651
|
return dirs;
|
|
5625
5652
|
}
|
|
5626
|
-
|
|
5627
|
-
const
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5653
|
+
function binEntries(manifest) {
|
|
5654
|
+
const { bin, name: name2 } = manifest;
|
|
5655
|
+
if (typeof bin === "string") {
|
|
5656
|
+
return typeof name2 === "string" ? [[name2.slice(name2.lastIndexOf("/") + 1), bin]] : [];
|
|
5657
|
+
}
|
|
5658
|
+
return bin && typeof bin === "object" ? Object.entries(bin) : [];
|
|
5659
|
+
}
|
|
5660
|
+
var MAX_HOPS = 40;
|
|
5661
|
+
function physicalResolver(fs) {
|
|
5662
|
+
const known = /* @__PURE__ */ new Map();
|
|
5663
|
+
const pending = /* @__PURE__ */ new Set();
|
|
5664
|
+
let hops = 0;
|
|
5665
|
+
const step = async (path) => {
|
|
5666
|
+
if (path === "/") return { path, file: false };
|
|
5667
|
+
const slash = path.lastIndexOf("/");
|
|
5668
|
+
const parent = await resolve2(path.slice(0, slash) || "/");
|
|
5669
|
+
if (parent === void 0) return void 0;
|
|
5670
|
+
const at = resolvePath(parent.path, path.slice(slash + 1));
|
|
5671
|
+
const st = await fs.lstat(at).catch(() => void 0);
|
|
5672
|
+
if (!st?.isSymbolicLink) return st ? { path: at, file: st.isFile === true } : void 0;
|
|
5673
|
+
const target = await fs.readlink(at).catch(() => void 0);
|
|
5674
|
+
if (target === void 0 || ++hops > MAX_HOPS) return void 0;
|
|
5675
|
+
return resolve2(resolvePath(parent.path, target));
|
|
5676
|
+
};
|
|
5677
|
+
const resolve2 = (path) => {
|
|
5678
|
+
if (pending.has(path)) return Promise.resolve(void 0);
|
|
5679
|
+
let found = known.get(path);
|
|
5680
|
+
if (!found) {
|
|
5681
|
+
pending.add(path);
|
|
5682
|
+
found = step(path).finally(() => pending.delete(path));
|
|
5683
|
+
known.set(path, found);
|
|
5634
5684
|
}
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5685
|
+
return found;
|
|
5686
|
+
};
|
|
5687
|
+
return (path) => {
|
|
5688
|
+
hops = 0;
|
|
5689
|
+
return resolve2(path);
|
|
5690
|
+
};
|
|
5691
|
+
}
|
|
5692
|
+
async function binCommandsOf(physical, pkg, manifest, taken) {
|
|
5693
|
+
const entries = binEntries(manifest);
|
|
5694
|
+
if (entries.length === 0) return [];
|
|
5695
|
+
const home = (await physical(pkg))?.path;
|
|
5696
|
+
const out = [];
|
|
5697
|
+
for (const [name2, rel2] of entries) {
|
|
5698
|
+
if (taken.has(name2) || !commandName(name2)) continue;
|
|
5699
|
+
const script = inside(pkg, rel2);
|
|
5700
|
+
if (!script) continue;
|
|
5701
|
+
const real = await physical(script);
|
|
5702
|
+
if (!real?.file || !real.path.startsWith(`${home}/`)) continue;
|
|
5703
|
+
out.push({
|
|
5704
|
+
name: name2,
|
|
5705
|
+
abi: "emscripten",
|
|
5706
|
+
glue: script,
|
|
5707
|
+
wasm: script,
|
|
5708
|
+
argv0: name2,
|
|
5709
|
+
script,
|
|
5710
|
+
bin: true
|
|
5711
|
+
});
|
|
5712
|
+
}
|
|
5713
|
+
return out;
|
|
5714
|
+
}
|
|
5715
|
+
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY) {
|
|
5716
|
+
const found = /* @__PURE__ */ new Map();
|
|
5717
|
+
const physical = physicalResolver(fs);
|
|
5718
|
+
for (const [index, root] of (typeof modules === "string" ? [modules] : modules).entries()) {
|
|
5719
|
+
for (const pkg of await packages(fs, root)) {
|
|
5720
|
+
let manifest;
|
|
5721
|
+
try {
|
|
5722
|
+
manifest = JSON.parse(await fs.readFile(`${pkg}/package.json`));
|
|
5723
|
+
} catch {
|
|
5724
|
+
continue;
|
|
5725
|
+
}
|
|
5726
|
+
const own = commandsOf(pkg, manifest);
|
|
5727
|
+
const named = new Set(own.map((command) => command.name));
|
|
5728
|
+
const bins = index >= binsFrom ? await binCommandsOf(physical, pkg, manifest, named) : [];
|
|
5729
|
+
for (const command of [...own, ...bins]) {
|
|
5730
|
+
if (!found.has(command.name))
|
|
5731
|
+
found.set(command.name, await withPackagePaths(fs, pkg, command));
|
|
5732
|
+
}
|
|
5638
5733
|
}
|
|
5639
5734
|
}
|
|
5640
5735
|
if (!found.has("sh") && found.has("bash")) {
|
|
@@ -6093,7 +6188,7 @@ var FreshModules = class {
|
|
|
6093
6188
|
};
|
|
6094
6189
|
|
|
6095
6190
|
// src/fs/physical-path.ts
|
|
6096
|
-
var
|
|
6191
|
+
var MAX_HOPS2 = 40;
|
|
6097
6192
|
function start(path) {
|
|
6098
6193
|
return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
|
|
6099
6194
|
}
|
|
@@ -6118,7 +6213,7 @@ function rest(walk2, part) {
|
|
|
6118
6213
|
return lexical(`/${[...walk2.done, part, ...walk2.todo].join("/")}`);
|
|
6119
6214
|
}
|
|
6120
6215
|
function follow(walk2, target) {
|
|
6121
|
-
if (++walk2.hops >
|
|
6216
|
+
if (++walk2.hops > MAX_HOPS2) return false;
|
|
6122
6217
|
if (target.startsWith("/")) walk2.done.length = 0;
|
|
6123
6218
|
walk2.todo = [...target.split("/").filter((p) => p !== ""), ...walk2.todo];
|
|
6124
6219
|
return true;
|
|
@@ -6490,12 +6585,12 @@ async function interruptible(work, signal) {
|
|
|
6490
6585
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
6491
6586
|
let stop = () => {
|
|
6492
6587
|
};
|
|
6493
|
-
const
|
|
6588
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
6494
6589
|
stop = () => reject(new KernelError("EINTR"));
|
|
6495
6590
|
signal.addEventListener("abort", stop, { once: true });
|
|
6496
6591
|
});
|
|
6497
6592
|
try {
|
|
6498
|
-
return await Promise.race([work,
|
|
6593
|
+
return await Promise.race([work, interrupted3]);
|
|
6499
6594
|
} finally {
|
|
6500
6595
|
signal.removeEventListener("abort", stop);
|
|
6501
6596
|
}
|
|
@@ -7795,11 +7890,12 @@ var MountFs = class {
|
|
|
7795
7890
|
});
|
|
7796
7891
|
}
|
|
7797
7892
|
async chmod(path, mode) {
|
|
7798
|
-
const
|
|
7799
|
-
|
|
7800
|
-
this.
|
|
7893
|
+
const real = await this.follow(path);
|
|
7894
|
+
const found = this.at(real);
|
|
7895
|
+
if (!found) return this.base.chmod(real, mode);
|
|
7896
|
+
this.writable(found.mount, real);
|
|
7801
7897
|
if (!found.mount.caps.chmod) return;
|
|
7802
|
-
this.table.forget(found.mount,
|
|
7898
|
+
this.table.forget(found.mount, real);
|
|
7803
7899
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
7804
7900
|
}
|
|
7805
7901
|
async utimes(path, atime, mtime) {
|
|
@@ -8269,7 +8365,7 @@ async function dispatchOne(entry, req) {
|
|
|
8269
8365
|
}
|
|
8270
8366
|
|
|
8271
8367
|
// src/realm/sync-sab-wire.ts
|
|
8272
|
-
var SAB_HEADER_I32 =
|
|
8368
|
+
var SAB_HEADER_I32 = 18;
|
|
8273
8369
|
var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
|
|
8274
8370
|
var SAB_CLOCK_I64 = 3;
|
|
8275
8371
|
var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
|
|
@@ -8289,6 +8385,7 @@ var SAB_I_OFFSET_HI = 12;
|
|
|
8289
8385
|
var SAB_I_KILLED = 13;
|
|
8290
8386
|
var SAB_I_ASYNC = 14;
|
|
8291
8387
|
var SAB_I_STOP = 15;
|
|
8388
|
+
var SAB_I_BLOCKED = 16;
|
|
8292
8389
|
var U32 = 2 ** 32;
|
|
8293
8390
|
function storeU53(header4, lo, hi, value) {
|
|
8294
8391
|
Atomics.store(header4, hi, Math.floor(value / U32));
|
|
@@ -8841,12 +8938,32 @@ function mountTable(mounts = []) {
|
|
|
8841
8938
|
`;
|
|
8842
8939
|
}
|
|
8843
8940
|
|
|
8941
|
+
// src/version.ts
|
|
8942
|
+
var KERNEL_VERSION = true ? "1.88.1" : "0.0.0-dev";
|
|
8943
|
+
var OS_RELEASE = "6.0.0-slicc";
|
|
8944
|
+
function procVersion() {
|
|
8945
|
+
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
8946
|
+
`;
|
|
8947
|
+
}
|
|
8948
|
+
|
|
8844
8949
|
// src/process/procfs.ts
|
|
8845
8950
|
var HZ = 100;
|
|
8846
8951
|
var KIB = 1024;
|
|
8847
8952
|
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
8848
8953
|
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
8849
|
-
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
|
|
8954
|
+
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime", "version"];
|
|
8955
|
+
var SYS_TREE = {
|
|
8956
|
+
kernel: { osrelease: `${OS_RELEASE}
|
|
8957
|
+
`, ostype: "Linux\n" }
|
|
8958
|
+
};
|
|
8959
|
+
function sysEntry(parts2) {
|
|
8960
|
+
let at = SYS_TREE;
|
|
8961
|
+
for (const part of parts2) {
|
|
8962
|
+
if (typeof at !== "object" || !Object.hasOwn(at, part)) return void 0;
|
|
8963
|
+
at = at[part];
|
|
8964
|
+
}
|
|
8965
|
+
return at;
|
|
8966
|
+
}
|
|
8850
8967
|
function commOf(info) {
|
|
8851
8968
|
const name2 = info.argv[0] ?? "";
|
|
8852
8969
|
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
@@ -8934,7 +9051,7 @@ function pidStatus(info) {
|
|
|
8934
9051
|
"SigQ: 0/0",
|
|
8935
9052
|
"SigPnd: 0000000000000000",
|
|
8936
9053
|
"ShdPnd: 0000000000000000",
|
|
8937
|
-
|
|
9054
|
+
`SigBlk: ${sigMask(info.sigBlk)}`,
|
|
8938
9055
|
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
8939
9056
|
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
8940
9057
|
""
|
|
@@ -8970,6 +9087,7 @@ function memoryInfo(source, used = 0) {
|
|
|
8970
9087
|
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
8971
9088
|
}
|
|
8972
9089
|
function systemFile(name2, listing, now, memory) {
|
|
9090
|
+
if (name2 === "version") return procVersion();
|
|
8973
9091
|
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
8974
9092
|
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
8975
9093
|
`;
|
|
@@ -9060,11 +9178,17 @@ var ProcTree = class {
|
|
|
9060
9178
|
names: () => [
|
|
9061
9179
|
...SYSTEM_NAMES,
|
|
9062
9180
|
"mounts",
|
|
9181
|
+
"sys",
|
|
9063
9182
|
"self",
|
|
9064
9183
|
...this.listing().processes.map((p) => String(p.pid))
|
|
9065
9184
|
]
|
|
9066
9185
|
};
|
|
9067
9186
|
}
|
|
9187
|
+
if (top === "sys") {
|
|
9188
|
+
const entry = sysEntry(parts2.slice(1));
|
|
9189
|
+
if (typeof entry === "string") return { kind: "file", content: () => entry };
|
|
9190
|
+
return entry && { kind: "dir", names: () => Object.keys(entry) };
|
|
9191
|
+
}
|
|
9068
9192
|
if (top === "self") {
|
|
9069
9193
|
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
9070
9194
|
}
|
|
@@ -9142,7 +9266,7 @@ var ProcTree = class {
|
|
|
9142
9266
|
}
|
|
9143
9267
|
}
|
|
9144
9268
|
};
|
|
9145
|
-
var
|
|
9269
|
+
var MAX_HOPS3 = 40;
|
|
9146
9270
|
function* procWalk(path, follow2) {
|
|
9147
9271
|
let done4 = [];
|
|
9148
9272
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -9161,7 +9285,7 @@ function* procWalk(path, follow2) {
|
|
|
9161
9285
|
if (!follow2 && todo.length === 0) return void 0;
|
|
9162
9286
|
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
9163
9287
|
if (typeof target === "string") {
|
|
9164
|
-
if (++hops >
|
|
9288
|
+
if (++hops > MAX_HOPS3) return void 0;
|
|
9165
9289
|
[done4, todo] = throughLink(target, done4, todo);
|
|
9166
9290
|
} else {
|
|
9167
9291
|
broken ??= refusalOf(target);
|
|
@@ -11703,16 +11827,16 @@ function interruption(signal) {
|
|
|
11703
11827
|
}
|
|
11704
11828
|
async function selectFds(fds, read, write, timeoutMs, interrupt) {
|
|
11705
11829
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
11706
|
-
const
|
|
11707
|
-
|
|
11830
|
+
const interrupted3 = interruption(interrupt);
|
|
11831
|
+
interrupted3.promise.catch(() => {
|
|
11708
11832
|
});
|
|
11709
11833
|
try {
|
|
11710
|
-
return await waitReady(fds, read, write, deadline,
|
|
11834
|
+
return await waitReady(fds, read, write, deadline, interrupted3.promise);
|
|
11711
11835
|
} finally {
|
|
11712
|
-
|
|
11836
|
+
interrupted3.done();
|
|
11713
11837
|
}
|
|
11714
11838
|
}
|
|
11715
|
-
async function waitReady(fds, read, write, deadline,
|
|
11839
|
+
async function waitReady(fds, read, write, deadline, interrupted3) {
|
|
11716
11840
|
for (; ; ) {
|
|
11717
11841
|
const now = ready(fds, read, write);
|
|
11718
11842
|
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
@@ -11724,7 +11848,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
|
11724
11848
|
let timer;
|
|
11725
11849
|
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
11726
11850
|
try {
|
|
11727
|
-
await Promise.race([...changes, ...expiry,
|
|
11851
|
+
await Promise.race([...changes, ...expiry, interrupted3]);
|
|
11728
11852
|
} finally {
|
|
11729
11853
|
round.abort();
|
|
11730
11854
|
clearTimeout(timer);
|
|
@@ -12041,11 +12165,12 @@ var VfsNodes = class {
|
|
|
12041
12165
|
byId = /* @__PURE__ */ new Map();
|
|
12042
12166
|
keepsOnDisk = false;
|
|
12043
12167
|
fs;
|
|
12044
|
-
entries
|
|
12168
|
+
entries;
|
|
12045
12169
|
onClosed;
|
|
12046
|
-
constructor(fs, onClosed) {
|
|
12170
|
+
constructor(fs, onClosed, entries = /* @__PURE__ */ new Map()) {
|
|
12047
12171
|
this.fs = fs;
|
|
12048
12172
|
this.onClosed = onClosed;
|
|
12173
|
+
this.entries = entries;
|
|
12049
12174
|
}
|
|
12050
12175
|
async onEntry(path, op) {
|
|
12051
12176
|
const key = await this.entryKey(path);
|
|
@@ -12535,6 +12660,7 @@ var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
|
12535
12660
|
var WasmProcess = class {
|
|
12536
12661
|
exited = false;
|
|
12537
12662
|
children;
|
|
12663
|
+
deathSignals = /* @__PURE__ */ new Map();
|
|
12538
12664
|
caught = 0;
|
|
12539
12665
|
ignored = 0;
|
|
12540
12666
|
inherited = 0;
|
|
@@ -12569,7 +12695,10 @@ var WasmProcess = class {
|
|
|
12569
12695
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
12570
12696
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
12571
12697
|
this.children.onChildState = () => this.signal(SIG.CHLD);
|
|
12572
|
-
this.children.onReap =
|
|
12698
|
+
this.children.onReap = (pid2) => {
|
|
12699
|
+
this.deathSignals.delete(pid2);
|
|
12700
|
+
options.onReap?.(pid2);
|
|
12701
|
+
};
|
|
12573
12702
|
}
|
|
12574
12703
|
ignores(bit) {
|
|
12575
12704
|
return (this.signalMasks().ignored & bit) !== 0;
|
|
@@ -12597,6 +12726,10 @@ var WasmProcess = class {
|
|
|
12597
12726
|
if (sig === SIG.STOP) return this.stop(sig);
|
|
12598
12727
|
const bit = sigbit(sig);
|
|
12599
12728
|
if (this.ignores(bit)) return "ignore";
|
|
12729
|
+
if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
|
|
12730
|
+
this.options.onPending?.(sig);
|
|
12731
|
+
return "deliver";
|
|
12732
|
+
}
|
|
12600
12733
|
if (!(this.caught & bit)) {
|
|
12601
12734
|
const action = defaultAction(sig);
|
|
12602
12735
|
return action === "stop" ? this.stop(sig) : action;
|
|
@@ -12613,16 +12746,27 @@ var WasmProcess = class {
|
|
|
12613
12746
|
return "deliver";
|
|
12614
12747
|
}
|
|
12615
12748
|
async spawn(req) {
|
|
12616
|
-
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session } = req;
|
|
12749
|
+
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
|
|
12750
|
+
if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
|
|
12751
|
+
throw new KernelError("EINVAL");
|
|
12752
|
+
}
|
|
12617
12753
|
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12618
12754
|
const named = argv0 !== void 0 ? { argv0 } : {};
|
|
12619
12755
|
const spawned = { file, argv, ...named, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
12620
12756
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
12757
|
+
if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
|
|
12621
12758
|
if (!exec) return pid;
|
|
12622
12759
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
12623
12760
|
else this.adoptExec(pid);
|
|
12624
12761
|
return pid;
|
|
12625
12762
|
}
|
|
12763
|
+
onDeath(target, sig) {
|
|
12764
|
+
if (this.exited) this.sendDeath(target, sig);
|
|
12765
|
+
else this.deathSignals.set(target, sig);
|
|
12766
|
+
}
|
|
12767
|
+
sendDeath(target, sig) {
|
|
12768
|
+
void Promise.resolve(this.options.kill?.(target, sig)).catch(() => void 0);
|
|
12769
|
+
}
|
|
12626
12770
|
async killSelf(sig, target, probe2) {
|
|
12627
12771
|
if (!this.options.exitSignal) throw new KernelError("ENOSYS");
|
|
12628
12772
|
if (!isSignal(sig) || defaultAction(sig) !== "terminate") throw new KernelError("EINVAL");
|
|
@@ -13521,6 +13665,8 @@ var WasmProcess = class {
|
|
|
13521
13665
|
this.interrupt.abort();
|
|
13522
13666
|
this.options.locks?.release(this.pid);
|
|
13523
13667
|
this.asyncOps.close();
|
|
13668
|
+
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
13669
|
+
this.deathSignals.clear();
|
|
13524
13670
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13525
13671
|
await this.stampClipboards();
|
|
13526
13672
|
await this.fds.closeAll();
|
|
@@ -13600,19 +13746,25 @@ var Dying = class {
|
|
|
13600
13746
|
}
|
|
13601
13747
|
};
|
|
13602
13748
|
function killThread(thread, caught, sig) {
|
|
13603
|
-
if (!thread
|
|
13749
|
+
if (!thread) return false;
|
|
13750
|
+
const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
|
|
13751
|
+
if (!held && (caught & sigbit(sig)) === 0) return false;
|
|
13604
13752
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
13753
|
+
if (held) return true;
|
|
13605
13754
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
13606
13755
|
const blocked = thread.interrupt;
|
|
13607
13756
|
thread.interrupt = new AbortController();
|
|
13608
13757
|
blocked.abort();
|
|
13609
13758
|
return true;
|
|
13610
13759
|
}
|
|
13760
|
+
function unblocked(header4) {
|
|
13761
|
+
return Atomics.load(header4, SAB_I_SIGNALS) & ~Atomics.load(header4, SAB_I_BLOCKED);
|
|
13762
|
+
}
|
|
13611
13763
|
function threadSignalsOf(sab) {
|
|
13612
13764
|
return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
|
|
13613
13765
|
}
|
|
13614
13766
|
function threadCancel(thread) {
|
|
13615
|
-
return
|
|
13767
|
+
return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
|
|
13616
13768
|
}
|
|
13617
13769
|
function notifiers(header4) {
|
|
13618
13770
|
return {
|
|
@@ -13737,15 +13889,16 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
13737
13889
|
resolver: opts.resolver,
|
|
13738
13890
|
...notifiers(header4),
|
|
13739
13891
|
onTimer: (which) => void Atomics.or(header4, SAB_I_TIMERS, 1 << which),
|
|
13740
|
-
hasPending: () =>
|
|
13892
|
+
hasPending: () => unblocked(header4) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
|
|
13741
13893
|
raise: hooks.raise,
|
|
13742
13894
|
threadKill: hooks.threadKill,
|
|
13743
13895
|
...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
|
|
13744
13896
|
...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
|
|
13745
|
-
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {}
|
|
13897
|
+
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {},
|
|
13898
|
+
...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header4, SAB_I_BLOCKED) } : {}
|
|
13746
13899
|
};
|
|
13747
13900
|
}
|
|
13748
|
-
function threadInit(opts, program, sab, cred, thread) {
|
|
13901
|
+
function threadInit(opts, program, sab, cred, thread, main) {
|
|
13749
13902
|
return {
|
|
13750
13903
|
type: WASM_THREAD_INIT,
|
|
13751
13904
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -13758,12 +13911,15 @@ function threadInit(opts, program, sab, cred, thread) {
|
|
|
13758
13911
|
cred: copyCred(cred),
|
|
13759
13912
|
owners: opts.owners === true,
|
|
13760
13913
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
13761
|
-
thread
|
|
13914
|
+
thread,
|
|
13915
|
+
signals: main
|
|
13762
13916
|
};
|
|
13763
13917
|
}
|
|
13764
13918
|
function spawnWasmProcess(opts) {
|
|
13765
13919
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13766
13920
|
const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
13921
|
+
if (opts.blocked && opts.program.abi === "wasi")
|
|
13922
|
+
Atomics.store(header4, SAB_I_BLOCKED, opts.blocked);
|
|
13767
13923
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
13768
13924
|
const created3 = new Created();
|
|
13769
13925
|
const process2 = new WasmProcess(
|
|
@@ -13864,6 +14020,7 @@ function spawnWasmProcess(opts) {
|
|
|
13864
14020
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13865
14021
|
const tw = opts.createWorker();
|
|
13866
14022
|
const tsignals = threadSignalsOf(tsab);
|
|
14023
|
+
if (thread.blocked) Atomics.store(tsignals.header, SAB_I_BLOCKED, thread.blocked);
|
|
13867
14024
|
threadSignals.set(thread.tid, tsignals);
|
|
13868
14025
|
const tdispatch = (req) => dying.serving(
|
|
13869
14026
|
() => isWasmSyscall(req) ? process2.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -13885,7 +14042,7 @@ function spawnWasmProcess(opts) {
|
|
|
13885
14042
|
tresponder.dispose();
|
|
13886
14043
|
tw.terminate();
|
|
13887
14044
|
});
|
|
13888
|
-
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread));
|
|
14045
|
+
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread, sab));
|
|
13889
14046
|
};
|
|
13890
14047
|
worker.postMessage(
|
|
13891
14048
|
processInit(opts, sab, process2.umask, copyCred(process2.cred), lane?.lane),
|
|
@@ -13907,6 +14064,7 @@ function spawnWasmProcess(opts) {
|
|
|
13907
14064
|
onState: (listener) => process2.onState(listener),
|
|
13908
14065
|
memory: () => Atomics.load(header4, SAB_I_MEMORY) * 65536,
|
|
13909
14066
|
ignoredSignals: (fork) => process2.inheritable(fork),
|
|
14067
|
+
blockedSignals: () => opts.program.abi === "wasi" ? Atomics.load(header4, SAB_I_BLOCKED) : 0,
|
|
13910
14068
|
signalMasks: () => process2.signalMasks(),
|
|
13911
14069
|
umask: () => process2.umask,
|
|
13912
14070
|
cred: () => copyCred(process2.cred),
|
|
@@ -14619,63 +14777,137 @@ function compile(secrets, options = {}) {
|
|
|
14619
14777
|
|
|
14620
14778
|
// src/kernel/scrub-file.ts
|
|
14621
14779
|
var SCRUB_IDLE_MS = 50;
|
|
14780
|
+
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
14622
14781
|
var encoder5 = new TextEncoder();
|
|
14623
14782
|
function scrubberOf(secrets) {
|
|
14624
14783
|
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
14625
14784
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
14626
14785
|
}
|
|
14627
|
-
async function writeAll2(file, bytes
|
|
14786
|
+
async function writeAll2(file, bytes) {
|
|
14628
14787
|
const write = file.write;
|
|
14629
|
-
for (let at = 0; at < bytes.length; )
|
|
14630
|
-
at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
|
|
14631
|
-
}
|
|
14788
|
+
for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
|
|
14632
14789
|
}
|
|
14633
14790
|
function bound(file, key) {
|
|
14634
14791
|
const method = file[key];
|
|
14635
14792
|
return typeof method === "function" ? { [key]: method.bind(file) } : {};
|
|
14636
14793
|
}
|
|
14794
|
+
function interrupted2(err) {
|
|
14795
|
+
const code = err?.code;
|
|
14796
|
+
return code === "EINTR" || code === "EAGAIN";
|
|
14797
|
+
}
|
|
14637
14798
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
14638
14799
|
const file = inner.file;
|
|
14639
14800
|
const stream2 = scrubber.stream();
|
|
14640
|
-
let
|
|
14801
|
+
let tail = Promise.resolve();
|
|
14802
|
+
let pending = 0;
|
|
14803
|
+
let busy = false;
|
|
14641
14804
|
let timer;
|
|
14642
14805
|
let failed3;
|
|
14806
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
14807
|
+
const quiet2 = () => !busy && pending === 0;
|
|
14808
|
+
const wake = () => {
|
|
14809
|
+
for (const waiter of [...waiters]) waiter();
|
|
14810
|
+
};
|
|
14643
14811
|
const raise = () => {
|
|
14644
14812
|
if (failed3 === void 0) return;
|
|
14645
14813
|
const err = failed3;
|
|
14646
14814
|
failed3 = void 0;
|
|
14647
14815
|
throw err;
|
|
14648
14816
|
};
|
|
14649
|
-
const
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14817
|
+
const later = (bytes) => {
|
|
14818
|
+
if (bytes.length === 0) return;
|
|
14819
|
+
pending += 1;
|
|
14820
|
+
tail = tail.then(() => writeAll2(file, bytes)).catch((err) => {
|
|
14821
|
+
if (failed3 === void 0) failed3 = err;
|
|
14822
|
+
}).finally(() => {
|
|
14823
|
+
pending -= 1;
|
|
14824
|
+
if (quiet2()) wake();
|
|
14825
|
+
});
|
|
14826
|
+
};
|
|
14827
|
+
const settling = (signal) => new Promise((resolve2, reject) => {
|
|
14828
|
+
const done4 = () => {
|
|
14829
|
+
waiters.delete(done4);
|
|
14830
|
+
signal?.removeEventListener("abort", stop);
|
|
14831
|
+
resolve2();
|
|
14832
|
+
};
|
|
14833
|
+
const stop = () => {
|
|
14834
|
+
waiters.delete(done4);
|
|
14835
|
+
reject(new KernelError("EINTR"));
|
|
14836
|
+
};
|
|
14837
|
+
if (signal?.aborted) return stop();
|
|
14838
|
+
waiters.add(done4);
|
|
14839
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
14840
|
+
});
|
|
14841
|
+
const settled = async () => {
|
|
14842
|
+
while (!quiet2()) await settling();
|
|
14843
|
+
};
|
|
14844
|
+
const changed = async (signal) => {
|
|
14845
|
+
const round = new AbortController();
|
|
14846
|
+
const stop = signal ? AbortSignal.any([signal, round.signal]) : round.signal;
|
|
14847
|
+
try {
|
|
14848
|
+
const own = settling(stop);
|
|
14849
|
+
await Promise.race(file.changed ? [own, file.changed(stop)] : [own]);
|
|
14850
|
+
} catch (err) {
|
|
14851
|
+
throw signal?.aborted ? new KernelError("EINTR") : err;
|
|
14852
|
+
} finally {
|
|
14853
|
+
round.abort();
|
|
14854
|
+
}
|
|
14855
|
+
};
|
|
14856
|
+
const turn = async (signal) => {
|
|
14857
|
+
for (let waited = false; ; waited = true) {
|
|
14858
|
+
if (quiet2() && (pollFile(file).writable || !file.changed)) {
|
|
14859
|
+
busy = true;
|
|
14860
|
+
return;
|
|
14861
|
+
}
|
|
14862
|
+
if (signal?.aborted) throw new KernelError(waited ? "EINTR" : "EAGAIN");
|
|
14863
|
+
await changed(signal);
|
|
14864
|
+
}
|
|
14865
|
+
};
|
|
14866
|
+
const send = async (out, signal) => {
|
|
14867
|
+
const write = file.write;
|
|
14868
|
+
for (let at = 0; at < out.length; ) {
|
|
14869
|
+
try {
|
|
14870
|
+
at += await write.call(file, out.subarray(at), signal);
|
|
14871
|
+
} catch (err) {
|
|
14872
|
+
if (!signal?.aborted || !interrupted2(err)) throw err;
|
|
14873
|
+
}
|
|
14874
|
+
if (at < out.length && signal?.aborted) return later(out.subarray(at));
|
|
14875
|
+
}
|
|
14653
14876
|
};
|
|
14654
14877
|
const release = () => {
|
|
14655
14878
|
timer = void 0;
|
|
14656
|
-
|
|
14657
|
-
failed3 = err;
|
|
14658
|
-
});
|
|
14879
|
+
later(stream2.idle());
|
|
14659
14880
|
};
|
|
14660
14881
|
return new OpenFile({
|
|
14661
14882
|
...bound(file, "read"),
|
|
14662
14883
|
...bound(file, "peek"),
|
|
14663
|
-
...bound(file, "poll"),
|
|
14664
|
-
...bound(file, "changed"),
|
|
14665
14884
|
...bound(file, "stat"),
|
|
14885
|
+
poll: () => {
|
|
14886
|
+
const state = pollFile(file);
|
|
14887
|
+
return quiet2() ? state : { ...state, writable: false };
|
|
14888
|
+
},
|
|
14889
|
+
changed,
|
|
14666
14890
|
...file.tty ? { tty: file.tty } : {},
|
|
14667
14891
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
14668
14892
|
...file.write ? {
|
|
14669
14893
|
write: async (bytes, signal) => {
|
|
14670
|
-
|
|
14671
|
-
|
|
14672
|
-
|
|
14894
|
+
await turn(signal);
|
|
14895
|
+
const taken = signal?.aborted && bytes.length > SCRUB_NONBLOCK_MAX ? bytes.subarray(0, SCRUB_NONBLOCK_MAX) : bytes;
|
|
14896
|
+
try {
|
|
14897
|
+
raise();
|
|
14898
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
14899
|
+
timer = void 0;
|
|
14900
|
+
await send(stream2.push(taken), signal);
|
|
14901
|
+
} finally {
|
|
14902
|
+
busy = false;
|
|
14903
|
+
if (quiet2()) wake();
|
|
14904
|
+
}
|
|
14673
14905
|
timer = setTimeout(release, idleMs);
|
|
14674
|
-
return
|
|
14906
|
+
return taken.length;
|
|
14675
14907
|
}
|
|
14676
14908
|
} : {},
|
|
14677
14909
|
flush: async () => {
|
|
14678
|
-
await
|
|
14910
|
+
await settled();
|
|
14679
14911
|
raise();
|
|
14680
14912
|
await file.flush?.();
|
|
14681
14913
|
},
|
|
@@ -14683,7 +14915,9 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
14683
14915
|
if (timer !== void 0) clearTimeout(timer);
|
|
14684
14916
|
let failure;
|
|
14685
14917
|
try {
|
|
14686
|
-
await
|
|
14918
|
+
await settled();
|
|
14919
|
+
later(stream2.end());
|
|
14920
|
+
await settled();
|
|
14687
14921
|
raise();
|
|
14688
14922
|
} catch (err) {
|
|
14689
14923
|
failure = { err };
|
|
@@ -14859,12 +15093,12 @@ var SealedChannel = class {
|
|
|
14859
15093
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
14860
15094
|
let stop = () => {
|
|
14861
15095
|
};
|
|
14862
|
-
const
|
|
15096
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
14863
15097
|
stop = () => reject(new KernelError("EINTR"));
|
|
14864
15098
|
signal.addEventListener("abort", stop, { once: true });
|
|
14865
15099
|
});
|
|
14866
15100
|
try {
|
|
14867
|
-
await Promise.race([flight.done,
|
|
15101
|
+
await Promise.race([flight.done, interrupted3]);
|
|
14868
15102
|
} finally {
|
|
14869
15103
|
signal.removeEventListener("abort", stop);
|
|
14870
15104
|
}
|
|
@@ -17132,15 +17366,25 @@ function shebang(head) {
|
|
|
17132
17366
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
17133
17367
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
17134
17368
|
}
|
|
17135
|
-
async function rootOnly(fs, path) {
|
|
17369
|
+
async function rootOnly(fs, path, dir = false) {
|
|
17136
17370
|
const names = chain(path);
|
|
17137
17371
|
for (const [i, at] of names.entries()) {
|
|
17138
17372
|
const st = await fs.lstat(at).catch(() => void 0);
|
|
17139
|
-
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17373
|
+
const kind = i === names.length - 1 && !dir ? st?.isFile : st?.isDirectory;
|
|
17140
17374
|
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17141
17375
|
}
|
|
17142
17376
|
return true;
|
|
17143
17377
|
}
|
|
17378
|
+
function appendedRoots(given) {
|
|
17379
|
+
const roots = given?.append ?? [];
|
|
17380
|
+
if (!Array.isArray(roots)) throw new TypeError("commands.append must be an array of paths");
|
|
17381
|
+
for (const root of roots) {
|
|
17382
|
+
if (typeof root !== "string" || !root.startsWith("/") || normalizePath(root) !== root) {
|
|
17383
|
+
throw new TypeError(`commands.append: not an absolute, normalised path: ${String(root)}`);
|
|
17384
|
+
}
|
|
17385
|
+
}
|
|
17386
|
+
return [...roots];
|
|
17387
|
+
}
|
|
17144
17388
|
function plainEnv(words2) {
|
|
17145
17389
|
const next2 = words2[1];
|
|
17146
17390
|
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
@@ -17233,6 +17477,8 @@ var Launcher = class {
|
|
|
17233
17477
|
base;
|
|
17234
17478
|
createWorker;
|
|
17235
17479
|
modulesDir;
|
|
17480
|
+
appended;
|
|
17481
|
+
reportedRoots = /* @__PURE__ */ new Set();
|
|
17236
17482
|
env;
|
|
17237
17483
|
catalogs = /* @__PURE__ */ new Map();
|
|
17238
17484
|
ownCatalogs = /* @__PURE__ */ new Map();
|
|
@@ -17339,6 +17585,7 @@ var Launcher = class {
|
|
|
17339
17585
|
this.processMounts = options.processMounts ?? true;
|
|
17340
17586
|
this.pnpmHome = options.env?.PNPM_HOME ?? SYSTEM_PNPM_HOME;
|
|
17341
17587
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17588
|
+
this.appended = appendedRoots(options.commands);
|
|
17342
17589
|
this.cdp = new CdpHosts(options.cdp);
|
|
17343
17590
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17344
17591
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
@@ -17388,9 +17635,9 @@ var Launcher = class {
|
|
|
17388
17635
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
17389
17636
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
17390
17637
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
17391
|
-
options.fs.protect?.(this.prefixes);
|
|
17392
17638
|
const integrity = options.protect?.integrity;
|
|
17393
17639
|
integrityOptions(integrity);
|
|
17640
|
+
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
17394
17641
|
if (integrity && this.prefixes.length > 0) {
|
|
17395
17642
|
this.integrity = new Integrity(
|
|
17396
17643
|
this.prefixes,
|
|
@@ -17413,7 +17660,7 @@ var Launcher = class {
|
|
|
17413
17660
|
});
|
|
17414
17661
|
void this.unlinked.sweep("/");
|
|
17415
17662
|
this.watchers.watch(
|
|
17416
|
-
[this.modulesDir, this.pnpmHome],
|
|
17663
|
+
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
17417
17664
|
{ recursive: true },
|
|
17418
17665
|
() => this.resetCatalogs()
|
|
17419
17666
|
);
|
|
@@ -17444,7 +17691,10 @@ var Launcher = class {
|
|
|
17444
17691
|
commands(scope = "") {
|
|
17445
17692
|
let found = this.catalogs.get(scope);
|
|
17446
17693
|
if (!found) {
|
|
17447
|
-
found = this.
|
|
17694
|
+
found = this.trustedAppended().then(async (appended) => {
|
|
17695
|
+
const roots = await this.roots(scope, appended);
|
|
17696
|
+
return scanCommands(this.scanned, roots, roots.length - appended.length);
|
|
17697
|
+
}).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
|
|
17448
17698
|
this.catalogs.set(scope, found);
|
|
17449
17699
|
}
|
|
17450
17700
|
return found;
|
|
@@ -17471,10 +17721,37 @@ var Launcher = class {
|
|
|
17471
17721
|
}
|
|
17472
17722
|
return found;
|
|
17473
17723
|
}
|
|
17474
|
-
async roots(scope = "") {
|
|
17475
|
-
const system = [
|
|
17724
|
+
async roots(scope = "", appended) {
|
|
17725
|
+
const system = [
|
|
17726
|
+
this.modulesDir,
|
|
17727
|
+
...await pnpmGlobalRoots(this.base, this.pnpmHome),
|
|
17728
|
+
...appended ?? await this.trustedAppended()
|
|
17729
|
+
];
|
|
17476
17730
|
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
17477
17731
|
}
|
|
17732
|
+
async rootOnlyPath(root) {
|
|
17733
|
+
for (const at of chain(root)) {
|
|
17734
|
+
const real = await physicalPathAsync(this.base, at);
|
|
17735
|
+
if (!await rootOnly(this.base, real, true)) return false;
|
|
17736
|
+
}
|
|
17737
|
+
return true;
|
|
17738
|
+
}
|
|
17739
|
+
async trustedAppended() {
|
|
17740
|
+
if (this.appended.length === 0 || this.usersMode === "off") return this.appended;
|
|
17741
|
+
const trusted = [];
|
|
17742
|
+
for (const root of this.appended) {
|
|
17743
|
+
const real = await physicalPathAsync(this.base, root);
|
|
17744
|
+
if (await this.rootOnlyPath(root)) trusted.push(root);
|
|
17745
|
+
else if (this.usersMode === "report" && await this.base.exists(real)) {
|
|
17746
|
+
if (!this.reportedRoots.has(root)) {
|
|
17747
|
+
this.reportedRoots.add(root);
|
|
17748
|
+
this.dac?.denied({ pid: 0, uid: 0, op: "commands", path: root, errno: "EACCES" });
|
|
17749
|
+
}
|
|
17750
|
+
trusted.push(root);
|
|
17751
|
+
}
|
|
17752
|
+
}
|
|
17753
|
+
return trusted;
|
|
17754
|
+
}
|
|
17478
17755
|
resetCatalogs() {
|
|
17479
17756
|
this.catalogs.clear();
|
|
17480
17757
|
this.ownCatalogs.clear();
|
|
@@ -17580,14 +17857,22 @@ var Launcher = class {
|
|
|
17580
17857
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
17581
17858
|
const via = [interp, ...inner?.via ?? []];
|
|
17582
17859
|
const sources = [script, ...inner?.sources ?? []];
|
|
17583
|
-
|
|
17860
|
+
const bins = [...command?.bin ? [script] : [], ...inner?.bins ?? []];
|
|
17861
|
+
return inner && {
|
|
17862
|
+
...inner,
|
|
17863
|
+
target: withScriptEnv(inner.target, command),
|
|
17864
|
+
via,
|
|
17865
|
+
sources,
|
|
17866
|
+
...bins.length > 0 ? { bins } : {}
|
|
17867
|
+
};
|
|
17584
17868
|
}
|
|
17585
17869
|
const target = withScriptEnv(found, command);
|
|
17586
17870
|
return {
|
|
17587
17871
|
target,
|
|
17588
17872
|
args: [...target.prefix ?? [], ...passed],
|
|
17589
17873
|
via: [interp],
|
|
17590
|
-
sources: [script]
|
|
17874
|
+
sources: [script],
|
|
17875
|
+
...command?.bin ? { bins: [script] } : {}
|
|
17591
17876
|
};
|
|
17592
17877
|
}
|
|
17593
17878
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17613,6 +17898,7 @@ var Launcher = class {
|
|
|
17613
17898
|
const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
|
|
17614
17899
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
17615
17900
|
}
|
|
17901
|
+
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
17616
17902
|
}
|
|
17617
17903
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17618
17904
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
@@ -17878,11 +18164,9 @@ var Launcher = class {
|
|
|
17878
18164
|
groupSession(pgid) {
|
|
17879
18165
|
return this.jobs.sessionOf(pgid);
|
|
17880
18166
|
}
|
|
17881
|
-
treeScrubs(
|
|
18167
|
+
treeScrubs(req) {
|
|
17882
18168
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
17883
|
-
|
|
17884
|
-
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
17885
|
-
return scrubs;
|
|
18169
|
+
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
17886
18170
|
}
|
|
17887
18171
|
start(req) {
|
|
17888
18172
|
this.sampling();
|
|
@@ -17890,7 +18174,7 @@ var Launcher = class {
|
|
|
17890
18174
|
throw new SpawnError("ESRCH");
|
|
17891
18175
|
}
|
|
17892
18176
|
const pid = req.pid ?? this.nextPid++;
|
|
17893
|
-
const scrubs = this.treeScrubs(
|
|
18177
|
+
const scrubs = this.treeScrubs(req);
|
|
17894
18178
|
const stack = this.stackFor(req.tag);
|
|
17895
18179
|
const terminal = req.fds.stdioTerminal();
|
|
17896
18180
|
const decided = req.decided ?? Promise.resolve(true);
|
|
@@ -17911,6 +18195,7 @@ var Launcher = class {
|
|
|
17911
18195
|
},
|
|
17912
18196
|
settling: () => this.settling.isSettling(pid),
|
|
17913
18197
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
18198
|
+
...req.blocked ? { blocked: req.blocked } : {},
|
|
17914
18199
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
17915
18200
|
cred: req.cred,
|
|
17916
18201
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
@@ -17959,6 +18244,7 @@ var Launcher = class {
|
|
|
17959
18244
|
...this.shownIds(req)
|
|
17960
18245
|
});
|
|
17961
18246
|
this.processes.set(pid, handle);
|
|
18247
|
+
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
17962
18248
|
const { cred } = req;
|
|
17963
18249
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
17964
18250
|
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
@@ -18185,6 +18471,7 @@ var Launcher = class {
|
|
|
18185
18471
|
report,
|
|
18186
18472
|
ppid,
|
|
18187
18473
|
ignored: this.ignoredBy(ppid),
|
|
18474
|
+
blocked: this.blockedBy(ppid),
|
|
18188
18475
|
umask: this.umaskOf(ppid),
|
|
18189
18476
|
cred,
|
|
18190
18477
|
tag: this.tagOf(ppid),
|
|
@@ -18246,6 +18533,7 @@ var Launcher = class {
|
|
|
18246
18533
|
ppid,
|
|
18247
18534
|
fork: state,
|
|
18248
18535
|
ignored: this.ignoredBy(ppid, true),
|
|
18536
|
+
blocked: this.blockedBy(ppid),
|
|
18249
18537
|
umask: this.umaskOf(ppid),
|
|
18250
18538
|
cred: this.credOf(ppid),
|
|
18251
18539
|
tag: this.tagOf(ppid)
|
|
@@ -18297,11 +18585,16 @@ var Launcher = class {
|
|
|
18297
18585
|
}
|
|
18298
18586
|
signalMasksOf(pid) {
|
|
18299
18587
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
18300
|
-
|
|
18588
|
+
const blocked = this.blockedBy(pid);
|
|
18589
|
+
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
18590
|
+
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
18301
18591
|
}
|
|
18302
18592
|
controlsJobs(pid) {
|
|
18303
18593
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
18304
18594
|
}
|
|
18595
|
+
blockedBy(pid) {
|
|
18596
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
18597
|
+
}
|
|
18305
18598
|
ignoredBy(pid, fork = false) {
|
|
18306
18599
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
18307
18600
|
}
|
|
@@ -18666,7 +18959,7 @@ var Launcher = class {
|
|
|
18666
18959
|
(dir) => this.userCommandDir(dir),
|
|
18667
18960
|
this.owners
|
|
18668
18961
|
);
|
|
18669
|
-
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
18962
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
18670
18963
|
nodes.keepsOnDisk = true;
|
|
18671
18964
|
this.openFiles.add(nodes);
|
|
18672
18965
|
const unlinked = new UnlinkedKeeper(
|
|
@@ -20059,6 +20352,7 @@ async function createNodeKernel(options = {}) {
|
|
|
20059
20352
|
terminated
|
|
20060
20353
|
),
|
|
20061
20354
|
...options.modules ? { modules: options.modules } : {},
|
|
20355
|
+
...options.commands ? { commands: options.commands } : {},
|
|
20062
20356
|
...options.env ? { env: options.env } : {},
|
|
20063
20357
|
...transport ? { transport } : {},
|
|
20064
20358
|
...options.network?.uplink ? { uplink: options.network.uplink } : {},
|