summaryrefslogtreecommitdiff
path: root/usr/src/cmd/svc/milestone/fs-joyent
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/svc/milestone/fs-joyent')
-rwxr-xr-xusr/src/cmd/svc/milestone/fs-joyent312
1 files changed, 312 insertions, 0 deletions
diff --git a/usr/src/cmd/svc/milestone/fs-joyent b/usr/src/cmd/svc/milestone/fs-joyent
new file mode 100755
index 0000000000..0a9dc065a3
--- /dev/null
+++ b/usr/src/cmd/svc/milestone/fs-joyent
@@ -0,0 +1,312 @@
+#!/bin/bash
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2020 Joyent, Inc.
+#
+
+set -o xtrace
+
+fatal()
+{
+ echo "Error: $1"
+ exit $SMF_EXIT_ERR_FATAL
+}
+
+. /lib/svc/share/smf_include.sh
+. /lib/svc/share/fs_include.sh
+. /lib/sdc/usb-key.sh
+
+# first of all, if we aren't the global zone this doesn't make any sense to run
+
+smf_is_globalzone || exit $SMF_EXIT_OK
+
+# We need the links to /dev/dsk. Rather than trying to play games with manually
+# invoking syseventd ask devfsadm to do some work.
+/usr/sbin/devfsadm -c disk
+
+function destroy_zpools
+{
+ for pool in $(zpool list -p -o name | grep -v NAME) ; do
+ zpool destroy -f ${pool}
+ done
+}
+
+function mount_zfs
+{
+ local dataset=$1
+ local mountpoint=$2
+ local output=
+
+ #
+ # Try to mount the ZFS dataset. If the mountpoint is busy, wait five
+ # seconds and try again. Fail if the mount attempt returns EBUSY three
+ # consecutive times.
+ #
+ for i in {1..3}; do
+ output=$(mount -F zfs ${dataset} ${mountpoint} 2>&1)
+ if [[ $? -eq 0 ]]; then
+ break
+ fi
+
+ if [ "${output}" == "mount failed: Device busy" ]; then
+ sleep 5
+ else
+ echo ${output} 1>&2
+ return
+ fi
+ done
+
+ # The mount attempt must have failed
+ echo ${output} 1>&2
+}
+
+function unlock_pool
+{
+ local pool=$1
+
+ # If the key is already loaded, don't bother trying again
+ local keystatus="$(zfs get -Hpo value keystatus $pool)"
+ if [[ "$keystatus" == "available" ]]; then
+ return
+ fi
+
+ kbmadm unlock $pool && return
+
+ echo "Failed to unlock $pool; recovery may be required" | \
+ tee -a /dev/console >&2
+
+ exit $SMF_EXIT_ERR_FATAL
+}
+
+/bin/bootparams | grep "^noimport=true" >/dev/null
+if [ $? -ne 0 ]; then
+ # If the zpool doesn't exist, then there's nothing to mount.
+
+ # Assume the system zpool is zones, but if a different system pool
+ # identifies itself (by virtue of the .system_pool file being present in the
+ # pool's root dataset), then use that system pool instead.
+ SYS_ZPOOL=zones
+
+ # Import specified zpools, or all zpools available
+ pools=$(/bin/bootparams | egrep "^zpools?=" | cut -d= -f2 | tr , ' ')
+ if [ -z ${pools} ]; then
+ pools=$(zpool import | grep "pool:" | awk '{print $2}')
+ fi
+
+ for pool in $pools; do
+ zpool import -f $pool || continue
+
+ is_encr="$(zfs get -Hpo value encryption $pool)"
+
+ [[ "$is_encr" != "off" ]] && unlock_pool $pool
+
+ # Due to early, failed attempts to support the filesystem_limits
+ # feature we now need to ensure the dependent feature is enabled.
+ zpool set feature@extensible_dataset=enabled $pool
+ if [[ -f /$pool/.system_pool ]]; then
+ SYS_ZPOOL=$pool
+ [[ "$is_encr" != "off" ]] && kbmadm set-syspool $pool
+ fi
+ done
+
+ svccfg -s svc:/system/smartdc/init setprop \
+ config/zpool=${SYS_ZPOOL}
+ svccfg -s svc:/system/smartdc/init:default refresh
+
+ # If the destroy_zpools boot parameter is set, destroy all zpools
+ /bin/bootparams | grep "^destroy_zpools=true" >/dev/null
+ if [ $? -eq 0 ]; then
+ destroy_zpools
+ fi
+
+ # A machine is reset to its original unsetup state (i.e. a 'factory reset')
+ # when the smartdc:factoryreset ZFS user property is set on the var dataset.
+ reset=$(zfs get -H -o value smartdc:factoryreset ${SYS_ZPOOL}/var)
+ if [ "${reset}" == "yes" ]; then
+ destroy_zpools
+ fi
+
+ # Capture the zpool's status output in the method's log file for
+ # troubleshooting.
+ #
+ # Note: It is critical that we do not run 'status -v'. If there are errors
+ # in the zpool error log and the zpool is large (e.g. > 200TB), then the
+ # lookup for the error file names can take a very long time (several hours).
+ # This would block the system boot until it completed.
+ zpool status ${SYS_ZPOOL}
+ if [ $? -eq 0 ]; then
+
+ # Stash the SUNWdefault.xml file so we can update the
+ # persistent version after mounting zones/config.
+ cp /etc/zones/SUNWdefault.xml /tmp/
+
+ # Mount and configure all system datasets
+ mount_zfs ${SYS_ZPOOL}/var /var
+ mount_zfs ${SYS_ZPOOL}/config /etc/zones
+ mount_zfs ${SYS_ZPOOL}/opt /opt
+
+ # Update the the persistent SUNWdefault.xml file to match the
+ # contents on ramdisk now that zones/config is mounted.
+ cp /tmp/SUNWdefault.xml /etc/zones/
+ rm -f /tmp/SUNWdefault.xml
+
+ #
+ # We include a manifest of all files shipped in the platform image,
+ # along with an MD5 hash of their contents. This was originally
+ # shipped as "/var/log/manifest", but once a machine is set up, "/var"
+ # now comes from the pool. The upshot of this is that every SmartOS
+ # machine has the manifest from the platform at setup time stored in
+ # "/var/log/manifest". Now that the manifest has moved to an
+ # accessible location, we should remove this file and replace it with a
+ # symbolic link.
+ #
+ if [[ -f '/var/log/manifest' && ! -L '/var/log/manifest' &&
+ ! -e '/var/log/manifest.original' ]]; then
+ mv '/var/log/manifest' '/var/log/manifest.original'
+ ln -s '../../usr/share/smartos/manifest' '/var/log/manifest'
+ fi
+
+ if [[ -z $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mkdir -p /opt/smartdc/agents/smf
+ mount -O -F lofs /var/svc/manifest/site /opt/smartdc/agents/smf
+ fi
+
+ if [[ -n $(/bin/bootparams | grep '^headnode=true') || \
+ -n $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mkdir /usbkey
+ mount_zfs ${SYS_ZPOOL}/usbkey /usbkey
+ fi
+
+ if [[ -n $(/bin/bootparams | grep '^smartos=true') ]]; then
+ mount -F lofs /usbkey/shadow /etc/shadow
+ mount -F lofs /usbkey/ssh /etc/ssh
+ fi
+
+ swap -a /dev/zvol/dsk/${SYS_ZPOOL}/swap || \
+ fatal "failed to configure swap device"
+
+ #
+ # Configure the dump device on top of a ZFS volume. In addition to the
+ # usual dumpadm(1m) call, there are two prerequisites for using this
+ # volume as a dump device: (1) that zvol must be using the noparity
+ # checksum algorithem, and (2) the MULTI_VDEV_CRASH_DUMP ZFS feature
+ # must be enabled. Prerequisite (1) is necessary since the exact
+ # on-disk value for ZIO_CHECKSUM_NOPARITY has changed, so to avoid a
+ # flag day on all systems, this service just sets that property again
+ # every time.
+ #
+ zfs set checksum=noparity ${SYS_ZPOOL}/dump || \
+ fatal "failed to set checksum=noparity on dump zvol"
+ zpool set feature@multi_vdev_crash_dump=enabled ${SYS_ZPOOL} || \
+ fatal "failed to enable multi_vdev_crash_dump ZFS feature"
+ dumpadm -y -d /dev/zvol/dsk/${SYS_ZPOOL}/dump || \
+ fatal "failed to configure dump device"
+
+ zfs list -H -o name ${SYS_ZPOOL}/cores/global >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ # Booting for the first time on a CN whose cores dataset is setup
+ # in the 6.x style. Convert to the new style.
+ zfs destroy -r ${SYS_ZPOOL}/cores
+ zfs create -o compression=gzip -o mountpoint=none ${SYS_ZPOOL}/cores
+ zfs create -o quota=10g -o mountpoint=/${SYS_ZPOOL}/global/cores \
+ ${SYS_ZPOOL}/cores/global
+ fi
+
+ ln -s /${SYS_ZPOOL}/global/cores /cores
+
+ [[ -f /${SYS_ZPOOL}/currbooted ]] && \
+ mv /${SYS_ZPOOL}/currbooted /${SYS_ZPOOL}/lastbooted
+ uname -v >/${SYS_ZPOOL}/currbooted
+ fi
+fi
+
+
+# The rest only applies to the headnode
+/bin/bootparams | grep "^headnode=true" >/dev/null || exit $SMF_EXIT_OK
+
+# If we rebooted during an upgrade, we're in deep trouble.
+if [ -d /var/upgrade_in_progress ]; then
+ echo "ERROR: An upgrade was in progress when the system rebooted." \
+ >/dev/console
+ echo " The system is in an indeterminate state, unable to continue." \
+ >/dev/console
+ exit $SMF_EXIT_ERR_FATAL
+fi
+
+COPYINPOINT=`svcprop -p "joyentfs/usb_copy_path" ${SMF_FMRI}`
+DEBUG=`svcprop -p "joyentfs/debug" ${SMF_FMRI}`
+
+if [[ -d /mnt ]]; then
+ chown root:root /mnt
+ chmod 700 /mnt
+else
+ mkdir -m 700 /mnt
+fi
+
+function make_usb_copy_if_possible
+{
+ [[ -n "${SYS_ZPOOL}" ]] || fatal "don't know system zpool name"
+
+ zpool list -Ho name | grep "^${SYS_ZPOOL}\$"
+ if [[ $? != 0 ]]; then
+ echo "skipping USB copy setup: no ${SYS_ZPOOL} zpool" >/dev/console
+ # Still return OK, because this is the expected case for first headnode
+ # boot.
+ return 0
+ fi
+
+ USBDATASET=${SYS_ZPOOL}/usbkey
+ if ! zfs list -Ho name | grep "^${USBDATASET}\$" >/dev/null; then
+ echo "skipping USB copy setup: no zones/usbkey dataset" >/dev/console
+ # Still return OK, because as of HEAD-2343 a CN being converted to a HN
+ # will not yet have this dataset on its first boot as an HN.
+ return 0
+ fi
+
+ echo "" > /dev/console
+ echo "Moving files from USB boot device onto disk storage." > /dev/console
+ echo "This may take several minutes. Please note the time..." > /dev/console
+ echo "" > /dev/console
+ echo "" > /dev/console
+
+ mkdir ${COPYINPOINT}
+ mount_zfs ${USBDATASET} ${COPYINPOINT}
+
+ (cd ${USBMOUNTPOINT}; rsync -av --log-file=/dev/console --exclude private --exclude os * ${COPYINPOINT})
+ if [[ -d ${USBMOUNTPOINT}/os ]]; then
+ (cd ${USBMOUNTPOINT}/os ; \
+ for dir in $(ls -d *); do
+ # source comes from pcfs which we've got lowering the case
+ # of everything, but we normally use capital T and Z for
+ # buildstamp, so fix it here.
+ source_dir=${dir}
+ target_dir=$(echo ${dir} | tr "[:lower:]" "[:upper:]")
+ mkdir -p ${COPYINPOINT}/os
+ echo "Copying: ${source_dir}/ ${COPYINPOINT}/os/${target_dir}" > /dev/console
+ rsync -a ${source_dir}/ ${COPYINPOINT}/os/${target_dir}
+ done
+ )
+ fi
+
+ echo "" > /dev/console
+ echo "Done copying files from USB device" > /dev/console
+ return 0
+}
+
+USBMOUNTPOINT=$(mount_usb_key "")
+if [[ $? -ne 0 ]]; then
+ fatal "couldn't mount USB key"
+fi
+
+make_usb_copy_if_possible
+exit $?