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 }