setup-disk.in 22.3 KB
Newer Older
Natanael Copa's avatar
Natanael Copa committed
1 2 3 4 5
#!/bin/sh

PREFIX=
. "$PREFIX/lib/libalpine.sh"

6
MBR=${MBR:-"/usr/share/syslinux/mbr.bin"}
7 8
ROOTFS=${ROOTFS:-ext4}
BOOTFS=${BOOTFS:-ext4}
9
VARFS=${VARFS:-ext4}
Natanael Copa's avatar
Natanael Copa committed
10

11 12 13
# default location for mounted root
SYSROOT=${SYSROOT:-/mnt}

Natanael Copa's avatar
Natanael Copa committed
14 15 16 17 18 19 20 21 22 23
in_list() {
	local i="$1"
	shift
	while [ $# -gt 0 ]; do
		[ "$i" = "$1" ] && return 0
		shift
	done
	return 1
}

24 25 26 27 28 29 30 31 32 33 34
all_in_list() {
	local needle="$1"
	local i
	[ -z "$needle" ] && return 1
	shift
	for i in $needle; do
		in_list "$i" $@ || return 1
	done
	return 0
}

35 36 37 38 39 40 41 42
# 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=
43 44 45
	case "$1" in
		/dev/md*) echo "$1" && return 0;;
	esac
46 47 48 49 50 51 52 53 54 55 56 57 58
	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
59
enumerate_fstab() {
60
	local mnt="$1"
61
	local fs_spec= fs_file= fs_vfstype= fs_mntops= fs_freq= fs_passno=
62
	[ -z "$mnt" ] && return
63 64
	local escaped_mnt=$(echo $mnt | sed -e 's:/*$::' -e 's:/:\\/:g')
	awk "\$2 ~ /^$escaped_mnt(\/|\$)/ {print \$0}" /proc/mounts | \
65 66 67 68
		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
69 70
}

71 72 73 74 75
is_vmware() {
	grep -q VMware /proc/scsi/scsi 2>/dev/null \
		|| grep -q VMware /proc/ide/hd*/model 2>/dev/null
}

76 77 78 79
is_xen() {
	[ -d /proc/xen ]
}

80 81 82 83 84
# return true (0) if given device is lvm
is_lvm() {
	lvs "$1" >/dev/null 2>&1
}

85 86
# Find the disk device from given partition
disk_from_part() {
87 88
	# we need convert cciss/c0d0* cciss!c0d0*...
	local i= part=$(echo ${1#/dev/} | sed 's:/:!:g')
89 90
	for i in /sys/block/*/$part; do
		i=${i%/*}
91
		# ...and back from cciss!c0d0 to cciss/c0d0
92 93 94 95
		if [ -b "/dev/${i##*/}" ]; then
			echo "/dev/${i##*/}" | sed 's:!:/:g'
			return 0
		fi
96 97 98 99
	done
	return 1
}

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
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
}

135 136 137 138 139 140 141 142
# find filesystem of given mounted dir
find_mount_fs() {
	local mount_point="$1"
	awk "\$2 == \"$mount_point\" {print \$3}" /proc/mounts | tail -n 1
}

# find device for given mounted dir
find_mount_dev() {
143
	local mnt="$1"
144 145 146 147
	awk "\$2 == \"$mnt\" { print \$1 }" /proc/mounts | tail -n 1
}

supported_boot_fs() {
148
	local supported="ext2 ext3 ext4 btrfs"
149 150 151 152 153 154 155 156
	local fs=
	for fs in $supported; do
		[ "$fs" = "$1" ] && return 0
	done
	echo "$1 is not supported. Only supported are: $supported" >&2
	return 1
}

