@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/kernel-worker.js
CHANGED
|
@@ -97,8 +97,8 @@ var MemoryMeta = class {
|
|
|
97
97
|
async get(paths) {
|
|
98
98
|
return paths.map((path) => this.entries.get(path));
|
|
99
99
|
}
|
|
100
|
-
async fresh(
|
|
101
|
-
return this.
|
|
100
|
+
async fresh(paths) {
|
|
101
|
+
return this.get(paths);
|
|
102
102
|
}
|
|
103
103
|
async update(path, change) {
|
|
104
104
|
this.set(path, change(this.entries.get(path)));
|
|
@@ -196,15 +196,13 @@ var IndexedDbMeta = class {
|
|
|
196
196
|
}
|
|
197
197
|
return paths.map((path) => this.cache.get(path) ?? void 0);
|
|
198
198
|
}
|
|
199
|
-
async fresh(
|
|
199
|
+
async fresh(paths) {
|
|
200
200
|
const [transaction, store] = this.transaction("readonly");
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
await settle(transaction, () => void 0);
|
|
207
|
-
return entry;
|
|
201
|
+
const requests = paths.map((path) => store.get(path));
|
|
202
|
+
return settle(
|
|
203
|
+
transaction,
|
|
204
|
+
() => requests.map((request2) => request2.result ?? void 0)
|
|
205
|
+
);
|
|
208
206
|
}
|
|
209
207
|
async update(path, change) {
|
|
210
208
|
this.settleRemoves();
|
|
@@ -1020,8 +1018,25 @@ var OpfsFs = class {
|
|
|
1020
1018
|
}
|
|
1021
1019
|
counted = [];
|
|
1022
1020
|
async stamp(path) {
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1021
|
+
const paths = [path, "/"];
|
|
1022
|
+
const [entry, root] = this.meta.fresh ? await this.meta.fresh(paths) : await this.meta.get(paths);
|
|
1023
|
+
return `${entry?.writes ?? 0}:${root?.epoch ?? 0}`;
|
|
1024
|
+
}
|
|
1025
|
+
async epoch() {
|
|
1026
|
+
await this.meta.update("/", (entry) => ({
|
|
1027
|
+
...entry,
|
|
1028
|
+
path: "/",
|
|
1029
|
+
epoch: (entry?.epoch ?? 0) + 1
|
|
1030
|
+
}));
|
|
1031
|
+
}
|
|
1032
|
+
async entering(path, change) {
|
|
1033
|
+
if (!isProtected(this.counted, path) && !holdsProtected(this.counted, path)) return change();
|
|
1034
|
+
await this.epoch();
|
|
1035
|
+
try {
|
|
1036
|
+
await change();
|
|
1037
|
+
} finally {
|
|
1038
|
+
await this.epoch();
|
|
1039
|
+
}
|
|
1025
1040
|
}
|
|
1026
1041
|
async counting(target) {
|
|
1027
1042
|
if (!isProtected(this.counted, target)) return;
|
|
@@ -1092,9 +1107,9 @@ var OpfsFs = class {
|
|
|
1092
1107
|
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
1093
1108
|
}
|
|
1094
1109
|
guarded = [];
|
|
1095
|
-
protect(prefixes2) {
|
|
1110
|
+
protect(prefixes2, versions = false) {
|
|
1096
1111
|
this.guarded = prefixes2;
|
|
1097
|
-
this.counted = prefixes2;
|
|
1112
|
+
this.counted = versions ? prefixes2 : [];
|
|
1098
1113
|
}
|
|
1099
1114
|
unguarded() {
|
|
1100
1115
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -1674,6 +1689,9 @@ var OpfsFs = class {
|
|
|
1674
1689
|
const parent = await this.locate(parentOf3(to), true);
|
|
1675
1690
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
1676
1691
|
this.refuse(destination, true);
|
|
1692
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
1693
|
+
}
|
|
1694
|
+
async moveTo(source, parent, destination, to) {
|
|
1677
1695
|
const sourceStat = await this.describe(source);
|
|
1678
1696
|
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
1679
1697
|
const target = await this.locate(destination, false).catch((err) => {
|
|
@@ -1781,15 +1799,18 @@ var OpfsFs = class {
|
|
|
1781
1799
|
}
|
|
1782
1800
|
const now = Date.now();
|
|
1783
1801
|
const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
|
|
1784
|
-
await this.
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1802
|
+
await this.entering(
|
|
1803
|
+
at,
|
|
1804
|
+
() => this.meta.update(at, () => ({
|
|
1805
|
+
path: at,
|
|
1806
|
+
link: target,
|
|
1807
|
+
dir: parent.path,
|
|
1808
|
+
ino: inodeOf(at),
|
|
1809
|
+
mtimeMs: now,
|
|
1810
|
+
ctimeMs: now,
|
|
1811
|
+
...fields
|
|
1812
|
+
}))
|
|
1813
|
+
);
|
|
1793
1814
|
this.touch(parent.path);
|
|
1794
1815
|
}
|
|
1795
1816
|
async realpath(path, follow2) {
|
|
@@ -4559,12 +4580,12 @@ async function interruptible(work, signal) {
|
|
|
4559
4580
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
4560
4581
|
let stop = () => {
|
|
4561
4582
|
};
|
|
4562
|
-
const
|
|
4583
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
4563
4584
|
stop = () => reject(new KernelError("EINTR"));
|
|
4564
4585
|
signal.addEventListener("abort", stop, { once: true });
|
|
4565
4586
|
});
|
|
4566
4587
|
try {
|
|
4567
|
-
return await Promise.race([work,
|
|
4588
|
+
return await Promise.race([work, interrupted3]);
|
|
4568
4589
|
} finally {
|
|
4569
4590
|
signal.removeEventListener("abort", stop);
|
|
4570
4591
|
}
|
|
@@ -7131,8 +7152,12 @@ function closeAll(entry) {
|
|
|
7131
7152
|
|
|
7132
7153
|
// src/commands.ts
|
|
7133
7154
|
var NAME2 = /^[A-Za-z0-9._+-]+$/;
|
|
7155
|
+
var COMMAND_NAME = /^[^/\s\p{Cc}]+$/u;
|
|
7134
7156
|
var ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7135
7157
|
var PACKAGE = /\$\{package\}/g;
|
|
7158
|
+
function commandName(name2) {
|
|
7159
|
+
return COMMAND_NAME.test(name2) && name2.isWellFormed() && name2 !== "." && name2 !== "..";
|
|
7160
|
+
}
|
|
7136
7161
|
function inside(pkg, rel2) {
|
|
7137
7162
|
if (typeof rel2 !== "string" || rel2 === "") return void 0;
|
|
7138
7163
|
const clean = rel2.replace(/^\.\//, "");
|
|
@@ -7222,7 +7247,7 @@ function commandsOf(pkg, manifest) {
|
|
|
7222
7247
|
const shared = envOf(pkg, slicc.env);
|
|
7223
7248
|
const out = [];
|
|
7224
7249
|
for (const [name2, raw] of Object.entries(entries)) {
|
|
7225
|
-
if (!
|
|
7250
|
+
if (!commandName(name2) || !raw || typeof raw !== "object") {
|
|
7226
7251
|
continue;
|
|
7227
7252
|
}
|
|
7228
7253
|
const command = commandOf(pkg, name2, raw, packageAbi, shared);
|
|
@@ -7274,18 +7299,86 @@ async function packagesIn(fs, roots) {
|
|
|
7274
7299
|
dirs.push(...await packages(fs, root));
|
|
7275
7300
|
return dirs;
|
|
7276
7301
|
}
|
|
7277
|
-
|
|
7278
|
-
const
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7302
|
+
function binEntries(manifest) {
|
|
7303
|
+
const { bin, name: name2 } = manifest;
|
|
7304
|
+
if (typeof bin === "string") {
|
|
7305
|
+
return typeof name2 === "string" ? [[name2.slice(name2.lastIndexOf("/") + 1), bin]] : [];
|
|
7306
|
+
}
|
|
7307
|
+
return bin && typeof bin === "object" ? Object.entries(bin) : [];
|
|
7308
|
+
}
|
|
7309
|
+
var MAX_HOPS = 40;
|
|
7310
|
+
function physicalResolver(fs) {
|
|
7311
|
+
const known = /* @__PURE__ */ new Map();
|
|
7312
|
+
const pending = /* @__PURE__ */ new Set();
|
|
7313
|
+
let hops = 0;
|
|
7314
|
+
const step = async (path) => {
|
|
7315
|
+
if (path === "/") return { path, file: false };
|
|
7316
|
+
const slash = path.lastIndexOf("/");
|
|
7317
|
+
const parent = await resolve2(path.slice(0, slash) || "/");
|
|
7318
|
+
if (parent === void 0) return void 0;
|
|
7319
|
+
const at = resolvePath(parent.path, path.slice(slash + 1));
|
|
7320
|
+
const st = await fs.lstat(at).catch(() => void 0);
|
|
7321
|
+
if (!st?.isSymbolicLink) return st ? { path: at, file: st.isFile === true } : void 0;
|
|
7322
|
+
const target = await fs.readlink(at).catch(() => void 0);
|
|
7323
|
+
if (target === void 0 || ++hops > MAX_HOPS) return void 0;
|
|
7324
|
+
return resolve2(resolvePath(parent.path, target));
|
|
7325
|
+
};
|
|
7326
|
+
const resolve2 = (path) => {
|
|
7327
|
+
if (pending.has(path)) return Promise.resolve(void 0);
|
|
7328
|
+
let found = known.get(path);
|
|
7329
|
+
if (!found) {
|
|
7330
|
+
pending.add(path);
|
|
7331
|
+
found = step(path).finally(() => pending.delete(path));
|
|
7332
|
+
known.set(path, found);
|
|
7285
7333
|
}
|
|
7286
|
-
|
|
7287
|
-
|
|
7288
|
-
|
|
7334
|
+
return found;
|
|
7335
|
+
};
|
|
7336
|
+
return (path) => {
|
|
7337
|
+
hops = 0;
|
|
7338
|
+
return resolve2(path);
|
|
7339
|
+
};
|
|
7340
|
+
}
|
|
7341
|
+
async function binCommandsOf(physical, pkg, manifest, taken) {
|
|
7342
|
+
const entries = binEntries(manifest);
|
|
7343
|
+
if (entries.length === 0) return [];
|
|
7344
|
+
const home = (await physical(pkg))?.path;
|
|
7345
|
+
const out = [];
|
|
7346
|
+
for (const [name2, rel2] of entries) {
|
|
7347
|
+
if (taken.has(name2) || !commandName(name2)) continue;
|
|
7348
|
+
const script = inside(pkg, rel2);
|
|
7349
|
+
if (!script) continue;
|
|
7350
|
+
const real = await physical(script);
|
|
7351
|
+
if (!real?.file || !real.path.startsWith(`${home}/`)) continue;
|
|
7352
|
+
out.push({
|
|
7353
|
+
name: name2,
|
|
7354
|
+
abi: "emscripten",
|
|
7355
|
+
glue: script,
|
|
7356
|
+
wasm: script,
|
|
7357
|
+
argv0: name2,
|
|
7358
|
+
script,
|
|
7359
|
+
bin: true
|
|
7360
|
+
});
|
|
7361
|
+
}
|
|
7362
|
+
return out;
|
|
7363
|
+
}
|
|
7364
|
+
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY) {
|
|
7365
|
+
const found = /* @__PURE__ */ new Map();
|
|
7366
|
+
const physical = physicalResolver(fs);
|
|
7367
|
+
for (const [index, root] of (typeof modules === "string" ? [modules] : modules).entries()) {
|
|
7368
|
+
for (const pkg of await packages(fs, root)) {
|
|
7369
|
+
let manifest;
|
|
7370
|
+
try {
|
|
7371
|
+
manifest = JSON.parse(await fs.readFile(`${pkg}/package.json`));
|
|
7372
|
+
} catch {
|
|
7373
|
+
continue;
|
|
7374
|
+
}
|
|
7375
|
+
const own = commandsOf(pkg, manifest);
|
|
7376
|
+
const named = new Set(own.map((command) => command.name));
|
|
7377
|
+
const bins = index >= binsFrom ? await binCommandsOf(physical, pkg, manifest, named) : [];
|
|
7378
|
+
for (const command of [...own, ...bins]) {
|
|
7379
|
+
if (!found.has(command.name))
|
|
7380
|
+
found.set(command.name, await withPackagePaths(fs, pkg, command));
|
|
7381
|
+
}
|
|
7289
7382
|
}
|
|
7290
7383
|
}
|
|
7291
7384
|
if (!found.has("sh") && found.has("bash")) {
|
|
@@ -7744,7 +7837,7 @@ var FreshModules = class {
|
|
|
7744
7837
|
};
|
|
7745
7838
|
|
|
7746
7839
|
// src/fs/physical-path.ts
|
|
7747
|
-
var
|
|
7840
|
+
var MAX_HOPS2 = 40;
|
|
7748
7841
|
function start(path) {
|
|
7749
7842
|
return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
|
|
7750
7843
|
}
|
|
@@ -7769,7 +7862,7 @@ function rest(walk2, part) {
|
|
|
7769
7862
|
return lexical(`/${[...walk2.done, part, ...walk2.todo].join("/")}`);
|
|
7770
7863
|
}
|
|
7771
7864
|
function follow(walk2, target) {
|
|
7772
|
-
if (++walk2.hops >
|
|
7865
|
+
if (++walk2.hops > MAX_HOPS2) return false;
|
|
7773
7866
|
if (target.startsWith("/")) walk2.done.length = 0;
|
|
7774
7867
|
walk2.todo = [...target.split("/").filter((p) => p !== ""), ...walk2.todo];
|
|
7775
7868
|
return true;
|
|
@@ -9501,11 +9594,12 @@ var MountFs = class {
|
|
|
9501
9594
|
});
|
|
9502
9595
|
}
|
|
9503
9596
|
async chmod(path, mode) {
|
|
9504
|
-
const
|
|
9505
|
-
|
|
9506
|
-
this.
|
|
9597
|
+
const real = await this.follow(path);
|
|
9598
|
+
const found = this.at(real);
|
|
9599
|
+
if (!found) return this.base.chmod(real, mode);
|
|
9600
|
+
this.writable(found.mount, real);
|
|
9507
9601
|
if (!found.mount.caps.chmod) return;
|
|
9508
|
-
this.table.forget(found.mount,
|
|
9602
|
+
this.table.forget(found.mount, real);
|
|
9509
9603
|
await found.mount.conn.call({ op: "setattr", path: found.rel, mode });
|
|
9510
9604
|
}
|
|
9511
9605
|
async utimes(path, atime, mtime) {
|
|
@@ -9975,7 +10069,7 @@ async function dispatchOne(entry, req) {
|
|
|
9975
10069
|
}
|
|
9976
10070
|
|
|
9977
10071
|
// src/realm/sync-sab-wire.ts
|
|
9978
|
-
var SAB_HEADER_I32 =
|
|
10072
|
+
var SAB_HEADER_I32 = 18;
|
|
9979
10073
|
var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
|
|
9980
10074
|
var SAB_CLOCK_I64 = 3;
|
|
9981
10075
|
var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
|
|
@@ -9995,6 +10089,7 @@ var SAB_I_OFFSET_HI = 12;
|
|
|
9995
10089
|
var SAB_I_KILLED = 13;
|
|
9996
10090
|
var SAB_I_ASYNC = 14;
|
|
9997
10091
|
var SAB_I_STOP = 15;
|
|
10092
|
+
var SAB_I_BLOCKED = 16;
|
|
9998
10093
|
var U32 = 2 ** 32;
|
|
9999
10094
|
function storeU53(header3, lo, hi, value) {
|
|
10000
10095
|
Atomics.store(header3, hi, Math.floor(value / U32));
|
|
@@ -10520,12 +10615,32 @@ function mountTable(mounts = []) {
|
|
|
10520
10615
|
`;
|
|
10521
10616
|
}
|
|
10522
10617
|
|
|
10618
|
+
// src/version.ts
|
|
10619
|
+
var KERNEL_VERSION = true ? "1.88.1" : "0.0.0-dev";
|
|
10620
|
+
var OS_RELEASE = "6.0.0-slicc";
|
|
10621
|
+
function procVersion() {
|
|
10622
|
+
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
10623
|
+
`;
|
|
10624
|
+
}
|
|
10625
|
+
|
|
10523
10626
|
// src/process/procfs.ts
|
|
10524
10627
|
var HZ = 100;
|
|
10525
10628
|
var KIB = 1024;
|
|
10526
10629
|
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
10527
10630
|
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
10528
|
-
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
|
|
10631
|
+
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime", "version"];
|
|
10632
|
+
var SYS_TREE = {
|
|
10633
|
+
kernel: { osrelease: `${OS_RELEASE}
|
|
10634
|
+
`, ostype: "Linux\n" }
|
|
10635
|
+
};
|
|
10636
|
+
function sysEntry(parts2) {
|
|
10637
|
+
let at = SYS_TREE;
|
|
10638
|
+
for (const part of parts2) {
|
|
10639
|
+
if (typeof at !== "object" || !Object.hasOwn(at, part)) return void 0;
|
|
10640
|
+
at = at[part];
|
|
10641
|
+
}
|
|
10642
|
+
return at;
|
|
10643
|
+
}
|
|
10529
10644
|
function commOf(info) {
|
|
10530
10645
|
const name2 = info.argv[0] ?? "";
|
|
10531
10646
|
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
@@ -10613,7 +10728,7 @@ function pidStatus(info) {
|
|
|
10613
10728
|
"SigQ: 0/0",
|
|
10614
10729
|
"SigPnd: 0000000000000000",
|
|
10615
10730
|
"ShdPnd: 0000000000000000",
|
|
10616
|
-
|
|
10731
|
+
`SigBlk: ${sigMask(info.sigBlk)}`,
|
|
10617
10732
|
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
10618
10733
|
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
10619
10734
|
""
|
|
@@ -10649,6 +10764,7 @@ function memoryInfo(source, used = 0) {
|
|
|
10649
10764
|
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
10650
10765
|
}
|
|
10651
10766
|
function systemFile(name2, listing, now, memory) {
|
|
10767
|
+
if (name2 === "version") return procVersion();
|
|
10652
10768
|
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
10653
10769
|
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
10654
10770
|
`;
|
|
@@ -10739,11 +10855,17 @@ var ProcTree = class {
|
|
|
10739
10855
|
names: () => [
|
|
10740
10856
|
...SYSTEM_NAMES,
|
|
10741
10857
|
"mounts",
|
|
10858
|
+
"sys",
|
|
10742
10859
|
"self",
|
|
10743
10860
|
...this.listing().processes.map((p) => String(p.pid))
|
|
10744
10861
|
]
|
|
10745
10862
|
};
|
|
10746
10863
|
}
|
|
10864
|
+
if (top === "sys") {
|
|
10865
|
+
const entry = sysEntry(parts2.slice(1));
|
|
10866
|
+
if (typeof entry === "string") return { kind: "file", content: () => entry };
|
|
10867
|
+
return entry && { kind: "dir", names: () => Object.keys(entry) };
|
|
10868
|
+
}
|
|
10747
10869
|
if (top === "self") {
|
|
10748
10870
|
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
10749
10871
|
}
|
|
@@ -10821,7 +10943,7 @@ var ProcTree = class {
|
|
|
10821
10943
|
}
|
|
10822
10944
|
}
|
|
10823
10945
|
};
|
|
10824
|
-
var
|
|
10946
|
+
var MAX_HOPS3 = 40;
|
|
10825
10947
|
function* procWalk(path, follow2) {
|
|
10826
10948
|
let done4 = [];
|
|
10827
10949
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -10840,7 +10962,7 @@ function* procWalk(path, follow2) {
|
|
|
10840
10962
|
if (!follow2 && todo.length === 0) return void 0;
|
|
10841
10963
|
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
10842
10964
|
if (typeof target === "string") {
|
|
10843
|
-
if (++hops >
|
|
10965
|
+
if (++hops > MAX_HOPS3) return void 0;
|
|
10844
10966
|
[done4, todo] = throughLink(target, done4, todo);
|
|
10845
10967
|
} else {
|
|
10846
10968
|
broken ??= refusalOf(target);
|
|
@@ -12061,16 +12183,16 @@ function interruption(signal) {
|
|
|
12061
12183
|
}
|
|
12062
12184
|
async function selectFds(fds, read, write, timeoutMs, interrupt) {
|
|
12063
12185
|
const deadline = timeoutMs < 0 ? Number.POSITIVE_INFINITY : Date.now() + timeoutMs;
|
|
12064
|
-
const
|
|
12065
|
-
|
|
12186
|
+
const interrupted3 = interruption(interrupt);
|
|
12187
|
+
interrupted3.promise.catch(() => {
|
|
12066
12188
|
});
|
|
12067
12189
|
try {
|
|
12068
|
-
return await waitReady(fds, read, write, deadline,
|
|
12190
|
+
return await waitReady(fds, read, write, deadline, interrupted3.promise);
|
|
12069
12191
|
} finally {
|
|
12070
|
-
|
|
12192
|
+
interrupted3.done();
|
|
12071
12193
|
}
|
|
12072
12194
|
}
|
|
12073
|
-
async function waitReady(fds, read, write, deadline,
|
|
12195
|
+
async function waitReady(fds, read, write, deadline, interrupted3) {
|
|
12074
12196
|
for (; ; ) {
|
|
12075
12197
|
const now = ready(fds, read, write);
|
|
12076
12198
|
if (now.read.length > 0 || now.write.length > 0 || Date.now() >= deadline) return now;
|
|
@@ -12082,7 +12204,7 @@ async function waitReady(fds, read, write, deadline, interrupted2) {
|
|
|
12082
12204
|
let timer;
|
|
12083
12205
|
const expiry = deadline === Number.POSITIVE_INFINITY ? [] : [new Promise((resolve2) => timer = setTimeout(resolve2, deadline - Date.now()))];
|
|
12084
12206
|
try {
|
|
12085
|
-
await Promise.race([...changes, ...expiry,
|
|
12207
|
+
await Promise.race([...changes, ...expiry, interrupted3]);
|
|
12086
12208
|
} finally {
|
|
12087
12209
|
round.abort();
|
|
12088
12210
|
clearTimeout(timer);
|
|
@@ -12399,11 +12521,12 @@ var VfsNodes = class {
|
|
|
12399
12521
|
byId = /* @__PURE__ */ new Map();
|
|
12400
12522
|
keepsOnDisk = false;
|
|
12401
12523
|
fs;
|
|
12402
|
-
entries
|
|
12524
|
+
entries;
|
|
12403
12525
|
onClosed;
|
|
12404
|
-
constructor(fs, onClosed) {
|
|
12526
|
+
constructor(fs, onClosed, entries = /* @__PURE__ */ new Map()) {
|
|
12405
12527
|
this.fs = fs;
|
|
12406
12528
|
this.onClosed = onClosed;
|
|
12529
|
+
this.entries = entries;
|
|
12407
12530
|
}
|
|
12408
12531
|
async onEntry(path, op) {
|
|
12409
12532
|
const key = await this.entryKey(path);
|
|
@@ -12893,6 +13016,7 @@ var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
|
12893
13016
|
var WasmProcess = class {
|
|
12894
13017
|
exited = false;
|
|
12895
13018
|
children;
|
|
13019
|
+
deathSignals = /* @__PURE__ */ new Map();
|
|
12896
13020
|
caught = 0;
|
|
12897
13021
|
ignored = 0;
|
|
12898
13022
|
inherited = 0;
|
|
@@ -12927,7 +13051,10 @@ var WasmProcess = class {
|
|
|
12927
13051
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
12928
13052
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
12929
13053
|
this.children.onChildState = () => this.signal(SIG.CHLD);
|
|
12930
|
-
this.children.onReap =
|
|
13054
|
+
this.children.onReap = (pid2) => {
|
|
13055
|
+
this.deathSignals.delete(pid2);
|
|
13056
|
+
options.onReap?.(pid2);
|
|
13057
|
+
};
|
|
12931
13058
|
}
|
|
12932
13059
|
ignores(bit) {
|
|
12933
13060
|
return (this.signalMasks().ignored & bit) !== 0;
|
|
@@ -12955,6 +13082,10 @@ var WasmProcess = class {
|
|
|
12955
13082
|
if (sig === SIG.STOP) return this.stop(sig);
|
|
12956
13083
|
const bit = sigbit(sig);
|
|
12957
13084
|
if (this.ignores(bit)) return "ignore";
|
|
13085
|
+
if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
|
|
13086
|
+
this.options.onPending?.(sig);
|
|
13087
|
+
return "deliver";
|
|
13088
|
+
}
|
|
12958
13089
|
if (!(this.caught & bit)) {
|
|
12959
13090
|
const action = defaultAction(sig);
|
|
12960
13091
|
return action === "stop" ? this.stop(sig) : action;
|
|
@@ -12971,16 +13102,27 @@ var WasmProcess = class {
|
|
|
12971
13102
|
return "deliver";
|
|
12972
13103
|
}
|
|
12973
13104
|
async spawn(req) {
|
|
12974
|
-
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session } = req;
|
|
13105
|
+
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
|
|
13106
|
+
if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
|
|
13107
|
+
throw new KernelError("EINVAL");
|
|
13108
|
+
}
|
|
12975
13109
|
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12976
13110
|
const named = argv0 !== void 0 ? { argv0 } : {};
|
|
12977
13111
|
const spawned = { file, argv, ...named, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
12978
13112
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
13113
|
+
if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
|
|
12979
13114
|
if (!exec) return pid;
|
|
12980
13115
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
12981
13116
|
else this.adoptExec(pid);
|
|
12982
13117
|
return pid;
|
|
12983
13118
|
}
|
|
13119
|
+
onDeath(target, sig) {
|
|
13120
|
+
if (this.exited) this.sendDeath(target, sig);
|
|
13121
|
+
else this.deathSignals.set(target, sig);
|
|
13122
|
+
}
|
|
13123
|
+
sendDeath(target, sig) {
|
|
13124
|
+
void Promise.resolve(this.options.kill?.(target, sig)).catch(() => void 0);
|
|
13125
|
+
}
|
|
12984
13126
|
async killSelf(sig, target, probe) {
|
|
12985
13127
|
if (!this.options.exitSignal) throw new KernelError("ENOSYS");
|
|
12986
13128
|
if (!isSignal(sig) || defaultAction(sig) !== "terminate") throw new KernelError("EINVAL");
|
|
@@ -13879,6 +14021,8 @@ var WasmProcess = class {
|
|
|
13879
14021
|
this.interrupt.abort();
|
|
13880
14022
|
this.options.locks?.release(this.pid);
|
|
13881
14023
|
this.asyncOps.close();
|
|
14024
|
+
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
14025
|
+
this.deathSignals.clear();
|
|
13882
14026
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13883
14027
|
await this.stampClipboards();
|
|
13884
14028
|
await this.fds.closeAll();
|
|
@@ -13958,19 +14102,25 @@ var Dying = class {
|
|
|
13958
14102
|
}
|
|
13959
14103
|
};
|
|
13960
14104
|
function killThread(thread, caught, sig) {
|
|
13961
|
-
if (!thread
|
|
14105
|
+
if (!thread) return false;
|
|
14106
|
+
const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
|
|
14107
|
+
if (!held && (caught & sigbit(sig)) === 0) return false;
|
|
13962
14108
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
14109
|
+
if (held) return true;
|
|
13963
14110
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
13964
14111
|
const blocked = thread.interrupt;
|
|
13965
14112
|
thread.interrupt = new AbortController();
|
|
13966
14113
|
blocked.abort();
|
|
13967
14114
|
return true;
|
|
13968
14115
|
}
|
|
14116
|
+
function unblocked(header3) {
|
|
14117
|
+
return Atomics.load(header3, SAB_I_SIGNALS) & ~Atomics.load(header3, SAB_I_BLOCKED);
|
|
14118
|
+
}
|
|
13969
14119
|
function threadSignalsOf(sab) {
|
|
13970
14120
|
return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
|
|
13971
14121
|
}
|
|
13972
14122
|
function threadCancel(thread) {
|
|
13973
|
-
return
|
|
14123
|
+
return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
|
|
13974
14124
|
}
|
|
13975
14125
|
function notifiers(header3) {
|
|
13976
14126
|
return {
|
|
@@ -14095,15 +14245,16 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
14095
14245
|
resolver: opts.resolver,
|
|
14096
14246
|
...notifiers(header3),
|
|
14097
14247
|
onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
|
|
14098
|
-
hasPending: () =>
|
|
14248
|
+
hasPending: () => unblocked(header3) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
|
|
14099
14249
|
raise: hooks.raise,
|
|
14100
14250
|
threadKill: hooks.threadKill,
|
|
14101
14251
|
...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
|
|
14102
14252
|
...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
|
|
14103
|
-
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
|
|
14253
|
+
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {},
|
|
14254
|
+
...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header3, SAB_I_BLOCKED) } : {}
|
|
14104
14255
|
};
|
|
14105
14256
|
}
|
|
14106
|
-
function threadInit(opts, program, sab, cred, thread) {
|
|
14257
|
+
function threadInit(opts, program, sab, cred, thread, main) {
|
|
14107
14258
|
return {
|
|
14108
14259
|
type: WASM_THREAD_INIT,
|
|
14109
14260
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -14116,12 +14267,15 @@ function threadInit(opts, program, sab, cred, thread) {
|
|
|
14116
14267
|
cred: copyCred(cred),
|
|
14117
14268
|
owners: opts.owners === true,
|
|
14118
14269
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
14119
|
-
thread
|
|
14270
|
+
thread,
|
|
14271
|
+
signals: main
|
|
14120
14272
|
};
|
|
14121
14273
|
}
|
|
14122
14274
|
function spawnWasmProcess(opts) {
|
|
14123
14275
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
14124
14276
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
14277
|
+
if (opts.blocked && opts.program.abi === "wasi")
|
|
14278
|
+
Atomics.store(header3, SAB_I_BLOCKED, opts.blocked);
|
|
14125
14279
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
14126
14280
|
const created3 = new Created();
|
|
14127
14281
|
const process = new WasmProcess(
|
|
@@ -14222,6 +14376,7 @@ function spawnWasmProcess(opts) {
|
|
|
14222
14376
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
14223
14377
|
const tw = opts.createWorker();
|
|
14224
14378
|
const tsignals = threadSignalsOf(tsab);
|
|
14379
|
+
if (thread.blocked) Atomics.store(tsignals.header, SAB_I_BLOCKED, thread.blocked);
|
|
14225
14380
|
threadSignals.set(thread.tid, tsignals);
|
|
14226
14381
|
const tdispatch = (req) => dying.serving(
|
|
14227
14382
|
() => isWasmSyscall(req) ? process.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -14243,7 +14398,7 @@ function spawnWasmProcess(opts) {
|
|
|
14243
14398
|
tresponder.dispose();
|
|
14244
14399
|
tw.terminate();
|
|
14245
14400
|
});
|
|
14246
|
-
tw.postMessage(threadInit(opts, program, tsab, process.cred, thread));
|
|
14401
|
+
tw.postMessage(threadInit(opts, program, tsab, process.cred, thread, sab));
|
|
14247
14402
|
};
|
|
14248
14403
|
worker.postMessage(
|
|
14249
14404
|
processInit(opts, sab, process.umask, copyCred(process.cred), lane?.lane),
|
|
@@ -14265,6 +14420,7 @@ function spawnWasmProcess(opts) {
|
|
|
14265
14420
|
onState: (listener) => process.onState(listener),
|
|
14266
14421
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
14267
14422
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
14423
|
+
blockedSignals: () => opts.program.abi === "wasi" ? Atomics.load(header3, SAB_I_BLOCKED) : 0,
|
|
14268
14424
|
signalMasks: () => process.signalMasks(),
|
|
14269
14425
|
umask: () => process.umask,
|
|
14270
14426
|
cred: () => copyCred(process.cred),
|
|
@@ -14977,63 +15133,137 @@ function compile(secrets, options = {}) {
|
|
|
14977
15133
|
|
|
14978
15134
|
// src/kernel/scrub-file.ts
|
|
14979
15135
|
var SCRUB_IDLE_MS = 50;
|
|
15136
|
+
var SCRUB_NONBLOCK_MAX = 64 * 1024;
|
|
14980
15137
|
var encoder5 = new TextEncoder();
|
|
14981
15138
|
function scrubberOf(secrets) {
|
|
14982
15139
|
const usable = secrets.filter((s) => encoder5.encode(s.value).length >= MIN_VALUE);
|
|
14983
15140
|
return usable.length > 0 ? compile(usable, { idleMs: SCRUB_IDLE_MS }) : void 0;
|
|
14984
15141
|
}
|
|
14985
|
-
async function writeAll2(file, bytes
|
|
15142
|
+
async function writeAll2(file, bytes) {
|
|
14986
15143
|
const write = file.write;
|
|
14987
|
-
for (let at = 0; at < bytes.length; )
|
|
14988
|
-
at += await write.call(file, bytes.subarray(at), at === 0 ? signal : void 0);
|
|
14989
|
-
}
|
|
15144
|
+
for (let at = 0; at < bytes.length; ) at += await write.call(file, bytes.subarray(at));
|
|
14990
15145
|
}
|
|
14991
15146
|
function bound(file, key) {
|
|
14992
15147
|
const method = file[key];
|
|
14993
15148
|
return typeof method === "function" ? { [key]: method.bind(file) } : {};
|
|
14994
15149
|
}
|
|
15150
|
+
function interrupted2(err) {
|
|
15151
|
+
const code = err?.code;
|
|
15152
|
+
return code === "EINTR" || code === "EAGAIN";
|
|
15153
|
+
}
|
|
14995
15154
|
function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
14996
15155
|
const file = inner.file;
|
|
14997
15156
|
const stream = scrubber.stream();
|
|
14998
|
-
let
|
|
15157
|
+
let tail = Promise.resolve();
|
|
15158
|
+
let pending = 0;
|
|
15159
|
+
let busy = false;
|
|
14999
15160
|
let timer;
|
|
15000
15161
|
let failed3;
|
|
15162
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
15163
|
+
const quiet = () => !busy && pending === 0;
|
|
15164
|
+
const wake = () => {
|
|
15165
|
+
for (const waiter of [...waiters]) waiter();
|
|
15166
|
+
};
|
|
15001
15167
|
const raise = () => {
|
|
15002
15168
|
if (failed3 === void 0) return;
|
|
15003
15169
|
const err = failed3;
|
|
15004
15170
|
failed3 = void 0;
|
|
15005
15171
|
throw err;
|
|
15006
15172
|
};
|
|
15007
|
-
const
|
|
15008
|
-
|
|
15009
|
-
|
|
15010
|
-
|
|
15173
|
+
const later = (bytes) => {
|
|
15174
|
+
if (bytes.length === 0) return;
|
|
15175
|
+
pending += 1;
|
|
15176
|
+
tail = tail.then(() => writeAll2(file, bytes)).catch((err) => {
|
|
15177
|
+
if (failed3 === void 0) failed3 = err;
|
|
15178
|
+
}).finally(() => {
|
|
15179
|
+
pending -= 1;
|
|
15180
|
+
if (quiet()) wake();
|
|
15181
|
+
});
|
|
15182
|
+
};
|
|
15183
|
+
const settling = (signal) => new Promise((resolve2, reject) => {
|
|
15184
|
+
const done4 = () => {
|
|
15185
|
+
waiters.delete(done4);
|
|
15186
|
+
signal?.removeEventListener("abort", stop);
|
|
15187
|
+
resolve2();
|
|
15188
|
+
};
|
|
15189
|
+
const stop = () => {
|
|
15190
|
+
waiters.delete(done4);
|
|
15191
|
+
reject(new KernelError("EINTR"));
|
|
15192
|
+
};
|
|
15193
|
+
if (signal?.aborted) return stop();
|
|
15194
|
+
waiters.add(done4);
|
|
15195
|
+
signal?.addEventListener("abort", stop, { once: true });
|
|
15196
|
+
});
|
|
15197
|
+
const settled = async () => {
|
|
15198
|
+
while (!quiet()) await settling();
|
|
15199
|
+
};
|
|
15200
|
+
const changed = async (signal) => {
|
|
15201
|
+
const round = new AbortController();
|
|
15202
|
+
const stop = signal ? AbortSignal.any([signal, round.signal]) : round.signal;
|
|
15203
|
+
try {
|
|
15204
|
+
const own = settling(stop);
|
|
15205
|
+
await Promise.race(file.changed ? [own, file.changed(stop)] : [own]);
|
|
15206
|
+
} catch (err) {
|
|
15207
|
+
throw signal?.aborted ? new KernelError("EINTR") : err;
|
|
15208
|
+
} finally {
|
|
15209
|
+
round.abort();
|
|
15210
|
+
}
|
|
15211
|
+
};
|
|
15212
|
+
const turn = async (signal) => {
|
|
15213
|
+
for (let waited = false; ; waited = true) {
|
|
15214
|
+
if (quiet() && (pollFile(file).writable || !file.changed)) {
|
|
15215
|
+
busy = true;
|
|
15216
|
+
return;
|
|
15217
|
+
}
|
|
15218
|
+
if (signal?.aborted) throw new KernelError(waited ? "EINTR" : "EAGAIN");
|
|
15219
|
+
await changed(signal);
|
|
15220
|
+
}
|
|
15221
|
+
};
|
|
15222
|
+
const send = async (out, signal) => {
|
|
15223
|
+
const write = file.write;
|
|
15224
|
+
for (let at = 0; at < out.length; ) {
|
|
15225
|
+
try {
|
|
15226
|
+
at += await write.call(file, out.subarray(at), signal);
|
|
15227
|
+
} catch (err) {
|
|
15228
|
+
if (!signal?.aborted || !interrupted2(err)) throw err;
|
|
15229
|
+
}
|
|
15230
|
+
if (at < out.length && signal?.aborted) return later(out.subarray(at));
|
|
15231
|
+
}
|
|
15011
15232
|
};
|
|
15012
15233
|
const release = () => {
|
|
15013
15234
|
timer = void 0;
|
|
15014
|
-
|
|
15015
|
-
failed3 = err;
|
|
15016
|
-
});
|
|
15235
|
+
later(stream.idle());
|
|
15017
15236
|
};
|
|
15018
15237
|
return new OpenFile({
|
|
15019
15238
|
...bound(file, "read"),
|
|
15020
15239
|
...bound(file, "peek"),
|
|
15021
|
-
...bound(file, "poll"),
|
|
15022
|
-
...bound(file, "changed"),
|
|
15023
15240
|
...bound(file, "stat"),
|
|
15241
|
+
poll: () => {
|
|
15242
|
+
const state = pollFile(file);
|
|
15243
|
+
return quiet() ? state : { ...state, writable: false };
|
|
15244
|
+
},
|
|
15245
|
+
changed,
|
|
15024
15246
|
...file.tty ? { tty: file.tty } : {},
|
|
15025
15247
|
...file.clipboard ? { clipboard: file.clipboard } : {},
|
|
15026
15248
|
...file.write ? {
|
|
15027
15249
|
write: async (bytes, signal) => {
|
|
15028
|
-
|
|
15029
|
-
|
|
15030
|
-
|
|
15250
|
+
await turn(signal);
|
|
15251
|
+
const taken = signal?.aborted && bytes.length > SCRUB_NONBLOCK_MAX ? bytes.subarray(0, SCRUB_NONBLOCK_MAX) : bytes;
|
|
15252
|
+
try {
|
|
15253
|
+
raise();
|
|
15254
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
15255
|
+
timer = void 0;
|
|
15256
|
+
await send(stream.push(taken), signal);
|
|
15257
|
+
} finally {
|
|
15258
|
+
busy = false;
|
|
15259
|
+
if (quiet()) wake();
|
|
15260
|
+
}
|
|
15031
15261
|
timer = setTimeout(release, idleMs);
|
|
15032
|
-
return
|
|
15262
|
+
return taken.length;
|
|
15033
15263
|
}
|
|
15034
15264
|
} : {},
|
|
15035
15265
|
flush: async () => {
|
|
15036
|
-
await
|
|
15266
|
+
await settled();
|
|
15037
15267
|
raise();
|
|
15038
15268
|
await file.flush?.();
|
|
15039
15269
|
},
|
|
@@ -15041,7 +15271,9 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
15041
15271
|
if (timer !== void 0) clearTimeout(timer);
|
|
15042
15272
|
let failure2;
|
|
15043
15273
|
try {
|
|
15044
|
-
await
|
|
15274
|
+
await settled();
|
|
15275
|
+
later(stream.end());
|
|
15276
|
+
await settled();
|
|
15045
15277
|
raise();
|
|
15046
15278
|
} catch (err) {
|
|
15047
15279
|
failure2 = { err };
|
|
@@ -15217,12 +15449,12 @@ var SealedChannel = class {
|
|
|
15217
15449
|
if (signal.aborted) throw new KernelError("EINTR");
|
|
15218
15450
|
let stop = () => {
|
|
15219
15451
|
};
|
|
15220
|
-
const
|
|
15452
|
+
const interrupted3 = new Promise((_, reject) => {
|
|
15221
15453
|
stop = () => reject(new KernelError("EINTR"));
|
|
15222
15454
|
signal.addEventListener("abort", stop, { once: true });
|
|
15223
15455
|
});
|
|
15224
15456
|
try {
|
|
15225
|
-
await Promise.race([flight.done,
|
|
15457
|
+
await Promise.race([flight.done, interrupted3]);
|
|
15226
15458
|
} finally {
|
|
15227
15459
|
signal.removeEventListener("abort", stop);
|
|
15228
15460
|
}
|
|
@@ -17387,15 +17619,25 @@ function shebang(head) {
|
|
|
17387
17619
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
17388
17620
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
17389
17621
|
}
|
|
17390
|
-
async function rootOnly(fs, path) {
|
|
17622
|
+
async function rootOnly(fs, path, dir = false) {
|
|
17391
17623
|
const names = chain(path);
|
|
17392
17624
|
for (const [i, at] of names.entries()) {
|
|
17393
17625
|
const st = await fs.lstat(at).catch(() => void 0);
|
|
17394
|
-
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17626
|
+
const kind = i === names.length - 1 && !dir ? st?.isFile : st?.isDirectory;
|
|
17395
17627
|
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17396
17628
|
}
|
|
17397
17629
|
return true;
|
|
17398
17630
|
}
|
|
17631
|
+
function appendedRoots(given) {
|
|
17632
|
+
const roots = given?.append ?? [];
|
|
17633
|
+
if (!Array.isArray(roots)) throw new TypeError("commands.append must be an array of paths");
|
|
17634
|
+
for (const root of roots) {
|
|
17635
|
+
if (typeof root !== "string" || !root.startsWith("/") || normalizePath(root) !== root) {
|
|
17636
|
+
throw new TypeError(`commands.append: not an absolute, normalised path: ${String(root)}`);
|
|
17637
|
+
}
|
|
17638
|
+
}
|
|
17639
|
+
return [...roots];
|
|
17640
|
+
}
|
|
17399
17641
|
function plainEnv(words2) {
|
|
17400
17642
|
const next2 = words2[1];
|
|
17401
17643
|
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
@@ -17488,6 +17730,8 @@ var Launcher = class {
|
|
|
17488
17730
|
base;
|
|
17489
17731
|
createWorker;
|
|
17490
17732
|
modulesDir;
|
|
17733
|
+
appended;
|
|
17734
|
+
reportedRoots = /* @__PURE__ */ new Set();
|
|
17491
17735
|
env;
|
|
17492
17736
|
catalogs = /* @__PURE__ */ new Map();
|
|
17493
17737
|
ownCatalogs = /* @__PURE__ */ new Map();
|
|
@@ -17594,6 +17838,7 @@ var Launcher = class {
|
|
|
17594
17838
|
this.processMounts = options.processMounts ?? true;
|
|
17595
17839
|
this.pnpmHome = options.env?.PNPM_HOME ?? SYSTEM_PNPM_HOME;
|
|
17596
17840
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17841
|
+
this.appended = appendedRoots(options.commands);
|
|
17597
17842
|
this.cdp = new CdpHosts(options.cdp);
|
|
17598
17843
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17599
17844
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
@@ -17643,9 +17888,9 @@ var Launcher = class {
|
|
|
17643
17888
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
17644
17889
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
17645
17890
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
17646
|
-
options.fs.protect?.(this.prefixes);
|
|
17647
17891
|
const integrity = options.protect?.integrity;
|
|
17648
17892
|
integrityOptions(integrity);
|
|
17893
|
+
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
17649
17894
|
if (integrity && this.prefixes.length > 0) {
|
|
17650
17895
|
this.integrity = new Integrity(
|
|
17651
17896
|
this.prefixes,
|
|
@@ -17668,7 +17913,7 @@ var Launcher = class {
|
|
|
17668
17913
|
});
|
|
17669
17914
|
void this.unlinked.sweep("/");
|
|
17670
17915
|
this.watchers.watch(
|
|
17671
|
-
[this.modulesDir, this.pnpmHome],
|
|
17916
|
+
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
17672
17917
|
{ recursive: true },
|
|
17673
17918
|
() => this.resetCatalogs()
|
|
17674
17919
|
);
|
|
@@ -17699,7 +17944,10 @@ var Launcher = class {
|
|
|
17699
17944
|
commands(scope = "") {
|
|
17700
17945
|
let found = this.catalogs.get(scope);
|
|
17701
17946
|
if (!found) {
|
|
17702
|
-
found = this.
|
|
17947
|
+
found = this.trustedAppended().then(async (appended) => {
|
|
17948
|
+
const roots = await this.roots(scope, appended);
|
|
17949
|
+
return scanCommands(this.scanned, roots, roots.length - appended.length);
|
|
17950
|
+
}).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
|
|
17703
17951
|
this.catalogs.set(scope, found);
|
|
17704
17952
|
}
|
|
17705
17953
|
return found;
|
|
@@ -17726,10 +17974,37 @@ var Launcher = class {
|
|
|
17726
17974
|
}
|
|
17727
17975
|
return found;
|
|
17728
17976
|
}
|
|
17729
|
-
async roots(scope = "") {
|
|
17730
|
-
const system = [
|
|
17977
|
+
async roots(scope = "", appended) {
|
|
17978
|
+
const system = [
|
|
17979
|
+
this.modulesDir,
|
|
17980
|
+
...await pnpmGlobalRoots(this.base, this.pnpmHome),
|
|
17981
|
+
...appended ?? await this.trustedAppended()
|
|
17982
|
+
];
|
|
17731
17983
|
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
17732
17984
|
}
|
|
17985
|
+
async rootOnlyPath(root) {
|
|
17986
|
+
for (const at of chain(root)) {
|
|
17987
|
+
const real = await physicalPathAsync(this.base, at);
|
|
17988
|
+
if (!await rootOnly(this.base, real, true)) return false;
|
|
17989
|
+
}
|
|
17990
|
+
return true;
|
|
17991
|
+
}
|
|
17992
|
+
async trustedAppended() {
|
|
17993
|
+
if (this.appended.length === 0 || this.usersMode === "off") return this.appended;
|
|
17994
|
+
const trusted = [];
|
|
17995
|
+
for (const root of this.appended) {
|
|
17996
|
+
const real = await physicalPathAsync(this.base, root);
|
|
17997
|
+
if (await this.rootOnlyPath(root)) trusted.push(root);
|
|
17998
|
+
else if (this.usersMode === "report" && await this.base.exists(real)) {
|
|
17999
|
+
if (!this.reportedRoots.has(root)) {
|
|
18000
|
+
this.reportedRoots.add(root);
|
|
18001
|
+
this.dac?.denied({ pid: 0, uid: 0, op: "commands", path: root, errno: "EACCES" });
|
|
18002
|
+
}
|
|
18003
|
+
trusted.push(root);
|
|
18004
|
+
}
|
|
18005
|
+
}
|
|
18006
|
+
return trusted;
|
|
18007
|
+
}
|
|
17733
18008
|
resetCatalogs() {
|
|
17734
18009
|
this.catalogs.clear();
|
|
17735
18010
|
this.ownCatalogs.clear();
|
|
@@ -17835,14 +18110,22 @@ var Launcher = class {
|
|
|
17835
18110
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
17836
18111
|
const via = [interp, ...inner?.via ?? []];
|
|
17837
18112
|
const sources = [script, ...inner?.sources ?? []];
|
|
17838
|
-
|
|
18113
|
+
const bins = [...command?.bin ? [script] : [], ...inner?.bins ?? []];
|
|
18114
|
+
return inner && {
|
|
18115
|
+
...inner,
|
|
18116
|
+
target: withScriptEnv(inner.target, command),
|
|
18117
|
+
via,
|
|
18118
|
+
sources,
|
|
18119
|
+
...bins.length > 0 ? { bins } : {}
|
|
18120
|
+
};
|
|
17839
18121
|
}
|
|
17840
18122
|
const target = withScriptEnv(found, command);
|
|
17841
18123
|
return {
|
|
17842
18124
|
target,
|
|
17843
18125
|
args: [...target.prefix ?? [], ...passed],
|
|
17844
18126
|
via: [interp],
|
|
17845
|
-
sources: [script]
|
|
18127
|
+
sources: [script],
|
|
18128
|
+
...command?.bin ? { bins: [script] } : {}
|
|
17846
18129
|
};
|
|
17847
18130
|
}
|
|
17848
18131
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17868,6 +18151,7 @@ var Launcher = class {
|
|
|
17868
18151
|
const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
|
|
17869
18152
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
17870
18153
|
}
|
|
18154
|
+
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
17871
18155
|
}
|
|
17872
18156
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17873
18157
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
@@ -18133,11 +18417,9 @@ var Launcher = class {
|
|
|
18133
18417
|
groupSession(pgid) {
|
|
18134
18418
|
return this.jobs.sessionOf(pgid);
|
|
18135
18419
|
}
|
|
18136
|
-
treeScrubs(
|
|
18420
|
+
treeScrubs(req) {
|
|
18137
18421
|
const inherited2 = req.ppid !== void 0 ? this.scrubs.get(req.ppid) : void 0;
|
|
18138
|
-
|
|
18139
|
-
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18140
|
-
return scrubs;
|
|
18422
|
+
return req.scrub ? [...inherited2 ?? [], req.scrub] : inherited2;
|
|
18141
18423
|
}
|
|
18142
18424
|
start(req) {
|
|
18143
18425
|
this.sampling();
|
|
@@ -18145,7 +18427,7 @@ var Launcher = class {
|
|
|
18145
18427
|
throw new SpawnError("ESRCH");
|
|
18146
18428
|
}
|
|
18147
18429
|
const pid = req.pid ?? this.nextPid++;
|
|
18148
|
-
const scrubs = this.treeScrubs(
|
|
18430
|
+
const scrubs = this.treeScrubs(req);
|
|
18149
18431
|
const stack = this.stackFor(req.tag);
|
|
18150
18432
|
const terminal = req.fds.stdioTerminal();
|
|
18151
18433
|
const decided = req.decided ?? Promise.resolve(true);
|
|
@@ -18166,6 +18448,7 @@ var Launcher = class {
|
|
|
18166
18448
|
},
|
|
18167
18449
|
settling: () => this.settling.isSettling(pid),
|
|
18168
18450
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
18451
|
+
...req.blocked ? { blocked: req.blocked } : {},
|
|
18169
18452
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
18170
18453
|
cred: req.cred,
|
|
18171
18454
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
@@ -18214,6 +18497,7 @@ var Launcher = class {
|
|
|
18214
18497
|
...this.shownIds(req)
|
|
18215
18498
|
});
|
|
18216
18499
|
this.processes.set(pid, handle);
|
|
18500
|
+
if (scrubs) this.scrubs.set(pid, scrubs);
|
|
18217
18501
|
const { cred } = req;
|
|
18218
18502
|
this.creds.set(pid, () => handle.cred?.() ?? copyCred(cred));
|
|
18219
18503
|
if (req.tag !== void 0) this.tags.set(pid, req.tag);
|
|
@@ -18440,6 +18724,7 @@ var Launcher = class {
|
|
|
18440
18724
|
report,
|
|
18441
18725
|
ppid,
|
|
18442
18726
|
ignored: this.ignoredBy(ppid),
|
|
18727
|
+
blocked: this.blockedBy(ppid),
|
|
18443
18728
|
umask: this.umaskOf(ppid),
|
|
18444
18729
|
cred,
|
|
18445
18730
|
tag: this.tagOf(ppid),
|
|
@@ -18501,6 +18786,7 @@ var Launcher = class {
|
|
|
18501
18786
|
ppid,
|
|
18502
18787
|
fork: state,
|
|
18503
18788
|
ignored: this.ignoredBy(ppid, true),
|
|
18789
|
+
blocked: this.blockedBy(ppid),
|
|
18504
18790
|
umask: this.umaskOf(ppid),
|
|
18505
18791
|
cred: this.credOf(ppid),
|
|
18506
18792
|
tag: this.tagOf(ppid)
|
|
@@ -18552,11 +18838,16 @@ var Launcher = class {
|
|
|
18552
18838
|
}
|
|
18553
18839
|
signalMasksOf(pid) {
|
|
18554
18840
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
18555
|
-
|
|
18841
|
+
const blocked = this.blockedBy(pid);
|
|
18842
|
+
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
18843
|
+
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
18556
18844
|
}
|
|
18557
18845
|
controlsJobs(pid) {
|
|
18558
18846
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
18559
18847
|
}
|
|
18848
|
+
blockedBy(pid) {
|
|
18849
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
18850
|
+
}
|
|
18560
18851
|
ignoredBy(pid, fork = false) {
|
|
18561
18852
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
18562
18853
|
}
|
|
@@ -18921,7 +19212,7 @@ var Launcher = class {
|
|
|
18921
19212
|
(dir) => this.userCommandDir(dir),
|
|
18922
19213
|
this.owners
|
|
18923
19214
|
);
|
|
18924
|
-
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
19215
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
18925
19216
|
nodes.keepsOnDisk = true;
|
|
18926
19217
|
this.openFiles.add(nodes);
|
|
18927
19218
|
const unlinked = new UnlinkedKeeper(
|
|
@@ -19325,6 +19616,7 @@ function serveKernel(port, deps) {
|
|
|
19325
19616
|
createWorker: deps.createWorker,
|
|
19326
19617
|
...deps.createDriverWorker ? { createDriverWorker: deps.createDriverWorker } : {},
|
|
19327
19618
|
...req.modules ? { modules: req.modules } : {},
|
|
19619
|
+
...req.commands ? { commands: req.commands } : {},
|
|
19328
19620
|
...req.env ? { env: req.env } : {},
|
|
19329
19621
|
...hostOptions(req, port, sealed.hook, clipboard.hook, integrity.lookup),
|
|
19330
19622
|
...req.approve ? { approve: approvals.ask } : {},
|