1 #!/usr/bin/ksh
   2 #
   3 # CDDL HEADER START
   4 #
   5 # The contents of this file are subject to the terms of the
   6 # Common Development and Distribution License (the "License").
   7 # You may not use this file except in compliance with the License.
   8 #
   9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10 # or http://www.opensolaris.org/os/licensing.
  11 # See the License for the specific language governing permissions
  12 # and limitations under the License.
  13 #
  14 # When distributing Covered Code, include this CDDL HEADER in each
  15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16 # If applicable, add the following below this CDDL HEADER, with the
  17 # fields enclosed by brackets "[]" replaced with your own identifying
  18 # information: Portions Copyright [yyyy] [name of copyright owner]
  19 #
  20 # CDDL HEADER END
  21 #
  22 
  23 #
  24 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  25 # Use is subject to license terms.
  26 #
  27 # dom_functions.sh - functions used to test the domain rules for nfsmapid
  28 #
  29 # Note: Some functions in this file uses ckreturn(), a function defined in 
  30 #       testsh.ksh. Please make sure you have already source'd that file 
  31 #       before you source this file.
  32 
  33 # print_state - dumps all information possibly used by nfsmapid to obtain a
  34 #       domain value from different sources.
  35 # all information is sent to stderr, return value is always 0
  36 #
  37 
  38 function print_state {
  39         echo "\n>>>>>>>>>>>>>>>>>>>>>> DEBUG INFORMATION <<<<<<<<<<<<<<<<<<<<<"
  40         echo "============== NFSMAPID_DOMAIN in /etc/default/nfs ============="
  41         grep NFSMAPID_DOMAIN /etc/default/nfs
  42         echo "======================= /etc/resolv.conf ======================="
  43         cat /etc/resolv.conf
  44         echo "=========== TXT RR in /var/named/dns.test.nfs.master ==========="
  45         grep TXT /var/named/${dns_domain}.master
  46         echo "======================= dns server state ======================="
  47         svcs -xv svc:/network/dns/server:default
  48         echo "========================== dig output =========================="
  49         get_domain_txt_record $dns_domain
  50         echo "========================== nis domain =========================="
  51         domainname
  52         echo "======================= nfs mapid domain ======================="
  53         cat /var/run/nfs4_domain
  54         echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" 
  55 }
  56 
  57 
  58 #
  59 # get_domain_txt_record - gets a nfsmapid text record from a (local) DNS server
  60 # Usage get_domain_txt_record dns_domain
  61 #       dns_domain      name of the dns_domain as specified in DNS files.
  62 # function returns 0 on success or 1 on error, stdout has the value of the
  63 #       text record on success, else stderr has a diagnostic message.
  64 
  65 function get_domain_txt_record {
  66         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x
  67         n=get_domain_txt_record
  68         if [ $# -ne 1 ]; then
  69                 echo "USAGE: $n dns_domain" >&2
  70                 exit 1
  71         fi
  72         typeset dns_domain=$1
  73         if [ -z "$dns_domain" ]; then
  74                 echo "\t$n ERROR: DNS domain parameter is \"$dns_domain\"" >&2
  75                 return 1
  76         fi
  77         typeset serverName=`uname -n | cut -d. -f1`
  78         typeset server=`getent hosts $serverName | cut -f1`
  79         
  80         typeset type=TXT
  81         typeset keyword="_nfsv4idmapdomain"
  82         typeset ns=dig
  83      
  84        
  85         pgrep -z `zonename` named 2> /dev/null > /dev/null
  86         if [ $? -ne 0 ]; then
  87                 sleep 3
  88                 pgrep -z `zonename` named 2> /dev/null > /dev/null
  89                 if [ $? -ne 0 ]; then
  90                         echo "\t$n ERROR: DNS server not running" >&2
  91                         return 1
  92                 fi
  93         fi
  94       
  95         
  96         typeset res
  97         res=$($ns @$server 2>&1)
  98         if [ $? -ne 0 ]; then
  99                 echo "$n ERROR cannot access DNS server \"$server\"" >&2
 100                 printf "\tdig $server $server returned:\n%s\n" "$res" >&2 
 101                 return 1
 102         fi
 103         typeset out=$($ns @$server $keyword.$dns_domain $type +domain=$dns_domain 2>&1)
 104         typeset keys
 105         keys=$(printf "%s\n" "$out" | grep $type | grep $keyword | grep -v ';')
 106         if [ $? -ne 0 ]; then
 107                 echo "\t$n ERROR: DNS server \"$server\" did not have $type "\
 108                         "records for \"$keyword\"" >&2
 109                 printf "\t\tTXT records query results:\n%s\n" "$out" >&2 
 110                 echo "===============================\n" >&2 
 111                 return 1
 112         fi
 113         # if multiple records, use the last one 
 114         typeset key=$(printf "%s\n" "$keys" | tail -1) 
 115         typeset domain=$(echo $key | awk '{print $NF}' | awk -F= '{print $NF}' \
 116                 | sed 's/"//g')
 117         if [ -z "$domain" ]; then
 118                 echo "\t$n ERROR: $type \"$keyword\"record was empty" >&2
 119                 printf "\t\trecords found were:\n%s\t<===\n" "$keys" >&2 
 120                 echo "===============================\n" >&2 
 121                 return 1
 122         fi
 123         typeset -l domain=$domain
 124         echo $domain
 125         return 0
 126 }
 127 
 128 
 129 #
 130 # get_nfsmapid_domain - get nfsmapid domain from /var/run/nfs4_domain file
 131 # Usage get_nfsmapid_domain
 132 # function returns 0 on success or 1 on error, stdout has the value of the
 133 #       nfsmapid domain on success, else stderr has a diagnostic message.
 134 
 135 function get_nfsmapid_domain {
 136         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 137         n=get_nfsmapid_domain
 138         if [ $# -ne 0 ]; then
 139                 echo "USAGE: $n" >&2
 140                 exit 1
 141         fi
 142 
 143         if [ ! -f /var/run/nfs4_domain ]; then
 144                 echo "/var/run/nfs4_domain file doens't exist" >&2
 145                 return 1
 146         fi
 147 
 148         cat /var/run/nfs4_domain
 149         return 0
 150 }
 151 
 152 
 153 #
 154 # get_nfsmapid_domain_tout - uses mdb to get nfsmapid's global 
 155 #                               nfscfg_domain_tmout
 156 # Usage get_nfsmapid_domain_tout
 157 # function returns 0 on success or 1 on error, stdout has the value of the
 158 #       global nfscfg_domain_tmout on success, else stderr has a diagnostic
 159 #       message.
 160 
 161 function get_nfsmapid_domain_tout {
 162         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 163         n=get_nfsmapid_domain_tout
 164         if [ $# -ne 0 ]; then
 165                 echo "USAGE: $n" >&2
 166                 exit 1
 167         fi
 168 
 169         typeset dae=nfsmapid
 170         typeset var=nfscfg_domain_tmout
 171         typeset Pid=$(pgrep -z `zonename` -x $dae 2> /dev/null)
 172         if [ -z "$Pid" ] && [ $D -ne 0 ]; then
 173                 echo "$n: $dae is not running" >&2
 174                 return 1
 175         fi
 176         typeset line=$(echo "$var/D" | mdb -p $Pid 2> $TMPDIR/domain2.$$ | tail -1) 
 177         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && cat $TMPDIR/domain2.$$ 
 178         rm -f $TMPDIR/domain2.$$ >/dev/null 2>&1 
 179         # make sure we are getting valid results
 180         typeset st=$(echo $line | grep $dae | grep "$var:" | wc -w 2>/dev/null)
 181         if [ $st -ne 2 ]; then
 182                 echo "$n: Cannot get symbol $var from $dae" >&2
 183                 return 1
 184         fi
 185         typeset tout=$(echo $line | awk '{print $NF}')
 186         echo $tout
 187         return 0 
 188 }
 189 
 190 
 191 #
 192 # get_domain_default_nfs - gets nfsmapid's domain from /etc/default/nfs 
 193 # Usage get_domain_default_nfs
 194 # function returns 0 on success or 1 on error, stdout has the value of the
 195 #       nfsmapid's domain on success, else stderr has a diagnostic message.
 196 
 197 function get_domain_default_nfs {
 198         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 199         n=get_domain_default_nfs
 200         if [ $# -ne 0 ]; then
 201                 echo "USAGE: $n" >&2
 202                 exit 1
 203         fi
 204 
 205         file=/etc/default/nfs
 206         str=NFSMAPID_DOMAIN
 207         if [ ! -r $file ]; then
 208                 [ $D -ne 0 ] && echo "$n: Cannot read \"$file\"" >&2
 209                 return 1
 210         fi
 211         line=$(grep "^${str}=" $file)
 212         st=$?
 213         # domain not present
 214         if [ $st -ne 0 ]; then
 215                 echo ""
 216                 return 0
 217         fi
 218         # domain present
 219         domain=$(echo $line | awk -F= '{print $NF}')
 220         typeset -l domain=$domain
 221         echo $domain
 222         return 0
 223 }
 224 
 225 
 226 #
 227 # get_domain_resolv - gets first item on search field, or domain value if
 228 #       search field is not present, from file /etc/resolv.conf
 229 # Usage get_domain_resolv
 230 # function returns 0 on success or 1 on error, stdout has the value of the
 231 #       domain on success, else stderr has a diagnostic message.
 232 
 233 function get_domain_resolv {
 234         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 235         n=get_domain_resolv
 236         if [ $# -ne 0 ]; then
 237                 echo "USAGE: $n" >&2
 238                 exit 1
 239         fi
 240 
 241         typeset file=/etc/resolv.conf
 242         if [ ! -r $file ] && [ $D -ne 0 ]; then
 243                 echo "$n: Cannot read \"$file\"" >&2
 244                 return 1
 245         fi
 246         #resp;ver gives preference to search over domain
 247         typeset str=search
 248         typeset line
 249         line=$(grep -i "^$str" $file)
 250         typeset st=$?
 251         typeset domain
 252         # search present
 253         if [ $st -eq 0 ]; then
 254                 domain=$(echo $line | awk '{print $2}')
 255                 typeset -l domain=$domain
 256                 echo $domain
 257                 return 0
 258         fi
 259         str=domain
 260         line=$(grep -i "^$str" $file)
 261         st=$?
 262         # domain present
 263         if [ $st -ne 0 ]; then
 264                 echo ""
 265                 return 0
 266         fi
 267         # domain present
 268         domain=$(echo $line | awk '{print $2}')
 269         typeset -l domain=$domain
 270         echo $domain
 271         return 0
 272 }
 273 
 274 
 275 #
 276 # get_domain_domainname - gets domain value from command domainname
 277 # Usage get_domain_domainname
 278 # function returns 0 on success or 1 on error, stdout has the value of the
 279 #       domain on success, else stderr has a diagnostic message.
 280 
 281 function get_domain_domainname {
 282         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x
 283         n=get_domain_domainname
 284         if [ $# -ne 0 ]; then
 285                 echo "USAGE: $n" >&2
 286                 exit 1
 287         fi
 288 
 289         typeset prog=domainname
 290         typeset str=domain
 291 
 292         typeset line=$(domainname)
 293         typeset st=$?
 294         # domain not set
 295         if [ $st -ne 0 ] || [ -z "$line" ]; then
 296                 echo ""
 297                 return 0
 298         fi
 299         # domain present
 300         typeset sdomain=$(echo $line | awk -F. '{for (i=2 ; i <= NF; i++) print $i}')
 301         typeset domain=$(echo $sdomain | sed 's/ /./g')
 302         echo $domain
 303         return 0
 304 }
 305 
 306 
 307 #
 308 # remove_search_from_dns - removes the search field from the file
 309 #       /etc/resolv.conf
 310 # Usage remove_search_from_dns
 311 # function returns 0 on success or 1 on error and stderr has a diagnostic
 312 #       message.
 313 
 314 function remove_search_from_dns {
 315         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 316         n=chg_txt_field_dns
 317         if [ $# -ne 0 ]; then
 318                 echo "USAGE: $n" >&2
 319                 exit 1
 320         fi
 321 
 322         typeset file=/etc/resolv.conf
 323         typeset key=search
 324         sed "s/^${key}.*$//" $file > /tmp/resolv-new
 325         if [ $? -ne 0 ]; then
 326                 echo "Could not remove $key entries in $file" >&2
 327                 rm -f /tmp/resolv-new > /dev/null 2>&1
 328                 return 1
 329         fi
 330         mv /tmp/resolv-new $file
 331         if [ $? -ne 0 ]; then
 332                 echo "Could not remove $key entries in $file" >&2
 333                 return 1
 334         fi
 335         return 0
 336 }
 337 
 338 
 339 #
 340 # chg_txt_field_dns - change the value of a nfsmapid text record, or the name
 341 #       and value of such text record for the specified master file.
 342 # Usage chg_txt_field_dns master_file {domain | field_name=value}
 343 #       master_file     DNS named config master file to modify
 344 #       domain          domain value for the nfsmapid text field
 345 #       field_name=value new tag and value to replace the nfsmapid field
 346 # function returns 0 on success or 1 on error and stderr has a diagnostic
 347 #       message.
 348 
 349 function chg_txt_field_dns {
 350         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 351         n=chg_txt_field_dns
 352         if [ $# -ne 2 ]; then
 353                 echo "USAGE: $n master_file {domain | field_name=value}" >&2
 354                 exit 1
 355         fi
 356         typeset file=$1
 357         if [ ! -r $file ]; then
 358                 echo " Can not read master_file $file" >&2
 359                 return 1
 360         fi
 361 
 362         typeset keyword
 363         typeset field
 364         typeset dns_txt=$2
 365         typeset res
 366         res=$(echo $dns_txt | egrep "[a-zA-Z0-9_-]+=.*" 2>&1)
 367         if [ $? -ne 0 ]; then
 368                 keyword="_nfsv4idmapdomain"
 369                 field="$dns_txt"
 370         else
 371                 keyword="$(echo $dns_txt | awk -F= '{print $1}')"
 372                 field="$(echo $dns_txt | awk -F= '{print $NF}')"
 373         fi
 374         
 375         nawk -v keyword="$keyword" -v field="$field" \
 376              '( $2 == "IN" && $3 == "TXT" ) {        \
 377                   printf("%s", keyword);             \
 378                   for (i=2; i < NF; i++)             \
 379                       printf("\t%s", $i);            \
 380                   printf("\t%s\n", field); }         \
 381               !( $2 == "IN" && $3 == "TXT" ) {       \
 382                   print $0; }' $file > /tmp/master-new
 383         if [ $? -ne 0 ]; then
 384                 echo "Could not change ${str}... in $file" >&2
 385                 return 1
 386         fi
 387         cp -p $file $file.old
 388         mv /tmp/master-new $file
 389         if [ $? -ne 0 ]; then
 390                 echo "Could not change ${str}... in $file" >&2
 391                 return 1
 392         fi
 393         return 0
 394 }
 395 
 396 
 397 #
 398 # chg_domain_dns - change the value of the domain field for /etc/resolv.conf
 399 # Usage chg_domain_dns new_dns_domain
 400 #       new_dns_domain  domain to replace current value
 401 # function returns 0 on success or 1 on error and stderr has a diagnostic
 402 #       message.
 403 
 404 function chg_domain_dns {
 405         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 406         n=chg_domain_dns
 407         if [ $# -ne 1 ]; then
 408                 echo "USAGE: $n dns_domain" >&2
 409                 exit 1
 410         fi
 411         typeset dns_domain=$1
 412         typeset str=domain
 413         
 414         sed "s/^$str .*\$/$str $dns_domain/" \
 415                 /etc/resolv.conf > /tmp/resolv-new
 416         if [ $? -ne 0 ]; then
 417                 echo "Could not change $str in /etc/resolv.conf" >&2
 418                 return 1
 419         fi
 420         cp -p /etc/resolv.conf /etc/resolv.old
 421         mv /tmp/resolv-new /etc/resolv.conf
 422         if [ $? -ne 0 ]; then
 423                 echo "Could not change $str in /etc/resolv.conf" >&2
 424                 return 1
 425         fi
 426         return 0
 427 }
 428 
 429 
 430 #
 431 # chg_server_dns - change the value of the nameserver field for /etc/resolv.conf
 432 # Usage chg_server_dns new_dns_server
 433 #       new_dns_server  nameserver value to replace current value
 434 # function returns 0 on success or 1 on error and stderr has a diagnostic
 435 #       message.
 436 
 437 function chg_server_dns {
 438         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 439         n=chg_server_dns
 440         if [ $# -ne 1 ]; then
 441                 echo "USAGE: $n dns_server" >&2
 442                 exit 1
 443         fi
 444         typeset server=$1
 445         typeset str=nameserver
 446         sed "s/^$str .*\$/$str $server/" \
 447                 /etc/resolv.conf > /tmp/resolv-new
 448         if [ $? -ne 0 ]; then
 449                 echo "Could not change $str in /etc/resolv.conf" >&2
 450                 return 1
 451         fi
 452         cp -p /etc/resolv.conf /etc/resolv.old
 453         mv /tmp/resolv-new /etc/resolv.conf
 454         if [ $? -ne 0 ]; then
 455                 echo "Could not change $str in /etc/resolv.conf" >&2
 456                 return 1
 457         fi
 458         return 0
 459 }
 460 
 461 
 462 #
 463 # chg_domain_default_nfs - change the value of the variable NFSMAPID_DOMAIN for
 464 #       /etc/default/nfs
 465 # Usage chg_domain_default_nfs domain
 466 #       domain  new value for the nfsmapid domain
 467 # function returns 0 on success or 1 on error and stderr has a diagnostic
 468 #       message.
 469 
 470 function chg_domain_default_nfs {
 471         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 472         n=chg_domain_default_nfs
 473         if [ $# -ne 1 ]; then
 474                 echo "USAGE: $n domain" >&2
 475                 exit 1
 476         fi
 477         typeset domain=$1
 478         typeset str=NFSMAPID_DOMAIN
 479         sed "/$str=.*/d" /etc/default/nfs > /tmp/nfs-new
 480         if [ $? -ne 0 ]; then
 481                 echo "Could not generate tmp file for /etc/default/nfs" >&2
 482                 return 1
 483         fi
 484         echo "$str=$domain" >> /tmp/nfs-new
 485         cp -p /etc/default/nfs /etc/default/nfs.old
 486         mv /tmp/nfs-new /etc/default/nfs
 487         if [ $? -ne 0 ]; then
 488                 echo "Could not change $str in /etc/default/nfs" >&2
 489                 return 1
 490         fi
 491         return 0
 492 }
 493 
 494 
 495 #
 496 # comm_domain_default_nfs - comment the entry for the variable NFSMAPID_DOMAIN
 497 #       in /etc/default/nfs
 498 # Usage comm_domain_default_nfs
 499 # function returns 0 on success or 1 on error and stderr has a diagnostic
 500 #       message.
 501 
 502 function comm_domain_default_nfs {
 503         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 504         n=comm_domain_default_nfs
 505 
 506         sed 's/^NFSMAPID_DOMAIN=/\# NFSMAPID_DOMAIN=/' /etc/default/nfs \
 507                 > /tmp/nfs-new
 508         cp -p /etc/default/nfs /etc/default/nfs.old
 509         mv /tmp/nfs-new /etc/default/nfs
 510 }
 511 
 512 
 513 #
 514 # uncomm_domain_default_nfs - uncomment the entry for the variable
 515 #       NFSMAPID_DOMAIN in /etc/default/nfs
 516 # Usage uncomm_domain_default_nfs
 517 # function returns 0 on success or 1 on error and stderr has a diagnostic
 518 #       message.
 519 
 520 function uncomm_domain_default_nfs {
 521         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 522         n=uncomm_domain_default_nfs
 523 
 524         sed 's/^\#[ \t]*NFSMAPID_DOMAIN=/NFSMAPID_DOMAIN=/' /etc/default/nfs \
 525                 > /tmp/nfs-new
 526         cp -p /etc/default/nfs /etc/default/nfs.old
 527         mv /tmp/nfs-new /etc/default/nfs
 528 }
 529 
 530 
 531 #
 532 # save_file - stores the source file to a temporal file, can only be used
 533 #       for one file, and does not "overwrites" the temporal file, so multiple
 534 #       consecutive calls have the same effect as the first call only. Must be
 535 #       "reset" by a call to restore_file.
 536 # Usage save_file filename
 537 #       filename        source file to be backup in the temporal file
 538 # function returns 0 on success or 1 on error and stderr has a diagnostic
 539 #       message.
 540 
 541 function save_file {
 542         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 543         n=save_file
 544         if [ $# -ne 1 ]; then
 545                 echo "USAGE: $n filename" >&2
 546                 exit 1
 547         fi
 548 
 549         typeset TMPNAM="${TMPDIR}/temp_file.$(basename $1).NMAPID.$$"
 550         typeset file1=$1
 551         [ -e "$TMPNAM" ] && echo "$n: A file was already saved" && return 1
 552         [ ! -f "$file1" ] && echo "$n: $file1 not a regular file" && return 1
 553         res=$(cp -p $file1 $TMPNAM 2>&1)
 554         [ $? -ne 0 ] && echo "$n: $file1 could not be saved" && return 1
 555         return 0
 556 }
 557 
 558 #
 559 # is_saved - checks if the specified file has been saved by save_file() or not.
 560 #       When one calls save_file() to back up one file, its contents is 
 561 #       stored in a temporal file under $TMPDIR, whose name follows an
 562 #       implementation specific naming convention. What this function does is 
 563 #       to check the existence of the temporal file. If it exists, the target
 564 #       file is supposed to be saved.
 565 # Usage is_saved filename
 566 #       filename        The target file whose temporal file is checked
 567 # function returns 0 if the specified file is saved or 1 if not.
 568 function is_saved {
 569         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 570         n=is_saved
 571         if [ $# -ne 1 ]; then
 572                 echo "USAGE: $n filename" >&2
 573                 exit 1
 574         fi
 575 
 576         typeset TMPNAM="${TMPDIR}/temp_file.$(basename $1).NMAPID.$$"
 577         [ -e "$TMPNAM" ] && return 0
 578         return 1
 579 }
 580 
 581 #
 582 # restore_file - restores the specified file from a temporal file, can only be
 583 #       used to restore one file, and does not "destroys" the target file,
 584 #       so  after the first call, multiple consecutive calls will fail.
 585 #       Must be "set" by a call to save_file.
 586 # Usage restore_file filename
 587 #       filename        Target file to be replaced by the temporal file
 588 # function returns 0 on success or 1 on error and stderr has a diagnostic
 589 #       message.
 590 
 591 function restore_file {
 592         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 593         n=restore_file
 594         if [ $# -ne 1 ]; then
 595                 echo "USAGE: $n filename" >&2
 596                 exit 1
 597         fi
 598 
 599         typeset TMPNAM="${TMPDIR}/temp_file.$(basename $1).NMAPID.$$"
 600         typeset file1=$1
 601         [ ! -e "$TMPNAM" ] && echo "$n: No file has been saved yet" && return 1
 602         res=$(/usr/bin/mv -f $TMPNAM $file1 2>&1)
 603         [ $? -ne 0 ] && echo "$n: $file1 could not be saved" && return 1
 604         return 0
 605 }
 606 
 607 # Function get_nfsmapid_domain_tout_wrapper
 608 #     A simple wrapper around get_nfsmapid_domain_tout() function. This 
 609 #     function calls get_nfsmapid_domain_tout() to get nfscfg_domain_tmout, 
 610 #     increase it a bit, and then output it. If the call of 
 611 #     get_nfsmapid_domain_tout() fails, the function output default value of
 612 #     305 seconds, and if DEBUG is turned on, outputs error message on stderr.
 613 # Usage
 614 #     get_nfsmapid_domain_tout_wrapper 
 615 # Return value
 616 #     On success it output timeout value on stdout; On failure it outputs 
 617 #     default timeout(305 seconds) on stdout, and error message on stderr.
 618 
 619 function get_nfsmapid_domain_tout_wrapper {
 620         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x
 621         typeset timeout=$(get_nfsmapid_domain_tout 2>$TMPDIR/tout.err.$$)
 622 
 623         ckreturn $? "failed to get nfsmapid timeout value" \
 624             $TMPDIR/tout.err.$$ "WARNING" || timeout=300
 625 
 626         rm -f $TMPDIR/tout.err.$$ >/dev/null 2>&1
 627         
 628         timeout=$(($timeout + 5))
 629         echo $timeout
 630 }
 631 
 632 # Function get_second_dns_server
 633 #     This function searchs for another dns server(instead of the one that 
 634 #     we set up locally)which have TXT record. It will first check 
 635 #     if $DNS_SERVER have TXT record. If so, $DNS_SERVER is returned; Otherwise
 636 #     129.149.246.6(sundns1.sfbay.sun.com) is checked. If that doesn't have 
 637 #     TXT record either, the function fails.
 638 # Usage
 639 #     get_second_dns_server
 640 # Return value
 641 #     On success it outputs the second dns server, its domain,  and its txt 
 642 #     record in the form of "server_name domain txt_record" and returns 0.
 643 #     On failure it outputs nothing and returns 1.
 644 
 645 function get_second_dns_server {
 646         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x
 647         n=get_second_dns_server
 648 
 649         #
 650         # Check if DNS_SERVER have TXT record
 651         #
 652         
 653         typeset dns_server_addr=$(getent hosts $DNS_SERVER | head -1 | cut  -f1)
 654         typeset txt_record
 655         typeset dns_domain
 656         typeset res
 657 
 658         if [[ -n "$dns_server_addr" ]]; then
 659                 dns_domain=$(get_domain $dns_server_addr)
 660         fi
 661 
 662         if [[ -n "$dns_server_addr" && -n "$dns_domain" ]]; then
 663                 res=$(/usr/sbin/nslookup -domain=$dns_domain \
 664                     -query=txt _nfsv4idmapdomain $DNS_SERVER \
 665                     | grep "_nfsv4idmapdomain.*text.*=" 2>&1)
 666 
 667                 if [[ -n "$res" ]]; then 
 668                         # the server has TXT RR for requested domain
 669                         txt_record=$(echo $res | cut -d'"' -f2)
 670                         echo "$dns_server_addr $dns_domain $txt_record"
 671                         return 0
 672                 fi 
 673         fi 
 674 
 675         # 
 676         # Then check 129.149.246.6 as last resort
 677         #
 678 
 679         res=$(/usr/sbin/nslookup -domain=sfbay.sun.com \
 680             -query=txt _nfsv4idmapdomain 129.149.246.6 \
 681             | grep "_nfsv4idmapdomain.*text.*=")
 682 
 683         if [[ -n "$res" ]]; then 
 684                 # the server has TXT RR for requested domain
 685                 txt_record=$(echo $res | cut -d'"' -f2)
 686                 echo "129.149.246.6 sfbay.sun.com $txt_record"
 687                 return 0
 688         fi
 689         
 690         return 1
 691 }
 692 
 693 # Function mapid_service
 694 #       refreshes, and restarts mapid service. The function is a wrapper
 695 #       around smf_fmri_transition_state(), which itself is a wrapper around
 696 #       svcadm command. It helps to save some typing, as well as
 697 #       to avoid the timing issue found when using smf_fmri_transition_state()
 698 #       to restart mapid service
 699 # Usage 
 700 #       mapid_service restart|refresh timeout errmsg result
 701 # Return value
 702 #       function returns 0 on success 
 703 #                     or 1 on error and stdout has a diagnostic message.
 704 
 705 function mapid_service {
 706         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x && D=1
 707         n=mapid_service
 708         if (( $# < 3 )); then
 709                 echo "USAGE: $n restart|refresh timeout errmsg result" >&2
 710                 return 1
 711         fi
 712 
 713         typeset action=$1
 714         typeset timeout=$2
 715         typeset errmsg=$3
 716         (($# > 3 )) && typeset result=$4
 717 
 718         typeset logfile=$TMPDIR/mapid_service.tmp.$$
 719         typeset ret
 720 
 721         case $action in
 722             restart )
 723                 smf_fmri_transition_state \
 724                     do svc:/network/nfs/mapid:default disabled $timeout \
 725                     >$logfile 2>&1
 726                 ckreturn $? "$errmsg" $logfile $result || return 1
 727 
 728                 smf_fmri_transition_state \
 729                     do svc:/network/nfs/mapid:default online $timeout \
 730                     >$logfile 2>&1
 731                 ckreturn $? "$errmsg" $logfile $result || return 1
 732                 ;;
 733             refresh )
 734                 # s10(up-to-u6) doesn't have "refresh" method for nfsmapid
 735                 typeset os_rel=$(uname -r)
 736                 if echo $os_rel | grep "5.10." >/dev/null 2>&1 || \
 737                    echo $os_rel | grep "5.11" >/dev/null 2>&1; 
 738                 then
 739                         svcadm refresh mapid >$logfile 2>&1 && sleep 3
 740                         ckreturn $? "$errmsg" $logfile $result || return 1
 741                 else
 742                         # so we use kill, but need to make sure
 743                         # the HUP signal is sent to the right process
 744                         kill -HUP `cat /etc/svc/volatile/nfs-mapid.lock` \
 745                                 >$logfile 2>&1 && sleep 3
 746                         ckreturn $? "$errmsg" $logfile $result || return 1
 747                 fi
 748                 ;;
 749             * )
 750                 echo "USAGE: $n restart|refresh timeout errmsg result" >&2
 751                 return 1
 752                 ;;
 753         esac
 754         
 755         rm -f $logfile >/dev/null 2>&1
 756         return 0
 757 }
 758 
 759 # Function dns_service 
 760 #       enables, disables, and restarts dns service. This function is a
 761 #       wrapper around smf_fmri_transition_state(), which itself is a wrapper
 762 #       around svcadm. 
 763 #
 764 #       Notes: while I used "svcadm restart svc:/network/dns/server:default" 
 765 #       to restart dns server set up by dnscfg.ksh, I found the command 
 766 #       didn't always work. Normally it took much time than expected, 
 767 #       sometimes the service was never brought up anymore. For that reason, 
 768 #       I would implement restart action by first disabling and then 
 769 #       enabling it.
 770 # Usage 
 771 #       dns_service enable|disable|restart timeout errmsg resstr
 772 # Return value
 773 #       returns 0 on success or 1 on error and stdout has a diagnostic
 774 #       message.
 775 
 776 function dns_service {
 777         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x && D=1
 778         n=dns_service
 779 
 780         if (( $# < 3 )); then
 781             echo "USAGE: $n enable|disable|restart timeout errmsg [resstr]" >&2
 782             return 1
 783         fi
 784 
 785         typeset action=$1
 786         typeset timeout=$2
 787         typeset errmsg=$3
 788         (( $# > 3 )) && typeset resstr=$4
 789         typeset ret
 790         typeset logfile=$TMPDIR/dns_service.tmp.$$
 791 
 792         case $action in 
 793             enable )
 794                 smf_fmri_transition_state \
 795                     do svc:/network/dns/server:default online ${timeout} \
 796                     >$logfile 2>&1
 797                 ckreturn $? "$errmsg" $logfile $resstr || return 1
 798                 ;;
 799             disable )
 800                 smf_fmri_transition_state \
 801                     do svc:/network/dns/server:default disabled ${timeout} \
 802                     >$logfile 2>&1
 803                 ckreturn $? "$errmsg" $logfile $resstr || return 1
 804                 ;;
 805             restart )
 806                 smf_fmri_transition_state \
 807                     do svc:/network/dns/server:default disabled ${timeout} \
 808                     >$logfile 2>&1
 809                 ckreturn $? "$errmsg" $logfile $resstr || return 1
 810 
 811                 smf_fmri_transition_state \
 812                     do svc:/network/dns/server:default online ${timeout} \
 813                     >$logfile 2>&1
 814                 ckreturn $? "$errmsg" $logfile $resstr || return 1
 815                 ;;      
 816             * )
 817                 echo "USAGE: $n enable|disable|restart timeout" >&2
 818                 return 1        
 819                 ;;      
 820         esac
 821                         
 822         rm -f $logfile >/dev/null 2>&1
 823         return 0
 824 }
 825 
 826 #
 827 # Function get_dns_txt_cache_flag
 828 #       the function checks if we have access to dns_txt_cached variable 
 829 #       in nfsmapid proccess via mdb. The varible is a flag in nfsmapid 
 830 #       to indicate if the cached txt rr is valid or not. 
 831 # Usage 
 832 #       get_dns_txt_cache_flag
 833 # Return Value
 834 #       returns 0 on success, and output value of dns_txt_cached on stdout;
 835 #       returns 1 on error, and output error message on stderr.
 836 
 837 function get_dns_txt_cache_flag {
 838         [ -n "$DEBUG" ] && [ $DEBUG != 0 ] && set -x 
 839         n=get_dns_txt_cache_flag
 840 
 841         typeset logfile=$TMPDIR/txt.tmp.$$
 842 
 843         typeset daemon=nfsmapid
 844         typeset pid=$(pgrep -z `zonename` -x $daemon 2>/dev/null)
 845         if [[ -z "$pid" ]]; then 
 846                 # no nfsmapid process found
 847                 echo "$n: $daemon is not running" 1>&2
 848                 return 1
 849         fi
 850 
 851         typeset var=dns_txt_cached
 852         typeset result=$(echo "$var/D" | mdb -p $pid 2>$logfile | tail -1)
 853         typeset found=$(echo $result | grep "$var:" | wc -w 2>/dev/null)
 854         if [[ $found -ne 2 ]]; then
 855                 cat $logfile && rm -f $logfile
 856                 echo "$n: Cannot get symbol $var from $daemon" >&2
 857                 return 1
 858         fi 
 859 
 860         echo $result | nawk '{print $NF}'
 861 
 862         rm -f $logfile
 863 
 864         return 0
 865 }
 866 
 867 # save_state - saves the system's current state(files, smf services' state,
 868 #       etc.), which can be restored later by calling restore_state(). 
 869 #       The function takes one argument to name the state to be saved. User
 870 #       can call this function consecutively to save system states at 
 871 #       different stages during test script execution.
 872 # Usage: save_state <state_name>
 873 #       state_name - the name for the state
 874 # function returns 0 on success or 1 on error, stderr has a diagnostic message
 875 #       on error.
 876 #
 877 
 878 function save_state {
 879         [[ -n "$DEBUG" ]] && [[ $DEBUG != 0 ]] && set -x 
 880         n=save_state
 881         logfile=$TMPDIR/save_state.$$
 882 
 883         if [[ $# != 1 ]]; then
 884                 echo "USAGE: $n tag"
 885                 return 1
 886         fi
 887         state_name=$1
 888 
 889         # create a temporary directory
 890         STATE_DIR=$TMPDIR/system_state.$$.$state_name
 891         rm -rf $STATE_DIR >$logfile 2>&1 \
 892             && mkdir $STATE_DIR >$logfile 2>&1
 893         ckreturn $? "$n: failed to remove/create directory" $logfile "ERROR" \
 894             || return 1
 895 
 896         # save /etc/default/nfs
 897         cp /etc/default/nfs $STATE_DIR/etc.default.nfs >$logfile 2>&1
 898         ckreturn $? "$n: failed to save /etc/default/nfs" $logfile "ERROR" \
 899             || return 1
 900 
 901         # save /etc/resolv.conf if it exists
 902         if [[ -f /etc/resolv.conf ]]; then
 903                 cp /etc/resolv.conf $STATE_DIR/etc.resolv.conf >$logfile 2>&1
 904                 ckreturn $? "$n: failed to save /etc/resolv.conf" $logfile \
 905                     "ERROR" || return 1
 906         fi
 907 
 908         # save /etc/named.conf if it exists
 909         if [[ -f /etc/named.conf ]]; then
 910                 cp /etc/named.conf $STATE_DIR/etc.named.conf >$logfile 2>&1
 911                 ckreturn $? "$n: failed to save /etc/named.conf" $logfile \
 912                     "ERROR" || return 1
 913         fi
 914 
 915         # save /var/named directory if it exists
 916         if [[ -d /var/named ]]; then
 917                 tar cf $STATE_DIR/var.named /var/named >$logfile 2>&1
 918                 ckreturn $? "$n: failed to save /var/named" $logfile "ERROR" \
 919                     || return 1
 920         fi
 921         
 922         # save NIS domain
 923         domainname > $STATE_DIR/domainname
 924 
 925         rm -f $logfile
 926 }
 927 
 928 # restore_state - restore a system state which was previously saved by
 929 #       save_state(). The function takes one argument, which specify the state 
 930 #       to be restored. 
 931 # Usage: restore_state -c <state_name>
 932 #       -c  - If this option is set, this function not only restores the 
 933 #             original state on the system, but also removes the temporary 
 934 #             files used to save the state; otherwise, those files are not
 935 #             removed by default.
 936 #       state_name - the name for the state
 937 # function returns 0 on success or an non-zero value on error, stderr has a 
 938 # diagnostic message on error.
 939 #
 940 
 941 function restore_state {
 942         [[ -n "$DEBUG" ]] && [[ $DEBUG != 0 ]] && set -x 
 943         n=restore_state
 944         logfile=$TMPDIR/restore_state.$$
 945 
 946         if (( $# < 1 )); then
 947                 echo "USAGE: $n -c state_name"
 948                 return 1
 949         fi
 950 
 951         removefile=0
 952         if [[ "$1" == "-c" ]]; then
 953                 removefile=1
 954                 shift
 955         fi
 956         state_name=$1
 957 
 958         STATE_DIR=$TMPDIR/system_state.$$.$state_name
 959         if [[ ! -d $STATE_DIR ]]; then
 960                 echo "$state_name state doesn't exists!"
 961                 return 1
 962         fi
 963         ret=0
 964         
 965         # If any of the following operations fails, the function doesn't 
 966         # return immediately. Instead, it continues to restore the system
 967         # state as much as possible.
 968 
 969         # resotre /etc/default/nfs
 970         cp $STATE_DIR/etc.default.nfs /etc/default/nfs >$logfile 2>&1
 971         ckreturn $? "$n: failed to restore /etc/default/nfs" $logfile "ERROR" 
 972         ret=$((ret + $?))
 973 
 974         # restore /etc/resolv.conf if the back up exists
 975         if [[ -f $STATE_DIR/etc.resolv.conf ]]; then
 976                 cp $STATE_DIR/etc.resolv.conf /etc/resolv.conf >$logfile 2>&1
 977                 ckreturn $? "$n: failed to restore /etc/resolv.conf" $logfile \
 978                     "ERROR" 
 979                 ret=$((ret + $?))
 980         else
 981                 rm -f /etc/resolv.conf
 982         fi 
 983 
 984         # disable DNS server temporarily
 985         dns_service disable 6 "failed to disable dns service" "ERROR"
 986         ret=$((ret + $?))
 987 
 988         # restore /etc/named.conf if the back up exists
 989         if [[ -f $STATE_DIR/etc.named.conf ]]; then
 990                 cp $STATE_DIR/etc.named.conf /etc/named.conf >$logfile 2>&1
 991                 ckreturn $? "$n: failed to restore /etc/named.conf" $logfile \
 992                     "ERROR" 
 993                 ret=$((ret + $?))
 994         else
 995                 rm -f /etc/named.conf
 996         fi
 997 
 998         # restore /var/named directory if it exists
 999         if [[ -f $STATE_DIR/var.named ]]; then
1000                 tar xf $STATE_DIR/var.named >$logfile 2>&1
1001                 ckreturn $? "$n: failed to restore /var/named" $logfile "ERROR"
1002                 ret=$((ret + $?))
1003         else
1004                 rm -rf /var/named
1005                 ret=$((ret + $?))
1006         fi
1007 
1008         # start dns server if necessary
1009         [[ -f /etc/named.conf ]] \
1010             && dns_service enable 6 "failed to disable dns service" "ERROR"
1011         ret=$((ret + $?))
1012 
1013         # resotre NIS domain
1014         domainname $(cat $STATE_DIR/domainname) 2>$logfile
1015         ckreturn $? "$n: failed to restore NIS domain" $logfile "ERROR"
1016         ret=$((ret + $?))
1017  
1018         # restart mapid service
1019         mapid_service refresh 6 "failed to restart mapid service" "UNRESOLVED"
1020         ret=$((ret + $?))
1021 
1022         [[ $removefile -eq 1 ]] && rm -rf $STATE_DIR
1023         rm -f $logfile
1024 
1025         return $ret
1026 }
1027 
1028 # clear_state - clear a system state which was previously saved by
1029 #       save_state(), which means, to remove the temporary files and directory
1030 #       used for it.
1031 # Usage: clear_state <state_name>
1032 #       state_name - the name for the state
1033 # function returns 0 on success or 1 if the state is unknown(that is, the 
1034 # directory for it is not found).
1035 #
1036 function clear_state {
1037         [[ -n "$DEBUG" ]] && [[ $DEBUG != 0 ]] && set -x 
1038         n=clear_state
1039         logfile=$TMPDIR/clear_state.$$
1040 
1041         if (( $# < 1 )); then
1042                 echo "USAGE: $n state_name"
1043                 return 1
1044         fi
1045         state_name=$1
1046 
1047         STATE_DIR=$TMPDIR/system_state.$$.$state_name
1048         if [[ ! -d $STATE_DIR ]]; then
1049                 echo "$state_name state doesn't exists!"
1050                 return 1
1051         fi
1052 
1053         rm -rf $STATE_DIR
1054 }
1055 
1056 # gen_assert_desc - generates assertion descriptions from the comments in
1057 #       function headers.
1058 # Usage: gen_assert_desc file keyword
1059 #       file - the file to be scanned
1060 #       prefix - the prefix of assertion names, which is used to construct
1061 #               a pattern to search for assertion descriptions. It can be null.
1062 # function always return 0.
1063 #
1064 function gen_assert_desc {
1065         [[ -n "$DEBUG" ]] && [[ $DEBUG != 0 ]] && set -x 
1066 
1067         file=$1
1068         assert_prefix=$2
1069 
1070         grep "^# ${assert_prefix}.*: " $file >$TMPFILE 2>/dev/null
1071         set -A assert_names $(cat $TMPFILE | cut -d' ' -f2 | sed 's/://g')
1072         x=0
1073         while (( $x < ${#assert_names[*]} )); do
1074                 assert_descs[$x]=$( \
1075                     nawk -v assert=${assert_names[$x]}             \
1076                         'BEGIN { pattern = "# " assert ": "; }     \
1077                          (index($0, pattern ) != 0) {              \
1078                             $0 = substr($0, length(pattern)+1);    \
1079                             getline nextline;                      \
1080                             while (index(nextline, "#\t") != 0) {  \
1081                                 $0 = $0 " " substr(nextline, 3);   \
1082                                 getline nextline;                  \
1083                             }                                      \
1084                             print $0;                              \
1085                         }' $file)
1086                 x=$((x + 1))
1087         done
1088         rm -f $TMPFILE
1089 }
1090 
1091 # get_assert_desc - gets assertion description from database generated by
1092 #       gen_assert_desc(), for a specific assertion
1093 # Usage: get_assert_desc assert
1094 #       assert - the name of the assertion to be search for
1095 # function always return 0.
1096 #
1097 
1098 function get_assert_desc {
1099         [[ -n "$DEBUG" ]] && [[ $DEBUG != 0 ]] && set -x 
1100 
1101         assert=$assert_prefix$1
1102 
1103         x=0
1104         while (( $x < ${#assert_names[*]} )); do
1105                 [[ ${assert_names[$x]} == "$assert" ]] \
1106                     && echo "${assert_descs[$x]}"
1107                 x=$((x + 1))
1108         done
1109 }