Files
bare-operating-system/packages/bare-os-seeder/kernel/init.js
T
2026-04-03 19:13:20 -04:00

181 lines
4.9 KiB
JavaScript

/**
* Hyperdrive-resident kernel (staged as /boot/init.js).
* Loaded by the booter with an injected ctx object (trusted replication source).
*
* Boot order: /etc/os-release → /etc/motd → /etc/bare-os/rc → /etc/bare-os/rc.d/*
* (sorted; digit-prefixed snippet names) → session banner → interactive loop.
* Use ctx.registerKernelShutdownHook(fn) for teardown before initd disposers.
*/
/**
* @param {Record<string, unknown>} ctx
*/
function wantBootTrace(ctx) {
const v = ctx.env && ctx.env.BARE_OS_BOOT_TRACE
return v === '1' || v === 'true'
}
/**
* @param {Record<string, unknown>} ctx
* @param {string} label
* @param {() => void | Promise<void>} fn
*/
async function bootTimed(ctx, label, fn) {
const t0 = Date.now()
await fn()
if (wantBootTrace(ctx)) {
ctx.console.error(`[boot] ${label}: ${Date.now() - t0}ms`)
}
}
/**
* @param {Record<string, unknown>} ctx
* @param {string} text
*/
async function runRcLines(ctx, text) {
const { execLine, console } = ctx
for (const line of text.split(/\r?\n/)) {
const t = line.trim()
if (!t || t.startsWith('#')) continue
try {
await execLine(t)
} catch (e) {
console.error((e && e.message) || String(e))
}
}
}
/**
* @param {Record<string, unknown>} ctx
*/
async function printOsRelease(ctx) {
const { drive, b4a, console } = ctx
try {
const rel = await drive.get('/etc/os-release')
if (rel) console.log(b4a.toString(rel))
} catch (e) {
console.error((e && e.message) || String(e))
}
}
/**
* @param {Record<string, unknown>} ctx
*/
async function printMotd(ctx) {
const { drive, b4a, console } = ctx
try {
const motd = await drive.get('/etc/motd')
if (motd) console.log(b4a.toString(motd).trimEnd())
} catch (e) {
console.error((e && e.message) || String(e))
}
}
/**
* @param {Record<string, unknown>} ctx
* @param {string} drivePath absolute path on system drive
* @param {string} label for errors
*/
async function runRcFileAt(ctx, drivePath, label) {
const { drive, b4a, console } = ctx
try {
const buf = await drive.get(drivePath)
if (!buf) return
await runRcLines(ctx, b4a.toString(buf))
} catch (e) {
console.error(`${label}: ` + ((e && e.message) || String(e)))
}
}
/**
* Only run rc.d files whose name starts with a digit (e.g. `10-local`).
* Skips README*, *.md, dotfiles, and *~ so documentation is never exec'd as shell.
* @param {string} name basename from readdir
*/
function isBareOsRcSnippetFile(name) {
if (!name || name.startsWith('.') || name.endsWith('~')) return false
if (/^README(\.|$)/i.test(name)) return false
if (/\.md$/i.test(name)) return false
return /^[0-9]/.test(name)
}
/**
* Optional snippets under /etc/bare-os/rc.d/ — executed in lexicographic order.
* @param {Record<string, unknown>} ctx
*/
async function runBareOsRcDir(ctx) {
const { drive, b4a, console } = ctx
try {
/** @type {string[]} */
const names = []
try {
for await (const n of drive.readdir('/etc/bare-os/rc.d')) names.push(n)
} catch {
return
}
names.sort()
for (const name of names) {
if (!isBareOsRcSnippetFile(name)) continue
const p = `/etc/bare-os/rc.d/${name}`
try {
const buf = await drive.get(p)
if (!buf) continue
await runRcLines(ctx, b4a.toString(buf))
} catch (e) {
console.error(`rc.d/${name}: ` + ((e && e.message) || String(e)))
}
}
} catch (e) {
console.error((e && e.message) || String(e))
}
}
/**
* @param {Record<string, unknown>} ctx
*/
async function printSessionBanner(ctx) {
const { drive, b4a, console } = ctx
for (const p of ['/etc/bare-os/banner', '/etc/issue']) {
try {
const buf = await drive.get(p)
if (buf) {
console.log(b4a.toString(buf).trimEnd())
return
}
} catch {
/* ignore */
}
}
const defaultBanner =
'Bare operating system — guest session (login [--new] <passphrase> to unlock) | shell: cd, export, if/fi, && || ;, |, exit | services: systemctl list-units, journalctl -u UNIT | try: help, ls /bin, crontab -l'
if (ctx.bareOsSkipRepl) {
console.log(
'Bare operating system — non-interactive session (BARE_OS_SKIP_REPL).'
)
return
}
console.log(defaultBanner)
}
async function start(ctx) {
const { readLine, execLine, console } = ctx
await bootTimed(ctx, 'os-release', () => printOsRelease(ctx))
await bootTimed(ctx, 'motd', () => printMotd(ctx))
await bootTimed(ctx, 'rc', () => runRcFileAt(ctx, '/etc/bare-os/rc', 'rc'))
await bootTimed(ctx, 'rc.d', () => runBareOsRcDir(ctx))
await printSessionBanner(ctx)
while (true) {
const line = await readLine('')
if (line == null) break
const t = line.trim()
if (t === '') continue
let status = 'ok'
try {
status = await execLine(t)
} catch (e) {
console.error((e && e.message) || String(e))
}
if (status === 'exit') break
}
}