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 133If / or /usr are on SVM (md(7d)) partitions, first run 134 /lib/svc/method/svc-metainit 135 136To properly mount / and /usr, run: 137 /lib/svc/method/fs-root 138then 139 /lib/svc/method/fs-usr 140 141After those have completed successfully, re-run: 142 $0 $* 143 144to continue. 145" 146 exit 1 147fi 148 149# at this point, we know / is mounted read-write, and /usr is mounted. 150oldreps="` 151 /bin/ls -1rt $repository-*-[0-9]*[0-9] | \ 152 /bin/sed -e '/[^A-Za-z0-9_,.-]/d' -e 's/^'$repository'-//' 153`" 154 155if [ -z "$oldreps" ]; then 156 cat >&2 <<EOF 157There are no available backups of $myroot$repositorydir/$repository.db. 158The only available repository is "-seed-". Note that restoring the seed 159will lose all customizations, including those made by the system during 160the installation and/or upgrade process. 161 162EOF 163 prompt="Enter -seed- to restore from the seed, or -quit- to exit: \c" 164 default= 165else 166 cat >&2 <<EOF 167The following backups of $myroot$repositorydir/$repository.db exist, from 168oldest to newest: 169 170$oldreps 171 172The backups are named based on their type and the time what they were taken. 173Backups beginning with "boot" are made before the first change is made to 174the repository after system boot. Backups beginning with "manifest_import" 175are made after svc:/system/manifest-import:default finishes its processing. 176The time of backup is given in YYYYMMDD_HHMMSS format. 177 178Please enter either a specific backup repository from the above list to 179restore 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 190EOF 191 prompt="Enter response [boot]: \c" 192 default="boot" 193fi 194 195cont=false 196while [ $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 239done 240 241errors="$myroot"etc/svc/volatile/db_errors 242repo="$myroot$repositorydir/$repository.db" 243new="$repo"_old_"`date +%Y''%m''%d'_'%H''%M''%S`" 244 245steps= 246if [ "$myroot" = / ]; then 247 steps="$steps 248svc.startd(1M) and svc.configd(1M) will be quiesced, if running." 249fi 250 251if [ -r $repo ]; then 252 steps="$steps 253$repo 254 -- renamed --> $new" 255fi 256if [ -r $errors ]; then 257 steps="$steps 258$errors 259 -- copied --> ${new}_errors" 260fi 261 262cat >&2 <<EOF 263 264After confirmation, the following steps will be taken: 265$steps 266$file 267 -- copied --> $repo 268EOF 269 270if [ "$myroot" = / ]; then 271 echo "and the system will be rebooted with reboot(1M)." 272fi 273 274echo 275cont=false 276while [ $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; 287done 288 289umask 077 # we want files to be root-readable only. 290 291startd_msg= 292if [ "$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." 308fi 309 310if [ -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 319fi 320 321if [ -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 331fi 332 333echo "$file" 334echo " -- copied --> $repo" 335 336if cp $file $repo.new.$$ && mv $repo.new.$$ $repo; then 337 : 338else 339 rm -f $repo.new.$$ ${new}_errors 340 mv -f $new $repo 341 echo "Failed. $startd_msg" 342 exit 1; 343fi 344 345echo 346echo "The backup repository has been successfully restored." 347echo 348 349if [ "$myroot" = / ]; then 350 echo "Rebooting in 5 seconds." 351 sleep 5 352 reboot 353fi 354