This commit is contained in:
Raven Scott
2026-04-03 04:23:17 -04:00
parent 98259a7b4a
commit 11cac45df6
86 changed files with 5516 additions and 93 deletions
+1
View File
@@ -10,6 +10,7 @@ const seederKernelBin = join(repoRoot, 'packages/bare-os-seeder/kernel/bin')
const commands = [
'basename',
'cat',
'chmod',
'clear',
'crontab',
'date',
+57
View File
@@ -2,3 +2,60 @@
function bareStdin(ctx) {
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
}
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
function bareFormatModeString(mode, type) {
const typeChar =
type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
const perm = mode & 0o777
const r = (bit) => (perm & bit ? 'r' : '-')
const w = (bit) => (perm & bit ? 'w' : '-')
const x = (bit) => (perm & bit ? 'x' : '-')
return (
typeChar +
r(0o400) +
w(0o200) +
x(0o100) +
r(0o040) +
w(0o020) +
x(0o010) +
r(0o004) +
w(0o002) +
x(0o001)
)
}
/** @param {number} mtimeMs @param {number} [nowMs] */
function bareFormatLsMtime(mtimeMs, nowMs) {
const now = nowMs != null ? nowMs : Date.now()
const d = new Date(mtimeMs)
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
]
const mon = months[d.getMonth()]
const day = String(d.getDate()).padStart(2, ' ')
const sixMo = 180 * 24 * 3600 * 1000
if (Math.abs(now - mtimeMs) > sixMo) {
const yr = String(d.getFullYear()).padStart(4, ' ')
return mon + ' ' + day + ' ' + yr
}
const hh = String(d.getHours()).padStart(2, '0')
const mm = String(d.getMinutes()).padStart(2, '0')
return mon + ' ' + day + ' ' + hh + ':' + mm
}
/** @param {number} size */
function barePosixBlocks(size) {
return Math.ceil(Number(size) / 512) || 0
}
+23
View File
@@ -0,0 +1,23 @@
async function run(ctx, argv) {
const modeStr = argv[1]
const files = argv.slice(2)
if (!modeStr || !files.length) {
ctx.console.error('usage: chmod OCTAL_MODE FILE...')
ctx.exitCode = 1
return
}
const mode = Number.parseInt(String(modeStr), 8)
if (!Number.isFinite(mode) || mode < 0) {
ctx.console.error('chmod: invalid mode')
ctx.exitCode = 1
return
}
for (const f of files) {
try {
await ctx.vfs.chmod(f, mode)
} catch (e) {
ctx.console.error('chmod: ' + f + ': ' + (e.message || e))
ctx.exitCode = 1
}
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
async function run(ctx, argv) {
ctx.console.log(
'Bare OS — default user: guest | builtins: alias, cd, export, exit, login, logout, unalias | /bin: basename cat clear crontab date dirname echo env exit false git grep head hdms help hostname id login logout ls nl pathchk printenv pwd rm savevault seq sleep sort tail test touch true tty uname wc which whoami'
'Bare OS — default user: guest | builtins: alias, cd, export, exit, login, logout, unalias | /bin: basename cat chmod clear crontab date dirname echo env exit false git grep head hdms help hostname id login logout ls nl pathchk printenv pwd rm savevault seq sleep sort tail test touch true tty uname wc which whoami'
)
ctx.console.log(
'Identity: login [--new] <passphrase> | logout [--save] | savevault (encrypt copy of personal drive under /.bare/vault/)'
+79 -7
View File
@@ -25,23 +25,95 @@ async function run(ctx, argv) {
for (const t of targets) {
if (targets.length > 1) ctx.console.log(t + ':')
let names
/** @type {string | null} */
let singleEntryPath = null
try {
names = await vfs.readdir(t)
const stT = await vfs.lstat(t)
if (stT && stT.type !== 'directory') {
const leaf = t
.replace(/\/+$/, '')
.split('/')
.filter(Boolean)
.pop()
names = [leaf || t]
singleEntryPath = t
} else {
names = await vfs.readdir(t)
}
} catch (e) {
ctx.console.error('ls: cannot access ' + t + ': ' + (e.message || e))
continue
}
// POSIX: hide dotfiles unless -a (. and .. are dot-prefixed too).
if (!showAll) names = names.filter((n) => !n.startsWith('.'))
if (!longFmt) {
ctx.console.log(names.join(' '))
} else {
let totalBlocks = 0
const rows = []
for (const n of names) {
const sub = t === '.' || t === './' ? n : t.replace(/\/$/, '') + '/' + n
const st = await vfs.stat(sub)
const tag = st ? (st.type === 'directory' ? 'd' : '-') : '?'
const sz = st && st.size != null ? String(st.size) : '0'
ctx.console.log(tag + 'rwxr-xr-x 1 user user ' + sz + ' ' + n)
const sub =
singleEntryPath != null
? singleEntryPath
: t === '.' || t === './'
? n
: t.replace(/\/$/, '') + '/' + n
const st = await vfs.lstat(sub)
if (!st) {
rows.push({
modeStr: '?---------',
nlink: '?',
user: '?',
group: '?',
size: 0,
mtimeStr: '?',
name: n,
arrow: ''
})
continue
}
const blocks = barePosixBlocks(st.size || 0)
totalBlocks += blocks
const modeStr = bareFormatModeString(st.mode, st.type)
const nlink = st.nlink != null ? String(st.nlink) : '1'
const user = st.user != null ? st.user : String(st.uid ?? 0)
const group = st.group != null ? st.group : String(st.gid ?? 0)
const size = st.size != null ? String(st.size) : '0'
const mtimeStr = bareFormatLsMtime(
typeof st.mtimeMs === 'number' ? st.mtimeMs : Date.now()
)
let arrow = ''
if (st.type === 'symlink' && st.linkname != null) {
arrow = ' -> ' + st.linkname
}
rows.push({
modeStr,
nlink,
user,
group,
size,
mtimeStr,
name: n,
arrow
})
}
if (singleEntryPath == null) ctx.console.log('total ' + totalBlocks)
for (const r of rows) {
ctx.console.log(
r.modeStr +
' ' +
r.nlink +
' ' +
r.user +
' ' +
r.group +
' ' +
r.size +
' ' +
r.mtimeStr +
' ' +
r.name +
r.arrow
)
}
}
}