157 158 159 160 161 162 163 164 165 166
find_volume_group() {
	local lv=${1##*/}
	lvs --noheadings "$1" | awk "\$1 == \"$lv\" {print \$2}"
}

find_pvs_in_vg() {
	local vg="$1"
	pvs --noheadings | awk "\$2 == \"$vg\" {print \$1}"
}

167
install_mounted_root() {
Natanael Copa's avatar
Natanael Copa committed
168
	local mnt="$1" mnt_boot= boot_fs= root_fs=
169
	local initfs_features="ata base ide scsi usb virtio"
170
	local pvs= dev= rootdev= bootdev= extlinux_raidopt= root= modules=
171
	local kernel_opts="quiet"
172

173
	rootdev=$(find_mount_dev "$mnt")
174 175 176 177
	if [ -z "$rootdev" ]; then
		echo "$mnt does not seem to be a mount point" >&2
		return 1
	fi
178
	root_fs=$(find_mount_fs "$mnt")
179 180 181 182
	initfs_features="$initfs_features $root_fs"

	if is_lvm "$rootdev"; then
		initfs_features="$initfs_features lvm"
183 184
		local vg=$(find_volume_group "$rootdev")
		pvs=$(find_pvs_in_vg $vg)
185 186
	fi

187

188 189 190
	bootdev=$(find_mount_dev "$mnt"/boot)
	if [ -z "$bootdev" ]; then
		bootdev=$rootdev
Natanael Copa's avatar
Natanael Copa committed
191
		mnt_boot="$mnt"
192 193 194 195 196 197
	else
		mnt_boot="$mnt"/boot
	fi
	boot_fs=$(find_mount_fs "$mnt_boot")
	supported_boot_fs "$boot_fs" || return 1

198 199
	# Check if we boot from raid so we can pass proper option to
	# extlinux later.
200
	if [ -e "/sys/block/${bootdev#/dev/}/md" ]; then
201
		extlinux_raidopt="--raid"
202
	fi
203

204 205
	# check if our root is on raid so we can feed mkinitfs and
	# update-exlinux.conf with the proper kernel module params
206 207 208 209
	for dev in $rootdev $pvs; do
		[ -e "/sys/block/${dev#/dev/}/md" ] || continue

		local md=${dev#/dev/}
210
		initfs_features="${initfs_features% raid} raid"
211 212
		local level=$(cat /sys/block/$md/md/level)
		case "$level" in
213 214
			raid1) raidmod="${raidmod%,raid1},raid1";;
			raid[456]) raidmod="${raidmod%,raid456},raid456";;
215 216
		esac
	done
217 218 219 220

	# check if we need hardware raid drivers
	case $rootdev in
		/dev/cciss/*)
221
			initfs_features="${initfs_features% raid} raid"
222 223 224
			;;
	esac

225 226 227 228 229 230
	if [ -n "$VERBOSE" ]; then
		echo "Root device:     $rootdev"
		echo "Root filesystem: $root_fs"
		echo "Boot device:     $bootdev"
		echo "Boot filesystem: $boot_fs"
	fi
231

232
	if [ -z "$APKOVL" ]; then
233 234
		ovlfiles=/tmp/ovlfiles
		lbu package - | tar -C "$mnt" -zxv > "$ovlfiles"
235 236
	else
		echo "Restoring backup from $APKOVL to $rootdev..."
237
		unpack_apkovl "$APKOVL" "$mnt" || return 1
238
	fi
239

240
	# generate mkinitfs.conf
241
	mkdir -p "$mnt"/etc/mkinitfs/files.d
242
	echo "features=\"$initfs_features\"" > "$mnt"/etc/mkinitfs/mkinitfs.conf
243 244 245 246
	if [ -n "$raidmod" ]; then
		echo "/sbin/mdadm" > "$mnt"/etc/mkinitfs/files.d/raid
		echo "/etc/mdadm.conf" >> "$mnt"/etc/mkinitfs/files.d/raid
	fi
247

248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
	# generate update-extlinux.conf
	root=$(uuid_or_device $rootdev)
	if is_vmware; then
		kernel_opts="pax_nouderef $kernel_opts"
	fi
	if is_xen; then
		kernel_opts="xen $kernel_opts"
	fi
	modules="sd-mod,usb-storage,${root_fs}${raidmod}"
	sed -e "s:^root=.*:root=$root:" \
		-e "s:^default_kernel_opts=.*:default_kernel_opts=\"$kernel_opts\":" \
		-e "s:^modules=.*:modules=$modules:" \
		/etc/update-extlinux.conf > "$mnt"/etc/update-extlinux.conf


263 264 265 266 267 268 269 270 271 272 273
	# generate the fstab
	if [ -f "$mnt"/etc/fstab ]; then
		mv "$mnt"/etc/fstab "$mnt"/etc/fstab.old
	fi
	enumerate_fstab "$mnt" >> "$mnt"/etc/fstab
	cat >>"$mnt"/etc/fstab <<EOF
/dev/cdrom	/media/cdrom	iso9660	noauto,ro 0 0
/dev/fd0	/media/floppy	vfat	noauto	0 0
/dev/usbdisk	/media/usb	vfat	noauto	0 0
EOF

274
	# remove the installed db in case its there so we force re-install
275
	rm -f "$mnt"/var/lib/apk/installed "$mnt"/lib/apk/db/installed
276
	echo "Installing system on $rootdev:"
277 278 279 280
	# 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/

281

282
	local apkflags="--initdb --quiet --progress --update-cache --clean-protected"
283
	local pkgs=$(cat "$mnt"/etc/apk/world "$mnt"/var/lib/apk/world 2>/dev/null)
284
	pkgs="$pkgs acct linux-$KERNEL_FLAVOR alpine-base"
285 286 287 288 289
	local repos=$(sed -e 's/\#.*//' /etc/apk/repositories)
	local repoflags=
	for i in $repos; do
		repoflags="$repoflags --repository $i"
	done
290 291
	
	apk add --root "$mnt" $apkflags --overlay-from-stdin \
292
		$repoflags $pkgs <$ovlfiles>/dev/null || return 1
293
	echo ""
294 295 296
	if ! is_xen; then
		extlinux $extlinux_raidopt --install "$mnt"/boot
	fi
297 298 299 300
}

