1#!/bin/sh
2#-
3# Copyright (c) 2010 iXsystems, Inc.  All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8# 1. Redistributions of source code must retain the above copyright
9#    notice, this list of conditions and the following disclaimer.
10# 2. Redistributions in binary form must reproduce the above copyright
11#    notice, this list of conditions and the following disclaimer in the
12#    documentation and/or other materials provided with the distribution.
13#
14# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24# SUCH DAMAGE.
25#
26# $FreeBSD$
27
28# Functions which perform the final cleanup after an install
29
30# Finishes up with ZFS setup before unmounting
31zfs_cleanup_unmount()
32{
33  # Loop through our FS and see if we have any ZFS partitions to cleanup
34  for PART in `ls ${PARTDIR}`
35  do
36    PARTDEV=`echo $PART | sed 's|-|/|g'`
37    PARTFS="`cat ${PARTDIR}/${PART} | cut -d '#' -f 1`"
38    PARTMNT="`cat ${PARTDIR}/${PART} | cut -d '#' -f 2`"
39    ZPOOLNAME=$(get_zpool_name "${PARTDEV}")
40
41    if [ "$PARTFS" = "ZFS" ]
42    then
43      # Check if we have multiple zfs mounts specified
44      for ZMNT in `echo ${PARTMNT} | sed 's|,| |g'`
45      do
46        if [ "${ZMNT}" = "/" ]
47        then
48          # Make sure we haven't already added the zfs boot line when
49          # Creating a dedicated "/boot" partition
50          cat ${FSMNT}/boot/loader.conf 2>/dev/null | grep -q "vfs.root.mountfrom=" 2>/dev/null
51          if [ $? -ne 0 ] ; then
52            echo "vfs.root.mountfrom=\"zfs:${ZPOOLNAME}/ROOT/default\"" >> ${FSMNT}/boot/loader.conf
53          fi
54          export FOUNDZFSROOT="${ZPOOLNAME}"
55        fi
56      done
57      FOUNDZFS="1"
58    fi
59  done
60
61  if [ -n "${FOUNDZFS}" ]
62  then
63    # Check if we need to add our ZFS flags to rc.conf, src.conf and loader.conf
64    cat ${FSMNT}/boot/loader.conf 2>/dev/null | grep -q 'zfs_load="YES"' 2>/dev/null
65    if [ $? -ne 0 ]
66    then
67      echo 'zfs_load="YES"' >>${FSMNT}/boot/loader.conf
68    fi
69    cat ${FSMNT}/etc/rc.conf 2>/dev/null | grep -q 'zfs_enable="YES"' 2>/dev/null
70    if [ $? -ne 0 ]
71    then
72      echo 'zfs_enable="YES"' >>${FSMNT}/etc/rc.conf
73    fi
74
75    sleep 2
76    # Copy over any ZFS cache data
77    cp /boot/zfs/* ${FSMNT}/boot/zfs/
78
79    # Copy the hostid so that our zfs cache works
80    cp /etc/hostid ${FSMNT}/etc/hostid
81  fi
82
83  # Loop through our FS and see if we have any ZFS partitions to cleanup
84  for PART in `ls ${PARTDIR}`
85  do
86    PARTDEV=`echo $PART | sed 's|-|/|g'`
87    PARTFS="`cat ${PARTDIR}/${PART} | cut -d '#' -f 1`"
88    PARTMNT="`cat ${PARTDIR}/${PART} | cut -d '#' -f 2`"
89    PARTENC="`cat ${PARTDIR}/${PART} | cut -d '#' -f 3`"
90    ZPOOLNAME=$(get_zpool_name "${PARTDEV}")
91
92    if [ "$PARTFS" = "ZFS" ]
93    then
94
95      # Create a list of zpool names we can export
96      echo $ZPOOLEXPORTS | grep -q "$ZPOOLNAME "
97      if [ $? -ne 0 ] ; then
98        export ZPOOLEXPORTS="$ZPOOLNAME $ZPOOLEXPORTS"
99      fi
100
101      # Check if we have multiple zfs mounts specified
102      for ZMNT in `echo ${PARTMNT} | sed 's|,| |g'`
103      do
104	ZMNT="`echo $ZMNT | cut -d '(' -f 1`"
105        PARTMNTREV="${ZMNT} ${PARTMNTREV}"
106      done
107
108      for ZMNT in ${PARTMNTREV}
109      do
110        if [ "${ZMNT}" = "/" ] ; then continue ; fi
111        # Some ZFS like /swap aren't mounted, and dont need unmounting
112        mount | grep -q "${FSMNT}${ZMNT}"
113	if [ $? -eq 0 ] ; then
114          rc_halt "zfs unmount ${ZPOOLNAME}${ZMNT}"
115          rc_halt "zfs set mountpoint=${ZMNT} ${ZPOOLNAME}${ZMNT}"
116        fi
117        sleep 2
118      done
119    fi
120  done
121
122};
123
124# Function which performs the specific setup for using a /boot partition
125setup_dedicated_boot_part()
126{
127  ROOTFS="${1}"
128  ROOTFSTYPE="${2}"
129  BOOTFS="${3}"
130  BOOTMNT="${4}"
131
132  # Set the root mount in loader.conf
133  echo "vfs.root.mountfrom=\"${ROOTFSTYPE}:${ROOTFS}\"" >> ${FSMNT}/boot/loader.conf
134  rc_halt "mkdir -p ${FSMNT}/${BOOTMNT}/boot"
135  rc_halt "mv ${FSMNT}/boot/* ${FSMNT}${BOOTMNT}/boot/"
136  rc_halt "mv ${FSMNT}${BOOTMNT}/boot ${FSMNT}/boot/"
137  rc_halt "umount ${BOOTFS}"
138  rc_halt "mount ${BOOTFS} ${FSMNT}${BOOTMNT}"
139  rc_halt "rmdir ${FSMNT}/boot"
140
141  # Strip the '/' from BOOTMNT before making symlink
142  BOOTMNTNS="`echo ${BOOTMNT} | sed 's|/||g'`"
143  rc_halt "chroot ${FSMNT} ln -s ${BOOTMNTNS}/boot /boot"
144  
145};
146
147# Function which creates the /etc/fstab for the installed system
148setup_fstab()
149{
150  FSTAB="${FSMNT}/etc/fstab"
151  rm ${FSTAB} >/dev/null 2>/dev/null
152
153  # Create the header
154  echo "# Device		Mountpoint		FStype		Options	Dump Pass" >> ${FSTAB}
155
156  # Loop through the partitions, and start creating /etc/fstab
157  for PART in `ls ${PARTDIR}`
158  do
159    PARTDEV=`echo $PART | sed 's|-|/|g'`
160    PARTFS="`cat ${PARTDIR}/${PART} | cut -d '#' -f 1`"
161    PARTMNT="`cat ${PARTDIR}/${PART} | cut -d '#' -f 2`"
162    PARTENC="`cat ${PARTDIR}/${PART} | cut -d '#' -f 3`"
163    PARTLABEL="`cat ${PARTDIR}/${PART} | cut -d '#' -f 4`"
164
165    # Unset EXT
166    EXT=""
167
168    # Set mount options for file-systems
169    case $PARTFS in
170      UFS+J) MNTOPTS="rw,noatime,async" ;;
171      SWAP) MNTOPTS="sw" ;;
172      *) MNTOPTS="rw,noatime" ;;
173    esac
174
175
176    # Figure out if we are using a glabel, or the raw name for this entry
177    if [ -n "${PARTLABEL}" ]
178    then
179      DEVICE="label/${PARTLABEL}"
180    else
181      # Check if using encryption 
182      if [ "${PARTENC}" = "ON" ] ; then
183        EXT=".eli"
184      fi
185
186      if [ "${PARTFS}" = "UFS+J" ] ; then
187        EXT="${EXT}.journal"
188      fi
189      DEVICE="${PARTDEV}${EXT}"
190    fi
191
192
193    # Set our ROOTFSTYPE for loader.conf if necessary
194    check_for_mount "${PARTMNT}" "/"
195    if [ $? -eq 0 ] ; then
196      if [ "${PARTFS}" = "ZFS" ] ; then
197        ROOTFSTYPE="zfs"
198        ZPOOLNAME=$(get_zpool_name "${PARTDEV}")
199        ROOTFS="${ZPOOLNAME}/ROOT/default"
200      else
201        ROOTFS="${DEVICE}"
202        ROOTFSTYPE="ufs"
203      fi
204    fi
205
206    # Only create non-zfs partitions
207    if [ "${PARTFS}" != "ZFS" ]
208    then
209
210      # Make sure geom_journal is loaded
211      if [ "${PARTFS}" = "UFS+J" ] ; then
212        setup_gjournal
213      fi
214
215      # Save the BOOTFS for call at the end
216      if [ "${PARTMNT}" = "/boot" ] ; then
217        BOOTFS="${PARTDEV}${EXT}"
218        BOOTMNT="${BOOT_PART_MOUNT}"
219        PARTMNT="${BOOTMNT}"
220      fi
221
222      # Echo out the fstab entry now
223      if [ "${PARTFS}" = "SWAP" ]
224      then
225        echo "/dev/${DEVICE}	none		swap	${MNTOPTS}	0	0" >> ${FSTAB}
226      else
227        echo "/dev/${DEVICE}	${PARTMNT}		ufs	${MNTOPTS}	1	1" >> ${FSTAB}
228      fi
229
230    fi # End of ZFS Check
231  done
232
233  # Setup some specific PC-BSD fstab options
234  if [ "$INSTALLTYPE" != "FreeBSD" ]
235  then
236    echo "procfs			/proc			procfs		rw		0	0" >> ${FSTAB}
237    echo "linprocfs		/compat/linux/proc	linprocfs	rw		0	0" >> ${FSTAB}
238  fi
239
240  # If we have a dedicated /boot, run the post-install setup of it now
241  if [ ! -z "${BOOTMNT}" ] ; then 
242    setup_dedicated_boot_part "${ROOTFS}" "${ROOTFSTYPE}" "${BOOTFS}" "${BOOTMNT}"
243  fi
244
245};
246
247# Setup our disk mirroring with gmirror
248setup_gmirror()
249{
250  cat ${FSMNT}/boot/loader.conf 2>/dev/null | grep -q 'geom_mirror_load="YES"' 2>/dev/null
251  if [ $? -ne 0 ]
252  then
253    echo 'geom_mirror_load="YES"' >>${FSMNT}/boot/loader.conf
254  fi
255
256};
257
258# Function which saves geli keys and sets up loading of them at boot
259setup_geli_loading()
260{
261
262  # Make our keys dir
263  mkdir -p ${FSMNT}/boot/keys >/dev/null 2>/dev/null
264
265  cd ${GELIKEYDIR}
266  for KEYFILE in `ls`
267  do
268     # Figure out the partition name based on keyfile name removing .key
269     PART="`echo ${KEYFILE} | cut -d '.' -f 1`"
270     PARTDEV="`echo ${PART} | sed 's|-|/|g'`"
271     PARTNAME="`echo ${PART} | sed 's|-dev-||g'`"
272
273     rc_halt "geli configure -b ${PARTDEV}"
274
275     # If no passphrase, setup key files
276     if [ ! -e "${PARTDIR}-enc/${PART}-encpass" ] ; then
277       echo "geli_${PARTNAME}_keyfile0_load=\"YES\"" >> ${FSMNT}/boot/loader.conf 
278       echo "geli_${PARTNAME}_keyfile0_type=\"${PARTNAME}:geli_keyfile0\"" >> ${FSMNT}/boot/loader.conf 
279       echo "geli_${PARTNAME}_keyfile0_name=\"/boot/keys/${PARTNAME}.key\"" >> ${FSMNT}/boot/loader.conf 
280
281       # Copy the key to the disk
282       rc_halt "cp ${GELIKEYDIR}/${KEYFILE} ${FSMNT}/boot/keys/${PARTNAME}.key"
283     fi
284
285  done
286
287  # Make sure we have geom_eli set to load at boot
288  cat ${FSMNT}/boot/loader.conf 2>/dev/null | grep -q 'geom_eli_load="YES"' 2>/dev/null
289  if [ $? -ne 0 ]
290  then
291    echo 'geom_eli_load="YES"' >>${FSMNT}/boot/loader.conf
292  fi
293
294};
295
296
297# Function to generate a random hostname if none was specified
298gen_hostname()
299{
300  RAND="`jot -r 1 1 9000`"
301
302  if [ "$INSTALLTYPE" = "FreeBSD" ]
303  then
304    VAL="freebsd-${RAND}" 
305  else
306    VAL="pcbsd-${RAND}" 
307  fi
308
309  export VAL
310
311};
312
313# Function which sets up the hostname for the system
314setup_hostname()
315{
316
317  get_value_from_cfg hostname
318  HOSTNAME="${VAL}"
319
320  # If we don't have a hostname, make one up
321  if [ -z "${HOSTNAME}" ]
322  then
323    gen_hostname
324    HOSTNAME="${VAL}"
325  fi
326
327  # Clean up any saved hostname
328  cat ${FSMNT}/etc/rc.conf | grep -v "hostname=" >${FSMNT}/etc/rc.conf.new
329  mv ${FSMNT}/etc/rc.conf.new ${FSMNT}/etc/rc.conf
330
331  # Set the hostname now
332  echo_log "Setting hostname: ${HOSTNAME}"
333  echo "hostname=\"${HOSTNAME}\"" >> ${FSMNT}/etc/rc.conf
334  sed -i -e "s|my.domain|${HOSTNAME} ${HOSTNAME}|g" ${FSMNT}/etc/hosts
335
336};
337
338
339# Check and make sure geom_journal is enabled on the system
340setup_gjournal()
341{
342
343  # Make sure we have geom_journal set to load at boot
344  cat ${FSMNT}/boot/loader.conf 2>/dev/null | grep -q 'geom_journal_load="YES"' 2>/dev/null
345  if [ $? -ne 0 ]
346  then
347    echo 'geom_journal_load="YES"' >>${FSMNT}/boot/loader.conf
348  fi
349
350};
351
352# Function which sets the root password from the install config
353set_root_pw()
354{
355  # Get the plaintext string
356  get_value_from_cfg_with_spaces rootPass
357  local PW="${VAL}"
358
359  # Get the encrypted string
360  get_value_from_cfg_with_spaces rootEncPass
361  local ENCPW="${VAL}"
362
363  # If we don't have a root pass, return
364  if [ -z "${PW}" -a -z "${ENCPW}" ] ; then return 0 ; fi
365
366  echo_log "Setting root password"
367
368  # Check if setting plaintext password
369  if [ -n "${PW}" ] ; then
370    echo "${PW}" > ${FSMNT}/.rootpw
371    run_chroot_cmd "cat /.rootpw | pw usermod root -h 0"
372    rc_halt "rm ${FSMNT}/.rootpw"
373  fi
374
375  # Check if setting encrypted password
376  if [ -n "${ENCPW}" ] ; then
377    echo "${ENCPW}" > ${FSMNT}/.rootpw
378    run_chroot_cmd "cat /.rootpw | pw usermod root -H 0"
379    rc_halt "rm ${FSMNT}/.rootpw"
380  fi
381
382};
383
384
385run_final_cleanup()
386{
387  # Check if we need to run any gmirror setup
388  ls ${MIRRORCFGDIR}/* >/dev/null 2>/dev/null
389  if [ $? -eq 0 ]
390  then
391    # Lets setup gmirror now
392    setup_gmirror
393  fi
394
395  # Check if we need to save any geli keys
396  ls ${GELIKEYDIR}/* >/dev/null 2>/dev/null
397  if [ $? -eq 0 ]
398  then
399    # Lets setup geli loading
400    setup_geli_loading
401  fi
402
403  # Set a hostname on the install system
404  setup_hostname
405
406  # Set the root_pw if it is specified
407  set_root_pw
408
409  # Generate the fstab for the installed system
410  setup_fstab
411};
412