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