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

Add fdisk utility #18

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
all: install test

TARGETS = echo cat
TARGETS = echo cat fdisk

test:
go test -v ./...

install:
@for cmd in $(TARGETS); do \
rm $(GOPATH)/bin/$$cmd; \
rm -f $(GOPATH)/bin/$$cmd; \
done; \
go install ./cmd/...
@for cmd in $(TARGETS); do \
Expand Down
94 changes: 94 additions & 0 deletions cmd/fdisk/cmds/mbr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package cmds

import (
"flag"
"fmt"

"github.com/tiago4orion/enzo/disk/mbr"
)

var (
flags *flag.FlagSet
flagHelp, flagCreate, flagUpdate *bool
flagAddpart, flagDelpart, flagStartsect *int
flagBootcode, flagLastsect *string
)

func init() {
flags = flag.NewFlagSet("mbr", flag.ContinueOnError)
flagHelp = flags.Bool("help", false, "Show this help")
flagCreate = flags.Bool("create", false, "Create new MBR")
flagUpdate = flags.Bool("update", false, "Update MBR")
flagAddpart = flag.Int("add-part", 0, "Add partition")
flagDelpart = flag.Int("del-part", 0, "Delete partition")
flagStartsect = flag.Int("start-sect", 0, "start sector")
flagLastsect = flag.String("last-sect", "", "last sector (modififers +K, +M, +G works)")
flagBootcode = flags.String("bootcode", "", "Bootsector binary code")
}

func addPart(disk string, partnumber int, startsect int, lastsect string) error {
mbrdata, err := mbr.FromFile(disk)

if err != nil {
return err
}

p := mbr.NewEmptyPartition()
mbrdata.SetPart(partnumber, p)
return nil
}

func MBR(args []string) error {
flags.Parse(args[1:])

if *flagHelp {
flags.PrintDefaults()
return nil
}

disks := flags.Args()

if len(disks) != 1 {
return fmt.Errorf("Require one device file")
}

if *flagCreate {
if *flagUpdate {
return fmt.Errorf("-create conflicts with -update")
}

return mbr.Create(disks[0], *flagBootcode)
}

if *flagUpdate {
if *flagAddpart <= 0 || *flagDelpart == 0 {
return fmt.Errorf("-update requires flag -add-part or --del-part")
}

if *flagAddpart != 0 {
partNumber := *flagAddpart

if *flagStartsect == -1 {
return fmt.Errorf("-add-part requires -start-sect")
}

if *flagLastsect == "" {
return fmt.Errorf("-add-part requires -last-sect")
}

return addPart(disks[0], partNumber, *flagStartsect, *flagLastsect)
}

return fmt.Errorf("-del-part not implemented")
}

for _, disk := range disks {
err := mbr.Info(disk)

if err != nil {
return err
}
}

return nil
}
Binary file added cmd/fdisk/fdisk
Binary file not shown.
44 changes: 44 additions & 0 deletions cmd/fdisk/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package main

import (
"fmt"
"os"

"github.com/tiago4orion/enzo/cmd/fdisk/cmds"
)

var (
perr = func(format string, args ...interface{}) (int, error) {
return fmt.Fprintf(os.Stderr, format, args...)
}
)

func usage() {
perr("fdisk <subcommand> [options] device/file\n")
perr("Subcommands:\n")
perr("\tmbr\n")
perr("\n")
perr("Use: fdisk <subcommand> -h for more info\n")
}

func main() {
var err error

if len(os.Args) <= 1 {
usage()
os.Exit(1)
}

switch os.Args[1] {
case "mbr":
err = cmds.MBR(os.Args[1:])
default:
perr("Invalid subcommand: %s\n", os.Args[1])
os.Exit(1)
}

if err != nil {
perr("error: %s\n", err)
os.Exit(1)
}
}
197 changes: 197 additions & 0 deletions disk/mbr/mbr.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
package mbr

import (
"fmt"
"io"
"math"
"os"
)

type (
mbr [MBRSize]byte

// cylinder-head-sector
chs struct {
head, sector uint8
cylinder uint16
}
)

