updates
This commit is contained in:
@@ -20,11 +20,11 @@ HTTP in Pear/Bare uses **WHATWG Fetch** (Node `fetch` or **`bare-fetch`** on `ba
|
||||
| `-f` / `--fail` | supported | Exit 22 |
|
||||
| `-s` / `-S` / `-v` | supported | |
|
||||
| `-u` / `--user` | supported | Basic auth only |
|
||||
| `-m` / `--max-time` | supported | Whole-request `AbortSignal` timeout (not separate connect timeout) |
|
||||
| `-m` / `--max-time` | supported | Whole-request `AbortSignal` timeout; combined with `--connect-timeout` as **`min(max-time, connect-timeout)`** when both are set |
|
||||
| `-w` / `--write-out` | partial | `%{http_code}`, `%{url_effective}`, `%{size_download}`; `%{num_redirects}` non-zero only for `-I -L` manual hop path |
|
||||
| `-V` / `--version`, `-h` / `--help` | supported | |
|
||||
| Cookie jar, `--cookie`, `-b`, `-c` / `--cookie-jar` | supported | JSON map `hostname → { name → value }` on **`~/.config/bare-os/curl/cookies.json`** (or path from `-c`); `-b` file or `name=value`; see `curl-cli.js` |
|
||||
| `--connect-timeout`, `-Y`, `-y` | out of scope | Fetch exposes one abort timer |
|
||||
| `--connect-timeout` | supported | Seconds (integer or decimal); sets the abort deadline when used alone, or **`min`** with **`--max-time`** when both are set. **`-Y` / `-y`** remain out of scope |
|
||||
| `--cacert`, `-k` / `--insecure` | partial | Node **undici** `Agent` when using global `fetch` (not when `ctx.httpFetch` is overridden) |
|
||||
| TLS client certs (mutual TLS) | out of scope | Stack only |
|
||||
| HTTP/2, HTTP/3, SOCKS, FTP, SCP | out of scope | |
|
||||
|
||||
@@ -242,6 +242,22 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
if (v != null && v !== '') shellEnv[k] = v
|
||||
}
|
||||
}
|
||||
let bootProfileResolved = ''
|
||||
const bpfEarly = shellEnv.BARE_OS_BOOT_PROFILE
|
||||
if (bpfEarly != null && String(bpfEarly).trim()) {
|
||||
bootProfileResolved = String(bpfEarly).trim()
|
||||
} else {
|
||||
try {
|
||||
const pbuf = await disk.drive.get('/etc/bare-os/profile')
|
||||
if (pbuf) {
|
||||
const line = b4a.toString(pbuf).split(/\r?\n/)[0] || ''
|
||||
bootProfileResolved = line.trim()
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
shellEnv.BARE_OS_BOOT_PROFILE_RESOLVED = bootProfileResolved
|
||||
/** @type {{ getMounts: () => Map<string, { drive: import('hyperdrive').default, writable: boolean }> }} */
|
||||
const vfsMountRef = { getMounts: () => new Map() }
|
||||
const bootStartedMs = Date.now()
|
||||
@@ -251,6 +267,9 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
cmdline: 'bare-os-booter'
|
||||
},
|
||||
bootStartedMs,
|
||||
bootProfileText() {
|
||||
return bootProfileResolved ? `${bootProfileResolved}\n` : '\n'
|
||||
},
|
||||
initdRunText() {
|
||||
const lines = [
|
||||
'# bare-initd units (name<TAB>phase<TAB>startedAtMs<TAB>description)',
|
||||
|
||||
@@ -33,6 +33,7 @@ export const BARE_OS_PSEUDO_FS_PATHS = Object.freeze([
|
||||
'/proc/version',
|
||||
'/run',
|
||||
'/run/bare-os',
|
||||
'/run/bare-os/boot_profile',
|
||||
'/run/bare-os/units',
|
||||
'/sys',
|
||||
'/sys/fs',
|
||||
|
||||
@@ -360,6 +360,8 @@ export async function runCurlCli(ctx, argv) {
|
||||
/** @type {string | null} */
|
||||
let writeOut = null
|
||||
let maxTimeMs = 0
|
||||
/** Whole-operation ceiling (Fetch has no separate connect phase; see CLI_PARITY.md). */
|
||||
let connectTimeMs = 0
|
||||
/** @type {string | null} */
|
||||
let userColonPass = null
|
||||
/** @type {string | null} */
|
||||
@@ -577,6 +579,23 @@ export async function runCurlCli(ctx, argv) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (a === '--connect-timeout') {
|
||||
if (i + 1 >= args.length) {
|
||||
ctx.console.error('curl: option requires an argument: --connect-timeout')
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
}
|
||||
const sec = Number(args[++i])
|
||||
if (!Number.isFinite(sec) || sec < 0) {
|
||||
ctx.console.error('curl: invalid --connect-timeout')
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
}
|
||||
connectTimeMs = Math.round(sec * 1000)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
if (a === '-k' || a === '--insecure') {
|
||||
insecureTls = true
|
||||
i++
|
||||
@@ -741,6 +760,13 @@ export async function runCurlCli(ctx, argv) {
|
||||
return
|
||||
}
|
||||
|
||||
const deadlineMs =
|
||||
maxTimeMs > 0 && connectTimeMs > 0
|
||||
? Math.min(maxTimeMs, connectTimeMs)
|
||||
: maxTimeMs > 0
|
||||
? maxTimeMs
|
||||
: connectTimeMs
|
||||
|
||||
let m = method
|
||||
if (!m) {
|
||||
if (headOnly) m = 'HEAD'
|
||||
@@ -873,16 +899,16 @@ export async function runCurlCli(ctx, argv) {
|
||||
outForUrl = defaultFetchSaveName(url)
|
||||
}
|
||||
|
||||
const ac = maxTimeMs > 0 ? new AbortController() : null
|
||||
const ac = deadlineMs > 0 ? new AbortController() : null
|
||||
const t =
|
||||
maxTimeMs > 0
|
||||
deadlineMs > 0
|
||||
? setTimeout(() => {
|
||||
try {
|
||||
ac.abort()
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}, maxTimeMs)
|
||||
}, deadlineMs)
|
||||
: null
|
||||
|
||||
let res
|
||||
|
||||
@@ -64,6 +64,7 @@ function printHelp(ctx, prog) {
|
||||
${prog} start|stop|restart UNIT
|
||||
${prog} enable|disable UNIT
|
||||
${prog} is-enabled UNIT
|
||||
${prog} is-active UNIT
|
||||
${prog} help
|
||||
|
||||
Persistent preset: ~/.config/bare-os/initd/disabled.txt (personal drive).
|
||||
@@ -347,6 +348,30 @@ export async function runSystemctlCli(ctx, argv) {
|
||||
return
|
||||
}
|
||||
|
||||
if (sub === 'is-active') {
|
||||
const unit = rest[0]
|
||||
if (!unit) {
|
||||
ctx.console.error(`${prog}: is-active requires a UNIT`)
|
||||
ctx.exitCode = 2
|
||||
return
|
||||
}
|
||||
const def = findBareServiceDefinition(unit)
|
||||
if (!def) {
|
||||
ctx.console.error(`${prog}: unknown unit: ${unit}`)
|
||||
ctx.exitCode = 3
|
||||
return
|
||||
}
|
||||
const rt = getBareServiceRuntime(unit)
|
||||
if (rt?.phase === 'active') {
|
||||
ctx.console.log('active')
|
||||
ctx.exitCode = 0
|
||||
} else {
|
||||
ctx.console.log('inactive')
|
||||
ctx.exitCode = 3
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.console.error(`${prog}: unknown command: ${sub}`)
|
||||
ctx.exitCode = 2
|
||||
}
|
||||
|
||||
@@ -31,7 +31,8 @@ const DIR_MARKER = '.bareos_empty'
|
||||
* @param {{
|
||||
* procSnapshot?: { version?: string, cmdline?: string },
|
||||
* bootStartedMs?: number,
|
||||
* initdRunText?: () => string
|
||||
* initdRunText?: () => string,
|
||||
* bootProfileText?: () => string
|
||||
* }} [vfsOptions]
|
||||
*/
|
||||
export function createVfs(
|
||||
@@ -50,6 +51,10 @@ export function createVfs(
|
||||
typeof vfsOptions.initdRunText === 'function'
|
||||
? vfsOptions.initdRunText
|
||||
: null
|
||||
const bootProfileText =
|
||||
typeof vfsOptions.bootProfileText === 'function'
|
||||
? vfsOptions.bootProfileText
|
||||
: null
|
||||
const HOME = () => env.HOME || '/home/guest'
|
||||
let cwd = env.PWD || HOME()
|
||||
|
||||
@@ -208,6 +213,10 @@ export function createVfs(
|
||||
: '# bare-initd: no snapshot provider\n'
|
||||
return utf8Encode(t)
|
||||
}
|
||||
if (k === 'run' && f === 'boot_profile') {
|
||||
const t = bootProfileText ? bootProfileText() : '\n'
|
||||
return utf8Encode(t)
|
||||
}
|
||||
if (k === 'dev' && f === 'null') return utf8Encode('')
|
||||
if (k === 'dev' && f === 'zero') return new Uint8Array(65536)
|
||||
if (k === 'dev' && f === 'urandom') return pseudoUrandomBytes()
|
||||
@@ -264,6 +273,14 @@ export function createVfs(
|
||||
if (n === '/run/bare-os/units') {
|
||||
return { virtualPseudo: true, kind: 'run', node: 'file', file: 'units' }
|
||||
}
|
||||
if (n === '/run/bare-os/boot_profile') {
|
||||
return {
|
||||
virtualPseudo: true,
|
||||
kind: 'run',
|
||||
node: 'file',
|
||||
file: 'boot_profile'
|
||||
}
|
||||
}
|
||||
return { virtualPseudo: true, kind: 'run', node: 'enoent' }
|
||||
}
|
||||
if (n === '/dev' || n.startsWith('/dev/')) {
|
||||
@@ -795,7 +812,7 @@ export function createVfs(
|
||||
return ['bare-os']
|
||||
}
|
||||
if (pr.kind === 'run' && pr.node === 'dir' && pr.dir === 'bare_os') {
|
||||
return ['units']
|
||||
return ['boot_profile', 'units']
|
||||
}
|
||||
if (pr.kind === 'dev' && pr.node === 'root') {
|
||||
return ['null', 'urandom', 'zero']
|
||||
|
||||
@@ -177,6 +177,40 @@ test('stock kernel init.js runs rc.local before onboot', async (t) => {
|
||||
t.is(execLines[1], 'echo onboot-line')
|
||||
})
|
||||
|
||||
test('stock kernel init.js runs kernel.d after rc.local before onboot', async (t) => {
|
||||
const src = await readFile(
|
||||
path.join(__dirname, '../../kernel/init.js'),
|
||||
'utf8'
|
||||
)
|
||||
const execLines = []
|
||||
const drive = {
|
||||
async get(p) {
|
||||
if (p === '/etc/bare-os/rc.local') return b4a.from('echo rc-local')
|
||||
if (p === '/etc/bare-os/kernel.d/05-k.mod') return b4a.from('echo kmod')
|
||||
return null
|
||||
},
|
||||
async *readdir(dir) {
|
||||
if (dir === '/etc/bare-os/kernel.d') yield '05-k.mod'
|
||||
}
|
||||
}
|
||||
const ctx = {
|
||||
bareOsSkipRepl: true,
|
||||
env: { BARE_OS_ONBOOT: 'echo onboot-line' },
|
||||
drive,
|
||||
b4a,
|
||||
console: { log() {}, error() {} },
|
||||
readLine: async () => null,
|
||||
async execLine(line) {
|
||||
execLines.push(String(line).trim())
|
||||
return 'ok'
|
||||
}
|
||||
}
|
||||
await runKernelFromSource(src, ctx)
|
||||
t.is(execLines[0], 'echo rc-local')
|
||||
t.is(execLines[1], 'echo kmod')
|
||||
t.is(execLines[2], 'echo onboot-line')
|
||||
})
|
||||
|
||||
test('stock kernel init.js BARE_OS_BOOT_TRACE=json emits phase JSON on stderr', async (t) => {
|
||||
const src = await readFile(
|
||||
path.join(__dirname, '../../kernel/init.js'),
|
||||
@@ -219,6 +253,7 @@ test('stock kernel init.js BARE_OS_BOOT_TRACE=json emits phase JSON on stderr',
|
||||
.filter(Boolean)
|
||||
t.ok(phases.length >= 3)
|
||||
t.ok(phases.some((o) => o.phase === 'rc.local'))
|
||||
t.ok(phases.some((o) => o.phase === 'kernel.d'))
|
||||
t.ok(phases.every((o) => typeof o.ms === 'number'))
|
||||
})
|
||||
|
||||
@@ -566,6 +601,7 @@ test('vfs /proc /sys read-only pseudo files; write rejected', async (t) => {
|
||||
const vfs = createVfs(sys, personal, env, null, {
|
||||
procSnapshot: { version: '1.2.3-test', cmdline: 'unit-test' },
|
||||
bootStartedMs: Date.now() - 4000,
|
||||
bootProfileText: () => 'mini\n',
|
||||
initdRunText: () => 'demo-unit\tactive\t1\tdemo\n'
|
||||
})
|
||||
const root = await vfs.readdir('/')
|
||||
@@ -616,6 +652,11 @@ test('vfs /proc /sys read-only pseudo files; write rejected', async (t) => {
|
||||
t.is((await vfs.readFile('/dev/null'))?.byteLength ?? 0, 0)
|
||||
const z = await vfs.readFile('/dev/zero')
|
||||
t.ok(z && z.byteLength === 65536)
|
||||
t.alike(await vfs.readdir('/run/bare-os').then((a) => [...a].sort()), [
|
||||
'boot_profile',
|
||||
'units'
|
||||
])
|
||||
t.is(b4a.toString(await vfs.readFile('/run/bare-os/boot_profile')), 'mini\n')
|
||||
const units = b4a.toString(await vfs.readFile('/run/bare-os/units'))
|
||||
t.ok(units.includes('demo-unit'))
|
||||
let writeErr = null
|
||||
@@ -876,6 +917,7 @@ test('buildBareOsRuntimeCaps matches ctx API version and pipeline env', async (t
|
||||
t.is(caps.pipeline.maxStages, 8)
|
||||
t.ok(Array.isArray(caps.pseudoFsPaths))
|
||||
t.ok(caps.pseudoFsPaths.includes('/proc/version'))
|
||||
t.ok(caps.pseudoFsPaths.includes('/run/bare-os/boot_profile'))
|
||||
t.is(caps.features.simulatedPipelines, true)
|
||||
t.is(caps.features.httpDelegate, true)
|
||||
t.is(caps.features.gitDelegate, true)
|
||||
@@ -1317,6 +1359,34 @@ test('systemctl list-units delegates to same backend', async (t) => {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('systemctl is-active matches bare-initd runtime', async (t) => {
|
||||
const dir = testCorestoreDir('initctlactive')
|
||||
const store = new Corestore(dir)
|
||||
const sys = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pica'))
|
||||
await sys.ready()
|
||||
await personal.ready()
|
||||
const logs = []
|
||||
const ctx = testCtx(sys, personal)
|
||||
ctx.execLine = async () => {}
|
||||
await startBareInitd(ctx)
|
||||
ctx.console = {
|
||||
log: (...a) => logs.push(a.join(' ')),
|
||||
error: (...a) => logs.push(a.join(' '))
|
||||
}
|
||||
ctx.exitCode = 0
|
||||
await runBinCommand(ctx, ['systemctl', 'is-active', 'kernel-logger'])
|
||||
t.is(ctx.exitCode, 0)
|
||||
t.ok(logs.join('\n').includes('active'))
|
||||
logs.length = 0
|
||||
ctx.exitCode = 0
|
||||
await runBinCommand(ctx, ['systemctl', 'is-active', 'nonexistent-unit'])
|
||||
t.is(ctx.exitCode, 3)
|
||||
stopBareInitd()
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('systemctl restart bare-cron succeeds', async (t) => {
|
||||
const dir = testCorestoreDir('initctlrst')
|
||||
const store = new Corestore(dir)
|
||||
@@ -1911,6 +1981,40 @@ test('curl delegated from booter with stub fetch', async (t) => {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('curl --connect-timeout aborts hanging stub fetch', async (t) => {
|
||||
const dir = testCorestoreDir('curlcto')
|
||||
const store = new Corestore(dir)
|
||||
const drive = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pccto'))
|
||||
await drive.ready()
|
||||
await personal.ready()
|
||||
const ctx = testCtx(drive, personal)
|
||||
ctx.exitCode = 0
|
||||
ctx.console = { log() {}, error() {} }
|
||||
ctx.httpFetch = async (_url, init) =>
|
||||
new Promise((_resolve, reject) => {
|
||||
const sig = init && init.signal
|
||||
if (sig && sig.aborted) {
|
||||
reject(new Error('The operation was aborted'))
|
||||
return
|
||||
}
|
||||
if (sig) {
|
||||
sig.addEventListener('abort', () =>
|
||||
reject(new Error('The operation was aborted'))
|
||||
)
|
||||
}
|
||||
})
|
||||
await runBinCommand(ctx, [
|
||||
'curl',
|
||||
'--connect-timeout',
|
||||
'1',
|
||||
'https://stub.example/hang'
|
||||
])
|
||||
t.is(ctx.exitCode, 7)
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('wget delegated from booter with stub fetch', async (t) => {
|
||||
const dir = testCorestoreDir('wget')
|
||||
const store = new Corestore(dir)
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
"systemctl status [UNIT] [--lines N]",
|
||||
"systemctl logs UNIT [--lines N]",
|
||||
"systemctl start|stop|restart UNIT",
|
||||
"systemctl enable|disable UNIT",
|
||||
"systemctl is-enabled UNIT",
|
||||
"systemctl is-active UNIT",
|
||||
"journalctl -u UNIT [--lines N]"
|
||||
],
|
||||
"description": "Lists and manages session-scoped bare-initd units (kernel-logger, bare-cron, …). Implemented by the booter (kernel-runner); /bin stubs exist for PATH and man(1). Units are not persistent: there is no enable/disable. Logs live under /var/log/bare-os/ when the unit defines a logPath. The legacy name bare-initctl is still accepted by the booter as an alias.",
|
||||
"description": "Lists and manages session-scoped bare-initd units (kernel-logger, bare-cron, …). Implemented by the booter (kernel-runner); /bin stubs exist for PATH and man(1). enable/disable toggle the personal-drive preset file ~/.config/bare-os/initd/disabled.txt for future boots in the same image. is-enabled reports enabled or disabled; is-active reports active vs inactive from runtime phase (exit 0 vs 3). Logs live under /var/log/bare-os/ when the unit defines a logPath. The legacy name bare-initctl is still accepted by the booter as an alias.",
|
||||
"options": [
|
||||
{
|
||||
"flag": "--lines N",
|
||||
|
||||
@@ -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`**) → **`/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)).
|
||||
- **`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)).
|
||||
- **`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`, …).
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
*
|
||||
* Boot order: /etc/os-release → /etc/motd → optional profile rc → /etc/bare-os/rc →
|
||||
* /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.
|
||||
* /etc/bare-os/kernel.d/* (same naming rules as rc.d) → 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).
|
||||
@@ -201,6 +202,37 @@ function isBareOsRcSnippetFile(name) {
|
||||
return /^[0-9]/.test(name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional snippets under /etc/bare-os/kernel.d/ — same rules as rc.d; runs after rc.local.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
*/
|
||||
async function runBareOsKernelDir(ctx) {
|
||||
const { drive, b4a, console } = ctx
|
||||
try {
|
||||
/** @type {string[]} */
|
||||
const names = []
|
||||
try {
|
||||
for await (const n of drive.readdir('/etc/bare-os/kernel.d')) names.push(n)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
names.sort()
|
||||
for (const name of names) {
|
||||
if (!isBareOsRcSnippetFile(name)) continue
|
||||
const p = `/etc/bare-os/kernel.d/${name}`
|
||||
try {
|
||||
const buf = await drive.get(p)
|
||||
if (!buf) continue
|
||||
await runRcLines(ctx, b4a.toString(buf))
|
||||
} catch (e) {
|
||||
console.error(`kernel.d/${name}: ` + ((e && e.message) || String(e)))
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error((e && e.message) || String(e))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional snippets under /etc/bare-os/rc.d/ — executed in lexicographic order.
|
||||
* @param {Record<string, unknown>} ctx
|
||||
@@ -270,6 +302,7 @@ async function start(ctx) {
|
||||
await bootTimed(ctx, 'rc.local', () =>
|
||||
runRcFileAt(ctx, '/etc/bare-os/rc.local', 'rc.local')
|
||||
)
|
||||
await bootTimed(ctx, 'kernel.d', () => runBareOsKernelDir(ctx))
|
||||
await printSessionBanner(ctx)
|
||||
await bootTimed(ctx, 'onboot', () => runOnboot(ctx))
|
||||
while (true) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user