setup-disk.in 25 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
		sed "s:$mnt:/:g; s: :\t:g" | sed -E 's:/+:/:g' | \
66 67 68
		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 80
# return true (0) if given device is lvm
is_lvm() {
	lvs "$1" >/dev/null 2>&1
}

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

96 97 98 99 100 101 102 103 104 105 106 107 108 109
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
110
		return 0
111 112
	fi

113
	apk add --quiet openssl
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

	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
}

131 132 133 134 135 136 137 138
# 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() {
139
	local mnt="$1"
140 141 142 143
	awk "\$2 == \"$mnt\" { print \$1 }" /proc/mounts | tail -n 1
}

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

153 154
find_volume_group() {
	local lv=${1##*/}
155
	lvs --noheadings "$1" | awk '{print $2}'
156 157 158 159 160 161 162
}

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

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
# echo current grsecurity option and set new
set_grsec() {
	local key="$1" value="$2"
	if ! [ -e /proc/sys/kernel/grsecurity/$key ]; then
		return 0
	fi
	cat /proc/sys/kernel/grsecurity/$key
	echo $value > /proc/sys/kernel/grsecurity/$key
}

init_chroot_mounts() {
	local mnt="$1" i=
	for i in proc dev; do
		mkdir -p "$mnt"/$i
		mount --bind /$i "$mnt"/$i
	done
}

cleanup_chroot_mounts() {
	local mnt="$1" i=
	for i in proc dev; do
		umount "$mnt"/$i
	done
}

188 189 190 191 192 193 194 195 196
has_bootopt() {
	local opt="$1"
	set -- $(cat /proc/cmdline)
	for i; do
		[ "$i" = "$opt" ] && return 0
	done
	return 1
}

197
install_mounted_root() {
Natanael Copa's avatar
Natanael Copa committed
198
	local mnt="$1" mnt_boot= boot_fs= root_fs=
199
	local initfs_features="ata base ide scsi usb virtio"
200
	local pvs= dev= rootdev= bootdev= extlinux_raidopt= root= modules=
201
	local kernel_opts="quiet"
202

203
	rootdev=$(find_mount_dev "$mnt")
204 205 206 207
	if [ -z "$rootdev" ]; then
		echo "$mnt does not seem to be a mount point" >&2
		return 1
	fi
208
	root_fs=$(find_mount_fs "$mnt")
209 210 211 212
	initfs_features="$initfs_features $root_fs"

	if is_lvm "$rootdev"; then
		initfs_features="$initfs_features lvm"
213 214
		local vg=$(find_volume_group "$rootdev")
		pvs=$(find_pvs_in_vg $vg)
215 216
	fi

217

218 219 220
	bootdev=$(find_mount_dev "$mnt"/boot)
	if [ -z "$bootdev" ]; then
		bootdev=$rootdev
Natanael Copa's avatar
Natanael Copa committed
221
		mnt_boot="$mnt"
222 223 224 225 226 227
	else
		mnt_boot="$mnt"/boot
	fi
	boot_fs=$(find_mount_fs "$mnt_boot")
	supported_boot_fs "$boot_fs" || return 1

228 229
	# Check if we boot from raid so we can pass proper option to
	# extlinux later.
230
	if [ -e "/sys/block/${bootdev#/dev/}/md" ]; then
231
		extlinux_raidopt="--raid"
232
	fi
233

234 235
	# check if our root is on raid so we can feed mkinitfs and
	# update-exlinux.conf with the proper kernel module params
236
	for dev in $rootdev $pvs; do
237 238 239 240 241 242 243 244

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

245 246 247
		[ -e "/sys/block/${dev#/dev/}/md" ] || continue

		local md=${dev#/dev/}
248
		initfs_features="${initfs_features% raid} raid"
249 250
		local level=$(cat /sys/block/$md/md/level)
		case "$level" in
251 252
			raid1) raidmod="${raidmod%,raid1},raid1";;
			raid[456]) raidmod="${raidmod%,raid456},raid456";;
253 254
		esac
	done
255 256


257 258 259 260 261 262
	if [ -n "$VERBOSE" ]; then
		echo "Root device:     $rootdev"
		echo "Root filesystem: $root_fs"
		echo "Boot device:     $bootdev"
		echo "Boot filesystem: $boot_fs"
	fi
263

264
	if [ -z "$APKOVL" ]; then
265 266
		ovlfiles=/tmp/ovlfiles
		lbu package - | tar -C "$mnt" -zxv > "$ovlfiles"
267 268 269 270
		# comment out local repositories
		if [ -f "$mnt"/etc/apk/repositories ]; then
			sed -i -e 's:^/:#/:' "$mnt"/etc/apk/repositories
		fi
271 272
	else
		echo "Restoring backup from $APKOVL to $rootdev..."
273
		unpack_apkovl "$APKOVL" "$mnt" || return 1
274
	fi
275

276 277 278
	# we should not try start modloop on sys install
	rm -f "$mnt"/etc/runlevels/*/modloop

279
	# generate mkinitfs.conf
280
	mkdir -p "$mnt"/etc/mkinitfs/features.d
281
	echo "features=\"$initfs_features\"" > "$mnt"/etc/mkinitfs/mkinitfs.conf
282
	if [ -n "$raidmod" ]; then
283 284
		echo "/sbin/mdadm" > "$mnt"/etc/mkinitfs/features.d/raid.files
		echo "/etc/mdadm.conf" >> "$mnt"/etc/mkinitfs/features.d/raid.files
285
	fi
286

287 288 289 290 291
	# generate update-extlinux.conf
	root=$(uuid_or_device $rootdev)
	if is_vmware; then
		kernel_opts="pax_nouderef $kernel_opts"
	fi
292 293 294
	if has_bootopt nomodeset; then
		kernel_opts="nomodeset $kernel_opts"
	fi
295 296 297 298 299
	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
300 301 302 303
	if [ "$(rc --sys)" = "XEN0" ]; then
		sed -i -e "s:^default=.*:default=xen-grsec:" \
			"$mnt"/etc/update-extlinux.conf
	fi
304

305 306 307 308 309
	# generate the fstab
	if [ -f "$mnt"/etc/fstab ]; then
		mv "$mnt"/etc/fstab "$mnt"/etc/fstab.old
	fi
	enumerate_fstab "$mnt" >> "$mnt"/etc/fstab
310 311 312 313
	if [ -n "$SWAP_DEVICE" ]; then
		echo -e "${SWAP_DEVICE}\tswap\tswap\tdefaults\t0 0" \
			>> "$mnt"/etc/fstab
	fi
314 315 316 317 318
	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
319
	# remove the installed db in case its there so we force re-install
320
	rm -f "$mnt"/var/lib/apk/installed "$mnt"/lib/apk/db/installed
321
	echo "Installing system on $rootdev:"
322 323
	extlinux $extlinux_raidopt --install "$mnt"/boot

324 325 326 327
	# 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/

328
	local apkflags="--initdb --quiet --progress --update-cache --clean-protected"
329
	local pkgs=$(cat "$mnt"/etc/apk/world "$mnt"/var/lib/apk/world 2>/dev/null)
330
	pkgs="$pkgs acct linux-$KERNEL_FLAVOR alpine-base"
331 332 333
	if [ "$(rc --sys)" = "XEN0" ]; then
		pkgs="$pkgs xen-hypervisor"
	fi
334 335 336 337 338
	local repos=$(sed -e 's/\#.*//' /etc/apk/repositories)
	local repoflags=
	for i in $repos; do
		repoflags="$repoflags --repository $i"
	done
339

340 341
	chroot_caps=$(set_grsec chroot_caps 0)
	init_chroot_mounts "$mnt"
342
	apk add --root "$mnt" $apkflags --overlay-from-stdin \
Natanael Copa's avatar
Natanael Copa committed
343
		$repoflags $pkgs <$ovlfiles
344 345 346 347
	local ret=$?
	cleanup_chroot_mounts "$mnt"
	set_grsec chroot_caps $chroot_caps > /dev/null
	return $ret
348 349 350 351
}

