Tools for creating MBR

This commit is contained in:
Eric-Paul Ickhorn 2023-04-18 08:56:51 +02:00
parent 7829f898fb
commit 5449543501
2 changed files with 243 additions and 0 deletions

8
crmbr/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "crmbr"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

235
crmbr/src/main.rs Normal file
View File

@ -0,0 +1,235 @@
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::env;
use std::vec::*;
use std::string::*;
struct MBRPartTableEntry {
part_type: u8,
first_sector: u64,
last_sector: u64,
bootable: bool,
}
fn serialize_mbr_partition_table_entry(info: MBRPartTableEntry) -> Vec<u8> {
let mut buffer = Vec::<u8>::new();
buffer.resize(16, 0x00);
if info.bootable {
buffer[0] = 0x80;
}
buffer[5] = info.part_type;
buffer[8] = ((info.first_sector & 0xff000000) >> 24) as u8;
buffer[9] = ((info.first_sector & 0x00ff0000) >> 16) as u8;
buffer[10] = ((info.first_sector & 0x0000ff00) >> 8) as u8;
buffer[11] = (info.first_sector & 0x000000ff) as u8;
buffer[12] = ((info.last_sector & 0xff000000) >> 24) as u8;
buffer[13] = ((info.last_sector & 0x00ff0000) >> 16) as u8;
buffer[14] = ((info.last_sector & 0x0000ff00) >> 8) as u8;
buffer[15] = (info.last_sector & 0x000000ff) as u8;
return buffer;
}
fn parse_command_line_partition_table_entry(input: Vec<String>) -> MBRPartTableEntry {
if input.len() != 4 {
panic!("Wrong number of fields in partition table entry");
}
let part_type = resolve_text_to_partition_type(&input[0]);
let first_sector: u64 = match input[1].parse() {
Ok(val) => val,
Err(_) => {
panic!("Invalid partition start sector in '-p1'!");
}
};
let last_sector: u64 = match input[2].parse() {
Ok(val) => val,
Err(_) => {
panic!("Invalid partition end sector in '-p1'!");
}
};
let mut is_bootable: bool = false;
if input[3] == "true" {
is_bootable = true;
}
return MBRPartTableEntry {
part_type: part_type,
first_sector: first_sector,
last_sector: last_sector,
bootable: is_bootable
}
}
fn resolve_text_to_partition_type(text: &String) -> u8 {
return match text.as_str() {
"empty" => 0x00,
"fat12" => 0x01,
"fat16" => 0x04,
"ext" => 0x05,
"fat16_big" => 0x06,
"ntfs" => 0x07,
"fat32_chs" => 0x0b,
"fat32_lba" => 0x0c,
"fat16_big_lba" => 0x0e,
"ext_lba" => 0x0f,
"win_lvm" => 0x42,
"gpfs" => 0x75,
"swap" => 0x82,
"linux" => 0x83,
"linux_lvm" => 0x8e,
"freebsd" => 0xa5,
"openbsd" => 0xa6,
"netbsd" => 0xa9,
"macos" => 0xaf,
&_ => 0xff
};
}
fn main() {
let mut buffer = Vec::<u8>::new();
buffer.resize(512, 0x00);
buffer[510] = 0x55;
buffer[511] = 0xAA;
let mut has_bootcode = false;
let mut bootcode: [u8; 440] = [0x00; 440];
let mut has_output_path = false;
let mut output_path: String = "".to_string();
let args: Vec<String> = env::args().collect();
let mut index: usize = 0;
while index < args.len() {
let arg = &args[index];
if arg == "-h" {
}
if arg == "-mbc" {
index += 1;
if index >= args.len() {
panic!("Failed reading stage 1 bootloader: No path provided!");
}
let mut file = match File::open(args[index].as_str()) {
Ok(val) => val,
Err(err) => {
panic!("Failed reading Master Boot Code from file: {}", err);
}
};
let file_len = match file.read(&mut bootcode) {
Ok(val) => val,
Err(err) => {
panic!("Failed reading stage 1 bootloader from '{}': {}", args[index], err);
}
};
if file_len > 440 {
panic!("The stage 1 bootloader can be at most 440 bytes in size!");
}
index += 1;
has_bootcode = true;
continue;
}
if arg == "-out" {
index += 1;
output_path = args[index].clone();
has_output_path = true;
index += 1;
continue;
}
if arg == "-p1" {
if args.len() <= (index + 4) {
println!("Too short input near '-p1': This argument has 4 fields!");
return;
}
index += 1;
let entry = serialize_mbr_partition_table_entry(
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
);
buffer[446..446+16].clone_from_slice(entry.as_slice());
index += 4;
continue;
}
if arg == "-p2" {
if args.len() <= (index + 4) {
println!("Too short input near '-p2': This argument has 4 fields!");
return;
}
index += 1;
let entry = serialize_mbr_partition_table_entry(
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
);
buffer[462..462+16].clone_from_slice(entry.as_slice());
index += 4;
continue;
}
if arg == "-p3" {
if args.len() <= (index + 4) {
println!("Too short input near '-p3': This argument has 4 fields!");
return;
}
index += 1;
let entry = serialize_mbr_partition_table_entry(
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
);
buffer[478..478+16].clone_from_slice(entry.as_slice());
index += 4;
continue;
}
if arg == "-p4" {
if args.len() <= (index + 4) {
println!("Too short input near '-p4': This argument has 4 fields!");
return;
}
index += 1;
let entry = serialize_mbr_partition_table_entry(
parse_command_line_partition_table_entry(args[index..index+4].to_vec())
);
buffer[494..494+16].clone_from_slice(entry.as_slice());
index += 4;
continue;
}
index += 1;
}
if !has_output_path {
panic!("No output path defined!");
}
if !has_bootcode {
panic!("No bootcode defined!");
}
buffer[0..440].clone_from_slice(bootcode.as_slice());
let mut output_file = match File::create(output_path) {
Ok(val) => val,
Err(err) => {
panic!("Failed opening output file: {}", err);
}
};
match output_file.write_all(&buffer) {
Ok(len) => len,
Err(err) => {
panic!("Failed writing output: {}", err);
}
}
}