@ai-ecoverse/slicc-kernel 1.20.1 → 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/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 wait of waits) wait.catch(() => void 0);
501
+ for (const wait2 of waits) wait2.catch(() => void 0);
502
502
  return pipeCall(() => Promise.race(waits));
503
503
  }
504
504
  bind(addr) {
@@ -6952,10 +6952,164 @@ function removableMedium(onLost, open = (handle) => new OpfsFs(handle)) {
6952
6952
  };
6953
6953
  }
6954
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
+
6955
7109
  // src/mount/hostfs.ts
6956
7110
  var HOSTFS_IO = 16 * 1024 * 1024;
6957
- var codeOf3 = (err) => err?.code;
6958
- var unreachable = (err) => codeOf3(err) === "ENOTCONN";
7111
+ var codeOf4 = (err) => err?.code;
7112
+ var unreachable = (err) => codeOf4(err) === "ENOTCONN";
6959
7113
  function rel(path) {
6960
7114
  return path.replace(/^\/+/, "");
6961
7115
  }
@@ -7090,7 +7244,7 @@ function hostfsHandlers(current) {
7090
7244
  try {
7091
7245
  return { opened: await opening(), restore: void 0 };
7092
7246
  } catch (err) {
7093
- if (!flags.write || codeOf3(err) !== "EACCES") throw err;
7247
+ if (!flags.write || codeOf4(err) !== "EACCES") throw err;
7094
7248
  const mode = (await client.call("stat", { path: rel(path) })).mode ?? 0;
7095
7249
  if (mode & 128) throw err;
7096
7250
  const restore = { path: rel(path), mode };
@@ -7179,7 +7333,7 @@ function keepWatching(loop, signal) {
7179
7333
  const uncap = () => clearTimeout(capped);
7180
7334
  void ready2.promise.then(uncap);
7181
7335
  signal.addEventListener("abort", uncap, { once: true });
7182
- let wait = first;
7336
+ let wait2 = first;
7183
7337
  let up = false;
7184
7338
  let current;
7185
7339
  async function session() {
@@ -7224,7 +7378,7 @@ function keepWatching(loop, signal) {
7224
7378
  const opened2 = await session();
7225
7379
  if (signal.aborted) return;
7226
7380
  if (opened2 && Date.now() - began >= first) {
7227
- wait = first;
7381
+ wait2 = first;
7228
7382
  continue;
7229
7383
  }
7230
7384
  if (!opened2 && up) {
@@ -7232,8 +7386,8 @@ function keepWatching(loop, signal) {
7232
7386
  loop.down();
7233
7387
  }
7234
7388
  ready2.resolve();
7235
- await sleep(wait, signal);
7236
- wait = Math.min(wait * 2, most);
7389
+ await sleep(wait2, signal);
7390
+ wait2 = Math.min(wait2 * 2, most);
7237
7391
  }
7238
7392
  })();
7239
7393
  return { ready: ready2.promise, kick: () => current?.abort() };
@@ -7297,93 +7451,6 @@ function memoryMedia() {
7297
7451
  };
7298
7452
  }
7299
7453
 
7300
- // src/mount/syscall.ts
7301
- var MS_RDONLY = 1;
7302
- var MS_MGC_MSK = 4294901760;
7303
- var MS_MGC_VAL = 3236757504;
7304
- var IGNORED_FLAGS = 2 | 4 | 8 | 16 | 128 | 1024 | 2048 | 32768 | 1 << 21 | 1 << 24 | 1 << 25;
7305
- var MNT_FORCE = 1;
7306
- var MNT_DETACH = 2;
7307
- var UMOUNT_NOFOLLOW = 8;
7308
- var GENERIC = /* @__PURE__ */ new Set([
7309
- "defaults",
7310
- "async",
7311
- "sync",
7312
- "dirsync",
7313
- "atime",
7314
- "noatime",
7315
- "diratime",
7316
- "nodiratime",
7317
- "relatime",
7318
- "norelatime",
7319
- "strictatime",
7320
- "nostrictatime",
7321
- "lazytime",
7322
- "nolazytime",
7323
- "suid",
7324
- "nosuid",
7325
- "dev",
7326
- "nodev",
7327
- "exec",
7328
- "noexec",
7329
- "auto",
7330
- "noauto",
7331
- "user",
7332
- "nouser",
7333
- "users",
7334
- "nofail",
7335
- "_netdev",
7336
- "silent",
7337
- "loud"
7338
- ]);
7339
- function parseMountOptions(data) {
7340
- const options = {};
7341
- for (const raw of data.split(",")) {
7342
- const item = raw.trim();
7343
- if (!item || GENERIC.has(item)) continue;
7344
- if (item === "rw") {
7345
- delete options.ro;
7346
- continue;
7347
- }
7348
- const eq = item.indexOf("=");
7349
- if (eq === 0) throw errnoError("EINVAL", `bad mount option ${item}`);
7350
- if (eq < 0) options[item] = "";
7351
- else options[item.slice(0, eq)] = item.slice(eq + 1);
7352
- }
7353
- if (options.maxfile !== void 0) parseSize(options.maxfile);
7354
- return options;
7355
- }
7356
- function refusedTarget(target) {
7357
- const at = normalizePath(target);
7358
- const kernel = at === "/" || [`/proc`, `/dev`].some((k) => at === k || at.startsWith(`${k}/`));
7359
- if (kernel) throw errnoError("EBUSY", `${at} belongs to the kernel`);
7360
- }
7361
- function absolute(target) {
7362
- if (!target) throw errnoError("ENOENT", "no mount point");
7363
- if (!target.startsWith("/")) throw errnoError("EINVAL", `not an absolute path: ${target}`);
7364
- return normalizePath(target);
7365
- }
7366
- function mountCall(call) {
7367
- let flags = call.flags >>> 0;
7368
- if ((flags & MS_MGC_MSK) >>> 0 === MS_MGC_VAL) flags &= ~MS_MGC_MSK;
7369
- if (flags & ~(MS_RDONLY | IGNORED_FLAGS)) {
7370
- throw errnoError("EINVAL", `unsupported mount flags ${flags.toString(16)}`);
7371
- }
7372
- if (!call.type) throw errnoError("EINVAL", "no file system type");
7373
- const target = absolute(call.target);
7374
- refusedTarget(target);
7375
- const options = parseMountOptions(call.data);
7376
- if (flags & MS_RDONLY) options.ro = "";
7377
- return { type: call.type, source: call.source || "none", target, options };
7378
- }
7379
- function umountCall(target, flags) {
7380
- const known = MNT_FORCE | MNT_DETACH | UMOUNT_NOFOLLOW;
7381
- if (flags >>> 0 & ~known) throw errnoError("EINVAL", `unsupported umount flags ${flags}`);
7382
- const at = absolute(target);
7383
- refusedTarget(at);
7384
- return { target: at, detach: (flags & (MNT_FORCE | MNT_DETACH)) !== 0 };
7385
- }
7386
-
7387
7454
  // src/mount/tmpfs.ts
7388
7455
  function tmpfs() {
7389
7456
  let inodes = 0;
@@ -7802,6 +7869,8 @@ var Launcher = class {
7802
7869
  openFiles = /* @__PURE__ */ new Set();
7803
7870
  held = /* @__PURE__ */ new Set();
7804
7871
  processMounts;
7872
+ booting = new AbortController();
7873
+ fstab = Promise.resolve([]);
7805
7874
  nextPid = 1e3;
7806
7875
  boot = Date.now();
7807
7876
  terminals = 0;
@@ -8209,6 +8278,7 @@ var Launcher = class {
8209
8278
  for (const holds of this.held) holds.revoke(at);
8210
8279
  }
8211
8280
  unmountAll() {
8281
+ this.booting.abort();
8212
8282
  const targets = this.mounts.list().map((m) => m.target);
8213
8283
  for (const target of targets.sort((a, b) => b.length - a.length)) this.umount(target, true);
8214
8284
  }
@@ -8240,6 +8310,17 @@ var Launcher = class {
8240
8310
  async prepare() {
8241
8311
  for (const dir of SHARED_DIRS) await this.base.mkdir(dir, { recursive: true });
8242
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
+ );
8243
8324
  }
8244
8325
  environment(cwd, extra) {
8245
8326
  return {