unmount_partitions() {
	local mnt="$1"
301 302

	# unmount the partitions
Natanael Copa's avatar
Natanael Copa committed
303
	umount $(awk '{print $2}' /proc/mounts | egrep "^$mnt(/|\$)" | sort -r)
304
}
305

306 307 308
# figure out decent default swap size in mega bytes
find_swap_size() {
	local memtotal_kb=$(awk '$1 == "MemTotal:" {print $2}' /proc/meminfo)
309 310 311 312
	# use 2 * avaiable ram or no more than 1/3 of smallest disk space
	local size=$(( $memtotal_kb * 2 / 1024 ))
	local disk= disksize=
	for disk in $@; do
313 314
		local sysfsdev=$(echo ${disk#/dev/} | sed 's:/:!:g')
		local sysfspath=/sys/block/$sysfsdev/size
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
		# disksize = x * 512 / (1024 * 1024) = x / 2048
		# maxsize = $disksize / 4 = x / (2048 * 4) = x / 8192
		maxsize=$(awk '{ printf "%i", $0 / 8192 }' $sysfspath )
		if [ $size -gt $maxsize ]; then
			size=$maxsize
		fi
	done
	if [ $size -gt 4096 ]; then
		# dont ever use more than 4G
		size=4096
	elif [ $size -lt 64 ]; then
		# dont bother create swap smaller than 64MB
		size=0
	fi
	echo $size
330 331 332 333
}

has_mounted_part() {
	local p
334
	local sysfsdev=$(echo ${1#/dev/} | sed 's:/:!:g')
Natanael Copa's avatar
Natanael Copa committed
335
	# parse /proc/mounts for mounted devices
336
	for p in $(awk '$1 ~ /^\/dev\// {gsub("/dev/", "", $1); gsub("/", "!", $1); print $1}' \
337
			/proc/mounts); do
338 339
		[ "$p" = "$sysfsdev" ] && return 0
		[ -e /sys/block/$sysfsdev/$p ] && return 0
340 341 342 343
	done
	return 1
}

Natanael Copa's avatar
Natanael Copa committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
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
364 365 366 367
	if has_holders /sys/block/$b; then
		[ -n "$USE_RAID" ] && echo "Warning: $dev is part of a running raid" >&2
		return 1
	fi
Natanael Copa's avatar
Natanael Copa committed
368 369 370 371 372 373 374

	# check so its not an md device
	[ -e /sys/block/$b/md ] && return 1

	return 0
}

375
find_disks() {
Natanael Copa's avatar
Natanael Copa committed
376
	local p=
377
	for p in $(awk '$1 ~ /[0-9]+/ {print $4}' /proc/partitions); do
Natanael Copa's avatar
Natanael Copa committed
378
		is_available_disk $p && echo -n " $p"
379 380 381
	done
}

382 383 384 385 386 387 388 389 390 391 392
stop_all_raid() {
	local rd
	for rd in /dev/md*; do
		[ -b $rd ] && mdadm --stop $rd
	done
}

# install needed programs
init_progs() {
	local raidpkg=
	[ -n "$USE_RAID" ] && raidpkg="mdadm"
393
	apk add -q sfdisk e2fsprogs lvm2 $raidpkg syslinux $@
394 395
}

396
show_disk_info() {
Natanael Copa's avatar
Natanael Copa committed
397
	local disk= vendor= model= d= size=
398
	for disk in $@; do
399 400
		local dev=${disk#/dev/}
		d=$(echo $dev | sed 's:/:!:g')
401 402 403
		vendor=$(cat /sys/block/$d/device/vendor 2>/dev/null)
		model=$(cat /sys/block/$d/device/model 2>/dev/null)
		size=$(awk '{gb = ($1 * 512)/1000000000; printf "%.1f GB\n", gb}' /sys/block/$d/size 2>/dev/null)
404
		echo "  $dev	($size $vendor $model)"
405 406
	done
}
407

408 409
confirm_erase() {
	local answer=
410
	echo "WARNING: The following disk(s) will be erased:"
411
	show_disk_info $@
412
	echo -n "WARNING: Erase the above disk(s) and continue? [y/N]: "
413
	
414 415
	read answer
	case "$answer" in
416
		y*|Y*) return 0;;
417
	esac
418
	return 1
419 420
}

421
# setup partitions on given disk dev in $1.
422 423 424 425 426 427
# usage: setup_partitions <diskdev> size1,type1 [size2,type2 ...] 
setup_partitions() {
	local diskdev="$1"
	shift

	echo "Initializing partitions on $diskdev..."
428 429 430 431 432 433 434

	# 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 $diskdev >/dev/null

435 436 437
	# fix the MBR while here so extlinux can boot
	cat "$MBR" > $diskdev

438 439
	local start=0
	local line=
440 441
	# create new partitions
	(
442 443 444 445
		for line in "$@"; do
			echo "$start,$line"
			start=
		done
446
	) | sfdisk -q -L -uM $diskdev >/dev/null || return 1
447 448 449 450 451 452 453 454 455 456 457

	# create device nodes if not exist
	mdev -s
}

# find the bootable partition on given disk
find_boot_partition() {
	sfdisk -d $1 | awk '/bootable/ {print $1}'
}

# find the partition(s) for LVM
458
# this is not marked as bootable and is type 8e
459 460 461 462 463
find_lvm_partition() {
	local type=8e
	sfdisk -d $1 | grep -v bootable | awk "/Id=$type/ {print \$1}"
}

464
# set up optional raid and create filesystem on boot device.
465
setup_boot_dev() {
466 467 468 469
	local disk= bootdev=
	local part=$(for disk in $@; do find_boot_partition $disk; done)
	set -- $part
	bootdev=$1
470
	[ -z "$bootdev" ] && return 1
471
	echo "Creating file systems..."
472
	if [ -n "$USE_RAID" ]; then
473 474 475 476 477 478
		local missing=
		local num=$#
		if [ $# -eq 1 ]; then
			missing="missing"
			num=2
		fi
479
		# we only use raid level 1 for boot devices
480 481
		mdadm --create /dev/md0 --level=1 --raid-devices=$num \
			--metadata=0.90 --quiet --run $@ $missing || return 1
482 483
		bootdev=/dev/md0
	fi
484
	mkfs.$BOOTFS -q $bootdev
485 486 487 488
	BOOT_DEV="$bootdev"
}

# $1 = index
489 490 491
# $2 = partition type
# $3... = disk devices
find_nth_non_boot_parts() {
492
	local idx=$1
493
	local id=$2
494 495
	local disk=
	shift
496
	shift
497 498
	for disk in $@; do
		sfdisk -d $disk | grep -v bootable \
499
			| awk "/Id=$id/ { i++; if (i==$idx) print \$1 }"
500 501 502 503 504 505 506 507 508
	done
}

setup_non_boot_raid_dev() {
	local md_dev=$1
	local idx=${md_dev#/dev/md}
	shift
	local level=1
	local missing=
509
	local raid_parts=$(find_nth_non_boot_parts $idx "fd" $@)
510 511 512 513 514 515 516 517 518 519
	set -- $raid_parts
	# how many disks do we have?
	case $# in
		0) echo "No Raid partitions found" >&2; return 1;;
		1) level=1; missing="missing"; num=2;;
		2) level=1; missing=  ; num=2;;
		*) level=5; missing=  ; num=$#;;
	esac
	mdadm --create /dev/md$idx --level=$level --raid-devices=$num \
		--quiet --run $@ $missing || return 1
520 521 522 523
}

# setup device for lvm, create raid array if needed
setup_lvm_volume_group() {
524 525 526
	local vgname="$1"
	shift
	local lvmdev=
527 528

	if [ -n "$USE_RAID" ]; then
529 530 531 532
		setup_non_boot_raid_dev /dev/md1 $@ || return 1
		lvmdev=/dev/md1
	else	
		lvmdev=$(find_lvm_partition $1)
533 534 535 536 537
	fi

	# be quiet on success
	local errmsg=$(dd if=/dev/zero of=$lvmdev bs=1k count=1 2>&1) \
		|| echo "$errmsg"
538 539 540 541 542 543 544 545 546 547 548 549 550 551
	pvcreate --quiet $lvmdev \
		&& vgcreate --quiet $vgname $lvmdev >/dev/null
}

# set up swap on given device(s)
setup_swap_dev() {
	local swap_dev=
	sed -i -e '/swap/d' /etc/fstab
	for swap_dev in "$@"; do
		mkswap $swap_dev >/dev/null
		echo -e "$swap_dev\tswap\t\tswap\tdefaults 0 0" >> /etc/fstab
	done
	swapon -a
	rc-update --quiet add swap boot
552 553 554
}

# setup and enable swap on given volumegroup if needed
555
setup_lvm_swap() {
556
	local vgname="$1"
557
	local swapname=lv_swap
558 559 560
	if [ -z "$SWAP_SIZE" ] || [ "$SWAP_SIZE" -eq 0 ]; then
		return
	fi
561 562
	lvcreate --quiet -n $swapname -L ${SWAP_SIZE}MB $vgname
	setup_swap_dev /dev/$vgname/$swapname
563 564 565 566 567 568 569 570 571 572
}

# if /var is mounted, move out data and umount it
reset_var() {
	[ -z "$(find_mount_dev /var)" ] && return 0
	mkdir /.var
	mv /var/* /.var/ 2>/dev/null
	umount /var && 	rm -rf /var && mv /.var /var && rm -rf /var/lost+found
}

573 574 575
# set up /var on given device
setup_var() {
	local var_dev="$1"
576
	local varfs=${VARFS}
577
	echo "Creating file systems..."
578 579 580 581 582 583 584 585 586 587 588
	mkfs.$varfs -q $var_dev >/dev/null || return 1
	sed -i -e '/[[:space:]]\/var[[:space:]]/d' /etc/fstab
	echo -e "${var_dev}\t/var\t\t${varfs}\tdefaults 1 2" >> /etc/fstab

	mv /var /.var
	mkdir /var
	mount /var
	mv /.var/* /var/
	rmdir /.var

	/etc/init.d/syslog --quiet restart
589
	setup_mdadm_conf
590 591
}

592
setup_mdadm_conf() {
593
	local mods= mod=
594 595 596
	if [ -n "$USE_RAID" ]; then
		mdadm --detail --scan > /etc/mdadm.conf
		rc-update --quiet add mdadm-raid boot
597 598 599 600 601 602
		mods=$(awk '/^raid/ {print $1}' /proc/modules)
		for mod in $mods; do
			if ! grep -q "^$mod" /etc/modules; then
				echo $mod >> /etc/modules
			fi
		done
603 604 605
	fi
}

606
data_only_disk_install_lvm() {
607
	local diskdev=
608 609
	local vgname=vg0
	local var_dev=/dev/$vgname/lv_var
610 611 612
	local lvm_part_type="8e"
	local part_type=$lvm_part_type
	local size=
613 614

	init_progs || return 1
615
	confirm_erase $@ || return 1
616

617
	if [ "$USE_RAID" ]; then
618 619
		# the paritition type for raid is "fd"
		part_type="fd"
620 621
		stop_all_raid
	fi
622

623 624 625 626 627 628
	for diskdev in "$@"; do
		setup_partitions $diskdev "$size,$part_type" || return 1
	done
	
	setup_lvm_volume_group $vgname $@ || return 1
	setup_lvm_swap $vgname
629
	lvcreate --quiet -n ${var_dev##*/} -l 100%FREE $vgname
630
	setup_mdadm_conf
Natanael Copa's avatar
Natanael Copa committed
631
	rc-update add lvm boot
632
	setup_var $var_dev
633 634
}

