@ai-ecoverse/slicc-kernel 1.87.0 → 1.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -7
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +280 -64
- 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 +274 -56
- 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;
|
|
@@ -8269,7 +8364,7 @@ async function dispatchOne(entry, req) {
|
|
|
8269
8364
|
}
|
|
8270
8365
|
|
|
8271
8366
|
// src/realm/sync-sab-wire.ts
|
|
8272
|
-
var SAB_HEADER_I32 =
|
|
8367
|
+
var SAB_HEADER_I32 = 18;
|
|
8273
8368
|
var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
|
|
8274
8369
|
var SAB_CLOCK_I64 = 3;
|
|
8275
8370
|
var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
|
|
@@ -8289,6 +8384,7 @@ var SAB_I_OFFSET_HI = 12;
|
|
|
8289
8384
|
var SAB_I_KILLED = 13;
|
|
8290
8385
|
var SAB_I_ASYNC = 14;
|
|
8291
8386
|
var SAB_I_STOP = 15;
|
|
8387
|
+
var SAB_I_BLOCKED = 16;
|
|
8292
8388
|
var U32 = 2 ** 32;
|
|
8293
8389
|
function storeU53(header4, lo, hi, value) {
|
|
8294
8390
|
Atomics.store(header4, hi, Math.floor(value / U32));
|
|
@@ -8841,12 +8937,32 @@ function mountTable(mounts = []) {
|
|
|
8841
8937
|
`;
|
|
8842
8938
|
}
|
|
8843
8939
|
|
|
8940
|
+
// src/version.ts
|
|
8941
|
+
var KERNEL_VERSION = true ? "1.88.0" : "0.0.0-dev";
|
|
8942
|
+
var OS_RELEASE = "6.0.0-slicc";
|
|
8943
|
+
function procVersion() {
|
|
8944
|
+
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
8945
|
+
`;
|
|
8946
|
+
}
|
|
8947
|
+
|
|
8844
8948
|
// src/process/procfs.ts
|
|
8845
8949
|
var HZ = 100;
|
|
8846
8950
|
var KIB = 1024;
|
|
8847
8951
|
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
8848
8952
|
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
8849
|
-
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
|
|
8953
|
+
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime", "version"];
|
|
8954
|
+
var SYS_TREE = {
|
|
8955
|
+
kernel: { osrelease: `${OS_RELEASE}
|
|
8956
|
+
`, ostype: "Linux\n" }
|
|
8957
|
+
};
|
|
8958
|
+
function sysEntry(parts2) {
|
|
8959
|
+
let at = SYS_TREE;
|
|
8960
|
+
for (const part of parts2) {
|
|
8961
|
+
if (typeof at !== "object" || !Object.hasOwn(at, part)) return void 0;
|
|
8962
|
+
at = at[part];
|
|
8963
|
+
}
|
|
8964
|
+
return at;
|
|
8965
|
+
}
|
|
8850
8966
|
function commOf(info) {
|
|
8851
8967
|
const name2 = info.argv[0] ?? "";
|
|
8852
8968
|
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
@@ -8934,7 +9050,7 @@ function pidStatus(info) {
|
|
|
8934
9050
|
"SigQ: 0/0",
|
|
8935
9051
|
"SigPnd: 0000000000000000",
|
|
8936
9052
|
"ShdPnd: 0000000000000000",
|
|
8937
|
-
|
|
9053
|
+
`SigBlk: ${sigMask(info.sigBlk)}`,
|
|
8938
9054
|
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
8939
9055
|
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
8940
9056
|
""
|
|
@@ -8970,6 +9086,7 @@ function memoryInfo(source, used = 0) {
|
|
|
8970
9086
|
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
8971
9087
|
}
|
|
8972
9088
|
function systemFile(name2, listing, now, memory) {
|
|
9089
|
+
if (name2 === "version") return procVersion();
|
|
8973
9090
|
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
8974
9091
|
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
8975
9092
|
`;
|
|
@@ -9060,11 +9177,17 @@ var ProcTree = class {
|
|
|
9060
9177
|
names: () => [
|
|
9061
9178
|
...SYSTEM_NAMES,
|
|
9062
9179
|
"mounts",
|
|
9180
|
+
"sys",
|
|
9063
9181
|
"self",
|
|
9064
9182
|
...this.listing().processes.map((p) => String(p.pid))
|
|
9065
9183
|
]
|
|
9066
9184
|
};
|
|
9067
9185
|
}
|
|
9186
|
+
if (top === "sys") {
|
|
9187
|
+
const entry = sysEntry(parts2.slice(1));
|
|
9188
|
+
if (typeof entry === "string") return { kind: "file", content: () => entry };
|
|
9189
|
+
return entry && { kind: "dir", names: () => Object.keys(entry) };
|
|
9190
|
+
}
|
|
9068
9191
|
if (top === "self") {
|
|
9069
9192
|
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
9070
9193
|
}
|
|
@@ -9142,7 +9265,7 @@ var ProcTree = class {
|
|
|
9142
9265
|
}
|
|
9143
9266
|
}
|
|
9144
9267
|
};
|
|
9145
|
-
var
|
|
9268
|
+
var MAX_HOPS3 = 40;
|
|
9146
9269
|
function* procWalk(path, follow2) {
|
|
9147
9270
|
let done4 = [];
|
|
9148
9271
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -9161,7 +9284,7 @@ function* procWalk(path, follow2) {
|
|
|
9161
9284
|
if (!follow2 && todo.length === 0) return void 0;
|
|
9162
9285
|
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
9163
9286
|
if (typeof target === "string") {
|
|
9164
|
-
if (++hops >
|
|
9287
|
+
if (++hops > MAX_HOPS3) return void 0;
|
|
9165
9288
|
[done4, todo] = throughLink(target, done4, todo);
|
|
9166
9289
|
} else {
|
|
9167
9290
|
broken ??= refusalOf(target);
|
|
@@ -12041,11 +12164,12 @@ var VfsNodes = class {
|
|
|
12041
12164
|
byId = /* @__PURE__ */ new Map();
|
|
12042
12165
|
keepsOnDisk = false;
|
|
12043
12166
|
fs;
|
|
12044
|
-
entries
|
|
12167
|
+
entries;
|
|
12045
12168
|
onClosed;
|
|
12046
|
-
constructor(fs, onClosed) {
|
|
12169
|
+
constructor(fs, onClosed, entries = /* @__PURE__ */ new Map()) {
|
|
12047
12170
|
this.fs = fs;
|
|
12048
12171
|
this.onClosed = onClosed;
|
|
12172
|
+
this.entries = entries;
|
|
12049
12173
|
}
|
|
12050
12174
|
async onEntry(path, op) {
|
|
12051
12175
|
const key = await this.entryKey(path);
|
|
@@ -12535,6 +12659,7 @@ var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
|
12535
12659
|
var WasmProcess = class {
|
|
12536
12660
|
exited = false;
|
|
12537
12661
|
children;
|
|
12662
|
+
deathSignals = /* @__PURE__ */ new Map();
|
|
12538
12663
|
caught = 0;
|
|
12539
12664
|
ignored = 0;
|
|
12540
12665
|
inherited = 0;
|
|
@@ -12569,7 +12694,10 @@ var WasmProcess = class {
|
|
|
12569
12694
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
12570
12695
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
12571
12696
|
this.children.onChildState = () => this.signal(SIG.CHLD);
|
|
12572
|
-
this.children.onReap =
|
|
12697
|
+
this.children.onReap = (pid2) => {
|
|
12698
|
+
this.deathSignals.delete(pid2);
|
|
12699
|
+
options.onReap?.(pid2);
|
|
12700
|
+
};
|
|
12573
12701
|
}
|
|
12574
12702
|
ignores(bit) {
|
|
12575
12703
|
return (this.signalMasks().ignored & bit) !== 0;
|
|
@@ -12597,6 +12725,10 @@ var WasmProcess = class {
|
|
|
12597
12725
|
if (sig === SIG.STOP) return this.stop(sig);
|
|
12598
12726
|
const bit = sigbit(sig);
|
|
12599
12727
|
if (this.ignores(bit)) return "ignore";
|
|
12728
|
+
if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
|
|
12729
|
+
this.options.onPending?.(sig);
|
|
12730
|
+
return "deliver";
|
|
12731
|
+
}
|
|
12600
12732
|
if (!(this.caught & bit)) {
|
|
12601
12733
|
const action = defaultAction(sig);
|
|
12602
12734
|
return action === "stop" ? this.stop(sig) : action;
|
|
@@ -12613,16 +12745,27 @@ var WasmProcess = class {
|
|
|
12613
12745
|
return "deliver";
|
|
12614
12746
|
}
|
|
12615
12747
|
async spawn(req) {
|
|
12616
|
-
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session } = req;
|
|
12748
|
+
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
|
|
12749
|
+
if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
|
|
12750
|
+
throw new KernelError("EINVAL");
|
|
12751
|
+
}
|
|
12617
12752
|
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12618
12753
|
const named = argv0 !== void 0 ? { argv0 } : {};
|
|
12619
12754
|
const spawned = { file, argv, ...named, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
12620
12755
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
12756
|
+
if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
|
|
12621
12757
|
if (!exec) return pid;
|
|
12622
12758
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
12623
12759
|
else this.adoptExec(pid);
|
|
12624
12760
|
return pid;
|
|
12625
12761
|
}
|
|
12762
|
+
onDeath(target, sig) {
|
|
12763
|
+
if (this.exited) this.sendDeath(target, sig);
|
|
12764
|
+
else this.deathSignals.set(target, sig);
|
|
12765
|
+
}
|
|
12766
|
+
sendDeath(target, sig) {
|
|
12767
|
+
void Promise.resolve(this.options.kill?.(target, sig)).catch(() => void 0);
|
|
12768
|
+
}
|
|
12626
12769
|
async killSelf(sig, target, probe2) {
|
|
12627
12770
|
if (!this.options.exitSignal) throw new KernelError("ENOSYS");
|
|
12628
12771
|
if (!isSignal(sig) || defaultAction(sig) !== "terminate") throw new KernelError("EINVAL");
|
|
@@ -13521,6 +13664,8 @@ var WasmProcess = class {
|
|
|
13521
13664
|
this.interrupt.abort();
|
|
13522
13665
|
this.options.locks?.release(this.pid);
|
|
13523
13666
|
this.asyncOps.close();
|
|
13667
|
+
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
13668
|
+
this.deathSignals.clear();
|
|
13524
13669
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13525
13670
|
await this.stampClipboards();
|
|
13526
13671
|
await this.fds.closeAll();
|
|
@@ -13600,19 +13745,25 @@ var Dying = class {
|
|
|
13600
13745
|
}
|
|
13601
13746
|
};
|
|
13602
13747
|
function killThread(thread, caught, sig) {
|
|
13603
|
-
if (!thread
|
|
13748
|
+
if (!thread) return false;
|
|
13749
|
+
const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
|
|
13750
|
+
if (!held && (caught & sigbit(sig)) === 0) return false;
|
|
13604
13751
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
13752
|
+
if (held) return true;
|
|
13605
13753
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
13606
13754
|
const blocked = thread.interrupt;
|
|
13607
13755
|
thread.interrupt = new AbortController();
|
|
13608
13756
|
blocked.abort();
|
|
13609
13757
|
return true;
|
|
13610
13758
|
}
|
|
13759
|
+
function unblocked(header4) {
|
|
13760
|
+
return Atomics.load(header4, SAB_I_SIGNALS) & ~Atomics.load(header4, SAB_I_BLOCKED);
|
|
13761
|
+
}
|
|
13611
13762
|
function threadSignalsOf(sab) {
|
|
13612
13763
|
return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
|
|
13613
13764
|
}
|
|
13614
13765
|
function threadCancel(thread) {
|
|
13615
|
-
return
|
|
13766
|
+
return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
|
|
13616
13767
|
}
|
|
13617
13768
|
function notifiers(header4) {
|
|
13618
13769
|
return {
|
|
@@ -13737,15 +13888,16 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
13737
13888
|
resolver: opts.resolver,
|
|
13738
13889
|
...notifiers(header4),
|
|
13739
13890
|
onTimer: (which) => void Atomics.or(header4, SAB_I_TIMERS, 1 << which),
|
|
13740
|
-
hasPending: () =>
|
|
13891
|
+
hasPending: () => unblocked(header4) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
|
|
13741
13892
|
raise: hooks.raise,
|
|
13742
13893
|
threadKill: hooks.threadKill,
|
|
13743
13894
|
...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
|
|
13744
13895
|
...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
|
|
13745
|
-
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {}
|
|
13896
|
+
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header4, SAB_I_SIGNALS) } : {},
|
|
13897
|
+
...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header4, SAB_I_BLOCKED) } : {}
|
|
13746
13898
|
};
|
|
13747
13899
|
}
|
|
13748
|
-
function threadInit(opts, program, sab, cred, thread) {
|
|
13900
|
+
function threadInit(opts, program, sab, cred, thread, main) {
|
|
13749
13901
|
return {
|
|
13750
13902
|
type: WASM_THREAD_INIT,
|
|
13751
13903
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -13758,12 +13910,15 @@ function threadInit(opts, program, sab, cred, thread) {
|
|
|
13758
13910
|
cred: copyCred(cred),
|
|
13759
13911
|
owners: opts.owners === true,
|
|
13760
13912
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
13761
|
-
thread
|
|
13913
|
+
thread,
|
|
13914
|
+
signals: main
|
|
13762
13915
|
};
|
|
13763
13916
|
}
|
|
13764
13917
|
function spawnWasmProcess(opts) {
|
|
13765
13918
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13766
13919
|
const header4 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
13920
|
+
if (opts.blocked && opts.program.abi === "wasi")
|
|
13921
|
+
Atomics.store(header4, SAB_I_BLOCKED, opts.blocked);
|
|
13767
13922
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
13768
13923
|
const created3 = new Created();
|
|
13769
13924
|
const process2 = new WasmProcess(
|
|
@@ -13864,6 +14019,7 @@ function spawnWasmProcess(opts) {
|
|
|
13864
14019
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13865
14020
|
const tw = opts.createWorker();
|
|
13866
14021
|
const tsignals = threadSignalsOf(tsab);
|
|
14022
|
+
if (thread.blocked) Atomics.store(tsignals.header, SAB_I_BLOCKED, thread.blocked);
|
|
13867
14023
|
threadSignals.set(thread.tid, tsignals);
|
|
13868
14024
|
const tdispatch = (req) => dying.serving(
|
|
13869
14025
|
() => isWasmSyscall(req) ? process2.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -13885,7 +14041,7 @@ function spawnWasmProcess(opts) {
|
|
|
13885
14041
|
tresponder.dispose();
|
|
13886
14042
|
tw.terminate();
|
|
13887
14043
|
});
|
|
13888
|
-
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread));
|
|
14044
|
+
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread, sab));
|
|
13889
14045
|
};
|
|
13890
14046
|
worker.postMessage(
|
|
13891
14047
|
processInit(opts, sab, process2.umask, copyCred(process2.cred), lane?.lane),
|
|
@@ -13907,6 +14063,7 @@ function spawnWasmProcess(opts) {
|
|
|
13907
14063
|
onState: (listener) => process2.onState(listener),
|
|
13908
14064
|
memory: () => Atomics.load(header4, SAB_I_MEMORY) * 65536,
|
|
13909
14065
|
ignoredSignals: (fork) => process2.inheritable(fork),
|
|
14066
|
+
blockedSignals: () => opts.program.abi === "wasi" ? Atomics.load(header4, SAB_I_BLOCKED) : 0,
|
|
13910
14067
|
signalMasks: () => process2.signalMasks(),
|
|
13911
14068
|
umask: () => process2.umask,
|
|
13912
14069
|
cred: () => copyCred(process2.cred),
|
|
@@ -17132,15 +17289,25 @@ function shebang(head) {
|
|
|
17132
17289
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
17133
17290
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
17134
17291
|
}
|
|
17135
|
-
async function rootOnly(fs, path) {
|
|
17292
|
+
async function rootOnly(fs, path, dir = false) {
|
|
17136
17293
|
const names = chain(path);
|
|
17137
17294
|
for (const [i, at] of names.entries()) {
|
|
17138
17295
|
const st = await fs.lstat(at).catch(() => void 0);
|
|
17139
|
-
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17296
|
+
const kind = i === names.length - 1 && !dir ? st?.isFile : st?.isDirectory;
|
|
17140
17297
|
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17141
17298
|
}
|
|
17142
17299
|
return true;
|
|
17143
17300
|
}
|
|
17301
|
+
function appendedRoots(given) {
|
|
17302
|
+
const roots = given?.append ?? [];
|
|
17303
|
+
if (!Array.isArray(roots)) throw new TypeError("commands.append must be an array of paths");
|
|
17304
|
+
for (const root of roots) {
|
|
17305
|
+
if (typeof root !== "string" || !root.startsWith("/") || normalizePath(root) !== root) {
|
|
17306
|
+
throw new TypeError(`commands.append: not an absolute, normalised path: ${String(root)}`);
|
|
17307
|
+
}
|
|
17308
|
+
}
|
|
17309
|
+
return [...roots];
|
|
17310
|
+
}
|
|
17144
17311
|
function plainEnv(words2) {
|
|
17145
17312
|
const next2 = words2[1];
|
|
17146
17313
|
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
@@ -17233,6 +17400,8 @@ var Launcher = class {
|
|
|
17233
17400
|
base;
|
|
17234
17401
|
createWorker;
|
|
17235
17402
|
modulesDir;
|
|
17403
|
+
appended;
|
|
17404
|
+
reportedRoots = /* @__PURE__ */ new Set();
|
|
17236
17405
|
env;
|
|
17237
17406
|
catalogs = /* @__PURE__ */ new Map();
|
|
17238
17407
|
ownCatalogs = /* @__PURE__ */ new Map();
|
|
@@ -17339,6 +17508,7 @@ var Launcher = class {
|
|
|
17339
17508
|
this.processMounts = options.processMounts ?? true;
|
|
17340
17509
|
this.pnpmHome = options.env?.PNPM_HOME ?? SYSTEM_PNPM_HOME;
|
|
17341
17510
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17511
|
+
this.appended = appendedRoots(options.commands);
|
|
17342
17512
|
this.cdp = new CdpHosts(options.cdp);
|
|
17343
17513
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17344
17514
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
@@ -17388,9 +17558,9 @@ var Launcher = class {
|
|
|
17388
17558
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
17389
17559
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
17390
17560
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
17391
|
-
options.fs.protect?.(this.prefixes);
|
|
17392
17561
|
const integrity = options.protect?.integrity;
|
|
17393
17562
|
integrityOptions(integrity);
|
|
17563
|
+
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
17394
17564
|
if (integrity && this.prefixes.length > 0) {
|
|
17395
17565
|
this.integrity = new Integrity(
|
|
17396
17566
|
this.prefixes,
|
|
@@ -17413,7 +17583,7 @@ var Launcher = class {
|
|
|
17413
17583
|
});
|
|
17414
17584
|
void this.unlinked.sweep("/");
|
|
17415
17585
|
this.watchers.watch(
|
|
17416
|
-
[this.modulesDir, this.pnpmHome],
|
|
17586
|
+
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
17417
17587
|
{ recursive: true },
|
|
17418
17588
|
() => this.resetCatalogs()
|
|
17419
17589
|
);
|
|
@@ -17444,7 +17614,10 @@ var Launcher = class {
|
|
|
17444
17614
|
commands(scope = "") {
|
|
17445
17615
|
let found = this.catalogs.get(scope);
|
|
17446
17616
|
if (!found) {
|
|
17447
|
-
found = this.
|
|
17617
|
+
found = this.trustedAppended().then(async (appended) => {
|
|
17618
|
+
const roots = await this.roots(scope, appended);
|
|
17619
|
+
return scanCommands(this.scanned, roots, roots.length - appended.length);
|
|
17620
|
+
}).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
|
|
17448
17621
|
this.catalogs.set(scope, found);
|
|
17449
17622
|
}
|
|
17450
17623
|
return found;
|
|
@@ -17471,10 +17644,37 @@ var Launcher = class {
|
|
|
17471
17644
|
}
|
|
17472
17645
|
return found;
|
|
17473
17646
|
}
|
|
17474
|
-
async roots(scope = "") {
|
|
17475
|
-
const system = [
|
|
17647
|
+
async roots(scope = "", appended) {
|
|
17648
|
+
const system = [
|
|
17649
|
+
this.modulesDir,
|
|
17650
|
+
...await pnpmGlobalRoots(this.base, this.pnpmHome),
|
|
17651
|
+
...appended ?? await this.trustedAppended()
|
|
17652
|
+
];
|
|
17476
17653
|
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
17477
17654
|
}
|
|
17655
|
+
async rootOnlyPath(root) {
|
|
17656
|
+
for (const at of chain(root)) {
|
|
17657
|
+
const real = await physicalPathAsync(this.base, at);
|
|
17658
|
+
if (!await rootOnly(this.base, real, true)) return false;
|
|
17659
|
+
}
|
|
17660
|
+
return true;
|
|
17661
|
+
}
|
|
17662
|
+
async trustedAppended() {
|
|
17663
|
+
if (this.appended.length === 0 || this.usersMode === "off") return this.appended;
|
|
17664
|
+
const trusted = [];
|
|
17665
|
+
for (const root of this.appended) {
|
|
17666
|
+
const real = await physicalPathAsync(this.base, root);
|
|
17667
|
+
if (await this.rootOnlyPath(root)) trusted.push(root);
|
|
17668
|
+
else if (this.usersMode === "report" && await this.base.exists(real)) {
|
|
17669
|
+
if (!this.reportedRoots.has(root)) {
|
|
17670
|
+
this.reportedRoots.add(root);
|
|
17671
|
+
this.dac?.denied({ pid: 0, uid: 0, op: "commands", path: root, errno: "EACCES" });
|
|
17672
|
+
}
|
|
17673
|
+
trusted.push(root);
|
|
17674
|
+
}
|
|
17675
|
+
}
|
|
17676
|
+
return trusted;
|
|
17677
|
+
}
|
|
17478
17678
|
resetCatalogs() {
|
|
17479
17679
|
this.catalogs.clear();
|
|
17480
17680
|
this.ownCatalogs.clear();
|
|
@@ -17580,14 +17780,22 @@ var Launcher = class {
|
|
|
17580
17780
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
17581
17781
|
const via = [interp, ...inner?.via ?? []];
|
|
17582
17782
|
const sources = [script, ...inner?.sources ?? []];
|
|
17583
|
-
|
|
17783
|
+
const bins = [...command?.bin ? [script] : [], ...inner?.bins ?? []];
|
|
17784
|
+
return inner && {
|
|
17785
|
+
...inner,
|
|
17786
|
+
target: withScriptEnv(inner.target, command),
|
|
17787
|
+
via,
|
|
17788
|
+
sources,
|
|
17789
|
+
...bins.length > 0 ? { bins } : {}
|
|
17790
|
+
};
|
|
17584
17791
|
}
|
|
17585
17792
|
const target = withScriptEnv(found, command);
|
|
17586
17793
|
return {
|
|
17587
17794
|
target,
|
|
17588
17795
|
args: [...target.prefix ?? [], ...passed],
|
|
17589
17796
|
via: [interp],
|
|
17590
|
-
sources: [script]
|
|
17797
|
+
sources: [script],
|
|
17798
|
+
...command?.bin ? { bins: [script] } : {}
|
|
17591
17799
|
};
|
|
17592
17800
|
}
|
|
17593
17801
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17613,6 +17821,7 @@ var Launcher = class {
|
|
|
17613
17821
|
const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
|
|
17614
17822
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
17615
17823
|
}
|
|
17824
|
+
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
17616
17825
|
}
|
|
17617
17826
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17618
17827
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
@@ -17911,6 +18120,7 @@ var Launcher = class {
|
|
|
17911
18120
|
},
|
|
17912
18121
|
settling: () => this.settling.isSettling(pid),
|
|
17913
18122
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
18123
|
+
...req.blocked ? { blocked: req.blocked } : {},
|
|
17914
18124
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
17915
18125
|
cred: req.cred,
|
|
17916
18126
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
@@ -18185,6 +18395,7 @@ var Launcher = class {
|
|
|
18185
18395
|
report,
|
|
18186
18396
|
ppid,
|
|
18187
18397
|
ignored: this.ignoredBy(ppid),
|
|
18398
|
+
blocked: this.blockedBy(ppid),
|
|
18188
18399
|
umask: this.umaskOf(ppid),
|
|
18189
18400
|
cred,
|
|
18190
18401
|
tag: this.tagOf(ppid),
|
|
@@ -18246,6 +18457,7 @@ var Launcher = class {
|
|
|
18246
18457
|
ppid,
|
|
18247
18458
|
fork: state,
|
|
18248
18459
|
ignored: this.ignoredBy(ppid, true),
|
|
18460
|
+
blocked: this.blockedBy(ppid),
|
|
18249
18461
|
umask: this.umaskOf(ppid),
|
|
18250
18462
|
cred: this.credOf(ppid),
|
|
18251
18463
|
tag: this.tagOf(ppid)
|
|
@@ -18297,11 +18509,16 @@ var Launcher = class {
|
|
|
18297
18509
|
}
|
|
18298
18510
|
signalMasksOf(pid) {
|
|
18299
18511
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
18300
|
-
|
|
18512
|
+
const blocked = this.blockedBy(pid);
|
|
18513
|
+
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
18514
|
+
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
18301
18515
|
}
|
|
18302
18516
|
controlsJobs(pid) {
|
|
18303
18517
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
18304
18518
|
}
|
|
18519
|
+
blockedBy(pid) {
|
|
18520
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
18521
|
+
}
|
|
18305
18522
|
ignoredBy(pid, fork = false) {
|
|
18306
18523
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
18307
18524
|
}
|
|
@@ -18666,7 +18883,7 @@ var Launcher = class {
|
|
|
18666
18883
|
(dir) => this.userCommandDir(dir),
|
|
18667
18884
|
this.owners
|
|
18668
18885
|
);
|
|
18669
|
-
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
18886
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
18670
18887
|
nodes.keepsOnDisk = true;
|
|
18671
18888
|
this.openFiles.add(nodes);
|
|
18672
18889
|
const unlinked = new UnlinkedKeeper(
|
|
@@ -20059,6 +20276,7 @@ async function createNodeKernel(options = {}) {
|
|
|
20059
20276
|
terminated
|
|
20060
20277
|
),
|
|
20061
20278
|
...options.modules ? { modules: options.modules } : {},
|
|
20279
|
+
...options.commands ? { commands: options.commands } : {},
|
|
20062
20280
|
...options.env ? { env: options.env } : {},
|
|
20063
20281
|
...transport ? { transport } : {},
|
|
20064
20282
|
...options.network?.uplink ? { uplink: options.network.uplink } : {},
|