- cubesys/src/bin/cube.rs: route known command words (prog/write/run/ls/stat/
seal/open/query/begin/commit/rollback/stats/audit) straight to Session::exec
from argv, making the coordinate-addressed 'open <path> <K.Z.Y.X> <tf>' surface
(Phase 3 'open by CZYX + flags') a real CLI command, not REPL/script-only.
Verified: ./check green; cube open/cube bogus both behave; dispatch reaches
crypto/run layer over in-process and durable daemon (cubec) paths.
- STARTUP-README.md: add verification points per standing directive; mark
Phase 2 FS + durability VERIFIED, Phase 3 surface DONE, boot-substrate IN PROGRESS.
- Guest binaries synced to host HEAD f40b448 + this change; OS state now persists
on the cube store in the VM (/cubefs/c200/...), durable across daemon restart.
139 lines
5.4 KiB
Rust
139 lines
5.4 KiB
Rust
//! `cube` — the CUBELinux-2 system CLI (local, in-process).
|
|
//!
|
|
//! One process holds ONE in-memory `CubeStore` shared by cubefs, cubecode and
|
|
//! cubecrypt. Commands are issued as a script (file) or interactively (REPL);
|
|
//! every command operates on that shared store, so `write` then `run` then
|
|
//! `seal` then `open` all see the same cube.
|
|
//!
|
|
//! For a persistent store served over a socket by a long-running daemon, use
|
|
//! `cube-server` + `cubec` instead (see `docs/integration.md`).
|
|
//!
|
|
//! Usage:
|
|
//! cube # print this help
|
|
//! cube demo # run the built-in integration demo
|
|
//! cube repl # read commands from stdin, one per line
|
|
//! cube script <file> # read commands from <file>, one per line
|
|
//!
|
|
//! Commands (operate on the shared cube):
|
|
//! prog <path> <ops...> # write CUBEVM bytecode from op names
|
|
//! write <path> <bytes...> # store cubevm bytecode (hex/dec) at a path
|
|
//! run <path> # load the code cell at <path> and run the VM
|
|
//! ls <dir> # list a cubefs directory
|
|
//! stat <path> # getattr via cubefs
|
|
//! seal <path> <K.C.Z.Y.X> <tf> # encrypt the record at <path> (tf: none|gcm|chacha|xts)
|
|
//! open <path> <K.C.Z.Y.X> <tf> # decrypt + decode + run the sealed record
|
|
//!
|
|
//! Coordinates are written `C.Z.Y.X` (decimal). Key cells live in Null space,
|
|
//! so they are given directly as coordinates, not as cubefs paths.
|
|
|
|
use std::io::BufRead;
|
|
|
|
use cubesys::commands::Session;
|
|
|
|
/// Command words understood by the shared interpreter. When `cube`'s first
|
|
/// argument is one of these, it is run as a single command against a fresh
|
|
/// in-memory store (the same path as `cube repl`), so the OS / a script can
|
|
/// invoke e.g. `cube open /c001/z001/y001/x001 001.001.001.001 none` directly
|
|
/// — this is the Phase-3 "open by CZYX + flags" surface made a first-class
|
|
/// CLI command rather than REPL-only.
|
|
fn is_command_word(w: &str) -> bool {
|
|
matches!(
|
|
w,
|
|
"prog"
|
|
| "write"
|
|
| "run"
|
|
| "ls"
|
|
| "stat"
|
|
| "seal"
|
|
| "open"
|
|
| "query"
|
|
| "begin"
|
|
| "commit"
|
|
| "rollback"
|
|
| "stats"
|
|
| "audit"
|
|
)
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
match args.get(1).map(|s| s.as_str()) {
|
|
None => print_help(),
|
|
Some("demo") => cubesys::demo::run(),
|
|
// A direct command word (e.g. `cube open <path> <K.Z.Y.X> <tf>`): run it
|
|
// against a fresh in-memory session and exit with the result. This makes
|
|
// the coordinate-addressed API a real CLI surface the OS can call.
|
|
Some(word) if is_command_word(word) => {
|
|
let line = args[1..].join(" ");
|
|
let mut session = Session::new();
|
|
match session.exec(&line) {
|
|
Ok(out) => println!("{out}"),
|
|
Err(e) => {
|
|
eprintln!("error: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
Some("repl") => {
|
|
let mut session = Session::new();
|
|
let stdin = std::io::stdin();
|
|
let lock = stdin.lock();
|
|
for line in lock.lines() {
|
|
let line = match line {
|
|
Ok(l) => l,
|
|
Err(_) => break,
|
|
};
|
|
if line.trim().is_empty() || line.starts_with('#') {
|
|
continue;
|
|
}
|
|
match session.exec(&line) {
|
|
Ok(out) => println!("{out}"),
|
|
Err(e) => eprintln!("error: {e}"),
|
|
}
|
|
}
|
|
}
|
|
Some("script") => {
|
|
let file = args.get(2).expect("script needs <file>");
|
|
let text = std::fs::read_to_string(file).expect("cannot read script file");
|
|
let mut session = Session::new();
|
|
for line in text.lines() {
|
|
if line.trim().is_empty() || line.starts_with('#') {
|
|
continue;
|
|
}
|
|
match session.exec(line) {
|
|
Ok(out) => println!("{out}"),
|
|
Err(e) => {
|
|
eprintln!("error: {e}");
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Some(other) => {
|
|
eprintln!("unknown subcommand: {other}\n");
|
|
print_help();
|
|
std::process::exit(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn print_help() {
|
|
println!(
|
|
"cube - CUBELinux-2 system CLI (cubefs + cubecode + cubecrypt over one store)\n\
|
|
\n\
|
|
Usage:\n \
|
|
cube show this help\n \
|
|
cube demo run the built-in integration demo\n \
|
|
cube repl read commands from stdin (one per line)\n \
|
|
cube script <file> run commands from a file\n\
|
|
\nCommands:\n \
|
|
prog <path> <ops...> write CUBEVM bytecode from op names\n \
|
|
write <path> <bytes...> store cubevm bytecode at a path\n \
|
|
run <path> run the code cell at <path>\n \
|
|
ls <dir> list a cubefs directory\n \
|
|
stat <path> getattr via cubefs\n \
|
|
seal <path> <K.Z.Y.X> <tf> encrypt a record (tf: none|gcm|chacha|xts)\n \
|
|
open <path> <K.Z.Y.X> <tf> decrypt + decode + run a sealed record\n"
|
|
);
|
|
}
|