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 }