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 }