#!/bin/sh PREFIX= . "$PREFIX/lib/libalpine.sh" MBR=${MBR:-"/usr/share/syslinux/mbr.bin"} in_list() { local i="$1" shift while [ $# -gt 0 ]; do [ "$i" = "$1" ] && return 0 shift done return 1 } # wrapper to only show given device _blkid() { blkid | grep "^$1:" } # if given device have an UUID display it, otherwise return the device uuid_or_device() { local i= case "$1" in /dev/md*) echo "$1" && return 0;; esac for i in $(_blkid "$1"); do case "$i" in UUID=*) eval $i;; esac done if [ -n "$UUID" ]; then echo "UUID=$UUID" else echo "$1" fi } # generate an fstab from a given mountpoint. Convert to UUID if possible enumerate_fstab() { local mnt="$1" local fs_spec= fs_file= fs_vfstype= fs_mntops= fs_freq= fs_passno= [ -z "$mnt" ] && return local escaped_mnt=$(echo $mnt | sed 's:/:\\/:g') awk "\$2 ~ /^$escaped_mnt/ {print \$0}" /proc/mounts | \ sed "s:$mnt:/:g; s: :\t:g" | sed 's:/\+:/:g' | \ while read fs_spec fs_file fs_vfstype fs_mntops fs_freq fs_passno; do echo -e "$(uuid_or_device $fs_spec)\t${fs_file}\t${fs_vfstype}\t${fs_mntops} ${fs_freq} ${fs_passno}" done } is_vmware() { grep -q VMware /proc/scsi/scsi 2>/dev/null \ || grep -q VMware /proc/ide/hd*/model 2>/dev/null } is_xen() { [ -d /proc/xen ] } # Find the disk device from given partition disk_from_part() { # we need convert cciss/c0d0* cciss!c0d0*... local i= part=$(echo ${1#/dev/} | sed 's:/:!:g') for i in /sys/block/*/$part; do i=${i%/*} # ...and back from cciss!c0d0 to cciss/c0d0 echo "/dev/${i##*/}" | sed 's:!:/:g' return 0 done return 1 } unpack_apkovl() { local ovl="$1" local dest="$2" local suffix=${ovl##*.} local i ovlfiles=/tmp/ovlfiles if [ "$suffix" = "gz" ]; then if ! tar -C "$dest" --numeric-owner -zxvf "$ovl" > $ovlfiles; then echo -n "Continue anyway? [Y/n]: " read i case "$i" in n*|N*) return 1;; esac fi return 0 fi apk add -q openssl if ! openssl list-cipher-commands | grep "^$suffix$" > /dev/null; then errstr="Cipher $suffix is not supported" return 1 fi local count=0 # beep echo -e "\007" while [ $count -lt 3 ]; do openssl enc -d -$suffix -in "$ovl" | tar --numeric-owner \ -C "$dest" -zxv >$ovlfiles 2>/dev/null && return 0 count=$(( $count + 1 )) done ovlfiles= return 1 } install_mounted_root() { local mnt="$1" local features="ata base bootchart cdrom ext2 ext3 ide scsi usb" rootdev=$(awk "\$2 == \"$mnt\" { print \$1 }" /proc/mounts) if [ -z "$rootdev" ]; then echo "$mnt does not seem to be a mount point" >&2 return 1 fi local fs=$(awk "\$1 == \"$rootdev\" {print \$3}" /proc/mounts) if [ "$fs" != "ext2" ] && [ "$fs" != "ext3" ]; then echo "$fs is not supported. Only ext2 and ext3 are supported" >&2 return 1 fi rootdisk=$(disk_from_part $rootdev) if [ -z "$APKOVL" ]; then ovlfiles=/tmp/ovlfiles lbu package - | tar -C "$mnt" -zxv > "$ovlfiles" else echo "Restoring backup from $APKOVL to $rootdev..." unpack_apkovl "$APKOVL" "$mnt" || return 1 fi # remove the installed db in case its there so we force re-install rm -f "$mnt"/var/lib/apk/installed echon "Installing system on $rootdev: " # apk reads config from target root so we need to copy the config mkdir -p "$mnt"/etc/apk/keys/ cp /etc/apk/keys/* "$mnt"/etc/apk/keys/ local apkflags="--quiet --progress --update-cache --clean-protected" local pkgs=$(cat "$mnt"/var/lib/apk/world) pkgs="$pkgs acct linux-$KERNEL_FLAVOR alpine-base" local repos=$(sed -e 's/\#.*//' /etc/apk/repositories) local repoflags= for i in $repos; do repoflags="$repoflags --repository $i" done apk add --root "$mnt" $apkflags --overlay-from-stdin \ $repoflags $pkgs <$ovlfiles>/dev/null || return 1 echo "" # make things bootable if [ -e "/sys/block/${rootdev#/dev/}/md" ]; then local md=${rootdev#/dev/} features="$features raid" raidmod=$(cat /sys/block/$md/md/level) raidmod=",$raidmod" raidopt="-r" # get a list of slaves rootdisk= for i in /sys/block/$md/slaves/*; do j=${i##*/} i=${j%[0-9]*} rootdisk="$rootdisk /dev/${i}" done fi if is_vmware; then pax_nouderef="pax_nouderef " else pax_nouderef= fi if is_xen; then # create a menu.lst mkdir -p "$mnt"/boot/grub cat >"$mnt"/boot/grub/menu.lst <"$mnt"/boot/extlinux.conf <> "$mnt"/etc/fstab # install extlinux apk add -q syslinux is_xen || extlinux -i $raidopt "$mnt"/boot/ # unmount the partitions umount $(awk '{print $2}' /proc/mounts | grep ^"$mnt" | sort -r) # fix mbr for all disk devices for i in $rootdisk; do local errmsg echo "Writing MBR to $i" errmsg=$(dd if="$MBR" of=$i 2>&1) \ || echo "$errmsg" done echo "" echo "Installation is done. Please reboot." apk del -q syslinux } # figure out decent default swap size in mega bytes find_swap_size() { local memtotal_kb=$(awk '$1 == "MemTotal:" {print $2}' /proc/meminfo) # use 2 * avaiable ram echo $(( $memtotal_kb * 2 / 1024 )) } has_mounted_part() { local p # parse /proc/mounts for mounted devices for p in $(awk '$1 ~ /^\/dev\// {gsub("/dev/", "", $1); print $1}' \ /proc/mounts); do [ "$p" = "$1" ] && return 0 [ -e /sys/block/$1/$p ] && return 0 done return 1 } has_holders() { local i # check if device is used by any md devices for i in $1/holders/* $1/*/holders/*; do [ -e "$i" ] && return 0 done return 1 } is_available_disk() { local dev=$1 local b=$(echo $p | sed 's:/:!:g') # check if its a "root" block device and not a partition [ -e /sys/block/$b ] || return 1 # check so it does not have mounted partitions has_mounted_part $dev && return 1 # check so its not part of an md setup if has_holders /sys/block/$b; then [ -n "$USE_RAID" ] && echo "Warning: $dev is part of a running raid" >&2 return 1 fi # check so its not an md device [ -e /sys/block/$b/md ] && return 1 return 0 } find_disks() { local p= for p in $(awk '$1 ~ /[0-9]+/ {print $4}' /proc/partitions); do is_available_disk $p && echo -n " $p" done } useall() { local rootdisk_dev="$1" local i size local boot_size=100 boot_part_type="83" local swap_size=$(find_swap_size) swap_part_type="82" local root_part_type="83" local raidpkg= partitions= local minimum_root_size=$(($boot_size * 2)); if [ -n "$USE_RAID" ]; then boot_part_type="fd" swap_part_type="fd" root_part_type="fd" raidpkg="mdadm" fi dmesg -n1 apk_add -q sfdisk e2fsprogs $raidpkg || return 1 local root_size=$(( $(sfdisk -s $rootdisk_dev) / 1024 - $swap_size - $boot_size)) if [ "$root_size" -lt "$minimum_root_size" ]; then echo "The $rootdisk_dev is too small. At least $(( $boot_size + $swap_size + $minimum_root_size)) is needed." >&2 return 1 fi echo "" echo "Creating the following partitions on $rootdisk_dev:" echo " /boot ${boot_size}MB" echo " swap ${swap_size}MB" echo " / ${root_size}MB" echo "" if [ -n "$APKOVL" ]; then echo "System from $APKOVL will be restored" fi echo -n "WARNING: All contents of $rootdisk_dev will be erased. Continue? [y/N]: " read i case "$i" in y*|Y*);; *) return 1;; esac echo "Initializing partitions..." if [ -n "$USE_RAID" ]; then local rd for rd in md0 md1 md2; do [ -b /dev/$rd ] && mdadm --stop /dev/$rd done fi # 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/show/145 echo "w" | fdisk $rootdisk_dev >/dev/null # create new partitions (cat <>/tmp/sfdisk.out || return 1 # create device nodes if not exist mdev -s if [ -n "$USE_RAID" ]; then local p= rd= for p in $(sfdisk -l $rootdisk_dev 2>/dev/null \ | awk '/Linux raid/ {print $1}'); do local opt="--metadata=0.90" case "$p" in *1) rd=/dev/md0; boot_dev=/dev/md0;; *2) rd=/dev/md1; swap_dev=/dev/md1 opt= ;; *3) rd=/dev/md2; root_dev=/dev/md2;; esac mdadm --create $rd --level=1 --raid-devices=2 \ $opt --quiet --run $p missing done else local p= for p in $(sfdisk -l $rootdisk_dev 2>/dev/null \ | awk '$1 ~ /^\/dev/ {print $1}'); do case "$p" in *1) boot_dev=$p;; *2) swap_dev=$p;; *3) root_dev=$p;; esac done fi mkfs.ext3 -q $boot_dev >/dev/null \ && mkswap $swap_dev >/dev/null \ && mkfs.ext3 -q >/dev/null $root_dev \ || return 1 mkdir -p /mnt mount -t ext3 $root_dev /mnt || return 1 mkdir -p /mnt/boot mount -t ext3 $boot_dev /mnt/boot || return 1 if [ -n "$USE_RAID" ]; then mdadm --detail --scan > /etc/mdadm.conf rc-update --quiet add mdadm-raid boot fi rc-update --quiet add swap boot install_mounted_root /mnt || return 1 # the func to generate fstab does not detect swap. add it manually sed -i -e '/swap/d' /etc/fstab echo -e "$(uuid_or_device $swap_dev)\tswap\t\tswap\tdefaults 0 0" >> /etc/fstab } usage() { cat <<__EOF__ usage: setup-disk [-hr] [-k kernelflavor] [-o apkovl] [MOUNTPOINT] Install alpine on harddisk. options: -h Show this help -o Restore system from given apkovl file -k Use kernelflavor instead of $KERNEL_FLAVOR -r Enable software raid1 with single disk __EOF__ exit 1 } KERNEL_FLAVOR=grsec case "$(uname -r)" in *-vs[0-9]*) KERNEL_FLAVOR=vserver;; *-pae) KERNEL_FLAVOR=pae;; esac # Parse args while getopts "hk:o:r" opt; do case $opt in k) KERNEL_FLAVOR="$OPTARG";; r) USE_RAID=1;; o) APKOVL="$OPTARG";; *) usage;; esac done shift $(( OPTIND - 1)) if [ -d "$1" ]; then # install to given mounted root install_mounted_root "${1%/}" exit $? fi disks=$(find_disks) # no disks so lets exit quietly. [ -z "$disks" ] && exit 0 if [ $# -gt 0 ]; then # check that they are for i in "$@"; do j=$(readlink -f "$i" | sed 's:^/dev/::; s:/:!:g') if ! [ -e "/sys/block/$j/device" ]; then echo "$i is not a suitable for partitioning" exit 1 fi done else set -- $disks rootdisk= while ! in_list "$rootdisk" $disks "none" "abort"; do echo "Available disks are: $disks" echon "Which one is the root disk? (or none) [$1] " default_read rootdisk $1 done case "$rootdisk" in none|abort) exit 0;; esac fi #echon "Do you want use *all* of $rootdisk for Alpine? (y/n) [n] " #default_read useall "n" #case "$useall" in # [Yy]*) useall="yes";; #esac # #if [ "x$useall" != "xyes" ]; then # echo "Only 'use all' option is available at the moment. Sorry" # exit 1 #fi rootdisk_dev=${rootdisk_dev:-"/dev/$rootdisk"} if ! [ -b "$rootdisk_dev" ]; then echo "$rootdisk_dev is not a block device" >&2 exit 1 fi useall $rootdisk_dev