17c478bd9Sstevel@tonic-gate#!/sbin/sh
27c478bd9Sstevel@tonic-gate#
37c478bd9Sstevel@tonic-gate# CDDL HEADER START
47c478bd9Sstevel@tonic-gate#
57c478bd9Sstevel@tonic-gate# The contents of this file are subject to the terms of the
67c478bd9Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only
77c478bd9Sstevel@tonic-gate# (the "License").  You may not use this file except in compliance
87c478bd9Sstevel@tonic-gate# with the License.
97c478bd9Sstevel@tonic-gate#
107c478bd9Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
117c478bd9Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing.
127c478bd9Sstevel@tonic-gate# See the License for the specific language governing permissions
137c478bd9Sstevel@tonic-gate# and limitations under the License.
147c478bd9Sstevel@tonic-gate#
157c478bd9Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each
167c478bd9Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
177c478bd9Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the
187c478bd9Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying
197c478bd9Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner]
207c478bd9Sstevel@tonic-gate#
217c478bd9Sstevel@tonic-gate# CDDL HEADER END
227c478bd9Sstevel@tonic-gate#
237c478bd9Sstevel@tonic-gate#
24943287c6SIgor Kozhukhov# Copyright 2012 Nexenta Sysytems, Inc.  All rights reserved.
258918dff3Sjwadams# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
267c478bd9Sstevel@tonic-gate# Use is subject to license terms.
277c478bd9Sstevel@tonic-gate#
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gatePATH=/sbin:/usr/bin:/usr/sbin
308918dff3SjwadamsLC_ALL=C
318918dff3Sjwadamsexport PATH LC_ALL
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate. /lib/svc/share/smf_include.sh
347c478bd9Sstevel@tonic-gate. /lib/svc/share/fs_include.sh
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gateusage()
377c478bd9Sstevel@tonic-gate{
387c478bd9Sstevel@tonic-gate	echo "usage: $0 [-r rootdir]" >&2
398918dff3Sjwadams	echo "
40654b400cSJoshua M. ClulowSee http://illumos.org/msg/SMF-8000-MY for more information on the use of
418918dff3Sjwadamsthis script."
427c478bd9Sstevel@tonic-gate	exit 2;
437c478bd9Sstevel@tonic-gate}
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gaterepositorydir=etc/svc
467c478bd9Sstevel@tonic-gaterepository=repository
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gatemyroot=/
497c478bd9Sstevel@tonic-gatewhile getopts r: opt; do
507c478bd9Sstevel@tonic-gate	case "$opt" in
517c478bd9Sstevel@tonic-gate	    r)	myroot=$OPTARG
527c478bd9Sstevel@tonic-gate		if [ ! -d $myroot ]; then
537c478bd9Sstevel@tonic-gate			echo "$myroot: not a directory" >&2
547c478bd9Sstevel@tonic-gate			exit 1
557c478bd9Sstevel@tonic-gate		fi
567c478bd9Sstevel@tonic-gate		# validate directory and make sure it ends in '/'.
577c478bd9Sstevel@tonic-gate		case "$myroot" in
587c478bd9Sstevel@tonic-gate		    //*) echo "$myroot: must begin with a single /" >&2
597c478bd9Sstevel@tonic-gate			usage;;
607c478bd9Sstevel@tonic-gate		    /)	echo "$myroot: alternate root cannot be /" >&2
617c478bd9Sstevel@tonic-gate			usage;;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate		    /*/) ;;			# ends with /
647c478bd9Sstevel@tonic-gate		    /*) myroot="$myroot/";;	# add final /
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate		    *)	echo "$myroot: must be a full path" >&2
677c478bd9Sstevel@tonic-gate			usage;;
687c478bd9Sstevel@tonic-gate		esac;;
697c478bd9Sstevel@tonic-gate	    ?)	usage;;
707c478bd9Sstevel@tonic-gate	esac
717c478bd9Sstevel@tonic-gatedone
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gateif [ $OPTIND -le $# ]; then
747c478bd9Sstevel@tonic-gate	# getopts(1) didn't slurp up everything.
757c478bd9Sstevel@tonic-gate	usage
767c478bd9Sstevel@tonic-gatefi
777c478bd9Sstevel@tonic-gate
788918dff3Sjwadams#
798918dff3Sjwadams# Note that the below test is carefully constructed to fail *open*;  if
808918dff3Sjwadams# anything goes wrong, it will drive onward.
818918dff3Sjwadams#
828918dff3Sjwadamsif [ -x /usr/bin/id -a -x /usr/bin/grep ] &&
838918dff3Sjwadams    /usr/bin/id 2>/dev/null | /usr/bin/grep -v '^[^=]*=0(' >/dev/null 2>&1; then
848918dff3Sjwadams	echo "$0: may only be invoked by root" >&2
858918dff3Sjwadams	exit 2
868918dff3Sjwadamsfi
878918dff3Sjwadams
888918dff3Sjwadamsecho >&2 "
89654b400cSJoshua M. ClulowSee http://illumos.org/msg/SMF-8000-MY for more information on the use of
90*bbf21555SRichard Lowethis script to restore backup copies of the smf(7) repository.
918918dff3Sjwadams
928918dff3SjwadamsIf there are any problems which need human intervention, this script will
938918dff3Sjwadamsgive instructions and then exit back to your shell."
948918dff3Sjwadams
95943287c6SIgor Kozhukhovif [ "$myroot" = "/" ]; then
967c478bd9Sstevel@tonic-gate	system="system"
977c478bd9Sstevel@tonic-gate	[ "`/sbin/zonename`" != global ] && system="zone"
987c478bd9Sstevel@tonic-gate	echo >&2 "
997c478bd9Sstevel@tonic-gateNote that upon full completion of this script, the $system will be rebooted
100*bbf21555SRichard Loweusing reboot(8), which will interrupt any active services.
1017c478bd9Sstevel@tonic-gate"
1027c478bd9Sstevel@tonic-gatefi
1037c478bd9Sstevel@tonic-gate
1047c478bd9Sstevel@tonic-gate# check that the filesystem is as expected
1057c478bd9Sstevel@tonic-gatecd "$myroot" || exit 1
1067c478bd9Sstevel@tonic-gatecd "$myroot$repositorydir" || exit 1
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gatenouser=false
1097c478bd9Sstevel@tonic-gaterootro=false
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate# check to make sure /usr is mounted
1127c478bd9Sstevel@tonic-gateif [ ! -x /usr/bin/pgrep ]; then
1137c478bd9Sstevel@tonic-gate	nouser=true
1147c478bd9Sstevel@tonic-gatefi
1158918dff3Sjwadams
1167c478bd9Sstevel@tonic-gateif [ ! -w "$myroot" ]; then
1177c478bd9Sstevel@tonic-gate	rootro=true
1187c478bd9Sstevel@tonic-gatefi
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gateif [ "$nouser" = true -o "$rootro" = true ]; then
1217c478bd9Sstevel@tonic-gate	if [ "$nouser" = true -a "$rootro" = true ]; then
1227c478bd9Sstevel@tonic-gate		echo "The / filesystem is mounted read-only, and the /usr" >&2
1237c478bd9Sstevel@tonic-gate		echo "filesystem has not yet been mounted." >&2
1247c478bd9Sstevel@tonic-gate	elif [ "$nouser" = true ]; then
1257c478bd9Sstevel@tonic-gate		echo "The /usr filesystem has not yet been mounted." >&2
1267c478bd9Sstevel@tonic-gate	else
1277c478bd9Sstevel@tonic-gate		echo "The / filesystem is mounted read-only." >&2
1287c478bd9Sstevel@tonic-gate	fi
1297c478bd9Sstevel@tonic-gate
1307c478bd9Sstevel@tonic-gate	echo >&2 "
1317c478bd9Sstevel@tonic-gateThis must be rectified before $0 can continue.
1327c478bd9Sstevel@tonic-gate
1337c478bd9Sstevel@tonic-gateTo properly mount / and /usr, run:
1347c478bd9Sstevel@tonic-gate    /lib/svc/method/fs-root
1357c478bd9Sstevel@tonic-gatethen
1367c478bd9Sstevel@tonic-gate    /lib/svc/method/fs-usr
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gateAfter those have completed successfully, re-run:
1397c478bd9Sstevel@tonic-gate    $0 $*
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gateto continue.
1427c478bd9Sstevel@tonic-gate"
1437c478bd9Sstevel@tonic-gate	exit 1
1447c478bd9Sstevel@tonic-gatefi
1457c478bd9Sstevel@tonic-gate
1467c478bd9Sstevel@tonic-gate# at this point, we know / is mounted read-write, and /usr is mounted.
1477c478bd9Sstevel@tonic-gateoldreps="`
1487c478bd9Sstevel@tonic-gate	/bin/ls -1rt $repository-*-[0-9]*[0-9] | \
1497c478bd9Sstevel@tonic-gate	    /bin/sed -e '/[^A-Za-z0-9_,.-]/d' -e 's/^'$repository'-//'
1507c478bd9Sstevel@tonic-gate`"
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gateif [ -z "$oldreps" ]; then
1537c478bd9Sstevel@tonic-gate	cat >&2 <<EOF
1547c478bd9Sstevel@tonic-gateThere are no available backups of $myroot$repositorydir/$repository.db.
1557c478bd9Sstevel@tonic-gateThe only available repository is "-seed-".  Note that restoring the seed
1568918dff3Sjwadamswill lose all customizations, including those made by the system during
1578918dff3Sjwadamsthe installation and/or upgrade process.
1587c478bd9Sstevel@tonic-gate
1597c478bd9Sstevel@tonic-gateEOF
1607c478bd9Sstevel@tonic-gate	prompt="Enter -seed- to restore from the seed, or -quit- to exit: \c"
1617c478bd9Sstevel@tonic-gate	default=
1627c478bd9Sstevel@tonic-gateelse
1637c478bd9Sstevel@tonic-gate	cat >&2 <<EOF
1647c478bd9Sstevel@tonic-gateThe following backups of $myroot$repositorydir/$repository.db exist, from
1657c478bd9Sstevel@tonic-gateoldest to newest:
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate$oldreps
1687c478bd9Sstevel@tonic-gate
1697c478bd9Sstevel@tonic-gateThe backups are named based on their type and the time what they were taken.
1707c478bd9Sstevel@tonic-gateBackups beginning with "boot" are made before the first change is made to
1717c478bd9Sstevel@tonic-gatethe repository after system boot.  Backups beginning with "manifest_import"
1727c478bd9Sstevel@tonic-gateare made after svc:/system/manifest-import:default finishes its processing.
1737c478bd9Sstevel@tonic-gateThe time of backup is given in YYYYMMDD_HHMMSS format.
1747c478bd9Sstevel@tonic-gate
1758918dff3SjwadamsPlease enter either a specific backup repository from the above list to
1768918dff3Sjwadamsrestore it, or one of the following choices:
1778918dff3Sjwadams
1788918dff3Sjwadams	CHOICE		  ACTION
1798918dff3Sjwadams	----------------  ----------------------------------------------
1808918dff3Sjwadams	boot		  restore the most recent post-boot backup
1818918dff3Sjwadams	manifest_import	  restore the most recent manifest_import backup
1828918dff3Sjwadams	-seed-		  restore the initial starting repository  (All
1838918dff3Sjwadams			    customizations will be lost, including those
1848918dff3Sjwadams			    made by the install/upgrade process.)
1858918dff3Sjwadams	-quit-		  cancel script and quit
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gateEOF
1887c478bd9Sstevel@tonic-gate	prompt="Enter response [boot]: \c"
1897c478bd9Sstevel@tonic-gate	default="boot"
1907c478bd9Sstevel@tonic-gatefi
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gatecont=false
1937c478bd9Sstevel@tonic-gatewhile [ $cont = false ]; do
1947c478bd9Sstevel@tonic-gate	echo "$prompt"
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate	read x || exit 1
1977c478bd9Sstevel@tonic-gate	[ -z "$x" ] && x="$default"
1987c478bd9Sstevel@tonic-gate
1997c478bd9Sstevel@tonic-gate	case "$x" in
2007c478bd9Sstevel@tonic-gate	    -seed-)
2017c478bd9Sstevel@tonic-gate		if [ $myroot != / -o "`/sbin/zonename`" = global ]; then
2027c478bd9Sstevel@tonic-gate			file="$myroot"lib/svc/seed/global.db
2037c478bd9Sstevel@tonic-gate		else
2047c478bd9Sstevel@tonic-gate			file="$myroot"lib/svc/seed/nonglobal.db
2057c478bd9Sstevel@tonic-gate		fi;;
2067c478bd9Sstevel@tonic-gate	    -quit-)
2077c478bd9Sstevel@tonic-gate		echo "Exiting."
2087c478bd9Sstevel@tonic-gate		exit 0;;
2097c478bd9Sstevel@tonic-gate	    /*)
2107c478bd9Sstevel@tonic-gate		file="$x";;
2117c478bd9Sstevel@tonic-gate	    */*)
2127c478bd9Sstevel@tonic-gate		file="$myroot$x";;
2137c478bd9Sstevel@tonic-gate	    ?*)
2147c478bd9Sstevel@tonic-gate		file="$myroot$repositorydir/repository-$x";;
2157c478bd9Sstevel@tonic-gate	    *)	file= ;;
2167c478bd9Sstevel@tonic-gate	esac
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate	if [ -f $file ]; then
2197c478bd9Sstevel@tonic-gate		if [ -r $file ]; then
2207c478bd9Sstevel@tonic-gate			checkresults="`echo PRAGMA integrity_check\; | \
2217c478bd9Sstevel@tonic-gate			    /lib/svc/bin/sqlite $file >&1 | grep -v '^ok$'`"
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate			if [ -n "$checkresults" ]; then
2247c478bd9Sstevel@tonic-gate				echo "$file: integrity check failed:" >&2
2257c478bd9Sstevel@tonic-gate				echo "$checkresults" >&2
2267c478bd9Sstevel@tonic-gate				echo
2277c478bd9Sstevel@tonic-gate			else
2287c478bd9Sstevel@tonic-gate				cont=true
2297c478bd9Sstevel@tonic-gate			fi
2307c478bd9Sstevel@tonic-gate		else
2317c478bd9Sstevel@tonic-gate			echo "$file: not readable"
2327c478bd9Sstevel@tonic-gate		fi
2337c478bd9Sstevel@tonic-gate	elif [ -n "$file" ]; then
2347c478bd9Sstevel@tonic-gate		echo "$file: not found"
2357c478bd9Sstevel@tonic-gate	fi
2367c478bd9Sstevel@tonic-gatedone
2377c478bd9Sstevel@tonic-gate
2387c478bd9Sstevel@tonic-gateerrors="$myroot"etc/svc/volatile/db_errors
2397c478bd9Sstevel@tonic-gaterepo="$myroot$repositorydir/$repository.db"
2407c478bd9Sstevel@tonic-gatenew="$repo"_old_"`date +%Y''%m''%d'_'%H''%M''%S`"
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gatesteps=
2437c478bd9Sstevel@tonic-gateif [ "$myroot" = / ]; then
2447c478bd9Sstevel@tonic-gate	steps="$steps
245*bbf21555SRichard Lowesvc.startd(8) and svc.configd(8) will be quiesced, if running."
2467c478bd9Sstevel@tonic-gatefi
2477c478bd9Sstevel@tonic-gate
2487c478bd9Sstevel@tonic-gateif [ -r $repo ]; then
2497c478bd9Sstevel@tonic-gate	steps="$steps
2507c478bd9Sstevel@tonic-gate$repo
2517c478bd9Sstevel@tonic-gate    -- renamed --> $new"
2527c478bd9Sstevel@tonic-gatefi
2537c478bd9Sstevel@tonic-gateif [ -r $errors ]; then
2547c478bd9Sstevel@tonic-gate	steps="$steps
2557c478bd9Sstevel@tonic-gate$errors
2567c478bd9Sstevel@tonic-gate    -- copied --> ${new}_errors"
2577c478bd9Sstevel@tonic-gatefi
2587c478bd9Sstevel@tonic-gate
2597c478bd9Sstevel@tonic-gatecat >&2 <<EOF
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gateAfter confirmation, the following steps will be taken:
2627c478bd9Sstevel@tonic-gate$steps
2637c478bd9Sstevel@tonic-gate$file
2647c478bd9Sstevel@tonic-gate    -- copied --> $repo
2657c478bd9Sstevel@tonic-gateEOF
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gateif [ "$myroot" = / ]; then
268*bbf21555SRichard Lowe	echo "and the system will be rebooted with reboot(8)."
2697c478bd9Sstevel@tonic-gatefi
2707c478bd9Sstevel@tonic-gate
2717c478bd9Sstevel@tonic-gateecho
2727c478bd9Sstevel@tonic-gatecont=false
2737c478bd9Sstevel@tonic-gatewhile [ $cont = false ]; do
2747c478bd9Sstevel@tonic-gate	echo "Proceed [yes/no]? \c"
2757c478bd9Sstevel@tonic-gate	read x || x=n
2767c478bd9Sstevel@tonic-gate
2777c478bd9Sstevel@tonic-gate	case "$x" in
2787c478bd9Sstevel@tonic-gate	    [Yy]|[Yy][Ee][Ss])
2797c478bd9Sstevel@tonic-gate		cont=true;;
2807c478bd9Sstevel@tonic-gate	    [Nn]|[Nn][Oo])
2817c478bd9Sstevel@tonic-gate		echo; echo "Exiting..."
2827c478bd9Sstevel@tonic-gate		exit 0;
2837c478bd9Sstevel@tonic-gate	esac;
2847c478bd9Sstevel@tonic-gatedone
2857c478bd9Sstevel@tonic-gate
2867c478bd9Sstevel@tonic-gateumask 077		# we want files to be root-readable only.
2877c478bd9Sstevel@tonic-gate
2887c478bd9Sstevel@tonic-gatestartd_msg=
2897c478bd9Sstevel@tonic-gateif [ "$myroot" = / ]; then
2907c478bd9Sstevel@tonic-gate	zone="`zonename`"
2917c478bd9Sstevel@tonic-gate	startd="`pgrep -z "$zone" -f svc.startd`"
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate	echo
294*bbf21555SRichard Lowe	echo "Quiescing svc.startd(8) and svc.configd(8): \c"
2957c478bd9Sstevel@tonic-gate	if [ -n "$startd" ]; then
2967c478bd9Sstevel@tonic-gate		pstop $startd
2977c478bd9Sstevel@tonic-gate		startd_msg=\
298*bbf21555SRichard Lowe"To start svc.start(8) running, do: /usr/bin/prun $startd"
2997c478bd9Sstevel@tonic-gate	fi
3007c478bd9Sstevel@tonic-gate	pkill -z "$zone" -f svc.configd
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate	sleep 1			# yes, this is hack
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate	echo "done."
3057c478bd9Sstevel@tonic-gatefi
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gateif [ -r "$repo" ]; then
3087c478bd9Sstevel@tonic-gate	echo "$repo"
3097c478bd9Sstevel@tonic-gate	echo "    -- renamed --> $new"
3107c478bd9Sstevel@tonic-gate	if mv $repo $new; then
3117c478bd9Sstevel@tonic-gate		:
3127c478bd9Sstevel@tonic-gate	else
3137c478bd9Sstevel@tonic-gate		echo "Failed.  $startd_msg"
3147c478bd9Sstevel@tonic-gate		exit 1;
3157c478bd9Sstevel@tonic-gate	fi
3167c478bd9Sstevel@tonic-gatefi
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gateif [ -r $errors ]; then
3197c478bd9Sstevel@tonic-gate	echo "$errors"
3207c478bd9Sstevel@tonic-gate	echo "    -- copied --> ${new}_errors"
3217c478bd9Sstevel@tonic-gate	if cp -p $errors ${new}_errors; then
3227c478bd9Sstevel@tonic-gate		:
3237c478bd9Sstevel@tonic-gate	else
3247c478bd9Sstevel@tonic-gate		mv -f $new $repo
3257c478bd9Sstevel@tonic-gate		echo "Failed.  $startd_msg"
3267c478bd9Sstevel@tonic-gate		exit 1;
3277c478bd9Sstevel@tonic-gate	fi
3287c478bd9Sstevel@tonic-gatefi
3297c478bd9Sstevel@tonic-gate
3307c478bd9Sstevel@tonic-gateecho "$file"
3317c478bd9Sstevel@tonic-gateecho "    -- copied --> $repo"
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gateif cp $file $repo.new.$$ && mv $repo.new.$$ $repo; then
3347c478bd9Sstevel@tonic-gate	:
3357c478bd9Sstevel@tonic-gateelse
3367c478bd9Sstevel@tonic-gate	rm -f $repo.new.$$ ${new}_errors
3377c478bd9Sstevel@tonic-gate	mv -f $new $repo
3387c478bd9Sstevel@tonic-gate	echo "Failed.  $startd_msg"
3397c478bd9Sstevel@tonic-gate	exit 1;
3407c478bd9Sstevel@tonic-gatefi
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gateecho
3437c478bd9Sstevel@tonic-gateecho "The backup repository has been successfully restored."
3447c478bd9Sstevel@tonic-gateecho
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gateif [ "$myroot" = / ]; then
3477c478bd9Sstevel@tonic-gate	echo "Rebooting in 5 seconds."
3487c478bd9Sstevel@tonic-gate	sleep 5
3497c478bd9Sstevel@tonic-gate	reboot
3507c478bd9Sstevel@tonic-gatefi
351