1 #
2 # CDDL HEADER START
3 #
4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
7 #
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
12 #
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
18 #
19 # CDDL HEADER END
20 #
21
22 #
23 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
25 #
26
27 whence -p stc_genutils > /dev/null 2>&1
28 if (( $? != 0 )); then
29 print -u2 "nfs-util.kshlib: stc_genutils command not found!"
30 exit 1
31 fi
32 STC_GENUTILS_TMPDIR=$(stc_genutils tmpdir)
33 if (( $? != 0 )); then
34 print -u2 "nfs-util.kshlib: directory $STC_GENUTILS_TMPDIR not exist" \
35 " and cannot create it!"
36 exit 1
37 fi
38 STC_GENUTILS_DEBUG=$(stc_genutils debug)
39
40 #
41 # Function to remotely execute one or more commands, using korn shell.
42 # Usage: RSH user machine command_string (rest of line)
43 # user target user on remote system
44 # machine remote machine to execute command
45 # command_string any desired command(s) (korn shell)
46 # STC_GENUTILS_DEBUG global to enable debugging mode
47 # UNIX_RES global to detect failures, if unix standard is followed
48 # for return codes (0=OK, !0=failure).
49 # This function in addition to execute remote command, adds code for
50 # getting the return code from last operation, and to trace the remote
51 # execution as enabled by set -x (depending on $STC_GENUTILS_DEBUG).
52 #
53 # NOTES
54 # Take care to no redirect stderr to stdout as that will cause
55 # a very messy output in debug mode, and possible test failures.
56 #
57 # This library uses Korn shell (ksh) syntax only, and must be invoked in
58 # ksh scripts only.
59 function RSH
60 {
61 typeset FNAME=RSH
62 typeset SETD=""
63
64 [[ :$STC_GENUTILS_DEBUG: == \
65 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
66 set -x && \
67 typeset SETD="export STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG; set -x; "
68
69 (( $# < 3 )) && \
70 echo "Usage: $FNAME ruser remotehost \"rcmd args\"" && \
71 return 1
72
73 typeset ruser=$1
74 typeset rmach=$2
75 shift; shift
76 typeset rcmd="${SETD}$@"
77 typeset -i ret=0
78
79 # by default, expect UNIX standard result codes
80 typeset UNIX_RES=${UNIX_RES:="1"}
81
82 typeset file=$STC_GENUTILS_TMPDIR/$rmach.$$.out
83 typeset file2=$STC_GENUTILS_TMPDIR/exec.$$.result
84
85 ssh -o "StrictHostKeyChecking no" $ruser@$rmach /usr/bin/ksh -c "'$rcmd; \
86 print -u 2 \"returned=(\$?)\"'" \
87 > $file 2>$file2
88 ret=$?
89 #
90 # Since the server may reboot in some tests and when
91 # that happens ssh can return 255 (remote down) and
92 # we may want to ignore that error
93 #
94 if (( $ret != 0 && $ret != 255 )); then
95 echo "ERROR: the rsh command failed, returned=$ret"
96 cat $file2
97 rm -f $file $file2
98 return $ret
99 fi
100
101 cat $file
102 ret=$(grep -v 'print -u 2' $file2 | grep 'returned=(' | \
103 sed 's/^.*returned=(//' | sed 's/).*$//')
104 if [[ $UNIX_RES != 1 ]]; then
105 if (( $ret == 0 )); then
106 ret=1
107 cat $file2 >&2
108 else
109 ret=0
110 fi
111 else
112 (( $ret != 0 )) || \
113 [[ :$STC_GENUTILS_DEBUG: == \
114 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] \
115 && cat $file2 >&2
116 fi
117 rm -f $file $file2 > /dev/null 2>&1
118 [[ :$STC_GENUTILS_DEBUG: == :RSH: ]] && set +x
119
120 return $ret
121 }
122
123 #
124 # Usage: set_nfs_param <parameter> <value> <file>
125 # parameter : parameter which value will be changed
126 # value : the value will be set
127 # file : which file will be changed
128 # This function is used to set/change the value of a parameter.
129 # The format must be like this, paramter=value, in this file.
130 # If value="-", parameter will be commented out from the file.
131 #
132 function set_nfs_param
133 {
134 typeset FNAME=set_nfs_param
135 [[ :$STC_GENUTILS_DEBUG: == \
136 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
137 set -vx
138
139 if (( $# != 3 )) ; then
140 print -u 2 "usage: $FNAME <parameter> <value> <file>"
141 return 2
142 fi
143 typeset parameter=$1
144 typeset value=$2
145 typeset file=$3
146 if [[ ! -w $file ]] ; then
147 print -u 2 "The file <$file> doesn't exist or isn't writable"
148 return 2
149 fi
150 if [[ $value == "-" ]] ; then
151 perl -i -p -e "s/^$parameter/#$parameter/g" $file
152 else
153 perl -i -p -e "s/^#?$parameter=.*/$parameter=$value/g" $file
154 fi
155 if (( $? != 0 )) ; then
156 print -u 2 "change the nfs config file <$file> failed"
157 return 2
158 fi
159 }
160
161 #
162 # Function to check and exit if the current zone is a non-global zone.
163 # Usage: ck_zone [err_msg]
164 # err_msg (optional); if provided, it will be added to the output
165 #
166 # This function is to verify if the current zone is a global zone
167 # Yes, it just returns 0 without any messages printed;
168 # No, it prints an error message and exit
169 #
170 function ck_zone
171 {
172 typeset FNAME=ck_zone
173 [[ :$STC_GENUTILS_DEBUG: == \
174 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
175 set -vx
176
177 typeset ErrMsg=$1
178 [[ -z $ErrMsg ]] && \
179 ErrMsg="This test is not supported in non-global zone."
180
181 typeset zn=$(/usr/bin/zonename)
182 if [[ $zn != global ]]; then
183 echo "$FNAME: current zonename is <$zn>"
184 echo "\t$ErrMsg"
185 exit 4
186 fi
187 return 0
188 }
189
190 #
191 # Function to print test system information.
192 # If $1 is provided, the function will print the info of remote host ($1).
193 # Make sure the remote host can be accessed with root before invocation.
194 # If there's no parameter, the function will print local host information.
195 #
196 # Usage: print_system_info [hostname]
197 # hostname(optional): the name of remote system
198 #
199 function print_system_info
200 {
201 host=$1
202
203 if [[ $host == "" ]]; then
204 echo "`hostname` info:"
205 echo "\tuname:\t\t`uname -a` \n\tisainfo:\t`isainfo` \
206 \n\tzonename:\t`zonename`"
207 else
208 echo "$host info:"
209 RSH root $host \
210 "echo \"\tuname:\t\t\`uname -a\` \n\tisainfo:\t\`isainfo\` \
211 \n\tzonename:\t\`zonename\`\" "
212 fi
213 }
214
215 #
216 # Function to create sub ZFS pool on specific file or volume
217 # Usage: create_zpool pname fname|vname [size]
218 #
219 # pname: name of zfs pool need to be created
220 # fname|vname: name of file or volume that the zfs pool is created on
221 # size: size of volume
222 #
223 function create_zpool
224 {
225 typeset FNAME=create_zpool
226 [[ :$STC_GENUTILS_DEBUG: == \
227 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
228 set -x
229
230 getopts fv opt
231 case $opt in
232 f) # create pool on file
233 typeset pname=$2
234 typeset fname=$3
235 zpool create -f $pname $fname > $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ 2>&1
236 if (( $? != 0 )); then
237 echo "$FNAME: failed to create zpool -"
238 cat $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
239 zpool status $pname
240 rm -f $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
241 return 2
242 fi
243 ;;
244 v) # create pool on volume
245 typeset pname=$2
246 typeset vname=$3
247 typeset size=$4 # size is in the form of 5m/2g
248 echo "$FNAME: Setting test filesystems with ZFS ..."
249 zpool status | grep "$vname" | grep ONLINE >/dev/null 2>&1
250 if (( $? != 0 )); then
251 zfs create -V $size $vname > $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$ 2>&1
252 if (( $? != 0 )); then
253 echo "$FNAME: failed to create volume -"
254 cat $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$
255 grep "same dev" $STC_GENUTILS_TMPDIR/$FNAME.zfsc.$$ \
256 > /dev/null 2>&1
257 (( $? == 0 )) && zpool status
258 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
259 return 2
260 fi
261 zpool create -f $pname /dev/zvol/dsk/$vname \
262 > $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ 2>&1
263 if (( $? != 0 )); then
264 echo "$FNAME: failed to create sub zpool -"
265 cat $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$
266 grep "same dev" $STC_GENUTILS_TMPDIR/$FNAME.zpc.$$ \
267 > /dev/null 2>&1
268 (( $? == 0 )) && zpool status
269 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
270 return 2
271 fi
272 fi
273 ;;
274 *)
275 echo "$FNAME: ERROR - incorrect usage."
276 return 2
277 ;;
278 esac
279
280 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
281 }
282
283 #
284 # Function to create ZFS filesystem in provided zfs pool.
285 # Usage: create_zfs_fs Zpool mountpoint [FSsize] [FSmopt]
286 #
287 # Zpool: zfs pool where ZFS filesystem is created
288 # mountpoint: the mount point new filesystem is mounted on
289 # FSsize: size is in the form of 5m/2g
290 # FSmopt: remount option
291 #
292 function create_zfs_fs {
293 typeset FNAME=create_zfs_fs
294 [[ :$STC_GENUTILS_DEBUG: == \
295 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
296 set -x
297
298 typeset Zpool=$1
299 typeset FSname=$2
300 (( $# >= 3 )) && typeset FSsize=$3
301 (( $# == 4 )) && typeset FSmopt=$4
302
303 typeset -u Zname=$(basename $FSname)
304 zfs create $Zpool/$Zname > $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$ 2>&1
305 if (( $? != 0 )); then
306 echo "$FNAME: failed to <zfs create $Zpool/$Zname>"
307 cat $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$
308 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
309 return 2
310 fi
311 [[ ! -d $FSname ]] && mkdir -p $FSname
312 zfs set mountpoint=$FSname $Zpool/$Zname \
313 > $STC_GENUTILS_TMPDIR/$FNAME.szfs.$$ 2>&1
314 if (( $? != 0 )); then
315 echo "$FNAME: failed to \c"
316 echo "<zfs set mountpoint=$FSname $Zpool/$Zname>"
317 cat $STC_GENUTILS_TMPDIR/$FNAME.szfs.$$
318 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
319 return 2
320 fi
321 chmod 0777 $FSname
322 ACLs=write_xattr/write_attributes/write_acl/add_file:allow
323 chmod A+everyone@:${ACLs} $FSname
324
325 if [[ -n $FSsize ]]; then
326 zfs set quota=$FSsize $Zpool/$Zname \
327 > $STC_GENUTILS_TMPDIR/$FNAME.qzfs.$$ 2>&1
328 if (( $? != 0 )); then
329 echo "$FNAME: failed to \c"
330 echo "<zfs set quota=$FSsize $Zpool/$Zname>"
331 cat $STC_GENUTILS_TMPDIR/$FNAME.qzfs.$$
332 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
333 return 2
334 fi
335 unset FSsize
336 fi
337 if [[ -n $FSmopt ]]; then
338 zfs umount $Zpool/$Zname > $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$ 2>&1
339 zfs mount -o $FSmopt $Zpool/$Zname \
340 >> $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$ 2>&1
341 if (( $? != 0 )); then
342 echo "$FNAME: failed to \c"
343 echo "<zfs mount -o $FSmopt $Zpool/$Zname>"
344 cat $STC_GENUTILS_TMPDIR/$FNAME.mzfs.$$
345 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
346 return 2
347 fi
348 unset FSmopt
349 fi
350
351 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
352 return 0
353 }
354
355 #
356 # Function to create LOFI filesystem with provided options.
357 # Usage: create_lofi_fs lofile mountpoint [FSsize] [FSmopt]
358 #
359 # lofile: lofi file where LOFI filesystem is created
360 # mountpoint: the mount point new filesystem is mounted on
361 # FSsize: size is in the form of 5m/2g, default is 5m
362 # FSmopt: mount option, default is rw
363 #
364 function create_lofi_fs {
365 typeset FNAME=create_lofi_fs
366 [[ :$STC_GENUTILS_DEBUG: == \
367 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
368 set -x
369
370 typeset LFname=$1
371 typeset FSname=$2
372 typeset FSsize=5m
373 typeset FSmopt="rw"
374 (( $# >= 3 )) && FSsize=$3
375 (( $# == 4 )) && FSmopt=$4
376
377 [[ -f $LFname ]] && rm -f $LFname
378 mkfile $FSsize $LFname > $STC_GENUTILS_TMPDIR/$FNAME.mkfile.$$ 2>&1
379 if (( $? != 0 )); then
380 echo "$FNAME: failed to <mkfile $FSsize $LFname>"
381 cat $STC_GENUTILS_TMPDIR/$FNAME.mkfile.$$
382 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
383 return 2
384 fi
385 lofiadm -a $LFname > $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ 2>&1
386 if (( $? != 0 )); then
387 echo "$FNAME: failed to <lofiadm -a $LFname>"
388 cat $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$
389 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
390 return 2
391 fi
392 typeset LDEV=$(head -1 $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ | awk '{print $1}')
393 echo "y" | newfs -i 10240 $LDEV > $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$ 2>&1
394 if (( $? != 0 )); then
395 echo "$FNAME: failed to <newfs -i 10240 $LDEV>"
396 cat $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$
397 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
398 return 2
399 fi
400 [[ ! -d $FSname ]] && mkdir -p $FSname
401 typeset fstype="ufs"
402 [[ $FSmopt == *"noxattr"* ]] && fstype="tmpfs"
403 mount -F $fstype -o $FSmopt $LDEV $FSname > \
404 $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$ 2>&1
405 if (( $? != 0 )); then
406 echo "$FNAME: failed to <mount -F $fstype -o $FSmopt $LDEV $FSname>"
407 cat $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$
408 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
409 return 2
410 fi
411 chmod 0777 $FSname
412
413 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
414 return 0
415 }
416
417 #
418 # Function to destroy LOFI filesystem.
419 # Usage: destroy_lofi_fs mountpoint
420 #
421 # mountpoint: mount point the filesystem is mounted on
422 #
423 function destroy_lofi_fs {
424 typeset FNAME=destroy_lofi_fs
425 [[ :$STC_GENUTILS_DEBUG: == \
426 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
427 set -x
428
429 typeset FSname=$1
430 typeset LDEV=$(df -k $FSname | awk '{print $1}' | \
431 grep -v "^Filesystem$")
432
433 umount -f $FSname > $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$ 2>&1
434 if (( $? != 0 )); then
435 echo "$FNAME: WARNING, umount $FSname failed."
436 cat $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$
437 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
438 return 2
439 fi
440 typeset LFname=$(lofiadm $LDEV 2>$STC_GENUTILS_TMPDIR/$FNAME.file.$$)
441 if (( $? != 0 )); then
442 echo "$FNAME: WARNING, lofiadm $LDEV failed."
443 cat $STC_GENUTILS_TMPDIR/$FNAME.file.$$
444 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
445 return 2
446 fi
447 lofiadm -d $LDEV > $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$ 2>&1
448 if (( $? != 0 )); then
449 echo "$FNAME: WARNING, lofiadm -d $LDEV failed."
450 cat $STC_GENUTILS_TMPDIR/$FNAME.lofi.$$
451 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
452 return 2
453 fi
454
455 rm -fr $STC_GENUTILS_TMPDIR/$FNAME.*.$$ $LFname $FSname
456 return 0
457 }
458
459 #
460 # Function to create UFS filesystem from zfs volume in provided zfs pool.
461 # Usage: create_ufs_fs Zpool mountpoint [FSsize] [FSmopt]
462 #
463 # Zpool: zfs pool where zfs volume is created
464 # mountpoint: the mount point new filesystem is mounted on
465 # FSsize: size is in the form of 5m/2g, default is 5m
466 # FSmopt: mount option, default is rw
467 #
468 function create_ufs_fs {
469 typeset FNAME=create_ufs_fs
470 [[ :$STC_GENUTILS_DEBUG: == \
471 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
472 set -x
473
474 typeset Zpool=$1
475 typeset FSname=$2
476 typeset FSsize=5m
477 typeset FSmopt="rw"
478 (( $# >= 3 )) && FSsize=$3
479 (( $# == 4 )) && FSmopt=$4
480
481 typeset -u Vname=$(basename $FSname)
482 zfs create -V $FSsize $Zpool/$Vname > $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$ 2>&1
483 if (( $? != 0 )); then
484 echo "$FNAME: failed to <zfs create -V $FSsize $Zpool/$Vname>"
485 cat $STC_GENUTILS_TMPDIR/$FNAME.czfs.$$
486 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
487 return 2
488 fi
489 echo "y" | newfs -i 10240 /dev/zvol/rdsk/$Zpool/$Vname > \
490 $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$ 2>&1
491 if (( $? != 0 )); then
492 echo "$FNAME: failed to <newfs /dev/zvol/rdsk/$Zpool/$Vname>"
493 cat $STC_GENUTILS_TMPDIR/$FNAME.newfs.$$
494 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
495 return 2
496 fi
497 [[ ! -d $FSname ]] && mkdir -p $FSname
498 mount -F ufs -o $FSmopt /dev/zvol/dsk/$Zpool/$Vname $FSname > \
499 $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$ 2>&1
500 if (( $? != 0 )); then
501 echo "$FNAME: failed to <mount /dev/zvol/dsk/$Zpool/$Vname $FSname>"
502 cat $STC_GENUTILS_TMPDIR/$FNAME.mnt.$$
503 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
504 return 2
505 fi
506 chmod 0777 $FSname
507
508 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
509 return 0
510 }
511
512 #
513 # Function to destroy UFS filesystem.
514 # Usage: destroy_ufs_fs mountpoint
515 #
516 # mountpoint: mount point the filesystem is mounted on
517 #
518 function destroy_ufs_fs {
519 typeset FNAME=destroy_ufs_fs
520 [[ :$STC_GENUTILS_DEBUG: == \
521 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
522 set -x
523
524 typeset FSname=$1
525 typeset BDEV=$(df -k $FSname | awk '{print $1}' | \
526 grep -v "^Filesystem$")
527
528 umount -f $FSname > $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$ 2>&1
529 if (( $? != 0 )); then
530 echo "$FNAME: WARNING, umount $FSname failed."
531 cat $STC_GENUTILS_TMPDIR/$FNAME.umnt.$$
532 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
533 return 2
534 fi
535 typeset Zvol=${BDEV##*/dsk/}
536 zfs destroy -f $Zvol > $STC_GENUTILS_TMPDIR/$FNAME.dzfs.$$ 2>&1
537 if (( $? != 0 )); then
538 echo "$FNAME: WARNING, zfs destroy $Zvol failed."
539 cat $STC_GENUTILS_TMPDIR/$FNAME.dzfs.$$
540 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
541 return 2
542 fi
543
544 rm -fr $STC_GENUTILS_TMPDIR/$FNAME.*.$$ $Fname $FSname
545 return 0
546 }
547
548 #
549 # Function to verify a specified condition
550 # Usage: wait_now max_TIMER the_condition [interval]
551 #
552 # max_TIMER: the maximum timer to wait
553 # condition: the condition to break the wait:
554 # "true" wait_now{} returns 0
555 # "false" wait_now{} continues until the TIMER
556 # interval: the interval between check condition
557 #
558 function wait_now {
559 typeset FNAME=wait_now
560 [[ :$STC_GENUTILS_DEBUG: == \
561 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
562 set -x
563
564 (( $# < 2 || $# > 3 )) && \
565 echo "Usage: $FNAME max_TIMER condition interval" && \
566 return -1
567
568 typeset -i Timer=$1 interval
569 typeset Wcond="$2"
570 [[ -n $3 ]] && interval=$3 || interval=1
571
572 typeset -i i=0
573 while (( i < Timer ))
574 do
575 eval ${Wcond}
576 [[ $? -eq 0 ]] && return 0
577 sleep $interval
578 let i+=interval
579 done
580 return $i
581 }
582
583 #
584 # Funtion to check return code of the last command.
585 # If the return code is equal to zero, it does nothing; if not,
586 # it prints an error message and an optional logfile on stderr,
587 # and return that error code.
588 #
589 # If a logfile is passed, it is removed automatically when the
590 # function exits. User can use -n option to ask not to remove
591 # that file.
592 # Usage: ckresult <-n> <retcode> <errmsg> <logfile>
593 # -n - don't remove logfile if the check passed
594 # retcode - the return code to be checked
595 # errmsg - error message if $retcode is non-zero
596 # logfile - logfile of the command of interest. This
597 # argument is optional.
598 # Return: the same as $retcode, the return code to be checked
599 #
600 function ckresult {
601 not_remove=0
602 if [[ $1 == "-n" ]]; then
603 not_remove=1
604 shift 1
605 fi
606
607 retcode=$1
608 errmsg="$2"
609 logfile=$3
610
611 # print $errmsg on stderr if $retcode is non-zero
612 if (( retcode != 0 )); then
613 if (( $# >= 3 )) && [[ -f $logfile ]]; then
614 cat $logfile
615 rm -f $logfile
616 fi
617 print -u2 "$errmsg"
618 fi
619
620 # remove the logfile
621 [[ -f "$logfile" ]] && ((not_remove == 0)) && rm -f $logfile
622
623 return $retcode
624 }
625
626 #
627 # get_hostname_remote - get the host name on a remote machine
628 # Based on the name service configruation in
629 # /etc/nsswitch.conf, different name maybe occur for
630 # the same host on different host. i.e. nodename vs FQDN
631 # Usage: get_hostname_remote <hostname> <remotehost>
632 # hostname - the host to be resolved on the remote host
633 # remotehost - the host which resolves hostname
634 #
635 function get_hostname_remote {
636 typeset FNAME=get_hostname_remote
637 typeset ip name
638
639 [[ :$STC_GENUTILS_DEBUG: == \
640 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
641 set -x
642
643 if (( $# < 2 )) ; then
644 echo "usage: $FNAME <hostname> <remotehost>"
645 return 1
646 fi
647
648 ip=$(getent ipnodes $1 | head -1 | awk '{print $1}')
649 (( $? != 0 )) && return 1
650 name=$(RSH root $2 "getent ipnodes $ip" \
651 2>$STC_GENUTILS_TMPDIR/rsh.out.$$)
652 if (( $? != 0 )); then
653 echo "$FNAME: run getent ipnodes on $2 failed:"
654 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
655 rm $STC_GENUTILS_TMPDIR/rsh.out.$$
656 return 1
657 fi
658 typeset retval=$(echo "$name" | head -1 | awk '{print $NF}')
659
660 # check the return value
661 if [[ -z $retval ]]; then
662 echo "$FNAME: did not get host name of $1 on $2:"
663 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
664 rm $STC_GENUTILS_TMPDIR/rsh.out.$$
665 return 1
666 fi
667 ping $retval > $STC_GENUTILS_TMPDIR/ping.out.$$ 2>&1
668 if (( $? != 0 )); then
669 echo "$FNAME: $retval not responding to pings:"
670 cat $STC_GENUTILS_TMPDIR/ping.out.$$
671 rm $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/ping.out.$$
672 return 1
673 fi
674
675 echo $retval
676 rm $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/ping.out.$$
677 return 0
678 }
679
680 #
681 # set_nfs_property - set property via "sharectl set" command
682 # if sharectl is available
683 # Usage: set_nfs_property <property> <value> [file]
684 # property - property name
685 # value - property value
686 # file - the file to save old value. It is optional.
687 #
688 function set_nfs_property {
689 typeset FNAME=set_nfs_property
690 [[ :$STC_GENUTILS_DEBUG: == \
691 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
692 set -x
693
694 if (( $# < 2 )); then
695 echo "Usage: $FNAME <property> <value> [file]"
696 return 1
697 fi
698
699 typeset property=$1
700 typeset value=$2
701 typeset file=$3
702 typeset cur_value
703 typeset envvar
704
705 typeset -l l_property
706 typeset -u u_property
707 typeset errmsg="$property: this property is unsupported by $FNAME now,"
708 errmsg="$errmsg please add more codes to it for your requirement."
709
710 case $property in
711 nfsmapid_domain | NFSMAPID_DOMAIN)
712 l_property=nfsmapid_domain
713 u_property=NFSMAPID_DOMAIN
714 ;;
715 server_versmax | NFS_SERVER_VERSMAX)
716 l_property=server_versmax
717 u_property=NFS_SERVER_VERSMAX
718 ;;
719 server_versmin | NFS_SERVER_VERSMIN)
720 l_property=server_versmin
721 u_property=NFS_SERVER_VERSMIN
722 ;;
723 server_delegation | NFS_SERVER_DELEGATION)
724 l_property=server_delegation
725 u_property=NFS_SERVER_DELEGATION
726 ;;
727 *)
728 print -u2 "$errmsg"
729 return 1
730 esac
731
732 typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
733 if [[ -n $file ]]; then
734 # get current value
735 typeset -i ret=0
736 if [[ -x /usr/sbin/sharectl ]]; then
737 cur_value=$(sharectl get -p $l_property nfs 2>$logfile)
738 ret=$?
739 else
740 cur_value=$(grep -i "^[ | ]*${u_property}=" \
741 /etc/default/nfs 2>$logfile)
742 fi
743 ckresult $ret "failed to get $property" $logfile || return 1
744 cur_value=${cur_value##*=}
745
746 # generate a env variable name for it
747 envvar="ORIG_$l_property"
748
749 # save the value into file
750 echo "$envvar=$cur_value" >> $file
751 fi
752
753 # set new value
754 if [[ -x /usr/sbin/sharectl ]]; then
755 sharectl set -p $l_property=$value nfs > $logfile
756 else
757 grep -vi "^[ | ]*${u_property}=" /etc/default/nfs \
758 > $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$
759 echo "$u_property=$value" >> $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$
760 mv $STC_GENUTILS_TMPDIR/$FNAME.nfs.$$ /etc/default/nfs
761 chown root:sys /etc/default/nfs
762 if [[ $u_property == NFSMAPID_DOMAIN ]]; then
763 svcadm restart mapid > $logfile
764 [[ -z $value ]] || wait_now 10 \
765 "[[ \$(cat /var/run/nfs4_domain) == $value ]]"
766 fi
767 fi
768 ckresult $? "failed to set $property to $value" $logfile || return 1
769 }
770
771 #
772 # restore_nfs_property - restore property via "sharectl set" command
773 # if sharectl is available
774 # Usage: restore_nfs_property <property> <file>
775 # property - property name
776 # file - the file contains the old value
777 #
778 function restore_nfs_property {
779 typeset FNAME=restore_nfs_property
780 [[ :$STC_GENUTILS_DEBUG: == \
781 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
782 set -x
783
784 if (( $# < 2 )); then
785 echo "Usage: $FNAME <property> <file>"
786 return 1
787 fi
788
789 typeset -l property
790 typeset file=$2
791 typeset envvar
792 typeset value
793
794 case $1 in
795 nfsmapid_domain | NFSMAPID_DOMAIN)
796 property=nfsmapid_domain
797 def_value=domain
798 ;;
799 server_versmax | NFS_SERVER_VERSMAX)
800 property=server_versmax
801 def_value=4
802 ;;
803 server_versmin | NFS_SERVER_VERSMIN)
804 property=server_versmin
805 def_value=2
806 ;;
807 server_delegation | NFS_SERVER_DELEGATION)
808 property=server_delegation
809 def_value=on
810 ;;
811 esac
812
813 # generate env variable name we need
814 envvar="ORIG_$property"
815
816 # get its value from file
817 typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
818 value=$(grep $envvar $file 2>$logfile)
819 ckresult $? "failed to get $envvar from $file" $logfile || return 1
820 value=${value##$envvar=}
821 [[ $value == "" ]] && value=$def_value
822
823 set_nfs_property $property "$value"
824 }
825
826 #
827 # sharemgr_share - share one dir using sharemgr if it is available
828 # Usage: sharemgr_share <group> <directory> [share_options]
829 #
830 function sharemgr_share {
831 typeset FNAME=sharemgr_share
832 [[ :$STC_GENUTILS_DEBUG: == \
833 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
834 set -x
835
836 typeset tgrp=$1
837 typeset dir=$2
838 typeset opts=${3:-"rw"}
839
840 typeset -i ret=0
841 typeset i=0
842 typeset j=0
843
844 # if there is no sharemgr, use share instead
845 if [[ ! -x /usr/sbin/sharemgr ]]; then
846 share -F nfs -o $opts $dir
847 return $?
848 fi
849
850 #
851 # divide options into groups, using "sec" as keywords
852 # Example:
853 # input: "anon=0,ro,sec=krb5,rw,sec=krb5:krb5p,ro=snake"
854 # output: "sec=sys,anon=0,ro" "sec=krb5,rw" "sec=krb5:krb5p,ro=snake"
855 #
856 while [[ -n $opts ]]; do
857 opt_group[$i]=${opts%%,sec=*}
858 [[ ${opt_group[$i]} == $opts ]] && break
859 opts=${opts#${opt_group[$i]},}
860 (( i += 1 ))
861 done
862 if [[ $opt_group[0] != "sec="* ]]; then
863 opt_group[0]="sec=sys,${opt_group[0]}"
864 fi
865
866 #
867 # extract options that are not sec flavour specific,
868 # Example:
869 # input: "sec=sys,anon=0,ro" "sec=krb5,rw" "sec=krb5:krb5p,ro=snake"
870 # output: "sec=sys ro" "sec=krb5 rw" "sec=krb5:krb5p ro=snake"
871 # and "anon=0"
872 #
873 i=0
874 while (( i < ${#opt_group[*]} )); do
875 opts=$(echo ${opt_group[$i]} | tr , ' ')
876 opt_group[$i]=""
877 for o in $opts; do
878 if echo $o | egrep "sec=|rw|ro|root=|window=" \
879 >/dev/null; then
880 # sec flavour specific options
881 opt_group[$i]="${opt_group[$i]} $o"
882 else
883 # global options, like anon, etc.
884 if ! echo $opt_global | grep $o >/dev/null; then
885 opt_global="$opt_global $o"
886 fi
887 fi
888 done
889 (( i += 1 ))
890 done
891
892 #
893 # divide a single definition for multiple sec flavours into
894 # multiple ones
895 # Example:
896 # input: "sec=sys ro" "sec=krb5 rw" "sec=krb5:krb5p ro=snake"
897 # output: "sec=sys ro" "sec=krb5 rw" "sec=krb5 ro=snake"
898 # "sec=krb5p ro=snake"
899 #
900 i=0
901 j=0
902 while (( i < ${#opt_group[*]} )); do
903 if ! echo ${opt_group[$i]} |awk '{print $1}' |grep ":" \
904 >/dev/null; then
905 opt_group2[$j]=${opt_group[$i]}
906 (( j += 1 ))
907 else
908 # contains multiple sec flavours
909 flavours=$(echo ${opt_group[$i]} | awk '{print $1}')
910 tmp=${opt_group[$i]}
911 tmp=${tmp# *}
912 rest=${tmp#$flavours}
913 flavours=${flavours##*=}
914 flavours=$(echo $flavours | tr : ' ')
915 for f in $flavours; do
916 opt_group2[$j]="sec=$f $rest"
917 (( j += 1 ))
918 done
919 fi
920 (( i += 1 ))
921 done
922
923 #
924 # use sharemgr to share the directory
925 # Example:
926 # input: share anon=0,ro,sec=krb5,rw,ro=snake,sec=krb5p,ro=snake /tmp
927 # output:
928 # sharemgr add-share -s /tmp $tgrp
929 # sharemgr set -P nfs -p anon=0 -s /tmp $tgrp
930 # sharemgr set -P nfs -S sys -p ro=* -s /tmp $tgrp
931 # sharemgr set -P nfs -S krb5 -p rw=* -p ro=snake -s /tmp $tgrp
932 # sharemgr set -P nfs -S krb5p -p ro=snake -s /tmp $tgrp
933 #
934 if sharemgr list | grep $tgrp >/dev/null 2>&1; then
935 sharemgr remove-share -f -s $dir $tgrp > /dev/null 2>&1
936 else
937 sharemgr create -P nfs $tgrp
938 fi
939 sharemgr add-share -s $dir $tgrp
940 ((ret |= $?))
941
942 typeset property=""
943 for o in $opt_global; do
944 if [[ $o == nosuid ]]; then
945 o="nosuid=true"
946 elif [[ $o == nosub ]]; then
947 o="nosub=true"
948 elif [[ $o == public ]]; then
949 o="public=true"
950 elif [[ $o == aclok ]]; then
951 o="aclok=true"
952 elif [[ $o == log ]]; then
953 o="log=global"
954 fi
955 property="$property -p $o"
956 done
957 if [[ -n $property ]]; then
958 sharemgr set -P nfs $property -s $dir $tgrp
959 ((ret |= $?))
960 fi
961
962 typeset flavour=""
963 i=0
964 while (( i < ${#opt_group2[*]} )); do
965 flavour=""
966 property=""
967 flavour=$(echo ${opt_group2[$i]} | awk '{print $1}')
968 tmp=${opt_group2[$i]}
969 tmp=$(echo $tmp | sed "s/^ *//")
970 optlist=${tmp##$flavour}
971
972 [[ -z $optlist ]] && optlist="rw"
973 for o in $optlist; do
974 if [[ $o == "rw" ]]; then
975 o="rw=*"
976 elif [[ $o == "ro" ]]; then
977 o="ro=*"
978 fi
979 property="$property -p $o"
980 done
981
982 flavour=${flavour##sec=}
983 sharemgr set -P nfs -S $flavour $property -s $dir $tgrp
984 ((ret |= $?))
985
986 (( i += 1 ))
987 done
988
989 return $ret
990 }
991
992 #
993 # sharemgr_unshare - unshare the passed directory. If sharemgr is available,
994 # the passed share group is deleted too.
995 # Usage: sharemgr_unshare <group> <directory>
996 #
997 function sharemgr_unshare {
998 typeset FNAME=sharemgr_unshare
999 [[ :$STC_GENUTILS_DEBUG: == \
1000 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1001 set -x
1002
1003 typeset tgrp=$1
1004 typeset dir=$2
1005
1006 if [[ ! -x /usr/sbin/sharemgr ]]; then
1007 unshare $dir
1008 else
1009 sharemgr delete -f $tgrp
1010 fi
1011 }
1012
1013 #
1014 # zfs_share - share one dir using zfs share
1015 # Usage: zfs_share <directory> [share_options]
1016 #
1017 function zfs_share {
1018 typeset FNAME=zfs_share
1019 [[ :$STC_GENUTILS_DEBUG: == \
1020 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1021 set -x
1022
1023 typeset dir=$1
1024 typeset opts=${2:-"rw"}
1025
1026 if [[ -z $dir ]]; then
1027 echo "$FNAME Error: exported diretory name not found"
1028 return 1
1029 fi
1030
1031 typeset -i ret=0
1032 typeset zfs_mntpnt_flag=1
1033
1034 typeset mntpnt=$(zfs list -H -o mountpoint)
1035 mntpnt=$(echo $mntpnt | tr -s "\n" " ")
1036 if [[ " $mntpnt " == *" $dir "* ]]; then
1037 zfs_mntpnt_flag=0
1038 fi
1039
1040 if (( zfs_mntpnt_flag == 0 )); then
1041 typeset fs=$(zfs list -H -o name,mountpoint | \
1042 grep "${dir}$" | awk '{print $1}')
1043
1044 zfs set sharenfs="$opts" $fs
1045 ret=$?
1046
1047 typeset sharedir=$(share | awk '{print $2}' | grep -w "$dir")
1048 sharedir=$(echo $sharedir | tr -s "\n" " ")
1049 if [[ " $sharedir " != *" $dir "* ]]; then
1050 zfs share $fs
1051 ((ret |= $?))
1052 fi
1053 else
1054 share -F nfs -o $opts $dir
1055 ret=$?
1056 fi
1057
1058 return $ret
1059 }
1060
1061 #
1062 # zfs_unshare - unshare one dir using zfs set sharenfs=off
1063 # Usage: zfs_unshare <directory>
1064 #
1065 function zfs_unshare {
1066 typeset FNAME=zfs_unshare
1067 [[ :$STC_GENUTILS_DEBUG: == \
1068 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1069 set -x
1070
1071 typeset dir=$1
1072 [[ -z $dir ]] && return 1
1073
1074 typeset -i ret=0
1075 typeset -i zfs_mntpnt_flag=1
1076
1077 typeset fs=$(zfs list -H -o name,mountpoint | \
1078 grep "${dir}$" | awk '{print $1}')
1079 typeset share_status=$(zfs get -H -o value sharenfs $fs)
1080
1081 typeset mntpnt=$(zfs list -H -o mountpoint)
1082 mntpnt=$(echo $mntpnt | tr -s "\n" " ")
1083 if [[ " $mntpnt " == *" $dir "* ]]; then
1084 zfs_mntpnt_flag=0
1085 fi
1086
1087 if [[ $share_status != "off" ]] && (( zfs_mntpnt_flag == 0 )); then
1088 zfs set sharenfs=off $fs
1089 ret=$?
1090 else
1091 unshare $dir
1092 ret=$?
1093 fi
1094
1095 return $ret
1096 }
1097
1098
1099 #
1100 # auto_unshare - unshare one dir automatically by looking up its group
1101 # If its group is zfs, use zfs_unshare();
1102 # else if sharemgr is available and its group is default or other one,
1103 # use sharemgr remove-share;
1104 # else use unshare.
1105 #
1106 # If misc share is done, unshare should be done according to the table shows:
1107 # +--------------------+----------------------+---------------------+-------+
1108 # | |sharemgr::remove-share|zfs::set sharenfs=off|unshare|
1109 # +--------------------+----------------------+---------------------+-------+
1110 # |sharemgr::add-share | Y | Y | N |
1111 # |zfs::set sharenfs=on| N | Y | N |
1112 # |share | Y | Y | Y |
1113 # +--------------------+----------------------+---------------------+-------+
1114 #
1115 # Usage: auto_unshare <directory>
1116 #
1117 function auto_unshare {
1118 typeset FNAME=auto_unshare
1119 [[ :$STC_GENUTILS_DEBUG: == \
1120 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1121 set -x
1122
1123 typeset -i ret=0
1124 typeset dir=$1
1125
1126 # strip last '/' of dir, e.g dir=/var/tmp/
1127 # after strip, dir=/var/tmp
1128 [[ $dir == */ ]] && dir=$(dirname ${dir}/FAKEFILE.$$)
1129
1130 # if dir is not shared, return 0 directly
1131 typeset shstr=$(share | awk '{print $2}' | tr '\n' ' ')
1132 [[ " $shstr " != *" $dir "* ]] && return 0
1133
1134 # if sharemgr is not existed, use zfs_unshare
1135 # zfs_unshare will check dir is zfs or not
1136 if [[ ! -x /usr/sbin/sharemgr ]]; then
1137 zfs_unshare $dir
1138 return $?
1139 fi
1140
1141 typeset sharedfile=$STC_GENUTILS_TMPDIR/sharedfile.out.$$
1142 typeset tmpfile=$STC_GENUTILS_TMPDIR/tmpfile.out.$$
1143
1144 # format all shared entries and save them to file
1145 typeset igroup=""
1146 for igroup in $(sharemgr list | tr -s '\n' ' '); do
1147 sharemgr show $igroup | sed '1d' | tr -d '\t' > $tmpfile
1148 while read line; do
1149 echo ${line}@${igroup} >> $sharedfile
1150 done < $tmpfile
1151 done
1152 rm -f $tmpfile
1153
1154 # lookup dir resides in which group
1155 typeset shdir=""
1156 igroup=""
1157 while read line; do
1158 shdir=$(echo $line | awk -F@ '{print $1}')
1159 if [[ @$shdir@ == *@$dir@* ]]; then
1160 igroup=$(echo $line | awk -F"@" '{print $2}')
1161 break
1162 fi
1163 done < $sharedfile
1164 rm -f $sharedfile
1165
1166 # unshare dir according to its group
1167 if [[ $igroup == "zfs" ]]; then
1168 zfs_unshare $dir
1169 elif [[ -n $igroup ]]; then
1170 sharemgr remove-share -f -s $dir $igroup
1171 else
1172 unshare $dir
1173 fi
1174 ret=$?
1175 if (( ret != 0 )); then
1176 echo "ERROR: unshare $dir failed, returned $ret"
1177 fi
1178
1179 return $ret
1180 }
1181
1182 #
1183 # Function to get share options from a standard entry
1184 # saved in /etc/dfs/dfstab
1185 # Usage: get_shareoptions <share entry>
1186 #
1187 # e.g.
1188 # get_shareoptions share -F nfs -o rw /tmp # rw
1189 # get_shareoptions share -o ro=client1 /tmp # ro=client1
1190 # get_shareoptions share /tmp # rw
1191 #
1192 function get_shareoptions {
1193 typeset FNAME=get_shareoptions
1194 [[ :$STC_GENUTILS_DEBUG: == \
1195 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1196 set -x
1197
1198 set -A a_opt $@
1199 typeset a_opt_len=${#a_opt[*]}
1200 typeset -i i=0
1201 typeset options=""
1202 while (( i < a_opt_len )); do
1203 if [[ ${a_opt[$i]} == "-o" ]]; then
1204 (( i+= 1 ))
1205 options=${a_opt[$i]}
1206 break
1207 fi
1208 (( i+= 1 ))
1209 done
1210 [[ -z $options ]] && options="rw"
1211 echo "$options"
1212 }
1213
1214 #
1215 # Function to check if running as root.
1216 # Usage: is_root [testname] [tmessage]
1217 #
1218 # testname optional; if provided, add to the output
1219 # tmessage optional; if provided, must follow testname
1220 #
1221 # The main purpose of testname and message is to provide a line that emulates
1222 # an assertion, so that the failure is captured in the summary and reported.
1223 # On success, it just returns 0, on failure, a message is printed, and exit.
1224 #
1225 function is_root {
1226 typeset FNAME=is_root
1227 [[ :$STC_GENUTILS_DEBUG: == \
1228 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1229 set -x
1230
1231 typeset TName=$1
1232 [[ -n $TName ]] && TName="$TName: "
1233 typeset Msg=$2
1234 typeset Stat=""
1235 [[ -n $Msg ]] && Stat="\tTest UNINITIATED: " || Msg="\c"
1236 id | grep "0(root)" > /dev/null 2>&1
1237 if (( $? != 0 )); then
1238 echo "$TName$Msg"
1239 echo "${Stat}Must run the tests as root."
1240 exit 6
1241 fi
1242 return 0
1243 }
1244
1245 # RUN_CHECK - run a command and check its return code. It prints out
1246 # error information if the return code is not equal to the expected
1247 # one.
1248 #
1249 # The expected return code is 0 by default. If user specifies "-n"
1250 # option(for negative checking purpose), however, the expected return
1251 # code is a non-zero value.
1252 #
1253 # If the check fails, the function prints out the failed command,
1254 # its stdout otupt, and its stderr ouput.
1255 #
1256 # The function uses its internal log files and removes them by default.
1257 # User can pass stdout log file and stderr log file via -o and -e
1258 # options. In that cases, these files won't be deleted automatically.
1259 #
1260 # Usage: RUN_CHECK [-n] [-o outlog] [-e errlog] <command> [args ...]
1261 # -n negatvie checking
1262 # -o outlog user specified outlog
1263 # -e errlog user specified errlog
1264 # command command to be executed
1265 # args args passed to the command
1266 #
1267 # WARNING:
1268 # Quote characters in args are silently discarded by shell when
1269 # command and args are passed to RUN_CHECK(). If these quotes matters,
1270 # you can't use RUN_CHECK().
1271 #
1272 # For example, you can't use RUN_CHECK() to run the following command:
1273 #
1274 # runat /tmp/testfile "echo hello > attr"
1275 #
1276 # Because if quote characters are removed, the command becomes a quite
1277 # different one:
1278 #
1279 # runat /tmp/testfile echo hello > attr
1280 #
1281 function RUN_CHECK {
1282 typeset FNAME=RUN_CHECK
1283 [[ :$STC_GENUTILS_DEBUG: == \
1284 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1285 set -x
1286
1287 typeset outlog
1288 typeset errlog
1289 typeset keep_outlog=0
1290 typeset keep_errlog=0
1291 typeset neg_check=0
1292 typeset debug=0
1293
1294 if [[ -n $STC_GENUTILS_DEBUG ]]; then
1295 case $STC_GENUTILS_DEBUG in
1296 *RUN_CHECK_ALL*) debug=2
1297 ;;
1298 *RUN_CHECK_CMD*) debug=1
1299 ;;
1300 ?)
1301 ;;
1302 esac
1303 fi
1304
1305 while getopts o:e:d:n flag; do
1306 case $flag in
1307 o) outlog=$OPTARG
1308 keep_outlog=1
1309 ;;
1310 e) errlog=$OPTARG
1311 keep_errlog=1
1312 ;;
1313 n) neg_check=1
1314 ;;
1315 ?) echo "$FNAME: invalid option" >&2
1316 return 1
1317 ;;
1318 esac
1319 done
1320 shift $((OPTIND - 1))
1321 typeset cmd="$@"
1322 if [[ -z $cmd ]]; then
1323 echo "$FNAME: should specify command name" >&2
1324 return 1
1325 fi
1326
1327 if ((keep_outlog == 0)); then
1328 outlog=$(mktemp -p $STC_GENUTILS_TMPDIR $$.log.XXXXXX)
1329 fi
1330 if ((keep_errlog == 0)); then
1331 errlog=$(mktemp -p $STC_GENUTILS_TMPDIR $$.log.XXXXXX)
1332 fi
1333
1334 if [[ -z $outlog || -z $errlog ]]; then
1335 echo "$FNAME: invalid logfile name" >&2
1336 echo "$FNAME: \toutlog=<$outlog>,errlog=<$errlog>" >&2
1337 return 1
1338 fi
1339
1340 eval $cmd 1>$outlog 2>$errlog
1341 typeset ret=$?
1342 typeset check_result="FAIL"
1343 if (( neg_check == 0 )); then
1344 # positive checking
1345 (( ret == 0 )) && check_result="PASS"
1346 else
1347 # negative checking
1348 (( ret != 0 )) && check_result="PASS"
1349 fi
1350
1351 cat $outlog
1352
1353 if [[ $check_result == "FAIL" ]]; then
1354 echo "command | [FAIL] $cmd" >&2
1355 sed "s/^/stdout | /" $outlog >&2
1356 sed "s/^/stderr | /" $errlog >&2
1357 elif (( debug == 1 )); then
1358 echo "command | [OK] $cmd" >&2
1359 elif (( debug == 2 )); then
1360 echo "command | [OK] $cmd" >&2
1361 sed "s/^/stdout | /" $outlog >&2
1362 sed "s/^/stderr | /" $errlog >&2
1363 fi
1364
1365 # remove logfiles
1366 (( keep_outlog == 0 )) && rm -f $outlog
1367 (( keep_errlog == 0 )) && rm -f $errlog
1368
1369 [[ $check_result == "PASS" ]] && return 0
1370 [[ $check_result == "FAIL" ]] && return 1
1371 }
1372
1373 # RUN_CHECKNEG - Run a command and check its return code to verify
1374 # it fails as expected. This a warpper around RUN_CHECK.
1375 #
1376 # Usage: RUN_CHECKNEG [-o outlog] [-e errlog] <command> [args ...]
1377 # -o outlog user specified outlog
1378 # -e errlog user specified errlog
1379 # command args the command to be executed, and its args
1380 #
1381 function RUN_CHECKNEG {
1382 RUN_CHECK -n $@
1383 }
1384
1385 #
1386 # Get free userid or groupid on client and servers
1387 # Usage:
1388 # get_free_id <database> [server 1] ... [server n]
1389 # database: passwd or group
1390 # If successful, print id and return 0
1391 # else return 1
1392 #
1393 function get_free_id {
1394 typeset FNAME=get_free_id
1395 [[ :$STC_GENUTILS_DEBUG: == \
1396 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1397 set -x
1398
1399 typeset database=$1
1400 # check databse: passwd or group
1401 if [[ $database != "passwd" && $database != "group" ]]; then
1402 echo "ERROR: invalid database."
1403 return 1
1404 fi
1405 shift
1406
1407 typeset -i id=$((RANDOM + 50000))
1408 [[ $database == "group" ]] && id=$((RANDOM/10 + 1000))
1409
1410 typeset getentcmd="/usr/bin/getent $database"
1411
1412 typeset servers=$@ # server1 server2 ... serverN
1413 typeset nserver=$#
1414
1415 typeset -i ret=1
1416 typeset -i i=0
1417 typeset -i counter=0
1418 while (( i < 1000 )); do # try 1000 times
1419 # check id on client
1420 $getentcmd $id > /dev/null 2>&1
1421 if (( $? == 0 )); then
1422 (( id += 1 ))
1423 (( i += 1 ))
1424 continue
1425 fi
1426
1427 # check id on servers one bye one
1428 counter=$nserver
1429 for srv in $servers; do
1430 [[ -z $srv ]] && break
1431
1432 RSH root $srv "$getentcmd $id | grep $id" \
1433 > $STC_GENUTILS_TMPDIR/rsh.out.$$ \
1434 2> $STC_GENUTILS_TMPDIR/rsh.err.$$
1435 (( $? == 0 )) && break
1436 #
1437 # $? == 0, id exists on srv
1438 # $? != 0, maybe due to
1439 # - RSH itself failed
1440 # - id does not exist on srv
1441 # Only id does not exist on srv, counter -= 1
1442 #
1443 grep "rsh command failed" \
1444 $STC_GENUTILS_TMPDIR/rsh.out.$$ \
1445 $STC_GENUTILS_TMPDIR/rsh.err.$$ > /dev/null 2>&1
1446 if (( $? == 0 )); then
1447 echo "ERROR: run <RSH root $srv $getentcmd $id> failed"
1448 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
1449 cat $STC_GENUTILS_TMPDIR/rsh.err.$$
1450 break
1451 fi
1452
1453 # confirm id on srv is not equale to current id
1454 srvid=$(cat $STC_GENUTILS_TMPDIR/rsh.out.$$ | awk -F: '{print $3}')
1455 [[ $srvid == $id ]] && break
1456
1457 (( counter -= 1 ))
1458 done
1459
1460 if (( counter == 0 )); then
1461 ret=0
1462 break
1463 fi
1464
1465 (( id += 1 ))
1466 (( i += 1 ))
1467 done
1468
1469 rm -f $STC_GENUTILS_TMPDIR/rsh.out.$$ $STC_GENUTILS_TMPDIR/rsh.err.$$
1470 echo $id
1471 return $ret
1472 }
1473
1474 #
1475 # Get free uid on client and servers
1476 # Usage:
1477 # get_free_uid <server 1> [server 2] ... [server n]
1478 # If sucessful, print free uid and return 0
1479 # else return 1
1480 #
1481 function get_free_uid {
1482 typeset FNAME=get_free_uid
1483 [[ :$STC_GENUTILS_DEBUG: == \
1484 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1485 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:get_free_id && set -x
1486
1487 get_free_id passwd $@
1488 return $?
1489 }
1490
1491 #
1492 # Get free gid on client and servers
1493 # Usage:
1494 # get_free_gid <server 1> [server 2] ... [server n]
1495 # If sucessful, print free uid and return 0
1496 # else return 1
1497 #
1498 function get_free_gid {
1499 typeset FNAME=get_free_gid
1500 [[ :$STC_GENUTILS_DEBUG: == \
1501 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1502 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:get_free_id && set -x
1503
1504 get_free_id group $@
1505 return $?
1506 }
1507
1508 #
1509 # Check user or group exists on client and remote servers.
1510 # If it does exist with the same id(uid or gid) on all hosts, return 0,
1511 # else return non-zero.
1512 # 1 - invalid database
1513 # - argument <name> is null
1514 # - run RSH failed
1515 # 2 - user or group does not exsit on client
1516 # - uid or gid is unmatched between client and one server
1517 #
1518 # Usage: check_user_group <database> <name> [server 1] [server 2] ... [server n]
1519 #
1520 function check_user_group {
1521 typeset FNAME=check_user_group
1522 [[ :$STC_GENUTILS_DEBUG: == \
1523 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1524 set -x
1525
1526 typeset database=$1
1527 # check databse: passwd or group
1528 if [[ $database != "passwd" && $database != "group" ]]; then
1529 echo "ERROR: invalid database."
1530 return 1
1531 fi
1532 shift
1533
1534 typeset key="user"
1535 [[ $database == "group" ]] && key="group"
1536
1537 typeset name=$1
1538 if [[ -z $name ]]; then
1539 echo "ERROR: $key name<$name> is necessary."
1540 return 1
1541 fi
1542 shift
1543
1544 typeset counter=$#
1545 typeset servers=$@
1546
1547 typeset getentcmd="/usr/bin/getent $database $name"
1548 typeset -i ret=0
1549
1550 # check user/group on client
1551 typeset clntid=$($getentcmd | awk -F: '{print $3}')
1552 [[ -z $clntid ]] && return 2
1553
1554 # check user/group with clntid on servers
1555 typeset srvid=0
1556 for srv in $servers; do
1557 RSH root $srv "$getentcmd" \
1558 > $STC_GENUTILS_TMPDIR/rsh.out.$$
1559 2> $STC_GENUTILS_TMPDIR/rsh.err.$$
1560 if (( $? != 0 )); then
1561 ret=1
1562 echo "ERROR: run <RSH root $srv getentcmd> failed"
1563 cat $STC_GENUTILS_TMPDIR/rsh.out.$$
1564 cat $STC_GENUTILS_TMPDIR/rsh.err.$$
1565 break
1566 fi
1567
1568 srvid=$(cat $STC_GENUTILS_TMPDIR/rsh.out.$$ | awk -F: '{print $3}')
1569 if [[ $srvid != $clntid ]]; then
1570 ret=2
1571 echo "INFO: $key id is unmatched,"
1572 echo " $key id on server<$srv>: $srvid"
1573 echo " $key id on client<$(hostname)>: $clntid"
1574 break
1575 fi
1576 done
1577
1578 rm -f $STC_GENUTILS_TMPDIR/rsh.*.$$
1579 return $ret
1580 }
1581
1582 function chk_user {
1583 typeset FNAME=chk_user
1584 [[ :$STC_GENUTILS_DEBUG: == \
1585 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1586 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:check_user_group && set -x
1587
1588 check_user_group passwd $@
1589 return $?
1590 }
1591
1592 function chk_group {
1593 typeset FNAME=chk_group
1594 [[ :$STC_GENUTILS_DEBUG: == \
1595 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1596 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:check_user_group && set -x
1597
1598 check_user_group group $@
1599 return $?
1600 }
1601
1602 #
1603 # Select valid uid and create specified user in specified group
1604 # on local host and remote servers.
1605 #
1606 # Usage: add_user [-g group] <user name> [server 1] [server 2] ... [server n]
1607 # e.g.
1608 # add_user usr1 srv1 srv2 # add to localhost, srv1, srv2
1609 # add_user -g goo usr2 srv1 # add to localhost, srv1 with group "goo"
1610 # add_user usr3 # only add to localhost
1611 #
1612 function add_user {
1613 typeset FNAME=add_user
1614 [[ :$STC_GENUTILS_DEBUG: == \
1615 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1616 set -x
1617
1618 typeset grp=""
1619 if [[ $1 == "-g" ]]; then
1620 shift
1621 grp=$1
1622 shift
1623 fi
1624
1625 typeset user=$1
1626 if [[ -z $user ]]; then
1627 echo "ERROR: user name<$user> is necessary."
1628 return 1
1629 fi
1630 shift
1631
1632 typeset counter=$#
1633 typeset servers=$@
1634
1635 typeset grpopt=""
1636 if [[ -n $grp ]]; then
1637 getent group $grp > /dev/null 2>&1
1638 if (( $? == 0 )); then
1639 grpopt="-g $grp"
1640 else
1641 echo "ERROR: group name<$grp> doesn't exist."
1642 return 1
1643 fi
1644 fi
1645
1646 typeset myuid=$(get_free_uid $servers)
1647 if (( $? != 0 )); then
1648 echo "ERROR: get free uid failed."
1649 return 1
1650 fi
1651
1652 # add to server
1653 typeset -i ret=0
1654 for srv in $servers; do
1655 RSH root $srv \
1656 "/usr/sbin/userdel $user;" \
1657 "/usr/sbin/useradd -u $myuid $grpopt -d /tmp -m $user" \
1658 > /dev/null 2>&1
1659 if (( $? == 0 )); then
1660 (( counter -= 1 ))
1661 else
1662 ret=1
1663 break
1664 fi
1665 done
1666
1667 # add to client
1668 if (( counter == 0 )); then
1669 /usr/sbin/userdel $user >/dev/null 2>&1
1670 /usr/sbin/useradd -u $myuid $grpopt -d /tmp -m $user
1671 ret=$?
1672 fi
1673
1674 # print uid for possible use outside
1675 (( ret == 0 )) && echo $myuid
1676
1677 return $ret
1678 }
1679
1680
1681 #
1682 # Select valid gid and create specified group with gid
1683 # on local host and remote servers.
1684 #
1685 # Usage: add_group <group name> [server 1] [server 2] ... [server n]
1686 # e.g.
1687 # add_group Tgrp01 srv1 srv2 # add to localhost, srv1, srv2
1688 # add_group Tgrp01 # only add to localhost
1689 #
1690 function add_group {
1691 typeset FNAME=add_group
1692 [[ :$STC_GENUTILS_DEBUG: == \
1693 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1694 set -x
1695
1696 typeset grp=$1
1697 if [[ -z $grp ]]; then
1698 echo "ERROR: group name<$grp> is necessary."
1699 return 1
1700 fi
1701 shift
1702
1703 typeset counter=$#
1704 typeset servers=$@
1705
1706 typeset mygid=$(get_free_gid $servers)
1707 if (( $? != 0 )); then
1708 echo "ERROR: get free gid failed."
1709 return 1
1710 fi
1711
1712 # add to servers
1713 typeset -i ret=0
1714 for srv in $servers; do
1715 RSH root $srv \
1716 "/usr/sbin/groupdel $grp; " \
1717 "/usr/sbin/groupadd -g $mygid $grp" \
1718 > /dev/null 2>&1
1719 if (( $? == 0 )); then
1720 (( counter -= 1 ))
1721 else
1722 ret=1
1723 break
1724 fi
1725 done
1726
1727 # add to client
1728 if (( counter == 0 )); then
1729 /usr/sbin/groupdel $grp > /dev/null 2>&1
1730 /usr/sbin/groupadd -g $mygid $grp
1731 ret=$?
1732 fi
1733
1734 # print gid for possible use outside
1735 (( ret == 0 )) && echo $mygid
1736
1737 return $ret
1738 }
1739
1740 #
1741 # Delete specified user or group on local host and remote servers.
1742 #
1743 # Usage: delete_user_group <database > <name> [server 1] [server 2] ... [server n]
1744 #
1745 function delete_user_group {
1746 typeset FNAME=delete_user_group
1747 [[ :$STC_GENUTILS_DEBUG: == \
1748 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1749 set -x
1750
1751 typeset database=$1
1752 # check databse: passwd or group
1753 if [[ $database != "passwd" && $database != "group" ]]; then
1754 echo "ERROR: invalid database."
1755 return 1
1756 fi
1757 shift
1758
1759 typeset name=$1
1760 if [[ -z $name ]]; then
1761 typeset key="user"
1762 [[ $database == "group" ]] && key="group"
1763 echo "ERROR: $key name<$name> is necessary."
1764 return 1
1765 fi
1766 shift
1767
1768 typeset getentcmd="/usr/bin/getent $database $name"
1769 if [[ $database == "passwd" ]]; then
1770 typeset delcmd="/usr/sbin/userdel $name"
1771 else
1772 typeset delcmd="/usr/sbin/groupdel $name"
1773 fi
1774
1775 typeset counter=$#
1776 typeset servers=$@
1777
1778 for srv in $servers; do
1779 # check user or group does exsit on srv
1780 RSH root $srv "$getentcmd | grep $name" \
1781 > /dev/null 2>&1
1782 if (( $? != 0 )); then
1783 (( counter -= 1 ))
1784 continue
1785 fi
1786
1787 # delete user or group on srv once user exsits
1788 RSH root $srv "$delcmd > /dev/null" \
1789 > /dev/null 2>&1
1790 if (( $? == 0 )); then
1791 (( counter -= 1 ))
1792 else
1793 break
1794 fi
1795 done
1796
1797 # If user or group are deleted on all remote servers,
1798 # then we delete it on client
1799 if (( counter == 0 )); then
1800 # check user or group does exist on client, if not, return 0
1801 $getentcmd | grep $name > /dev/null 2>&1
1802 (( $? != 0 )) && return 0
1803
1804 $delcmd > /dev/null 2>&1
1805 return $?
1806 fi
1807
1808 return 1
1809
1810 }
1811
1812 #
1813 # Delete specified user on local host and remote servers.
1814 #
1815 # Usage: del_user <user name> [server 1] [server 2] ... [server n]
1816 #
1817 function del_user {
1818 typeset FNAME=del_user
1819 [[ :$STC_GENUTILS_DEBUG: == \
1820 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1821 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:delete_user_group && set -x
1822
1823 delete_user_group passwd $@
1824 return $?
1825 }
1826
1827 #
1828 # Delete specified group on local host and remote servers.
1829 #
1830 # Usage: del_group <group name> [server 1] [server 2] ... [server n]
1831 #
1832 function del_group {
1833 typeset FNAME=del_group
1834 [[ :$STC_GENUTILS_DEBUG: == \
1835 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1836 STC_GENUTILS_DEBUG=$STC_GENUTILS_DEBUG:delete_user_group && set -x
1837
1838 delete_user_group group $@
1839 return $?
1840 }
1841
1842 #
1843 # Function to check if the specific system variable is set and it is
1844 # accessible for nfs test suite.
1845 #
1846 function check_system {
1847 typeset VAR=$1
1848 eval system=\${$VAR}
1849
1850 if [[ -z $system ]]; then
1851 echo "$VAR is not set, exiting."
1852 exit 1
1853 fi
1854
1855 /usr/sbin/ping $system > /dev/null 2>&1
1856 if (( $? != 0 )); then
1857 echo "$system not responding to pings, exiting"
1858 exit 1
1859 fi
1860
1861 RSH root $system /bin/true > $STC_GENUTILS_TMPDIR/ckrsh.$$ 2>&1
1862 if (( $? != 0 )); then
1863 echo "Failed to <rsh> to $system, exiting."
1864 cat $STC_GENUTILS_TMPDIR/ckrsh.$$
1865 rm -f $STC_GENUTILS_TMPDIR/ckrsh.$$
1866 exit 1
1867 fi
1868 rm -f $STC_GENUTILS_TMPDIR/ckrsh.$$
1869 }
1870
1871 #
1872 # Function to get zone id
1873 # Usage: get_zone_id <host>
1874 #
1875 function get_zone_id {
1876 typeset FNAME=get_zone_id
1877 [[ :$STC_GENUTILS_DEBUG: == \
1878 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1879 set -x
1880
1881 typeset host=$1
1882
1883 # Check host is localhost or not
1884 typeset ip1=$(getent ipnodes $host | head -1 | awk '{print $1}')
1885 typeset ip2=$(getent ipnodes $(hostname) | head -1 | awk '{print $1}')
1886 if [[ $ip1 == $ip2 ]]; then
1887 typeset zone_id=$(zoneadm -z $(zonename) list -p | awk -F: '{print $1}')
1888 echo $zone_id
1889 return 0
1890 fi
1891
1892 RSH root $host \
1893 "/usr/sbin/zoneadm -z \$(/usr/bin/zonename) list -p" \
1894 > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1895 if (( $? != 0 )); then
1896 echo "$FNAME: rsh to host<$host> failed"
1897 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1898 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1899 return 2
1900 fi
1901 typeset zone_id=$(cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ | awk -F: '{print $1}')
1902
1903 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1904 echo $zone_id
1905 return 0
1906 }
1907
1908 #
1909 # Function to reboot rhost and make sure rsh is available again
1910 #
1911 # A standard model to reboot a remote host for us is:
1912 # 1) before reboot rhost:
1913 # 1.1 ping rhost [OK] # this step needn't checking as we will do 1.2
1914 # 1.2 rsh to create script for rebooting [OK]
1915 # 2) rhost is rebooting:
1916 # 2.1 ping rhost [FAIL] # rhost is down
1917 # 3) after rhost rebooted:
1918 # 3.1 ping rhost [OK] # rhost is up again
1919 # 3.2 rsh rhost to test something [OK]
1920 #
1921 # Usage: reboot_rhost <timer> <rhost> [ boot_arguments ]
1922 # Return: if reboot successfully, return 0;
1923 # if create reboot script on rhost failed, return 1;
1924 # if rhost is not down in 90s after reboot, return 2;
1925 # if rhost is not up again in $timer seconds, return 3;
1926 # if rsh is not available again, return 4.
1927 #
1928 function reboot_rhost {
1929 typeset FNAME=reboot_rhost
1930 [[ :$STC_GENUTILS_DEBUG: == \
1931 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1932 set -x
1933
1934 typeset timer=$1
1935 typeset rhost=$2
1936 shift 2
1937 typeset boot_args=$@
1938
1939 #
1940 # Check rhost is non-global zone or not
1941 #
1942 RSH root $rhost "/usr/bin/zonename" > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1943 if (( $? != 0 )); then
1944 echo "$FNAME: rsh to rhost<$rhost> failed"
1945 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1946 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1947 return 5
1948 fi
1949 typeset zone_name=$(cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$)
1950 typeset -i iszone=1
1951 [[ $zone_name != global ]] && iszone=0
1952
1953 #
1954 # Get current zone id if rhost is non-global zone
1955 #
1956 if (( iszone == 0 )); then
1957 typeset zone_id=$(get_zone_id $rhost)
1958 if (( $? != 0 )); then
1959 echo "$FNAME: get zone id for rhost<$rhost> failed"
1960 echo $zone_id
1961 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1962 return 6
1963 fi
1964 fi
1965
1966 #
1967 # Create rebooting script on rhost and let it run by 'at'
1968 # Notice: To let rhost sleep 10 before reboot is to avoid rsh timeout
1969 #
1970 typeset f2reboot=$STC_GENUTILS_TMPDIR/reboot_by_$(hostname)
1971 RSH root $rhost \
1972 "echo \"#! /usr/bin/ksh -p\" > $f2reboot; \
1973 echo \"/usr/bin/sleep 10\" >> $f2reboot; \
1974 echo \"/usr/sbin/reboot $boot_args\" >> $f2reboot; \
1975 chmod 0755 $f2reboot; \
1976 at -k -f $f2reboot now" \
1977 > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1
1978 if (( $? != 0 )); then
1979 echo "$FNAME: setup job for rebooting on rhost<$rhost> failed"
1980 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
1981 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
1982 return 1
1983 fi
1984
1985 [[ :$STC_GENUTILS_DEBUG: == \
1986 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
1987 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
1988 echo "rhost<$rhost> will reboot in 10s..."
1989
1990 #
1991 # Check rhost is back if rhost is non-global zone
1992 # as reboot a non-global zone is very fast actually
1993 #
1994 # Notice:
1995 # Function get_zone_id() will use RSH, so we don't have to check rsh
1996 # on rhost is available again after reboot.
1997 #
1998 if (( iszone == 0 )); then
1999 sleep 10
2000 typeset zone_id2=0
2001 typeset -i i=0
2002 typeset -i flag=1
2003 while (( i < $timer )); do
2004 zone_id2=$(get_zone_id $rhost)
2005 if [[ $? == 0 && $zone_id != $zone_id2 ]]; then
2006 flag=0
2007 break
2008 fi
2009
2010 sleep 10
2011 (( i += 10 ))
2012 done
2013
2014 if (( flag != 0 )); then
2015 echo "$FNAME: reboot rhost<$rhost> failed in ${timer}s,"
2016 echo "\t rhost is a non-global zone,"
2017 echo "\t and seems never come back, please check it manually"
2018 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2019 return 3
2020 fi
2021
2022 [[ :$STC_GENUTILS_DEBUG: == \
2023 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2024 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2025 echo "rhost<$rhost> is up again..."
2026
2027 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2028 return 0
2029 fi
2030
2031 #
2032 # Wait for rhost is down
2033 # for ping, the default value of timeout is 20 seconds,
2034 # we set it to be 5 seconds to save time.
2035 #
2036 wait_now 90 "! ping $rhost 5 > /dev/null 2>&1" 5
2037 if (( $? != 0 )); then
2038 echo "$FNAME: reboot rhost<$rhost> failed, it seems not down in 90s."
2039 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2040 return 2
2041 fi
2042
2043 [[ :$STC_GENUTILS_DEBUG: == \
2044 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2045 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2046 echo "rhost<$rhost> is down..."
2047
2048 #
2049 # Wait for rhost is up
2050 # If timer = 600, the max timeout is:
2051 # 5 * (600 / 10) + 600 = 900 seconds
2052 #
2053 wait_now $timer "ping $rhost 5 > /dev/null 2>&1" 10
2054 if (( $? != 0 )); then
2055 echo "$FNAME: reboot rhost<$rhost> failed,"
2056 echo "\t it is not responding to pings in ${timer}s,"
2057 echo "\t and seems never come back, please check it manually"
2058 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2059 return 3
2060 fi
2061
2062 [[ :$STC_GENUTILS_DEBUG: == \
2063 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2064 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2065 echo "rhost<$rhost> is up again..."
2066
2067 sleep 30 # wait for services on rhost start
2068
2069 #
2070 # Check rsh on rhost is available again
2071 # If rsh is not availbale, rsh will timeout in N (about 200) seconds, then
2072 # if we call "wait_now $timer 'RSH ...' $interval" will have to wait for
2073 # N * (( $timer / $interval )) + $timer seconds.
2074 #
2075 wait_now 90 \
2076 "RSH root $rhost true > $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$ 2>&1" 30
2077 if (( $? != 0 )); then
2078 echo "$FNAME: reboot rhost<$rhost> failed,"
2079 echo "\t rsh is not available after reboot in 90s,"
2080 echo "\t please check it manually"
2081 cat $STC_GENUTILS_TMPDIR/$FNAME.rsh.$$
2082 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2083 return 4
2084 fi
2085
2086 [[ :$STC_GENUTILS_DEBUG: == \
2087 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2088 echo "[$(date +'%Y-%m-%d %H:%M:%S')] \c" && \
2089 echo "rsh on rhost<$rhost> is available again!"
2090
2091 rm -f $STC_GENUTILS_TMPDIR/$FNAME.*.$$
2092 return 0
2093 }
2094
2095 #
2096 # Function to chech if the passed argument is a device name or not.
2097 # Usage: is_device_name <name>
2098 #
2099 function is_device_name {
2100 typeset FNAME=is_device_name
2101 [[ :$STC_GENUTILS_DEBUG: == \
2102 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2103 set -x
2104
2105 typeset name=$1
2106 name=/dev/dsk/$name
2107
2108 ls ${name}* >/dev/null 2>&1
2109 return $?
2110 }
2111
2112 # Description
2113 # A function to get the name of the test case which is generated
2114 # dynamically.
2115 # Usage:
2116 # get_casename prefix index
2117 # Return:
2118 # The function returns the name of the case.
2119 #
2120 function get_casename {
2121 typeset FNAME=get_casename
2122 [[ :$STC_GENUTILS_DEBUG: == \
2123 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2124 set -x
2125
2126 typeset prefix=$1
2127 typeset ind=$2
2128 if (( $ind < 10 )); then
2129 tname=${prefix}00${ind}
2130 elif (( $ind < 100 )); then
2131 tname=${prefix}0${ind}
2132 else
2133 tname=${prefix}${ind}
2134 fi
2135 echo $tname
2136 }
2137
2138 # Description:
2139 # A function to extract the assertion information from the test source file.
2140 # Usage:
2141 # extract_assertion_info test_src_filename
2142 # Return:
2143 # The function only prints the info, nothing is returned.
2144 #
2145 function extract_assertion_info {
2146 typeset FNAME=extract_assertion_info
2147 [[ :$STC_GENUTILS_DEBUG: == \
2148 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2149 set -x
2150
2151 typeset FILE=$1
2152 echo "==================================================================="
2153 nawk \
2154 '$2 ~ /__stc_assertion_start/,/__stc_assertion_end/ { print $0}' \
2155 $FILE | sed -e 's/^#//' -e '/__stc_assertion_/d'
2156 echo "==================================================================="
2157 }
2158
2159 #
2160 # Description
2161 # A function used to block the network communication between two machines
2162 # Usage:
2163 # ipf_network
2164 # -t timeout // timeout before restore ipfilter setting
2165 # -f blockflagfile // restore ipfilter setting once the flagfile
2166 # removed
2167 # -k feedbackfile // remove the feedbackfile once ipfilter was
2168 # applied, used to tell user the network already
2169 # blocked
2170 # -v ip_version // ipv4 or ipv6.
2171 # -r rules // ipfilter rules where hostname rather than ip is used.
2172 # example: ipf_network -s flowerbud -t 100 -f /tmp/blockflagfile
2173 # -r "block in from flowerpot"
2174 # -r "pass in from flowerpot to port != 513
2175 # Return:
2176 # 0: success
2177 # other: failure
2178 # Notes:
2179 # This function calls smf_fmri_transition_state() and smf_get_state()
2180 # functions which locate in include/libsmf.shlib of STC genutils tool,
2181 # so the caller should source the lib file before using this function.
2182 #
2183 function ipf_network
2184 {
2185 typeset FNAME=ipf_network
2186 [[ :$STC_GENUTILS_DEBUG: == \
2187 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2188 set -x
2189
2190 typeset IPF_TIMEOUT=90
2191 typeset blockflagfile=""
2192 typeset feedbackfile=""
2193 typeset enabled=0
2194 typeset rulesfile="$STC_GENUTILS_TMPDIR/ipf_cmd_file"
2195 typeset IPF_FMRI=svc:/network/ipfilter:default
2196
2197 rm -f $rulesfile
2198 while getopts "t:f:k:v:r:" opt; do
2199 case $opt in
2200 t) timeout=$OPTARG;;
2201 f) blockflagfile=$OPTARG;;
2202 k) feedbackfile=$OPTARG;;
2203 v) ip_version=$OPTARG;;
2204 r) echo $OPTARG >> $rulesfile;;
2205 ?) echo "undefined argument"; return 1;;
2206 esac
2207 done
2208
2209 echo "Start to ipf_network... "
2210 typeset -i ret_v4 ret_v6=0
2211 [[ `smf_get_state $IPF_FMRI` == online ]] && enabled=1
2212 if (( $enabled != 1 )); then
2213 echo "ipfilter service is not online"
2214 RUN_CHECK smf_fmri_transition_state do \
2215 $IPF_FMRI online $IPF_TIMEOUT || return 1
2216 sleep 5
2217 else
2218 # backup original rules
2219 ipfstat -i > $STC_GENUTILS_TMPDIR/ipfilter_in
2220 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_in \
2221 || mv $STC_GENUTILS_TMPDIR/ipfilter_in $STC_GENUTILS_TMPDIR/ipfilter_ori
2222 ipfstat -o > $STC_GENUTILS_TMPDIR/ipfilter_out; ret_v4=$?
2223 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_out \
2224 || cat $STC_GENUTILS_TMPDIR/ipfilter_out >> $STC_GENUTILS_TMPDIR/ipfilter_ori
2225 rm -f $STC_GENUTILS_TMPDIR/ipfilter_in $STC_GENUTILS_TMPDIR/ipfilter_out
2226 if [[ $ip_version == ipv6 ]]; then
2227 ipfstat -6 -i > $STC_GENUTILS_TMPDIR/ipfilter_in_v6
2228 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_in_v6 \
2229 || mv $STC_GENUTILS_TMPDIR/ipfilter_in_v6 $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2230 ipfstat -6 -o > $STC_GENUTILS_TMPDIR/ipfilter_out_v6; ret_v6=$?
2231 grep "empty list for ipfilter" $STC_GENUTILS_TMPDIR/ipfilter_out_v6 \
2232 || cat $STC_GENUTILS_TMPDIR/ipfilter_out_v6 >> $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2233 rm -f $STC_GENUTILS_TMPDIR/ipfilter_in_v6 $STC_GENUTILS_TMPDIR/ipfilter_out_v6
2234 fi
2235 if (( $ret_v4 != 0 )) || (( $ret_v6 != 0 )); then
2236 echo "failed to backup original ipfilter rules"
2237 cat $STC_GENUTILS_TMPDIR/ipfilter_ori $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2238 rm -f $STC_GENUTILS_TMPDIR/ipfilter_in \
2239 $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2240 $rulesfile
2241 return 1
2242 fi
2243 fi
2244
2245 echo "apply new rules"
2246 ipf -Fa -f $rulesfile > $STC_GENUTILS_TMPDIR/ipf.out.$$ 2>&1
2247 ret_v4=$?
2248 if [[ $ip_version == ipv6 ]]; then
2249 ipf -6 -Fa -f $rulesfile >> $STC_GENUTILS_TMPDIR/ipf.out.$$ 2>&1
2250 ret_v6=$?
2251 fi
2252 if (( $ret_v4 != 0 )) || (( $ret_v6 != 0 )); then
2253 echo "failed to apply new rules"
2254 cat $STC_GENUTILS_TMPDIR/ipf.out.$$
2255 rm -f $STC_GENUTILS_TMPDIR/ipf.out.$$ \
2256 $STC_GENUTILS_TMPDIR/ipfilter_ori \
2257 $STC_GENUTILS_TMPDIR/ipfilter_ori_v6
2258 return 1
2259 fi
2260
2261 RUN_CHECK smf_fmri_transition_state check \
2262 $IPF_FMRI online $IPF_TIMEOUT || return 1
2263 sleep 5
2264
2265 # remove the feedbackfile to tell user network already blocked
2266 [[ -n $feedbackfile ]] && rm $feedbackfile
2267
2268 # wait blockflagfile removed or timeout
2269 if [[ -n $blockflagfile ]]; then
2270 wait_now $timeout "[[ ! -f $blockflagfile ]]" > /dev/null 2>&1
2271 else
2272 sleep $timeout
2273 rm -f $blockflagfile
2274 fi
2275
2276 # restore ipfilter settings
2277 echo "restore ipfilter settings"
2278 if (( $enabled != 1 )); then
2279 echo "disable ipfilter service on $host"
2280 RUN_CHECK smf_fmri_transition_state do \
2281 $IPF_FMRI disabled $IPF_TIMEOUT || return 1
2282 else
2283 echo "apply original rules on $host"
2284 RUN_CHECK ipf -Fa -f $STC_GENUTILS_TMPDIR/ipfilter_ori || return 1
2285 if [[ $ip_version == ipv6 ]]; then
2286 ipf -6 -Fa -f $STC_GENUTILS_TMPDIR/ipfilter_ori_v6 || return 1
2287 fi
2288 RUN_CHECK smf_fmri_transition_state check \
2289 $IPF_FMRI online $IPF_TIMEOUT || return 1
2290 fi
2291 sleep 5
2292
2293 echo "ipf_network finished"
2294 rm -f $STC_GENUTILS_TMPDIR/ipf.out.$$ $rulesfile
2295 return 0
2296 }
2297
2298 #
2299 # Function: get_zpool_name
2300 # get the zpool name of a zfs filesystem and print out
2301 # Usage:
2302 # get_zpool_name <fs name>
2303 # Return:
2304 # always return 0 unless fs name is null string
2305 #
2306 function get_zpool_name {
2307 typeset FNAME=get_zpool_name
2308 [[ :$STC_GENUTILS_DEBUG: == \
2309 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2310 set -x
2311
2312 typeset fs_name=$1
2313 [[ -z $fs_name ]] && return 1
2314 typeset zpool_name=$(echo $fs_name | awk -F\/ '{print $1}')
2315
2316 echo $zpool_name
2317 return 0
2318 }
2319
2320 #
2321 # Function: get_zpool_stat
2322 # get the status of a zpool and print out
2323 # Usage:
2324 # get_zpool_stat <zpool name>
2325 # Return:
2326 # return 0 if successful
2327 #
2328 function get_zpool_stat {
2329 typeset FNAME=get_zpool_stat
2330 [[ :$STC_GENUTILS_DEBUG: == \
2331 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2332 set -x
2333
2334 typeset zpool_name=$1
2335 [[ -z $zpool_name ]] && return 1
2336
2337 typeset zpool_stat=""
2338 typeset f1=$STC_GENUTILS_TMPDIR/get_zpool_stat.out.$$
2339 typeset f2=$STC_GENUTILS_TMPDIR/get_zpool_stat.err.$$
2340
2341 /usr/sbin/zpool list -H -o health $zpool_name > $f1 2>$f2
2342 typeset -i rc=$?
2343 (( rc == 0 )) && zpool_stat=$(cat $f1) || zpool_stat=$(cat $f2)
2344 echo $zpool_stat
2345 rm -f $f1 $f2
2346 return $rc
2347 }
2348
2349 #
2350 # ------------------
2351 # Function: get_fstype
2352 # ------------------
2353 # This function is to check what type of filesystem of a directory,
2354 # then print related information out as such format,"
2355 # <FAIL|OKAY> <fs type> <fs name | <zpool name> [zpool stat]>"
2356 # and return 0 if OKAY or return 1 if FAIL."
2357 #
2358 # Usage: get_fstype <directory name>"
2359 # e.g. get_fstype /export/foo # print OKAY zfs rpool ONLINE"
2360 # e.g. get_fstype /ufsdisk/d1 # print OKAY ufs /dev/dsk/c0t1d0s3"
2361 # e.g. get_fstype /tmp/dirxxx # print OKAY tmpfs swap"
2362 # e.g. get_fstype /proc/12345 # print OKAY proc proc"
2363 # e.g. get_fstype /home # print OKAY autofs auto.home"
2364 # e.g. get_fstype /ws/onnv-gate # print OKAY nfs onnv.sfbay:/export/onnv-gate
2365 #
2366 # Return 0 and print related information if successful, otherwise return 1
2367 #
2368 function get_fstype {
2369 typeset FNAME=get_fstype
2370 [[ :$STC_GENUTILS_DEBUG: == \
2371 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2372 set -x
2373
2374 [[ $# != 1 ]] && echo "ERROR: No directory privided" && return 1
2375
2376 typeset dir=$1
2377 [[ -z $dir ]] && return 1
2378 typeset basepath=$dir
2379 typeset strout=""
2380
2381 #
2382 # get base path of dir which does not exist
2383 #
2384 if [[ ! -d $dir ]]; then
2385 typeset pdir="" # dir begins with a relative path
2386 [[ $dir == /* ]] && pdir="/" # dir begins with an absolute path
2387 typeset d=""
2388 for d in $(echo $dir | sed 's%/% %g'); do
2389 if [[ -z $pdir ]]; then
2390 pdir=$d
2391 else
2392 [[ $pdir == "/" ]] && pdir=/$d || pdir=$pdir/$d
2393 fi
2394
2395 if [[ ! -d $pdir ]]; then
2396 basepath=$(dirname $pdir)
2397 break
2398 fi
2399 done
2400 fi
2401
2402 #
2403 # get filesystem type: ufs, zfs, tmpfs, ...
2404 #
2405 typeset fs_type=$(/usr/sbin/df -n $basepath | awk '{print $3}')
2406
2407 #
2408 # get filesystem name
2409 # e.g.
2410 # +---------+---------+-------------------+
2411 # | dir | fs_type | fs_name |
2412 # +---------+---------+-------------------+
2413 # | /root | ufs | /dev/dsk/c0t4d0s0 |
2414 # | /tmp | tmpfs | swap |
2415 # | /export | zfs | rpool/export |
2416 # | /proc | proc | proc |
2417 # +---------+---------+-------------------+
2418 #
2419 typeset fs_name=$(/usr/sbin/df $basepath | awk -F\( '{print $2}' \
2420 | awk -F\) '{print $1}')
2421
2422 if [[ $fs_type == "zfs" ]]; then
2423 strout=$fs_type
2424
2425 zpool_name=$(get_zpool_name $fs_name)
2426 if (( $? != 0 )); then
2427 echo "FAIL $strout \n$zpool_name"
2428 return 1
2429 fi
2430 strout="$strout $zpool_name"
2431
2432 zpool_stat=$(get_zpool_stat $zpool_name)
2433 if (( $? != 0 )); then
2434 echo "FAIL $strout \n$zpool_stat"
2435 return 1
2436 fi
2437 strout="$strout $zpool_stat"
2438 else
2439 strout="$fs_type $fs_name"
2440 fi
2441
2442 echo OKAY $strout
2443 return 0
2444 }
2445
2446 # check_knfs - function to check if the client can use kerberos to
2447 # access nfs server successfully. If <client> is set to
2448 # "localhost", then we don't need to call rsh for the check.
2449 # <client> can be set to multiple machines
2450 # Usage: check_knfs <server> <client>
2451 # Return: 0 on success, 1 on error, 2 if not supported
2452 function check_knfs {
2453 typeset FNAME=check_knfs
2454 [[ :$STC_GENUTILS_DEBUG: == \
2455 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2456 set -x
2457
2458 typeset server=$1
2459 typeset clients=$2
2460 typeset KRB5_SHRDIR=$ZONE_PATH/krb5_shr
2461 typeset KRB5_MNTDIR=$ZONE_PATH/krb5_mnt
2462 typeset logfile=$STC_GENUTILS_TMPDIR/$FNAME.$$
2463
2464 # the server is always a remote machine
2465 SRV_CMD="RSH root $server"
2466 # share with krb5 authentication
2467 $SRV_CMD "mkdir -p $KRB5_SHRDIR && \
2468 share -o sec=krb5 $KRB5_SHRDIR && sleep 2" \
2469 > $logfile 2>&1
2470 ckresult $? "$FNAME: failed to share $KRB5_SHRDIR on $server" $logfile \
2471 || return 1
2472
2473 for clt in $clients; do
2474 [[ $clt == localhost ]] && \
2475 CLT_CMD=RUN_CHECK || CLT_CMD="RSH root $clt"
2476
2477 # mount it and check mount options
2478 $CLT_CMD "mkdir -p $KRB5_MNTDIR" || return 1
2479 $CLT_CMD "mount -o sec=krb5 $server:$KRB5_SHRDIR $KRB5_MNTDIR" \
2480 > $logfile 2>&1
2481 # verify if mount succeeded
2482 $CLT_CMD "mount -p | grep $server:$KRB5_SHRDIR | grep sec=krb5" \
2483 >> $logfile 2>&1
2484 ckresult $? "$FNAME: failed to mount $server:$KRB5_SHRDIR on $clt" \
2485 $logfile || return 1
2486
2487 # clean up
2488 $CLT_CMD "umount -f $KRB5_MNTDIR && rm -rf $KRB5_MNTDIR"
2489 done
2490
2491 $SRV_CMD "unshare $KRB5_SHRDIR && rm -rf $KRB5_SHRDIR" \
2492 2>$logfile
2493 ckresult $? "$FNAME: failed to unshare $server:$KRB5_SHRDIR" $logfile
2494
2495 return 0
2496 }
2497
2498 #
2499 # Function get_DNS_INFO
2500 #
2501 # get dns domain or nameserver from /etc/resolv.conf,
2502 # if fails, then set it to default value which is specified
2503 # as the third parameter.
2504 # Usage:
2505 # get_DNS_INFO <key> <host> <default>
2506 # key - key should be "domain" or "nameserver",
2507 # if key is "domain", we get dns domain;
2508 # if key is "nameserver", we get dns nameserver.
2509 # host - hostname, if it's local host, just set to "localhost".
2510 # default - default value for domain or nameserver.
2511 # Return:
2512 # if key is valid, return 0 and print domain or nameserver.
2513 #
2514 function get_DNS_INFO {
2515 typeset FNAME=get_DNS_INFO
2516 [[ :$STC_GENUTILS_DEBUG: == \
2517 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2518 set -x
2519
2520 typeset -l key=$1
2521 typeset -l host=$2
2522 typeset default=$3
2523 typeset CMD=""
2524 [[ $host != localhost ]] && CMD="RSH root $host "
2525
2526 case $key in
2527 domain)
2528 typeset domain=$(${CMD}egrep "^$key" /etc/resolv.conf 2>/dev/null \
2529 | awk '{print $2}')
2530 [[ -z $domain ]] && domain=$default
2531 typeset -l str=$domain
2532 ;;
2533
2534 nameserver)
2535 typeset nameserver=$(${CMD}nslookup www.sun.com 2>/dev/null \
2536 | egrep "^Server:" | awk '{print $2}')
2537 [[ -z $nameserver ]] && nameserver=$default
2538 typeset -l str=$nameserver
2539 ;;
2540
2541 *)
2542 print -u2 "$FNAME: invalid key, must be domain or nameserver"
2543 return 1
2544 ;;
2545 esac
2546
2547 echo $str
2548 return 0
2549 }
2550
2551 #
2552 # Function: is_IPv6
2553 # Check if current system communicate with remote system via IPv6
2554 # Usage:
2555 # is_IPv6 <remote_host>
2556 # Return:
2557 # 0 and print IPv4 address
2558 # 1 and print IPv6 address
2559 # 2 and print error message
2560 #
2561 function is_IPv6 {
2562 typeset FNAME=is_IPv6
2563 [[ :$STC_GENUTILS_DEBUG: == \
2564 @(*:$FNAME:*|*:nfs-util.kshlib:*|*:genutils:*) ]] && \
2565 set -x
2566
2567 typeset rhost=$1
2568 typeset rhost_ip=""
2569 typeset -i ret=0
2570
2571 getent ipnodes $rhost | grep -i $rhost > $STC_GENUTILS_TMPDIR/getent.$$ 2>&1
2572 if (( $? != 0 )); then
2573 echo "failed to get <$rshost>'s IP:"
2574 cat $STC_GENUTILS_TMPDIR/getent.$$
2575 rm -f $STC_GENUTILS_TMPDIR/getent.$$
2576 return 2
2577 fi
2578
2579 rhost_ip=$(head -1 $STC_GENUTILS_TMPDIR/getent.$$ | awk '{print $1}')
2580 [[ $rhost_ip == *":"* ]] && ret=1
2581 echo "$rhost_ip"
2582 rm -f $STC_GENUTILS_TMPDIR/getent.$$
2583 return $ret
2584 }
2585