From f42a480cbe487fc5fb9b3772990e80926201f6e4 Mon Sep 17 00:00:00 2001 From: Alejandro Sior Date: Tue, 21 Jun 2022 15:38:48 +0200 Subject: gptman: reorganize commands in a cmd module --- cmd/convert/convert.ha | 58 ++++++++++++++++++++++ cmd/create/create.ha | 41 +++++++++++++++ cmd/info/info.ha | 36 ++++++++++++++ cmd/mkbackup/mkbackup.ha | 23 +++++++++ cmd/part/part.ha | 126 ++++++++++++++++++++++++++++++++++++++++++++++ cmd/util.ha | 37 ++++++++++++++ convert/convert.ha | 59 ---------------------- create/create.ha | 41 --------------- info/info.ha | 36 -------------- main.ha | 10 ++-- mkbackup/mkbackup.ha | 23 --------- part/part.ha | 127 ----------------------------------------------- volume/volume.ha | 37 -------------- 13 files changed, 326 insertions(+), 328 deletions(-) create mode 100644 cmd/convert/convert.ha create mode 100644 cmd/create/create.ha create mode 100644 cmd/info/info.ha create mode 100644 cmd/mkbackup/mkbackup.ha create mode 100644 cmd/part/part.ha create mode 100644 cmd/util.ha delete mode 100644 convert/convert.ha delete mode 100644 create/create.ha delete mode 100644 info/info.ha delete mode 100644 mkbackup/mkbackup.ha delete mode 100644 part/part.ha delete mode 100644 volume/volume.ha diff --git a/cmd/convert/convert.ha b/cmd/convert/convert.ha new file mode 100644 index 0000000..807ae7f --- /dev/null +++ b/cmd/convert/convert.ha @@ -0,0 +1,58 @@ +use fmt; + +use cmd; +use mbr; +use gpt; +use sector; + +use os; +use io; +use fs; +use strings; +use errors; +use rt; + +export fn convert(vol: str, args: []str) void = { + if (len(args) < 2) { + fmt::fatalf("convert: needs disk"); + }; + + let source = os::open(args[1], fs::flags::RDONLY)!; + defer io::close(source)!; + + const source = mbr::from(source)!; + + const vol = cmd::openvol(vol); + let vol = gpt::from(vol)!; + defer { + gpt::chksums(vol); + gpt::commit(vol)!; + gpt::finish(vol); + }; + + rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector)); + for (let i = 0z; i < 4; i += 1) { + const entry = &source.bootsector.entries[i]; + if (entry.lba_begin == 0 && entry.length == 0) + continue; + + const reader = mbr::partstream_reader(source, entry)!; + const partlength = entry.length; + + const part = gpt::allocate(vol, partlength) as *gpt::entry; + + const writer = gpt::partstream_writer(vol, part)!; + + io::copy(&writer, &reader)!; + + vol.mbr.entries[i].lba_begin = part.lba_begin: u32; + vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32; + }; + + vol.mbr.entries[3] = mbr::entry { + part_type = 0xEE, + lba_begin = 0, + length = -1: u32, + ... + }; +}; diff --git a/cmd/create/create.ha b/cmd/create/create.ha new file mode 100644 index 0000000..124d86e --- /dev/null +++ b/cmd/create/create.ha @@ -0,0 +1,41 @@ +use fmt; +use fs; +use getopt; +use io; +use os; +use strconv; + +use gpt; +use cmd; + +export fn create(vol: str, args: []str) void = { + // XXX this is a stub + + const c = getopt::parse(args, + "create a volume", + ('f', "file", "specify another partition file to fit"), + ('l', "length", "specify another length margin") + ); + defer getopt::finish(&c); + + let length = 0z; + + for (let i = 0z; i < len(c.opts); i += 1) { + const opt = c.opts[i]; + switch (opt.0) { + case 'l' => + length += (strconv::stoi(opt.1)! / 512 + 1): size; + case 'f' => + const stat = os::stat(opt.1)!; + length += stat.sz / 512 + 1; + }; + }; + + const vol = cmd::mkvol(vol); + const vol = gpt::create(vol, length); + defer { + gpt::chksums(vol); + gpt::commit(vol)!; + gpt::finish(vol); + }; +}; diff --git a/cmd/info/info.ha b/cmd/info/info.ha new file mode 100644 index 0000000..75ab499 --- /dev/null +++ b/cmd/info/info.ha @@ -0,0 +1,36 @@ +use fmt; +use io; + +use gpt; +use cmd; + +fn booltonum(a: bool) str = if (a) { return "1"; } else { return "0"; }; + +export fn info(vol: str, args: []str) void = { + const name = vol; + const vol = cmd::opengpt(vol); + defer gpt::finish(vol); + + const header = vol.primary.header; + + fmt::printfln("# GPT header info {}", name)!; + fmt::printfln("revision({})", header.revision)!; + fmt::printfln("header_size({})", header.header_size)!; + fmt::printfln("header_crc32({})", header.header_crc32)!; + fmt::printfln("header_lba({})", header.header_lba)!; + fmt::printfln("backup_header_lba({})", header.backup_header_lba)!; + fmt::printfln("first_lba({})", header.first_lba)!; + fmt::printfln("last_lba({})", header.last_lba)!; + // XXX Add a comment output for the GUID written in normal form + fmt::printfln("disk_guid([{},{}])", header.disk_guid[0], header.disk_guid[1])!; + fmt::printfln("entries_lba({})", header.entries_lba)!; + fmt::printfln("entries_len({})", header.entries_len)!; + fmt::printfln("entry_size({})", header.entry_size)!; + fmt::printfln("entries_crc32({})", header.entries_crc32)!; + + const primary_sane = gpt::header_crc32(header) == header.header_crc32 && gpt::entries_crc32(vol.primary.entries) == header.entries_crc32; + const backup_sane = gpt::header_crc32(vol.backup.header) == vol.backup.header.header_crc32 && gpt::entries_crc32(vol.backup.entries) == vol.backup.header.entries_crc32; + + fmt::printfln("primary_sane({})", booltonum(primary_sane))!; + fmt::printfln("backup_sane({})", booltonum(backup_sane))!; +}; diff --git a/cmd/mkbackup/mkbackup.ha b/cmd/mkbackup/mkbackup.ha new file mode 100644 index 0000000..12093b5 --- /dev/null +++ b/cmd/mkbackup/mkbackup.ha @@ -0,0 +1,23 @@ +use fmt; +use io; + +use cmd; +use gpt; + +export fn mkbackup(vol: str, args: []str) void = { + const vol = cmd::openvol(vol); + const vol = match(gpt::from(vol)) { + case let g: *gpt::gpt => + yield g; + case gpt::nogpt => + fmt::fatalf("{}: disk does not have valid gpt", args[0]); + case => + fmt::fatalf("{}: could not access volume", args[0]); + }; + defer { + gpt::commit(vol)!; + gpt::finish(vol); + }; + + gpt::mkbackup(vol); +}; diff --git a/cmd/part/part.ha b/cmd/part/part.ha new file mode 100644 index 0000000..a4b114f --- /dev/null +++ b/cmd/part/part.ha @@ -0,0 +1,126 @@ +use fmt; +use io; +use os; +use strconv; + +use gpt; +use cmd; + +export fn part(vol: str, args: []str) void = { + if (len(args) <= 1) { + partlist(vol, args[1..]); + return; + }; + + match (strconv::stou(args[1])) { + case let i: uint => + const vol = cmd::opengpt(vol); + defer gpt::finish(vol); + partno(vol, i, args[2..]); + return; + case => + yield; + }; + + switch (args[1]) { + case "new" => partnew(vol, args[1..]); + case "list" => partlist(vol, args[1..]); + }; +}; + +export fn partnew(vol: str, args: []str) void = { + const vol = cmd::opengpt(vol); + defer { + gpt::chksums(vol); + gpt::commit(vol)!; + gpt::finish(vol); + }; + + const sz = 71z; + + const entry = match (gpt::allocate(vol, sz)) { + case let e: *gpt::entry => + yield e; + case => + fmt::fatalf("gpt.part: could not allocate entry of size {}", sz); + }; +}; + +export fn partlist(vol: str, args: []str) void = { + const vol = cmd::opengpt(vol); + defer gpt::finish(vol); + const header = vol.primary.header; + const entries = vol.primary.entries; + + for (let i = 0z; i < header.entries_len; i += 1) { + const entry = &entries[i]; + if (entry.lba_begin == 0 && entry.lba_end == 0) + continue; + + partinfo(vol, i); + }; +}; + +fn partinfo(vol: *gpt::gpt, i: size) void = { + const entry = &vol.primary.entries[i]; + + fmt::printfln("# Partition {}", i)!; + fmt::printfln("entries[{}].part_type([{},{}])", i, entry.part_type[0], entry.part_type[1])!; + fmt::printfln("entries[{}].part([{},{}])", i, entry.part[0], entry.part[1])!; + fmt::printfln("entries[{}].lba_begin({})", i, entry.lba_begin)!; + fmt::printfln("entries[{}].lba_end({})", i, entry.lba_end)!; + fmt::printfln("entries[{}].attributes({})", i, entry.attributes)!; + + // XXX name +}; + +fn partno(vol: *gpt::gpt, i: size, args: []str) void = { + const header = vol.primary.header; + + if (i >= header.entries_len) + fmt::fatalf("gpt.part: invalid partition number"); + + if (len(args) == 0) { + partinfo(vol, i); + return; + }; + + switch (args[0]) { + case "fill" => + partfill(vol, i); + case "dump" => + partdump(vol, i); + }; +}; + +fn partfill(vol: *gpt::gpt, i: size) void = { + const entry = &vol.primary.entries[i]; + + if (entry.lba_begin == 0 && entry.lba_end == 0) + fmt::fatalf("gpt.part: partition {} is not allocated", i); + + const writer = match (gpt::partstream_writer(vol, entry)) { + case let l: io::limitstream => + yield l; + case => + fmt::fatalf("gpt.part: could not create a writing stream"); + }; + + io::copy(&writer, os::stdin)!; +}; + +fn partdump(vol: *gpt::gpt, i: size) void = { + const entry = &vol.primary.entries[i]; + + if (entry.lba_begin == 0 && entry.lba_end == 0) + fmt::fatalf("gpt.part: partition {} is not allocated", i); + + const reader = match (gpt::partstream_reader(vol, entry)) { + case let l: io::limitstream => + yield l; + case => + fmt::fatalf("gpt.part: could not create a reading stream"); + }; + + io::copy(os::stdout, &reader)!; +}; diff --git a/cmd/util.ha b/cmd/util.ha new file mode 100644 index 0000000..832a96f --- /dev/null +++ b/cmd/util.ha @@ -0,0 +1,37 @@ +use fmt; +use fs; +use io; +use os; + +use gpt; + +export fn mkvol(vol: str) io::file = { + return match (os::create(vol, fs::mode::USER_RWX | fs::mode::GROUP_RX | fs::mode::OTHER_RX, fs::flags::RDWR)) { + case let v: io::file => + yield v; + case => + fmt::fatalf("{}: cannot open file {}", os::args[0], vol); + }; +}; + +export fn openvol(vol: str) io::file = { + return match (os::open(vol, fs::flags::RDWR)) { + case let v: io::file => + yield v; + case => + fmt::fatalf("{}: cannot open file {}", os::args[0], vol); + }; +}; + +export fn opengpt(vol: str) *gpt::gpt = { + const vol = openvol(vol); + + return match (gpt::from(vol)) { + case let g: *gpt::gpt => + yield g; + case io::error => + fmt::fatalf("{}: could not properly read disk {}", os::args[0], os::args[1]); + case => + fmt::fatalf("{}: no valid gpt in disk", os::args[0]); + }; +}; diff --git a/convert/convert.ha b/convert/convert.ha deleted file mode 100644 index dbf4ef4..0000000 --- a/convert/convert.ha +++ /dev/null @@ -1,59 +0,0 @@ -use fmt; - -use mbr; -use gpt; -use sector; - -use os; -use io; -use fs; -use strings; -use errors; -use rt; - -use volume; - -export fn convert(vol: str, args: []str) void = { - if (len(args) < 2) { - fmt::fatalf("convert: needs disk"); - }; - - let source = os::open(args[1], fs::flags::RDONLY)!; - defer io::close(source)!; - - const source = mbr::from(source)!; - - const vol = volume::openvol(vol); - let vol = gpt::from(vol)!; - defer { - gpt::chksums(vol); - gpt::commit(vol)!; - gpt::finish(vol); - }; - - rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector)); - for (let i = 0z; i < 4; i += 1) { - const entry = &source.bootsector.entries[i]; - if (entry.lba_begin == 0 && entry.length == 0) - continue; - - const reader = mbr::partstream_reader(source, entry)!; - const partlength = entry.length; - - const part = gpt::allocate(vol, partlength) as *gpt::entry; - - const writer = gpt::partstream_writer(vol, part)!; - - io::copy(&writer, &reader)!; - - vol.mbr.entries[i].lba_begin = part.lba_begin: u32; - vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32; - }; - - vol.mbr.entries[3] = mbr::entry { - part_type = 0xEE, - lba_begin = 0, - length = -1: u32, - ... - }; -}; diff --git a/create/create.ha b/create/create.ha deleted file mode 100644 index b7dc0f7..0000000 --- a/create/create.ha +++ /dev/null @@ -1,41 +0,0 @@ -use fmt; -use fs; -use getopt; -use io; -use os; -use strconv; - -use gpt; -use volume; - -export fn create(vol: str, args: []str) void = { - // XXX this is a stub - - const cmd = getopt::parse(args, - "create a volume", - ('f', "file", "specify another partition file to fit"), - ('l', "length", "specify another length margin") - ); - defer getopt::finish(&cmd); - - let length = 0z; - - for (let i = 0z; i < len(cmd.opts); i += 1) { - const opt = cmd.opts[i]; - switch (opt.0) { - case 'l' => - length += (strconv::stoi(opt.1)! / 512 + 1): size; - case 'f' => - const stat = os::stat(opt.1)!; - length += stat.sz / 512 + 1; - }; - }; - - const vol = volume::mkvol(vol); - const vol = gpt::create(vol, length); - defer { - gpt::chksums(vol); - gpt::commit(vol)!; - gpt::finish(vol); - }; -}; diff --git a/info/info.ha b/info/info.ha deleted file mode 100644 index 7df9ee2..0000000 --- a/info/info.ha +++ /dev/null @@ -1,36 +0,0 @@ -use fmt; -use io; - -use gpt; -use volume; - -fn booltonum(a: bool) str = if (a) { return "1"; } else { return "0"; }; - -export fn info(vol: str, args: []str) void = { - const name = vol; - const vol = volume::opengpt(vol); - defer gpt::finish(vol); - - const header = vol.primary.header; - - fmt::printfln("# GPT header info {}", name)!; - fmt::printfln("revision({})", header.revision)!; - fmt::printfln("header_size({})", header.header_size)!; - fmt::printfln("header_crc32({})", header.header_crc32)!; - fmt::printfln("header_lba({})", header.header_lba)!; - fmt::printfln("backup_header_lba({})", header.backup_header_lba)!; - fmt::printfln("first_lba({})", header.first_lba)!; - fmt::printfln("last_lba({})", header.last_lba)!; - // XXX Add a comment output for the GUID written in normal form - fmt::printfln("disk_guid([{},{}])", header.disk_guid[0], header.disk_guid[1])!; - fmt::printfln("entries_lba({})", header.entries_lba)!; - fmt::printfln("entries_len({})", header.entries_len)!; - fmt::printfln("entry_size({})", header.entry_size)!; - fmt::printfln("entries_crc32({})", header.entries_crc32)!; - - const primary_sane = gpt::header_crc32(header) == header.header_crc32 && gpt::entries_crc32(vol.primary.entries) == header.entries_crc32; - const backup_sane = gpt::header_crc32(vol.backup.header) == vol.backup.header.header_crc32 && gpt::entries_crc32(vol.backup.entries) == vol.backup.header.entries_crc32; - - fmt::printfln("primary_sane({})", booltonum(primary_sane))!; - fmt::printfln("backup_sane({})", booltonum(backup_sane))!; -}; diff --git a/main.ha b/main.ha index b82aa3d..304b56c 100644 --- a/main.ha +++ b/main.ha @@ -7,11 +7,11 @@ use io; use mbr; use gpt; -use convert; -use create; -use info; -use mkbackup; -use part; +use cmd::convert; +use cmd::create; +use cmd::info; +use cmd::mkbackup; +use cmd::part; export fn main() void = { diff --git a/mkbackup/mkbackup.ha b/mkbackup/mkbackup.ha deleted file mode 100644 index 55f8464..0000000 --- a/mkbackup/mkbackup.ha +++ /dev/null @@ -1,23 +0,0 @@ -use fmt; -use io; - -use volume; -use gpt; - -export fn mkbackup(vol: str, args: []str) void = { - const vol = volume::openvol(vol); - const vol = match(gpt::from(vol)) { - case let g: *gpt::gpt => - yield g; - case gpt::nogpt => - fmt::fatalf("{}: disk does not have valid gpt", args[0]); - case => - fmt::fatalf("{}: could not access volume", args[0]); - }; - defer { - gpt::commit(vol)!; - gpt::finish(vol); - }; - - gpt::mkbackup(vol); -}; diff --git a/part/part.ha b/part/part.ha deleted file mode 100644 index 7584daf..0000000 --- a/part/part.ha +++ /dev/null @@ -1,127 +0,0 @@ -use fmt; -use io; -use os; -use strconv; - -use gpt; -use volume; - - -export fn part(vol: str, args: []str) void = { - if (len(args) <= 1) { - partlist(vol, args[1..]); - return; - }; - - match (strconv::stou(args[1])) { - case let i: uint => - const vol = volume::opengpt(vol); - defer gpt::finish(vol); - partno(vol, i, args[2..]); - return; - case => - yield; - }; - - switch (args[1]) { - case "new" => partnew(vol, args[1..]); - case "list" => partlist(vol, args[1..]); - }; -}; - -export fn partnew(vol: str, args: []str) void = { - const vol = volume::opengpt(vol); - defer { - gpt::chksums(vol); - gpt::commit(vol)!; - gpt::finish(vol); - }; - - const sz = 71z; - - const entry = match (gpt::allocate(vol, sz)) { - case let e: *gpt::entry => - yield e; - case => - fmt::fatalf("gpt.part: could not allocate entry of size {}", sz); - }; -}; - -export fn partlist(vol: str, args: []str) void = { - const vol = volume::opengpt(vol); - defer gpt::finish(vol); - const header = vol.primary.header; - const entries = vol.primary.entries; - - for (let i = 0z; i < header.entries_len; i += 1) { - const entry = &entries[i]; - if (entry.lba_begin == 0 && entry.lba_end == 0) - continue; - - partinfo(vol, i); - }; -}; - -fn partinfo(vol: *gpt::gpt, i: size) void = { - const entry = &vol.primary.entries[i]; - - fmt::printfln("# Partition {}", i)!; - fmt::printfln("entries[{}].part_type([{},{}])", i, entry.part_type[0], entry.part_type[1])!; - fmt::printfln("entries[{}].part([{},{}])", i, entry.part[0], entry.part[1])!; - fmt::printfln("entries[{}].lba_begin({})", i, entry.lba_begin)!; - fmt::printfln("entries[{}].lba_end({})", i, entry.lba_end)!; - fmt::printfln("entries[{}].attributes({})", i, entry.attributes)!; - - // XXX name -}; - -fn partno(vol: *gpt::gpt, i: size, args: []str) void = { - const header = vol.primary.header; - - if (i >= header.entries_len) - fmt::fatalf("gpt.part: invalid partition number"); - - if (len(args) == 0) { - partinfo(vol, i); - return; - }; - - switch (args[0]) { - case "fill" => - partfill(vol, i); - case "dump" => - partdump(vol, i); - }; -}; - -fn partfill(vol: *gpt::gpt, i: size) void = { - const entry = &vol.primary.entries[i]; - - if (entry.lba_begin == 0 && entry.lba_end == 0) - fmt::fatalf("gpt.part: partition {} is not allocated", i); - - const writer = match (gpt::partstream_writer(vol, entry)) { - case let l: io::limitstream => - yield l; - case => - fmt::fatalf("gpt.part: could not create a writing stream"); - }; - - io::copy(&writer, os::stdin)!; -}; - -fn partdump(vol: *gpt::gpt, i: size) void = { - const entry = &vol.primary.entries[i]; - - if (entry.lba_begin == 0 && entry.lba_end == 0) - fmt::fatalf("gpt.part: partition {} is not allocated", i); - - const reader = match (gpt::partstream_reader(vol, entry)) { - case let l: io::limitstream => - yield l; - case => - fmt::fatalf("gpt.part: could not create a reading stream"); - }; - - io::copy(os::stdout, &reader)!; -}; diff --git a/volume/volume.ha b/volume/volume.ha deleted file mode 100644 index 832a96f..0000000 --- a/volume/volume.ha +++ /dev/null @@ -1,37 +0,0 @@ -use fmt; -use fs; -use io; -use os; - -use gpt; - -export fn mkvol(vol: str) io::file = { - return match (os::create(vol, fs::mode::USER_RWX | fs::mode::GROUP_RX | fs::mode::OTHER_RX, fs::flags::RDWR)) { - case let v: io::file => - yield v; - case => - fmt::fatalf("{}: cannot open file {}", os::args[0], vol); - }; -}; - -export fn openvol(vol: str) io::file = { - return match (os::open(vol, fs::flags::RDWR)) { - case let v: io::file => - yield v; - case => - fmt::fatalf("{}: cannot open file {}", os::args[0], vol); - }; -}; - -export fn opengpt(vol: str) *gpt::gpt = { - const vol = openvol(vol); - - return match (gpt::from(vol)) { - case let g: *gpt::gpt => - yield g; - case io::error => - fmt::fatalf("{}: could not properly read disk {}", os::args[0], os::args[1]); - case => - fmt::fatalf("{}: no valid gpt in disk", os::args[0]); - }; -}; -- cgit v1.2.3