635 636
data_only_disk_install() {
	local diskdev=
637 638
	local var_dev=
	local var_part_type="83"
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
	local swap_part_type=82
	local size=
	local swap_dev= var_dev=

	init_progs || return 1
	confirm_erase $@ || return 1

	if [ "$USE_RAID" ]; then
		var_part_type="fd"
		swap_part_type="fd"
		stop_all_raid
	fi

	for diskdev in "$@"; do
		setup_partitions $diskdev \
			"$SWAP_SIZE,$swap_part_type" \
			"$size,$var_part_type" || return 1
	done

	if [ "$USE_RAID" ]; then
		[ $SWAP_SIZE -gt 0 ] && setup_non_boot_raid_dev /dev/md1 $@
		setup_non_boot_raid_dev /dev/md2 $@ || return 1
		swap_dev=/dev/md1
		var_dev=/dev/md2
	else
		swap_dev=$(find_nth_non_boot_parts 1 82 $@)
		var_dev=$(find_nth_non_boot_parts 1 83 $@)
	fi
	[ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev
	setup_var $var_dev
}

671 672 673 674
# setup 
setup_root() {
	local root_dev="$1" boot_dev="$2"
	mkfs.$ROOTFS -q "$root_dev"
675 676
	mkdir -p "$SYSROOT"
	mount -t $ROOTFS $root_dev "$SYSROOT" || return 1
677
	if [ -n "$boot_dev" ]; then
678 679
		mkdir -p "$SYSROOT"/boot
		mount -t $BOOTFS $boot_dev "$SYSROOT"/boot || return 1
680 681 682
	fi

	setup_mdadm_conf
683 684
	install_mounted_root "$SYSROOT" || return 1
	unmount_partitions "$SYSROOT"
685 686 687
	swapoff -a

	echo ""
688
	echo "Installation is complete. Please reboot."
689 690
}

691
native_disk_install_lvm() {
692 693 694 695 696 697 698
	local diskdev= vgname=vg0
	local lvm_part_type="8e"
	local boot_part_type="83"
	local boot_size=${BOOT_SIZE:-100}
	local lvm_size=
	local root_dev=/dev/$vgname/lv_root

699
	init_progs || return 1
700
	confirm_erase $@ || return 1
701 702

	if [ -n "$USE_RAID" ]; then
703 704 705
		boot_part_type="fd"
		lvm_part_type="fd"
		stop_all_raid
706
	fi
707 708 709 710 711 712 713 714 715 716 717 718
	for diskdev in "$@"; do
		setup_partitions $diskdev \
			"$boot_size,$boot_part_type,*" \
			"$lvm_size,$lvm_part_type" || return 1
	done

	# will find BOOT_DEV for us
	setup_boot_dev $@

	setup_lvm_volume_group $vgname $@ || return 1
	setup_lvm_swap $vgname
	lvcreate --quiet -n ${root_dev##*/} -l 100%FREE $vgname
Natanael Copa's avatar
Natanael Copa committed
719
	rc-update add lvm boot
720
	setup_root $root_dev $BOOT_DEV
Natanael Copa's avatar
Natanael Copa committed
721 722
}

723 724 725 726 727 728 729
native_disk_install() {
	local root_part_type="83" swap_part_type="82" boot_part_type="83"
	local boot_size=${BOOT_SIZE:-100}
	local swap_size=${SWAP_SIZE}
	local root_size=
	local root_dev= boot_dev= swap_dev=

730
	init_progs || return 1
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
	confirm_erase $@ || return 1

	if [ -n "$USE_RAID" ]; then
		boot_part_type="fd"
		root_part_type="fd"
		swap_part_type="fd"
		stop_all_raid
	fi
	for diskdev in "$@"; do
		setup_partitions $diskdev \
			"$boot_size,$boot_part_type,*" \
			"$swap_size,$swap_part_type" \
			"$root_size,$root_part_type" \
			|| return 1
	done

	# will find BOOT_DEV for us
	setup_boot_dev $@
	
	if [ "$USE_RAID" ]; then
		[ $SWAP_SIZE -gt 0 ] && setup_non_boot_raid_dev /dev/md1 $@
		setup_non_boot_raid_dev /dev/md2 $@ || return 1
		swap_dev=/dev/md1
		root_dev=/dev/md2
	else
		swap_dev=$(find_nth_non_boot_parts 1 82 $@)
		root_dev=$(find_nth_non_boot_parts 1 83 $@)
	fi
	[ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev
	setup_root $root_dev $BOOT_DEV
}

763
diskselect_help() {
764 765
	cat <<__EOF__

Natanael Copa's avatar
Natanael Copa committed
766
The disk you select can be used for a traditional disk install or for a
767 768 769 770
data-only install.

The disk will be erased.

Natanael Copa's avatar
Natanael Copa committed
771
Enter 'none' if you want to run diskless.
772 773 774 775

__EOF__
}

776
diskmode_help() {
777 778
	cat <<__EOF__

779
You can select between 'sys' or 'data'.
780

Natanael Copa's avatar
Natanael Copa committed
781 782 783 784 785
sys:
  This mode is a traditional disk install. The following partitions will be
  created on the disk: /boot, / (filesystem root) and swap.
    
  This mode may be used for development boxes, desktops, virtual servers, etc.
786

Natanael Copa's avatar
Natanael Copa committed
787 788 789
data:
  This mode uses your disk(s) for data storage, not for the operating system.
  The system itself will run from tmpfs (RAM).
790

Natanael Copa's avatar
Natanael Copa committed
791 792
  Use this mode if you only want to use the disk(s) for a mailspool, databases,
  logs, etc.
793 794 795 796 797 798 799 800 801

__EOF__
}

# ask for a root or data disk
# returns answer in global variable $answer
ask_disk() {
	local prompt="$1"
	local help_func="$2"
802
	local i=
803 804
	shift 2
	answer=
805
	local default_disk=${DEFAULT_DISK:-$1}
806

807 808 809
	while ! all_in_list "$answer" $@ "none" "abort"; do
		echo "Available disks are:"
		show_disk_info "$@"
810 811
		echon "$prompt [$default_disk] "
		default_read answer $default_disk
812 813 814 815
		case "$answer" in
			'abort') exit 0;;
			'none') return 0;;
			'?') $help_func;;
816 817 818 819 820 821
			*) for i in $answer; do
				if ! [ -b "/dev/$i" ]; then
					echo "/dev/$i is not a block device" >&2
					answer=
				   fi
			done;;
