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