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 2008 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
25 #
26
27 # any of the *_wait_* functions that take a timeout will use this value
28 # if none is supplied by the caller.
29 typeset lib_wait_time=${DEFAULT_WAIT_TIME:-30}
30
31
32 #############################################################################
33 # Function Name: verify_daemon
34 # Purpose:
35 # verify that the startd is executing
36 # Arguments: none
37 # returns:
38 # true if the master starter is executing
39 #############################################################################
40 function verify_daemon {
41 typeset ret_value=0
42
43 typeset -f check_gl_env >/dev/null
44 typeset thiszone=`zonename`
45 if [ $? -ne 0 ]; then
46 test -n "`pgrep -z $thiszone svc.startd`"
47 ret_value=$?
48 if [ $ret_value -ne 0 ]; then
49 ret_value=2
50 fi
51 else
52 check_gl_env
53 ret_value=$?
54 fi
55 if [ $ret_value -eq 2 ]; then
56 if [ `/usr/xpg4/bin/id -u` = 0 ]; then
57 (exec 1>/dev/sysmsg 2>/dev/sysmsg;
58 /lib/svc/bin/svc.startd)
59 fi
60 sleep 5
61 test -n "`pgrep -z $thiszone svc.startd`"
62 ret_value=$?
63 fi
64 return $ret_value
65 }
66
67
68 #############################################################################
69 # Function Name: feature_test
70 # Purpose:
71 # *cough* verify *cough* the availability of certain features for testing
72 # in the starter. This is based on the existence of variables set in the
73 # environment. All the passed 'features' need to be set in order for the
74 # test to be useful.
75 # Arguments:
76 # ... - each feature to test
77 # Returns:
78 # true if all the features passed exist.
79 # Output:
80 # text stating what features are missing
81 #
82 #############################################################################
83 function feature_test {
84 typeset output=
85 typeset lv=
86
87 while [ -n "$1" ]; do
88 eval "lv=${1}_AVAILABLE"
89 eval "lv=\$$lv"
90 if [ "$lv" != 1 ]; then
91 output="$output $1"
92 fi
93 shift
94 done
95 if [ -n "$output" ]; then
96 echo "$output"
97 return 1
98 fi
99 return 0
100 }
101
102
103 #############################################################################
104 # Function Name: fmri_to_assign
105 # Purpose:
106 # break an frmi up into a string of service= and instance=
107 # Return:
108 # Ignore
109 # Output:
110 # string of the service=<service>;instance=<instance> or empty.
111 # Note:
112 # this is ugly.
113 #
114 #############################################################################
115 function fmri_to_assign {
116 print $1 | /usr/xpg4/bin/sed -n \
117 's@\(svc:\)*/*\(/localhost/\)*\(.*\):\(.*\)@service=\3;instance=\4@p'
118 }
119
120
121 #############################################################################
122 # Function Name: service_count_method
123 # Purpose:
124 # Count the invocation of a certain method.
125 # Arguments:
126 # $1 - service to count
127 # $2 - method to count
128 # Return:
129 # count of invocations.
130 #
131 #############################################################################
132 function service_count_method {
133 typeset service=
134 typeset instance=
135 typeset call=$2
136 typeset statef=`svcprop -p cfg/state $1`
137 statef=${statef:+-f $statef}
138 typeset nsec=0
139 typeset lastcall=
140
141 # translate FMRI to service= and instance=
142 eval `fmri_to_assign $1`
143 if [ -z "$service" -o -z "$instance" ]; then
144 print -- "--INFO: invalid FMRI($1) passed in"
145 return 255
146 fi
147
148 service_countcall -s $service -i $instance $statef
149 return $?
150 }
151
152
153 #############################################################################
154 # Function Name: service_check_method
155 # Purpose
156 # Check the invocation of a certain method was the last invoked method
157 # Arguments:
158 # $1 - FMRI of service
159 # $2 - method to check
160 # Returns:
161 # 0 - method was invoked; 1 otherwise
162 #
163 #############################################################################
164 function service_check_method {
165 typeset service=
166 typeset instance=
167 typeset call=$2
168 typeset statef=`svcprop -p cfg/state $1`
169 statef=${statef:+-f $statef}
170 typeset nsec=0
171 typeset lastcall=
172
173 # translate FMRI to service= and instance=
174 eval `fmri_to_assign $1`
175 if [ -z "$service" -o -z "$instance" ]; then
176 print -- "--INFO: invalid FMRI($1) passed in"
177 return 255
178 fi
179
180 lastcall=`service_lastcall -s $service -i $instance $statef`
181 if [ "$lastcall" = "$call" ]; then
182 return 0
183 fi
184 return 1
185 }
186
187
188 #############################################################################
189 # Function Name: service_wait_method
190 # Purpose:
191 # Wait for a certain method to be called from the test service
192 # Arguments:
193 # $1 - FMRI of service
194 # $2 - method to wait for
195 # $3 - [ optional ] timeout
196 # Returns:
197 # 0 - method was invoked; 1 otherwise
198 #
199 #############################################################################
200 function service_wait_method {
201 typeset fmri="$1"
202 typeset call=$2
203 typeset wait_time=${3:-$lib_wait_time}
204 typeset nsec=0
205 typeset lastcall=
206
207 while [ $nsec -le $wait_time ]; do
208 service_check_method "$fmri" $call
209 if [ $? -eq 0 ]; then
210 return 0
211 fi
212 sleep 1
213 nsec=$((nsec + 1))
214 done
215 return 1
216 }
217
218
219 #############################################################################
220 # Function Name: manifest_generate
221 # Purpose:
222 # generate a manifest file to stdout from the manifest template
223 # it pattern replaces KEY=<value> pairs passed in on the command line
224 # Arguments:
225 # [ <KEY0>=<VAL0> ] ... [ <KEYN>=<VALN> ]
226 # Return:
227 # Don't Care
228 # Output:
229 # text of new file
230 # XXX: should this function be changed to take input from stdout? It's kind
231 # of asymmetric.
232 #
233 #############################################################################
234 function manifest_generate {
235 typeset file=$1
236 typeset tfile=/tmp/mgfile$$
237 typeset tfile2=/tmp/mgfile2.$$
238 typeset keyval=
239 typeset key=
240 typeset val=
241
242 shift
243 cat $file > $tfile
244 while [ -n "$1" ]; do
245 keyval="$1"
246 eval `echo $keyval | sed 's/\([^=]*\)=\(.*\)/key="\1";val="\2"/'`
247 sed -e "s!$key!$val!g" $tfile > $tfile2
248 mv $tfile2 $tfile
249 shift
250 done
251 cat $tfile
252 rm -f $tfile $tfile2
253 }
254
255 #############################################################################
256 # Function Name: manifest_zone_clean
257 # Purpose:
258 # verify the manifest file is setup correctly for a zone based on
259 # known zone setting differences. Ignore any keywords that are
260 # given.
261 # Aruments:
262 # keyword0 ... keywordn
263 # Return:
264 # Don't Care
265 # Output:
266 # none
267 #############################################################################
268 function manifest_zone_clean {
269 typeset file=$1
270 typeset tfile=/tmp/mgfile$$
271 typeset tfile2=/tmp/mgfile2.$$
272
273 if [ "`/bin/zonename`" == "global" ]; then
274 return
275 fi
276
277 set -A zone_in "limit_privileges=\"all"
278 set -A zone_out "limit_privileges=\"zone"
279
280 shift
281 keywords=$@
282
283 n=0
284 cat $file > $tfile
285 while [ -n "${zone_in[$n]}" ]; do
286 ignore=0
287 for keyw in $keywords
288 do
289 echo ${zone_in[$n]} | grep -w $keyw > /dev/null 2>&1
290 if [ $? -eq 0 ]
291 then
292 ignore=1
293 break
294 fi
295 done
296 if [ $ignore -eq 0 ]; then
297 eval sed -e 's/${zone_in[$n]}/${zone_out[$n]}/g \
298 $tfile' > $tfile2
299 mv $tfile2 $tfile
300 fi
301 n=`expr $n + 1`
302 done
303
304 mv $tfile $file
305 rm -f $tfile2
306 }
307
308
309 #############################################################################
310 # Function Name: property_alter
311 # Purpose:
312 # Alter/create a service's property in the repository. This property
313 # will be set to the astring type, unless you state otherwise
314 # the new value may be specified as: 'type: (<value>)', which makes it
315 # of that type.
316 # Arguments:
317 # $1 - FMRI who's property we want to tweak
318 # $2 - property to tweak
319 # $3 - <NEW VALUE> - optional.
320 # Returns:
321 # return code from svccfg.
322 #
323 #############################################################################
324 function property_alter {
325 typeset fmri="$1"
326 typeset property="$2"
327 typeset newvalue="$3"
328
329 if [ $# -lt 2 ]; then
330 echo --DIAG: property_alter: insufficient parameters
331 return 1
332 fi
333
334 if [ -z "$newvalue" ]; then
335 svccfg -f - <<-EOM
336 select $fmri
337 delprop $property
338 end
339 EOM
340 else
341 # XXX: hackish WRT parenthesis
342 echo $newvalue | grep ')$' >/dev/null
343 if [ $? -ne 0 ]; then
344 newvalue="astring: \"$newvalue\""
345 fi
346 svccfg -f - <<-EOM
347 select $fmri
348 setprop $property = $newvalue
349 end
350 EOM
351 fi
352
353 return $?
354 }
355
356
357 #############################################################################
358 # Function Name: propgroup_remove
359 # Purpose:
360 # remove a specified property group
361 # Arguments:
362 # $1 - FMRI of service who's property to remove
363 # $2 - property group to remove
364 # Returns:
365 # return code from svccfg
366 #
367 #############################################################################
368 function propgroup_remove {
369 typeset fmri="$1"
370 typeset pg="$2"
371
372 if [ -z "$fmri" -o -z "$pg" ]; then
373 return 1
374 fi
375 svccfg -f - <<-EOM
376 select $fmri
377 delpg $pg
378 end
379 EOM
380 return $?
381 }
382
383
384 #############################################################################
385 # Function Name: service_dependency_add
386 # Purpose:
387 # add a dependency to a service
388 # if any of the dependency FMRI's start with file:/ then the dependency
389 # will be recorded as a path type dependency.
390 # Arguments:
391 # $1 - Name of FMRI to place dependency under
392 # $2 - dependency group name (for removal later)
393 # $3 - dependency grouping - require_(all|any), exclude_(all|any)
394 # $4 - restart_on semantics - error
395 # $5... - dependency FMRI's
396 # Returns:
397 # non zero if the dependency could not be added for any reason
398 #
399 #############################################################################
400 function service_dependency_add {
401 typeset function=service_dependency_add
402 typeset log=/tmp/log_depadd.$$
403
404 if [ $# -lt 5 ]; then
405 print -- "--DIAG: not enough arguments for $function"
406 return 1
407 fi
408
409 typeset fmri="$1"
410 typeset depname="$2"
411 typeset depgrouping="$3"
412 typeset deprestarton="$4"
413 typeset depstring=""
414 typeset deptype="service"
415 shift 4
416
417 while [ -n "$1" ]; do
418 if [ -n "$depstring" ]; then
419 depstring="$depstring $1"
420 else
421 depstring="$1"
422 fi
423 if [ "${1%:/*}" = "file" ]; then
424 deptype="path"
425 fi
426 shift
427 done
428 svccfg >$log 2>&1 <<-EOM
429 select $fmri
430 addpg $depname dependency
431 setprop $depname/grouping = astring: ("$depgrouping")
432 setprop $depname/restart_on = astring: ("$deprestarton")
433 setprop $depname/type = astring: ("$deptype")
434 setprop $depname/entities = fmri: ("$depstring")
435 end
436 EOM
437 if [ $? -ne 0 ]; then
438 print -- "--DIAG: could not add dependency; reason:"
439 print -- " \"$(cat $log)\""
440 rm -f $log
441 return 1
442 fi
443 rm -f $log
444 return 0
445 }
446
447
448 #############################################################################
449 # Function Name: service_dependency_remove
450 # Purpose:
451 # remove a dependency from a service
452 # Arguments:
453 # $1 - service fmri
454 # $2 - dependency name
455 # Returns: non-zero if dependency group could not be removed
456 #
457 #############################################################################
458 function service_dependency_remove {
459 typeset function=service_dependency_remove
460 typeset log=/tmp/logdep_rem.$$
461
462 if [ $# -ne 2 ]; then
463 print -- "--DIAG: wrong argument count for $function"
464 return 1
465 fi
466 svccfg >$log 2>&1 <<-EOM
467 select $1
468 delpg $2
469 end
470 EOM
471 if [ $? -ne 0 ]; then
472 print -- "--DIAG: could not remove dependency; reason:"
473 print -- " \"$(cat $log)\""
474 rm -f $log
475 return 1
476 fi
477 rm -f $log
478 return 0
479 }
480
481
482 #############################################################################
483 # Function Name: service_dependency_elt_remove
484 # Purpose:
485 # remove a dependency element from a dependency
486 # Arguments:
487 # $1 - service
488 # $2 - dependency group
489 # $3... - dependency strings to remove
490 # Return:
491 # non-zero if the dependency elements could not be removed
492 #
493 #############################################################################
494 function service_dependency_elt_remove {
495 typeset function=service_dependency_elt_remove
496 typeset log=/tmp/logdep_eltrem.$$
497
498 if [ $# -lt 3 ]; then
499 print -- "--DIAG: wrong argument count($#) for $function"
500 return 1
501 fi
502 typeset fmri=$1
503 typeset depgroup=$2
504 shift 2
505
506 typeset props=`svcprop -p $depgroup/entities $fmri 2>$log`
507
508 if [ $? -ne 0 ]; then
509 print -- "--DIAG: could not retrieve service information"
510 print -- " reason: "$(cat $log)""
511 rm -f $log
512 return 1
513 fi
514 while [ -n "$1" ]; do
515 props=`echo $props | sed "s!$1!!"`
516 shift
517 done
518 svccfg >$log 2>&1 <<-EOM
519 select $fmri
520 setprop $depgroup/entities = fmri: ("$props")
521 end
522 EOM
523 if [ $? -ne 0 ]; then
524 print -- "--DIAG: could not write dependency entities($props)"
525 print -- " reason: \"$(cat $log)\""
526 rm -f $log
527 return 1
528 fi
529 rm -f $log
530 return 0
531 }
532
533
534 #############################################################################
535 # Function Name: service_dependency_elt_add
536 # Purpose:
537 # add a dependency element from a dependency
538 # Arguments:
539 # $1 - service
540 # $2 - dependency group
541 # $3... - dependency fmris to add
542 # Return:
543 # non-zero if the dependency element could not be added
544 #
545 #############################################################################
546 function service_dependency_elt_add {
547 typeset function=service_dependency_elt_add
548 typeset log=/tmp/logdep_eltrem.$$
549
550 if [ $# -lt 3 ]; then
551 print -- "--DIAG: wrong argument count($#) for $function"
552 return 1
553 fi
554 typeset fmri=$1
555 typeset depgroup=$2
556 shift 2
557 typeset props=`svcprop -p $depgroup/entities $fmri 2>$log`
558
559 if [ $? -ne 0 ]; then
560 print -- "--DIAG: could not retrieve service information"
561 print -- " reason: "$(cat $log)""
562 rm -f $log
563 return 1
564 fi
565 while [ -n "$1" ]; do
566 props="$props $1"
567 shift
568 done
569
570 typeset newprops=""
571 for prop in $props; do
572 newprops="\"$prop\" $newprops"
573 done
574 svccfg >$log 2>&1 <<-EOM
575 select $fmri
576 setprop $depgroup/entities = fmri: ($newprops)
577 end
578 EOM
579 if [ $? -ne 0 ]; then
580 print -- "--DIAG: could not write dependency entities($props)"
581 print -- " reason: \"$(cat $log)\""
582 rm -f $log
583 return 1
584 fi
585 rm -f $log
586 return 0
587 }
588
589
590 #############################################################################
591 # Function Name: grep_logline_entry
592 # Purpose:
593 # get a specific log line entry from the service log.
594 # if a log file is not specified it will get the entry from the
595 # cfg/log property group of the service instance.
596 # Arguments:
597 # $1 - service
598 # $2 - instance
599 # $3 - method
600 # $4 - entry
601 # $5 - logfile [ optional ]
602 # Returns:
603 # non-zero if the line was not found
604 # Output:
605 # the last line where the elements matched the term
606 #
607 #############################################################################
608 function grep_logline_entry {
609 typeset function=grep_logline_entry
610 typeset service="$1"
611 typeset instance="$2"
612 typeset method="$3"
613 typeset entry="$4"
614 typeset logfile="$5"
615
616 if [ $# -lt 4 ]; then
617 print -- "--DIAG: $function: insufficient arguments($#)"
618 return 1
619 fi
620 if [ -z "$logfile" ]; then
621 logfile=`svcprop -p cfg/log $service:$instance`
622 fi
623
624 if [ -z "$logfile" ]; then
625 print -- "--DIAG: $function: could not get logfile"
626 return 1
627 fi
628
629 text=`sed -n -e "s!.*<$entry service=\"$service\" instance=\"$instance\" method=\"$method\" $entry=\"\(.*\)\".*!\1!p" $logfile | tail -1`
630 if [ -n "$text" ]; then
631 echo $text
632 return 0
633 fi
634 return 1
635 }