unmount_partitions() {
	local mnt="$1"
352 353

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

357 358 359
# figure out decent default swap size in mega bytes
find_swap_size() {
	local memtotal_kb=$(awk '$1 == "MemTotal:" {print $2}' /proc/meminfo)
360 361 362 363
	# 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
364 365
		local sysfsdev=$(echo ${disk#/dev/} | sed 's:/:!:g')
		local sysfspath=/sys/block/$sysfsdev/size
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
		# 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
381 382 383 384
}

has_mounted_part() {
	local p
385
	local sysfsdev=$(echo ${1#/dev/} | sed 's:/:!:g')
Natanael Copa's avatar
Natanael Copa committed
386
	# parse /proc/mounts for mounted devices
387
	for p in $(awk '$1 ~ /^\/dev\// {gsub("/dev/", "", $1); gsub("/", "!", $1); print $1}' \
388
			/proc/mounts); do
389 390
		[ "$p" = "$sysfsdev" ] && return 0
		[ -e /sys/block/$sysfsdev/$p ] && return 0
391 392 393 394
	done
	return 1
}

Natanael Copa's avatar
Natanael Copa committed
395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
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
410

Natanael Copa's avatar
Natanael Copa committed
411 412 413 414
	# check so it does not have mounted partitions
	has_mounted_part $dev && return 1

	# check so its not part of an md setup
415 416 417 418
	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
419 420 421 422 423 424 425

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

	return 0
}

426
find_disks() {
Natanael Copa's avatar
Natanael Copa committed
427
	local p=
428 429
	# filter out ramdisks (major=1)
	for p in $(awk '$1 != 1 && $1 ~ /[0-9]+/ {print $4}' /proc/partitions); do
Natanael Copa's avatar
Natanael Copa committed
430
		is_available_disk $p && echo -n " $p"
431 432 433
	done
}

434 435 436 437 438 439 440 441 442
stop_all_raid() {
	local rd
	for rd in /dev/md*; do
		[ -b $rd ] && mdadm --stop $rd
	done
}

# install needed programs
init_progs() {
443
	local raidpkg= lvmpkg= fs= fstools=
444
	[ -n "$USE_RAID" ] && raidpkg="mdadm"
445
	[ -n "$USE_LVM" ] && lvmpkg="lvm2"
446 447 448
	for fs in $BOOTFS $ROOTFS $VARFS; do
		# we need load btrfs module early to avoid the error message:
		# 'failed to open /dev/btrfs-control'
449 450 451 452 453 454
		modprobe $fs

		case $fs in
		xfs) fstools="$fstools xfsprogs";;
		ext*) fstools="$fstools e2fsprogs";;
		btrfs) fstools="$fstools btrfs-progs";;
455 456
		esac
	done
457
	apk add --quiet sfdisk $lvmpkg $raidpkg syslinux $fstools $@
458 459
}

460
show_disk_info() {
Natanael Copa's avatar
Natanael Copa committed
461
	local disk= vendor= model= d= size=
462
	for disk in $@; do
463 464
		local dev=${disk#/dev/}
		d=$(echo $dev | sed 's:/:!:g')
465 466 467
		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)
468
		echo "  $dev	($size $vendor $model)"
469 470
	done
}
471

472 473
confirm_erase() {
	local answer=
474 475
	local erasedisks="$@"
	if [ "$ERASE_DISKS" = "$erasedisks" ]; then
Natanael Copa's avatar
Natanael Copa committed
476
		return 0
477
	fi
478
	echo "WARNING: The following disk(s) will be erased:"
479
	show_disk_info $@
480
	echo -n "WARNING: Erase the above disk(s) and continue? [y/N]: "
481

482 483
	read answer
	case "$answer" in
484
		y*|Y*) return 0;;
485
	esac
486
	return 1
487 488
}

