@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/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) {
|
|
@@ -2580,6 +2601,10 @@ var KernelError = class extends Error {
|
|
|
2580
2601
|
if (detail !== void 0) this.detail = detail;
|
|
2581
2602
|
}
|
|
2582
2603
|
};
|
|
2604
|
+
function openAccess(flags2) {
|
|
2605
|
+
const mode = flags2 & 3;
|
|
2606
|
+
return mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
2607
|
+
}
|
|
2583
2608
|
function pollFile(file) {
|
|
2584
2609
|
return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
|
|
2585
2610
|
}
|
|
@@ -7127,8 +7152,12 @@ function closeAll(entry) {
|
|
|
7127
7152
|
|
|
7128
7153
|
// src/commands.ts
|
|
7129
7154
|
var NAME2 = /^[A-Za-z0-9._+-]+$/;
|
|
7155
|
+
var COMMAND_NAME = /^[^/\s\p{Cc}]+$/u;
|
|
7130
7156
|
var ENV_KEY = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7131
7157
|
var PACKAGE = /\$\{package\}/g;
|
|
7158
|
+
function commandName(name2) {
|
|
7159
|
+
return COMMAND_NAME.test(name2) && name2.isWellFormed() && name2 !== "." && name2 !== "..";
|
|
7160
|
+
}
|
|
7132
7161
|
function inside(pkg, rel2) {
|
|
7133
7162
|
if (typeof rel2 !== "string" || rel2 === "") return void 0;
|
|
7134
7163
|
const clean = rel2.replace(/^\.\//, "");
|
|
@@ -7218,7 +7247,7 @@ function commandsOf(pkg, manifest) {
|
|
|
7218
7247
|
const shared = envOf(pkg, slicc.env);
|
|
7219
7248
|
const out = [];
|
|
7220
7249
|
for (const [name2, raw] of Object.entries(entries)) {
|
|
7221
|
-
if (!
|
|
7250
|
+
if (!commandName(name2) || !raw || typeof raw !== "object") {
|
|
7222
7251
|
continue;
|
|
7223
7252
|
}
|
|
7224
7253
|
const command = commandOf(pkg, name2, raw, packageAbi, shared);
|
|
@@ -7270,18 +7299,86 @@ async function packagesIn(fs, roots) {
|
|
|
7270
7299
|
dirs.push(...await packages(fs, root));
|
|
7271
7300
|
return dirs;
|
|
7272
7301
|
}
|
|
7273
|
-
|
|
7274
|
-
const
|
|
7275
|
-
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
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);
|
|
7281
7333
|
}
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
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
|
+
}
|
|
7285
7382
|
}
|
|
7286
7383
|
}
|
|
7287
7384
|
if (!found.has("sh") && found.has("bash")) {
|
|
@@ -7740,7 +7837,7 @@ var FreshModules = class {
|
|
|
7740
7837
|
};
|
|
7741
7838
|
|
|
7742
7839
|
// src/fs/physical-path.ts
|
|
7743
|
-
var
|
|
7840
|
+
var MAX_HOPS2 = 40;
|
|
7744
7841
|
function start(path) {
|
|
7745
7842
|
return { done: [], todo: path.split("/").filter((p) => p !== ""), hops: 0 };
|
|
7746
7843
|
}
|
|
@@ -7765,7 +7862,7 @@ function rest(walk2, part) {
|
|
|
7765
7862
|
return lexical(`/${[...walk2.done, part, ...walk2.todo].join("/")}`);
|
|
7766
7863
|
}
|
|
7767
7864
|
function follow(walk2, target) {
|
|
7768
|
-
if (++walk2.hops >
|
|
7865
|
+
if (++walk2.hops > MAX_HOPS2) return false;
|
|
7769
7866
|
if (target.startsWith("/")) walk2.done.length = 0;
|
|
7770
7867
|
walk2.todo = [...target.split("/").filter((p) => p !== ""), ...walk2.todo];
|
|
7771
7868
|
return true;
|
|
@@ -9971,7 +10068,7 @@ async function dispatchOne(entry, req) {
|
|
|
9971
10068
|
}
|
|
9972
10069
|
|
|
9973
10070
|
// src/realm/sync-sab-wire.ts
|
|
9974
|
-
var SAB_HEADER_I32 =
|
|
10071
|
+
var SAB_HEADER_I32 = 18;
|
|
9975
10072
|
var SAB_CLOCK_OFFSET = SAB_HEADER_I32 * 4;
|
|
9976
10073
|
var SAB_CLOCK_I64 = 3;
|
|
9977
10074
|
var SAB_HEADER_BYTES = SAB_CLOCK_OFFSET + SAB_CLOCK_I64 * 8;
|
|
@@ -9991,6 +10088,7 @@ var SAB_I_OFFSET_HI = 12;
|
|
|
9991
10088
|
var SAB_I_KILLED = 13;
|
|
9992
10089
|
var SAB_I_ASYNC = 14;
|
|
9993
10090
|
var SAB_I_STOP = 15;
|
|
10091
|
+
var SAB_I_BLOCKED = 16;
|
|
9994
10092
|
var U32 = 2 ** 32;
|
|
9995
10093
|
function storeU53(header3, lo, hi, value) {
|
|
9996
10094
|
Atomics.store(header3, hi, Math.floor(value / U32));
|
|
@@ -10516,12 +10614,32 @@ function mountTable(mounts = []) {
|
|
|
10516
10614
|
`;
|
|
10517
10615
|
}
|
|
10518
10616
|
|
|
10617
|
+
// src/version.ts
|
|
10618
|
+
var KERNEL_VERSION = true ? "1.88.0" : "0.0.0-dev";
|
|
10619
|
+
var OS_RELEASE = "6.0.0-slicc";
|
|
10620
|
+
function procVersion() {
|
|
10621
|
+
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
10622
|
+
`;
|
|
10623
|
+
}
|
|
10624
|
+
|
|
10519
10625
|
// src/process/procfs.ts
|
|
10520
10626
|
var HZ = 100;
|
|
10521
10627
|
var KIB = 1024;
|
|
10522
10628
|
var FALLBACK_MEMORY = 4 * KIB * KIB * KIB;
|
|
10523
10629
|
var PID_FILES = ["cmdline", "comm", "stat", "statm", "status"];
|
|
10524
|
-
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime"];
|
|
10630
|
+
var SYSTEM_FILES = ["loadavg", "meminfo", "stat", "uptime", "version"];
|
|
10631
|
+
var SYS_TREE = {
|
|
10632
|
+
kernel: { osrelease: `${OS_RELEASE}
|
|
10633
|
+
`, ostype: "Linux\n" }
|
|
10634
|
+
};
|
|
10635
|
+
function sysEntry(parts2) {
|
|
10636
|
+
let at = SYS_TREE;
|
|
10637
|
+
for (const part of parts2) {
|
|
10638
|
+
if (typeof at !== "object" || !Object.hasOwn(at, part)) return void 0;
|
|
10639
|
+
at = at[part];
|
|
10640
|
+
}
|
|
10641
|
+
return at;
|
|
10642
|
+
}
|
|
10525
10643
|
function commOf(info) {
|
|
10526
10644
|
const name2 = info.argv[0] ?? "";
|
|
10527
10645
|
return name2.slice(name2.lastIndexOf("/") + 1).slice(0, 15);
|
|
@@ -10609,7 +10727,7 @@ function pidStatus(info) {
|
|
|
10609
10727
|
"SigQ: 0/0",
|
|
10610
10728
|
"SigPnd: 0000000000000000",
|
|
10611
10729
|
"ShdPnd: 0000000000000000",
|
|
10612
|
-
|
|
10730
|
+
`SigBlk: ${sigMask(info.sigBlk)}`,
|
|
10613
10731
|
`SigIgn: ${sigMask(info.sigIgn)}`,
|
|
10614
10732
|
`SigCgt: ${sigMask(info.sigCgt)}`,
|
|
10615
10733
|
""
|
|
@@ -10645,6 +10763,7 @@ function memoryInfo(source, used = 0) {
|
|
|
10645
10763
|
].map(([key, value]) => `${`${key}:`.padEnd(16)}${value.padStart(12)}`).concat("").join("\n");
|
|
10646
10764
|
}
|
|
10647
10765
|
function systemFile(name2, listing, now, memory) {
|
|
10766
|
+
if (name2 === "version") return procVersion();
|
|
10648
10767
|
const up = Math.max(0, now - listing.boot) / 1e3;
|
|
10649
10768
|
if (name2 === "uptime") return `${up.toFixed(2)} ${up.toFixed(2)}
|
|
10650
10769
|
`;
|
|
@@ -10735,11 +10854,17 @@ var ProcTree = class {
|
|
|
10735
10854
|
names: () => [
|
|
10736
10855
|
...SYSTEM_NAMES,
|
|
10737
10856
|
"mounts",
|
|
10857
|
+
"sys",
|
|
10738
10858
|
"self",
|
|
10739
10859
|
...this.listing().processes.map((p) => String(p.pid))
|
|
10740
10860
|
]
|
|
10741
10861
|
};
|
|
10742
10862
|
}
|
|
10863
|
+
if (top === "sys") {
|
|
10864
|
+
const entry = sysEntry(parts2.slice(1));
|
|
10865
|
+
if (typeof entry === "string") return { kind: "file", content: () => entry };
|
|
10866
|
+
return entry && { kind: "dir", names: () => Object.keys(entry) };
|
|
10867
|
+
}
|
|
10743
10868
|
if (top === "self") {
|
|
10744
10869
|
return leaf === void 0 ? { kind: "link", target: String(this.pid) } : void 0;
|
|
10745
10870
|
}
|
|
@@ -10817,7 +10942,7 @@ var ProcTree = class {
|
|
|
10817
10942
|
}
|
|
10818
10943
|
}
|
|
10819
10944
|
};
|
|
10820
|
-
var
|
|
10945
|
+
var MAX_HOPS3 = 40;
|
|
10821
10946
|
function* procWalk(path, follow2) {
|
|
10822
10947
|
let done4 = [];
|
|
10823
10948
|
let todo = path.split("/").filter((part) => part !== "");
|
|
@@ -10836,7 +10961,7 @@ function* procWalk(path, follow2) {
|
|
|
10836
10961
|
if (!follow2 && todo.length === 0) return void 0;
|
|
10837
10962
|
const target = yield { at, check: todo.find((next2) => next2 !== ".") === ".." };
|
|
10838
10963
|
if (typeof target === "string") {
|
|
10839
|
-
if (++hops >
|
|
10964
|
+
if (++hops > MAX_HOPS3) return void 0;
|
|
10840
10965
|
[done4, todo] = throughLink(target, done4, todo);
|
|
10841
10966
|
} else {
|
|
10842
10967
|
broken ??= refusalOf(target);
|
|
@@ -12395,11 +12520,12 @@ var VfsNodes = class {
|
|
|
12395
12520
|
byId = /* @__PURE__ */ new Map();
|
|
12396
12521
|
keepsOnDisk = false;
|
|
12397
12522
|
fs;
|
|
12398
|
-
entries
|
|
12523
|
+
entries;
|
|
12399
12524
|
onClosed;
|
|
12400
|
-
constructor(fs, onClosed) {
|
|
12525
|
+
constructor(fs, onClosed, entries = /* @__PURE__ */ new Map()) {
|
|
12401
12526
|
this.fs = fs;
|
|
12402
12527
|
this.onClosed = onClosed;
|
|
12528
|
+
this.entries = entries;
|
|
12403
12529
|
}
|
|
12404
12530
|
async onEntry(path, op) {
|
|
12405
12531
|
const key = await this.entryKey(path);
|
|
@@ -12889,6 +13015,7 @@ var HOSTS_ONLY = new Resolver({ routes: new Routes() });
|
|
|
12889
13015
|
var WasmProcess = class {
|
|
12890
13016
|
exited = false;
|
|
12891
13017
|
children;
|
|
13018
|
+
deathSignals = /* @__PURE__ */ new Map();
|
|
12892
13019
|
caught = 0;
|
|
12893
13020
|
ignored = 0;
|
|
12894
13021
|
inherited = 0;
|
|
@@ -12923,7 +13050,10 @@ var WasmProcess = class {
|
|
|
12923
13050
|
this.nodes = options.nodes ?? new VfsNodes(options.fs);
|
|
12924
13051
|
if (!options.nodes) options.openFiles?.add(this.nodes);
|
|
12925
13052
|
this.children.onChildState = () => this.signal(SIG.CHLD);
|
|
12926
|
-
this.children.onReap =
|
|
13053
|
+
this.children.onReap = (pid2) => {
|
|
13054
|
+
this.deathSignals.delete(pid2);
|
|
13055
|
+
options.onReap?.(pid2);
|
|
13056
|
+
};
|
|
12927
13057
|
}
|
|
12928
13058
|
ignores(bit) {
|
|
12929
13059
|
return (this.signalMasks().ignored & bit) !== 0;
|
|
@@ -12951,6 +13081,10 @@ var WasmProcess = class {
|
|
|
12951
13081
|
if (sig === SIG.STOP) return this.stop(sig);
|
|
12952
13082
|
const bit = sigbit(sig);
|
|
12953
13083
|
if (this.ignores(bit)) return "ignore";
|
|
13084
|
+
if (((this.options.blockedBits?.() ?? 0) & bit) !== 0) {
|
|
13085
|
+
this.options.onPending?.(sig);
|
|
13086
|
+
return "deliver";
|
|
13087
|
+
}
|
|
12954
13088
|
if (!(this.caught & bit)) {
|
|
12955
13089
|
const action = defaultAction(sig);
|
|
12956
13090
|
return action === "stop" ? this.stop(sig) : action;
|
|
@@ -12967,16 +13101,27 @@ var WasmProcess = class {
|
|
|
12967
13101
|
return "deliver";
|
|
12968
13102
|
}
|
|
12969
13103
|
async spawn(req) {
|
|
12970
|
-
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session } = req;
|
|
13104
|
+
const { file, argv, argv0, env, cwd, stdio, inherit: inherit2, exec, pgid, session, deathSignal } = req;
|
|
13105
|
+
if (deathSignal !== void 0 && (exec || !isSignal(deathSignal))) {
|
|
13106
|
+
throw new KernelError("EINVAL");
|
|
13107
|
+
}
|
|
12971
13108
|
const group = { ...pgid !== void 0 ? { pgid } : {}, ...session ? { session } : {} };
|
|
12972
13109
|
const named = argv0 !== void 0 ? { argv0 } : {};
|
|
12973
13110
|
const spawned = { file, argv, ...named, env, cwd, ...group, ...exec ? { exec } : {} };
|
|
12974
13111
|
const pid = await this.children.spawn(spawned, stdio, inherit2);
|
|
13112
|
+
if (deathSignal !== void 0) this.onDeath(pgid === 0 || session ? -pid : pid, deathSignal);
|
|
12975
13113
|
if (!exec) return pid;
|
|
12976
13114
|
if (this.killed) void Promise.allSettled([this.options.kill?.(pid, SIG.KILL)]);
|
|
12977
13115
|
else this.adoptExec(pid);
|
|
12978
13116
|
return pid;
|
|
12979
13117
|
}
|
|
13118
|
+
onDeath(target, sig) {
|
|
13119
|
+
if (this.exited) this.sendDeath(target, sig);
|
|
13120
|
+
else this.deathSignals.set(target, sig);
|
|
13121
|
+
}
|
|
13122
|
+
sendDeath(target, sig) {
|
|
13123
|
+
void Promise.resolve(this.options.kill?.(target, sig)).catch(() => void 0);
|
|
13124
|
+
}
|
|
12980
13125
|
async killSelf(sig, target, probe) {
|
|
12981
13126
|
if (!this.options.exitSignal) throw new KernelError("ENOSYS");
|
|
12982
13127
|
if (!isSignal(sig) || defaultAction(sig) !== "terminate") throw new KernelError("EINVAL");
|
|
@@ -13255,17 +13400,15 @@ var WasmProcess = class {
|
|
|
13255
13400
|
const file = tty.file();
|
|
13256
13401
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13257
13402
|
}
|
|
13258
|
-
openSealed() {
|
|
13403
|
+
openSealed(flags2) {
|
|
13259
13404
|
const broker = this.options.sealed;
|
|
13260
13405
|
if (!broker) throw new KernelError("ENOENT");
|
|
13261
|
-
return this.fds.install(broker.open(), 3);
|
|
13406
|
+
return this.fds.install(broker.open(openAccess(flags2)), 3);
|
|
13262
13407
|
}
|
|
13263
13408
|
async openClipboard(flags2) {
|
|
13264
13409
|
const broker = this.options.clipboard;
|
|
13265
13410
|
if (!broker) throw new KernelError("ENOENT");
|
|
13266
|
-
const
|
|
13267
|
-
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
13268
|
-
const file = broker.open(access2, await this.clipboardStamp());
|
|
13411
|
+
const file = broker.open(openAccess(flags2), await this.clipboardStamp());
|
|
13269
13412
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13270
13413
|
}
|
|
13271
13414
|
async clipboardStamp() {
|
|
@@ -13424,7 +13567,7 @@ var WasmProcess = class {
|
|
|
13424
13567
|
case "fd-tty-names":
|
|
13425
13568
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
13426
13569
|
case "fd-open-sealed":
|
|
13427
|
-
return { ok: true, kind: "json", json: this.openSealed() };
|
|
13570
|
+
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
13428
13571
|
case "fd-open-clipboard":
|
|
13429
13572
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
13430
13573
|
case "fd-tty-owner":
|
|
@@ -13877,6 +14020,8 @@ var WasmProcess = class {
|
|
|
13877
14020
|
this.interrupt.abort();
|
|
13878
14021
|
this.options.locks?.release(this.pid);
|
|
13879
14022
|
this.asyncOps.close();
|
|
14023
|
+
for (const [target, sig] of this.deathSignals) this.sendDeath(target, sig);
|
|
14024
|
+
this.deathSignals.clear();
|
|
13880
14025
|
for (const pid of this.children.pids()) this.options.onReap?.(pid);
|
|
13881
14026
|
await this.stampClipboards();
|
|
13882
14027
|
await this.fds.closeAll();
|
|
@@ -13956,19 +14101,25 @@ var Dying = class {
|
|
|
13956
14101
|
}
|
|
13957
14102
|
};
|
|
13958
14103
|
function killThread(thread, caught, sig) {
|
|
13959
|
-
if (!thread
|
|
14104
|
+
if (!thread) return false;
|
|
14105
|
+
const held = (Atomics.load(thread.header, SAB_I_BLOCKED) & sigbit(sig)) !== 0;
|
|
14106
|
+
if (!held && (caught & sigbit(sig)) === 0) return false;
|
|
13960
14107
|
Atomics.or(thread.header, SAB_I_SIGNALS, sigbit(sig));
|
|
14108
|
+
if (held) return true;
|
|
13961
14109
|
Atomics.notify(thread.header, SAB_I_SIGNALS);
|
|
13962
14110
|
const blocked = thread.interrupt;
|
|
13963
14111
|
thread.interrupt = new AbortController();
|
|
13964
14112
|
blocked.abort();
|
|
13965
14113
|
return true;
|
|
13966
14114
|
}
|
|
14115
|
+
function unblocked(header3) {
|
|
14116
|
+
return Atomics.load(header3, SAB_I_SIGNALS) & ~Atomics.load(header3, SAB_I_BLOCKED);
|
|
14117
|
+
}
|
|
13967
14118
|
function threadSignalsOf(sab) {
|
|
13968
14119
|
return { header: new Int32Array(sab, 0, SAB_HEADER_I32), interrupt: new AbortController() };
|
|
13969
14120
|
}
|
|
13970
14121
|
function threadCancel(thread) {
|
|
13971
|
-
return
|
|
14122
|
+
return unblocked(thread.header) !== 0 ? AbortSignal.abort() : thread.interrupt.signal;
|
|
13972
14123
|
}
|
|
13973
14124
|
function notifiers(header3) {
|
|
13974
14125
|
return {
|
|
@@ -14093,15 +14244,16 @@ function processOptions(opts, header3, hooks, created3) {
|
|
|
14093
14244
|
resolver: opts.resolver,
|
|
14094
14245
|
...notifiers(header3),
|
|
14095
14246
|
onTimer: (which) => void Atomics.or(header3, SAB_I_TIMERS, 1 << which),
|
|
14096
|
-
hasPending: () =>
|
|
14247
|
+
hasPending: () => unblocked(header3) !== 0 || Atomics.load(header3, SAB_I_TIMERS) !== 0,
|
|
14097
14248
|
raise: hooks.raise,
|
|
14098
14249
|
threadKill: hooks.threadKill,
|
|
14099
14250
|
...hooks.exitNow ? { exitNow: hooks.exitNow } : {},
|
|
14100
14251
|
...hooks.exitSignal ? { exitSignal: hooks.exitSignal } : {},
|
|
14101
|
-
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {}
|
|
14252
|
+
...opts.program.abi === "wasi" || opts.program.abi === "js" ? { pendingBits: () => Atomics.load(header3, SAB_I_SIGNALS) } : {},
|
|
14253
|
+
...opts.program.abi === "wasi" ? { blockedBits: () => Atomics.load(header3, SAB_I_BLOCKED) } : {}
|
|
14102
14254
|
};
|
|
14103
14255
|
}
|
|
14104
|
-
function threadInit(opts, program, sab, cred, thread) {
|
|
14256
|
+
function threadInit(opts, program, sab, cred, thread, main) {
|
|
14105
14257
|
return {
|
|
14106
14258
|
type: WASM_THREAD_INIT,
|
|
14107
14259
|
pid: opts.shownPid ?? opts.pid,
|
|
@@ -14114,12 +14266,15 @@ function threadInit(opts, program, sab, cred, thread) {
|
|
|
14114
14266
|
cred: copyCred(cred),
|
|
14115
14267
|
owners: opts.owners === true,
|
|
14116
14268
|
...opts.ppid !== void 0 ? { ppid: opts.ppid } : {},
|
|
14117
|
-
thread
|
|
14269
|
+
thread,
|
|
14270
|
+
signals: main
|
|
14118
14271
|
};
|
|
14119
14272
|
}
|
|
14120
14273
|
function spawnWasmProcess(opts) {
|
|
14121
14274
|
const sab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
14122
14275
|
const header3 = new Int32Array(sab, 0, SAB_HEADER_I32);
|
|
14276
|
+
if (opts.blocked && opts.program.abi === "wasi")
|
|
14277
|
+
Atomics.store(header3, SAB_I_BLOCKED, opts.blocked);
|
|
14123
14278
|
const threadSignals = /* @__PURE__ */ new Map();
|
|
14124
14279
|
const created3 = new Created();
|
|
14125
14280
|
const process = new WasmProcess(
|
|
@@ -14220,6 +14375,7 @@ function spawnWasmProcess(opts) {
|
|
|
14220
14375
|
const tsab = new SharedArrayBuffer(SAB_HEADER_BYTES + SAB_DEFAULT_WINDOW_BYTES);
|
|
14221
14376
|
const tw = opts.createWorker();
|
|
14222
14377
|
const tsignals = threadSignalsOf(tsab);
|
|
14378
|
+
if (thread.blocked) Atomics.store(tsignals.header, SAB_I_BLOCKED, thread.blocked);
|
|
14223
14379
|
threadSignals.set(thread.tid, tsignals);
|
|
14224
14380
|
const tdispatch = (req) => dying.serving(
|
|
14225
14381
|
() => isWasmSyscall(req) ? process.syscall(req, threadCancel(tsignals)) : dispatchSyncFs(req)
|
|
@@ -14241,7 +14397,7 @@ function spawnWasmProcess(opts) {
|
|
|
14241
14397
|
tresponder.dispose();
|
|
14242
14398
|
tw.terminate();
|
|
14243
14399
|
});
|
|
14244
|
-
tw.postMessage(threadInit(opts, program, tsab, process.cred, thread));
|
|
14400
|
+
tw.postMessage(threadInit(opts, program, tsab, process.cred, thread, sab));
|
|
14245
14401
|
};
|
|
14246
14402
|
worker.postMessage(
|
|
14247
14403
|
processInit(opts, sab, process.umask, copyCred(process.cred), lane?.lane),
|
|
@@ -14263,6 +14419,7 @@ function spawnWasmProcess(opts) {
|
|
|
14263
14419
|
onState: (listener) => process.onState(listener),
|
|
14264
14420
|
memory: () => Atomics.load(header3, SAB_I_MEMORY) * 65536,
|
|
14265
14421
|
ignoredSignals: (fork) => process.inheritable(fork),
|
|
14422
|
+
blockedSignals: () => opts.program.abi === "wasi" ? Atomics.load(header3, SAB_I_BLOCKED) : 0,
|
|
14266
14423
|
signalMasks: () => process.signalMasks(),
|
|
14267
14424
|
umask: () => process.umask,
|
|
14268
14425
|
cred: () => copyCred(process.cred),
|
|
@@ -15143,14 +15300,19 @@ var SealedChannel = class {
|
|
|
15143
15300
|
offset = 0;
|
|
15144
15301
|
inflight;
|
|
15145
15302
|
broker;
|
|
15146
|
-
|
|
15303
|
+
access;
|
|
15304
|
+
constructor(broker, access2) {
|
|
15147
15305
|
this.broker = broker;
|
|
15306
|
+
this.access = access2;
|
|
15148
15307
|
}
|
|
15149
15308
|
send(bytes, caller, gone) {
|
|
15309
|
+
if (this.access === "read") {
|
|
15310
|
+
bytes.fill(0);
|
|
15311
|
+
throw new KernelError("EBADF");
|
|
15312
|
+
}
|
|
15150
15313
|
const length2 = bytes.length;
|
|
15151
15314
|
const fields = parseSealed(bytes);
|
|
15152
|
-
this.
|
|
15153
|
-
this.offset = 0;
|
|
15315
|
+
this.drop();
|
|
15154
15316
|
this.inflight?.control.abort("replaced");
|
|
15155
15317
|
const control = new AbortController();
|
|
15156
15318
|
const withdraw = () => control.abort("withdrawn");
|
|
@@ -15186,15 +15348,18 @@ var SealedChannel = class {
|
|
|
15186
15348
|
if (!signal.aborted) return reply;
|
|
15187
15349
|
return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
|
|
15188
15350
|
}
|
|
15351
|
+
drop() {
|
|
15352
|
+
this.reply?.fill(0);
|
|
15353
|
+
this.reply = void 0;
|
|
15354
|
+
this.offset = 0;
|
|
15355
|
+
}
|
|
15189
15356
|
async read(max, signal) {
|
|
15357
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
15190
15358
|
for (; ; ) {
|
|
15191
15359
|
if (this.reply) {
|
|
15192
15360
|
const out = this.reply.slice(this.offset, this.offset + max);
|
|
15193
15361
|
this.offset += out.length;
|
|
15194
|
-
if (this.offset >= this.reply.length)
|
|
15195
|
-
this.reply = void 0;
|
|
15196
|
-
this.offset = 0;
|
|
15197
|
-
}
|
|
15362
|
+
if (this.offset >= this.reply.length) this.drop();
|
|
15198
15363
|
return out;
|
|
15199
15364
|
}
|
|
15200
15365
|
const flight = this.inflight;
|
|
@@ -15227,7 +15392,7 @@ var SealedChannel = class {
|
|
|
15227
15392
|
close() {
|
|
15228
15393
|
this.inflight?.control.abort("withdrawn");
|
|
15229
15394
|
this.inflight = void 0;
|
|
15230
|
-
this.
|
|
15395
|
+
this.drop();
|
|
15231
15396
|
}
|
|
15232
15397
|
};
|
|
15233
15398
|
function swapOf(reply) {
|
|
@@ -15284,12 +15449,14 @@ var SealedBroker = class {
|
|
|
15284
15449
|
control.abort("done");
|
|
15285
15450
|
}
|
|
15286
15451
|
}
|
|
15287
|
-
open() {
|
|
15288
|
-
const channel = new SealedChannel(this);
|
|
15452
|
+
open(access2 = "both") {
|
|
15453
|
+
const channel = new SealedChannel(this, access2);
|
|
15289
15454
|
return new OpenFile({
|
|
15290
|
-
read: (max, signal) => channel.read(max, signal),
|
|
15291
|
-
|
|
15292
|
-
|
|
15455
|
+
...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
|
|
15456
|
+
...access2 === "read" ? {} : {
|
|
15457
|
+
write: async () => {
|
|
15458
|
+
throw new KernelError("EINVAL");
|
|
15459
|
+
}
|
|
15293
15460
|
},
|
|
15294
15461
|
poll: () => channel.poll(),
|
|
15295
15462
|
changed: (signal) => channel.changed(signal),
|
|
@@ -16908,7 +17075,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
16908
17075
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
16909
17076
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
16910
17077
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
16911
|
-
var
|
|
17078
|
+
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
17079
|
+
var RULE = new RegExp(
|
|
17080
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
17081
|
+
);
|
|
16912
17082
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
16913
17083
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
16914
17084
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
@@ -16943,17 +17113,25 @@ function validWho(who) {
|
|
|
16943
17113
|
if (who === "ALL") return true;
|
|
16944
17114
|
return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
|
|
16945
17115
|
}
|
|
17116
|
+
function cwdOf(word) {
|
|
17117
|
+
const words2 = splitWords(word);
|
|
17118
|
+
const path = words2?.length === 1 ? words2[0] : "";
|
|
17119
|
+
return path.startsWith("/") ? normalizePath(path) : "";
|
|
17120
|
+
}
|
|
16946
17121
|
function parseRule(line) {
|
|
16947
17122
|
const text = line.trim();
|
|
16948
17123
|
if (text === "" || text.startsWith("#")) return null;
|
|
16949
17124
|
const m = RULE.exec(text);
|
|
16950
17125
|
if (!m) return void 0;
|
|
16951
|
-
const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
|
|
17126
|
+
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
16952
17127
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
16953
|
-
|
|
17128
|
+
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
17129
|
+
if (cwd === "") return void 0;
|
|
17130
|
+
const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
|
|
17131
|
+
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
16954
17132
|
const cmnd = splitWords(rest2);
|
|
16955
17133
|
if (!cmnd?.[0]?.startsWith("/")) return void 0;
|
|
16956
|
-
return {
|
|
17134
|
+
return { ...rule, cmnd };
|
|
16957
17135
|
}
|
|
16958
17136
|
function flags(parsed2, arg, next2) {
|
|
16959
17137
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -16992,7 +17170,8 @@ function parseArgs(args) {
|
|
|
16992
17170
|
}
|
|
16993
17171
|
function described(rule) {
|
|
16994
17172
|
const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
|
|
16995
|
-
|
|
17173
|
+
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
17174
|
+
return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
16996
17175
|
}
|
|
16997
17176
|
var Sudo = class {
|
|
16998
17177
|
o;
|
|
@@ -17132,7 +17311,7 @@ var Sudo = class {
|
|
|
17132
17311
|
if (untrusted) return untrusted;
|
|
17133
17312
|
const argv = [path, ...args];
|
|
17134
17313
|
const matching = rules.filter(
|
|
17135
|
-
(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]))
|
|
17314
|
+
(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]))
|
|
17136
17315
|
);
|
|
17137
17316
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
17138
17317
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -17154,7 +17333,7 @@ var Sudo = class {
|
|
|
17154
17333
|
}
|
|
17155
17334
|
const changed = await this.untrusted(path, cwd, word);
|
|
17156
17335
|
if (changed) return changed;
|
|
17157
|
-
if (answer === "always" && !await this.remember(self, target, argv)) {
|
|
17336
|
+
if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
17158
17337
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
17159
17338
|
}
|
|
17160
17339
|
return grant();
|
|
@@ -17219,7 +17398,7 @@ ${lines2}
|
|
|
17219
17398
|
requester.removeEventListener("abort", withdraw);
|
|
17220
17399
|
}
|
|
17221
17400
|
}
|
|
17222
|
-
async remember(self, target, argv) {
|
|
17401
|
+
async remember(self, target, cwd, argv) {
|
|
17223
17402
|
const { fs } = this.o;
|
|
17224
17403
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
17225
17404
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -17229,7 +17408,8 @@ ${lines2}
|
|
|
17229
17408
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
17230
17409
|
if (st && !await this.trusted(path)) return false;
|
|
17231
17410
|
const old = st ? await fs.readFile(path) : "";
|
|
17232
|
-
const
|
|
17411
|
+
const words2 = argv.map(quoteWord).join(" ");
|
|
17412
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
17233
17413
|
`;
|
|
17234
17414
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
17235
17415
|
${line}`;
|
|
@@ -17362,15 +17542,25 @@ function shebang(head) {
|
|
|
17362
17542
|
if (head[0] !== 35 || head[1] !== 33) return void 0;
|
|
17363
17543
|
return new TextDecoder().decode(head.subarray(0, SHEBANG_MAX)).slice(2).split("\n")[0].trim().split(/[ \t]+/);
|
|
17364
17544
|
}
|
|
17365
|
-
async function rootOnly(fs, path) {
|
|
17545
|
+
async function rootOnly(fs, path, dir = false) {
|
|
17366
17546
|
const names = chain(path);
|
|
17367
17547
|
for (const [i, at] of names.entries()) {
|
|
17368
17548
|
const st = await fs.lstat(at).catch(() => void 0);
|
|
17369
|
-
const kind = i === names.length - 1 ? st?.isFile : st?.isDirectory;
|
|
17549
|
+
const kind = i === names.length - 1 && !dir ? st?.isFile : st?.isDirectory;
|
|
17370
17550
|
if (!kind || st?.uid !== 0 || (st.mode & 18) !== 0) return false;
|
|
17371
17551
|
}
|
|
17372
17552
|
return true;
|
|
17373
17553
|
}
|
|
17554
|
+
function appendedRoots(given) {
|
|
17555
|
+
const roots = given?.append ?? [];
|
|
17556
|
+
if (!Array.isArray(roots)) throw new TypeError("commands.append must be an array of paths");
|
|
17557
|
+
for (const root of roots) {
|
|
17558
|
+
if (typeof root !== "string" || !root.startsWith("/") || normalizePath(root) !== root) {
|
|
17559
|
+
throw new TypeError(`commands.append: not an absolute, normalised path: ${String(root)}`);
|
|
17560
|
+
}
|
|
17561
|
+
}
|
|
17562
|
+
return [...roots];
|
|
17563
|
+
}
|
|
17374
17564
|
function plainEnv(words2) {
|
|
17375
17565
|
const next2 = words2[1];
|
|
17376
17566
|
if (baseName(words2[0] ?? "") !== "env" || next2 === void 0) return false;
|
|
@@ -17463,6 +17653,8 @@ var Launcher = class {
|
|
|
17463
17653
|
base;
|
|
17464
17654
|
createWorker;
|
|
17465
17655
|
modulesDir;
|
|
17656
|
+
appended;
|
|
17657
|
+
reportedRoots = /* @__PURE__ */ new Set();
|
|
17466
17658
|
env;
|
|
17467
17659
|
catalogs = /* @__PURE__ */ new Map();
|
|
17468
17660
|
ownCatalogs = /* @__PURE__ */ new Map();
|
|
@@ -17569,6 +17761,7 @@ var Launcher = class {
|
|
|
17569
17761
|
this.processMounts = options.processMounts ?? true;
|
|
17570
17762
|
this.pnpmHome = options.env?.PNPM_HOME ?? SYSTEM_PNPM_HOME;
|
|
17571
17763
|
this.modulesDir = options.modules ?? "/node_modules";
|
|
17764
|
+
this.appended = appendedRoots(options.commands);
|
|
17572
17765
|
this.cdp = new CdpHosts(options.cdp);
|
|
17573
17766
|
const hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
17574
17767
|
if (!isHostname(hostname)) throw new Error(`not a host name: ${String(hostname)}`);
|
|
@@ -17618,9 +17811,9 @@ var Launcher = class {
|
|
|
17618
17811
|
this.unguardedRoot = options.fs.unguarded?.() ?? options.fs;
|
|
17619
17812
|
this.prefixes = protectedPrefixes(options.protect?.paths ?? []);
|
|
17620
17813
|
this.processFs = this.prefixes.length > 0 ? new ProtectedFs(this.prefixes).view(this.fs) : this.fs;
|
|
17621
|
-
options.fs.protect?.(this.prefixes);
|
|
17622
17814
|
const integrity = options.protect?.integrity;
|
|
17623
17815
|
integrityOptions(integrity);
|
|
17816
|
+
options.fs.protect?.(this.prefixes, Boolean(integrity));
|
|
17624
17817
|
if (integrity && this.prefixes.length > 0) {
|
|
17625
17818
|
this.integrity = new Integrity(
|
|
17626
17819
|
this.prefixes,
|
|
@@ -17643,7 +17836,7 @@ var Launcher = class {
|
|
|
17643
17836
|
});
|
|
17644
17837
|
void this.unlinked.sweep("/");
|
|
17645
17838
|
this.watchers.watch(
|
|
17646
|
-
[this.modulesDir, this.pnpmHome],
|
|
17839
|
+
[this.modulesDir, this.pnpmHome, ...this.appended],
|
|
17647
17840
|
{ recursive: true },
|
|
17648
17841
|
() => this.resetCatalogs()
|
|
17649
17842
|
);
|
|
@@ -17674,7 +17867,10 @@ var Launcher = class {
|
|
|
17674
17867
|
commands(scope = "") {
|
|
17675
17868
|
let found = this.catalogs.get(scope);
|
|
17676
17869
|
if (!found) {
|
|
17677
|
-
found = this.
|
|
17870
|
+
found = this.trustedAppended().then(async (appended) => {
|
|
17871
|
+
const roots = await this.roots(scope, appended);
|
|
17872
|
+
return scanCommands(this.scanned, roots, roots.length - appended.length);
|
|
17873
|
+
}).then((commands) => commands.set(SUDO_COMMAND.name, SUDO_COMMAND));
|
|
17678
17874
|
this.catalogs.set(scope, found);
|
|
17679
17875
|
}
|
|
17680
17876
|
return found;
|
|
@@ -17701,10 +17897,37 @@ var Launcher = class {
|
|
|
17701
17897
|
}
|
|
17702
17898
|
return found;
|
|
17703
17899
|
}
|
|
17704
|
-
async roots(scope = "") {
|
|
17705
|
-
const system = [
|
|
17900
|
+
async roots(scope = "", appended) {
|
|
17901
|
+
const system = [
|
|
17902
|
+
this.modulesDir,
|
|
17903
|
+
...await pnpmGlobalRoots(this.base, this.pnpmHome),
|
|
17904
|
+
...appended ?? await this.trustedAppended()
|
|
17905
|
+
];
|
|
17706
17906
|
return scope ? [...await pnpmGlobalRoots(this.base, scope), ...system] : system;
|
|
17707
17907
|
}
|
|
17908
|
+
async rootOnlyPath(root) {
|
|
17909
|
+
for (const at of chain(root)) {
|
|
17910
|
+
const real = await physicalPathAsync(this.base, at);
|
|
17911
|
+
if (!await rootOnly(this.base, real, true)) return false;
|
|
17912
|
+
}
|
|
17913
|
+
return true;
|
|
17914
|
+
}
|
|
17915
|
+
async trustedAppended() {
|
|
17916
|
+
if (this.appended.length === 0 || this.usersMode === "off") return this.appended;
|
|
17917
|
+
const trusted = [];
|
|
17918
|
+
for (const root of this.appended) {
|
|
17919
|
+
const real = await physicalPathAsync(this.base, root);
|
|
17920
|
+
if (await this.rootOnlyPath(root)) trusted.push(root);
|
|
17921
|
+
else if (this.usersMode === "report" && await this.base.exists(real)) {
|
|
17922
|
+
if (!this.reportedRoots.has(root)) {
|
|
17923
|
+
this.reportedRoots.add(root);
|
|
17924
|
+
this.dac?.denied({ pid: 0, uid: 0, op: "commands", path: root, errno: "EACCES" });
|
|
17925
|
+
}
|
|
17926
|
+
trusted.push(root);
|
|
17927
|
+
}
|
|
17928
|
+
}
|
|
17929
|
+
return trusted;
|
|
17930
|
+
}
|
|
17708
17931
|
resetCatalogs() {
|
|
17709
17932
|
this.catalogs.clear();
|
|
17710
17933
|
this.ownCatalogs.clear();
|
|
@@ -17810,14 +18033,22 @@ var Launcher = class {
|
|
|
17810
18033
|
const inner = await this.interpreted(interp, [interp, ...passed], cwd, scope, depth + 1);
|
|
17811
18034
|
const via = [interp, ...inner?.via ?? []];
|
|
17812
18035
|
const sources = [script, ...inner?.sources ?? []];
|
|
17813
|
-
|
|
18036
|
+
const bins = [...command?.bin ? [script] : [], ...inner?.bins ?? []];
|
|
18037
|
+
return inner && {
|
|
18038
|
+
...inner,
|
|
18039
|
+
target: withScriptEnv(inner.target, command),
|
|
18040
|
+
via,
|
|
18041
|
+
sources,
|
|
18042
|
+
...bins.length > 0 ? { bins } : {}
|
|
18043
|
+
};
|
|
17814
18044
|
}
|
|
17815
18045
|
const target = withScriptEnv(found, command);
|
|
17816
18046
|
return {
|
|
17817
18047
|
target,
|
|
17818
18048
|
args: [...target.prefix ?? [], ...passed],
|
|
17819
18049
|
via: [interp],
|
|
17820
|
-
sources: [script]
|
|
18050
|
+
sources: [script],
|
|
18051
|
+
...command?.bin ? { bins: [script] } : {}
|
|
17821
18052
|
};
|
|
17822
18053
|
}
|
|
17823
18054
|
async plan(file, argv, cwd, scope, argv0) {
|
|
@@ -17843,6 +18074,7 @@ var Launcher = class {
|
|
|
17843
18074
|
const want = i < via.length - 1 ? R_OK | X_OK : X_OK;
|
|
17844
18075
|
await need(g, "exec", this.fs.resolvePath(req.cwd, file), want);
|
|
17845
18076
|
}
|
|
18077
|
+
for (const bin of planned?.bins ?? []) await need(g, "exec", bin, R_OK | X_OK);
|
|
17846
18078
|
}
|
|
17847
18079
|
async checkedPlan(req, { ppid, cred, scope }, fds) {
|
|
17848
18080
|
const planned = await this.plan(req.file, req.argv, req.cwd, scope, req.argv0);
|
|
@@ -18141,6 +18373,7 @@ var Launcher = class {
|
|
|
18141
18373
|
},
|
|
18142
18374
|
settling: () => this.settling.isSettling(pid),
|
|
18143
18375
|
...req.ignored ? { ignored: req.ignored } : {},
|
|
18376
|
+
...req.blocked ? { blocked: req.blocked } : {},
|
|
18144
18377
|
...req.umask !== void 0 ? { umask: req.umask } : {},
|
|
18145
18378
|
cred: req.cred,
|
|
18146
18379
|
...this.owners && req.program.abi === "wasi" ? { fresh: (path, umask) => this.freshModules.add(path, umask, pid) } : {},
|
|
@@ -18415,6 +18648,7 @@ var Launcher = class {
|
|
|
18415
18648
|
report,
|
|
18416
18649
|
ppid,
|
|
18417
18650
|
ignored: this.ignoredBy(ppid),
|
|
18651
|
+
blocked: this.blockedBy(ppid),
|
|
18418
18652
|
umask: this.umaskOf(ppid),
|
|
18419
18653
|
cred,
|
|
18420
18654
|
tag: this.tagOf(ppid),
|
|
@@ -18476,6 +18710,7 @@ var Launcher = class {
|
|
|
18476
18710
|
ppid,
|
|
18477
18711
|
fork: state,
|
|
18478
18712
|
ignored: this.ignoredBy(ppid, true),
|
|
18713
|
+
blocked: this.blockedBy(ppid),
|
|
18479
18714
|
umask: this.umaskOf(ppid),
|
|
18480
18715
|
cred: this.credOf(ppid),
|
|
18481
18716
|
tag: this.tagOf(ppid)
|
|
@@ -18527,11 +18762,16 @@ var Launcher = class {
|
|
|
18527
18762
|
}
|
|
18528
18763
|
signalMasksOf(pid) {
|
|
18529
18764
|
const masks = this.processes.get(pid)?.signalMasks?.();
|
|
18530
|
-
|
|
18765
|
+
const blocked = this.blockedBy(pid);
|
|
18766
|
+
const sigBlk = blocked ? { sigBlk: blocked } : {};
|
|
18767
|
+
return masks ? { sigIgn: masks.ignored, sigCgt: masks.caught, ...sigBlk } : sigBlk;
|
|
18531
18768
|
}
|
|
18532
18769
|
controlsJobs(pid) {
|
|
18533
18770
|
return this.settling.isSettling(pid) || (this.ignoredBy(pid) & sigbit(SIG.TTOU)) !== 0;
|
|
18534
18771
|
}
|
|
18772
|
+
blockedBy(pid) {
|
|
18773
|
+
return this.processes.get(pid)?.blockedSignals?.() ?? 0;
|
|
18774
|
+
}
|
|
18535
18775
|
ignoredBy(pid, fork = false) {
|
|
18536
18776
|
return this.processes.get(pid)?.ignoredSignals(fork) ?? 0;
|
|
18537
18777
|
}
|
|
@@ -18896,7 +19136,7 @@ var Launcher = class {
|
|
|
18896
19136
|
(dir) => this.userCommandDir(dir),
|
|
18897
19137
|
this.owners
|
|
18898
19138
|
);
|
|
18899
|
-
const nodes = new VfsNodes(fs, (path) => this.released(path));
|
|
19139
|
+
const nodes = new VfsNodes(fs, (path) => this.released(path), this.nodes.entries);
|
|
18900
19140
|
nodes.keepsOnDisk = true;
|
|
18901
19141
|
this.openFiles.add(nodes);
|
|
18902
19142
|
const unlinked = new UnlinkedKeeper(
|
|
@@ -19300,6 +19540,7 @@ function serveKernel(port, deps) {
|
|
|
19300
19540
|
createWorker: deps.createWorker,
|
|
19301
19541
|
...deps.createDriverWorker ? { createDriverWorker: deps.createDriverWorker } : {},
|
|
19302
19542
|
...req.modules ? { modules: req.modules } : {},
|
|
19543
|
+
...req.commands ? { commands: req.commands } : {},
|
|
19303
19544
|
...req.env ? { env: req.env } : {},
|
|
19304
19545
|
...hostOptions(req, port, sealed.hook, clipboard.hook, integrity.lookup),
|
|
19305
19546
|
...req.approve ? { approve: approvals.ask } : {},
|