Home | History | Annotate | Download | only in configd
      1 #!/sbin/sh
      2 #
      3 # CDDL HEADER START
      4 #
      5 # The contents of this file are subject to the terms of the
      6 # Common Development and Distribution License, Version 1.0 only
      7 # (the "License").  You may not use this file except in compliance
      8 # with the License.
      9 #
     10 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     11 # or http://www.opensolaris.org/os/licensing.
     12 # See the License for the specific language governing permissions
     13 # and limitations under the License.
     14 #
     15 # When distributing Covered Code, include this CDDL HEADER in each
     16 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     17 # If applicable, add the following below this CDDL HEADER, with the
     18 # fields enclosed by brackets "[]" replaced with your own identifying
     19 # information: Portions Copyright [yyyy] [name of copyright owner]
     20 #
     21 # CDDL HEADER END
     22 #
     23 #
     24 # Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     25 # Use is subject to license terms.
     26 #
     27 #ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 PATH=/sbin:/usr/bin:/usr/sbin
     30 LC_ALL=C
     31 export PATH LC_ALL
     32 
     33 . /lib/svc/share/smf_include.sh
     34 . /lib/svc/share/fs_include.sh
     35 
     36 usage()
     37 {
     38 	echo "usage: $0 [-r rootdir]" >&2
     39 	echo "
     40 See http://sun.com/msg/SMF-8000-MY for more information on the use of
     41 this script."
     42 	exit 2;
     43 }
     44 
     45 repositorydir=etc/svc
     46 repository=repository
     47 
     48 myroot=/
     49 while getopts r: opt; do
     50 	case "$opt" in
     51 	    r)	myroot=$OPTARG
     52 		if [ ! -d $myroot ]; then
     53 			echo "$myroot: not a directory" >&2
     54 			exit 1
     55 		fi
     56 		# validate directory and make sure it ends in '/'.
     57 		case "$myroot" in
     58 		    //*) echo "$myroot: must begin with a single /" >&2
     59 			usage;;
     60 		    /)	echo "$myroot: alternate root cannot be /" >&2
     61 			usage;;
     62 
     63 		    /*/) ;;			# ends with /
     64 		    /*) myroot="$myroot/";;	# add final /
     65 
     66 		    *)	echo "$myroot: must be a full path" >&2
     67 			usage;;
     68 		esac;;
     69 	    ?)	usage;;
     70 	esac
     71 done
     72 
     73 if [ $OPTIND -le $# ]; then
     74 	# getopts(1) didn't slurp up everything.
     75 	usage
     76 fi
     77 
     78 #
     79 # Note that the below test is carefully constructed to fail *open*;  if
     80 # anything goes wrong, it will drive onward.
     81 #
     82 if [ -x /usr/bin/id -a -x /usr/bin/grep ] &&
     83     /usr/bin/id 2>/dev/null | /usr/bin/grep -v '^[^=]*=0(' >/dev/null 2>&1; then
     84 	echo "$0: may only be invoked by root" >&2
     85 	exit 2
     86 fi
     87 
     88 echo >&2 "
     89 See http://sun.com/msg/SMF-8000-MY for more information on the use of
     90 this script to restore backup copies of the smf(5) repository.
     91 
     92 If there are any problems which need human intervention, this script will
     93 give instructions and then exit back to your shell."
     94 
     95 if [ "$myroot" -eq / ]; then
     96 	system="system"
     97 	[ "`/sbin/zonename`" != global ] && system="zone"
     98 	echo >&2 "
     99 Note that upon full completion of this script, the $system will be rebooted
    100 using reboot(1M), which will interrupt any active services.
    101 "
    102 fi
    103 
    104 # check that the filesystem is as expected
    105 cd "$myroot" || exit 1
    106 cd "$myroot$repositorydir" || exit 1
    107 
    108 nouser=false
    109 rootro=false
    110 
    111 # check to make sure /usr is mounted
    112 if [ ! -x /usr/bin/pgrep ]; then
    113 	nouser=true
    114 fi
    115 
    116 if [ ! -w "$myroot" ]; then
    117 	rootro=true
    118 fi
    119 
    120 if [ "$nouser" = true -o "$rootro" = true ]; then
    121 	if [ "$nouser" = true -a "$rootro" = true ]; then
    122 		echo "The / filesystem is mounted read-only, and the /usr" >&2
    123 		echo "filesystem has not yet been mounted." >&2
    124 	elif [ "$nouser" = true ]; then
    125 		echo "The /usr filesystem has not yet been mounted." >&2
    126 	else
    127 		echo "The / filesystem is mounted read-only." >&2
    128 	fi
    129 
    130 	echo >&2 "
    131 This must be rectified before $0 can continue.
    132 
    133 If / or /usr are on SVM (md(7d)) partitions, first run
    134     /lib/svc/method/svc-metainit
    135 
    136 To properly mount / and /usr, run:
    137     /lib/svc/method/fs-root
    138 then
    139     /lib/svc/method/fs-usr
    140 
    141 After those have completed successfully, re-run:
    142     $0 $*
    143 
    144 to continue.
    145 "
    146 	exit 1
    147 fi
    148 
    149 # at this point, we know / is mounted read-write, and /usr is mounted.
    150 oldreps="`
    151 	/bin/ls -1rt $repository-*-[0-9]*[0-9] | \
    152 	    /bin/sed -e '/[^A-Za-z0-9_,.-]/d' -e 's/^'$repository'-//'
    153 `"
    154 
    155 if [ -z "$oldreps" ]; then
    156 	cat >&2 <<EOF
    157 There are no available backups of $myroot$repositorydir/$repository.db.
    158 The only available repository is "-seed-".  Note that restoring the seed
    159 will lose all customizations, including those made by the system during
    160 the installation and/or upgrade process.
    161 
    162 EOF
    163 	prompt="Enter -seed- to restore from the seed, or -quit- to exit: \c"
    164 	default=
    165 else
    166 	cat >&2 <<EOF
    167 The following backups of $myroot$repositorydir/$repository.db exist, from
    168 oldest to newest:
    169 
    170 $oldreps
    171 
    172 The backups are named based on their type and the time what they were taken.
    173 Backups beginning with "boot" are made before the first change is made to
    174 the repository after system boot.  Backups beginning with "manifest_import"
    175 are made after svc:/system/manifest-import:default finishes its processing.
    176 The time of backup is given in YYYYMMDD_HHMMSS format.
    177 
    178 Please enter either a specific backup repository from the above list to
    179 restore it, or one of the following choices:
    180 
    181 	CHOICE		  ACTION
    182 	----------------  ----------------------------------------------
    183 	boot		  restore the most recent post-boot backup
    184 	manifest_import	  restore the most recent manifest_import backup
    185 	-seed-		  restore the initial starting repository  (All
    186 			    customizations will be lost, including those
    187 			    made by the install/upgrade process.)
    188 	-quit-		  cancel script and quit
    189 
    190 EOF
    191 	prompt="Enter response [boot]: \c"
    192 	default="boot"
    193 fi
    194 
    195 cont=false
    196 while [ $cont = false ]; do
    197 	echo "$prompt"
    198 
    199 	read x || exit 1
    200 	[ -z "$x" ] && x="$default"
    201 
    202 	case "$x" in
    203 	    -seed-)
    204 		if [ $myroot != / -o "`/sbin/zonename`" = global ]; then
    205 			file="$myroot"lib/svc/seed/global.db
    206 		else
    207 			file="$myroot"lib/svc/seed/nonglobal.db
    208 		fi;;
    209 	    -quit-)
    210 		echo "Exiting."
    211 		exit 0;;
    212 	    /*)
    213 		file="$x";;
    214 	    */*)
    215 		file="$myroot$x";;
    216 	    ?*)
    217 		file="$myroot$repositorydir/repository-$x";;
    218 	    *)	file= ;;
    219 	esac
    220 
    221 	if [ -f $file ]; then
    222 		if [ -r $file ]; then
    223 			checkresults="`echo PRAGMA integrity_check\; | \
    224 			    /lib/svc/bin/sqlite $file >&1 | grep -v '^ok$'`"
    225 
    226 			if [ -n "$checkresults" ]; then
    227 				echo "$file: integrity check failed:" >&2
    228 				echo "$checkresults" >&2
    229 				echo
    230 			else
    231 				cont=true
    232 			fi
    233 		else
    234 			echo "$file: not readable"
    235 		fi
    236 	elif [ -n "$file" ]; then
    237 		echo "$file: not found"
    238 	fi
    239 done
    240 
    241 errors="$myroot"etc/svc/volatile/db_errors
    242 repo="$myroot$repositorydir/$repository.db"
    243 new="$repo"_old_"`date +%Y''%m''%d'_'%H''%M''%S`"
    244 
    245 steps=
    246 if [ "$myroot" = / ]; then
    247 	steps="$steps
    248 svc.startd(1M) and svc.configd(1M) will be quiesced, if running."
    249 fi
    250 
    251 if [ -r $repo ]; then
    252 	steps="$steps
    253 $repo
    254     -- renamed --> $new"
    255 fi
    256 if [ -r $errors ]; then
    257 	steps="$steps
    258 $errors
    259     -- copied --> ${new}_errors"
    260 fi
    261 
    262 cat >&2 <<EOF
    263 
    264 After confirmation, the following steps will be taken:
    265 $steps
    266 $file
    267     -- copied --> $repo
    268 EOF
    269 
    270 if [ "$myroot" = / ]; then
    271 	echo "and the system will be rebooted with reboot(1M)."
    272 fi
    273 
    274 echo
    275 cont=false
    276 while [ $cont = false ]; do
    277 	echo "Proceed [yes/no]? \c"
    278 	read x || x=n
    279 
    280 	case "$x" in
    281 	    [Yy]|[Yy][Ee][Ss])
    282 		cont=true;;
    283 	    [Nn]|[Nn][Oo])
    284 		echo; echo "Exiting..."
    285 		exit 0;
    286 	esac;
    287 done
    288 
    289 umask 077		# we want files to be root-readable only.
    290 
    291 startd_msg=
    292 if [ "$myroot" = / ]; then
    293 	zone="`zonename`"
    294 	startd="`pgrep -z "$zone" -f svc.startd`"
    295 
    296 	echo
    297 	echo "Quiescing svc.startd(1M) and svc.configd(1M): \c"
    298 	if [ -n "$startd" ]; then
    299 		pstop $startd
    300 		startd_msg=\
    301 "To start svc.start(1M) running, do: /usr/bin/prun $startd"
    302 	fi
    303 	pkill -z "$zone" -f svc.configd
    304 
    305 	sleep 1			# yes, this is hack
    306 
    307 	echo "done."
    308 fi
    309 
    310 if [ -r "$repo" ]; then
    311 	echo "$repo"
    312 	echo "    -- renamed --> $new"
    313 	if mv $repo $new; then
    314 		:
    315 	else
    316 		echo "Failed.  $startd_msg"
    317 		exit 1;
    318 	fi
    319 fi
    320 
    321 if [ -r $errors ]; then
    322 	echo "$errors"
    323 	echo "    -- copied --> ${new}_errors"
    324 	if cp -p $errors ${new}_errors; then
    325 		:
    326 	else
    327 		mv -f $new $repo
    328 		echo "Failed.  $startd_msg"
    329 		exit 1;
    330 	fi
    331 fi
    332 
    333 echo "$file"
    334 echo "    -- copied --> $repo"
    335 
    336 if cp $file $repo.new.$$ && mv $repo.new.$$ $repo; then
    337 	:
    338 else
    339 	rm -f $repo.new.$$ ${new}_errors
    340 	mv -f $new $repo
    341 	echo "Failed.  $startd_msg"
    342 	exit 1;
    343 fi
    344 
    345 echo
    346 echo "The backup repository has been successfully restored."
    347 echo
    348 
    349 if [ "$myroot" = / ]; then
    350 	echo "Rebooting in 5 seconds."
    351 	sleep 5
    352 	reboot
    353 fi
    354