489
# setup partitions on given disk dev in $1.
490
# usage: setup_partitions <diskdev> size1,type1 [size2,type2 ...]
491 492 493 494 495
setup_partitions() {
	local diskdev="$1"
	shift

	echo "Initializing partitions on $diskdev..."
496 497 498 499 500 501 502

	# 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

503 504 505
	# fix the MBR while here so extlinux can boot
	cat "$MBR" > $diskdev

506
	local start=1M
507
	local line=
508 509
	# create new partitions
	(
510 511 512 513
		for line in "$@"; do
			echo "$start,$line"
			start=
		done
514
	) | sfdisk --quiet $diskdev >/dev/null || return 1
515 516 517 518 519 520 521 522 523 524 525

	# 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
526
# this is not marked as bootable and is type 8e
527 528
find_lvm_partition() {
	local type=8e
529
	sfdisk -d $1 | grep -v bootable | awk "/(Id|type)=$type/ {print \$1}"
530 531
}

532
# set up optional raid and create filesystem on boot device.
533
setup_boot_dev() {
534
	local disk= bootdev= mkfs_args="-q"
535 536 537
	local part=$(for disk in $@; do find_boot_partition $disk; done)
	set -- $part
	bootdev=$1
538
	[ -z "$bootdev" ] && return 1
539
	echo "Creating file systems..."
540
	if [ -n "$USE_RAID" ]; then
541 542 543 544 545 546
		local missing=
		local num=$#
		if [ $# -eq 1 ]; then
			missing="missing"
			num=2
		fi
547
		# we only use raid level 1 for boot devices
548 549
		mdadm --create /dev/md0 --level=1 --raid-devices=$num \
			--metadata=0.90 --quiet --run $@ $missing || return 1
550 551
		bootdev=/dev/md0
	fi
Natanael Copa's avatar
Natanael Copa committed
552
	[ "$BOOTFS" = "btrfs" ] && mkfs_args=""
553
	mkfs.$BOOTFS $mkfs_args $bootdev
554 555 556 557
	BOOT_DEV="$bootdev"
}

# $1 = index
558 559 560
# $2 = partition type
# $3... = disk devices
find_nth_non_boot_parts() {
561
	local idx=$1
562
	local id=$2
563 564
	local disk=
	shift
565
	shift
566 567
	for disk in $@; do
		sfdisk -d $disk | grep -v bootable \
568
			| awk "/(Id|type)=$id/ { i++; if (i==$idx) print \$1 }"
569 570 571 572 573 574 575 576 577
	done
}

setup_non_boot_raid_dev() {
	local md_dev=$1
	local idx=${md_dev#/dev/md}
	shift
	local level=1
	local missing=
578
	local raid_parts=$(find_nth_non_boot_parts $idx "fd" $@)
579 580 581 582 583 584 585 586 587 588
	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
589 590 591 592
}

# setup device for lvm, create raid array if needed
setup_lvm_volume_group() {
593 594 595
	local vgname="$1"
	shift
	local lvmdev=
596 597

	if [ -n "$USE_RAID" ]; then
598 599
		setup_non_boot_raid_dev /dev/md1 $@ || return 1
		lvmdev=/dev/md1
600
	else
601
		lvmdev=$(find_lvm_partition $1)
602 603 604 605 606
	fi

	# be quiet on success
	local errmsg=$(dd if=/dev/zero of=$lvmdev bs=1k count=1 2>&1) \
		|| echo "$errmsg"
607 608 609 610 611 612 613 614 615 616 617 618
	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
619
	SWAP_DEVICE="$(uuid_or_device $swap_dev)"
620 621
	swapon -a
	rc-update --quiet add swap boot
622 623 624
}

# setup and enable swap on given volumegroup if needed
625
setup_lvm_swap() {
626
	local vgname="$1"
627
	local swapname=lv_swap
628 629 630
	if [ -z "$SWAP_SIZE" ] || [ "$SWAP_SIZE" -eq 0 ]; then
		return
	fi
631 632
	lvcreate --quiet -n $swapname -L ${SWAP_SIZE}MB $vgname
	setup_swap_dev /dev/$vgname/$swapname
633 634 635 636 637 638 639 640 641 642
}

# 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
}

643 644 645
# set up /var on given device
setup_var() {
	local var_dev="$1"
646
	local varfs=${VARFS}
647
	echo "Creating file systems..."
648
	mkfs.$varfs $var_dev >/dev/null || return 1
649 650 651 652 653 654 655 656 657 658
	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
659
	setup_mdadm_conf
660 661
}

662
setup_mdadm_conf() {
663
	local mods= mod=
664 665 666
	if [ -n "$USE_RAID" ]; then
		mdadm --detail --scan > /etc/mdadm.conf
		rc-update --quiet add mdadm-raid boot
667 668 669 670 671 672
		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
673 674 675
	fi
}

676
data_only_disk_install_lvm() {
677
	local diskdev=
678 679
	local vgname=vg0
	local var_dev=/dev/$vgname/lv_var
680 681 682
	local lvm_part_type="8e"
	local part_type=$lvm_part_type
	local size=
683 684

	init_progs || return 1
685
	confirm_erase $@ || return 1
686

687
	if [ "$USE_RAID" ]; then
688 689
		# the paritition type for raid is "fd"
		part_type="fd"
690 691
		stop_all_raid
	fi
692

693
	for diskdev in "$@"; do
694
		setup_partitions $diskdev "${size}${size:+M},$part_type" || return 1
695
	done
696

697 698
	setup_lvm_volume_group $vgname $@ || return 1
	setup_lvm_swap $vgname
699
	lvcreate --quiet -n ${var_dev##*/} -l 100%FREE $vgname
700
	setup_mdadm_conf
Natanael Copa's avatar
Natanael Copa committed
701
	rc-update add lvm boot
702
	setup_var $var_dev
703 704
}

705 706
data_only_disk_install() {
	local diskdev=
707 708
	local var_dev=
	local var_part_type="83"
709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
	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 \
724 725
			"${SWAP_SIZE}M,$swap_part_type" \
			"${size}${size:+M},$var_part_type" || return 1
726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
	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
}

741
# setup
742
setup_root() {
743
	local root_dev="$1" boot_dev="$2" mkfs_args="-q"
Natanael Copa's avatar
Natanael Copa committed
744
	[ "$ROOTFS" = "btrfs" ] && mkfs_args=""
745
	mkfs.$ROOTFS $mkfs_args "$root_dev"
746 747
	mkdir -p "$SYSROOT"
	mount -t $ROOTFS $root_dev "$SYSROOT" || return 1
748
	if [ -n "$boot_dev" ]; then
749 750
		mkdir -p "$SYSROOT"/boot
		mount -t $BOOTFS $boot_dev "$SYSROOT"/boot || return 1
751 752 753
	fi

	setup_mdadm_conf
754 755
	install_mounted_root "$SYSROOT" || return 1
	unmount_partitions "$SYSROOT"
756 757 758
	swapoff -a

	echo ""
759
	echo "Installation is complete. Please reboot."
760 761
}

762
native_disk_install_lvm() {
763 764 765 766 767 768 769
	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

770
	init_progs || return 1
771
	confirm_erase $@ || return 1
772 773

	if [ -n "$USE_RAID" ]; then
774 775 776
		boot_part_type="fd"
		lvm_part_type="fd"
		stop_all_raid
777
	fi
778 779
	for diskdev in "$@"; do
		setup_partitions $diskdev \
780 781
			"${boot_size}M,$boot_part_type,*" \
			"${lvm_size}${lvm_size:+M},$lvm_part_type" || return 1
782 783 784 785 786 787 788 789
	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
790
	rc-update add lvm boot
791
	setup_root $root_dev $BOOT_DEV
Natanael Copa's avatar
Natanael Copa committed
792 793
}

794 795 796 797 798 799 800
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=

801
	init_progs || return 1
802 803 804 805 806 807 808 809 810 811
	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 \
812 813 814
			"${boot_size}M,$boot_part_type,*" \
			"${swap_size}M,$swap_part_type" \
			"${root_size}${root_size:+M},$root_part_type" \
815 816 817 818 819
			|| return 1
	done

	# will find BOOT_DEV for us
	setup_boot_dev $@
820

821 822 823 824 825 826 827 828 829 830 831 832 833
	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
}

834
diskselect_help() {
835 836
	cat <<__EOF__

Natanael Copa's avatar
Natanael Copa committed
837
The disk you select can be used for a traditional disk install or for a
838 839 840 841
data-only install.

The disk will be erased.

Natanael Copa's avatar
Natanael Copa committed
842
Enter 'none' if you want to run diskless.
843 844 845 846

__EOF__
}

847
diskmode_help() {
848 849
	cat <<__EOF__

850
You can select between 'sys', 'data', 'lvm', 'lvmsys' or 'lvmdata'.
851

Natanael Copa's avatar
Natanael Copa committed
852 853 854
sys:
  This mode is a traditional disk install. The following partitions will be
  created on the disk: /boot, / (filesystem root) and swap.
855

Natanael Copa's avatar
Natanael Copa committed
856
  This mode may be used for development boxes, desktops, virtual servers, etc.
857

Natanael Copa's avatar
Natanael Copa committed
858 859 860
data:
  This mode uses your disk(s) for data storage, not for the operating system.
  The system itself will run from tmpfs (RAM).
861

Natanael Copa's avatar
Natanael Copa committed
862 863
  Use this mode if you only want to use the disk(s) for a mailspool, databases,
  logs, etc.
864

865 866 867 868 869 870 871 872 873
lvm:
  Enable logical volume manager and ask again for 'sys' or 'data'.

lvmsys:
  Same as 'sys' but use logical volume manager for partitioning.

lvmdata:
  Same as 'data' but use logical volume manager for partitioning.

874 875 876 877 878 879 880 881
__EOF__
}

# ask for a root or data disk
# returns answer in global variable $answer
ask_disk() {
	local prompt="$1"
	local help_func="$2"
882
	local i=
883 884
	shift 2
	answer=
885
	local default_disk=${DEFAULT_DISK:-$1}
886

887 888 889
	while ! all_in_list "$answer" $@ "none" "abort"; do
		echo "Available disks are:"
		show_disk_info "$@"
890 891
		echon "$prompt [$default_disk] "
		default_read answer $default_disk
892 893 894 895
		case "$answer" in
			'abort') exit 0;;
			'none') return 0;;
			'?') $help_func;;
