use std::env;
use std::process;
mod cmdline;
mod bls;
use cmdline::CmdlineHandler;
use bls::BLSEntry;
fn cmdline_usage() {
eprintln!(" cmdline ENTRY show # shows the kernel cmdline from a bls ENTRY (options)");
eprintln!(" cmdline ENTRY get PARAM # displays the value of parameter 'param'");
eprintln!(" cmdline ENTRY|all set PARAM[=VALUE] # sets pairs of 'params' to corresponding 'value', you can also set a parameter with no value");
eprintln!(" cmdline ENTRY|all add PARAM[=VALUE] # adds an additional 'param' or 'param=value' pair to the cmdline even if it was previously set");
eprintln!(" cmdline ENTRY|all remove PARAM[=VALUE] # removes a specific param or param=value pair from the cmdline, to remove all pairs or");
eprintln!(" # a parameter with no value use 'clear'");
eprintln!(" cmdline ENTRY|all clear PARAM # removes all instances of a specific parameter");
}
fn entry_usage() {
eprintln!(" entry list # lists all Boot Loader Spec *.conf entries in order");
eprintln!(" entry ENTRY show # shows the content of a bls ENTRY");
eprintln!(" entry ENTRY get KEY # displays the value of a key in a bls ENTRY");
eprintln!(" entry ENTRY set KEY VALUE # sets the value for a key in a bls ENTRY");
eprintln!(" entry ENTRY remove KEY # removes the key from a bls ENTRY");
eprintln!(" entry ENTRY create # creates an empty bls ENTRY");
eprintln!(" entry ENTRY delete # deletes the bls ENTRY");
}
fn help_usage() {
eprintln!(" help [COMMAND] # prints this usage help or help for specific command");
}
fn log_usage () {
eprintln!("blscfg usage:");
cmdline_usage();
eprintln!("");
entry_usage();
help_usage();
}
fn assert_invalid_command(expected_length: usize, args: &[String], max: bool, usage: &dyn Fn()) {
if args.len() < expected_length {
eprintln!("ERROR insuficient arguments: `{}`", args.join(" "));
} else if max && args.len() > expected_length {
eprintln!("ERROR too many arguments: `{}`", args.join(" "));
} else {
return;
}
usage();
process::exit(1);
}
fn handle_cmdline(args: &[String]) {
let base: usize = 3;
assert_invalid_command(base, args, false, &cmdline_usage);
let mut _entry;
let mut entries = BLSEntry::get_bls_entries().unwrap_or_else (|e| {
eprintln!("ERROR: {}", e);
process::exit(1);
});
let provider: &mut dyn CmdlineHandler = match &args[base-2] {
entry if entry.as_str() == "all" => {
match args[base-1].as_str() {
arg @ "get" | arg @ "show" => {
eprintln!("ERROR: cannot {} cmdline for all entries", arg);
process::exit(1);
}
_ => {}
};
&mut entries
},
entry @ _ => {
let blsentry = BLSEntry::new(entry);
match blsentry {
Ok(ent) => { _entry = ent; &mut _entry }
Err(_) => {
eprintln!("ERROR: {} is not a valid bootloader entry", entry);
process::exit(1);
}
}
}
};
macro_rules! exit_error {
() => { |msg| {
eprintln!("ERROR: {}", msg);
process::exit(1);
}
}
};
match args[base-1].as_str() {
"show" => {
assert_invalid_command(base, args, true, &cmdline_usage);
println!("{}", provider.cmdline_render()
.unwrap_or_else(exit_error!()));
},
"get" => {
assert_invalid_command(base+1, args, true, &cmdline_usage);
match provider.cmdline_get(&args[base]) {
Ok(params) => {
for param in params {
print!("{}", &args[base]);
if let Some(param) = param {
print!("={}", param);
}
println!("");
}
},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"set" => {
assert_invalid_command(base+1, args, false, &cmdline_usage);
match provider.cmdline_set(&args[base..]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"add" => {
assert_invalid_command(base+1, args, false, &cmdline_usage);
match provider.cmdline_add(&args[base..]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"remove" => {
assert_invalid_command(base+1, args, false, &cmdline_usage);
match provider.cmdline_remove(&args[base..]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"clear" => {
assert_invalid_command(base+1, args, false, &cmdline_usage);
match provider.cmdline_clear(&args[base..]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
_ => {
eprintln!("ERROR: unrecognized command {}", args.join(" "));
process::exit(1);
}
}
process::exit(0);
}
fn handle_entry(args: &[String]) {
assert_invalid_command(2, args, false, &entry_usage);
match args[1].as_str() {
"list" => {
assert_invalid_command(2, args, true, &entry_usage);
let entries = BLSEntry::get_bls_entries ()
.unwrap_or_else(|e| { eprintln!("ERROR: could not read bootloader entries from directory {}", e);
process::exit(1); });
let mut index: u8 = 0;
for entry in entries {
println!("{} {}", index, entry);
index += 1;
}
return;
},
_ => {}
}
let base: usize = 3;
assert_invalid_command(base, args, false, &entry_usage);
if args[base-1].as_str() == "create" {
assert_invalid_command(base, args, true, &entry_usage);
if let Err(e) = BLSEntry::create(&args[base-2]) {
eprintln!("ERROR: {}", e);
process::exit(1);
} else {
return;
}
}
let entry = {
let blsentry = BLSEntry::new(&args[base-2]);
match blsentry {
Ok(ent) => ent,
Err(_) => {
eprintln!("ERROR: {} is not a valid bootloader entry", &args[base-2]);
process::exit(1);
}
}
};
match args[base-1].as_str() {
"show" => {
assert_invalid_command(base, args, true, &entry_usage);
println!("{}", entry);
},
"get" => {
assert_invalid_command(base+1, args, true, &entry_usage);
match entry.get(&args[base]) {
Ok(value) => {
println!("{} {}", &args[base], value.join(" "));
},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"set" => {
assert_invalid_command(base+2, args, true, &entry_usage);
match entry.set(&args[base], &[String::from(&args[base+1])]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"remove" => {
assert_invalid_command(base+1, args, true, &entry_usage);
match entry.remove(&args[base]) {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
"delete" => {
assert_invalid_command(base, args, true, &entry_usage);
match entry.delete() {
Ok(()) => {},
Err(error) => {
eprintln!("ERROR: {}", error);
process::exit(1);
}
}
},
_ => {
eprintln!("ERROR: unrecognized command {}", args.join(" "));
process::exit(1);
}
}
}
fn handle_help(args: &[String]) {
assert_invalid_command(1, &args[1..], true, &help_usage);
log_usage();
}
fn main() {
let args: Vec<_> = env::args().collect();
if args.len() <= 1 {
log_usage();
process::exit(1);
}
match args[1].as_str() {
"cmdline" => handle_cmdline(&args[1..]),
"entry" => handle_entry(&args[1..]),
"help" => handle_help(&args[1..]),
_ => {
eprintln!("ERROR: invalid command {}", args[1]);
log_usage();
process::exit(1);
}
}
process::exit(0);
}