setup-disk.in 10.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"}
Natanael Copa's avatar
Natanael Copa committed
7
8
9
10
11
12
13
14
15
16
17

in_list() {
	local i="$1"
	shift
	while [ $# -gt 0 ]; do
		[ "$i" = "$1" ] && return 0
		shift
	done
	return 1
}

18
19
20
21
22
23
24
25
# 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=
26
27
28
	case "$1" in
		/dev/md*) echo "$1" && return 0;;
	esac
29
30
31
32
33
34
35
36
37
38
39
40
41
	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
42
enumerate_fstab() {
43
	local mnt="$1"
44
	local fs_spec= fs_file= fs_vfstype= fs_mntops= fs_freq= fs_passno=
45
	[ -z "$mnt" ] && return
46
47
	local escaped_mnt=$(echo $mnt | sed 's:/:\\/:g')
	awk "\$2 ~ /^$escaped_mnt/ {print \$0}" /proc/mounts | \
48
49
50
51
		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
52
53
}

54
55
56
57
58
is_vmware() {
	grep -q VMware /proc/scsi/scsi 2>/dev/null \
		|| grep -q VMware /proc/ide/hd*/model 2>/dev/null
}

59
60
# Find the disk device from given partition
disk_from_part() {
61
62
	# we need convert cciss/c0d0* cciss!c0d0*...
	local i= part=$(echo ${1#/dev/} | sed 's:/:!:g')
63
64
	for i in /sys/block/*/$part; do
		i=${i%/*}
65
66
		# ...and back from cciss!c0d0 to cciss/c0d0
		echo "/dev/${i##*/}" | sed 's:!:/:g'
67
68
69
70
71
		return 0
	done
	return 1
}

72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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
}

107
108
install_mounted_root() {
	local mnt="$1"
109
	local features="ata base bootchart cdrom ext2 ext3 ide scsi usb"
110

111
	rootdev=$(awk "\$2 == \"$mnt\" { print \$1 }" /proc/mounts)
112
113
114
115
116
	if [ -z "$rootdev" ]; then
		echo "$mnt does not seem to be a mount point" >&2
		return 1
	fi

117
118
119
120
121
122
	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
		
123
	rootdisk=$(disk_from_part $rootdev)
124

125
	if [ -z "$APKOVL" ]; then
126
127
		ovlfiles=/tmp/ovlfiles
		lbu package - | tar -C "$mnt" -zxv > "$ovlfiles"
128
129
	else
		echo "Restoring backup from $APKOVL to $rootdev..."
130
		unpack_apkovl "$APKOVL" "$mnt" || return 1
131
	fi
132
133
	# remove the installed db in case its there so we force re-install
	rm -f "$mnt"/var/lib/apk/installed
134
	echon "Installing system on $rootdev: "
135
136
137
138
	# 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/

139
140
	local apkflags="--quiet --progress --update-cache --clean-protected"
	local pkgs=$(cat "$mnt"/var/lib/apk/world)
141
	pkgs="$pkgs acct linux-$KERNEL_FLAVOR alpine-base"
142
143
144
145
146
	local repos=$(sed -e 's/\#.*//' /etc/apk/repositories)
	local repoflags=
	for i in $repos; do
		repoflags="$repoflags --repository $i"
	done
147
148
	
	apk add --root "$mnt" $apkflags --overlay-from-stdin \
149
		$repoflags $pkgs <$ovlfiles>/dev/null || return 1
150
	echo ""
151

152
	# make things bootable
153
	if [ -e "/sys/block/${rootdev#/dev/}/md" ]; then
154
155
156
157
158
159
160
161
		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
162
163
164
			j=${i##*/}
			i=${j%[0-9]*}
			rootdisk="$rootdisk /dev/${i}"
165
166
		done
	fi
167

168
169
170
171
172
173
	if is_vmware; then
		pax_nouderef="pax_nouderef "
	else
		pax_nouderef=
	fi

174
175
176
177
	# create an extlinux.conf
	cat >"$mnt"/boot/extlinux.conf <<EOF
timeout 20
prompt 1
178
179
180
181
default $KERNEL_FLAVOR
label $KERNEL_FLAVOR
	kernel /boot/vmlinuz-$KERNEL_FLAVOR
	append initrd=/boot/initramfs-$KERNEL_FLAVOR root=$(uuid_or_device $rootdev) modules=sd-mod,usb-storage,ext3$raidmod ${pax_nouderef}quiet
182
EOF
183
184
185
186
187
	# fix the fstab
	enumerate_fstab "$mnt" >> "$mnt"/etc/fstab

	# install extlinux
	apk add -q syslinux
188
189
190
191
	extlinux -i $raidopt "$mnt"/boot/

	# unmount the partitions
	umount $(awk '{print $2}' /proc/mounts | grep ^"$mnt" | sort -r)
192

193
194
	# fix mbr for all disk devices
	for i in $rootdisk; do
195
196
197
198
		local errmsg
		echo "Writing MBR to $i"
		errmsg=$(dd if="$MBR" of=$i 2>&1) \
			|| echo "$errmsg"
199
	done
200
201
202
203
204
	echo ""
	echo "Installation is done. Please reboot."
	apk del -q syslinux
}

205
206
207
208
209
210
211
212
213
# 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
Natanael Copa's avatar
Natanael Copa committed
214
	# parse /proc/mounts for mounted devices
215
216
	for p in $(awk '$1 ~ /^\/dev\// {gsub("/dev/", "", $1); print $1}' \
			/proc/mounts); do
217
		[ "$p" = "$1" ] && return 0
Natanael Copa's avatar
Natanael Copa committed
218
		[ -e /sys/block/$1/$p ] && return 0
219
220
221
222
	done
	return 1
}