822 823 824 825
		esac
	done
}

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
usage() {
	cat <<__EOF__
usage: setup-disk [-hqr] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE]
		  [MOUNTPOINT | DISKDEV...]

Install alpine on harddisk.

If MOUNTPOINT is specified, then do a traditional disk install with MOUNTPOINT
as root.

If DISKDEV is specified, then use the specified disk(s) without asking. If
multiple disks are specified then set them up in a RAID array. If there are
mode than 2 disks, then use raid level 5 instead of raid level 1.

options:
 -h  Show this help
 -m  Use disk for MODE without asking, where MODE is either 'data' or 'root'
 -o  Restore system from given apkovl file
 -k  Use kernelflavor instead of $KERNEL_FLAVOR
845
 -L  Use LVM to manage partitions
846 847 848 849 850 851 852 853
 -q  Exit quietly if no disks are found
 -r  Enable software raid1 with single disk
 -s  Use SWAPSIZE MB instead of $SWAP_SIZE MB for swap (Use 0 to disable swap)
 -v  Be more verbose about what is happening
__EOF__
	exit 1
}

854 855 856
KERNEL_FLAVOR=grsec
case "$(uname -r)" in
	*-vs[0-9]*) KERNEL_FLAVOR=vserver;;
857
	*-pae) KERNEL_FLAVOR=pae;;
