Updates
This commit is contained in:
+1
-1
@@ -14,7 +14,7 @@ Files in this directory are **read from disk by the seeder** (or copied into `pa
|
||||
|
||||
## Contents
|
||||
|
||||
- **`init.js`** — Kernel entry: must define `async function start(ctx)`. Boot order: **`/etc/os-release`** → **`/etc/motd`** → optional **`/etc/bare-os/rc.profile.<profile>`** (profile from **`BARE_OS_BOOT_PROFILE`** or first line of **`/etc/bare-os/profile`**; the booter mirrors the resolved name in **`ctx.env.BARE_OS_BOOT_PROFILE_RESOLVED`** and **`/run/bare-os/boot_profile`**) → **`/etc/bare-os/rc`** → **`/etc/bare-os/rc.d/*`** (sorted; only names starting with a digit, plus skips dotfiles, `*~`, `README*`, `*.md`) → optional **`/etc/bare-os/rc.local`** → **`/etc/bare-os/kernel.d/*`** (same rules as **`rc.d`**) → banner → when **`BARE_OS_SKIP_REPL`**, optional **onboot** lines from **`BARE_OS_ONBOOT`** (newline-separated) or **`/etc/bare-os/onboot`** (file order) → **`readLine` / `execLine`** loop (boot snippet errors are logged, not fatal). Custom kernels may call **`ctx.registerKernelShutdownHook(fn)`** before initd disposers; use **`ctx.bareOsRuntimeCaps`** for limits, pseudo paths, and **`features`** ([`developer-guide/02-the-context-object.md`](../developer-guide/02-the-context-object.md)).
|
||||
- **`init.js`** — Kernel entry: must define `async function start(ctx)`. Boot order: **`/etc/os-release`** → **`/etc/motd`** → optional **`/etc/bare-os/rc.profile.<profile>`** (profile from **`BARE_OS_BOOT_PROFILE`** or first line of **`/etc/bare-os/profile`**; the booter mirrors the resolved name in **`ctx.env.BARE_OS_BOOT_PROFILE_RESOLVED`** and **`/run/bare-os/boot_profile`**) → **`/etc/bare-os/rc`** → **`/etc/bare-os/rc.d/*`** (sorted; digit-prefixed names only; skip dotfiles, `*~`, `README*`, `*.md`; optional **`BARE_OS_RC_D_SKIP`** comma list and **`prefix*`** patterns) → optional **`/etc/bare-os/rc.local`** → **`/etc/bare-os/kernel.d/*`** (same rules as **`rc.d`**) → banner → when **`BARE_OS_SKIP_REPL`**, optional **onboot** lines from **`BARE_OS_ONBOOT`** or **`/etc/bare-os/onboot`** → **`readLine` / `execLine`** loop. Boot **`execLine`** errors in trusted snippets are logged; with **`BARE_OS_BOOT_STRICT=1`** or **`true`**, the first throw calls **`requestBooterExit(1)`** and stops later boot phases. Custom kernels may call **`ctx.registerKernelShutdownHook(fn)`** before initd disposers; use **`ctx.bareOsRuntimeCaps`** for limits, pseudo paths, and **`features`** ([`developer-guide/02-the-context-object.md`](../developer-guide/02-the-context-object.md)).
|
||||
- **`bin/`** — **Tier-1 utilities** built by [bare-os-coreutils](../packages/bare-os-coreutils/README.md). Each file is **`runtime.js`** + optional **`lib/*-engine.js`** (**`sed`**, **`awk`**) or **`lib/man-render.js`** (**`man`**) + **`async function run(ctx, argv)`** (no ESM **`import`** in **`src/`**).
|
||||
- **`share/man/man.json`** — Merged manual database for **`/bin/man`** (built by **`bare-os-coreutils`**; see [handbook ch.10](../handbook/10-manpages-and-online-help.md)).
|
||||
- **`etc/os-release`** — Static OS metadata (`NAME`, `VERSION`, …).
|
||||
|
||||
+103
-18
@@ -16,6 +16,12 @@
|
||||
*
|
||||
* BARE_OS_BOOT_TRACE=json logs one JSON object per phase on stderr: {"phase":"…","ms":n}.
|
||||
*
|
||||
* BARE_OS_BOOT_STRICT=1 or true: first execLine throw in trusted boot snippets calls
|
||||
* requestBooterExit(1) and stops further boot phases.
|
||||
*
|
||||
* BARE_OS_RC_D_SKIP: comma-separated rc.d basenames to skip; a pattern ending with * skips
|
||||
* names with that prefix (e.g. 10-* skips 10-foo).
|
||||
*
|
||||
* Use ctx.registerKernelShutdownHook(fn) for teardown before initd disposers.
|
||||
*/
|
||||
|
||||
@@ -34,6 +40,42 @@ function isBootTraceJson(ctx) {
|
||||
return ctx.env && ctx.env.BARE_OS_BOOT_TRACE === 'json'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
*/
|
||||
function bootStrict(ctx) {
|
||||
const v = ctx.env && ctx.env.BARE_OS_BOOT_STRICT
|
||||
return v === '1' || v === 'true'
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function parseRcDSkipPatterns(ctx) {
|
||||
const raw = ctx.env && ctx.env.BARE_OS_RC_D_SKIP
|
||||
if (raw == null || !String(raw).trim()) return []
|
||||
return String(raw)
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string[]} patterns
|
||||
*/
|
||||
function shouldSkipRcDName(name, patterns) {
|
||||
for (const p of patterns) {
|
||||
if (p === name) return true
|
||||
if (p.endsWith('*') && p.length > 1) {
|
||||
const pre = p.slice(0, -1)
|
||||
if (name.startsWith(pre)) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} label
|
||||
@@ -55,9 +97,11 @@ async function bootTimed(ctx, label, fn) {
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} text
|
||||
* @returns {Promise<boolean>} false if BARE_OS_BOOT_STRICT and a line threw
|
||||
*/
|
||||
async function runRcLines(ctx, text) {
|
||||
const { execLine, console } = ctx
|
||||
const strict = bootStrict(ctx)
|
||||
for (const line of text.split(/\r?\n/)) {
|
||||
const t = line.trim()
|
||||
if (!t || t.startsWith('#')) continue
|
||||
@@ -65,8 +109,13 @@ async function runRcLines(ctx, text) {
|
||||
await execLine(t)
|
||||
} catch (e) {
|
||||
console.error((e && e.message) || String(e))
|
||||
if (strict) {
|
||||
if (typeof ctx.requestBooterExit === 'function') ctx.requestBooterExit(1)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,17 +167,18 @@ async function resolveBootProfileName(ctx) {
|
||||
* Optional trusted snippet /etc/bare-os/rc.profile.<name> (before /etc/bare-os/rc).
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} profileName
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function runProfileRc(ctx, profileName) {
|
||||
if (!profileName) return
|
||||
if (!profileName) return true
|
||||
const safe = profileName.replace(/[^a-zA-Z0-9._-]/g, '')
|
||||
if (safe !== profileName) {
|
||||
ctx.console.error(
|
||||
'[boot] profile name contains unsupported characters; skipping rc.profile'
|
||||
)
|
||||
return
|
||||
return true
|
||||
}
|
||||
await runRcFileAt(
|
||||
return await runRcFileAt(
|
||||
ctx,
|
||||
`/etc/bare-os/rc.profile.${safe}`,
|
||||
`rc.profile.${safe}`
|
||||
@@ -138,10 +188,12 @@ async function runProfileRc(ctx, profileName) {
|
||||
/**
|
||||
* When stdin is non-interactive, run trusted boot commands (automation).
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function runOnboot(ctx) {
|
||||
if (!ctx.bareOsSkipRepl) return
|
||||
if (!ctx.bareOsSkipRepl) return true
|
||||
const { execLine, console, drive, b4a, env } = ctx
|
||||
const strict = bootStrict(ctx)
|
||||
/** @type {string[]} */
|
||||
const lines = []
|
||||
const fromEnv = env && env.BARE_OS_ONBOOT
|
||||
@@ -170,23 +222,30 @@ async function runOnboot(ctx) {
|
||||
await execLine(line)
|
||||
} catch (e) {
|
||||
console.error((e && e.message) || String(e))
|
||||
if (strict) {
|
||||
if (typeof ctx.requestBooterExit === 'function') ctx.requestBooterExit(1)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} drivePath absolute path on system drive
|
||||
* @param {string} label for errors
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
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))
|
||||
if (!buf) return true
|
||||
return await runRcLines(ctx, b4a.toString(buf))
|
||||
} catch (e) {
|
||||
console.error(`${label}: ` + ((e && e.message) || String(e)))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +264,7 @@ function isBareOsRcSnippetFile(name) {
|
||||
/**
|
||||
* Optional snippets under /etc/bare-os/kernel.d/ — same rules as rc.d; runs after rc.local.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function runBareOsKernelDir(ctx) {
|
||||
const { drive, b4a, console } = ctx
|
||||
@@ -214,7 +274,7 @@ async function runBareOsKernelDir(ctx) {
|
||||
try {
|
||||
for await (const n of drive.readdir('/etc/bare-os/kernel.d')) names.push(n)
|
||||
} catch {
|
||||
return
|
||||
return true
|
||||
}
|
||||
names.sort()
|
||||
for (const name of names) {
|
||||
@@ -223,7 +283,8 @@ async function runBareOsKernelDir(ctx) {
|
||||
try {
|
||||
const buf = await drive.get(p)
|
||||
if (!buf) continue
|
||||
await runRcLines(ctx, b4a.toString(buf))
|
||||
const cont = await runRcLines(ctx, b4a.toString(buf))
|
||||
if (!cont) return false
|
||||
} catch (e) {
|
||||
console.error(`kernel.d/${name}: ` + ((e && e.message) || String(e)))
|
||||
}
|
||||
@@ -231,30 +292,35 @@ async function runBareOsKernelDir(ctx) {
|
||||
} catch (e) {
|
||||
console.error((e && e.message) || String(e))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional snippets under /etc/bare-os/rc.d/ — executed in lexicographic order.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function runBareOsRcDir(ctx) {
|
||||
const { drive, b4a, console } = ctx
|
||||
const skip = parseRcDSkipPatterns(ctx)
|
||||
try {
|
||||
/** @type {string[]} */
|
||||
const names = []
|
||||
try {
|
||||
for await (const n of drive.readdir('/etc/bare-os/rc.d')) names.push(n)
|
||||
} catch {
|
||||
return
|
||||
return true
|
||||
}
|
||||
names.sort()
|
||||
for (const name of names) {
|
||||
if (!isBareOsRcSnippetFile(name)) continue
|
||||
if (shouldSkipRcDName(name, skip)) 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))
|
||||
const cont = await runRcLines(ctx, b4a.toString(buf))
|
||||
if (!cont) return false
|
||||
} catch (e) {
|
||||
console.error(`rc.d/${name}: ` + ((e && e.message) || String(e)))
|
||||
}
|
||||
@@ -262,6 +328,7 @@ async function runBareOsRcDir(ctx) {
|
||||
} catch (e) {
|
||||
console.error((e && e.message) || String(e))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -296,15 +363,33 @@ async function start(ctx) {
|
||||
await bootTimed(ctx, 'os-release', () => printOsRelease(ctx))
|
||||
await bootTimed(ctx, 'motd', () => printMotd(ctx))
|
||||
const profileName = await resolveBootProfileName(ctx)
|
||||
await bootTimed(ctx, 'rc.profile', () => runProfileRc(ctx, profileName))
|
||||
await bootTimed(ctx, 'rc', () => runRcFileAt(ctx, '/etc/bare-os/rc', 'rc'))
|
||||
await bootTimed(ctx, 'rc.d', () => runBareOsRcDir(ctx))
|
||||
await bootTimed(ctx, 'rc.local', () =>
|
||||
runRcFileAt(ctx, '/etc/bare-os/rc.local', 'rc.local')
|
||||
)
|
||||
await bootTimed(ctx, 'kernel.d', () => runBareOsKernelDir(ctx))
|
||||
/** @type {boolean} */
|
||||
let bootOk = true
|
||||
await bootTimed(ctx, 'rc.profile', async () => {
|
||||
bootOk = await runProfileRc(ctx, profileName)
|
||||
})
|
||||
if (!bootOk) return
|
||||
await bootTimed(ctx, 'rc', async () => {
|
||||
bootOk = await runRcFileAt(ctx, '/etc/bare-os/rc', 'rc')
|
||||
})
|
||||
if (!bootOk) return
|
||||
await bootTimed(ctx, 'rc.d', async () => {
|
||||
bootOk = await runBareOsRcDir(ctx)
|
||||
})
|
||||
if (!bootOk) return
|
||||
await bootTimed(ctx, 'rc.local', async () => {
|
||||
bootOk = await runRcFileAt(ctx, '/etc/bare-os/rc.local', 'rc.local')
|
||||
})
|
||||
if (!bootOk) return
|
||||
await bootTimed(ctx, 'kernel.d', async () => {
|
||||
bootOk = await runBareOsKernelDir(ctx)
|
||||
})
|
||||
if (!bootOk) return
|
||||
await printSessionBanner(ctx)
|
||||
await bootTimed(ctx, 'onboot', () => runOnboot(ctx))
|
||||
await bootTimed(ctx, 'onboot', async () => {
|
||||
bootOk = await runOnboot(ctx)
|
||||
})
|
||||
if (!bootOk) return
|
||||
while (true) {
|
||||
const line = await readLine('')
|
||||
if (line == null) break
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user