diff --git a/system/filesystem_linux.go b/system/filesystem_linux.go index 49aee85..706f543 100644 --- a/system/filesystem_linux.go +++ b/system/filesystem_linux.go @@ -17,13 +17,17 @@ package system import ( "bufio" "bytes" + "errors" "fmt" "io" + "io/ioutil" "log" "os" "os/exec" "path/filepath" + "strconv" "strings" + "syscall" "unicode" "github.com/vtolstov/go-ioctl" @@ -89,29 +93,38 @@ func ResizeRootFS() error { var stdout io.ReadCloser var stdin bytes.Buffer - mountpoint, err := rootMount() + partstart := 0 + partnum := 0 + device := "/tmp/resize_dev" + partition := "/tmp/resize_part" + active := false + extended := false + parttype := "Linux" + devFs, err := findFs() if err != nil { return err } - - partstart := "2048" - device, err := rootDevice() + devBlk, err := findBlock("/sys/block", devFs) if err != nil { return err } - - mbr := make([]byte, 446) - - f, err := os.OpenFile(device, os.O_RDONLY, os.FileMode(0400)) - if err != nil { - return err - } - _, err = io.ReadFull(f, mbr) - f.Close() - if err != nil { + if err = syscall.Mknod(device, uint32(os.ModeDevice|syscall.S_IFBLK|0600), devBlk.Int()); err != nil { return err } + defer os.Remove(device) + // mbr := make([]byte, 446) + /* + f, err := os.OpenFile(device, os.O_RDONLY, os.FileMode(0400)) + if err != nil { + return err + } + _, err = io.ReadFull(f, mbr) + f.Close() + if err != nil { + return err + } + */ cmd := exec.Command("fdisk", "-l", "-u", device) stdout, err = cmd.StdoutPipe() if err != nil { @@ -131,21 +144,42 @@ func ResizeRootFS() error { break } - if strings.HasPrefix(line, mountpoint) { - ps := strings.Fields(line) // /dev/sda1 * 4096 251658239 125827072 83 Linux + if strings.HasPrefix(line, device) { + partnum += 1 + ///test3 * 16384 204799 188416 92M 5 Extended + ps := strings.Fields(line) if ps[1] == "*" { - partstart = ps[2] + active = true + partstart, _ = strconv.Atoi(ps[2]) + parttype = ps[6] + if ps[7] == "Extended" { + extended = true + } } else { - partstart = ps[1] + active = false + partstart, _ = strconv.Atoi(ps[1]) + parttype = ps[5] + if ps[6] == "Extended" { + extended = true + } } } } - if err = cmd.Wait(); err != nil || partstart == "" { + if err = cmd.Wait(); err != nil || partstart == 0 { return fmt.Errorf("failed to open %s via fdisk 4\n", device) } - stdin.Write([]byte("o\nn\np\n1\n" + partstart + "\n\na\n1\nw\n")) + stdin.Write([]byte("d\n" + fmt.Sprintf("%d", partnum) + "\n")) + if extended { + stdin.Write([]byte("n\nl\n" + fmt.Sprintf("%d", partnum) + "\n" + fmt.Sprintf("%d", partstart) + "\n\n")) + } else { + stdin.Write([]byte("n\np\n" + fmt.Sprintf("%d", partnum) + "\n\n")) + } + if active { + stdin.Write([]byte("a\n" + fmt.Sprintf("%d", partnum) + "\n")) + } + stdin.Write([]byte("t\n" + fmt.Sprintf("%d", partnum) + "\n" + parttype + "\nw")) cmd = exec.Command("fdisk", "-u", device) cmd.Stdin = &stdin cmd.Run() @@ -155,15 +189,16 @@ func ResizeRootFS() error { if err != nil { return err } - _, err = w.Write(mbr) - if err != nil { - return err - } - err = w.Sync() - if err != nil { - return err - } - + /* + _, err = w.Write(mbr) + if err != nil { + return err + } + err = w.Sync() + if err != nil { + return err + } + */ blkerr := ioctl.BlkRRPart(w.Fd()) err = w.Close() if err != nil { @@ -186,10 +221,71 @@ func ResizeRootFS() error { } } } - log.Printf("resize filesystem via %s %s", "resize2fs", mountpoint) - err = exec.Command("resize2fs", mountpoint).Run() + + if err = syscall.Mknod(partition, uint32(os.ModeDevice|syscall.S_IFBLK|0600), devFs.Int()); err != nil { + return err + } + defer os.Remove(partition) + log.Printf("resize filesystem via %s %s", "resize2fs", partition) + buf, err := exec.Command("resize2fs", partition).CombinedOutput() if err != nil { + log.Printf("resize2fs %s", buf) return err } return nil } + +type Dev struct { + Major uint64 + Minor uint64 +} + +func (d *Dev) String() string { + return fmt.Sprintf("%d:%d", d.Major, d.Minor) +} + +func (d *Dev) Int() int { + return int(d.Major*256 + d.Minor) +} + +func findFs() (*Dev, error) { + var st syscall.Stat_t + + err := syscall.Stat("/", &st) + if err != nil { + return nil, err + } + return &Dev{Major: uint64(st.Dev / 256), Minor: uint64(st.Dev % 256)}, nil +} + +func findBlock(start string, s *Dev) (*Dev, error) { + var err error + fis, err := ioutil.ReadDir(start) + if err != nil { + return nil, err + } + for _, fi := range fis { + switch fi.Name() { + case "bdi", "subsystem", "device", "trace": + continue + } + if _, err := os.Stat(filepath.Join(start, "dev")); err == nil { + if buf, err := ioutil.ReadFile(filepath.Join(start, "dev")); err == nil { + dev := strings.TrimSpace(string(buf)) + if s.String() == dev { + if buf, err = ioutil.ReadFile(filepath.Join(filepath.Dir(start), "dev")); err == nil { + majorminor := strings.Split(strings.TrimSpace(string(buf)), ":") + major, _ := strconv.Atoi(majorminor[0]) + minor, _ := strconv.Atoi(majorminor[1]) + return &Dev{Major: uint64(major), Minor: uint64(minor)}, nil + } + } + } + } + devBlk, err := findBlock(filepath.Join(start, fi.Name()), s) + if err == nil { + return devBlk, err + } + } + return nil, errors.New("failed to find dev") +}