@ai-ecoverse/slicc-kernel 1.108.5 → 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 +430 -234
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +2 -1
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +216 -20
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +2 -1
- 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) {
|
|
@@ -16584,6 +16753,7 @@ var SYSCALL_OPS = /* @__PURE__ */ new Set([
|
|
|
16584
16753
|
"proc-wait",
|
|
16585
16754
|
"proc-captured",
|
|
16586
16755
|
"proc-sudo",
|
|
16756
|
+
"proc-crontab",
|
|
16587
16757
|
"proc-run",
|
|
16588
16758
|
"proc-exit",
|
|
16589
16759
|
"proc-kill-self",
|
|
@@ -17773,8 +17943,17 @@ var WasmProcess = class {
|
|
|
17773
17943
|
return { ok: true, kind: "bytes", bytes: this.children.captured(req.pid, req.slot) };
|
|
17774
17944
|
case "proc-sudo":
|
|
17775
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) };
|
|
17776
17948
|
}
|
|
17777
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
|
+
}
|
|
17778
17957
|
signalSyscall(req) {
|
|
17779
17958
|
if (req.op === "sig-inherited") {
|
|
17780
17959
|
return { ok: true, kind: "json", json: this.inherited & ~this.caught };
|
|
@@ -18177,6 +18356,7 @@ function processOptions(opts, header4, hooks, created3) {
|
|
|
18177
18356
|
...opts.writesBack ? { writesBack: opts.writesBack } : {},
|
|
18178
18357
|
processes: opts.processes,
|
|
18179
18358
|
...opts.sudo ? { sudo: opts.sudo } : {},
|
|
18359
|
+
...opts.crontab ? { crontab: opts.crontab } : {},
|
|
18180
18360
|
openFiles: opts.openFiles,
|
|
18181
18361
|
...opts.nodes ? { nodes: opts.nodes } : {},
|
|
18182
18362
|
mounts: opts.mounts,
|
|
@@ -21712,6 +21892,7 @@ var LAYOUT = [
|
|
|
21712
21892
|
["/usr", 493],
|
|
21713
21893
|
["/usr/local", 493]
|
|
21714
21894
|
];
|
|
21895
|
+
var IN_TREE = /* @__PURE__ */ new Set([SUDO_PATH, CRONTAB_PATH]);
|
|
21715
21896
|
var LOAD_SAMPLE_MS = 5e3;
|
|
21716
21897
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
21717
21898
|
var encoder8 = new TextEncoder();
|
|
@@ -21942,6 +22123,7 @@ var Launcher = class {
|
|
|
21942
22123
|
boot = Date.now();
|
|
21943
22124
|
bootId = crypto.randomUUID();
|
|
21944
22125
|
cron;
|
|
22126
|
+
crontabs;
|
|
21945
22127
|
terminals = 0;
|
|
21946
22128
|
constructor(options) {
|
|
21947
22129
|
this.usersMode = usersMode(options.users);
|
|
@@ -22142,7 +22324,9 @@ var Launcher = class {
|
|
|
22142
22324
|
found = this.trustedAppended().then(async (appended2) => {
|
|
22143
22325
|
const tiers = await this.tiers(scope, appended2);
|
|
22144
22326
|
return scanCommands(this.scanned, tiers, tiers.length - appended2.length);
|
|
22145
|
-
}).then(
|
|
22327
|
+
}).then(
|
|
22328
|
+
(commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND).set(CRONTAB_COMMAND.name, CRONTAB_COMMAND)
|
|
22329
|
+
);
|
|
22146
22330
|
this.catalogs.set(scope, found);
|
|
22147
22331
|
}
|
|
22148
22332
|
return found;
|
|
@@ -22547,7 +22731,7 @@ var Launcher = class {
|
|
|
22547
22731
|
const root = packageRootOf(at, roots) ?? PACKAGE_ROOT.exec(at)?.[1];
|
|
22548
22732
|
if (root !== void 0) files.push(`${root}/package.json`);
|
|
22549
22733
|
}
|
|
22550
|
-
return [...new Set(files)].filter((path) => path !== "" && path
|
|
22734
|
+
return [...new Set(files)].filter((path) => path !== "" && !IN_TREE.has(path));
|
|
22551
22735
|
}
|
|
22552
22736
|
async unrunnable(file, cwd, scope) {
|
|
22553
22737
|
const path = this.fs.resolvePath(cwd, file);
|
|
@@ -22687,6 +22871,9 @@ var Launcher = class {
|
|
|
22687
22871
|
if (target.abi === "js" && target.wasm === SUDO_PATH) {
|
|
22688
22872
|
return { abi: "js", glue: SUDO_SOURCE, path: SUDO_PATH };
|
|
22689
22873
|
}
|
|
22874
|
+
if (target.abi === "js" && target.wasm === CRONTAB_PATH) {
|
|
22875
|
+
return { abi: "js", glue: CRONTAB_SOURCE, path: CRONTAB_PATH };
|
|
22876
|
+
}
|
|
22690
22877
|
if (target.abi === "js" && target.wasm === REFUSED_PATH) {
|
|
22691
22878
|
return { abi: "js", glue: REFUSED_SOURCE, path: REFUSED_PATH };
|
|
22692
22879
|
}
|
|
@@ -22842,6 +23029,7 @@ var Launcher = class {
|
|
|
22842
23029
|
cpu: this.cpuTotal()
|
|
22843
23030
|
}),
|
|
22844
23031
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
23032
|
+
crontab: (call) => this.crontab(pid, call),
|
|
22845
23033
|
openFiles: this.openFiles,
|
|
22846
23034
|
nodes: stack.nodes,
|
|
22847
23035
|
held: this.held,
|
|
@@ -23060,6 +23248,14 @@ var Launcher = class {
|
|
|
23060
23248
|
const threads = this.stateOf(pid) === "S" ? this.processes.get(pid)?.threads?.() : void 0;
|
|
23061
23249
|
return threads ? { threads } : {};
|
|
23062
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
|
+
}
|
|
23063
23259
|
sudo(pid, call, signal) {
|
|
23064
23260
|
const caller = {
|
|
23065
23261
|
cred: this.credOf(pid),
|