896 897 898 899 900 901
			*) for i in $answer; do
				if ! [ -b "/dev/$i" ]; then
					echo "/dev/$i is not a block device" >&2
					answer=
				   fi
			done;;
902 903 904 905
		esac
	done
}

906 907
usage() {
	cat <<__EOF__
908
usage: setup-disk [-hLqrv] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE]
909 910 911 912 913 914 915 916 917 918 919 920 921
		  [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
922
 -m  Use disk for MODE without asking, where MODE is either 'data' or 'sys'
923 924
 -o  Restore system from given apkovl file
 -k  Use kernelflavor instead of $KERNEL_FLAVOR
925
 -L  Use LVM to manage partitions
926 927
 -q  Exit quietly if no disks are found
 -r  Enable software raid1 with single disk
928
 -s  Use SWAPSIZE MB instead of autodetecting swap size (Use 0 to disable swap)
929
 -v  Be more verbose about what is happening
930

931 932 933 934 935 936
If BOOTFS, ROOTFS, VARFS are specified, then format a partition with specified
filesystem. If not specified, the default filesystem is ext4.
Supported filesystems for
  boot: ext2, ext3, ext4, btrfs
  root: ext2, ext3, ext4, btrfs, xfs
   var: ext2, ext3, ext4, btrfs, xfs
937 938 939 940
__EOF__
	exit 1
}

