summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-06-21 15:38:48 +0200
committerAlejandro Sior <aho@sior.be>2022-06-21 15:38:48 +0200
commitf42a480cbe487fc5fb9b3772990e80926201f6e4 (patch)
treed6af05ea6942732fafa721c97895b66cd42298b3 /cmd
parentd000a6edf4ad9fcc2302a80080fdbebb23fb7378 (diff)
gptman: reorganize commands in a cmd module
Diffstat (limited to 'cmd')
-rw-r--r--cmd/convert/convert.ha58
-rw-r--r--cmd/create/create.ha41
-rw-r--r--cmd/info/info.ha36
-rw-r--r--cmd/mkbackup/mkbackup.ha23
-rw-r--r--cmd/part/part.ha126
-rw-r--r--cmd/util.ha37
6 files changed, 321 insertions, 0 deletions
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]);
+ };
+};