This commit is contained in:
Raven Scott
2026-04-03 19:49:21 -04:00
parent 76dc3ecb7c
commit 4dfee8398b
19 changed files with 504 additions and 250 deletions
+9 -9
View File
@@ -4,22 +4,22 @@ Files in this directory are **read from disk by the seeder** (or copied into `pa
## Staging map (seeder)
| Source | Drive path |
| ----------------- | --------------------- |
| `init.js` | `/boot/init.js` |
| `bin/<name>` | `/bin/<name>` |
| `etc/...` | `/etc/...` |
| `share/man/...` | `/share/man/...` |
| Any other file | `/<relative path>` |
| Source | Drive path |
| --------------- | ------------------ |
| `init.js` | `/boot/init.js` |
| `bin/<name>` | `/bin/<name>` |
| `etc/...` | `/etc/...` |
| `share/man/...` | `/share/man/...` |
| Any other file | `/<relative path>` |
## 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`**) → **`/etc/bare-os/rc`** → **`/etc/bare-os/rc.d/*`** (sorted; only names starting with a digit, plus skips dotfiles, `*~`, `README*`, `*.md`) → banner → when **`BARE_OS_SKIP_REPL`**, optional one line from **`BARE_OS_ONBOOT`** or **`/etc/bare-os/onboot`** → **`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 and pseudo path lists ([`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`**) → **`/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`** → 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)).
- **`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`, …).
- **`etc/motd`** — Optional message printed after **`os-release`** (distributors can customize).
- **`etc/bare-os/banner`** or **`/etc/issue`** — If present on the system drive, the default kernel prints one of these instead of the built-in session hint (unless **`BARE_OS_SKIP_REPL`** shortens the banner). Set **`BARE_OS_BOOT_TRACE=1`** in the session environment to log boot phase timings on stderr.
- **`etc/bare-os/banner`** or **`/etc/issue`** — If present on the system drive, the default kernel prints one of these instead of the built-in session hint (unless **`BARE_OS_SKIP_REPL`** shortens the banner). Set **`BARE_OS_BOOT_TRACE=1`** or **`true`** for **`[boot] phase: Nms`** lines on stderr, or **`json`** for **`{"phase":"…","ms":n}`** per phase.
- **`etc/bare-os/rc`** — Optional boot snippet: one **`execLine`** per non-comment line (trusted).
- **`etc/bare-os/rc.d/`** — Optional extra snippets (basename must start with a digit), same line rules, run after **`rc`** in filename order. Human-oriented notes live in **`.README`** (a dotfile so legacy **`init.js`** never executes it).
+23 -5
View File
@@ -60,7 +60,11 @@ function barePosixBlocks(size) {
return Math.ceil(Number(size) / 512) || 0
}
async function walk(ctx, dir, nameRe, wantType, maxDepth, curDepth) {
/**
* curDepth is distance from the search root directory (0 at the initial path).
* Printed paths use gnu-like depth curDepth + 1 (immediate children of the root are depth 1).
*/
async function walk(ctx, dir, nameRe, wantType, maxDepth, minDepth, curDepth) {
if (maxDepth >= 0 && curDepth > maxDepth) return
let names
try {
@@ -78,15 +82,21 @@ async function walk(ctx, dir, nameRe, wantType, maxDepth, curDepth) {
continue
}
if (!st) continue
const gnuDepth = curDepth + 1
if (!nameRe || nameRe.test(n)) {
if (!wantType || st.type === wantType) ctx.console.log(path)
if (!wantType || st.type === wantType) {
if (gnuDepth >= minDepth) ctx.console.log(path)
}
}
if (st.type === 'directory') await walk(ctx, path, nameRe, wantType, maxDepth, curDepth + 1)
if (st.type === 'directory')
await walk(ctx, path, nameRe, wantType, maxDepth, minDepth, curDepth + 1)
}
}
async function run(ctx, argv) {
let maxDepth = -1
/** Minimum path depth below the search root (1 = default; same as GNU -mindepth 1 for tree walks). */
let minDepth = 1
/** @type {string | null} */
let nameGlob = null
/** @type {'file' | 'directory' | 'symlink' | null} */
@@ -98,6 +108,11 @@ async function run(ctx, argv) {
maxDepth = Number.parseInt(argv[++i], 10)
continue
}
if (a === '-mindepth' && argv[i + 1]) {
minDepth = Number.parseInt(argv[++i], 10)
if (!Number.isFinite(minDepth) || minDepth < 1) minDepth = 1
continue
}
if (a === '-name' && argv[i + 1]) {
nameGlob = argv[++i]
continue
@@ -123,9 +138,12 @@ async function run(ctx, argv) {
const root = rest[0] || '.'
let nameRe = null
if (nameGlob) {
const esc = nameGlob.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*').replace(/\?/g, '.')
const esc = nameGlob
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
.replace(/\*/g, '.*')
.replace(/\?/g, '.')
nameRe = new RegExp('^' + esc + '$')
}
const abs = ctx.vfs.resolveLogical(root)
await walk(ctx, abs, nameRe, wantType, maxDepth, 0)
await walk(ctx, abs, nameRe, wantType, maxDepth, minDepth, 0)
}
+41 -18
View File
@@ -3,14 +3,17 @@
* Loaded by the booter with an injected ctx object (trusted replication source).
*
* Boot order: /etc/os-release → /etc/motd → optional profile rc → /etc/bare-os/rc →
* /etc/bare-os/rc.d/* (sorted; digit-prefixed snippet names) → session banner
* optional oneshot onboot when BARE_OS_SKIP_REPL → interactive loop.
* /etc/bare-os/rc.d/* (sorted; digit-prefixed snippet names) → /etc/bare-os/rc.local
* session banner → optional onboot lines when BARE_OS_SKIP_REPL → interactive loop.
*
* Profile: first non-empty line of /etc/bare-os/profile, overridden by BARE_OS_BOOT_PROFILE.
* When set, runs /etc/bare-os/rc.profile.<name> if present (trusted execLine, before main rc).
*
* Non-interactive onboot: when ctx.bareOsSkipRepl, runs one line from BARE_OS_ONBOOT env
* or first non-empty, non-# line from /etc/bare-os/onboot (trusted), then readLine yields EOF.
* Non-interactive onboot: when ctx.bareOsSkipRepl, runs each non-empty, non-# line from
* BARE_OS_ONBOOT (newline-separated) or, if unset, every such line from /etc/bare-os/onboot
* in file order (trusted). Then readLine yields EOF.
*
* BARE_OS_BOOT_TRACE=json logs one JSON object per phase on stderr: {"phase":"…","ms":n}.
*
* Use ctx.registerKernelShutdownHook(fn) for teardown before initd disposers.
*/
@@ -20,7 +23,14 @@
*/
function wantBootTrace(ctx) {
const v = ctx.env && ctx.env.BARE_OS_BOOT_TRACE
return v === '1' || v === 'true'
return v === '1' || v === 'true' || v === 'json'
}
/**
* @param {Record<string, unknown>} ctx
*/
function isBootTraceJson(ctx) {
return ctx.env && ctx.env.BARE_OS_BOOT_TRACE === 'json'
}
/**
@@ -32,7 +42,12 @@ async function bootTimed(ctx, label, fn) {
const t0 = Date.now()
await fn()
if (wantBootTrace(ctx)) {
ctx.console.error(`[boot] ${label}: ${Date.now() - t0}ms`)
const ms = Date.now() - t0
if (isBootTraceJson(ctx)) {
ctx.console.error(JSON.stringify({ phase: label, ms }))
} else {
ctx.console.error(`[boot] ${label}: ${ms}ms`)
}
}
}
@@ -120,16 +135,21 @@ async function runProfileRc(ctx, profileName) {
}
/**
* When stdin is non-interactive, run a single trusted boot command (automation).
* When stdin is non-interactive, run trusted boot commands (automation).
* @param {Record<string, unknown>} ctx
*/
async function runOnbootOnce(ctx) {
async function runOnboot(ctx) {
if (!ctx.bareOsSkipRepl) return
const { execLine, console, drive, b4a, env } = ctx
let line = ''
/** @type {string[]} */
const lines = []
const fromEnv = env && env.BARE_OS_ONBOOT
if (fromEnv != null && String(fromEnv).trim()) {
line = String(fromEnv).trim()
for (const raw of String(fromEnv).split(/\r?\n/)) {
const t = raw.trim()
if (!t || t.startsWith('#')) continue
lines.push(t)
}
} else {
try {
const buf = await drive.get('/etc/bare-os/onboot')
@@ -137,19 +157,19 @@ async function runOnbootOnce(ctx) {
for (const raw of b4a.toString(buf).split(/\r?\n/)) {
const t = raw.trim()
if (!t || t.startsWith('#')) continue
line = t
break
lines.push(t)
}
}
} catch (e) {
console.error('onboot: ' + ((e && e.message) || String(e)))
}
}
if (!line) return
try {
await execLine(line)
} catch (e) {
console.error((e && e.message) || String(e))
for (const line of lines) {
try {
await execLine(line)
} catch (e) {
console.error((e && e.message) || String(e))
}
}
}
@@ -247,8 +267,11 @@ async function start(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 printSessionBanner(ctx)
await bootTimed(ctx, 'onboot', () => runOnbootOnce(ctx))
await bootTimed(ctx, 'onboot', () => runOnboot(ctx))
while (true) {
const line = await readLine('')
if (line == null) break
File diff suppressed because one or more lines are too long