Francesco Colista's avatar
Francesco Colista committed
941 942 943 944 945
kver=$(uname -r)
case $kver in
        *-rc[0-9]*) KERNEL_FLAVOR=vanilla;;
        *-[a-z]*) KERNEL_FLAVOR=${kver##*-};;
        *) KERNEL_FLAVOR=vanilla;;
946 947
esac

948
DISK_MODE=
949
USE_LVM=
950
# Parse args
951
while getopts "hk:Lm:o:qrs:v" opt; do
952
	case $opt in
953
		m) DISK_MODE="$OPTARG";;
954
		k) KERNEL_FLAVOR="$OPTARG";;
955
		L) USE_LVM="_lvm";;
956
		o) APKOVL="$OPTARG";;
957 958
		q) QUIET=1;;
		r) USE_RAID=1;;
959
		s) SWAP_SIZE="$OPTARG";;
960
		v) VERBOSE=1;;
Natanael Copa's avatar
Natanael Copa committed
961
		*) usage;;
962 963
	esac
done
964
shift $(( $OPTIND - 1))
965

966 967
if [ -d "$1" ]; then
	# install to given mounted root
968
	apk add --quiet syslinux
969 970
	install_mounted_root "${1%/}" \
		&& echo "You might need fix the MBR to be able to boot" >&2
