1#!/bin/sh
2#
3# This script takes in account a disk list to make a lvm(8) stripe
4# which will contain a hammer filesystem and the swap partition.
5#
6# Be aware that this is just to provide _basic_ installation
7# functionalities and it may need actions from the sysadmin to
8# properly install and get a consistent installed system.
9
10# set -x
11
12export LVM_SUPPRESS_FD_WARNINGS=1
13
14disklist="da0 da1"
15bootdisk=""
16logfile="/tmp/hammer_lvm_stripe.log"
17
18#
19# err exitval message
20#     Display an error and exit
21#
22err()
23{
24    exitval=$1
25    shift
26
27    echo 1>&2 "$0: ERROR: $*"
28    exit $exitval
29}
30
31#
32# cktmpdir
33#
34#     Checks whether /tmp is writeable.
35#     Exit if not
36#
37cktmpdir()
38{
39    mktemp "/tmp/XXX" >> ${logfile} 2>&1
40
41    if [ $? -ne 0 ]; then
42	err 1 "/tmp directory must be writeable"
43    fi
44}
45
46#
47# ckpreinstall
48#
49#     Checks whether lv nodes exist which would may
50#     indicate an installation already succeeded or
51#     a previous failed one.
52#
53ckpreinstall()
54{
55
56    # Try to activate the volume first
57    vgchange -a y main >> ${logfile} 2>&1
58
59    if [ -c /dev/mapper/main-lv_root -o -c /dev/mapper/main-lv_swap ]; then
60	echo " ERROR: Either a previous installation failed or your installation"
61	echo " is already done. If the former, please follow instructions below."
62	echo ""
63
64	lvmexit
65    fi
66}
67
68
69#
70# ckstatus status progname
71#
72#     Checks exit status of programs and if it fails
73#     it exists with a message
74#
75ckstatus()
76{
77    local st=$1
78    local prog=$2
79
80    if [ ${st} -ne 0 ]; then
81	err 1 "Failed to run $2. Check ${logfile}"
82    fi
83}
84
85#
86# ckloadmod modname
87#
88#     Checks if a module is loaded, if not
89#     it tries to load it. In case of failure
90#     it exits
91#
92ckloadmod()
93{
94    local mod=$1
95
96    if ! kldstat -q -m ${mod}; then
97	kldload $1 >> ${logfile} 2>&1
98
99	if [ $? -ne 0 ]; then
100	    err 1 "Could not load ${mod}"
101        fi
102    fi
103}
104
105#
106# prepdisk disk
107#
108#     Clears the first sectors of the disk
109#     and then prepares the disk for disklabel.
110#     It also installs bootblocks in the first
111#     disk of the list.
112#
113prepdisk()
114{
115    local disk=$1
116
117    # Hey don't shoot yourself in the foot
118    if [ ! "$disk" = "" ]; then
119	mount | fgrep ${disk} >> ${logfile} 2>&1
120
121	if [ $? -ne 1 ]; then
122	    err 1 "${disk} is already being used, aborting"
123	fi
124    fi
125
126    if [ "${bootdisk}" = "" ]; then
127	bootdisk=${disk}
128    fi
129
130    dd if=/dev/zero of=/dev/${disk} bs=32k count=16 >> ${logfile} 2>&1
131    ckstatus $? "dd"
132
133    fdisk -IB ${disk} >> ${logfile} 2>&1
134    ckstatus $? "fdisk"
135
136    disklabel -r -w ${disk}s1 >> ${logfile} 2>&1
137    ckstatus $? "disklabel"
138
139    if [ ! "${bootdisk}" = "" ]; then
140	disklabel -B ${disk}s1 >> ${logfile} 2>&1
141	ckstatus $? "disklabel"
142    fi
143}
144
145#
146# mklabel disk
147#
148#     Create same labels for every disk
149#     except for the disk that will contain
150#     /boot partition
151#
152mklabel()
153{
154    local disk=$1
155
156    disklabel ${disk}s1 > /tmp/label
157    ckstatus $? "disklabel"
158
159    if [ "${disk}" = "${bootdisk}" ]; then
160	cat >> /tmp/label <<EOF
161 a: 768m 0 4.2BSD
162 d: * * unknown
163EOF
164    else
165	cat >> /tmp/label <<EOF
166 d: * * unknown
167EOF
168
169    fi
170
171    disklabel -R ${disk}s1 /tmp/label >> ${logfile} 2>&1
172    ckstatus $? "disklabel"
173}
174
175
176#
177# lvmexit
178#
179#     lvm exit message
180lvmexit()
181{
182    local status=$1
183
184    if [ $# -ne 0 ]; then
185	if [ ${status} -eq 0 ]; then
186	    return
187	fi
188    fi
189
190    echo " There was an error during or after LVM operations for this"
191    echo " installation and those operations done cannot be reverted"
192    echo " by the script itself. Please revert them manually:"
193    echo ""
194    echo " Basically you need to perform these steps:"
195    echo "   1. Remove all logical volumes in VG main (lv_swap, lv_root)"
196    echo "   2. Remove main volume group"
197    echo "   3. Remove all the physical volumes. PVs are all in [disk]1d"
198    echo "      For example, if you have 2 disks, you need to remove:"
199    echo "        /sbin/pvremove /dev/da0s1d"
200    echo "        /sbin/pvremove /dev/da1s1d"
201    echo ""
202    exit 1
203}
204
205#
206# rev_lvmops
207#
208#     Revert all lvmops
209#
210rev_lvmops()
211{
212
213    vgchange -a n main >> ${logfile} 2>&1
214
215    lvremove --force lv_swap main >> ${logfile} 2>&1
216    if [ $? -ne 0 ]; then
217        lvmexit
218    fi
219
220    lvremove --force lv_root main >> ${logfile} 2>&1
221    if [ $? -ne 0 ]; then
222        lvmexit
223    fi
224
225    vgremove --force main >> ${logfile} 2>&1
226    if [ $? -ne 0 ]; then
227        lvmexit
228    fi
229
230    for disk in ${disklist}
231    do
232	pvremove /dev/${disk}s1d >> ${logfile} 2>&1
233    done
234}
235
236#
237# lvmops
238#
239#     Create physical volumes, volume group 'main' and
240#     the ROOT hammer filesystem where everything will
241#     be installed. swap is also created as a log. volume.
242#
243lvmops()
244{
245    local lst=""
246    local tmp=""
247
248    for disk in ${disklist}
249    do
250	pvcreate /dev/${disk}s1d >> ${logfile} 2>&1
251	if [ $? -ne 0 ]; then
252	    rev_lvmops
253        fi
254	tmp=${lst}
255	lst="${tmp} /dev/${disk}s1d"
256
257	# Be safe
258	sync
259	sleep 1
260    done
261
262    # Do a full scan in the hope the lvm
263    # cache is rebuilt
264    pvscan >> ${logfile} 2>&1
265
266    vgcreate main ${lst} >> ${logfile} 2>&1
267    if [ $? -ne 0 ]; then
268        rev_lvmops
269    fi
270
271    # We need to sync and wait for some secs to settle
272    # Otherwise /dev/main won't appear
273    echo "     Settling LVM operations (5 secs)"
274    sync
275    sleep 5
276    vgscan >> ${logfile} 2>&1
277
278    lvcreate -Z n -n lv_swap -L ${memtotal} main >> ${logfile} 2>&1
279    if [ $? -ne 0 ]; then
280        rev_lvmops
281    fi
282
283    # We sync in every lvm operation
284    sync
285    lvscan >> ${logfile} 2>&1
286    sleep 1
287
288    lvcreate -Z n -n lv_root -l 100%FREE main >> ${logfile} 2>&1
289    if [ $? -ne 0 ]; then
290        rev_lvmops
291    fi
292
293}
294
295echo "ALL DATA IN DISKS ${disklist} WILL BE LOST!"
296echo "Press ^C to abort."
297for n in 10 9 8 7 6 5 4 3 2 1
298do
299    echo -n " ${n}"
300    sleep 1
301done
302echo ""
303
304# /tmp has to be writeable
305echo "* Checking /tmp is writeable"
306cktmpdir
307
308rm "${logfile}" >> ${logfile} 2>&1
309echo "* Output to ${logfile}"
310
311# calculate memory
312tmp=`sysctl hw.physmem | cut -w -f 2`
313memtotal=`expr ${tmp} / 1024 / 1024`
314
315# kldload needed modules and start udevd
316echo "* Loading modules"
317ckloadmod dm_target_striped >> ${logfile} 2>&1
318ckloadmod dm_target_linear >> ${logfile} 2>&1
319/sbin/udevd >> ${logfile} 2>&1
320
321# check previous installations
322ckpreinstall
323
324# Unmount any prior mounts on /mnt, reverse order to unwind
325# sub-directory mounts.
326#
327for mount in `df | fgrep /mnt | awk '{ print $6; }' | tail -r`
328do
329    echo " Umounting ${mount}"
330    umount ${mount} >> ${logfile} 2>&1
331done
332
333# Prepare the disks in the list
334for disk in ${disklist}
335do
336    echo "* Preparing disk ${disk}"
337    prepdisk ${disk}
338    mklabel ${disk}
339    pvscan >> ${logfile} 2>&1
340done
341
342# lvm(8) operations in the disks
343echo "* Performing LVM operations"
344lvmops
345
346# Format the volumes
347echo "* Formatting ${bootdisk} and LVs lv_root"
348newfs /dev/${bootdisk}s1a >> ${logfile} 2>&1
349lvmexit $?
350
351newfs_hammer -f -L ROOT /dev/main/lv_root >> ${logfile} 2>&1
352lvmexit $?
353
354# Mount it
355#
356echo "* Mounting everything"
357mount_hammer /dev/main/lv_root /mnt >> ${logfile} 2>&1
358lvmexit $?
359
360mkdir /mnt/boot
361
362mount /dev/${bootdisk}s1a /mnt/boot >> ${logfile} 2>&1
363lvmexit $?
364
365# Create PFS mount points for nullfs.
366pfslist="usr usr.obj var var.crash var.tmp tmp home"
367
368mkdir /mnt/pfs
369
370for pfs in ${pfslist}
371do
372    hammer pfs-master /mnt/pfs/$pfs >> ${logfile} 2>&1
373    lvmexit $?
374done
375
376# Mount /usr and /var so that you can add subdirs
377mkdir /mnt/usr >> ${logfile} 2>&1
378mkdir /mnt/var >> ${logfile} 2>&1
379mount_null /mnt/pfs/usr /mnt/usr >> ${logfile} 2>&1
380lvmexit $?
381
382mount_null /mnt/pfs/var /mnt/var >> ${logfile} 2>&1
383lvmexit $?
384
385mkdir /mnt/usr/obj >> ${logfile} 2>&1
386mkdir /mnt/var/tmp >> ${logfile} 2>&1
387mkdir /mnt/var/crash >> ${logfile} 2>&1
388
389mkdir /mnt/tmp >> ${logfile} 2>&1
390mkdir /mnt/home >> ${logfile} 2>&1
391
392mount_null /mnt/pfs/tmp /mnt/tmp >> ${logfile} 2>&1
393lvmexit $?
394
395mount_null /mnt/pfs/home /mnt/home >> ${logfile} 2>&1
396lvmexit $?
397
398mount_null /mnt/pfs/var.tmp /mnt/var/tmp >> ${logfile} 2>&1
399lvmexit $?
400
401mount_null /mnt/pfs/var.crash /mnt/var/crash >> ${logfile} 2>&1
402lvmexit $?
403
404mount_null /mnt/pfs/usr.obj /mnt/usr/obj >> ${logfile} 2>&1
405lvmexit $?
406
407chmod 1777 /mnt/tmp >> ${logfile} 2>&1
408chmod 1777 /mnt/var/tmp >> ${logfile} 2>&1
409
410# Install the system from the live CD
411#
412echo "* Starting file copy"
413cpdup -vv -o / /mnt >> ${logfile} 2>&1
414lvmexit $?
415
416cpdup -vv -o /boot /mnt/boot >> ${logfile} 2>&1
417lvmexit $?
418
419cpdup -vv -o /usr /mnt/usr >> ${logfile} 2>&1
420lvmexit $?
421
422cpdup -vv -o /var /mnt/var >> ${logfile} 2>&1
423lvmexit $?
424
425cpdup -vv -i0 /etc.hdd /mnt/etc >> ${logfile} 2>&1
426lvmexit $?
427
428chflags -R nohistory /mnt/tmp >> ${logfile} 2>&1
429chflags -R nohistory /mnt/var/tmp >> ${logfile} 2>&1
430chflags -R nohistory /mnt/var/crash >> ${logfile} 2>&1
431chflags -R nohistory /mnt/usr/obj >> ${logfile} 2>&1
432
433echo "* Adapting fstab and loader.conf"
434cat > /mnt/etc/fstab << EOF
435# Device		Mountpoint	FStype	Options		Dump	Pass#
436/dev/main/lv_root	/		hammer	rw		1	1
437/dev/${bootdisk}s1a	/boot		ufs	rw		1	1
438/dev/main/lv_swap	none		swap	sw		0	0
439/pfs/usr		/usr		null	rw		0	0
440/pfs/var		/var		null	rw		0	0
441/pfs/tmp		/tmp		null	rw		0	0
442/pfs/home		/home		null	rw		0	0
443/pfs/var.tmp		/var/tmp	null	rw		0	0
444/pfs/usr.obj		/usr/obj	null	rw		0	0
445/pfs/var.crash		/var/crash	null	rw		0	0
446proc			/proc		procfs	rw		0	0
447EOF
448
449# Because root is not on the boot partition we have to tell the loader
450# to tell the kernel where root is.
451#
452cat > /mnt/boot/loader.conf << EOF
453dm_target_striped_load="YES"
454dm_target_linear_load="YES"
455initrd.img_load="YES"
456initrd.img_type="md_image"
457vfs.root.mountfrom="ufs:md0s0"
458vfs.root.realroot="local:hammer:/dev/main/lv_root"
459EOF
460
461# Setup interface, configuration, sshd
462#
463echo "* iface setup"
464ifc=`route -n get default | fgrep interface | awk '{ print $2; }'`
465ip=`ifconfig $ifc | fgrep inet | fgrep -v inet6 | awk '{ print $2; }'`
466lip=`echo $ip | awk -F . '{ print $4; }'`
467
468echo -n "ifconfig_$ifc=" >> /mnt/etc/rc.conf
469echo '"DHCP"' >> /mnt/etc/rc.conf
470cat >> /mnt/etc/rc.conf << EOF
471sshd_enable="YES"
472dntpd_enable="YES"
473hostname="test$lip.MYDOMAIN.XXX"
474dumpdev="/dev/main/lv_swap"
475EOF
476
477# Misc sysctls
478#
479cat >> /mnt/etc/sysctl.conf << EOF
480#net.inet.ip.portrange.first=4000
481EOF
482
483# mkinitd image
484echo "* Preparing initrd image"
485/sbin/mkinitrd -b /mnt/boot >> ${logfile} 2>&1
486
487# Warn about ssh
488echo ""
489echo "Warning:"
490echo "chroot now to /mnt and change root password and also edit"
491echo "/mnt/etc/ssh/sshd_config to allow root login and authentication"
492echo "using passwords. Alternatively, you can also just copy your"
493echo "~/.ssh/authorized_keys file to allow login using your ssh keys."
494
495echo "Installation finished successfully."
496
497
498# take CD out and reboot
499#
500