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