@ai-ecoverse/slicc-kernel 1.86.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 +18 -11
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +333 -92
- 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 +284 -84
- package/dist/node-process-worker.js.map +4 -4
- package/dist/node.js +327 -84
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +284 -84
- package/dist/process-worker.js.map +4 -4
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -753,6 +753,10 @@ var KernelError = class extends Error {
|
|
|
753
753
|
if (detail !== void 0) this.detail = detail;
|
|
754
754
|
}
|
|
755
755
|
};
|
|
756
|
+
function openAccess(flags2) {
|
|
757
|
+
const mode = flags2 & 3;
|
|
758
|
+
return mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
759
|
+
}
|
|
756
760
|
function pollFile(file) {
|
|
757
761
|
return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
|
|
758
762
|
}
|
|
@@ -3010,8 +3014,8 @@ var MemoryMeta = class {
|
|
|
3010
3014
|
async get(paths) {
|
|
3011
3015
|
return paths.map((path) => this.entries.get(path));
|
|
3012
3016
|
}
|
|
3013
|
-
async fresh(
|
|
3014
|
-
return this.
|
|
3017
|
+
async fresh(paths) {
|
|
3018
|
+
return this.get(paths);
|
|
3015
3019
|
}
|
|
3016
3020
|
async update(path, change) {
|
|
3017
3021
|
this.set(path, change(this.entries.get(path)));
|
|
@@ -3611,8 +3615,25 @@ var OpfsFs = class {
|
|
|
3611
3615
|
}
|
|
3612
3616
|
counted = [];
|
|
3613
3617
|
async stamp(path) {
|
|
3614
|
-
const
|
|
3615
|
-
|
|
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
|
+
}
|
|
3616
3637
|
}
|
|
3617
3638
|
async counting(target) {
|
|
3618
3639
|
if (!isProtected(this.counted, target)) return;
|
|
@@ -3683,9 +3704,9 @@ var OpfsFs = class {
|
|
|
3683
3704
|
if (fields) await this.meta.update(path, (entry) => ({ ...entry, path, ...fields }));
|
|
3684
3705
|
}
|
|
3685
3706
|
guarded = [];
|
|
3686
|
-
protect(prefixes2) {
|
|
3707
|
+
protect(prefixes2, versions = false) {
|
|
3687
3708
|
this.guarded = prefixes2;
|
|
3688
|
-
this.counted = prefixes2;
|
|
3709
|
+
this.counted = versions ? prefixes2 : [];
|
|
3689
3710
|
}
|
|
3690
3711
|
unguarded() {
|
|
3691
3712
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -4265,6 +4286,9 @@ var OpfsFs = class {
|
|
|
4265
4286
|
const parent = await this.locate(parentOf4(to), true);
|
|
4266
4287
|
const destination = resolvePath(parent.path, baseOf(to));
|
|
4267
4288
|
this.refuse(destination, true);
|
|
4289
|
+
await this.entering(destination, () => this.moveTo(source, parent, destination, to));
|
|
4290
|
+
}
|
|
4291
|
+
async moveTo(source, parent, destination, to) {
|
|
4268
4292
|
const sourceStat = await this.describe(source);
|
|
4269
4293
|
if (sourceStat.isDirectory && within2(destination, source.path)) throw fsError("EINVAL", to);
|
|
4270
4294
|
const target = await this.locate(destination, false).catch((err) => {
|
|
@@ -4372,15 +4396,18 @@ var OpfsFs = class {
|
|
|
4372
4396
|
}
|
|
4373
4397
|
const now = Date.now();
|
|
4374
4398
|
const fields = await this.newFields(at, owner && { uid: owner.uid, gid: owner.gid }, false);
|
|
4375
|
-
await this.
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
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
|
+
);
|
|
4384
4411
|
this.touch(parent.path);
|
|
4385
4412
|
}
|
|
4386
4413
|
async realpath(path, follow2) {
|
|
@@ -5476,8 +5503,12 @@ function closeAll(entry) {
|
|
|
5476
5503
|
|
|
5477
5504
|
// src/commands.ts
|
|
5478
5505
|
var NAME2 = /^[A-Za-z0-9._+-]+$/;
|
|
5506
|
+
var COMMAND_NAME = /^[^/\s\p{Cc}]+$/u;
|
|
5479
5507
|
var ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5480
5508
|
var PACKAGE = /\$\{package\}/g;
|
|
5509
|
+
function commandName(name2) {
|
|
5510
|
+
return COMMAND_NAME.test(name2) && name2.isWellFormed() && name2 !== "." && name2 !== "..";
|
|
5511
|
+
}
|
|
5481
5512
|
function inside(pkg, rel2) {
|
|
5482
5513
|
if (typeof rel2 !== "string" || rel2 === "") return void 0;
|
|
5483
5514
|
const clean = rel2.replace(/^\.\//, "");
|
|
@@ -5567,7 +5598,7 @@ function commandsOf(pkg, manifest) {
|
|
|
5567
5598
|
const shared = envOf(pkg, slicc.env);
|
|
5568
5599
|
const out = [];
|
|
5569
5600
|
for (const [name2, raw] of Object.entries(entries)) {
|
|
5570
|
-
if (!
|
|
5601
|
+
if (!commandName(name2) || !raw || typeof raw !== "object") {
|
|
5571
5602
|
continue;
|
|
5572
5603
|
}
|
|
5573
5604
|
const command = commandOf(pkg, name2, raw, packageAbi, shared);
|
|
@@ -5619,18 +5650,86 @@ async function packagesIn(fs, roots) {
|
|
|
5619
5650
|
dirs.push(...await packages(fs, root));
|
|
5620
5651
|
return dirs;
|
|
5621
5652
|
}
|
|
5622
|
-
|
|
5623
|
-
const
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
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);
|
|
5630
5684
|
}
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
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
|
+
}
|
|
5634
5733
|
}
|
|
5635
5734
|
}
|
|
5636
5735
|
if (!found.has("sh") && found.has("bash")) {
|
|
@@ -6089,7 +6188,7 @@ var FreshModules = class {
|
|
|
6089
6188
|
};
|
|
6090
6189
|
|
|
6091
6190
|
// src/fs/physical-path.ts
|
|
6092
|
-
var
|
|
6191
|
+
var MAX_HOPS2 = 40;
|
|
6093
6192
|
function start(path) {
|
|
6094
6193
|
return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
|
|
6095
6194
|
}
|
|
@@ -6114,7 +6213,7 @@ function rest(walk2, part) {
|
|
|
6114
6213
|
return lexical(`/${[...walk2.done, part, ...walk2.todo].join("/")}`);
|
|
6115
6214
|
}
|
|
6116
6215
|
function follow(walk2, target) {
|
|
6117
|
-
if (++walk2.hops >
|
|
6216
|
+
if (++walk2.hops > MAX_HOPS2) return false;
|
|
6118
6217
|
if (target.startsWith("/")) walk2.done.length = 0;
|
|
6119
6218
|
walk2.todo = [...target.split("/").filter((p) => p !== ""), ...walk2.todo];
|
|
6120
6219
|
return true;
|
|
@@ -8265,7 +8364,7 @@ async function dispatchOne(entry, req) {
|
|
|
8265
8364
|
}
|
|
8266
8365
|
|
|
8267
8366
|
// src/realm/sync-sab-wire.ts
|
|
8268
|
-
var SAB_HEADER_I32 =
|
|
8367
|
+
var SAB_HEADER_I32 = 18;
|
|
8269
8368
|
var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
|
|
8270
8369
|
var SAB_CLOCK_I64 = 3;
|
|
8271
8370
|
var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
|
|
@@ -8285,6 +8384,7 @@ var SAB_I_OFFSET_HI = 12;
|
|
|
8285
8384
|
var SAB_I_KILLED = 13;
|
|
8286
8385
|
var SAB_I_ASYNC = 14;
|
|
8287
8386
|
var SAB_I_STOP = 15;
|
|
8387
|
+
var SAB_I_BLOCKED = 16;
|
|
8288
8388
|
var U32 = 2 ** 32;
|
|
8289
8389
|
function storeU53(header4, lo, hi, value) {
|
|
8290
8390
|
Atomics.store(header4, hi, Math.floor(value / U32));
|
|
@@ -8837,12 +8937,32 @@ function mountTable(mounts = []) {
|
|
|
8837
8937
|
`;
|
|
8838
8938
|
}
|
|
8839
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
|
+
|
|
8840
8948
|
// src/process/procfs.ts
|
|
8841
8949
|
var HZ = 100;
|
|
8842
8950
|
var KIB = 1024;
|
|
8843
8951
|
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
8844
8952
|
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
8845
|
-
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
|
+
}
|
|
8846
8966
|
function commOf(info) {
|
|
8847
8967
|
const name2 = info.argv[0] ?? "";
|
|
8848
8968
|
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
@@ -8930,7 +9050,7 @@ function pidStatus(info) {
|
|
|
8930
9050
|
"SigQ: 0/0",
|
|
8931
9051
|
"SigPnd: 0000000000000000",
|
|
8932
9052
|
"ShdPnd: 0000000000000000",
|
|
8933
|
-
|
|
9053
|
+
`SigBlk: ${sigMask(info.sigBlk)}`,
|
|
8934
9054
|
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
8935
9055
|
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
8936
9056
|
""
|
|
@@ -8966,6 +9086,7 @@ function memoryInfo(source, used = 0) {
|
|
|
8966
9086
|
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
8967
9087
|
}
|
|
8968
9088
|
function systemFile(name2, listing, now, memory) {
|
|
9089
|
+
if (name2 === "version") return procVersion();
|
|
8969
9090
|
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
8970
9091
|
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
8971
9092
|
`;
|
|
@@ -9056,11 +9177,17 @@ var ProcTree = class {
|
|
|
9056
9177
|
names: () => [
|
|
9057
9178
|
...SYSTEM_NAMES,
|
|
9058
9179
|
"mounts",
|
|
9180
|
+
"sys",
|
|
9059
9181
|
"self",
|
|
9060
9182
|
...this.listing().processes.map((p) => String(p.pid))
|
|
9061
9183
|
]
|
|
9062
9184
|
};
|
|
9063
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
|
+
}
|
|
9064
9191
|
if (top === "self") {
|
|
9065
9192
|
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
9066
9193
|
}
|
|
@@ -9138,7 +9265,7 @@ var ProcTree = class {
|
|
|
9138
9265
|
}
|
|
9139
9266
|
}
|
|
9140
9267
|
};
|
|
9141
|
-
var
|
|
9268
|
+
var MAX_HOPS3 = 40;
|
|
9142
9269
|
function* procWalk(path, follow2) {
|
|
9143
9270
|
let done4 = [];
|
|
9144
9271
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -9157,7 +9284,7 @@ function* procWalk(path, follow2) {
|
|
|
9157
9284
|
if (!follow2 && todo.length === 0) return void 0;
|
|
9158
9285
|
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
9159
9286
|
if (typeof target === "string") {
|
|
9160
|
-
if (++hops >
|
|
9287
|
+
if (++hops > MAX_HOPS3) return void 0;
|
|
9161
9288
|
[done4, todo] = throughLink(target, done4, todo);
|
|
9162
9289
|
} else {
|
|
9163
9290
|
broken ??= refusalOf(target);
|
|
@@ -12037,11 +12164,12 @@ var VfsNodes = class {
|
|
|
12037
12164
|
byId = /* @__PURE__ */ new Map();
|
|
12038
12165
|
keepsOnDisk = false;
|
|
12039
12166
|
fs;
|
|
12040
|
-
entries
|
|
12167
|
+
entries;
|
|
12041
12168
|
onClosed;
|
|
12042
|
-
constructor(fs, onClosed) {
|
|
12169
|
+
constructor(fs, onClosed, entries = /* @__PURE__ */ new Map()) {
|
|
12043
12170
|
this.fs = fs;
|
|
12044
12171
|
this.onClosed = onClosed;
|
|
12172
|
+
this.entries = entries;
|
|
12045
12173
|
}
|
|
12046
12174
|
async onEntry(path, op) {
|
|
12047
12175
|
const key = await this.entryKey(path);
|
|
@@ -12531,6 +12659,7 @@ var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
|
12531
12659
|
var WasmProcess = class {
|
|
12532
12660
|
exited = false;
|
|
12533
12661
|
children;
|
|
12662
|
+
deathSignals = /* @__PURE__ */ new Map();
|
|
12534
12663
|
caught = 0;
|
|
12535
12664
|
ignored = 0;
|
|
12536
12665
|
inherited = 0;
|
|
@@ -12565,7 +12694,10 @@ var WasmProcess = class {
|
|
|
12565
12694
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
12566
12695
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
12567
12696
|
this.children.onChildState = () => this.signal(SIG.CHLD);
|
|
12568
|
-
this.children.onReap =
|
|
12697
|
+
this.children.onReap = (pid2) => {
|
|
12698
|
+
this.deathSignals.delete(pid2);
|
|
12699
|
+
options.onReap?.(pid2);
|
|
12700
|
+
};
|
|
12569
12701
|
}
|
|
12570
12702
|
ignores(bit) {
|
|
12571
12703
|
return (this.signalMasks().ignored & bit) !== 0;
|
|
@@ -12593,6 +12725,10 @@ var WasmProcess = class {
|
|
|
12593
12725
|
if (sig === SIG.STOP) return this.stop(sig);
|
|
12594
12726
|
const bit = sigbit(sig);
|
|
12595
12727
|
if (this.ignores(bit)) return "ignore";
|
|
12728
|
+
if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
|
|
12729
|
+
this.options.onPending?.(sig);
|
|
12730
|
+
return "deliver";
|
|
12731
|
+
}
|
|
12596
12732
|
if (!(this.caught & bit)) {
|
|
12597
12733
|
const action = defaultAction(sig);
|
|
12598
12734
|
return action === "stop" ? this.stop(sig) : action;
|
|
@@ -12609,16 +12745,27 @@ var WasmProcess = class {
|
|
|
12609
12745
|
return "deliver";
|
|
12610
12746
|
}
|
|
12611
12747
|
async spawn(req) {
|
|
12612
|
-
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
|
+
}
|
|
12613
12752
|
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12614
12753
|
const named = argv0 !== void 0 ? { argv0 } : {};
|
|
12615
12754
|
const spawned = { file, argv, ...named, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
12616
12755
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
12756
|
+
if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
|
|
12617
12757
|
if (!exec) return pid;
|
|
12618
12758
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
12619
12759
|
else this.adoptExec(pid);
|
|
12620
12760
|
return pid;
|
|
12621
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
|
+
}
|
|
12622
12769
|
async killSelf(sig, target, probe2) {
|
|
12623
12770
|
if (!this.options.exitSignal) throw new KernelError("ENOSYS");
|
|
12624
12771
|
if (!isSignal(sig) || defaultAction(sig) !== "terminate") throw new KernelError("EINVAL");
|
|
@@ -12897,17 +13044,15 @@ var WasmProcess = class {
|
|
|
12897
13044
|
const file = tty.file();
|
|
12898
13045
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
12899
13046
|
}
|
|
12900
|
-
openSealed() {
|
|
13047
|
+
openSealed(flags2) {
|
|
12901
13048
|
const broker = this.options.sealed;
|
|
12902
13049
|
if (!broker) throw new KernelError("ENOENT");
|
|
12903
|
-
return this.fds.install(broker.open(), 3);
|
|
13050
|
+
return this.fds.install(broker.open(openAccess(flags2)), 3);
|
|
12904
13051
|
}
|
|
12905
13052
|
async openClipboard(flags2) {
|
|
12906
13053
|
const broker = this.options.clipboard;
|
|
12907
13054
|
if (!broker) throw new KernelError("ENOENT");
|
|
12908
|
-
const
|
|
12909
|
-
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
12910
|
-
const file = broker.open(access2, await this.clipboardStamp());
|
|
13055
|
+
const file = broker.open(openAccess(flags2), await this.clipboardStamp());
|
|
12911
13056
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
12912
13057
|
}
|
|
12913
13058
|
async clipboardStamp() {
|
|
@@ -13066,7 +13211,7 @@ var WasmProcess = class {
|
|
|
13066
13211
|
case "fd-tty-names":
|
|
13067
13212
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
13068
13213
|
case "fd-open-sealed":
|
|
13069
|
-
return { ok: true, kind: "json", json: this.openSealed() };
|
|
13214
|
+
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
13070
13215
|
case "fd-open-clipboard":
|
|
13071
13216
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
13072
13217
|
case "fd-tty-owner":
|
|
@@ -13519,6 +13664,8 @@ var WasmProcess = class {
|
|
|
13519
13664
|
this.interrupt.abort();
|
|
13520
13665
|
this.options.locks?.release(this.pid);
|
|
13521
13666
|
this.asyncOps.close();
|
|
13667
|
+
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
13668
|
+
this.deathSignals.clear();
|
|
13522
13669
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13523
13670
|
await this.stampClipboards();
|
|
13524
13671
|
await this.fds.closeAll();
|
|
@@ -13598,19 +13745,25 @@ var Dying = class {
|
|
|
13598
13745
|
}
|
|
13599
13746
|
};
|
|
13600
13747
|
function killThread(thread, caught, sig) {
|
|
13601
|
-
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;
|
|
13602
13751
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
13752
|
+
if (held) return true;
|
|
13603
13753
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
13604
13754
|
const blocked = thread.interrupt;
|
|
13605
13755
|
thread.interrupt = new AbortController();
|
|
13606
13756
|
blocked.abort();
|
|
13607
13757
|
return true;
|
|
13608
13758
|
}
|
|
13759
|
+
function unblocked(header4) {
|
|
13760
|
+
return Atomics.load(header4, SAB_I_SIGNALS) & ~Atomics.load(header4, SAB_I_BLOCKED);
|
|
13761
|
+
}
|
|
13609
13762
|
function threadSignalsOf(sab) {
|
|
13610
13763
|
return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
|
|
13611
13764
|
}
|
|
13612
13765
|
function threadCancel(thread) {
|
|
13613
|
-
return
|
|
13766
|
+
return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
|
|
13614
13767
|
}
|
|
13615
13768
|
function notifiers(header4) {
|
|
13616
13769
|
return {
|
|
@@ -13735,15 +13888,16 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
13735
13888
|
resolver: opts.resolver,
|
|
13736
13889
|
...notifiers(header4),
|
|
13737
13890
|
onTimer: (which) => void Atomics.or(header4, SAB_I_TIMERS, 1 << which),
|
|
13738
|
-
hasPending: () =>
|
|
13891
|
+
hasPending: () => unblocked(header4) !== 0 || Atomics.load(header4, SAB_I_TIMERS) !== 0,
|
|
13739
13892
|
raise: hooks.raise,
|
|
13740
13893
|
threadKill: hooks.threadKill,
|
|
13741
13894
|
...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
|
|
13742
13895
|
...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
|
|
13743
|
-
...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) } : {}
|
|
13744
13898
|
};
|
|
13745
13899
|
}
|
|
13746
|
-
function threadInit(opts, program, sab, cred, thread) {
|
|
13900
|
+
function threadInit(opts, program, sab, cred, thread, main) {
|
|
13747
13901
|
return {
|
|
13748
13902
|
type: WASM_THREAD_INIT,
|
|
13749
13903
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -13756,12 +13910,15 @@ function threadInit(opts, program, sab, cred, thread) {
|
|
|
13756
13910
|
cred: copyCred(cred),
|
|
13757
13911
|
owners: opts.owners === true,
|
|
13758
13912
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
13759
|
-
thread
|
|
13913
|
+
thread,
|
|
13914
|
+
signals: main
|
|
13760
13915
|
};
|
|
13761
13916
|
}
|
|
13762
13917
|
function spawnWasmProcess(opts) {
|
|
13763
13918
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13764
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);
|
|
13765
13922
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
13766
13923
|
const created3 = new Created();
|
|
13767
13924
|
const process2 = new WasmProcess(
|
|
@@ -13862,6 +14019,7 @@ function spawnWasmProcess(opts) {
|
|
|
13862
14019
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
13863
14020
|
const tw = opts.createWorker();
|
|
13864
14021
|
const tsignals = threadSignalsOf(tsab);
|
|
14022
|
+
if (thread.blocked) Atomics.store(tsignals.header, SAB_I_BLOCKED, thread.blocked);
|
|
13865
14023
|
threadSignals.set(thread.tid, tsignals);
|
|
13866
14024
|
const tdispatch = (req) => dying.serving(
|
|
13867
14025
|
() => isWasmSyscall(req) ? process2.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -13883,7 +14041,7 @@ function spawnWasmProcess(opts) {
|
|
|
13883
14041
|
tresponder.dispose();
|
|
13884
14042
|
tw.terminate();
|
|
13885
14043
|
});
|
|
13886
|
-
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread));
|
|
14044
|
+
tw.postMessage(threadInit(opts, program, tsab, process2.cred, thread, sab));
|
|
13887
14045
|
};
|
|
13888
14046
|
worker.postMessage(
|
|
13889
14047
|
processInit(opts, sab, process2.umask, copyCred(process2.cred), lane?.lane),
|
|
@@ -13905,6 +14063,7 @@ function spawnWasmProcess(opts) {
|
|
|
13905
14063
|
onState: (listener) => process2.onState(listener),
|
|
13906
14064
|
memory: () => Atomics.load(header4, SAB_I_MEMORY) * 65536,
|
|
13907
14065
|
ignoredSignals: (fork) => process2.inheritable(fork),
|
|
14066
|
+
blockedSignals: () => opts.program.abi === "wasi" ? Atomics.load(header4, SAB_I_BLOCKED) : 0,
|
|
13908
14067
|
signalMasks: () => process2.signalMasks(),
|
|
13909
14068
|
umask: () => process2.umask,
|
|
13910
14069
|
cred: () => copyCred(process2.cred),
|
|
@@ -14785,14 +14944,19 @@ var SealedChannel = class {
|
|
|
14785
14944
|
offset = 0;
|
|
14786
14945
|
inflight;
|
|
14787
14946
|
broker;
|
|
14788
|
-
|
|
14947
|
+
access;
|
|
14948
|
+
constructor(broker, access2) {
|
|
14789
14949
|
this.broker = broker;
|
|
14950
|
+
this.access = access2;
|
|
14790
14951
|
}
|
|
14791
14952
|
send(bytes, caller, gone) {
|
|
14953
|
+
if (this.access === "read") {
|
|
14954
|
+
bytes.fill(0);
|
|
14955
|
+
throw new KernelError("EBADF");
|
|
14956
|
+
}
|
|
14792
14957
|
const length2 = bytes.length;
|
|
14793
14958
|
const fields = parseSealed(bytes);
|
|
14794
|
-
this.
|
|
14795
|
-
this.offset = 0;
|
|
14959
|
+
this.drop();
|
|
14796
14960
|
this.inflight?.control.abort("replaced");
|
|
14797
14961
|
const control = new AbortController();
|
|
14798
14962
|
const withdraw = () => control.abort("withdrawn");
|
|
@@ -14828,15 +14992,18 @@ var SealedChannel = class {
|
|
|
14828
14992
|
if (!signal.aborted) return reply;
|
|
14829
14993
|
return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
|
|
14830
14994
|
}
|
|
14995
|
+
drop() {
|
|
14996
|
+
this.reply?.fill(0);
|
|
14997
|
+
this.reply = void 0;
|
|
14998
|
+
this.offset = 0;
|
|
14999
|
+
}
|
|
14831
15000
|
async read(max, signal) {
|
|
15001
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
14832
15002
|
for (; ; ) {
|
|
14833
15003
|
if (this.reply) {
|
|
14834
15004
|
const out = this.reply.slice(this.offset, this.offset + max);
|
|
14835
15005
|
this.offset += out.length;
|
|
14836
|
-
if (this.offset >= this.reply.length)
|
|
14837
|
-
this.reply = void 0;
|
|
14838
|
-
this.offset = 0;
|
|
14839
|
-
}
|
|
15006
|
+
if (this.offset >= this.reply.length) this.drop();
|
|
14840
15007
|
return out;
|
|
14841
15008
|
}
|
|
14842
15009
|
const flight = this.inflight;
|
|
@@ -14869,7 +15036,7 @@ var SealedChannel = class {
|
|
|
14869
15036
|
close() {
|
|
14870
15037
|
this.inflight?.control.abort("withdrawn");
|
|
14871
15038
|
this.inflight = void 0;
|
|
14872
|
-
this.
|
|
15039
|
+
this.drop();
|
|
14873
15040
|
}
|
|
14874
15041
|
};
|
|
14875
15042
|
function swapOf(reply) {
|
|
@@ -14926,12 +15093,14 @@ var SealedBroker = class {
|
|
|
14926
15093
|
control.abort("done");
|
|
14927
15094
|
}
|
|
14928
15095
|
}
|
|
14929
|
-
open() {
|
|
14930
|
-
const channel = new SealedChannel(this);
|
|
15096
|
+
open(access2 = "both") {
|
|
15097
|
+
const channel = new SealedChannel(this, access2);
|
|
14931
15098
|
return new OpenFile({
|
|
14932
|
-
read: (max, signal) => channel.read(max, signal),
|
|
14933
|
-
|
|
14934
|
-
|
|
15099
|
+
...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
|
|
15100
|
+
...access2 === "read" ? {} : {
|
|
15101
|
+
write: async () => {
|
|
15102
|
+
throw new KernelError("EINVAL");
|
|
15103
|
+
}
|
|
14935
15104
|
},
|
|
14936
15105
|
poll: () => channel.poll(),
|
|
14937
15106
|
changed: (signal) => channel.changed(signal),
|
|
@@ -16653,7 +16822,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
16653
16822
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
16654
16823
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
16655
16824
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
16656
|
-
var
|
|
16825
|
+
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
16826
|
+
var RULE = new RegExp(
|
|
16827
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
16828
|
+
);
|
|
16657
16829
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
16658
16830
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
16659
16831
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
@@ -16688,17 +16860,25 @@ function validWho(who) {
|
|
|
16688
16860
|
if (who === "ALL") return true;
|
|
16689
16861
|
return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
|
|
16690
16862
|
}
|
|
16863
|
+
function cwdOf(word) {
|
|
16864
|
+
const words2 = splitWords(word);
|
|
16865
|
+
const path = words2?.length === 1 ? words2[0] : "";
|
|
16866
|
+
return path.startsWith("/") ? normalizePath(path) : "";
|
|
16867
|
+
}
|
|
16691
16868
|
function parseRule(line) {
|
|
16692
16869
|
const text = line.trim();
|
|
16693
16870
|
if (text === "" || text.startsWith("#")) return null;
|
|
16694
16871
|
const m = RULE.exec(text);
|
|
16695
16872
|
if (!m) return void 0;
|
|
16696
|
-
const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
|
|
16873
|
+
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
16697
16874
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
16698
|
-
|
|
16875
|
+
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
16876
|
+
if (cwd === "") return void 0;
|
|
16877
|
+
const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
|
|
16878
|
+
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
16699
16879
|
const cmnd = splitWords(rest2);
|
|
16700
16880
|
if (!cmnd?.[0]?.startsWith("/")) return void 0;
|
|
16701
|
-
return {
|
|
16881
|
+
return { ...rule, cmnd };
|
|
16702
16882
|
}
|
|
16703
16883
|
function flags(parsed2, arg, next2) {
|
|
16704
16884
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -16737,7 +16917,8 @@ function parseArgs(args) {
|
|
|
16737
16917
|
}
|
|
16738
16918
|
function described(rule) {
|
|
16739
16919
|
const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
|
|
16740
|
-
|
|
16920
|
+
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
16921
|
+
return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
16741
16922
|
}
|
|
16742
16923
|
var Sudo = class {
|
|
16743
16924
|
o;
|
|
@@ -16877,7 +17058,7 @@ var Sudo = class {
|
|
|
16877
17058
|
if (untrusted) return untrusted;
|
|
16878
17059
|
const argv = [path, ...args];
|
|
16879
17060
|
const matching = rules.filter(
|
|
16880
|
-
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
|
|
17061
|
+
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
|
|
16881
17062
|
);
|
|
16882
17063
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
16883
17064
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -16899,7 +17080,7 @@ var Sudo = class {
|
|
|
16899
17080
|
}
|
|
16900
17081
|
const changed = await this.untrusted(path, cwd, word);
|
|
16901
17082
|
if (changed) return changed;
|
|
16902
|
-
if (answer === "always" && !await this.remember(self, target, argv)) {
|
|
17083
|
+
if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
16903
17084
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
16904
17085
|
}
|
|
16905
17086
|
return grant();
|
|
@@ -16964,7 +17145,7 @@ ${lines2}
|
|
|
16964
17145
|
requester.removeEventListener("abort", withdraw);
|
|
16965
17146
|
}
|
|
16966
17147
|
}
|
|
16967
|
-
async remember(self, target, argv) {
|
|
17148
|
+
async remember(self, target, cwd, argv) {
|
|
16968
17149
|
const { fs } = this.o;
|
|
16969
17150
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
16970
17151
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -16974,7 +17155,8 @@ ${lines2}
|
|
|
16974
17155
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
16975
17156
|
if (st && !await this.trusted(path)) return false;
|
|
16976
17157
|
const old = st ? await fs.readFile(path) : "";
|
|
16977
|
-
const
|
|
17158
|
+
const words2 = argv.map(quoteWord).join(" ");
|
|
17159
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
16978
17160
|
`;
|
|
16979
17161
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
16980
17162
|
${line}`;
|
|
@@ -17107,15 +17289,25 @@ function shebang(head) {
|
|
|
17107
17289
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
17108
17290
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
17109
17291
|
}
|
|
17110
|
-
async function rootOnly(fs, path) {
|
|
17292
|
+
async function rootOnly(fs, path, dir = false) {
|
|
17111
17293
|
const names = chain(path);
|
|
17112
17294
|
for (const [i, at] of names.entries()) {
|
|
17113
17295
|
const st = await fs.lstat(at).catch(() => void 0);
|
|
17114
|
-
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17296
|
+
const kind = i === names.length - 1 && !dir ? st?.isFile : st?.isDirectory;
|
|
17115
17297
|
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17116
17298
|
}
|
|
17117
17299
|
return true;
|
|
17118
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
|
+
}
|
|
17119
17311
|
function plainEnv(words2) {
|
|
17120
17312
|
const next2 = words2[1];
|
|
17121
17313
|
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
@@ -17208,6 +17400,8 @@ var Launcher = class {
|
|
|
17208
17400
|
base;
|
|
17209
17401
|
createWorker;
|
|
17210
17402
|
modulesDir;
|
|
17403
|
+
appended;
|
|
17404
|
+
reportedRoots = /* @__PURE__ */ new Set();
|
|
17211
17405
|
env;
|
|
17212
17406
|
catalogs = /* @__PURE__ */ new Map();
|
|
17213
17407
|
ownCatalogs = /* @__PURE__ */ new Map();
|
|
@@ -17314,6 +17508,7 @@ var Launcher = class {
|
|
|
17314
17508
|
this.processMounts = options.processMounts ?? true;
|
|
17315
17509
|
this.pnpmHome = options.env?.PNPM_HOME ?? SYSTEM_PNPM_HOME;
|
|
17316
17510
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17511
|
+
this.appended = appendedRoots(options.commands);
|
|
17317
17512
|
this.cdp = new CdpHosts(options.cdp);
|
|
17318
17513
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17319
17514
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
@@ -17363,9 +17558,9 @@ var Launcher = class {
|
|
|
17363
17558
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
17364
17559
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
17365
17560
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
17366
|
-
options.fs.protect?.(this.prefixes);
|
|
17367
17561
|
const integrity = options.protect?.integrity;
|
|
17368
17562
|
integrityOptions(integrity);
|
|
17563
|
+
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
17369
17564
|
if (integrity && this.prefixes.length > 0) {
|
|
17370
17565
|
this.integrity = new Integrity(
|
|
17371
17566
|
this.prefixes,
|
|
@@ -17388,7 +17583,7 @@ var Launcher = class {
|
|
|
17388
17583
|
});
|
|
17389
17584
|
void this.unlinked.sweep("/");
|
|
17390
17585
|
this.watchers.watch(
|
|
17391
|
-
[this.modulesDir, this.pnpmHome],
|
|
17586
|
+
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
17392
17587
|
{ recursive: true },
|
|
17393
17588
|
() => this.resetCatalogs()
|
|
17394
17589
|
);
|
|
@@ -17419,7 +17614,10 @@ var Launcher = class {
|
|
|
17419
17614
|
commands(scope = "") {
|
|
17420
17615
|
let found = this.catalogs.get(scope);
|
|
17421
17616
|
if (!found) {
|
|
17422
|
-
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));
|
|
17423
17621
|
this.catalogs.set(scope, found);
|
|
17424
17622
|
}
|
|
17425
17623
|
return found;
|
|
@@ -17446,10 +17644,37 @@ var Launcher = class {
|
|
|
17446
17644
|
}
|
|
17447
17645
|
return found;
|
|
17448
17646
|
}
|
|
17449
|
-
async roots(scope = "") {
|
|
17450
|
-
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
|
+
];
|
|
17451
17653
|
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
17452
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
|
+
}
|
|
17453
17678
|
resetCatalogs() {
|
|
17454
17679
|
this.catalogs.clear();
|
|
17455
17680
|
this.ownCatalogs.clear();
|
|
@@ -17555,14 +17780,22 @@ var Launcher = class {
|
|
|
17555
17780
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
17556
17781
|
const via = [interp, ...inner?.via ?? []];
|
|
17557
17782
|
const sources = [script, ...inner?.sources ?? []];
|
|
17558
|
-
|
|
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
|
+
};
|
|
17559
17791
|
}
|
|
17560
17792
|
const target = withScriptEnv(found, command);
|
|
17561
17793
|
return {
|
|
17562
17794
|
target,
|
|
17563
17795
|
args: [...target.prefix ?? [], ...passed],
|
|
17564
17796
|
via: [interp],
|
|
17565
|
-
sources: [script]
|
|
17797
|
+
sources: [script],
|
|
17798
|
+
...command?.bin ? { bins: [script] } : {}
|
|
17566
17799
|
};
|
|
17567
17800
|
}
|
|
17568
17801
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17588,6 +17821,7 @@ var Launcher = class {
|
|
|
17588
17821
|
const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
|
|
17589
17822
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
17590
17823
|
}
|
|
17824
|
+
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
17591
17825
|
}
|
|
17592
17826
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17593
17827
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
@@ -17886,6 +18120,7 @@ var Launcher = class {
|
|
|
17886
18120
|
},
|
|
17887
18121
|
settling: () => this.settling.isSettling(pid),
|
|
17888
18122
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
18123
|
+
...req.blocked ? { blocked: req.blocked } : {},
|
|
17889
18124
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
17890
18125
|
cred: req.cred,
|
|
17891
18126
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
@@ -18160,6 +18395,7 @@ var Launcher = class {
|
|
|
18160
18395
|
report,
|
|
18161
18396
|
ppid,
|
|
18162
18397
|
ignored: this.ignoredBy(ppid),
|
|
18398
|
+
blocked: this.blockedBy(ppid),
|
|
18163
18399
|
umask: this.umaskOf(ppid),
|
|
18164
18400
|
cred,
|
|
18165
18401
|
tag: this.tagOf(ppid),
|
|
@@ -18221,6 +18457,7 @@ var Launcher = class {
|
|
|
18221
18457
|
ppid,
|
|
18222
18458
|
fork: state,
|
|
18223
18459
|
ignored: this.ignoredBy(ppid, true),
|
|
18460
|
+
blocked: this.blockedBy(ppid),
|
|
18224
18461
|
umask: this.umaskOf(ppid),
|
|
18225
18462
|
cred: this.credOf(ppid),
|
|
18226
18463
|
tag: this.tagOf(ppid)
|
|
@@ -18272,11 +18509,16 @@ var Launcher = class {
|
|
|
18272
18509
|
}
|
|
18273
18510
|
signalMasksOf(pid) {
|
|
18274
18511
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
18275
|
-
|
|
18512
|
+
const blocked = this.blockedBy(pid);
|
|
18513
|
+
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
18514
|
+
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
18276
18515
|
}
|
|
18277
18516
|
controlsJobs(pid) {
|
|
18278
18517
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
18279
18518
|
}
|
|
18519
|
+
blockedBy(pid) {
|
|
18520
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
18521
|
+
}
|
|
18280
18522
|
ignoredBy(pid, fork = false) {
|
|
18281
18523
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
18282
18524
|
}
|
|
@@ -18641,7 +18883,7 @@ var Launcher = class {
|
|
|
18641
18883
|
(dir) => this.userCommandDir(dir),
|
|
18642
18884
|
this.owners
|
|
18643
18885
|
);
|
|
18644
|
-
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
18886
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
18645
18887
|
nodes.keepsOnDisk = true;
|
|
18646
18888
|
this.openFiles.add(nodes);
|
|
18647
18889
|
const unlinked = new UnlinkedKeeper(
|
|
@@ -20034,6 +20276,7 @@ async function createNodeKernel(options = {}) {
|
|
|
20034
20276
|
terminated
|
|
20035
20277
|
),
|
|
20036
20278
|
...options.modules ? { modules: options.modules } : {},
|
|
20279
|
+
...options.commands ? { commands: options.commands } : {},
|
|
20037
20280
|
...options.env ? { env: options.env } : {},
|
|
20038
20281
|
...transport ? { transport } : {},
|
|
20039
20282
|
...options.network?.uplink ? { uplink: options.network.uplink } : {},
|