971 972 973
	exit $?
fi

974 975 976 977 978 979 980 981 982 983
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

984
disks=$(find_disks)
985
diskdevs=
Natanael Copa's avatar
Natanael Copa committed
986 987

# no disks so lets exit quietly.
988 989 990 991
if [ -z "$disks" ]; then
	[ -z "$QUIET" ] && echo "No disks found." >&2
	exit 0
fi
Natanael Copa's avatar
Natanael Copa committed
992

993
if [ $# -gt 0 ]; then
994
	# check that they are
995 996 997
	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
998
			echo "$i is not a suitable for partitioning"
999 1000
			exit 1
		fi
1001
		diskdevs="$diskdevs /dev/${j//!//}"
1002 1003
	done
else
1004
	ask_disk "Which disk(s) would you like to use? (or '?' for help or 'none')" \
1005
		diskselect_help $disks
1006
	if [ "$answer" != none ]; then
1007 1008 1009
		for i in $answer; do
			diskdevs="$diskdevs /dev/$i"
		done
1010 1011
	else
		DISK_MODE="none"
1012
	fi
1013
fi
Natanael Copa's avatar
Natanael Copa committed
1014

1015
if [ -n "$diskdevs" ] && [ -z "$DISK_MODE" ]; then
1016
	answer=
1017
	disk_is_or_disks_are="disk is"
1018
	it_them="it"
1019
	set -- $diskdevs
1020
	if [ $# -gt 1 ]; then
1021
		disk_is_or_disks_are="disks are"
1022 1023
		it_them="them"
	fi
1024

1025
	while true; do
1026
		echo "The following $disk_is_or_disks_are selected${USE_LVM:+ (with LVM)}:"
1027
		show_disk_info $diskdevs
1028 1029
		local _lvm=${USE_LVM:-", 'lvm'"}
		echon "How would you like to use $it_them? ('sys', 'data'${_lvm#_lvm} or '?' for help) [?] "
1030 1031 1032
		default_read answer '?'
		case "$answer" in
		'?') diskmode_help;;
1033
		sys|data) break;;
1034 1035 1036 1037 1038 1039 1040
		lvm) USE_LVM="_lvm" ;;
		nolvm) USE_LVM="";;
		lvmsys|lvmdata)
			answer=${answer#lvm}
			USE_LVM="_lvm"
			break
			;;
1041 1042
		esac
	done
1043
	DISK_MODE="$answer"
1044
fi
Natanael Copa's avatar
Natanael Copa committed
1045

1046 1047 1048 1049
if [ -z "$SWAP_SIZE" ]; then
	SWAP_SIZE=$(find_swap_size $diskdevs)
fi

1050 1051 1052 1053
set -- $diskdevs
if [ $# -gt 1 ]; then
	USE_RAID=1
fi
1054

1055 1056
dmesg -n1

1057
# native disk install
1058
case "$DISK_MODE" in
1059
sys) native_disk_install$USE_LVM $diskdevs;;
1060
data) data_only_disk_install$USE_LVM $diskdevs;;
1061
none) exit 0;;
1062
*) echo "Not a valid install mode: $DISK_MODE" >&2; exit 1;;
1063
esac
Natanael Copa's avatar
Natanael Copa committed
1064

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