Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script to create an MBR formatted disk. #28

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ To do items
* Implement tools to manipulate MBR-formatted disk images
to construct, inspect or fill partitions that can later
be used in Mirage unikernels.

70 changes: 70 additions & 0 deletions bin/create_mbr_disk.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
open Cmdliner

let create_mbr_disk destination partition_files =
let sector_size = Mbr.sizeof in
let num_partitions = List.length partition_files in
if num_partitions > 4 then
failwith
"Too many partition files. Limit number of files to 4 as MBR supports at \
most 4 partitions"
else Printf.printf "Total partitions to create: %d\n" num_partitions;

let partition_sizes =
List.map (fun file -> (Unix.stat file).Unix.st_size) partition_files
in

let partition_size = List.fold_left ( + ) 0 partition_sizes in
let mbr_size = Mbr.sizeof in
let total_size = partition_size + mbr_size in

Printf.printf "Total disk size: %d bytes\n" total_size;

let partitions =
List.mapi
(fun i size ->
Printf.printf "Creating partition: %d" (i + 1);
let start_sector = (i + 1) * sector_size in
let num_sectors = (size + sector_size - 1) / sector_size in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we round up the size to the nearest sector boundary. This is certainly a valid choice. I lean more towards erroring out as rounding up means we have to think about the (potential) slack at the end of the partition and whether to zero it out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@reynir Here I wish to ask, the files to be written to the disk, should they have a size that is an exact multiple of sector_size before it is validated and we error otherwise.

I agree too much slack at the end of the partition will be a waste.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I would do it that way. The user can call truncate to add padding if they need it and it makes sense for the data in question.

match
Mbr.Partition.make ~active:false ~partition_type:1
PizieDust marked this conversation as resolved.
Show resolved Hide resolved
(Int32.of_int start_sector)
(Int32.of_int num_sectors)
with
| Ok partition ->
Printf.printf " - OK\n";
partition
| Error msg -> failwith msg)
partition_sizes
in
(* Mbr.make smart constructor checks for partition overlap, more than 1 active partitions and too many partitions *)
let mbr =
match Mbr.make partitions with
| Ok mbr -> mbr
| Error msg -> failwith ("Failed to create MBR: " ^ msg)
in

let oc = open_out_bin destination in
let mbr_buffer = Cstruct.create Mbr.sizeof in
Mbr.marshal mbr_buffer mbr;
output oc (Cstruct.to_bytes mbr_buffer) 0 Mbr.sizeof;
close_out oc;
Unix.truncate destination total_size
PizieDust marked this conversation as resolved.
Show resolved Hide resolved

let destination =
let doc = "Output file for the MBR formatted disk image" in
Arg.(
required
& opt (some string) None
& info [ "d"; "destination" ] ~docv:"destination" ~doc)

let partition_files =
let doc = "Data files to be written to the partitions" in
Arg.(value & pos_all file [] & info [] ~docv:"partition_files" ~doc)

let cmd =
let doc = "Create an MBR formatted disk image with an MBR header." in
let info = Cmd.info "create_mbr_disk" ~version:"1.0.0" ~doc in
Cmd.v info Term.(const create_mbr_disk $ destination $ partition_files)

let main () = exit (Cmd.eval cmd)
let () = main ()
7 changes: 6 additions & 1 deletion bin/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
(executables
(names mbr_inspect read_partition write_partition resize_partition)
(names
mbr_inspect
read_partition
write_partition
resize_partition
create_mbr_disk)
(libraries mbr cstruct cmdliner unix))
20 changes: 19 additions & 1 deletion bin/mbr_inspect.ml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,18 @@ let print_mbr_fields print_bootstrap_code mbr =
Printf.printf " minutes: %d\n" mbr.Mbr.minutes;
Printf.printf " hours: %d\n" mbr.Mbr.hours;
Printf.printf " disk_signature: %lx\n" mbr.Mbr.disk_signature;
let total_disk_size =
List.fold_left
(fun acc part ->
let partition_size =
Int64.mul
(Int64.of_int32 part.Mbr.Partition.sectors)
(Int64.of_int Mbr.sizeof)
in
Int64.add acc partition_size)
Int64.zero mbr.partitions
in
Printf.printf " disk_size: %Ld bytes\n" total_disk_size;
PizieDust marked this conversation as resolved.
Show resolved Hide resolved
List.iteri
(fun i part ->
let chs_begin = part.Mbr.Partition.first_absolute_sector_chs in
Expand All @@ -30,7 +42,13 @@ let print_mbr_fields print_bootstrap_code mbr =
cylinders heads sectors;
Printf.printf " lba_begin: %ld\n"
part.Mbr.Partition.first_absolute_sector_lba;
Printf.printf " size_sectors: %ld\n" part.Mbr.Partition.sectors)
Printf.printf " size_sectors: %ld\n" part.Mbr.Partition.sectors;
let partition_size =
Int64.mul
(Int64.of_int32 part.Mbr.Partition.sectors)
(Int64.of_int Mbr.sizeof)
in
Printf.printf " partition_size: %Ld bytes\n" partition_size)
mbr.partitions

let read_mbrs print_bootstrap_code mbrs =
Expand Down