| // Copyright 2020 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package partutil |
| |
| import ( |
| "bytes" |
| "fmt" |
| "log" |
| "os" |
| "os/exec" |
| ) |
| |
| // ExtendPartition extends a partition to a specific end sector. |
| func ExtendPartition(disk string, partNumInt int, end uint64) error { |
| if len(disk) <= 0 || partNumInt <= 0 || end <= 0 { |
| return fmt.Errorf("invalid disk name, partition number or end sector, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d. ", disk, partNumInt, end) |
| } |
| |
| // get partition number string |
| partNum, err := PartNumIntToString(disk, partNumInt) |
| if err != nil { |
| return fmt.Errorf("error in converting partition number, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", disk, partNumInt, end, err) |
| } |
| |
| partName := disk + partNum |
| var tableBuffer bytes.Buffer |
| |
| // dump partition table. |
| table, err := ReadPartitionTable(disk) |
| if err != nil { |
| return fmt.Errorf("cannot read partition table of %q, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", disk, disk, partNumInt, end, err) |
| } |
| |
| var oldSize uint64 = 0 |
| var newSize uint64 = 0 |
| |
| // edit partition table. |
| table, err = HandlePartitionTable(table, partName, true, func(p *PartContent) { |
| oldSize = p.Size |
| newSize = end - p.Start + 1 |
| p.Size = newSize |
| }) |
| if err != nil { |
| return fmt.Errorf("error when editing partition table of %q, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", disk, disk, partNumInt, end, err) |
| } |
| if newSize <= oldSize { |
| return fmt.Errorf("new size=%d is not larger than the old size=%d, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", newSize, oldSize, disk, partNumInt, end, err) |
| } |
| |
| tableBuffer.WriteString(table) |
| |
| // write partition table back. |
| writeTableCmd := exec.Command("sudo", "sfdisk", "--no-reread", disk) |
| writeTableCmd.Stdin = &tableBuffer |
| writeTableCmd.Stdout = os.Stdout |
| writeTableCmd.Stderr = os.Stderr |
| if err := writeTableCmd.Run(); err != nil { |
| return fmt.Errorf("error in writing partition table back to %q, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", disk, disk, partNumInt, end, err) |
| } |
| |
| log.Printf("\nCompleted extending %s\n\n", partName) |
| |
| // check and repair file system in the partition. |
| cmd := exec.Command("sudo", "e2fsck", "-fp", partName) |
| cmd.Stdout = os.Stdout |
| cmd.Stderr = os.Stderr |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("error in checking file system of %q, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", partName, disk, partNumInt, end, err) |
| } |
| log.Printf("\nCompleted checking file system of %s\n\n", partName) |
| |
| // resize file system in the partition. |
| cmd = exec.Command("sudo", "resize2fs", partName) |
| cmd.Stdout = os.Stdout |
| cmd.Stderr = os.Stderr |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("error in resizing file system of %q, "+ |
| "input: disk=%q, partNumInt=%d, end sector=%d, "+ |
| "error msg: (%v)", partName, disk, partNumInt, end, err) |
| } |
| |
| log.Printf("\nCompleted updating file system of %q\n\n", partName) |
| return nil |
| } |