use fmt; use getopt; use io; use os; use strconv; use cmd; use gpt; export fn part(args: []str) void = { const fd = cmd::openfile(); defer io::close(fd)!; const vol = cmd::opengpt(fd); defer gpt::finish(vol); if (len(args) == 1) { partlist(vol); return; }; switch (args[1]) { case "new" => partnew(vol, args[1..]); return; case "list" => partlist(vol); return; case => yield; }; const entid = match (strconv::stou(args[1])) { case let i: uint => yield i; case => fmt::fatalf("gpt.part: invalid number"); }; partno(vol, entid, args[2..]); }; export fn partnew(vol: *gpt::gpt, args: []str) void = { defer { gpt::chksums(vol); gpt::commit(vol)!; }; const c = getopt::parse(args, ('f', "file", "specify a file that the partition must fit"), ('b', "bytes", "specify another length margin (bytes)"), ('s', "sectors", "specify another length margin (sectors, 512 bytes)") ); defer getopt::finish(&c); let length = 0z; for (let i = 0z; i < len(c.opts); i += 1) { const opt = c.opts[i]; // XXX incorrect calculations and handle incorrect input switch (opt.0) { case 'l' => length += (strconv::stoi64(opt.1)! / 512 + 1): size; case 's' => length += strconv::stou64(opt.1)!: size; case 'f' => const stat = os::stat(opt.1)!; length += stat.sz / 512 + 1; }; }; const entry = match (gpt::allocate(vol, length)) { case let e: *gpt::entry => yield e; case => fmt::fatalf("gpt.part: could not allocate entry of size {}", length); }; let id = (entry: uintptr - vol.primary.entries: uintptr): size / size(gpt::entry); fmt::printfln("{}", id)!; }; export fn partlist(vol: *gpt::gpt) void = { 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 = cmd::getgptentry(vol, 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 = cmd::getgptentry(vol, 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 = cmd::getgptentry(vol, 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)!; };