Updates
This commit is contained in:
+116
-4
@@ -60,9 +60,121 @@ function barePosixBlocks(size) {
|
||||
return Math.ceil(Number(size) / 512) || 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Bounded xargs for Bare OS: invokes ctx.runBinCommand only (no host spawn).
|
||||
* Limits: stdin 256KiB, 4096 whitespace/null tokens, 128 args per invocation,
|
||||
* 64 invocations per run. Exceeding limits is a fatal error (exit 125).
|
||||
*/
|
||||
|
||||
const MAX_STDIN = 256 * 1024
|
||||
const MAX_TOKENS = 4096
|
||||
const MAX_PER_INVOCATION = 128
|
||||
const MAX_INVOCATIONS = 64
|
||||
|
||||
async function run(ctx, argv) {
|
||||
ctx.console.error(
|
||||
'xargs: running arbitrary commands from /bin/xargs is not supported in Bare OS; use the shell to expand arguments.'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
if (typeof ctx.runBinCommand !== 'function') {
|
||||
ctx.console.error(
|
||||
'xargs: ctx.runBinCommand is not available (requires a Bare OS booter session)'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
const args = argv.slice(1)
|
||||
let nullSep = false
|
||||
let maxBatch = MAX_PER_INVOCATION
|
||||
let i = 0
|
||||
|
||||
while (i < args.length && args[i].startsWith('-')) {
|
||||
const a = args[i]
|
||||
if (a === '--') {
|
||||
i++
|
||||
break
|
||||
}
|
||||
if (a === '-0' || a === '--null') {
|
||||
nullSep = true
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if (a === '-n' || a === '--max-args') {
|
||||
const n = args[i + 1]
|
||||
if (n == null || !/^\d+$/.test(n) || Number(n) < 1) {
|
||||
ctx.console.error('xargs: -n requires a positive integer')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
maxBatch = Math.min(Number(n), MAX_PER_INVOCATION)
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('-n') && a.length > 2 && /^\d+$/.test(a.slice(2))) {
|
||||
const n = Number(a.slice(2))
|
||||
maxBatch = Math.min(n, MAX_PER_INVOCATION)
|
||||
i++
|
||||
continue
|
||||
}
|
||||
ctx.console.error('xargs: unsupported option: ' + a)
|
||||
ctx.console.error(
|
||||
'xargs: Bare OS supports: -0/--null, -n N (max ' +
|
||||
MAX_PER_INVOCATION +
|
||||
' per run)'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
|
||||
/** @type {string[]} */
|
||||
let cmd = args.slice(i)
|
||||
if (cmd.length === 0) cmd = ['echo']
|
||||
|
||||
let text = bareStdin(ctx) || ''
|
||||
if (text.length > MAX_STDIN) {
|
||||
ctx.console.error(
|
||||
'xargs: stdin exceeds ' + MAX_STDIN + ' bytes (Bare OS limit)'
|
||||
)
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
|
||||
/** @type {string[]} */
|
||||
let pieces
|
||||
if (nullSep) {
|
||||
pieces = text.split('\0').filter((s) => s.length > 0)
|
||||
} else {
|
||||
pieces = text.trim() === '' ? [] : text.trim().split(/\s+/).filter(Boolean)
|
||||
}
|
||||
|
||||
if (pieces.length > MAX_TOKENS) {
|
||||
ctx.console.error(
|
||||
'xargs: too many arguments (' + pieces.length + ' > ' + MAX_TOKENS + ')'
|
||||
)
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
|
||||
const runOne = async (batch) => {
|
||||
await ctx.runBinCommand(cmd.concat(batch))
|
||||
}
|
||||
|
||||
if (pieces.length === 0) {
|
||||
await runOne([])
|
||||
return
|
||||
}
|
||||
|
||||
let invocations = 0
|
||||
for (let o = 0; o < pieces.length; o += maxBatch) {
|
||||
if (++invocations > MAX_INVOCATIONS) {
|
||||
ctx.console.error(
|
||||
'xargs: exceeded ' + MAX_INVOCATIONS + ' invocations (Bare OS limit)'
|
||||
)
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
const batch = pieces.slice(o, o + maxBatch)
|
||||
await runOne(batch)
|
||||
const ec = Number(ctx.exitCode) || 0
|
||||
if (ec !== 0) {
|
||||
ctx.exitCode = ec
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user