/** * 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} ctx */ function wantBootTrace(ctx) { const v = ctx.env && ctx.env.BARE_OS_BOOT_TRACE return v === '1' || v === 'true' } /** * @param {Record} ctx * @param {string} label * @param {() => void | Promise} 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} 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} 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} 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} 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} 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} 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] 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 } }