Natanael Copa's avatar
Natanael Copa committed
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
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
243
244
245
246
	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
247
248
249
250
251
252
253

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

	return 0
}

254
find_disks() {
Natanael Copa's avatar
Natanael Copa committed
255
	local p=
256
	for p in $(awk '$1 ~ /[0-9]+/ {print $4}' /proc/partitions); do
Natanael Copa's avatar
Natanael Copa committed
257
		is_available_disk $p && echo -n " $p"
258
259
260
	done
}

Natanael Copa's avatar
Natanael Copa committed
261
useall() {
262
	local rootdisk_dev="$1"
Natanael Copa's avatar
Natanael Copa committed
263
	local i size
264
265
266
267
268
269
270
271
272
273
274
275
276
	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

277
278
	dmesg -n1
	apk_add -q sfdisk e2fsprogs $raidpkg || return 1
279
280
281
282
283
284
285
286
287
288
289
290
	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 ""
291
292
293
	if [ -n "$APKOVL" ]; then
		echo "System from $APKOVL will be restored"
	fi
294
295
296
297
298
299
	echo -n "WARNING: All contents of $rootdisk_dev will be erased. Continue? [y/N]: "
	read i
	case "$i" in
		y*|Y*);;
		*) return 1;;
	esac
300
301
	
	echo "Initializing partitions..."
302
303
304
305
306
307
308
	if [ -n "$USE_RAID" ]; then
		local rd
		for rd in md0 md1 md2; do
			[ -b /dev/$rd ] && mdadm --stop /dev/$rd
		done
	fi

309
310
311
312
313
314
	# 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

315
316
317
318
319
320
	# create new partitions
	(cat <<EOF
0,$boot_size,$boot_part_type,*
,$swap_size,$swap_part_type
,,$root_part_type
EOF
321
	) | sfdisk -q -L -uM $rootdisk_dev >>/tmp/sfdisk.out || return 1
322
323

	# create device nodes if not exist
Natanael Copa's avatar
Natanael Copa committed
324
325
	mdev -s

326
327
328
329
	if [ -n "$USE_RAID" ]; then
		local p= rd=
		for p in $(sfdisk -l $rootdisk_dev 2>/dev/null \
				| awk '/Linux raid/ {print $1}'); do
330
			local opt="--metadata=0.90"
331
332
			case "$p" in
				*1) rd=/dev/md0; boot_dev=/dev/md0;;
333
334
				*2) rd=/dev/md1; swap_dev=/dev/md1
				    opt= ;;
335
336
337
				*3) rd=/dev/md2; root_dev=/dev/md2;;
			esac
			mdadm --create $rd --level=1 --raid-devices=2 \
338
				$opt --quiet --run $p missing
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
		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
367
	echo -e "$(uuid_or_device $swap_dev)\tswap\t\tswap\tdefaults 0 0" >> /etc/fstab
368
	install_mounted_root /mnt
Natanael Copa's avatar
Natanael Copa committed
369
370
}

371
372
373
374
375
KERNEL_FLAVOR=grsec
case "$(uname -r)" in
	*-vs[0-9]*) KERNEL_FLAVOR=vserver;;
esac

376
# Parse args
377
while getopts "k:o:r" opt; do
378
	case $opt in
379
		k) KERNEL_FLAVOR="$OPTARG";;
380
		r) USE_RAID=1;;
381
		o) APKOVL="$OPTARG";;
382
383
384
385
	esac
done
shift $(( OPTIND - 1))

386
387
if [ -d "$1" ]; then
	# install to given mounted root
388
	install_mounted_root "${1%/}"
389
390
391
	exit $?
fi

392
disks=$(find_disks)
Natanael Copa's avatar
Natanael Copa committed
393
394
395
396

# no disks so lets exit quietly.
[ -z "$disks" ] && exit 0

397
398
399
400
401
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
402
			echo "$i is not a suitable for partitioning"
403
404
405
406
407
			exit 1
		fi
	done

else
408
	set -- $disks
409
410
411
	rootdisk=
	while ! in_list "$rootdisk" $disks "none" "abort"; do
		echo "Available disks are: $disks"
412
413
		echon "Which one is the root disk? (or none) [$1] "
		default_read rootdisk $1
414
415
416
417
418
	done
	case "$rootdisk" in
		none|abort) exit 0;;
	esac
fi
Natanael Copa's avatar
Natanael Copa committed
419

420
421
422
423
424
425
426
427
428
429
#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
Natanael Copa's avatar
Natanael Copa committed
430

431
rootdisk_dev=${rootdisk_dev:-"/dev/$rootdisk"}
Natanael Copa's avatar
Natanael Copa committed
432

433
434
if ! [ -b "$rootdisk_dev" ]; then
	echo "$rootdisk_dev is not a block device" >&2
Natanael Copa's avatar
Natanael Copa committed
435
436
437
	exit 1
fi

438
useall $rootdisk_dev