10Sstevel@tonic-gate#!/sbin/sh 20Sstevel@tonic-gate# 30Sstevel@tonic-gate# CDDL HEADER START 40Sstevel@tonic-gate# 50Sstevel@tonic-gate# The contents of this file are subject to the terms of the 60Sstevel@tonic-gate# Common Development and Distribution License, Version 1.0 only 70Sstevel@tonic-gate# (the "License"). You may not use this file except in compliance 80Sstevel@tonic-gate# with the License. 90Sstevel@tonic-gate# 100Sstevel@tonic-gate# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 110Sstevel@tonic-gate# or http://www.opensolaris.org/os/licensing. 120Sstevel@tonic-gate# See the License for the specific language governing permissions 130Sstevel@tonic-gate# and limitations under the License. 140Sstevel@tonic-gate# 150Sstevel@tonic-gate# When distributing Covered Code, include this CDDL HEADER in each 160Sstevel@tonic-gate# file and include the License file at usr/src/OPENSOLARIS.LICENSE. 170Sstevel@tonic-gate# If applicable, add the following below this CDDL HEADER, with the 180Sstevel@tonic-gate# fields enclosed by brackets "[]" replaced with your own identifying 190Sstevel@tonic-gate# information: Portions Copyright [yyyy] [name of copyright owner] 200Sstevel@tonic-gate# 210Sstevel@tonic-gate# CDDL HEADER END 220Sstevel@tonic-gate# 230Sstevel@tonic-gate# 24*407Sjwadams# Copyright 2005 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate# Use is subject to license terms. 260Sstevel@tonic-gate# 270Sstevel@tonic-gate#ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gatePATH=/sbin:/usr/bin:/usr/sbin 30*407SjwadamsLC_ALL=C 31*407Sjwadamsexport PATH LC_ALL 320Sstevel@tonic-gate 330Sstevel@tonic-gate. /lib/svc/share/smf_include.sh 340Sstevel@tonic-gate. /lib/svc/share/fs_include.sh 350Sstevel@tonic-gate 360Sstevel@tonic-gateusage() 370Sstevel@tonic-gate{ 380Sstevel@tonic-gate echo "usage: $0 [-r rootdir]" >&2 39*407Sjwadams echo " 40*407SjwadamsSee http://sun.com/msg/SMF-8000-MY for more information on the use of 41*407Sjwadamsthis script." 420Sstevel@tonic-gate exit 2; 430Sstevel@tonic-gate} 440Sstevel@tonic-gate 450Sstevel@tonic-gaterepositorydir=etc/svc 460Sstevel@tonic-gaterepository=repository 470Sstevel@tonic-gate 480Sstevel@tonic-gatemyroot=/ 490Sstevel@tonic-gatewhile getopts r: opt; do 500Sstevel@tonic-gate case "$opt" in 510Sstevel@tonic-gate r) myroot=$OPTARG 520Sstevel@tonic-gate if [ ! -d $myroot ]; then 530Sstevel@tonic-gate echo "$myroot: not a directory" >&2 540Sstevel@tonic-gate exit 1 550Sstevel@tonic-gate fi 560Sstevel@tonic-gate # validate directory and make sure it ends in '/'. 570Sstevel@tonic-gate case "$myroot" in 580Sstevel@tonic-gate //*) echo "$myroot: must begin with a single /" >&2 590Sstevel@tonic-gate usage;; 600Sstevel@tonic-gate /) echo "$myroot: alternate root cannot be /" >&2 610Sstevel@tonic-gate usage;; 620Sstevel@tonic-gate 630Sstevel@tonic-gate /*/) ;; # ends with / 640Sstevel@tonic-gate /*) myroot="$myroot/";; # add final / 650Sstevel@tonic-gate 660Sstevel@tonic-gate *) echo "$myroot: must be a full path" >&2 670Sstevel@tonic-gate usage;; 680Sstevel@tonic-gate esac;; 690Sstevel@tonic-gate ?) usage;; 700Sstevel@tonic-gate esac 710Sstevel@tonic-gatedone 720Sstevel@tonic-gate 730Sstevel@tonic-gateif [ $OPTIND -le $# ]; then 740Sstevel@tonic-gate # getopts(1) didn't slurp up everything. 750Sstevel@tonic-gate usage 760Sstevel@tonic-gatefi 770Sstevel@tonic-gate 78*407Sjwadams# 79*407Sjwadams# Note that the below test is carefully constructed to fail *open*; if 80*407Sjwadams# anything goes wrong, it will drive onward. 81*407Sjwadams# 82*407Sjwadamsif [ -x /usr/bin/id -a -x /usr/bin/grep ] && 83*407Sjwadams /usr/bin/id 2>/dev/null | /usr/bin/grep -v '^[^=]*=0(' >/dev/null 2>&1; then 84*407Sjwadams echo "$0: may only be invoked by root" >&2 85*407Sjwadams exit 2 86*407Sjwadamsfi 87*407Sjwadams 88*407Sjwadamsecho >&2 " 89*407SjwadamsSee http://sun.com/msg/SMF-8000-MY for more information on the use of 90*407Sjwadamsthis script to restore backup copies of the smf(5) repository. 91*407Sjwadams 92*407SjwadamsIf there are any problems which need human intervention, this script will 93*407Sjwadamsgive instructions and then exit back to your shell." 94*407Sjwadams 950Sstevel@tonic-gateif [ "$myroot" -eq / ]; then 960Sstevel@tonic-gate system="system" 970Sstevel@tonic-gate [ "`/sbin/zonename`" != global ] && system="zone" 980Sstevel@tonic-gate echo >&2 " 990Sstevel@tonic-gateNote that upon full completion of this script, the $system will be rebooted 1000Sstevel@tonic-gateusing reboot(1M), which will interrupt any active services. 1010Sstevel@tonic-gate" 1020Sstevel@tonic-gatefi 1030Sstevel@tonic-gate 1040Sstevel@tonic-gate# check that the filesystem is as expected 1050Sstevel@tonic-gatecd "$myroot" || exit 1 1060Sstevel@tonic-gatecd "$myroot$repositorydir" || exit 1 1070Sstevel@tonic-gate 1080Sstevel@tonic-gatenouser=false 1090Sstevel@tonic-gaterootro=false 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate# check to make sure /usr is mounted 1120Sstevel@tonic-gateif [ ! -x /usr/bin/pgrep ]; then 1130Sstevel@tonic-gate nouser=true 1140Sstevel@tonic-gatefi 115*407Sjwadams 1160Sstevel@tonic-gateif [ ! -w "$myroot" ]; then 1170Sstevel@tonic-gate rootro=true 1180Sstevel@tonic-gatefi 1190Sstevel@tonic-gate 1200Sstevel@tonic-gateif [ "$nouser" = true -o "$rootro" = true ]; then 1210Sstevel@tonic-gate if [ "$nouser" = true -a "$rootro" = true ]; then 1220Sstevel@tonic-gate echo "The / filesystem is mounted read-only, and the /usr" >&2 1230Sstevel@tonic-gate echo "filesystem has not yet been mounted." >&2 1240Sstevel@tonic-gate elif [ "$nouser" = true ]; then 1250Sstevel@tonic-gate echo "The /usr filesystem has not yet been mounted." >&2 1260Sstevel@tonic-gate else 1270Sstevel@tonic-gate echo "The / filesystem is mounted read-only." >&2 1280Sstevel@tonic-gate fi 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate echo >&2 " 1310Sstevel@tonic-gateThis must be rectified before $0 can continue. 1320Sstevel@tonic-gate 1330Sstevel@tonic-gateIf / or /usr are on SVM (md(7d)) partitions, first run 1340Sstevel@tonic-gate /lib/svc/method/svc-metainit 1350Sstevel@tonic-gate 1360Sstevel@tonic-gateTo properly mount / and /usr, run: 1370Sstevel@tonic-gate /lib/svc/method/fs-root 1380Sstevel@tonic-gatethen 1390Sstevel@tonic-gate /lib/svc/method/fs-usr 1400Sstevel@tonic-gate 1410Sstevel@tonic-gateAfter those have completed successfully, re-run: 1420Sstevel@tonic-gate $0 $* 1430Sstevel@tonic-gate 1440Sstevel@tonic-gateto continue. 1450Sstevel@tonic-gate" 1460Sstevel@tonic-gate exit 1 1470Sstevel@tonic-gatefi 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate# at this point, we know / is mounted read-write, and /usr is mounted. 1500Sstevel@tonic-gateoldreps="` 1510Sstevel@tonic-gate /bin/ls -1rt $repository-*-[0-9]*[0-9] | \ 1520Sstevel@tonic-gate /bin/sed -e '/[^A-Za-z0-9_,.-]/d' -e 's/^'$repository'-//' 1530Sstevel@tonic-gate`" 1540Sstevel@tonic-gate 1550Sstevel@tonic-gateif [ -z "$oldreps" ]; then 1560Sstevel@tonic-gate cat >&2 <<EOF 1570Sstevel@tonic-gateThere are no available backups of $myroot$repositorydir/$repository.db. 1580Sstevel@tonic-gateThe only available repository is "-seed-". Note that restoring the seed 159*407Sjwadamswill lose all customizations, including those made by the system during 160*407Sjwadamsthe installation and/or upgrade process. 1610Sstevel@tonic-gate 1620Sstevel@tonic-gateEOF 1630Sstevel@tonic-gate prompt="Enter -seed- to restore from the seed, or -quit- to exit: \c" 1640Sstevel@tonic-gate default= 1650Sstevel@tonic-gateelse 1660Sstevel@tonic-gate cat >&2 <<EOF 1670Sstevel@tonic-gateThe following backups of $myroot$repositorydir/$repository.db exist, from 1680Sstevel@tonic-gateoldest to newest: 1690Sstevel@tonic-gate 1700Sstevel@tonic-gate$oldreps 1710Sstevel@tonic-gate 1720Sstevel@tonic-gateThe backups are named based on their type and the time what they were taken. 1730Sstevel@tonic-gateBackups beginning with "boot" are made before the first change is made to 1740Sstevel@tonic-gatethe repository after system boot. Backups beginning with "manifest_import" 1750Sstevel@tonic-gateare made after svc:/system/manifest-import:default finishes its processing. 1760Sstevel@tonic-gateThe time of backup is given in YYYYMMDD_HHMMSS format. 1770Sstevel@tonic-gate 178*407SjwadamsPlease enter either a specific backup repository from the above list to 179*407Sjwadamsrestore it, or one of the following choices: 180*407Sjwadams 181*407Sjwadams CHOICE ACTION 182*407Sjwadams ---------------- ---------------------------------------------- 183*407Sjwadams boot restore the most recent post-boot backup 184*407Sjwadams manifest_import restore the most recent manifest_import backup 185*407Sjwadams -seed- restore the initial starting repository (All 186*407Sjwadams customizations will be lost, including those 187*407Sjwadams made by the install/upgrade process.) 188*407Sjwadams -quit- cancel script and quit 1890Sstevel@tonic-gate 1900Sstevel@tonic-gateEOF 1910Sstevel@tonic-gate prompt="Enter response [boot]: \c" 1920Sstevel@tonic-gate default="boot" 1930Sstevel@tonic-gatefi 1940Sstevel@tonic-gate 1950Sstevel@tonic-gatecont=false 1960Sstevel@tonic-gatewhile [ $cont = false ]; do 1970Sstevel@tonic-gate echo "$prompt" 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate read x || exit 1 2000Sstevel@tonic-gate [ -z "$x" ] && x="$default" 2010Sstevel@tonic-gate 2020Sstevel@tonic-gate case "$x" in 2030Sstevel@tonic-gate -seed-) 2040Sstevel@tonic-gate if [ $myroot != / -o "`/sbin/zonename`" = global ]; then 2050Sstevel@tonic-gate file="$myroot"lib/svc/seed/global.db 2060Sstevel@tonic-gate else 2070Sstevel@tonic-gate file="$myroot"lib/svc/seed/nonglobal.db 2080Sstevel@tonic-gate fi;; 2090Sstevel@tonic-gate -quit-) 2100Sstevel@tonic-gate echo "Exiting." 2110Sstevel@tonic-gate exit 0;; 2120Sstevel@tonic-gate /*) 2130Sstevel@tonic-gate file="$x";; 2140Sstevel@tonic-gate */*) 2150Sstevel@tonic-gate file="$myroot$x";; 2160Sstevel@tonic-gate ?*) 2170Sstevel@tonic-gate file="$myroot$repositorydir/repository-$x";; 2180Sstevel@tonic-gate *) file= ;; 2190Sstevel@tonic-gate esac 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate if [ -f $file ]; then 2220Sstevel@tonic-gate if [ -r $file ]; then 2230Sstevel@tonic-gate checkresults="`echo PRAGMA integrity_check\; | \ 2240Sstevel@tonic-gate /lib/svc/bin/sqlite $file >&1 | grep -v '^ok$'`" 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if [ -n "$checkresults" ]; then 2270Sstevel@tonic-gate echo "$file: integrity check failed:" >&2 2280Sstevel@tonic-gate echo "$checkresults" >&2 2290Sstevel@tonic-gate echo 2300Sstevel@tonic-gate else 2310Sstevel@tonic-gate cont=true 2320Sstevel@tonic-gate fi 2330Sstevel@tonic-gate else 2340Sstevel@tonic-gate echo "$file: not readable" 2350Sstevel@tonic-gate fi 2360Sstevel@tonic-gate elif [ -n "$file" ]; then 2370Sstevel@tonic-gate echo "$file: not found" 2380Sstevel@tonic-gate fi 2390Sstevel@tonic-gatedone 2400Sstevel@tonic-gate 2410Sstevel@tonic-gateerrors="$myroot"etc/svc/volatile/db_errors 2420Sstevel@tonic-gaterepo="$myroot$repositorydir/$repository.db" 2430Sstevel@tonic-gatenew="$repo"_old_"`date +%Y''%m''%d'_'%H''%M''%S`" 2440Sstevel@tonic-gate 2450Sstevel@tonic-gatesteps= 2460Sstevel@tonic-gateif [ "$myroot" = / ]; then 2470Sstevel@tonic-gate steps="$steps 2480Sstevel@tonic-gatesvc.startd(1M) and svc.configd(1M) will be quiesced, if running." 2490Sstevel@tonic-gatefi 2500Sstevel@tonic-gate 2510Sstevel@tonic-gateif [ -r $repo ]; then 2520Sstevel@tonic-gate steps="$steps 2530Sstevel@tonic-gate$repo 2540Sstevel@tonic-gate -- renamed --> $new" 2550Sstevel@tonic-gatefi 2560Sstevel@tonic-gateif [ -r $errors ]; then 2570Sstevel@tonic-gate steps="$steps 2580Sstevel@tonic-gate$errors 2590Sstevel@tonic-gate -- copied --> ${new}_errors" 2600Sstevel@tonic-gatefi 2610Sstevel@tonic-gate 2620Sstevel@tonic-gatecat >&2 <<EOF 2630Sstevel@tonic-gate 2640Sstevel@tonic-gateAfter confirmation, the following steps will be taken: 2650Sstevel@tonic-gate$steps 2660Sstevel@tonic-gate$file 2670Sstevel@tonic-gate -- copied --> $repo 2680Sstevel@tonic-gateEOF 2690Sstevel@tonic-gate 2700Sstevel@tonic-gateif [ "$myroot" = / ]; then 2710Sstevel@tonic-gate echo "and the system will be rebooted with reboot(1M)." 2720Sstevel@tonic-gatefi 2730Sstevel@tonic-gate 2740Sstevel@tonic-gateecho 2750Sstevel@tonic-gatecont=false 2760Sstevel@tonic-gatewhile [ $cont = false ]; do 2770Sstevel@tonic-gate echo "Proceed [yes/no]? \c" 2780Sstevel@tonic-gate read x || x=n 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate case "$x" in 2810Sstevel@tonic-gate [Yy]|[Yy][Ee][Ss]) 2820Sstevel@tonic-gate cont=true;; 2830Sstevel@tonic-gate [Nn]|[Nn][Oo]) 2840Sstevel@tonic-gate echo; echo "Exiting..." 2850Sstevel@tonic-gate exit 0; 2860Sstevel@tonic-gate esac; 2870Sstevel@tonic-gatedone 2880Sstevel@tonic-gate 2890Sstevel@tonic-gateumask 077 # we want files to be root-readable only. 2900Sstevel@tonic-gate 2910Sstevel@tonic-gatestartd_msg= 2920Sstevel@tonic-gateif [ "$myroot" = / ]; then 2930Sstevel@tonic-gate zone="`zonename`" 2940Sstevel@tonic-gate startd="`pgrep -z "$zone" -f svc.startd`" 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate echo 2970Sstevel@tonic-gate echo "Quiescing svc.startd(1M) and svc.configd(1M): \c" 2980Sstevel@tonic-gate if [ -n "$startd" ]; then 2990Sstevel@tonic-gate pstop $startd 3000Sstevel@tonic-gate startd_msg=\ 3010Sstevel@tonic-gate"To start svc.start(1M) running, do: /usr/bin/prun $startd" 3020Sstevel@tonic-gate fi 3030Sstevel@tonic-gate pkill -z "$zone" -f svc.configd 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate sleep 1 # yes, this is hack 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate echo "done." 3080Sstevel@tonic-gatefi 3090Sstevel@tonic-gate 3100Sstevel@tonic-gateif [ -r "$repo" ]; then 3110Sstevel@tonic-gate echo "$repo" 3120Sstevel@tonic-gate echo " -- renamed --> $new" 3130Sstevel@tonic-gate if mv $repo $new; then 3140Sstevel@tonic-gate : 3150Sstevel@tonic-gate else 3160Sstevel@tonic-gate echo "Failed. $startd_msg" 3170Sstevel@tonic-gate exit 1; 3180Sstevel@tonic-gate fi 3190Sstevel@tonic-gatefi 3200Sstevel@tonic-gate 3210Sstevel@tonic-gateif [ -r $errors ]; then 3220Sstevel@tonic-gate echo "$errors" 3230Sstevel@tonic-gate echo " -- copied --> ${new}_errors" 3240Sstevel@tonic-gate if cp -p $errors ${new}_errors; then 3250Sstevel@tonic-gate : 3260Sstevel@tonic-gate else 3270Sstevel@tonic-gate mv -f $new $repo 3280Sstevel@tonic-gate echo "Failed. $startd_msg" 3290Sstevel@tonic-gate exit 1; 3300Sstevel@tonic-gate fi 3310Sstevel@tonic-gatefi 3320Sstevel@tonic-gate 3330Sstevel@tonic-gateecho "$file" 3340Sstevel@tonic-gateecho " -- copied --> $repo" 3350Sstevel@tonic-gate 3360Sstevel@tonic-gateif cp $file $repo.new.$$ && mv $repo.new.$$ $repo; then 3370Sstevel@tonic-gate : 3380Sstevel@tonic-gateelse 3390Sstevel@tonic-gate rm -f $repo.new.$$ ${new}_errors 3400Sstevel@tonic-gate mv -f $new $repo 3410Sstevel@tonic-gate echo "Failed. $startd_msg" 3420Sstevel@tonic-gate exit 1; 3430Sstevel@tonic-gatefi 3440Sstevel@tonic-gate 3450Sstevel@tonic-gateecho 3460Sstevel@tonic-gateecho "The backup repository has been successfully restored." 3470Sstevel@tonic-gateecho 3480Sstevel@tonic-gate 3490Sstevel@tonic-gateif [ "$myroot" = / ]; then 3500Sstevel@tonic-gate echo "Rebooting in 5 seconds." 3510Sstevel@tonic-gate sleep 5 3520Sstevel@tonic-gate reboot 3530Sstevel@tonic-gatefi 354