@ai-ecoverse/slicc-kernel 1.108.4 → 1.109.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 +2 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +437 -240
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +28 -3
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +223 -26
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +28 -3
- package/dist/process-worker.js.map +3 -3
- package/dist/types/cron/command.d.ts +4 -0
- package/dist/types/cron/crontab.d.ts +27 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/host.d.ts +1 -0
- package/dist/types/kernel/process.d.ts +4 -1
- package/dist/types/launcher.d.ts +2 -0
- package/dist/types/process/js/js-context.d.ts +13 -0
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -6435,7 +6435,7 @@ function satisfies(version, range2) {
|
|
|
6435
6435
|
}
|
|
6436
6436
|
|
|
6437
6437
|
// src/version.ts
|
|
6438
|
-
var KERNEL_VERSION = true ? "1.
|
|
6438
|
+
var KERNEL_VERSION = true ? "1.109.0" : "0.0.0-dev";
|
|
6439
6439
|
var OS_RELEASE = "6.0.0-slicc";
|
|
6440
6440
|
function procVersion() {
|
|
6441
6441
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -6794,23 +6794,115 @@ function binfmtOf(binfmts, path) {
|
|
|
6794
6794
|
return best === void 0 ? void 0 : binfmts.get(best);
|
|
6795
6795
|
}
|
|
6796
6796
|
|
|
6797
|
-
// src/cron/
|
|
6798
|
-
var
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
signal.removeEventListener("abort", done4);
|
|
6806
|
-
resolve2();
|
|
6807
|
-
};
|
|
6808
|
-
const timer = setTimeout(done4, Math.max(0, until - Date.now()));
|
|
6809
|
-
timer.unref?.();
|
|
6810
|
-
signal.addEventListener("abort", done4, { once: true });
|
|
6811
|
-
});
|
|
6812
|
-
}
|
|
6797
|
+
// src/cron/command.ts
|
|
6798
|
+
var CRONTAB_PATH = "/usr/bin/crontab";
|
|
6799
|
+
var CRONTAB_COMMAND = {
|
|
6800
|
+
name: "crontab",
|
|
6801
|
+
abi: "js",
|
|
6802
|
+
glue: CRONTAB_PATH,
|
|
6803
|
+
wasm: CRONTAB_PATH,
|
|
6804
|
+
argv0: "crontab"
|
|
6813
6805
|
};
|
|
6806
|
+
var CRONTAB_SOURCE = `export default async function crontab(ctx) {
|
|
6807
|
+
const say = (fd, text) => ctx.write(fd, text).catch(() => undefined);
|
|
6808
|
+
const usage = async () => {
|
|
6809
|
+
await say(2, "usage: crontab [-u user] { -l | -r | -e | file | - }\\n");
|
|
6810
|
+
return 1;
|
|
6811
|
+
};
|
|
6812
|
+
const args = ctx.argv.slice(1);
|
|
6813
|
+
let user;
|
|
6814
|
+
let action;
|
|
6815
|
+
let file;
|
|
6816
|
+
for (let i = 0; i < args.length; i++) {
|
|
6817
|
+
const arg = args[i];
|
|
6818
|
+
if (arg === "-u") {
|
|
6819
|
+
user = args[++i];
|
|
6820
|
+
if (user === undefined) return usage();
|
|
6821
|
+
} else if (arg === "-l" || arg === "-r" || arg === "-e") {
|
|
6822
|
+
if (action !== undefined) return usage();
|
|
6823
|
+
action = arg.slice(1);
|
|
6824
|
+
} else if (arg === "-" || !arg.startsWith("-")) {
|
|
6825
|
+
if (file !== undefined) return usage();
|
|
6826
|
+
file = arg;
|
|
6827
|
+
} else return usage();
|
|
6828
|
+
}
|
|
6829
|
+
if ((action === undefined) === (file === undefined)) return usage();
|
|
6830
|
+
const call = (c) => ctx.crontab(user === undefined ? c : { ...c, user });
|
|
6831
|
+
const failed = async (answer) => {
|
|
6832
|
+
await say(2, answer.error + "\\n");
|
|
6833
|
+
return 1;
|
|
6834
|
+
};
|
|
6835
|
+
const decode = (bytes) => new TextDecoder().decode(bytes);
|
|
6836
|
+
if (action === "l") {
|
|
6837
|
+
const answer = await call({ action: "list" });
|
|
6838
|
+
if (answer.error !== undefined) return failed(answer);
|
|
6839
|
+
await say(1, answer.text);
|
|
6840
|
+
return 0;
|
|
6841
|
+
}
|
|
6842
|
+
if (action === "r") {
|
|
6843
|
+
const answer = await call({ action: "remove" });
|
|
6844
|
+
return answer.error !== undefined ? failed(answer) : 0;
|
|
6845
|
+
}
|
|
6846
|
+
if (action === "e") return edit();
|
|
6847
|
+
let text;
|
|
6848
|
+
try {
|
|
6849
|
+
if (file === "-") {
|
|
6850
|
+
const parts = [];
|
|
6851
|
+
for (;;) {
|
|
6852
|
+
const chunk = await ctx.read(0);
|
|
6853
|
+
if (chunk.length === 0) break;
|
|
6854
|
+
parts.push(decode(chunk));
|
|
6855
|
+
}
|
|
6856
|
+
text = parts.join("");
|
|
6857
|
+
} else text = decode(await ctx.fs.readFile(ctx.resolve(file)));
|
|
6858
|
+
} catch (err) {
|
|
6859
|
+
await say(2, "crontab: " + file + ": " + (err && err.code ? err.code : String(err)) + "\\n");
|
|
6860
|
+
return 1;
|
|
6861
|
+
}
|
|
6862
|
+
const answer = await call({ action: "install", text });
|
|
6863
|
+
return answer.error !== undefined ? failed(answer) : 0;
|
|
6864
|
+
|
|
6865
|
+
async function edit() {
|
|
6866
|
+
const editor = ctx.env.VISUAL || ctx.env.EDITOR;
|
|
6867
|
+
if (!editor) {
|
|
6868
|
+
await say(2, "crontab: set VISUAL or EDITOR to edit, or install a file with crontab <file>\\n");
|
|
6869
|
+
return 1;
|
|
6870
|
+
}
|
|
6871
|
+
const current = await call({ action: "list" });
|
|
6872
|
+
const before = current.error === undefined ? current.text : "";
|
|
6873
|
+
if (current.error !== undefined && !current.error.startsWith("no crontab for ")) return failed(current);
|
|
6874
|
+
const tmp = "/tmp/crontab." + ctx.pid + "." + crypto.randomUUID();
|
|
6875
|
+
try {
|
|
6876
|
+
const file = await ctx.open(tmp, { write: true, create: true, exclusive: true, mode: 0o600 });
|
|
6877
|
+
await file.write(0, new TextEncoder().encode(before));
|
|
6878
|
+
await file.close();
|
|
6879
|
+
} catch (err) {
|
|
6880
|
+
await say(2, "crontab: " + tmp + ": " + (err && err.code ? err.code : String(err)) + "\\n");
|
|
6881
|
+
return 1;
|
|
6882
|
+
}
|
|
6883
|
+
const child = await ctx.spawn({ argv: ["/bin/bash", "-c", editor + ' "$1"', "crontab", tmp] });
|
|
6884
|
+
const ended = await ctx.wait(child.pid);
|
|
6885
|
+
if (ended.status !== 0) {
|
|
6886
|
+
await say(2, "crontab: the editor exited with status " + ended.status + ", crontab not changed\\n");
|
|
6887
|
+
await ctx.fs.rm(tmp).catch(() => undefined);
|
|
6888
|
+
return 1;
|
|
6889
|
+
}
|
|
6890
|
+
const after = decode(await ctx.fs.readFile(tmp));
|
|
6891
|
+
if (after === before) {
|
|
6892
|
+
await say(2, "crontab: no changes made to crontab\\n");
|
|
6893
|
+
await ctx.fs.rm(tmp).catch(() => undefined);
|
|
6894
|
+
return 0;
|
|
6895
|
+
}
|
|
6896
|
+
const answer = await call({ action: "install", text: after });
|
|
6897
|
+
if (answer.error !== undefined) {
|
|
6898
|
+
await say(2, answer.error + "\\ncrontab: your edit is kept in " + tmp + "\\n");
|
|
6899
|
+
return 1;
|
|
6900
|
+
}
|
|
6901
|
+
await ctx.fs.rm(tmp).catch(() => undefined);
|
|
6902
|
+
return 0;
|
|
6903
|
+
}
|
|
6904
|
+
}
|
|
6905
|
+
`;
|
|
6814
6906
|
|
|
6815
6907
|
// src/cron/schedule.ts
|
|
6816
6908
|
var MISSED_CAP = 1e5;
|
|
@@ -7056,6 +7148,83 @@ function parseCrontab(text, path, system = false) {
|
|
|
7056
7148
|
return { jobs, errors };
|
|
7057
7149
|
}
|
|
7058
7150
|
|
|
7151
|
+
// src/cron/crontab.ts
|
|
7152
|
+
var CRONTAB_MAX = 256 * 1024;
|
|
7153
|
+
var ACTIONS = /* @__PURE__ */ new Set(["list", "remove", "install"]);
|
|
7154
|
+
function crontabCall(req) {
|
|
7155
|
+
const { action, user, text } = req;
|
|
7156
|
+
if (typeof action !== "string" || !ACTIONS.has(action)) return void 0;
|
|
7157
|
+
if (user !== void 0 && typeof user !== "string") return void 0;
|
|
7158
|
+
if (action === "install" && typeof text !== "string") return void 0;
|
|
7159
|
+
return {
|
|
7160
|
+
op: "proc-crontab",
|
|
7161
|
+
action,
|
|
7162
|
+
...user !== void 0 ? { user } : {},
|
|
7163
|
+
...action === "install" ? { text } : {}
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
var Crontabs = class {
|
|
7167
|
+
o;
|
|
7168
|
+
constructor(options) {
|
|
7169
|
+
this.o = options;
|
|
7170
|
+
}
|
|
7171
|
+
async request(cred, call) {
|
|
7172
|
+
const caller = await this.o.lookup(cred.ruid);
|
|
7173
|
+
if (!caller) return { error: `crontab: your uid ${cred.ruid} is not in /etc/passwd` };
|
|
7174
|
+
let target = caller;
|
|
7175
|
+
if (call.user !== void 0 && call.user !== caller.name) {
|
|
7176
|
+
if (cred.euid !== 0) return { error: "crontab: must be privileged to use -u" };
|
|
7177
|
+
const found = await this.o.lookup(call.user);
|
|
7178
|
+
if (!found) return { error: `crontab: user ${call.user} unknown` };
|
|
7179
|
+
target = found;
|
|
7180
|
+
}
|
|
7181
|
+
const path = `${SPOOL_DIR}/${target.name}`;
|
|
7182
|
+
const none = { error: `no crontab for ${target.name}` };
|
|
7183
|
+
const { fs } = this.o;
|
|
7184
|
+
if (call.action === "install") return this.install(path, target, call.text);
|
|
7185
|
+
if (!await fs.exists(path)) return none;
|
|
7186
|
+
if (call.action === "list") return { text: await fs.readFile(path) };
|
|
7187
|
+
await fs.rm(path);
|
|
7188
|
+
return { text: "" };
|
|
7189
|
+
}
|
|
7190
|
+
async install(path, target, text) {
|
|
7191
|
+
if (text.length > CRONTAB_MAX) return { error: "crontab: the table is too long" };
|
|
7192
|
+
const { errors } = parseCrontab(text, path);
|
|
7193
|
+
if (errors.length > 0) {
|
|
7194
|
+
const lines2 = errors.map(({ line, message: message3 }) => `"-":${line}: ${message3}`);
|
|
7195
|
+
return { error: ["crontab: errors in crontab file, cannot install", ...lines2].join("\n") };
|
|
7196
|
+
}
|
|
7197
|
+
const { fs, owners } = this.o;
|
|
7198
|
+
if (!await fs.exists(SPOOL_DIR)) {
|
|
7199
|
+
await fs.mkdir(SPOOL_DIR, { recursive: true });
|
|
7200
|
+
if (owners) await fs.chown?.(SPOOL_DIR, { uid: 0, gid: 0, mode: 448, follow: false });
|
|
7201
|
+
}
|
|
7202
|
+
const fresh2 = `${SPOOL_DIR}/.${target.name}.${crypto.randomUUID()}.new`;
|
|
7203
|
+
const owner = owners ? { uid: target.uid, gid: target.gid, mode: 384 } : void 0;
|
|
7204
|
+
await fs.writeFile(fresh2, text, owner);
|
|
7205
|
+
await fs.rename(fresh2, path);
|
|
7206
|
+
return { text: "" };
|
|
7207
|
+
}
|
|
7208
|
+
};
|
|
7209
|
+
|
|
7210
|
+
// src/cron/clock.ts
|
|
7211
|
+
var systemCronClock = {
|
|
7212
|
+
now: () => Date.now(),
|
|
7213
|
+
sleep(until, signal) {
|
|
7214
|
+
if (signal.aborted) return Promise.resolve();
|
|
7215
|
+
return new Promise((resolve2) => {
|
|
7216
|
+
const done4 = () => {
|
|
7217
|
+
clearTimeout(timer);
|
|
7218
|
+
signal.removeEventListener("abort", done4);
|
|
7219
|
+
resolve2();
|
|
7220
|
+
};
|
|
7221
|
+
const timer = setTimeout(done4, Math.max(0, until - Date.now()));
|
|
7222
|
+
timer.unref?.();
|
|
7223
|
+
signal.addEventListener("abort", done4, { once: true });
|
|
7224
|
+
});
|
|
7225
|
+
}
|
|
7226
|
+
};
|
|
7227
|
+
|
|
7059
7228
|
// src/cron/service.ts
|
|
7060
7229
|
var CRON_DIR = "/var/spool/cron";
|
|
7061
7230
|
var STAMP_PATH = `${CRON_DIR}/stamp`;
|
|
@@ -7232,7 +7401,7 @@ var CronService = class {
|
|
|
7232
7401
|
}
|
|
7233
7402
|
const names = await fs.readdir(SPOOL_DIR).catch(() => []);
|
|
7234
7403
|
for (const name2 of names.sort()) {
|
|
7235
|
-
if (name2.startsWith(".") || name2.endsWith("~")
|
|
7404
|
+
if (name2.startsWith(".") || name2.endsWith("~")) continue;
|
|
7236
7405
|
const path = `${SPOOL_DIR}/${name2}`;
|
|
7237
7406
|
const account = await this.host.lookup(name2);
|
|
7238
7407
|
if (!account) {
|
|
@@ -11391,12 +11560,11 @@ function attachSyncSabResponder(port, sab, token, opts) {
|
|
|
11391
11560
|
if (disposed) return;
|
|
11392
11561
|
const { status, payload } = encodeSabResult(result);
|
|
11393
11562
|
drop(id2);
|
|
11394
|
-
const entry = {
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
}
|
|
11399
|
-
pending.set(id2, entry);
|
|
11563
|
+
const entry = { status, payload };
|
|
11564
|
+
if (payload.byteLength > window.byteLength) {
|
|
11565
|
+
entry.timer = setTimeout(() => drop(id2), PENDING_TTL_MS);
|
|
11566
|
+
pending.set(id2, entry);
|
|
11567
|
+
}
|
|
11400
11568
|
publish(id2, entry, 0);
|
|
11401
11569
|
}
|
|
11402
11570
|
const handler = (event) => {
|
|
@@ -12106,6 +12274,8 @@ var AsyncRangedFile = class {
|
|
|
12106
12274
|
|
|
12107
12275
|
// src/realm/sync-sab-bridge.ts
|
|
12108
12276
|
var PATH_OPS = new Set(SYNC_FS_OPS);
|
|
12277
|
+
var SPIN_CORES = 4;
|
|
12278
|
+
var spinning = (globalThis.navigator?.hardwareConcurrency ?? 0) >= SPIN_CORES;
|
|
12109
12279
|
|
|
12110
12280
|
// src/realm/live-vfs-fs.ts
|
|
12111
12281
|
var EARLY_WHOLE_FILE = 64 * 1024;
|
|
@@ -16583,6 +16753,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
16583
16753
|
"proc-wait",
|
|
16584
16754
|
"proc-captured",
|
|
16585
16755
|
"proc-sudo",
|
|
16756
|
+
"proc-crontab",
|
|
16586
16757
|
"proc-run",
|
|
16587
16758
|
"proc-exit",
|
|
16588
16759
|
"proc-kill-self",
|
|
@@ -17772,8 +17943,17 @@ var WasmProcess = class {
|
|
|
17772
17943
|
return { ok: true, kind: "bytes", bytes: this.children.captured(req.pid, req.slot) };
|
|
17773
17944
|
case "proc-sudo":
|
|
17774
17945
|
return { ok: true, kind: "json", json: await this.sudo(req, cancelled) };
|
|
17946
|
+
case "proc-crontab":
|
|
17947
|
+
return { ok: true, kind: "json", json: await this.crontab(req) };
|
|
17775
17948
|
}
|
|
17776
17949
|
}
|
|
17950
|
+
async crontab(req) {
|
|
17951
|
+
const { crontab } = this.options;
|
|
17952
|
+
if (!crontab) throw new KernelError("ENOSYS");
|
|
17953
|
+
const call = crontabCall(req);
|
|
17954
|
+
if (!call) throw new KernelError("EINVAL");
|
|
17955
|
+
return crontab(call);
|
|
17956
|
+
}
|
|
17777
17957
|
signalSyscall(req) {
|
|
17778
17958
|
if (req.op === "sig-inherited") {
|
|
17779
17959
|
return { ok: true, kind: "json", json: this.inherited & ~this.caught };
|
|
@@ -18176,6 +18356,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
18176
18356
|
...opts.writesBack ? { writesBack: opts.writesBack } : {},
|
|
18177
18357
|
processes: opts.processes,
|
|
18178
18358
|
...opts.sudo ? { sudo: opts.sudo } : {},
|
|
18359
|
+
...opts.crontab ? { crontab: opts.crontab } : {},
|
|
18179
18360
|
openFiles: opts.openFiles,
|
|
18180
18361
|
...opts.nodes ? { nodes: opts.nodes } : {},
|
|
18181
18362
|
mounts: opts.mounts,
|
|
@@ -21711,6 +21892,7 @@ var LAYOUT = [
|
|
|
21711
21892
|
["/usr", 493],
|
|
21712
21893
|
["/usr/local", 493]
|
|
21713
21894
|
];
|
|
21895
|
+
var IN_TREE = /* @__PURE__ */ new Set([SUDO_PATH, CRONTAB_PATH]);
|
|
21714
21896
|
var LOAD_SAMPLE_MS = 5e3;
|
|
21715
21897
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
21716
21898
|
var encoder8 = new TextEncoder();
|
|
@@ -21941,6 +22123,7 @@ var Launcher = class {
|
|
|
21941
22123
|
boot = Date.now();
|
|
21942
22124
|
bootId = crypto.randomUUID();
|
|
21943
22125
|
cron;
|
|
22126
|
+
crontabs;
|
|
21944
22127
|
terminals = 0;
|
|
21945
22128
|
constructor(options) {
|
|
21946
22129
|
this.usersMode = usersMode(options.users);
|
|
@@ -22141,7 +22324,9 @@ var Launcher = class {
|
|
|
22141
22324
|
found = this.trustedAppended().then(async (appended2) => {
|
|
22142
22325
|
const tiers = await this.tiers(scope, appended2);
|
|
22143
22326
|
return scanCommands(this.scanned, tiers, tiers.length - appended2.length);
|
|
22144
|
-
}).then(
|
|
22327
|
+
}).then(
|
|
22328
|
+
(commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND).set(CRONTAB_COMMAND.name, CRONTAB_COMMAND)
|
|
22329
|
+
);
|
|
22145
22330
|
this.catalogs.set(scope, found);
|
|
22146
22331
|
}
|
|
22147
22332
|
return found;
|
|
@@ -22546,7 +22731,7 @@ var Launcher = class {
|
|
|
22546
22731
|
const root = packageRootOf(at, roots) ?? PACKAGE_ROOT.exec(at)?.[1];
|
|
22547
22732
|
if (root !== void 0) files.push(`${root}/package.json`);
|
|
22548
22733
|
}
|
|
22549
|
-
return [...new Set(files)].filter((path) => path !== "" && path
|
|
22734
|
+
return [...new Set(files)].filter((path) => path !== "" && !IN_TREE.has(path));
|
|
22550
22735
|
}
|
|
22551
22736
|
async unrunnable(file, cwd, scope) {
|
|
22552
22737
|
const path = this.fs.resolvePath(cwd, file);
|
|
@@ -22686,6 +22871,9 @@ var Launcher = class {
|
|
|
22686
22871
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
22687
22872
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
22688
22873
|
}
|
|
22874
|
+
if (target.abi === "js" && target.wasm === CRONTAB_PATH) {
|
|
22875
|
+
return { abi: "js", glue: CRONTAB_SOURCE, path: CRONTAB_PATH };
|
|
22876
|
+
}
|
|
22689
22877
|
if (target.abi === "js" && target.wasm === REFUSED_PATH) {
|
|
22690
22878
|
return { abi: "js", glue: REFUSED_SOURCE, path: REFUSED_PATH };
|
|
22691
22879
|
}
|
|
@@ -22841,6 +23029,7 @@ var Launcher = class {
|
|
|
22841
23029
|
cpu: this.cpuTotal()
|
|
22842
23030
|
}),
|
|
22843
23031
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
23032
|
+
crontab: (call) => this.crontab(pid, call),
|
|
22844
23033
|
openFiles: this.openFiles,
|
|
22845
23034
|
nodes: stack.nodes,
|
|
22846
23035
|
held: this.held,
|
|
@@ -23059,6 +23248,14 @@ var Launcher = class {
|
|
|
23059
23248
|
const threads = this.stateOf(pid) === "S" ? this.processes.get(pid)?.threads?.() : void 0;
|
|
23060
23249
|
return threads ? { threads } : {};
|
|
23061
23250
|
}
|
|
23251
|
+
crontab(pid, call) {
|
|
23252
|
+
this.crontabs ??= new Crontabs({
|
|
23253
|
+
fs: this.fs,
|
|
23254
|
+
owners: this.owners,
|
|
23255
|
+
lookup: (user) => this.users.lookup(user)
|
|
23256
|
+
});
|
|
23257
|
+
return this.crontabs.request(this.credOf(pid), call);
|
|
23258
|
+
}
|
|
23062
23259
|
sudo(pid, call, signal) {
|
|
23063
23260
|
const caller = {
|
|
23064
23261
|
cred: this.credOf(pid),
|