Home | History | Annotate | Download | only in shell
      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 
     32 vfstab=${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 #
     55 readvfstab() {
     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 
     75 readswapdev() {
     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 #
    107 readmnttab() {
    108 	while read special mountp fstype mntopts mnttime; do
    109 		[ "x$mountp" = "x$1" ] && break
    110 	done
    111 }
    112 
    113 cecho() {
    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 #
    125 checkmessage() {
    126 	cecho ""
    127 	cecho "WARNING - Unable to repair the $3 filesystem. Run fsck"
    128 	cecho "manually (fsck -F $2 $1)."
    129 	cecho ""
    130 }
    131 
    132 checkmessage2() {
    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 #
    156 checkfs() {
    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 #
    224 checkopt() {
    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 #
    255 hasopts() {
    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 #
    288 mounted() {
    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 #
    320 mountfs() {
    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