#!/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 } # Find the disk device from given partition disk_from_part() { local i= part=${1#/dev/} for i in /sys/block/*/$part; do i=${i%/*} echo "/dev/${i##*/}" return 0 done 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) echon "Installing system on $rootdev: " lbu package - | tar -C "$mnt" -zx # 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/ apk add -q --progress --update-cache --root "$mnt" \ $(cat "$mnt"/var/lib/apk/world) \ acct linux-grsec alpine-base >/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 # create an extlinux.conf cat >"$mnt"/boot/extlinux.conf <> "$mnt"/etc/fstab # install extlinux apk add -q syslinux 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 has_holders /sys/block/$b && return 1 # 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 "" 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 case "$p" in *1) rd=/dev/md0; boot_dev=/dev/md0;; *2) rd=/dev/md1; swap_dev=/dev/md1;; *3) rd=/dev/md2; root_dev=/dev/md2;; esac mdadm --create $rd --level=1 --raid-devices=2 \ --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 # 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 install_mounted_root /mnt } # Parse args while getopts "r" opt; do case $opt in r) USE_RAID=1;; 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