mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-21 01:59:07 +00:00
format: Add partition labels and new filesystems
This commit re-writes the format package in Go and adds the ability to add partition labels and also specify either ext4, btrfs or xfs Signed-off-by: Dave Tucker <dt@docker.com>
This commit is contained in:
parent
7cafad4fba
commit
5273ec1d33
@ -1,4 +1,4 @@
|
|||||||
FROM linuxkit/alpine:9bcf61f605ef0ce36cc94d59b8eac307862de6e1 AS mirror
|
FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS mirror
|
||||||
|
|
||||||
RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/
|
RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/
|
||||||
RUN apk add --no-cache --initdb -p /out \
|
RUN apk add --no-cache --initdb -p /out \
|
||||||
@ -6,17 +6,27 @@ RUN apk add --no-cache --initdb -p /out \
|
|||||||
busybox \
|
busybox \
|
||||||
e2fsprogs \
|
e2fsprogs \
|
||||||
e2fsprogs-extra \
|
e2fsprogs-extra \
|
||||||
jq \
|
btrfs-progs \
|
||||||
|
xfsprogs \
|
||||||
musl \
|
musl \
|
||||||
sfdisk \
|
sfdisk \
|
||||||
|
util-linux \
|
||||||
&& true
|
&& true
|
||||||
RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache
|
RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache
|
||||||
|
|
||||||
|
FROM linuxkit/alpine:488aa6f5dd2d8121a3c5c5c7a1ecf97c424b96ac AS build
|
||||||
|
|
||||||
|
RUN apk add --no-cache go musl-dev
|
||||||
|
ENV GOPATH=/go PATH=$PATH:/go/bin
|
||||||
|
|
||||||
|
COPY format.go /go/src/format/
|
||||||
|
RUN go-compile.sh /go/src/format
|
||||||
|
|
||||||
FROM scratch
|
FROM scratch
|
||||||
ENTRYPOINT []
|
ENTRYPOINT []
|
||||||
CMD []
|
CMD []
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
COPY --from=mirror /out/ /
|
COPY --from=mirror /out/ /
|
||||||
COPY format.sh /
|
COPY --from=build /go/bin/format usr/bin/format
|
||||||
CMD ["/bin/sh", "/format.sh"]
|
CMD ["/usr/bin/format"]
|
||||||
LABEL org.mobyproject.config='{"binds": ["/dev:/dev"], "capabilities": ["CAP_SYS_ADMIN", "CAP_MKNOD"], "net": "new", "ipc": "new"}'
|
LABEL org.mobyproject.config='{"binds": ["/dev:/dev"], "capabilities": ["CAP_SYS_ADMIN", "CAP_MKNOD"], "net": "new", "ipc": "new"}'
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
IMAGE=format
|
IMAGE=format
|
||||||
DEPS=format.sh
|
DEPS=format.go
|
||||||
|
|
||||||
include ../package.mk
|
include ../package.mk
|
||||||
|
184
pkg/format/format.go
Normal file
184
pkg/format/format.go
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
timeout = 60
|
||||||
|
ext4opts = "resize_inode,has_journal,extent,huge_file,flex_bg,uninit_bg,64bit,dir_nlink,extra_isize"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
labelVar string
|
||||||
|
fsTypeVar string
|
||||||
|
drives map[string]bool
|
||||||
|
driveKeys []string
|
||||||
|
)
|
||||||
|
|
||||||
|
func autoformat(label, fsType string) error {
|
||||||
|
var first string
|
||||||
|
for _, d := range driveKeys {
|
||||||
|
err := exec.Command("sfdisk", "-d", d).Run()
|
||||||
|
if err == nil {
|
||||||
|
log.Printf("Partition table found on device %s. Skipping.", d)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
first = d
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if first == "" {
|
||||||
|
return fmt.Errorf("No eligible disks found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := format(first, label, fsType); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func format(d, label, fsType string) error {
|
||||||
|
log.Printf("Creating partition on %s", d)
|
||||||
|
/* new disks do not have an DOS signature in sector 0
|
||||||
|
this makes sfdisk complain. We can workaround this by letting
|
||||||
|
fdisk create that DOS signature, by just do a "w", a write.
|
||||||
|
http://bugs.alpinelinux.org/issues/145
|
||||||
|
*/
|
||||||
|
fdiskCmd := exec.Command("fdisk", d)
|
||||||
|
fdiskCmd.Stdin = strings.NewReader("w")
|
||||||
|
if out, err := fdiskCmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("Error running fdisk: %v\n%s", err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// format one large partition
|
||||||
|
partCmd := exec.Command("sfdisk", "--quiet", d)
|
||||||
|
partCmd.Stdin = strings.NewReader(";")
|
||||||
|
if out, err := partCmd.CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("Error running sfdisk: %v\n%s", err, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update status
|
||||||
|
if err := exec.Command("blockdev", "--rereadpt", d).Run(); err != nil {
|
||||||
|
return fmt.Errorf("Error running blockdev: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
exec.Command("mdev", "-s").Run()
|
||||||
|
|
||||||
|
partition := fmt.Sprintf("%s1", d)
|
||||||
|
// wait for device
|
||||||
|
var done bool
|
||||||
|
for i := 0; i < timeout; i++ {
|
||||||
|
stat, err := os.Stat(partition)
|
||||||
|
if err == nil {
|
||||||
|
mode := stat.Sys().(*syscall.Stat_t).Mode
|
||||||
|
if (mode & syscall.S_IFMT) == syscall.S_IFBLK {
|
||||||
|
done = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
exec.Command("mdev", "-s").Run()
|
||||||
|
}
|
||||||
|
if !done {
|
||||||
|
return fmt.Errorf("Error waiting for device %s", partition)
|
||||||
|
}
|
||||||
|
// even after the device appears we still have a race
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
|
// mkfs
|
||||||
|
mkfsArgs := []string{"-t", fsType}
|
||||||
|
|
||||||
|
switch fsType {
|
||||||
|
case "ext4":
|
||||||
|
ext4Args := []string{"-F", "-O", ext4opts}
|
||||||
|
if label != "" {
|
||||||
|
ext4Args = append(ext4Args, []string{"-L", label}...)
|
||||||
|
}
|
||||||
|
mkfsArgs = append(mkfsArgs, ext4Args...)
|
||||||
|
case "btrfs":
|
||||||
|
btrfsArgs := []string{"-f"}
|
||||||
|
if label != "" {
|
||||||
|
btrfsArgs = append(btrfsArgs, []string{"-l", label}...)
|
||||||
|
}
|
||||||
|
mkfsArgs = append(mkfsArgs, btrfsArgs...)
|
||||||
|
case "xfs":
|
||||||
|
xfsArgs := []string{"-f"}
|
||||||
|
if label != "" {
|
||||||
|
xfsArgs = append(xfsArgs, []string{"-L", label}...)
|
||||||
|
}
|
||||||
|
mkfsArgs = append(mkfsArgs, xfsArgs...)
|
||||||
|
default:
|
||||||
|
log.Println("WARNING: Unsupported filesystem.")
|
||||||
|
}
|
||||||
|
|
||||||
|
mkfsArgs = append(mkfsArgs, partition)
|
||||||
|
if out, err := exec.Command("mkfs", mkfsArgs...).CombinedOutput(); err != nil {
|
||||||
|
return fmt.Errorf("Error running mkfs: %v\n%s", err, string(out))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Partition %s successfully created!", partition)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// return a list of all available drives
|
||||||
|
func findDrives() {
|
||||||
|
drives = make(map[string]bool)
|
||||||
|
driveKeys = []string{}
|
||||||
|
ignoreExp := regexp.MustCompile(`^loop.*$|^nbd.*$|^[a-z]+[0-9]+$`)
|
||||||
|
devs, _ := ioutil.ReadDir("/dev")
|
||||||
|
for _, d := range devs {
|
||||||
|
// this probably shouldn't be so hard
|
||||||
|
// but d.Mode()&os.ModeDevice == 0 doesn't work as expected
|
||||||
|
mode := d.Sys().(*syscall.Stat_t).Mode
|
||||||
|
if (mode & syscall.S_IFMT) != syscall.S_IFBLK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// ignore if it matches regexp
|
||||||
|
if ignoreExp.MatchString(d.Name()) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
driveKeys = append(driveKeys, filepath.Join("/dev", d.Name()))
|
||||||
|
}
|
||||||
|
sort.Strings(driveKeys)
|
||||||
|
for _, d := range driveKeys {
|
||||||
|
drives[d] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&labelVar, "label", "", "Disk label to apply")
|
||||||
|
flag.StringVar(&fsTypeVar, "type", "ext4", "Type of filesystem to create")
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
findDrives()
|
||||||
|
|
||||||
|
if flag.NArg() > 1 {
|
||||||
|
log.Fatalf("Too many arguments provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
if err := autoformat(labelVar, fsTypeVar); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := format(flag.Args()[0], labelVar, fsTypeVar); err != nil {
|
||||||
|
log.Fatalf("%v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,116 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# this script assumes anything on the disk can be removed if corrupted
|
|
||||||
# other use cases may need different scripts.
|
|
||||||
|
|
||||||
# currently only supports ext4 but should be expanded
|
|
||||||
|
|
||||||
do_fsck()
|
|
||||||
{
|
|
||||||
# preen
|
|
||||||
/sbin/e2fsck -p $*
|
|
||||||
EXIT_CODE=$?
|
|
||||||
# exit code 1 is errors corrected
|
|
||||||
[ "${EXIT_CODE}" -eq 1 ] && EXIT_CODE=0
|
|
||||||
# exit code 2 or 3 means need to reboot
|
|
||||||
[ "${EXIT_CODE}" -eq 2 -o "${EXIT_CODE}" -eq 3 ] && /sbin/reboot
|
|
||||||
# exit code 4 or over is fatal
|
|
||||||
[ "${EXIT_CODE}" -lt 4 ] && return "${EXIT_CODE}"
|
|
||||||
|
|
||||||
# try harder
|
|
||||||
/sbin/e2fsck -y $*
|
|
||||||
# exit code 1 is errors corrected
|
|
||||||
[ "${EXIT_CODE}" -eq 1 ] && EXIT_CODE=0
|
|
||||||
# exit code 2 or 3 means need to reboot
|
|
||||||
[ "${EXIT_CODE}" -eq 2 -o "${EXIT_CODE}" -eq 3 ] && /sbin/reboot
|
|
||||||
# exit code 4 or over is fatal
|
|
||||||
[ "${EXIT_CODE}" -ge 4 ] && printf "Filesystem unrecoverably corrupted, will reformat\n"
|
|
||||||
|
|
||||||
return "${EXIT_CODE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
do_fsck_extend_mount()
|
|
||||||
{
|
|
||||||
DRIVE="$1"
|
|
||||||
DATA="$2"
|
|
||||||
|
|
||||||
do_fsck "$DATA" || return 1
|
|
||||||
|
|
||||||
# only try to extend if there is a single partition and free space
|
|
||||||
PARTITIONS=$(sfdisk -J "$DRIVE" | jq '.partitiontable.partitions | length')
|
|
||||||
|
|
||||||
if [ "$PARTITIONS" -eq 1 ] && \
|
|
||||||
sfdisk -F "$DRIVE" | grep -q 'Unpartitioned space' &&
|
|
||||||
! sfdisk -F "$DRIVE" | grep -q '0 B, 0 bytes, 0 sectors'
|
|
||||||
then
|
|
||||||
SPACE=$(sfdisk -F "$DRIVE" | grep 'Unpartitioned space')
|
|
||||||
printf "Resizing disk partition: $SPACE\n"
|
|
||||||
|
|
||||||
# 83 is Linux partition id
|
|
||||||
START=$(sfdisk -J "$DRIVE" | jq -e '.partitiontable.partitions | map(select(.type=="83")) | .[0].start')
|
|
||||||
|
|
||||||
sfdisk -q --delete "$DRIVE" 2> /dev/null
|
|
||||||
echo "${START},,83;" | sfdisk -q "$DRIVE"
|
|
||||||
|
|
||||||
# set bootable flag
|
|
||||||
sfdisk -A "$DRIVE" 1
|
|
||||||
|
|
||||||
# update status
|
|
||||||
blockdev --rereadpt $diskdev 2> /dev/null
|
|
||||||
mdev -s
|
|
||||||
|
|
||||||
# wait for device
|
|
||||||
for i in $(seq 1 50); do test -b "$DATA" && break || sleep .1; mdev -s; done
|
|
||||||
|
|
||||||
# resize2fs fails unless we use -f here
|
|
||||||
do_fsck -f "$DATA" || return 1
|
|
||||||
resize2fs "$DATA"
|
|
||||||
|
|
||||||
do_fsck "$DATA" || return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
do_mkfs()
|
|
||||||
{
|
|
||||||
diskdev="$1"
|
|
||||||
|
|
||||||
# new disks does not have an DOS signature in sector 0
|
|
||||||
# this makes sfdisk complain. We can workaround this by letting
|
|
||||||
# fdisk create that DOS signature, by just do a "w", a write.
|
|
||||||
# http://bugs.alpinelinux.org/issues/145
|
|
||||||
echo "w" | fdisk $diskdev >/dev/null
|
|
||||||
|
|
||||||
# format one large partition
|
|
||||||
echo ";" | sfdisk --quiet $diskdev
|
|
||||||
|
|
||||||
# update status
|
|
||||||
blockdev --rereadpt $diskdev 2> /dev/null
|
|
||||||
|
|
||||||
# wait for device
|
|
||||||
for i in $(seq 1 50); do test -b "$DATA" && break || sleep .1; mdev -s; done
|
|
||||||
|
|
||||||
FSOPTS="-O resize_inode,has_journal,extent,huge_file,flex_bg,uninit_bg,64bit,dir_nlink,extra_isize"
|
|
||||||
|
|
||||||
mkfs.ext4 -q -F $FSOPTS ${diskdev}1
|
|
||||||
}
|
|
||||||
|
|
||||||
# TODO fix for multiple disks, cdroms etc
|
|
||||||
DEV="$(find /dev -maxdepth 1 -type b ! -name 'loop*' | grep -v '[0-9]$' | sed 's@.*/dev/@@' | sort | head -1 )"
|
|
||||||
|
|
||||||
[ -z "${DEV}" ] && exit 1
|
|
||||||
|
|
||||||
DRIVE="/dev/${DEV}"
|
|
||||||
|
|
||||||
# see if it has a partition table already
|
|
||||||
if sfdisk -d "${DRIVE}" >/dev/null 2>/dev/null
|
|
||||||
then
|
|
||||||
DATA=$(sfdisk -J "$DRIVE" | jq -e -r '.partitiontable.partitions | map(select(.type=="83")) | .[0].node')
|
|
||||||
if [ $? -eq 0 ]
|
|
||||||
then
|
|
||||||
do_fsck_extend_mount "$DRIVE" "$DATA" || do_mkfs "$DRIVE"
|
|
||||||
else
|
|
||||||
do_mkfs "$DRIVE"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
do_mkfs "$DRIVE"
|
|
||||||
fi
|
|
Loading…
Reference in New Issue
Block a user