Updates
This commit is contained in:
@@ -148,9 +148,13 @@ export const MAN_EXTRA_PAGES = [
|
||||
* Keep sorted; see build.mjs.
|
||||
*/
|
||||
export const HELP_DELEGATED_COMMANDS = [
|
||||
'bundlebee',
|
||||
'git',
|
||||
'hrpc',
|
||||
'journalctl',
|
||||
'openssl',
|
||||
'pear-runtime-matrix',
|
||||
'sidecar',
|
||||
'ssh-keygen',
|
||||
'systemctl',
|
||||
'tar'
|
||||
|
||||
@@ -3,25 +3,21 @@
|
||||
"section": 1,
|
||||
"title": "change file group ownership",
|
||||
"synopsis": [
|
||||
"chgrp [OPTION]... [OPERAND]..."
|
||||
"chgrp [OPTION]... GROUP FILE..."
|
||||
],
|
||||
"description": "Changing group ownership is not supported on Bare OS: Hyperdrive metadata is single-session oriented.",
|
||||
"description": "Updates group metadata on the personal Hyperdrive for writable paths (same scope as chown). GROUP may be a numeric gid or root/guest/nobody/current GROUP name.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"chgrp",
|
||||
"bare-os",
|
||||
"coreutils",
|
||||
"stub"
|
||||
"metadata"
|
||||
],
|
||||
"stub": true,
|
||||
"diagnostics": [
|
||||
"chgrp: changing group is not supported on Bare OS"
|
||||
],
|
||||
"bareOsNotes": "Single-user identity; gid fields exist for display only.",
|
||||
"bareOsNotes": "Uses vfs.chown with preserved uid; see chown(1) and vfs.js.",
|
||||
"examples": [
|
||||
{
|
||||
"caption": "not supported — use identity model",
|
||||
"code": "# chgrp is a stub; group is display metadata only"
|
||||
"caption": "set group by name",
|
||||
"code": "chgrp guest shared.conf"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,25 +3,25 @@
|
||||
"section": 1,
|
||||
"title": "change file owner and group",
|
||||
"synopsis": [
|
||||
"chown [OPTION]... [OPERAND]..."
|
||||
"chown [OPTION]... OWNER[:GROUP] FILE..."
|
||||
],
|
||||
"description": "Changing file owner is not supported on Bare OS (single-user Hyperdrive metadata).",
|
||||
"description": "Updates uid/gid metadata on the personal Hyperdrive for paths under the active session home, $HOME, /tmp, and /var/log. System paths are read-only. Non-root may only chgrp on files they own; root (euid 0) may set any owner.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"chown",
|
||||
"bare-os",
|
||||
"coreutils",
|
||||
"stub"
|
||||
"metadata"
|
||||
],
|
||||
"stub": true,
|
||||
"diagnostics": [
|
||||
"chown: changing owner is not supported on Bare OS"
|
||||
],
|
||||
"bareOsNotes": "Use identity login/logout instead of POSIX ownership changes.",
|
||||
"bareOsNotes": "OWNER/GROUP may be numeric ids or root/guest/nobody/current USER/GROUP. See packages/bare-os-booter/lib/vfs.js chown.",
|
||||
"examples": [
|
||||
{
|
||||
"caption": "not supported",
|
||||
"code": "# chown stub — see man identity / login"
|
||||
"caption": "change group only",
|
||||
"code": "chown :guest file.txt"
|
||||
},
|
||||
{
|
||||
"caption": "numeric owner and group",
|
||||
"code": "chown 1000:1000 notes.txt"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,19 +3,28 @@
|
||||
"section": 1,
|
||||
"title": "kernel-home-snapshot",
|
||||
"synopsis": [
|
||||
"kernel-home-snapshot [--json]"
|
||||
"kernel-home-snapshot [--json] [--max N] [--depth D] [DIR]"
|
||||
],
|
||||
"description": "Placeholder for future personal-drive snapshot export.",
|
||||
"description": "Walks a directory on the VFS and emits a bounded JSON manifest (paths, kinds, sizes). No archive bytes are produced — use for inventory, backup planning, and diagnostics.",
|
||||
"options": [
|
||||
{
|
||||
"flag": "--json",
|
||||
"meaning": "JSON status."
|
||||
"meaning": "Print JSON manifest (default human summary also available)."
|
||||
},
|
||||
{
|
||||
"flag": "--max N",
|
||||
"meaning": "Cap number of file entries (default 8000)."
|
||||
},
|
||||
{
|
||||
"flag": "--depth D",
|
||||
"meaning": "Maximum directory depth (default 12)."
|
||||
}
|
||||
],
|
||||
"keywords": [
|
||||
"kernel-home-snapshot",
|
||||
"bare-os",
|
||||
"backup"
|
||||
"backup",
|
||||
"manifest"
|
||||
],
|
||||
"stub": true
|
||||
"bareOsNotes": "Schema field schema:2 in emitted JSON; see packages/bare-os-coreutils/src/kernel-home-snapshot.js."
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { COREUTILS_COMMANDS, MAN_EXTRA_PAGES } from '../lib/commands.mjs'
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const pagesDir = join(__dirname, '../man/pages')
|
||||
|
||||
const STUB = new Set(['chgrp', 'chown'])
|
||||
const STUB = new Set()
|
||||
|
||||
const POSIX_TITLE = {
|
||||
awk: 'pattern scanning and processing language',
|
||||
@@ -113,10 +113,7 @@ EXAMPLES.cat = [
|
||||
{ caption: 'here-string via echo pipe', code: 'echo hello | cat' }
|
||||
]
|
||||
EXAMPLES.chgrp = [
|
||||
{
|
||||
caption: 'not supported — use identity model',
|
||||
code: '# chgrp is a stub; group is display metadata only'
|
||||
}
|
||||
{ caption: 'set group by name', code: 'chgrp guest shared.conf' }
|
||||
]
|
||||
EXAMPLES.chmod = [
|
||||
{ caption: 'octal', code: 'chmod 644 ~/.profile' },
|
||||
@@ -128,7 +125,8 @@ EXAMPLES.chmod = [
|
||||
{ caption: 'all read, owner write', code: 'chmod a+r,u+w shared.txt' }
|
||||
]
|
||||
EXAMPLES.chown = [
|
||||
{ caption: 'not supported', code: '# chown stub — see man identity / login' }
|
||||
{ caption: 'group only', code: 'chown :guest file.txt' },
|
||||
{ caption: 'numeric ids', code: 'chown 1000:1000 notes.txt' }
|
||||
]
|
||||
EXAMPLES.cksum = [
|
||||
{ caption: 'checksum file', code: 'cksum iso.img' },
|
||||
@@ -357,15 +355,15 @@ const EXTRA = {}
|
||||
|
||||
EXTRA.chgrp = {
|
||||
description:
|
||||
'Changing group ownership is not supported on Bare OS: Hyperdrive metadata is single-session oriented.',
|
||||
diagnostics: ['chgrp: changing group is not supported on Bare OS'],
|
||||
bareOsNotes: 'Single-user identity; gid fields exist for display only.'
|
||||
'Updates group metadata on the personal Hyperdrive for writable paths (session home, $HOME, /tmp, /var/log).',
|
||||
bareOsNotes:
|
||||
'Uses vfs.chown with preserved uid; system image paths are read-only. See packages/bare-os-booter/lib/vfs.js.'
|
||||
}
|
||||
EXTRA.chown = {
|
||||
description:
|
||||
'Changing file owner is not supported on Bare OS (single-user Hyperdrive metadata).',
|
||||
diagnostics: ['chown: changing owner is not supported on Bare OS'],
|
||||
bareOsNotes: 'Use identity login/logout instead of POSIX ownership changes.'
|
||||
'Updates uid/gid metadata on the personal Hyperdrive where the booter allows writes; euid 0 may set any owner.',
|
||||
bareOsNotes:
|
||||
'OWNER/GROUP may be numeric or root/guest/nobody/current user. See vfs chown and identity env UID/GID.'
|
||||
}
|
||||
EXTRA.xargs = {
|
||||
description:
|
||||
|
||||
@@ -2,6 +2,48 @@
|
||||
* rm — remove files or directories.
|
||||
* Flags: -r -R --recursive, -f --force, -d --dir, -- ; bundled e.g. -rf
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} vfs
|
||||
* @param {string} p logical path
|
||||
* @param {boolean} force
|
||||
*/
|
||||
async function rmTreeManual(vfs, p, force) {
|
||||
/** @type {{ type?: string } | null} */
|
||||
let st = null
|
||||
try {
|
||||
st = await vfs.lstat(p)
|
||||
} catch (e) {
|
||||
if (!force) throw e
|
||||
return
|
||||
}
|
||||
if (!st) {
|
||||
if (!force) throw new Error('No such file')
|
||||
return
|
||||
}
|
||||
if (st.type === 'directory') {
|
||||
/** @type {string[]} */
|
||||
const names = []
|
||||
try {
|
||||
for await (const n of vfs.readdir(p)) names.push(n)
|
||||
} catch (e) {
|
||||
if (!force) throw e
|
||||
return
|
||||
}
|
||||
for (const n of names) {
|
||||
const child =
|
||||
p.replace(/\/+$/, '') === ''
|
||||
? '/' + n
|
||||
: p.replace(/\/$/, '') + '/' + n
|
||||
await rmTreeManual(vfs, child, force)
|
||||
}
|
||||
if (typeof vfs.rmdir === 'function') await vfs.rmdir(p)
|
||||
else await vfs.unlink(p)
|
||||
return
|
||||
}
|
||||
await vfs.unlink(p)
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
const vfs = ctx.vfs
|
||||
let recursive = false
|
||||
@@ -56,7 +98,7 @@ async function run(ctx, argv) {
|
||||
vfs && typeof vfs.rm === 'function'
|
||||
? (p) => vfs.rm(p, { recursive, force })
|
||||
: async (p) => {
|
||||
if (recursive) throw new Error('recursive rm not supported')
|
||||
if (recursive) return rmTreeManual(vfs, p, force)
|
||||
return vfs.unlink(p)
|
||||
}
|
||||
for (const f of files) {
|
||||
|
||||
@@ -1,27 +1,51 @@
|
||||
/**
|
||||
* @param {string} raw
|
||||
* @param {number} curLen
|
||||
* @returns {number | null}
|
||||
*/
|
||||
function resolveTruncateSize(raw, curLen) {
|
||||
const s = String(raw).trim()
|
||||
if (!s) return null
|
||||
if (/%$/.test(s)) {
|
||||
const inner = s.startsWith('+') || s.startsWith('-') ? s.slice(1) : s
|
||||
const pct = Number.parseFloat(inner.replace(/%$/, ''))
|
||||
if (!Number.isFinite(pct)) return null
|
||||
const delta = Math.floor((curLen * pct) / 100)
|
||||
if (s.startsWith('+')) return Math.max(0, curLen + delta)
|
||||
if (s.startsWith('-')) return Math.max(0, curLen - delta)
|
||||
return Math.max(0, Math.floor((curLen * pct) / 100))
|
||||
}
|
||||
if (s.startsWith('+')) {
|
||||
const n = Number.parseInt(s.slice(1), 10)
|
||||
if (!Number.isFinite(n)) return null
|
||||
return Math.max(0, curLen + n)
|
||||
}
|
||||
if (s.startsWith('-')) {
|
||||
const n = Number.parseInt(s.slice(1), 10)
|
||||
if (!Number.isFinite(n)) return null
|
||||
return Math.max(0, curLen - n)
|
||||
}
|
||||
const abs = Number.parseInt(s, 10)
|
||||
if (!Number.isFinite(abs) || abs < 0) return null
|
||||
return abs
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
let size = null
|
||||
/** @type {string | null} */
|
||||
let sizeSpec = null
|
||||
const paths = []
|
||||
for (let i = 1; i < argv.length; i++) {
|
||||
const a = argv[i]
|
||||
if (a === '-h' || a === '--help') {
|
||||
ctx.console.log(
|
||||
'usage: truncate -s SIZE FILE\nSet file length to SIZE bytes (padded with zeros if growing).'
|
||||
'usage: truncate -s SIZE FILE\n' +
|
||||
'SIZE: bytes, +N, -N, +N%, -N%, or N% (of current length).\n' +
|
||||
'Sets file length (padded with zeros if growing).'
|
||||
)
|
||||
return
|
||||
}
|
||||
if ((a === '-s' || a === '--size') && argv[i + 1]) {
|
||||
const raw = argv[++i]
|
||||
if (raw.startsWith('+') || raw.startsWith('-')) {
|
||||
ctx.console.error('truncate: relative sizes not supported')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
size = parseInt(raw, 10)
|
||||
if (!Number.isFinite(size) || size < 0) {
|
||||
ctx.console.error('truncate: invalid size')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
sizeSpec = argv[++i]
|
||||
continue
|
||||
}
|
||||
if (a.startsWith('-')) {
|
||||
@@ -31,7 +55,7 @@ async function run(ctx, argv) {
|
||||
}
|
||||
paths.push(a)
|
||||
}
|
||||
if (size == null || paths.length !== 1) {
|
||||
if (!sizeSpec || paths.length !== 1) {
|
||||
ctx.console.error('usage: truncate -s SIZE FILE')
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
@@ -42,7 +66,13 @@ async function run(ctx, argv) {
|
||||
const b = await ctx.vfs.readFile(file)
|
||||
if (b) cur = b instanceof Uint8Array ? b : new Uint8Array(b)
|
||||
} catch {
|
||||
/* new file */
|
||||
/* new file — relative sizes use curLen 0 */
|
||||
}
|
||||
const size = resolveTruncateSize(sizeSpec, cur.length)
|
||||
if (size == null) {
|
||||
ctx.console.error('truncate: invalid size: ' + sizeSpec)
|
||||
ctx.exitCode = 1
|
||||
return
|
||||
}
|
||||
const out = new Uint8Array(size)
|
||||
out.set(cur.subarray(0, Math.min(cur.length, size)))
|
||||
|
||||
Reference in New Issue
Block a user