@ai-ecoverse/slicc-kernel 1.167.3 → 1.168.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 +10 -2
- package/dist/index.js.map +1 -1
- package/dist/kernel-worker.js +218 -87
- package/dist/kernel-worker.js.map +4 -4
- package/dist/meta.js +61 -2
- package/dist/meta.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.cjs.map +2 -2
- package/dist/node-process-worker.js +1 -1
- package/dist/node-process-worker.js.map +2 -2
- package/dist/node.js +372 -241
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/process-worker.js.map +2 -2
- package/dist/types/fs/dac.d.ts +1 -1
- package/dist/types/fs/opfs.d.ts +1 -0
- package/dist/types/fs/remote.d.ts +1 -0
- package/dist/types/fs/types.d.ts +2 -0
- package/dist/types/kernel/replacing.d.ts +17 -0
- package/dist/types/launcher.d.ts +7 -0
- package/dist/types/meta.d.ts +4 -0
- package/package.json +3 -3
package/dist/kernel-worker.js
CHANGED
|
@@ -1753,9 +1753,11 @@ var OpfsFs = class {
|
|
|
1753
1753
|
this.channel.onmessage = ({ data }) => {
|
|
1754
1754
|
const { paths, trees, outside } = noticeOf(data);
|
|
1755
1755
|
for (const path of [...paths, ...trees]) this.forget(normalizePath(path));
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1756
|
+
if (!outside) remote?.emit({ paths, trees });
|
|
1757
|
+
else
|
|
1758
|
+
void this.noticed(paths.map(normalizePath), Date.now()).finally(
|
|
1759
|
+
() => remote?.emit({ paths, trees, outside: true })
|
|
1760
|
+
);
|
|
1759
1761
|
};
|
|
1760
1762
|
this.channel.unref?.();
|
|
1761
1763
|
}
|
|
@@ -2121,6 +2123,9 @@ var OpfsFs = class {
|
|
|
2121
2123
|
this.exact--;
|
|
2122
2124
|
}
|
|
2123
2125
|
}
|
|
2126
|
+
refresh(trees) {
|
|
2127
|
+
for (const tree2 of trees) this.forget(normalizePath(tree2));
|
|
2128
|
+
}
|
|
2124
2129
|
forget(path) {
|
|
2125
2130
|
this.changes++;
|
|
2126
2131
|
this.dirs.deleteTree(path);
|
|
@@ -2838,6 +2843,10 @@ var OpfsFs = class {
|
|
|
2838
2843
|
const children3 = /* @__PURE__ */ new Map();
|
|
2839
2844
|
this.others++;
|
|
2840
2845
|
for await (const child of handle.values()) children3.set(child.name, child);
|
|
2846
|
+
if (this.absent.size > 0) {
|
|
2847
|
+
const base = found.path === "/" ? "" : found.path;
|
|
2848
|
+
for (const name2 of children3.keys()) this.absent.delete(`${base}/${name2}`);
|
|
2849
|
+
}
|
|
2841
2850
|
for (const link2 of await this.meta.links(found.path)) {
|
|
2842
2851
|
const name2 = baseOf(link2.path);
|
|
2843
2852
|
if (!children3.has(name2)) children3.set(name2, link2);
|
|
@@ -5271,28 +5280,39 @@ async function stickyEntry(g, op, path, dir) {
|
|
|
5271
5280
|
if (sticky(g.cred, perm, (await ancestryOf(g.fs, entry)).at(-1))) return;
|
|
5272
5281
|
if (await present(g.fs, entry, false)) deny(g, op, path, "EPERM");
|
|
5273
5282
|
}
|
|
5283
|
+
async function unwritable(g, op, path, dir) {
|
|
5284
|
+
if (dir.denied === void 0) return false;
|
|
5285
|
+
if (dir.link) {
|
|
5286
|
+
deny(g, op, dir.denied);
|
|
5287
|
+
return false;
|
|
5288
|
+
}
|
|
5289
|
+
const perm = dir.denied === dir.path ? dir.perm : void 0;
|
|
5290
|
+
if (perm && !await present(g.fs, dir.path, true)) return false;
|
|
5291
|
+
if (perm && permits(g.cred, perm, X_OK)) return true;
|
|
5292
|
+
deny(g, op, path);
|
|
5293
|
+
return false;
|
|
5294
|
+
}
|
|
5274
5295
|
async function inParent(g, op, path, old = false) {
|
|
5275
5296
|
await fence(g, op, path);
|
|
5276
|
-
if (old === "replaced") {
|
|
5277
|
-
const dir2 = await need(g, op, parentOf4(path), W_OK | X_OK, DIR, path);
|
|
5278
|
-
return dir2.denied === void 0 ? stickyEntry(g, op, path, dir2) : void 0;
|
|
5279
|
-
}
|
|
5280
|
-
if (!old) return void await need(g, op, parentOf4(path), W_OK | X_OK, DIR, path);
|
|
5281
5297
|
const dir = await access(g.fs, g.cred, parentOf4(path), W_OK | X_OK, linked(g, DIR));
|
|
5298
|
+
if (old !== true) {
|
|
5299
|
+
if (await unwritable(g, op, path, dir)) deny(g, op, path);
|
|
5300
|
+
else if (old === "replaced" && dir.denied === void 0) await stickyEntry(g, op, path, dir);
|
|
5301
|
+
return;
|
|
5302
|
+
}
|
|
5282
5303
|
if (dir.denied === void 0) return stickyEntry(g, op, path, dir);
|
|
5283
5304
|
if (dir.link) return deny(g, op, dir.denied);
|
|
5284
5305
|
const lookup2 = dir.denied === dir.path && dir.perm && permits(g.cred, dir.perm, X_OK);
|
|
5285
5306
|
if (!lookup2 || await present(g.fs, entryIn(dir, path), false)) deny(g, op, path);
|
|
5286
5307
|
}
|
|
5287
|
-
async function makeIn(g, op, path) {
|
|
5308
|
+
async function makeIn(g, op, path, parents = true) {
|
|
5288
5309
|
for (let dir = parentOf4(path); ; dir = parentOf4(dir)) {
|
|
5289
5310
|
const walked = await access(g.fs, g.cred, dir, W_OK | X_OK, linked(g, DIR));
|
|
5290
|
-
if (
|
|
5291
|
-
if (walked.denied !== void 0) {
|
|
5311
|
+
if (await unwritable(g, op, path, walked)) {
|
|
5292
5312
|
if (!await present(g.fs, path, true)) deny(g, op, path);
|
|
5293
5313
|
return;
|
|
5294
5314
|
}
|
|
5295
|
-
if (!walked.missing || dir === "/") return;
|
|
5315
|
+
if (!parents || !walked.missing || dir === "/") return;
|
|
5296
5316
|
}
|
|
5297
5317
|
}
|
|
5298
5318
|
async function tree(g, op, dir, perm) {
|
|
@@ -7583,14 +7603,14 @@ var UserDb = class {
|
|
|
7583
7603
|
this.fs = fs;
|
|
7584
7604
|
this.owners = owners;
|
|
7585
7605
|
}
|
|
7586
|
-
async stampHome(row,
|
|
7606
|
+
async stampHome(row, shared2, homeMode) {
|
|
7587
7607
|
const home = this.fs.resolvePath("/", row.home);
|
|
7588
7608
|
if (!this.owners || !this.fs.chown || !HOME_DIR.test(home)) return;
|
|
7589
7609
|
if (!await this.realDir(home)) return;
|
|
7590
|
-
const gid =
|
|
7610
|
+
const gid = shared2?.gid ?? row.gid;
|
|
7591
7611
|
await this.fs.chown(home, { uid: row.uid, gid, follow: false, kind: "adopt" });
|
|
7592
7612
|
const scoop = row.name.startsWith("scoop-");
|
|
7593
|
-
await this.fs.chmod(home, homeMode ?? (
|
|
7613
|
+
await this.fs.chmod(home, homeMode ?? (shared2 ? 1512 : scoop ? 488 : 448));
|
|
7594
7614
|
const pnpm = `${home}/.local/share/pnpm`;
|
|
7595
7615
|
if (await this.realDir(pnpm)) await this.fs.chmod(pnpm, scoop ? 488 : 448);
|
|
7596
7616
|
}
|
|
@@ -7627,9 +7647,9 @@ var UserDb = class {
|
|
|
7627
7647
|
const [passwd, group] = await this.texts();
|
|
7628
7648
|
return { passwd: parsePasswd(passwd), group: parseGroup(group) };
|
|
7629
7649
|
}
|
|
7630
|
-
async provision(row, umask,
|
|
7631
|
-
const dirs = 511 & ~umask | (
|
|
7632
|
-
const gid =
|
|
7650
|
+
async provision(row, umask, shared2) {
|
|
7651
|
+
const dirs = 511 & ~umask | (shared2 ? 1024 : 0);
|
|
7652
|
+
const gid = shared2?.gid ?? row.gid;
|
|
7633
7653
|
const owner = this.owners ? { uid: row.uid, gid } : void 0;
|
|
7634
7654
|
const made2 = owner ? { recursive: true, owner: { ...owner, mode: dirs, parents: dirs } } : { recursive: true };
|
|
7635
7655
|
const pnpm = `${row.home}/.local/share/pnpm`;
|
|
@@ -7733,7 +7753,7 @@ var UserDb = class {
|
|
|
7733
7753
|
const users = parsed(passwd);
|
|
7734
7754
|
const groups = parsed(group);
|
|
7735
7755
|
const found = users.find((r) => r.name === name2);
|
|
7736
|
-
const
|
|
7756
|
+
const shared2 = homeGroupOf(groups, options.homeGroup);
|
|
7737
7757
|
const homeMode = homeModeOf(options.homeMode);
|
|
7738
7758
|
if (found) {
|
|
7739
7759
|
const more = groupsOf(groups, options.groups ?? []);
|
|
@@ -7741,8 +7761,8 @@ var UserDb = class {
|
|
|
7741
7761
|
throw fsError("EINVAL", `a user is no member of its own group ${name2}`);
|
|
7742
7762
|
}
|
|
7743
7763
|
if (found.uid >= FIRST_UID && found.uid <= LAST_UID) {
|
|
7744
|
-
await this.provision(found, this.umaskFor(options),
|
|
7745
|
-
await this.stampHome(found,
|
|
7764
|
+
await this.provision(found, this.umaskFor(options), shared2);
|
|
7765
|
+
await this.stampHome(found, shared2, homeMode);
|
|
7746
7766
|
}
|
|
7747
7767
|
if (joined(name2, more)) await this.fs.writeFile(GROUP, formatGroup(group));
|
|
7748
7768
|
remember();
|
|
@@ -7759,8 +7779,8 @@ var UserDb = class {
|
|
|
7759
7779
|
const fresh3 = !await this.fs.exists(home);
|
|
7760
7780
|
await this.fs.mkdir(home, { recursive: true });
|
|
7761
7781
|
try {
|
|
7762
|
-
await this.provision(row, this.umaskFor(options),
|
|
7763
|
-
await this.stampHome(row,
|
|
7782
|
+
await this.provision(row, this.umaskFor(options), shared2);
|
|
7783
|
+
await this.stampHome(row, shared2, homeMode);
|
|
7764
7784
|
await this.fs.mkdir("/etc", { recursive: true });
|
|
7765
7785
|
await this.commit(formatPasswd(passwd), formatGroup(group));
|
|
7766
7786
|
} catch (err) {
|
|
@@ -7809,10 +7829,10 @@ var UserDb = class {
|
|
|
7809
7829
|
);
|
|
7810
7830
|
for (const r of parsed(keptGroups)) r.members = r.members.filter((m) => m !== name2);
|
|
7811
7831
|
const home = this.fs.resolvePath("/", row.home);
|
|
7812
|
-
const
|
|
7832
|
+
const shared2 = parsed(passwd).some(
|
|
7813
7833
|
(r) => r !== row && this.fs.resolvePath("/", r.home) === home
|
|
7814
7834
|
);
|
|
7815
|
-
const removeHome = !options.keepHome && !
|
|
7835
|
+
const removeHome = !options.keepHome && !shared2 && HOME_DIR.test(home) && await this.fs.exists(home);
|
|
7816
7836
|
const staged = `/home/.${name2}.removed-${Date.now()}`;
|
|
7817
7837
|
await this.commit(
|
|
7818
7838
|
formatPasswd(passwd.filter((r) => r !== row)),
|
|
@@ -8477,7 +8497,7 @@ function satisfies(version, range2) {
|
|
|
8477
8497
|
}
|
|
8478
8498
|
|
|
8479
8499
|
// src/version.ts
|
|
8480
|
-
var KERNEL_VERSION = true ? "1.
|
|
8500
|
+
var KERNEL_VERSION = true ? "1.168.0" : "0.0.0-dev";
|
|
8481
8501
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8482
8502
|
function procVersion() {
|
|
8483
8503
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -8560,8 +8580,8 @@ function abiOf(raw2, fallback) {
|
|
|
8560
8580
|
const abi = raw2 ?? fallback;
|
|
8561
8581
|
return abi === "emscripten" || abi === "wasi" || abi === "js" ? abi : void 0;
|
|
8562
8582
|
}
|
|
8563
|
-
function commandOf(pkg, name2, raw2, packageAbi,
|
|
8564
|
-
const withEnv = envFields({ ...
|
|
8583
|
+
function commandOf(pkg, name2, raw2, packageAbi, shared2) {
|
|
8584
|
+
const withEnv = envFields({ ...shared2, ...envOf(pkg, raw2.env) });
|
|
8565
8585
|
const script = inside(pkg, raw2.script);
|
|
8566
8586
|
if (script) {
|
|
8567
8587
|
return { name: name2, abi: packageAbi, glue: script, wasm: script, argv0: name2, script, ...withEnv };
|
|
@@ -8611,13 +8631,13 @@ function commandsOf(pkg, manifest) {
|
|
|
8611
8631
|
const packageAbi = abiOf(slicc.abi, "emscripten");
|
|
8612
8632
|
const entries = slicc.commands;
|
|
8613
8633
|
if (!packageAbi || !entries || typeof entries !== "object") return [];
|
|
8614
|
-
const
|
|
8634
|
+
const shared2 = envOf(pkg, slicc.env);
|
|
8615
8635
|
const out = [];
|
|
8616
8636
|
for (const [name2, raw2] of Object.entries(entries)) {
|
|
8617
8637
|
if (!commandName(name2) || !raw2 || typeof raw2 !== "object") {
|
|
8618
8638
|
continue;
|
|
8619
8639
|
}
|
|
8620
|
-
const command = commandOf(pkg, name2, raw2, packageAbi,
|
|
8640
|
+
const command = commandOf(pkg, name2, raw2, packageAbi, shared2);
|
|
8621
8641
|
if (command) out.push(command);
|
|
8622
8642
|
}
|
|
8623
8643
|
return out;
|
|
@@ -9778,8 +9798,8 @@ var UnlinkedKeeper = class {
|
|
|
9778
9798
|
void peers.ask(tab, { kept: { items: [], paths } }, PEER_RM_MS);
|
|
9779
9799
|
throw fsError("EBUSY", `${target}: open in another tab that did not answer`);
|
|
9780
9800
|
}
|
|
9781
|
-
const { whole, sends, shared } = await this.setAside(target, asked);
|
|
9782
|
-
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard,
|
|
9801
|
+
const { whole, sends, shared: shared2 } = await this.setAside(target, asked);
|
|
9802
|
+
return { whole, undoing: (op) => this.undoing(op, peers, sends, heard, shared2) };
|
|
9783
9803
|
}
|
|
9784
9804
|
async setAside(target, asked) {
|
|
9785
9805
|
const mine = this.heldWithin(target);
|
|
@@ -9787,25 +9807,25 @@ var UnlinkedKeeper = class {
|
|
|
9787
9807
|
for (const { holders } of asked)
|
|
9788
9808
|
for (const { path } of holders) tabsOf.set(path, (tabsOf.get(path) ?? 0) + 1);
|
|
9789
9809
|
const done5 = /* @__PURE__ */ new Map();
|
|
9790
|
-
const
|
|
9810
|
+
const shared2 = [];
|
|
9791
9811
|
const sends = [];
|
|
9792
9812
|
for (const { tab, holders, paths } of asked) {
|
|
9793
9813
|
const items = [];
|
|
9794
9814
|
for (const holder of holders) {
|
|
9795
9815
|
if (!done5.has(holder.path)) {
|
|
9796
9816
|
const many = mine.has(holder.path) || (tabsOf.get(holder.path) ?? 0) > 1;
|
|
9797
|
-
done5.set(holder.path, await this.asideOne(holder, many, mine,
|
|
9817
|
+
done5.set(holder.path, await this.asideOne(holder, many, mine, shared2));
|
|
9798
9818
|
}
|
|
9799
9819
|
items.push({ path: holder.path, hidden: done5.get(holder.path), fid: holder.fid });
|
|
9800
9820
|
}
|
|
9801
9821
|
sends.push({ tab, items, paths });
|
|
9802
9822
|
}
|
|
9803
|
-
return { whole: done5.get(target) !== void 0, sends, shared };
|
|
9823
|
+
return { whole: done5.get(target) !== void 0, sends, shared: shared2 };
|
|
9804
9824
|
}
|
|
9805
|
-
async asideOne(holder, many, mine,
|
|
9825
|
+
async asideOne(holder, many, mine, shared2) {
|
|
9806
9826
|
if (!many) return this.asideFor(holder.path, holder.instance);
|
|
9807
9827
|
const one = await this.sharedAside(holder.path, mine);
|
|
9808
|
-
if (one)
|
|
9828
|
+
if (one) shared2.push(one);
|
|
9809
9829
|
return one?.hidden;
|
|
9810
9830
|
}
|
|
9811
9831
|
async sharedAside(path, mine) {
|
|
@@ -9850,16 +9870,16 @@ var UnlinkedKeeper = class {
|
|
|
9850
9870
|
sharedLocks() {
|
|
9851
9871
|
return this.locks;
|
|
9852
9872
|
}
|
|
9853
|
-
async undoing(op, peers, sends, heard,
|
|
9873
|
+
async undoing(op, peers, sends, heard, shared2 = []) {
|
|
9854
9874
|
let failed3;
|
|
9855
9875
|
let out;
|
|
9856
9876
|
try {
|
|
9857
9877
|
out = await op();
|
|
9858
9878
|
} catch (err) {
|
|
9859
9879
|
failed3 = err ?? new Error("failed");
|
|
9860
|
-
await this.rollBackAsides(sends,
|
|
9880
|
+
await this.rollBackAsides(sends, shared2);
|
|
9861
9881
|
}
|
|
9862
|
-
const hiddenShared = new Set(
|
|
9882
|
+
const hiddenShared = new Set(shared2.map((one) => one.hidden));
|
|
9863
9883
|
const answers2 = sends.map(({ tab, items, paths }) => {
|
|
9864
9884
|
const keeps = items.some((item) => item.hidden && hiddenShared.has(item.hidden));
|
|
9865
9885
|
return {
|
|
@@ -9870,7 +9890,7 @@ var UnlinkedKeeper = class {
|
|
|
9870
9890
|
await Promise.all(
|
|
9871
9891
|
answers2.map(({ told }, i) => heard[i] ? Promise.race([told, delay(PEER_RM_MS)]) : void 0)
|
|
9872
9892
|
);
|
|
9873
|
-
for (const one of
|
|
9893
|
+
for (const one of shared2) {
|
|
9874
9894
|
const waits = answers2.filter(
|
|
9875
9895
|
({ keeps }, i) => keeps && sends[i]?.items.some((item) => item.hidden === one.hidden)
|
|
9876
9896
|
);
|
|
@@ -9880,7 +9900,7 @@ var UnlinkedKeeper = class {
|
|
|
9880
9900
|
if (failed3 !== void 0) throw failed3;
|
|
9881
9901
|
return out;
|
|
9882
9902
|
}
|
|
9883
|
-
async rollBackAsides(sends,
|
|
9903
|
+
async rollBackAsides(sends, shared2) {
|
|
9884
9904
|
const back = /* @__PURE__ */ new Map();
|
|
9885
9905
|
for (const item of sends.flatMap((send2) => send2.items)) {
|
|
9886
9906
|
const { hidden, path } = item;
|
|
@@ -9888,7 +9908,7 @@ var UnlinkedKeeper = class {
|
|
|
9888
9908
|
if (!back.has(hidden)) back.set(hidden, await this.moveBack(hidden, path));
|
|
9889
9909
|
if (back.get(hidden)) item.hidden = void 0;
|
|
9890
9910
|
}
|
|
9891
|
-
for (const { hidden, path, local: local2, file } of
|
|
9911
|
+
for (const { hidden, path, local: local2, file } of shared2) {
|
|
9892
9912
|
if (!back.get(hidden) || !file) continue;
|
|
9893
9913
|
for (const holder of local2) {
|
|
9894
9914
|
holder.unkeep(path, file);
|
|
@@ -13129,8 +13149,8 @@ var CwdTable = class {
|
|
|
13129
13149
|
this.inodeOf = inodeOf2;
|
|
13130
13150
|
}
|
|
13131
13151
|
async hold(path, from) {
|
|
13132
|
-
const
|
|
13133
|
-
if (
|
|
13152
|
+
const shared2 = from === void 0 ? void 0 : this.held.get(from);
|
|
13153
|
+
if (shared2 && shared2.path === path) return this.share(from);
|
|
13134
13154
|
const ino = await this.inodeOf(path).catch(() => void 0);
|
|
13135
13155
|
const slot2 = this.free.pop() ?? (this.next < UNTRACKED ? this.next++ : UNTRACKED);
|
|
13136
13156
|
if (slot2 === UNTRACKED) return slot2;
|
|
@@ -15134,7 +15154,7 @@ async function guard(g, path, req, cwd) {
|
|
|
15134
15154
|
return { path: w };
|
|
15135
15155
|
}
|
|
15136
15156
|
case "mkdir": {
|
|
15137
|
-
await makeIn(g, op, path);
|
|
15157
|
+
await makeIn(g, op, path, !req.exclusive);
|
|
15138
15158
|
return { path: await walkSafe(g, path, false) };
|
|
15139
15159
|
}
|
|
15140
15160
|
case "create":
|
|
@@ -17494,13 +17514,13 @@ async function flock(req, ctx) {
|
|
|
17494
17514
|
if (!FLOCK_KINDS.has(req.kind)) throw new KernelError("EINVAL");
|
|
17495
17515
|
const { key, owner } = await flockOf(req.fd);
|
|
17496
17516
|
const granted2 = req.kind !== "unlock";
|
|
17497
|
-
const
|
|
17498
|
-
if (
|
|
17517
|
+
const shared2 = locks.shared?.() === true;
|
|
17518
|
+
if (shared2 && !granted2) await ctx.settle?.(req.fd, false);
|
|
17499
17519
|
if (req.kind !== "unlock" && req.wait)
|
|
17500
17520
|
await locks.flocks.wait(key, owner, req.kind, ctx.blocking);
|
|
17501
17521
|
else if (!await locks.flocks.set(key, owner, req.kind)) throw new KernelError("EAGAIN");
|
|
17502
|
-
if (
|
|
17503
|
-
return
|
|
17522
|
+
if (shared2 && granted2) await grantedAcross(ctx, req.fd);
|
|
17523
|
+
return shared2 ? json3(true) : done3;
|
|
17504
17524
|
}
|
|
17505
17525
|
async function grantedAcross(ctx, fd) {
|
|
17506
17526
|
ctx.locks?.fresh?.();
|
|
@@ -17528,15 +17548,15 @@ async function recordLock2(req, ctx) {
|
|
|
17528
17548
|
return json3({ kind: held.kind, pid: held.owner, start: held.start, len });
|
|
17529
17549
|
}
|
|
17530
17550
|
const granted2 = req.kind !== "unlock";
|
|
17531
|
-
const
|
|
17532
|
-
const fd =
|
|
17551
|
+
const shared2 = locks.shared?.() === true;
|
|
17552
|
+
const fd = shared2 ? req.fd : void 0;
|
|
17533
17553
|
if (!granted2 && fd !== void 0) await ctx.settle?.(fd, false);
|
|
17534
17554
|
if (req.kind !== "unlock" && req.wait)
|
|
17535
17555
|
await locks.wait(key, owner, req.kind, range2, ctx.blocking);
|
|
17536
17556
|
else if (!await locks.set(key, owner, req.kind, range2.start, range2.end))
|
|
17537
17557
|
throw new KernelError("EAGAIN");
|
|
17538
|
-
if (granted2 &&
|
|
17539
|
-
return
|
|
17558
|
+
if (granted2 && shared2) await grantedAcross(ctx, fd);
|
|
17559
|
+
return shared2 ? json3(true) : done3;
|
|
17540
17560
|
}
|
|
17541
17561
|
|
|
17542
17562
|
// src/kernel/net/loopback-transport.ts
|
|
@@ -23776,9 +23796,9 @@ function pausing(signal) {
|
|
|
23776
23796
|
return { pausedAt, select };
|
|
23777
23797
|
}
|
|
23778
23798
|
async function serveSecure(proc, socket, req) {
|
|
23779
|
-
const
|
|
23780
|
-
if (req.listener && !
|
|
23781
|
-
const server =
|
|
23799
|
+
const shared2 = req.listener?.serving;
|
|
23800
|
+
if (req.listener && !shared2) throw new KernelError("EINVAL", "the listener has no tls");
|
|
23801
|
+
const server = shared2 ?? await serverOf(proc, req);
|
|
23782
23802
|
const { engine, leaf, alpn, store, flags: flags2 } = server;
|
|
23783
23803
|
const limit = handshakeSignal(proc, server.timeoutMs);
|
|
23784
23804
|
const { pausedAt, select } = pausing(limit.signal);
|
|
@@ -23792,12 +23812,12 @@ async function serveSecure(proc, socket, req) {
|
|
|
23792
23812
|
(flags2 & TLS_KEYLOG) !== 0
|
|
23793
23813
|
),
|
|
23794
23814
|
limit.signal,
|
|
23795
|
-
(reason) => !
|
|
23815
|
+
(reason) => !shared2 && reason === timedOut
|
|
23796
23816
|
).finally(() => {
|
|
23797
23817
|
limit.done();
|
|
23798
23818
|
selections.delete(socket);
|
|
23799
23819
|
socket.pending = void 0;
|
|
23800
|
-
if (!
|
|
23820
|
+
if (!shared2) server.release();
|
|
23801
23821
|
});
|
|
23802
23822
|
run2.catch(() => void 0);
|
|
23803
23823
|
const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
|
|
@@ -29032,6 +29052,39 @@ var RenameLog = class {
|
|
|
29032
29052
|
}
|
|
29033
29053
|
};
|
|
29034
29054
|
|
|
29055
|
+
// src/kernel/replacing.ts
|
|
29056
|
+
var REPLACING_LOCK = "slicc-kernel-replacing:v1:";
|
|
29057
|
+
function replacingLocks(scope = globalThis) {
|
|
29058
|
+
const locks = scope.navigator?.locks;
|
|
29059
|
+
return typeof locks?.request === "function" ? locks : void 0;
|
|
29060
|
+
}
|
|
29061
|
+
function replacingLock(metadata, root) {
|
|
29062
|
+
return `${REPLACING_LOCK}${metadata}:${root}`;
|
|
29063
|
+
}
|
|
29064
|
+
function shared(locks, names2, run2, waited) {
|
|
29065
|
+
const [name2, ...rest2] = names2;
|
|
29066
|
+
if (name2 === void 0) return run2(waited);
|
|
29067
|
+
const next3 = (after) => shared(locks, rest2, run2, after);
|
|
29068
|
+
return locks.request(
|
|
29069
|
+
name2,
|
|
29070
|
+
{ mode: "shared", ifAvailable: true },
|
|
29071
|
+
(lock) => lock ? next3(waited) : locks.request(name2, { mode: "shared" }, () => next3(true))
|
|
29072
|
+
);
|
|
29073
|
+
}
|
|
29074
|
+
var PackageLocks = class {
|
|
29075
|
+
locks;
|
|
29076
|
+
metadata;
|
|
29077
|
+
constructor(metadata, locks = replacingLocks()) {
|
|
29078
|
+
this.metadata = metadata;
|
|
29079
|
+
this.locks = locks;
|
|
29080
|
+
}
|
|
29081
|
+
loading(roots, run2) {
|
|
29082
|
+
if (!this.locks || roots.length === 0) return run2(false);
|
|
29083
|
+
const names2 = roots.map((root) => replacingLock(this.metadata, root));
|
|
29084
|
+
return shared(this.locks, names2, run2, false);
|
|
29085
|
+
}
|
|
29086
|
+
};
|
|
29087
|
+
|
|
29035
29088
|
// src/kernel/settling.ts
|
|
29036
29089
|
var SETUP_OPS = /* @__PURE__ */ new Set([
|
|
29037
29090
|
"proc-list",
|
|
@@ -31282,6 +31335,7 @@ var COMMAND2 = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
|
31282
31335
|
var SHIM_MARKER = /^\/\/ pnpm-wasm-shim=(\{.*\})$/gm;
|
|
31283
31336
|
var SHIM_MAX = 64 * 1024;
|
|
31284
31337
|
var PACKAGE_ROOT = /^(.*\/node_modules\/(?:@[^/]+\/)?[^/]+)\//;
|
|
31338
|
+
var NODE_MODULES = /\/node_modules(?:\/|$)/;
|
|
31285
31339
|
var ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
31286
31340
|
var WASM_MAGIC = [0, 97, 115, 109];
|
|
31287
31341
|
var SHEBANG_MAX = 256;
|
|
@@ -31349,6 +31403,21 @@ function packageRootOf(path, roots) {
|
|
|
31349
31403
|
}
|
|
31350
31404
|
return void 0;
|
|
31351
31405
|
}
|
|
31406
|
+
function planFiles(planned) {
|
|
31407
|
+
const { target } = planned;
|
|
31408
|
+
const files = [
|
|
31409
|
+
target.glue,
|
|
31410
|
+
target.wasm,
|
|
31411
|
+
target.imports,
|
|
31412
|
+
target.copy,
|
|
31413
|
+
...(target.variants ?? []).map((variant) => variant.wasm),
|
|
31414
|
+
...planned.sources ?? []
|
|
31415
|
+
];
|
|
31416
|
+
return files.filter((file) => file !== void 0);
|
|
31417
|
+
}
|
|
31418
|
+
function sameList(a, b) {
|
|
31419
|
+
return a.length === b.length && a.every((item, i) => item === b[i]);
|
|
31420
|
+
}
|
|
31352
31421
|
function modulePath(glue) {
|
|
31353
31422
|
return glue.endsWith(".js") ? `${glue.slice(0, -3)}.wasm` : `${glue}.wasm`;
|
|
31354
31423
|
}
|
|
@@ -31522,6 +31591,7 @@ var Launcher = class {
|
|
|
31522
31591
|
sudoer;
|
|
31523
31592
|
jobs = new JobTable();
|
|
31524
31593
|
locks;
|
|
31594
|
+
packageLocks;
|
|
31525
31595
|
fifos = new FifoTable();
|
|
31526
31596
|
memories;
|
|
31527
31597
|
sems = new SemTable();
|
|
@@ -31594,6 +31664,7 @@ var Launcher = class {
|
|
|
31594
31664
|
this.memories = memoriesOf(options.wasmMemories);
|
|
31595
31665
|
this.rootFs = options.fs;
|
|
31596
31666
|
this.locks = kernelLocks(options.fs.rootName, this.flushingPeers(options.fs));
|
|
31667
|
+
this.packageLocks = new PackageLocks(options.packageLocks ?? META_DB);
|
|
31597
31668
|
this.dac = this.usersMode === "off" ? void 0 : new Dac(this.usersMode, options.onDenial);
|
|
31598
31669
|
if (this.dac) this.wireDac(this.dac);
|
|
31599
31670
|
this.clipboard = new ClipboardBroker(
|
|
@@ -31687,15 +31758,7 @@ var Launcher = class {
|
|
|
31687
31758
|
this.nodes.keepsOnDisk = true;
|
|
31688
31759
|
this.openFiles.add(this.nodes);
|
|
31689
31760
|
options.fs.onPeer?.(() => this.flushOpen());
|
|
31690
|
-
options.fs.remoteChanges?.((change) =>
|
|
31691
|
-
this.held.doubt(change.paths, change.moved?.to);
|
|
31692
|
-
if (change.moved) this.moved(change.moved.from, change.moved.to);
|
|
31693
|
-
this.changes.flush();
|
|
31694
|
-
this.cwds.touched(change.paths, change.trees);
|
|
31695
|
-
this.rewritten(change.paths, change.trees);
|
|
31696
|
-
this.watchers.heard(change.content ? "change" : "rename", change.paths);
|
|
31697
|
-
this.watchers.heard("rename", change.trees ?? []);
|
|
31698
|
-
});
|
|
31761
|
+
options.fs.remoteChanges?.((change) => this.remoteChanged(change));
|
|
31699
31762
|
const holders = [this.held, this.openFiles];
|
|
31700
31763
|
options.fs.heldBy?.(
|
|
31701
31764
|
(dir) => holders.flatMap((set3) => [...set3].flatMap((holder) => [...holder.held()])).filter((p) => p.startsWith(`${dir}/`) && this.mounts.locate(p) === void 0)
|
|
@@ -31905,6 +31968,26 @@ var Launcher = class {
|
|
|
31905
31968
|
}
|
|
31906
31969
|
return trusted;
|
|
31907
31970
|
}
|
|
31971
|
+
remoteChanged(change) {
|
|
31972
|
+
this.held.doubt(change.paths, change.moved?.to);
|
|
31973
|
+
if (change.moved) this.moved(change.moved.from, change.moved.to);
|
|
31974
|
+
this.changes.flush();
|
|
31975
|
+
this.cwds.touched(change.paths, change.trees);
|
|
31976
|
+
this.rewritten(change.paths, change.trees);
|
|
31977
|
+
this.watchers.heard(change.content ? "change" : "rename", change.paths);
|
|
31978
|
+
this.watchers.heard("rename", change.trees ?? []);
|
|
31979
|
+
if (change.outside && this.catalogChanged([...change.paths, ...change.trees ?? []])) {
|
|
31980
|
+
this.resetCatalogs();
|
|
31981
|
+
}
|
|
31982
|
+
}
|
|
31983
|
+
catalogChanged(paths) {
|
|
31984
|
+
const roots = [this.modulesDir, this.pnpmHome, ...this.appended].map(normalizePath);
|
|
31985
|
+
return paths.map(normalizePath).some(
|
|
31986
|
+
(at) => at === "/" || NODE_MODULES.test(at) || roots.some(
|
|
31987
|
+
(root) => at === root || at.startsWith(`${root}/`) || root.startsWith(`${at}/`)
|
|
31988
|
+
)
|
|
31989
|
+
);
|
|
31990
|
+
}
|
|
31908
31991
|
resetCatalogs() {
|
|
31909
31992
|
this.catalogs.clear();
|
|
31910
31993
|
this.ownCatalogs.clear();
|
|
@@ -32305,7 +32388,11 @@ var Launcher = class {
|
|
|
32305
32388
|
secrets.push({ name: name2, value: value2, placeholder });
|
|
32306
32389
|
}
|
|
32307
32390
|
const scrub = scrubberOf(secrets);
|
|
32308
|
-
|
|
32391
|
+
const recheck = async (next3) => {
|
|
32392
|
+
const same3 = sameList(planFiles(next3), planFiles(planned)) && sameList(await this.interpreterChain(next3, booked.cwd, scope), interpreters) && (this.usersMode === "enforce" && await this.trustedFiles(next3, req.file, booked.cwd, scope)) === trusted;
|
|
32393
|
+
if (!same3) throw new SpawnError("EACCES");
|
|
32394
|
+
};
|
|
32395
|
+
return { env, pid, cwd: booked.cwd, ...scrub ? { scrub } : {}, recheck };
|
|
32309
32396
|
}
|
|
32310
32397
|
async interpreterChain(planned, cwd, scope) {
|
|
32311
32398
|
const out = [];
|
|
@@ -32590,25 +32677,16 @@ var Launcher = class {
|
|
|
32590
32677
|
async launch(asked, req) {
|
|
32591
32678
|
const cwd = await physicalPathAsync(this.base, req.cwd);
|
|
32592
32679
|
const seen = { ...req.env, HOSTNAME: this.hostname, cwd };
|
|
32593
|
-
const env = { ...expandDefaults(asked.target.env, seen), ...req.env };
|
|
32594
|
-
for (const key of asked.target.unset ?? []) delete env[key];
|
|
32595
|
-
delete env[TICKET_ENV];
|
|
32596
|
-
const own = env.HOSTNAME;
|
|
32597
|
-
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
32598
|
-
const planned = chosen2(asked, env);
|
|
32599
|
-
const { target, args } = planned;
|
|
32600
|
-
let program;
|
|
32601
|
-
let exeId;
|
|
32602
32680
|
await this.pnpmReady();
|
|
32681
|
+
let loaded;
|
|
32603
32682
|
try {
|
|
32604
|
-
|
|
32605
|
-
if (this.integrity) await this.checkedSources(planned, caller);
|
|
32606
|
-
[program, exeId] = await this.loaded(target, env, caller);
|
|
32607
|
-
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
32683
|
+
loaded = await this.loadedUnder(asked, (planned2) => this.loadPlanned(planned2, req, seen));
|
|
32608
32684
|
} catch (err) {
|
|
32609
32685
|
await req.fds.closeAll();
|
|
32610
32686
|
throw err;
|
|
32611
32687
|
}
|
|
32688
|
+
const { planned, env, program, exeId } = loaded;
|
|
32689
|
+
const { target, args } = planned;
|
|
32612
32690
|
const done5 = this.heldUrl(program);
|
|
32613
32691
|
try {
|
|
32614
32692
|
const cwdSlot = await this.cwds.hold(cwd, req.cwdFrom);
|
|
@@ -32636,6 +32714,52 @@ var Launcher = class {
|
|
|
32636
32714
|
throw err;
|
|
32637
32715
|
}
|
|
32638
32716
|
}
|
|
32717
|
+
async loadPlanned(asked, req, seen) {
|
|
32718
|
+
const env = { ...expandDefaults(asked.target.env, seen), ...req.env };
|
|
32719
|
+
for (const key of asked.target.unset ?? []) delete env[key];
|
|
32720
|
+
delete env[TICKET_ENV];
|
|
32721
|
+
const own = env.HOSTNAME;
|
|
32722
|
+
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
32723
|
+
const planned = chosen2(asked, env);
|
|
32724
|
+
const caller = { pid: req.ppid ?? 0, uid: req.cred.euid, tag: req.tags?.[0] };
|
|
32725
|
+
if (this.integrity) await this.checkedSources(planned, caller);
|
|
32726
|
+
const [program, exeId] = await this.loaded(planned.target, env, caller);
|
|
32727
|
+
if (readsEtcHostname(program)) setOrDrop(env, "HOSTNAME", own);
|
|
32728
|
+
return { planned, env, program, exeId };
|
|
32729
|
+
}
|
|
32730
|
+
packageRoots(planned) {
|
|
32731
|
+
const packages2 = [this.modulesDir, ...this.appended];
|
|
32732
|
+
const roots = /* @__PURE__ */ new Set();
|
|
32733
|
+
for (const file of planFiles(planned)) {
|
|
32734
|
+
if (!file.startsWith("/")) continue;
|
|
32735
|
+
const at = normalizePath(file);
|
|
32736
|
+
const root = PACKAGE_ROOT.exec(at)?.[1] ?? packageRootOf(at, packages2);
|
|
32737
|
+
if (root !== void 0 && root !== at) roots.add(root);
|
|
32738
|
+
}
|
|
32739
|
+
return [...roots].sort();
|
|
32740
|
+
}
|
|
32741
|
+
async loadedUnder(asked, load) {
|
|
32742
|
+
const { replan, recheck } = asked;
|
|
32743
|
+
let planned = asked;
|
|
32744
|
+
let roots = this.packageRoots(planned);
|
|
32745
|
+
let stale = false;
|
|
32746
|
+
for (; ; ) {
|
|
32747
|
+
const held = roots;
|
|
32748
|
+
const done5 = await this.packageLocks.loading(held, async (waited) => {
|
|
32749
|
+
if (!waited && !stale) return { value: await load(planned) };
|
|
32750
|
+
this.rootFs.refresh?.(held);
|
|
32751
|
+
this.resetCatalogs();
|
|
32752
|
+
if (replan) planned = await replan() ?? planned;
|
|
32753
|
+
await recheck?.(planned);
|
|
32754
|
+
const now = this.packageRoots(planned);
|
|
32755
|
+
if (now.every((root) => held.includes(root))) return { value: await load(planned) };
|
|
32756
|
+
roots = [.../* @__PURE__ */ new Set([...held, ...now])].sort();
|
|
32757
|
+
stale = true;
|
|
32758
|
+
return void 0;
|
|
32759
|
+
});
|
|
32760
|
+
if (done5) return done5.value;
|
|
32761
|
+
}
|
|
32762
|
+
}
|
|
32639
32763
|
groupSession(pgid) {
|
|
32640
32764
|
return this.jobs.sessionOf(pgid);
|
|
32641
32765
|
}
|
|
@@ -33064,7 +33188,7 @@ var Launcher = class {
|
|
|
33064
33188
|
const scope = grant ? "" : await this.scopeOf(cred.euid);
|
|
33065
33189
|
const file = booked === void 0 ? req.file : await this.ticketFile(req, fds);
|
|
33066
33190
|
const planned = await this.checkedPlan({ ...req, file }, { ppid, cred, scope }, fds);
|
|
33067
|
-
const redeemed = await this.redeemed(
|
|
33191
|
+
const { recheck, ...redeemed } = await this.redeemed(
|
|
33068
33192
|
{ ...req, file },
|
|
33069
33193
|
{ ppid, cred, scope, booked },
|
|
33070
33194
|
planned,
|
|
@@ -33072,7 +33196,9 @@ var Launcher = class {
|
|
|
33072
33196
|
);
|
|
33073
33197
|
const exec = req.exec ? { exec: true } : {};
|
|
33074
33198
|
const deciding = req.exec ? void 0 : this.undecided(ppid);
|
|
33075
|
-
const
|
|
33199
|
+
const replan = () => this.planOrSearch({ ...req, file }, { ppid, cred, scope });
|
|
33200
|
+
const again = { ...planned, replan, recheck };
|
|
33201
|
+
const handle = await this.launch(again, {
|
|
33076
33202
|
...deciding ? { decided: deciding.promise } : {},
|
|
33077
33203
|
cwd: req.cwd,
|
|
33078
33204
|
cwdFrom: inheritedCwd(req.chdir, this.cwdSlots.get(ppid)),
|
|
@@ -33966,9 +34092,13 @@ var Launcher = class {
|
|
|
33966
34092
|
const file = await this.execFile(argv[0] ?? "", cwd, this.execGuard(credOf(account), 0, tag));
|
|
33967
34093
|
if (!await this.base.exists(cwd))
|
|
33968
34094
|
await this.stackFor(tags, base).fs.mkdir(cwd, { recursive: true });
|
|
33969
|
-
const
|
|
33970
|
-
|
|
33971
|
-
|
|
34095
|
+
const plan = async () => {
|
|
34096
|
+
const found = await this.plan(file, argv, cwd, scope);
|
|
34097
|
+
await this.mayExec(credOf(account), { file, cwd, pid: 0, tag }, found);
|
|
34098
|
+
return found;
|
|
34099
|
+
};
|
|
34100
|
+
const planned = await plan();
|
|
34101
|
+
return { cwd, file, planned: planned && { ...planned, replan: plan } };
|
|
33972
34102
|
}
|
|
33973
34103
|
async openTerminal(argv, options) {
|
|
33974
34104
|
const tagged = tagsOption(options);
|
|
@@ -34692,6 +34822,7 @@ function serveKernel(port, deps) {
|
|
|
34692
34822
|
await fs.reconcile();
|
|
34693
34823
|
const started = new Launcher({
|
|
34694
34824
|
fs,
|
|
34825
|
+
...name2 ? { packageLocks: name2 } : {},
|
|
34695
34826
|
...workers(deps),
|
|
34696
34827
|
...req.modules ? { modules: req.modules } : {},
|
|
34697
34828
|
...req.commands ? { commands: req.commands } : {},
|