xref: /illumos-gate/usr/src/cmd/svc/shell/fs_include.sh (revision e7cbe64f)
1#!/bin/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 (the "License").
7# You may not use this file except in compliance with the License.
8#
9# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10# or http://www.opensolaris.org/os/licensing.
11# See the License for the specific language governing permissions
12# and limitations under the License.
13#
14# When distributing Covered Code, include this CDDL HEADER in each
15# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16# If applicable, add the following below this CDDL HEADER, with the
17# fields enclosed by brackets "[]" replaced with your own identifying
18# information: Portions Copyright [yyyy] [name of copyright owner]
19#
20# CDDL HEADER END
21#
22#
23# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24# Use is subject to license terms.
25#
26# Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T.
27# All rights reserved.
28#
29#
30#ident	"%Z%%M%	%I%	%E% SMI"
31
32vfstab=${vfstab:=/etc/vfstab}
33
34#
35# readvfstab mount_point
36#   -> (special, fsckdev, mountp, fstype, fsckpass, automnt, mntopts)
37#
38#   A vfstab-like input stream is scanned for the mount point specified
39#   as $1.  Returns the fields of vfstab in the following shell
40#   variables:
41#
42#       special		block device
43#       fsckdev		raw device
44#       mountp		mount point (must match $1, if found)
45#       fstype		file system type
46#       fsckpass	fsck(1M) pass number
47#       automnt		automount flag (yes or no)
48#       mntopts		file system-specific mount options.
49#
50#   If the mount point can not be found in the standard input stream,
51#   then all fields are set to empty values.  This function assumes that
52#   stdin is already set /etc/vfstab (or other appropriate input
53#   stream).
54#
55readvfstab() {
56	while read special fsckdev mountp fstype fsckpass automnt mntopts; do
57		case "$special" in
58			'' )	# Ignore empty lines.
59				continue
60				;;
61
62			'#'* )	# Ignore comment lines.
63				continue
64				;;
65
66			'-')	# Ignore "no-action" lines.
67				continue
68				;;
69		esac
70
71		[ "x$mountp" = "x$1" ] && break
72	done
73}
74
75readswapdev() {
76	while read special fsckdev mountp fstype fsckpass automnt mntopts; do
77		# Ignore comments, empty lines, and no-action lines
78		case "$special" in
79		'#'* | '' | '-') continue;;
80		esac
81
82		[ "$fstype" != swap ] && continue
83
84		[ "x$special" = "x$1" ] && break
85	done
86}
87
88#
89# readmnttab mount_point
90#   -> (special, mountp, fstype, mntopts, mnttime)
91#
92#   A mnttab-like input stream is scanned for the mount point specified
93#   as $1.  Returns the fields of mnttab in the following shell
94#   variables:
95#
96#       special		block device
97#       mountp		mount point (must match $1, if found)
98#       fstype		file system type
99#       mntopts		file system-specific mount options.
100#	mnttime		time at which file system was mounted
101#
102#   If the mount point can not be found in the standard input stream,
103#   then all fields are set to empty values.  This function assumes that
104#   stdin is already set to /etc/mnttab (or other appropriate input
105#   stream).
106#
107readmnttab() {
108	while read special mountp fstype mntopts mnttime; do
109		[ "x$mountp" = "x$1" ] && break
110	done
111}
112
113cecho() {
114	echo $*
115	echo $* >/dev/msglog
116}
117
118#
119# checkmessage raw_device fstype mountpoint
120# checkmessage2 raw_device fstype mountpoint
121#
122#   Two simple auxilary routines to the shell function checkfs.  Both
123#   display instructions for a manual file system check.
124#
125checkmessage() {
126	cecho ""
127	cecho "WARNING - Unable to repair the $3 filesystem. Run fsck"
128	cecho "manually (fsck -F $2 $1)."
129	cecho ""
130}
131
132checkmessage2() {
133	cecho ""
134	cecho "WARNING - fatal error from fsck - error $4"
135	cecho "Unable to repair the $3 filesystem. Run fsck manually"
136	cecho "(fsck -F $2 $1)."
137	cecho ""
138}
139
140#
141# checkfs raw_device fstype mountpoint
142#
143#   Check the file system specified. The return codes from fsck have the
144#   following meanings.
145#
146#	 0	file system is unmounted and okay
147#	32	file system is unmounted and needs checking (fsck -m only)
148#	33	file system is already mounted
149#	34	cannot stat device
150#	35	modified root or something equally dangerous
151#	36	uncorrectable errors detected - terminate normally (4.1 code 8)
152#	37	a signal was caught during processing (4.1 exit 12)
153#	39	uncorrectable errors detected - terminate rightaway (4.1 code 8)
154#	40	 for root, same as 0 (used here to remount root)
155#
156checkfs() {
157	# skip checking if the fsckdev is "-"
158	[ "x$1" = x- ] && return
159
160	# if fsck isn't present, it is probably because either the mount of
161	# /usr failed or the /usr filesystem is badly damanged.  In either
162	# case, there is not much to be done automatically.  Fail with
163	# a message to the user.
164	if [ ! -x /usr/sbin/fsck ]; then
165		cecho ""
166		cecho "WARNING - /usr/sbin/fsck not found.  Most likely the"
167		cecho "mount of /usr failed or the /usr filesystem is badly"
168		cecho "damaged."
169		cecho ""
170		return 1
171	fi
172
173	# If a filesystem-specific fsck binary is unavailable, then no
174	# fsck pass is required.
175	[ ! -x /usr/lib/fs/$2/fsck ] && [ ! -x /etc/fs/$2/fsck ] && return
176
177	/usr/sbin/fsck -F $2 -m $1 >/dev/null 2>&1
178
179	if [ $? -ne 0 ]; then
180		# Determine fsck options by file system type
181		case $2 in
182			ufs)	foptions="-o p"
183				;;
184			*)	foptions="-y"
185				;;
186		esac
187
188		cecho "The $3 file system ($1) is being checked."
189		/usr/sbin/fsck -F $2 $foptions $1
190
191		case $? in
192		0|40)	# File system OK
193			;;
194
195		1|34|36|37|39)	# couldn't fix the file system - fail
196			checkmessage "$1" "$2" "$3"
197			return 1
198			;;
199		33)	# already mounted
200			return 0
201			;;
202
203		*)	# fsck child process killed (+ error code 35)
204			checkmessage2 "$1" "$2" "$3" "$?"
205			return 1
206			;;
207		esac
208	fi
209
210	return 0
211}
212
213#
214# checkopt option option-string
215# -> ($option, $otherops)
216#
217#   Check to see if a given mount option is present in the comma
218#   separated list gotten from vfstab.
219#
220#	Returns:
221#	${option}       : the option if found the empty string if not found
222#	${otherops}     : the option string with the found option deleted
223#
224checkopt() {
225	option=
226	otherops=
227
228	[ "x$2" = x- ] && return
229
230	searchop="$1"
231	set -- `IFS=, ; echo $2`
232
233	while [ $# -gt 0 ]; do
234		if [ "x$1" = "x$searchop" ]; then
235			option="$1"
236		else
237			if [ -z "$otherops" ]; then
238				otherops="$1"
239			else
240				otherops="${otherops},$1"
241			fi
242		fi
243		shift
244	done
245}
246
247#
248# hasopts $opts $allopts
249#
250#   Check if all options from the list $opts are present in $allopts.
251#   Both $opts and $allopts should be in comma separated format.
252#
253# Return 0 on success, and 1 otherwise.
254#
255hasopts() {
256	opts="$1"
257	allopts="$2"
258
259	set -- `IFS=, ; echo $opts`
260	while [ $# -gt 0 ]; do
261		if [ "$1" != "remount" ]; then
262			checkopt $1 $allopts
263			#
264			# Don't report errors if the filesystem is already
265			# read-write when mounting it as read-only.
266			#
267			[ -z "$option" ] && [ "$1" = "ro" ] && \
268				checkopt rw $allopts
269			[ -z "$option" ] && return 1
270		fi
271		shift
272	done
273	return 0
274}
275
276#
277# mounted $path $fsopts $fstype
278#
279#   Check whether the specified file system of the given type is currently
280#   mounted with all required filesystem options by going through /etc/mnttab
281#   in our standard input.
282#
283#   Return values:
284#   0	Success.
285#   1	The filesystem is not currently mounted, or mounted without required
286#	options, or a filesystem of a different type is mounted instead.
287#
288mounted() {
289	path="$1"
290	fsopts="$2"
291	fstype="$3"
292
293	while read mntspec mntpath mnttype mntopts on; do
294		[ "$mntpath" = "$path" ] || continue
295		[ "$fstype" != "-" ] && [ "$mnttype" != "$fstype" ] && return 1
296		[ "$fsopts" = "-" ] && return 0
297		hasopts $fsopts $mntopts && return 0
298	done
299	return 1
300}
301
302#
303# mountfs $opts $path $type $fsopts $special
304#
305#   Try to mount a filesystem.  If failed, display our standard error
306#   message on the console and print more details about what happened
307#   to our service log.
308#
309# Arguments:
310#   $opts	- options for mount(1M)				[optional]
311#   $path	- mount point
312#   $type	- file system type				[optional]
313#   $fsopts	- file system specific options (-o)		[optional]
314#   $special	- device on which the file system resides	[optional]
315#
316# Return codes:
317#   0		- success.
318#   otherwise	- error code returned by mount(1M).
319#
320mountfs() {
321	opts="$1"
322	path="$2"
323	special="$5"
324
325	#
326	# Take care of optional arguments
327	#
328	[ "$opts" = "-" ] && opts=""
329	[ "$special" = "-" ] &&	special=""
330	[ "$3" = "-" ] && type=""
331	[ "$3" != "-" ] && type="-F $3"
332	[ "$4" = "-" ] && fsopts=""
333	[ "$4" != "-" ] && fsopts="-o $4"
334
335	cmd="/sbin/mount $opts $type $fsopts $special $path"
336	msg=`$cmd 2>&1`
337	err=$?
338
339	[ $err = 0 ] && return 0
340
341	#
342	# If the specified file system is already mounted with all
343	# required options, and has the same filesystem type
344	# then ignore errors and return success
345	#
346	mounted $path $4 $3 < /etc/mnttab && return 0
347
348	echo "ERROR: $SMF_FMRI failed to mount $path "\
349	     "(see 'svcs -x' for details)" > /dev/msglog
350	echo "ERROR: $cmd failed, err=$err"
351	echo $msg
352	return $err
353}
354