858 859
esac

860
DISK_MODE=
861
USE_LVM=
862
# Parse args
863
while getopts "hk:Lm:o:qrs:v" opt; do
864
	case $opt in
865
		m) DISK_MODE="$OPTARG";;
866
		k) KERNEL_FLAVOR="$OPTARG";;
867
		L) USE_LVM="_lvm";;
868
		o) APKOVL="$OPTARG";;
869 870
		q) QUIET=1;;
		r) USE_RAID=1;;
871
		s) SWAP_SIZE="$OPTARG";;
872
		v) VERBOSE=1;;
Natanael Copa's avatar
Natanael Copa committed
873
		*) usage;;
874 875
	esac
done
876
shift $(( $OPTIND - 1))
877

878 879
if [ -d "$1" ]; then
	# install to given mounted root
880
	apk add -q syslinux
881 882
	install_mounted_root "${1%/}" \
		&& echo "You might need fix the MBR to be able to boot" >&2
883 884 885
	exit $?
fi

886 887 888 889 890 891 892 893 894 895
reset_var
swapoff -a

# stop all volume groups in use
vgchange --ignorelockingfailure -a n >/dev/null 2>&1

if [ -n "$USE_RAID" ]; then
	stop_all_raid
fi

896
disks=$(find_disks)
897
diskdevs=
Natanael Copa's avatar
Natanael Copa committed
898 899

