@ai-ecoverse/slicc-kernel 1.20.0 → 1.21.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 +16 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +208 -103
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node.js +196 -100
- package/dist/node.js.map +4 -4
- package/package.json +2 -2
package/dist/node.js
CHANGED
|
@@ -498,7 +498,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
498
498
|
const own = this.changes.wait(signal);
|
|
499
499
|
if (this.state !== "connected" || !this.link) return own;
|
|
500
500
|
const waits = [own, this.link.rx.changed(signal), this.link.tx.changed(signal)];
|
|
501
|
-
for (const
|
|
501
|
+
for (const wait2 of waits) wait2.catch(() => void 0);
|
|
502
502
|
return pipeCall(() => Promise.race(waits));
|
|
503
503
|
}
|
|
504
504
|
bind(addr) {
|
|
@@ -4664,12 +4664,27 @@ function kernelCa(store) {
|
|
|
4664
4664
|
function kernelTlsEngine(load) {
|
|
4665
4665
|
return () => loadTlsEngine(load);
|
|
4666
4666
|
}
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4667
|
+
var CERTIFICATE = /-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g;
|
|
4668
|
+
var CA_BUNDLE_MAX = 16;
|
|
4669
|
+
var CA_FILE_LOCK = "slicc-kernel-ca-file";
|
|
4670
|
+
var CA_FILE_TRIES = 3;
|
|
4671
|
+
async function addToBundle(fs, own) {
|
|
4672
|
+
const current = await fs.exists(CA_PATH) ? await fs.readFile(CA_PATH) : "";
|
|
4673
|
+
const all = current.match(CERTIFICATE) ?? [];
|
|
4674
|
+
const others = all.filter((cert) => cert !== own);
|
|
4675
|
+
if (others.length < all.length) return true;
|
|
4676
|
+
const bundle = [...others, own].slice(-CA_BUNDLE_MAX);
|
|
4671
4677
|
await fs.mkdir(CA_PATH.slice(0, CA_PATH.lastIndexOf("/")), { recursive: true });
|
|
4672
|
-
await fs.writeFile(CA_PATH,
|
|
4678
|
+
await fs.writeFile(CA_PATH, `${bundle.join("\n")}
|
|
4679
|
+
`);
|
|
4680
|
+
return false;
|
|
4681
|
+
}
|
|
4682
|
+
async function writeCaFile(fs, ca, locks = globalThis.navigator?.locks) {
|
|
4683
|
+
const own = (await ca()).pem.trim();
|
|
4684
|
+
const update = async () => {
|
|
4685
|
+
for (let i = 0; i < CA_FILE_TRIES && !await addToBundle(fs, own); i++) ;
|
|
4686
|
+
};
|
|
4687
|
+
await (locks ? locks.request(CA_FILE_LOCK, update) : update());
|
|
4673
4688
|
}
|
|
4674
4689
|
function enableNetwork(net, options) {
|
|
4675
4690
|
let proxy;
|
|
@@ -6937,10 +6952,164 @@ function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
|
|
|
6937
6952
|
};
|
|
6938
6953
|
}
|
|
6939
6954
|
|
|
6955
|
+
// src/mount/syscall.ts
|
|
6956
|
+
var MS_RDONLY = 1;
|
|
6957
|
+
var MS_MGC_MSK = 4294901760;
|
|
6958
|
+
var MS_MGC_VAL = 3236757504;
|
|
6959
|
+
var IGNORED_FLAGS = 2 | 4 | 8 | 16 | 128 | 1024 | 2048 | 32768 | 1 << 21 | 1 << 24 | 1 << 25;
|
|
6960
|
+
var MNT_FORCE = 1;
|
|
6961
|
+
var MNT_DETACH = 2;
|
|
6962
|
+
var UMOUNT_NOFOLLOW = 8;
|
|
6963
|
+
var GENERIC = /* @__PURE__ */ new Set([
|
|
6964
|
+
"defaults",
|
|
6965
|
+
"async",
|
|
6966
|
+
"sync",
|
|
6967
|
+
"dirsync",
|
|
6968
|
+
"atime",
|
|
6969
|
+
"noatime",
|
|
6970
|
+
"diratime",
|
|
6971
|
+
"nodiratime",
|
|
6972
|
+
"relatime",
|
|
6973
|
+
"norelatime",
|
|
6974
|
+
"strictatime",
|
|
6975
|
+
"nostrictatime",
|
|
6976
|
+
"lazytime",
|
|
6977
|
+
"nolazytime",
|
|
6978
|
+
"suid",
|
|
6979
|
+
"nosuid",
|
|
6980
|
+
"dev",
|
|
6981
|
+
"nodev",
|
|
6982
|
+
"exec",
|
|
6983
|
+
"noexec",
|
|
6984
|
+
"auto",
|
|
6985
|
+
"noauto",
|
|
6986
|
+
"user",
|
|
6987
|
+
"nouser",
|
|
6988
|
+
"users",
|
|
6989
|
+
"nofail",
|
|
6990
|
+
"_netdev",
|
|
6991
|
+
"silent",
|
|
6992
|
+
"loud"
|
|
6993
|
+
]);
|
|
6994
|
+
function parseMountOptions(data) {
|
|
6995
|
+
const options = {};
|
|
6996
|
+
for (const raw of data.split(",")) {
|
|
6997
|
+
const item = raw.trim();
|
|
6998
|
+
if (!item || GENERIC.has(item)) continue;
|
|
6999
|
+
if (item === "rw") {
|
|
7000
|
+
delete options.ro;
|
|
7001
|
+
continue;
|
|
7002
|
+
}
|
|
7003
|
+
const eq = item.indexOf("=");
|
|
7004
|
+
if (eq === 0) throw errnoError("EINVAL", `bad mount option ${item}`);
|
|
7005
|
+
if (eq < 0) options[item] = "";
|
|
7006
|
+
else options[item.slice(0, eq)] = item.slice(eq + 1);
|
|
7007
|
+
}
|
|
7008
|
+
if (options.maxfile !== void 0) parseSize(options.maxfile);
|
|
7009
|
+
return options;
|
|
7010
|
+
}
|
|
7011
|
+
function refusedTarget(target) {
|
|
7012
|
+
const at = normalizePath(target);
|
|
7013
|
+
const kernel = at === "/" || [`/proc`, `/dev`].some((k) => at === k || at.startsWith(`${k}/`));
|
|
7014
|
+
if (kernel) throw errnoError("EBUSY", `${at} belongs to the kernel`);
|
|
7015
|
+
}
|
|
7016
|
+
function absolute(target) {
|
|
7017
|
+
if (!target) throw errnoError("ENOENT", "no mount point");
|
|
7018
|
+
if (!target.startsWith("/")) throw errnoError("EINVAL", `not an absolute path: ${target}`);
|
|
7019
|
+
return normalizePath(target);
|
|
7020
|
+
}
|
|
7021
|
+
function mountCall(call) {
|
|
7022
|
+
let flags = call.flags >>> 0;
|
|
7023
|
+
if ((flags & MS_MGC_MSK) >>> 0 === MS_MGC_VAL) flags &= ~MS_MGC_MSK;
|
|
7024
|
+
if (flags & ~(MS_RDONLY | IGNORED_FLAGS)) {
|
|
7025
|
+
throw errnoError("EINVAL", `unsupported mount flags ${flags.toString(16)}`);
|
|
7026
|
+
}
|
|
7027
|
+
if (!call.type) throw errnoError("EINVAL", "no file system type");
|
|
7028
|
+
const target = absolute(call.target);
|
|
7029
|
+
refusedTarget(target);
|
|
7030
|
+
const options = parseMountOptions(call.data);
|
|
7031
|
+
if (flags & MS_RDONLY) options.ro = "";
|
|
7032
|
+
return { type: call.type, source: call.source || "none", target, options };
|
|
7033
|
+
}
|
|
7034
|
+
function umountCall(target, flags) {
|
|
7035
|
+
const known = MNT_FORCE | MNT_DETACH | UMOUNT_NOFOLLOW;
|
|
7036
|
+
if (flags >>> 0 & ~known) throw errnoError("EINVAL", `unsupported umount flags ${flags}`);
|
|
7037
|
+
const at = absolute(target);
|
|
7038
|
+
refusedTarget(at);
|
|
7039
|
+
return { target: at, detach: (flags & (MNT_FORCE | MNT_DETACH)) !== 0 };
|
|
7040
|
+
}
|
|
7041
|
+
|
|
7042
|
+
// src/mount/fstab.ts
|
|
7043
|
+
var FSTAB_PATH = "/etc/fstab";
|
|
7044
|
+
var FSTAB_RETRIES = [1e3, 4e3, 16e3];
|
|
7045
|
+
var FINAL = /* @__PURE__ */ new Set(["EINVAL", "EBUSY", "EPERM", "EACCES"]);
|
|
7046
|
+
function unescape(field) {
|
|
7047
|
+
return field.replace(
|
|
7048
|
+
/\\([0-7]{3})/g,
|
|
7049
|
+
(_, octal) => String.fromCharCode(Number.parseInt(octal, 8))
|
|
7050
|
+
);
|
|
7051
|
+
}
|
|
7052
|
+
function parseFstab(text) {
|
|
7053
|
+
const lines = [];
|
|
7054
|
+
text.split("\n").forEach((raw, index) => {
|
|
7055
|
+
const content = raw.replace(/#.*$/, "").trim();
|
|
7056
|
+
if (!content) return;
|
|
7057
|
+
const [source, target, type, options = "defaults"] = content.split(/\s+/).map(unescape);
|
|
7058
|
+
if (source === void 0 || target === void 0 || type === void 0) return;
|
|
7059
|
+
if (options.split(",").includes("noauto")) return;
|
|
7060
|
+
const spec = { source, target, type, options: {} };
|
|
7061
|
+
try {
|
|
7062
|
+
lines.push({ line: index + 1, spec: { ...spec, options: parseMountOptions(options) } });
|
|
7063
|
+
} catch (err) {
|
|
7064
|
+
lines.push({ line: index + 1, spec, invalid: err });
|
|
7065
|
+
}
|
|
7066
|
+
});
|
|
7067
|
+
return lines;
|
|
7068
|
+
}
|
|
7069
|
+
function codeOf3(err) {
|
|
7070
|
+
const code = err?.code;
|
|
7071
|
+
return typeof code === "string" ? code : "EIO";
|
|
7072
|
+
}
|
|
7073
|
+
function wait(ms, signal) {
|
|
7074
|
+
if (signal.aborted) return Promise.resolve();
|
|
7075
|
+
return new Promise((resolve) => {
|
|
7076
|
+
const done4 = () => {
|
|
7077
|
+
clearTimeout(timer);
|
|
7078
|
+
signal.removeEventListener("abort", done4);
|
|
7079
|
+
resolve();
|
|
7080
|
+
};
|
|
7081
|
+
const timer = setTimeout(done4, ms);
|
|
7082
|
+
signal.addEventListener("abort", done4, { once: true });
|
|
7083
|
+
});
|
|
7084
|
+
}
|
|
7085
|
+
async function mountFstab(lines, mount, signal, retries = FSTAB_RETRIES, discard = () => {
|
|
7086
|
+
}) {
|
|
7087
|
+
return Promise.all(
|
|
7088
|
+
lines.map(async ({ line, spec, invalid }) => {
|
|
7089
|
+
let failed = invalid;
|
|
7090
|
+
for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
|
|
7091
|
+
try {
|
|
7092
|
+
const entry = await mount(spec);
|
|
7093
|
+
if (!signal.aborted) return { line, target: spec.target, entry };
|
|
7094
|
+
discard(entry);
|
|
7095
|
+
failed = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
|
|
7096
|
+
break;
|
|
7097
|
+
} catch (err) {
|
|
7098
|
+
failed = err;
|
|
7099
|
+
if (FINAL.has(codeOf3(err)) || attempt === retries.length) break;
|
|
7100
|
+
await wait(retries[attempt], signal);
|
|
7101
|
+
}
|
|
7102
|
+
}
|
|
7103
|
+
const code = codeOf3(failed);
|
|
7104
|
+
return { line, target: spec.target, code, error: String(failed?.message ?? code) };
|
|
7105
|
+
})
|
|
7106
|
+
);
|
|
7107
|
+
}
|
|
7108
|
+
|
|
6940
7109
|
// src/mount/hostfs.ts
|
|
6941
7110
|
var HOSTFS_IO = 16 * 1024 * 1024;
|
|
6942
|
-
var
|
|
6943
|
-
var unreachable = (err) =>
|
|
7111
|
+
var codeOf4 = (err) => err?.code;
|
|
7112
|
+
var unreachable = (err) => codeOf4(err) === "ENOTCONN";
|
|
6944
7113
|
function rel(path) {
|
|
6945
7114
|
return path.replace(/^\/+/, "");
|
|
6946
7115
|
}
|
|
@@ -7075,7 +7244,7 @@ function hostfsHandlers(current) {
|
|
|
7075
7244
|
try {
|
|
7076
7245
|
return { opened: await opening(), restore: void 0 };
|
|
7077
7246
|
} catch (err) {
|
|
7078
|
-
if (!flags.write ||
|
|
7247
|
+
if (!flags.write || codeOf4(err) !== "EACCES") throw err;
|
|
7079
7248
|
const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
|
|
7080
7249
|
if (mode & 128) throw err;
|
|
7081
7250
|
const restore = { path: rel(path), mode };
|
|
@@ -7164,7 +7333,7 @@ function keepWatching(loop, signal) {
|
|
|
7164
7333
|
const uncap = () => clearTimeout(capped);
|
|
7165
7334
|
void ready2.promise.then(uncap);
|
|
7166
7335
|
signal.addEventListener("abort", uncap, { once: true });
|
|
7167
|
-
let
|
|
7336
|
+
let wait2 = first;
|
|
7168
7337
|
let up = false;
|
|
7169
7338
|
let current;
|
|
7170
7339
|
async function session() {
|
|
@@ -7209,7 +7378,7 @@ function keepWatching(loop, signal) {
|
|
|
7209
7378
|
const opened2 = await session();
|
|
7210
7379
|
if (signal.aborted) return;
|
|
7211
7380
|
if (opened2 && Date.now() - began >= first) {
|
|
7212
|
-
|
|
7381
|
+
wait2 = first;
|
|
7213
7382
|
continue;
|
|
7214
7383
|
}
|
|
7215
7384
|
if (!opened2 && up) {
|
|
@@ -7217,8 +7386,8 @@ function keepWatching(loop, signal) {
|
|
|
7217
7386
|
loop.down();
|
|
7218
7387
|
}
|
|
7219
7388
|
ready2.resolve();
|
|
7220
|
-
await sleep(
|
|
7221
|
-
|
|
7389
|
+
await sleep(wait2, signal);
|
|
7390
|
+
wait2 = Math.min(wait2 * 2, most);
|
|
7222
7391
|
}
|
|
7223
7392
|
})();
|
|
7224
7393
|
return { ready: ready2.promise, kick: () => current?.abort() };
|
|
@@ -7282,93 +7451,6 @@ function memoryMedia() {
|
|
|
7282
7451
|
};
|
|
7283
7452
|
}
|
|
7284
7453
|
|
|
7285
|
-
// src/mount/syscall.ts
|
|
7286
|
-
var MS_RDONLY = 1;
|
|
7287
|
-
var MS_MGC_MSK = 4294901760;
|
|
7288
|
-
var MS_MGC_VAL = 3236757504;
|
|
7289
|
-
var IGNORED_FLAGS = 2 | 4 | 8 | 16 | 128 | 1024 | 2048 | 32768 | 1 << 21 | 1 << 24 | 1 << 25;
|
|
7290
|
-
var MNT_FORCE = 1;
|
|
7291
|
-
var MNT_DETACH = 2;
|
|
7292
|
-
var UMOUNT_NOFOLLOW = 8;
|
|
7293
|
-
var GENERIC = /* @__PURE__ */ new Set([
|
|
7294
|
-
"defaults",
|
|
7295
|
-
"async",
|
|
7296
|
-
"sync",
|
|
7297
|
-
"dirsync",
|
|
7298
|
-
"atime",
|
|
7299
|
-
"noatime",
|
|
7300
|
-
"diratime",
|
|
7301
|
-
"nodiratime",
|
|
7302
|
-
"relatime",
|
|
7303
|
-
"norelatime",
|
|
7304
|
-
"strictatime",
|
|
7305
|
-
"nostrictatime",
|
|
7306
|
-
"lazytime",
|
|
7307
|
-
"nolazytime",
|
|
7308
|
-
"suid",
|
|
7309
|
-
"nosuid",
|
|
7310
|
-
"dev",
|
|
7311
|
-
"nodev",
|
|
7312
|
-
"exec",
|
|
7313
|
-
"noexec",
|
|
7314
|
-
"auto",
|
|
7315
|
-
"noauto",
|
|
7316
|
-
"user",
|
|
7317
|
-
"nouser",
|
|
7318
|
-
"users",
|
|
7319
|
-
"nofail",
|
|
7320
|
-
"_netdev",
|
|
7321
|
-
"silent",
|
|
7322
|
-
"loud"
|
|
7323
|
-
]);
|
|
7324
|
-
function parseMountOptions(data) {
|
|
7325
|
-
const options = {};
|
|
7326
|
-
for (const raw of data.split(",")) {
|
|
7327
|
-
const item = raw.trim();
|
|
7328
|
-
if (!item || GENERIC.has(item)) continue;
|
|
7329
|
-
if (item === "rw") {
|
|
7330
|
-
delete options.ro;
|
|
7331
|
-
continue;
|
|
7332
|
-
}
|
|
7333
|
-
const eq = item.indexOf("=");
|
|
7334
|
-
if (eq === 0) throw errnoError("EINVAL", `bad mount option ${item}`);
|
|
7335
|
-
if (eq < 0) options[item] = "";
|
|
7336
|
-
else options[item.slice(0, eq)] = item.slice(eq + 1);
|
|
7337
|
-
}
|
|
7338
|
-
if (options.maxfile !== void 0) parseSize(options.maxfile);
|
|
7339
|
-
return options;
|
|
7340
|
-
}
|
|
7341
|
-
function refusedTarget(target) {
|
|
7342
|
-
const at = normalizePath(target);
|
|
7343
|
-
const kernel = at === "/" || [`/proc`, `/dev`].some((k) => at === k || at.startsWith(`${k}/`));
|
|
7344
|
-
if (kernel) throw errnoError("EBUSY", `${at} belongs to the kernel`);
|
|
7345
|
-
}
|
|
7346
|
-
function absolute(target) {
|
|
7347
|
-
if (!target) throw errnoError("ENOENT", "no mount point");
|
|
7348
|
-
if (!target.startsWith("/")) throw errnoError("EINVAL", `not an absolute path: ${target}`);
|
|
7349
|
-
return normalizePath(target);
|
|
7350
|
-
}
|
|
7351
|
-
function mountCall(call) {
|
|
7352
|
-
let flags = call.flags >>> 0;
|
|
7353
|
-
if ((flags & MS_MGC_MSK) >>> 0 === MS_MGC_VAL) flags &= ~MS_MGC_MSK;
|
|
7354
|
-
if (flags & ~(MS_RDONLY | IGNORED_FLAGS)) {
|
|
7355
|
-
throw errnoError("EINVAL", `unsupported mount flags ${flags.toString(16)}`);
|
|
7356
|
-
}
|
|
7357
|
-
if (!call.type) throw errnoError("EINVAL", "no file system type");
|
|
7358
|
-
const target = absolute(call.target);
|
|
7359
|
-
refusedTarget(target);
|
|
7360
|
-
const options = parseMountOptions(call.data);
|
|
7361
|
-
if (flags & MS_RDONLY) options.ro = "";
|
|
7362
|
-
return { type: call.type, source: call.source || "none", target, options };
|
|
7363
|
-
}
|
|
7364
|
-
function umountCall(target, flags) {
|
|
7365
|
-
const known = MNT_FORCE | MNT_DETACH | UMOUNT_NOFOLLOW;
|
|
7366
|
-
if (flags >>> 0 & ~known) throw errnoError("EINVAL", `unsupported umount flags ${flags}`);
|
|
7367
|
-
const at = absolute(target);
|
|
7368
|
-
refusedTarget(at);
|
|
7369
|
-
return { target: at, detach: (flags & (MNT_FORCE | MNT_DETACH)) !== 0 };
|
|
7370
|
-
}
|
|
7371
|
-
|
|
7372
7454
|
// src/mount/tmpfs.ts
|
|
7373
7455
|
function tmpfs() {
|
|
7374
7456
|
let inodes = 0;
|
|
@@ -7787,6 +7869,8 @@ var Launcher = class {
|
|
|
7787
7869
|
openFiles = /* @__PURE__ */ new Set();
|
|
7788
7870
|
held = /* @__PURE__ */ new Set();
|
|
7789
7871
|
processMounts;
|
|
7872
|
+
booting = new AbortController();
|
|
7873
|
+
fstab = Promise.resolve([]);
|
|
7790
7874
|
nextPid = 1e3;
|
|
7791
7875
|
boot = Date.now();
|
|
7792
7876
|
terminals = 0;
|
|
@@ -8194,6 +8278,7 @@ var Launcher = class {
|
|
|
8194
8278
|
for (const holds of this.held) holds.revoke(at);
|
|
8195
8279
|
}
|
|
8196
8280
|
unmountAll() {
|
|
8281
|
+
this.booting.abort();
|
|
8197
8282
|
const targets = this.mounts.list().map((m) => m.target);
|
|
8198
8283
|
for (const target of targets.sort((a, b) => b.length - a.length)) this.umount(target, true);
|
|
8199
8284
|
}
|
|
@@ -8225,6 +8310,17 @@ var Launcher = class {
|
|
|
8225
8310
|
async prepare() {
|
|
8226
8311
|
for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
|
|
8227
8312
|
await writeCaFile(this.base, this.ca).catch(() => void 0);
|
|
8313
|
+
this.fstab = this.mountFstab();
|
|
8314
|
+
}
|
|
8315
|
+
async mountFstab() {
|
|
8316
|
+
const text = await this.base.readFile(FSTAB_PATH).catch(() => "");
|
|
8317
|
+
return mountFstab(
|
|
8318
|
+
parseFstab(text),
|
|
8319
|
+
(spec) => this.mount(spec),
|
|
8320
|
+
this.booting.signal,
|
|
8321
|
+
FSTAB_RETRIES,
|
|
8322
|
+
(entry) => this.umount(entry.target, true)
|
|
8323
|
+
);
|
|
8228
8324
|
}
|
|
8229
8325
|
environment(cwd, extra) {
|
|
8230
8326
|
return {
|