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