# no disks so lets exit quietly.
900 901 902 903
if [ -z "$disks" ]; then
	[ -z "$QUIET" ] && echo "No disks found." >&2
	exit 0
fi
Natanael Copa's avatar
Natanael Copa committed
904

905 906 907 908 909
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
Natanael Copa's avatar
Natanael Copa committed
910
			echo "$i is not a suitable for partitioning"
911 912
			exit 1
		fi
913
		diskdevs="$diskdevs /dev/$j"
914 915
	done
else
916
	ask_disk "Which disk(s) would you like to use? (or '?' for help or 'none')" \
917
		diskselect_help $disks
918
	if [ "$answer" != none ]; then
919 920 921
		for i in $answer; do
			diskdevs="$diskdevs /dev/$i"
		done
922 923
	else
		DISK_MODE="none"
924
	fi
925
fi
Natanael Copa's avatar
Natanael Copa committed
926

927
if [ -n "$diskdevs" ] && [ -z "$DISK_MODE" ]; then
928
	answer=
929
	disk_is_or_disks_are="disk is"
930
	it_them="it"
931
	set -- $diskdevs
932
	if [ $# -gt 1 ]; then
933
		disk_is_or_disks_are="disks are"
934 935 936
		it_them="them"
	fi
		
937
	while true; do
938
		echo "The following $disk_is_or_disks_are selected:"
939
		show_disk_info $diskdevs
940
		echon "How would you like to use $it_them? ('sys', 'data' or '?' for help) [?] "
941 942 943
		default_read answer '?'
		case "$answer" in
		'?') diskmode_help;;
944
		sys|data) break;;
945 946
		esac
	done
947
	DISK_MODE="$answer"
948
fi
Natanael Copa's avatar
Natanael Copa committed
949

950 951 952 953
if [ -z "$SWAP_SIZE" ]; then
	SWAP_SIZE=$(find_swap_size $diskdevs)
fi

954 955 956 957
set -- $diskdevs
if [ $# -gt 1 ]; then
	USE_RAID=1
fi
958

959 960
dmesg -n1

961
# native disk install
962
case "$DISK_MODE" in
963
sys) native_disk_install$USE_LVM $diskdevs;;
964
data) data_only_disk_install$USE_LVM $diskdevs;;
965
none) exit 0;;
966
*) echo "Not a valid install mode: $DISK_MODE" >&2; exit 1;;
967
esac
Natanael Copa's avatar
Natanael Copa committed
968

969
echo "$DISK_MODE" > /tmp/alpine-install-diskmode.out