summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlejandro Sior <aho@sior.be>2022-06-21 17:31:07 +0200
committerAlejandro Sior <aho@sior.be>2022-06-21 17:31:07 +0200
commit68b9c04241ef433f346279fbc153928bcbd360e9 (patch)
tree7235a65503151837906962cdc8f46ab241b432c2
parentf42a480cbe487fc5fb9b3772990e80926201f6e4 (diff)
gptman: polish create and convert
-rw-r--r--cmd/convert/convert.ha91
-rw-r--r--cmd/create/create.ha22
-rw-r--r--cmd/info/info.ha9
-rw-r--r--cmd/mkbackup/mkbackup.ha8
-rw-r--r--cmd/part/part.ha31
-rw-r--r--cmd/util.ha36
-rw-r--r--main.ha12
7 files changed, 145 insertions, 64 deletions
diff --git a/cmd/convert/convert.ha b/cmd/convert/convert.ha
index 807ae7f..b3cfd38 100644
--- a/cmd/convert/convert.ha
+++ b/cmd/convert/convert.ha
@@ -1,36 +1,76 @@
use fmt;
-
-use cmd;
-use mbr;
-use gpt;
-use sector;
-
use os;
use io;
use fs;
use strings;
use errors;
use rt;
+use getopt;
+
+use cmd;
+use mbr;
+use gpt;
+use sector;
+
-export fn convert(vol: str, args: []str) void = {
- if (len(args) < 2) {
- fmt::fatalf("convert: needs disk");
+export fn convert(args: []str) void = {
+ let nombr = false;
+ let notranslation = false;
+ let nohybrid = false;
+
+ const c = getopt::parse(args,
+ ('m', "do not overwrite the MBR bootstrap"),
+ ('t', "do not translate partitions to GPT"),
+ ('H', "do not create a hybrid MBR"),
+ "disk file"
+ );
+ defer getopt::finish(&c);
+
+ for (let i = 0z; i < len(c.opts); i += 1) {
+ const opt = c.opts[i];
+ switch (opt.0) {
+ case 'm' => nombr = true;
+ case 't' => notranslation = true;
+ case 'H' => nohybrid = true;
+ };
+ };
+
+ if (len(c.args) < 1)
+ fmt::fatalf("gpt.convert: need a disk file");
+
+ let sourcefd = match (os::open(c.args[0], fs::flags::RDONLY)) {
+ case let f: io::file =>
+ yield f;
+ case => fmt::fatalf("gpt.convert: could not open file {}", args[1]);
};
+ defer io::close(sourcefd)!;
- let source = os::open(args[1], fs::flags::RDONLY)!;
- defer io::close(source)!;
+ const source = mbr::from(sourcefd)!;
+ // XXX need mbr::finish()
- const source = mbr::from(source)!;
+ let fd = cmd::openfile();
+ defer io::close(fd)!;
- const vol = cmd::openvol(vol);
- let vol = gpt::from(vol)!;
+ let vol = cmd::opengpt(fd);
defer {
+ vol.mbr.entries[3] = mbr::entry {
+ part_type = 0xEE,
+ lba_begin = 0,
+ length = -1: u32,
+ ...
+ };
+
gpt::chksums(vol);
gpt::commit(vol)!;
gpt::finish(vol);
};
- rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector));
+ if (!nombr)
+ rt::memcpy(vol.mbr, source.bootsector, size(mbr::bootsector));
+
+ if (notranslation)
+ return;
+
for (let i = 0z; i < 4; i += 1) {
const entry = &source.bootsector.entries[i];
if (entry.lba_begin == 0 && entry.length == 0)
@@ -39,20 +79,21 @@ export fn convert(vol: str, args: []str) void = {
const reader = mbr::partstream_reader(source, entry)!;
const partlength = entry.length;
- const part = gpt::allocate(vol, partlength) as *gpt::entry;
+ const part = match (gpt::allocate(vol, partlength)) {
+ case let e: *gpt::entry =>
+ yield e;
+ case =>
+ fmt::errorfln("gpt.convert: could not allocate size needed for MBR partition {}", i)!;
+ continue;
+ };
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,
- ...
+ if (!nohybrid) {
+ vol.mbr.entries[i].lba_begin = part.lba_begin: u32;
+ vol.mbr.entries[i].length = (part.lba_end - part.lba_begin + 1): u32;
+ };
};
};
diff --git a/cmd/create/create.ha b/cmd/create/create.ha
index 124d86e..7733928 100644
--- a/cmd/create/create.ha
+++ b/cmd/create/create.ha
@@ -6,15 +6,16 @@ use os;
use strconv;
use gpt;
+use mbr;
use cmd;
-export fn create(vol: str, args: []str) void = {
+export fn create(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")
+ ('b', "bytes", "specify another length margin (bytes)"),
+ ('s', "sectors", "specify another length margin (sectors, 512 bytes)")
);
defer getopt::finish(&c);
@@ -25,17 +26,28 @@ export fn create(vol: str, args: []str) void = {
switch (opt.0) {
case 'l' =>
length += (strconv::stoi(opt.1)! / 512 + 1): size;
+ case 's' =>
+ length += strconv::stoi(opt.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);
+ const fd = cmd::mkfile();
+ defer io::close(fd)!;
+
+ const vol = gpt::create(fd, length);
defer {
gpt::chksums(vol);
gpt::commit(vol)!;
gpt::finish(vol);
};
+
+ vol.mbr.entries[3] = mbr::entry {
+ part_type = 0xEE,
+ lba_begin = 0,
+ length = -1: u32,
+ ...
+ };
};
diff --git a/cmd/info/info.ha b/cmd/info/info.ha
index 75ab499..8c0110a 100644
--- a/cmd/info/info.ha
+++ b/cmd/info/info.ha
@@ -1,19 +1,20 @@
use fmt;
use io;
+use os;
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);
+export fn info(args: []str) void = {
+ const fd = cmd::openfile();
+ const vol = cmd::opengpt(fd);
defer gpt::finish(vol);
const header = vol.primary.header;
- fmt::printfln("# GPT header info {}", name)!;
+ fmt::printfln("# GPT header info {}", os::args[1])!;
fmt::printfln("revision({})", header.revision)!;
fmt::printfln("header_size({})", header.header_size)!;
fmt::printfln("header_crc32({})", header.header_crc32)!;
diff --git a/cmd/mkbackup/mkbackup.ha b/cmd/mkbackup/mkbackup.ha
index 12093b5..b2c9ae6 100644
--- a/cmd/mkbackup/mkbackup.ha
+++ b/cmd/mkbackup/mkbackup.ha
@@ -4,9 +4,11 @@ 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)) {
+export fn mkbackup(args: []str) void = {
+ const fd = cmd::openfile();
+ defer io::close(fd)!;
+
+ const vol = match(gpt::from(fd)) {
case let g: *gpt::gpt =>
yield g;
case gpt::nogpt =>
diff --git a/cmd/part/part.ha b/cmd/part/part.ha
index a4b114f..138c093 100644
--- a/cmd/part/part.ha
+++ b/cmd/part/part.ha
@@ -3,18 +3,21 @@ use io;
use os;
use strconv;
-use gpt;
use cmd;
+use gpt;
-export fn part(vol: str, args: []str) void = {
+export fn part(args: []str) void = {
if (len(args) <= 1) {
- partlist(vol, args[1..]);
+ partlist(args[1..]);
return;
};
match (strconv::stou(args[1])) {
case let i: uint =>
- const vol = cmd::opengpt(vol);
+ const fd = cmd::openfile();
+ defer io::close(fd)!;
+
+ const vol = cmd::opengpt(fd);
defer gpt::finish(vol);
partno(vol, i, args[2..]);
return;
@@ -23,13 +26,16 @@ export fn part(vol: str, args: []str) void = {
};
switch (args[1]) {
- case "new" => partnew(vol, args[1..]);
- case "list" => partlist(vol, args[1..]);
+ case "new" => partnew(args[1..]);
+ case "list" => partlist(args[1..]);
};
};
-export fn partnew(vol: str, args: []str) void = {
- const vol = cmd::opengpt(vol);
+export fn partnew(args: []str) void = {
+ const fd = cmd::openfile();
+ defer io::close(fd)!;
+
+ const vol = cmd::opengpt(fd);
defer {
gpt::chksums(vol);
gpt::commit(vol)!;
@@ -46,8 +52,11 @@ export fn partnew(vol: str, args: []str) void = {
};
};
-export fn partlist(vol: str, args: []str) void = {
- const vol = cmd::opengpt(vol);
+export fn partlist(args: []str) void = {
+ const fd = cmd::openfile();
+ defer io::close(fd)!;
+
+ const vol = cmd::opengpt(fd);
defer gpt::finish(vol);
const header = vol.primary.header;
const entries = vol.primary.entries;
@@ -62,7 +71,7 @@ export fn partlist(vol: str, args: []str) void = {
};
fn partinfo(vol: *gpt::gpt, i: size) void = {
- const entry = &vol.primary.entries[i];
+ const entry = cmd::getgptentry(vol, i);
fmt::printfln("# Partition {}", i)!;
fmt::printfln("entries[{}].part_type([{},{}])", i, entry.part_type[0], entry.part_type[1])!;
diff --git a/cmd/util.ha b/cmd/util.ha
index 832a96f..7bbeca8 100644
--- a/cmd/util.ha
+++ b/cmd/util.ha
@@ -5,33 +5,49 @@ use os;
use gpt;
-export fn mkvol(vol: str) io::file = {
+export fn mkfile() io::file = {
+ const vol = os::args[1];
+
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);
+ fmt::fatalf("gpt: cannot open file {}", vol);
};
};
-export fn openvol(vol: str) io::file = {
+export fn openfile() io::file = {
+ const vol = os::args[1];
+
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);
+ fmt::fatalf("gpt: cannot open file {}", vol);
};
};
-export fn opengpt(vol: str) *gpt::gpt = {
- const vol = openvol(vol);
-
- return match (gpt::from(vol)) {
+export fn opengpt(fd: io::file) *gpt::gpt = {
+ return match (gpt::from(fd)) {
case let g: *gpt::gpt =>
yield g;
case io::error =>
- fmt::fatalf("{}: could not properly read disk {}", os::args[0], os::args[1]);
+ fmt::fatalf("gpt: could not properly read disk");
case =>
- fmt::fatalf("{}: no valid gpt in disk", os::args[0]);
+ fmt::fatalf("gpt: no valid gpt in disk");
};
};
+
+export fn getgptentry(vol: *gpt::gpt, i: size) *gpt::entry = {
+ const header = vol.primary.header;
+
+ if (i >= header.entries_len)
+ fmt::fatalf("gpt: invalid entry index");
+
+ const entry = &vol.primary.entries[i];
+
+ if (entry.lba_begin == 0 && entry.lba_end == 0)
+ fmt::fatalf("gpt: entry {} is not allocated", i);
+
+ return entry;
+};
diff --git a/main.ha b/main.ha
index 304b56c..09c5bf7 100644
--- a/main.ha
+++ b/main.ha
@@ -16,17 +16,17 @@ use cmd::part;
export fn main() void = {
if (len(os::args) < 3) {
- fmt::fatalf("{}: expected disk name", os::args[0]);
+ fmt::fatalf("gpt: expected disk name", os::args[0]);
};
const volume = os::args[1];
switch (os::args[2]) {
- case "convert" => convert::convert(volume, os::args[2..]);
- case "create" => create::create(volume, os::args[2..]);
- case "info" => info::info(volume, os::args[2..]);
- case "mkbackup" => mkbackup::mkbackup(volume, os::args[2..]);
- case "part" => part::part(volume, os::args[2..]);
+ case "convert" => convert::convert(os::args[2..]);
+ case "create" => create::create(os::args[2..]);
+ case "info" => info::info(os::args[2..]);
+ case "mkbackup" => mkbackup::mkbackup(os::args[2..]);
+ case "part" => part::part(os::args[2..]);
case => fmt::fatalf("{}: no such command {}", os::args[0], os::args[2]);
};
};