const (
MBRSize = 0x200
// Classical MBR structure
CPart1 = 0x1be // 16 bytes each
CPart2 = 0x1ce
CPart3 = 0x1de
CPart4 = 0x1ee

PEntrySZ = 16

Magic1Off = 0x1fe
Magic2Off = 0x1ff

// MBR magic numbers
Magic1 = 0x55
Magic2 = 0xaa

// bootstrap code
BCOffEnd = 0x01bd
BCSize = BCOffEnd
)

func NewCHS(cylinder uint16, head uint8, sector uint8) chs {
return chs{
cylinder: cylinder,
head: head,
sector: sector,
}
}

func Info(fname string) error {
file, err := os.Open(fname)

if err != nil {
return err
}

var mbr [MBRSize]byte

_, err = file.Read(mbr[:])

if err != nil && err != io.EOF {
return err
}

if mbr[Magic1Off] != Magic1 &&
mbr[Magic2Off] != Magic2 {
return fmt.Errorf("no MBR found\n")
}

var part *partition
var empty bool

if part, err, empty = NewPartition(mbr[CPart1 : CPart1+PEntrySZ]); err != nil {
return err
} else if !empty {
fmt.Printf("%s\n", part)
}

if part, err, empty = NewPartition(mbr[CPart2 : CPart2+PEntrySZ]); err != nil {
return err
} else if !empty {
fmt.Printf("%s\n", part)
}

if part, err, empty = NewPartition(mbr[CPart3 : CPart3+PEntrySZ]); err != nil {
return err
} else if !empty {
fmt.Printf("%s\n", part)
}

if part, err, empty = NewPartition(mbr[CPart4 : CPart4+PEntrySZ]); err != nil {
return err
} else if !empty {
fmt.Printf("%s\n", part)
}

return nil
}

func NewMBR() mbr {
mbr := mbr{}
mbr[Magic1Off] = Magic1
mbr[Magic2Off] = Magic2
return mbr
}

func FromFile(disk string) (*mbr, error) {
mbr := mbr{}
devfile, err := os.OpenFile(disk, os.O_RDWR, 0)

if err != nil {
return nil, err
}

n, err := devfile.Read(mbr[:])

if err != nil && err != io.EOF {
return nil, err
}

if n < MBRSize {
return nil, fmt.Errorf("MBR requires at least 512 bytes")
}

return &mbr, nil
}

func (m mbr) SetBootcode(bcode []byte) error {
if len(bcode) > BCSize {
return fmt.Errorf("bootcode must have less than %d bytes", BCSize)
}

if copied := copy(m[0:BCOffEnd], bcode[:]); copied != len(bcode) {
return fmt.Errorf("Failed to copy bootcode to mbr")
}

return nil
}

func (m mbr) SetPart(index int, part *partition) {
copy(m[CPart1+index*16:16], part.Bytes())
}

func Create(devfname, bootfname string) error {
mbr := NewMBR()

devfile, err := os.OpenFile(devfname, os.O_RDWR, 0)

if err != nil {
return err
}

if bootfname != "" {
bfile, err := os.Open(bootfname)

if err != nil {
return err
}

var bootcode [BCSize + 1]byte

n, err := bfile.Read(bootcode[:])

if err == io.EOF || n > BCSize {
return fmt.Errorf("bootcode must have less than %d bytes. Got %d", BCSize, n)
}

err = mbr.SetBootcode(bootcode[0:n])

if err != nil {
return err
}
}

_, err = devfile.Write(mbr[:])

return err
}

func CHS2LBA(c uint16, h uint8, s uint8) uint32 {
return (uint32(c)*16+uint32(h))*63 + uint32((s - 1))
}

func LBA2C(lba uint32) uint16 {
return uint16(math.Mod(float64(lba), 16*63))
}

func LBA2H(lba uint32) uint8 {
lbaf := float64(lba)
spt := float64(63)
hpt := float64(16)
return uint8(math.Mod(math.Mod(lbaf, spt), hpt))
}

func LBA2S(lba uint32) uint8 {
return uint8(math.Mod(float64(lba), float64(63))) + 1
}
Loading