#!/bin/sh # # @(#)check.sh 1.51 00/01/17 SMI # # Copyright (c) 1995-1996 by Sun Microsystems, Inc. All Rights Reserved. # This shell script is for checking the validity of rules, # begin, profiles, finish, and probes. # # NOTE: cannot I18N this script since it runs on 4.x & 5.x systems PATH=/usr/ucb:/usr/sbin/install.d:${PATH} export PATH myname=`basename $0` # check script name for usage message DEBUG=0 CONV_TMP_FILE=/tmp/conv_awk.script.$$ PROF_TMP_FILE=/tmp/.profile_names.$$ CMP_VAR=compare_$$ STD_RULES=rules CUSTOM_PROBES=custom_probes # error codes E_PROBE_NOT_FOUND=1 E_CMP_NOT_FOUND=2 E_CLASS_NOT_FOUND=3 E_FINISH_NOT_FOUND=4 E_LACK_ARGS=5 E_BEGIN_NOT_FOUND=6 E_NO_BEGIN_TO_DERIVE=7 E_EXCESS_ARGS=8 E_DUP_INST_TYPE=9 E_INV_INST_TYPE=10 E_DUP_SYS_TYPE=11 E_INV_SYS_TYPE=12 E_DUP_PART_TYPE=13 E_INV_PART_TYPE=14 E_INV_OPTION=15 E_NO_INST_TYPE=16 E_CMP_LACK_ARGS=17 E_BAD_DEVICE_SPEC=18 E_AUTO_EXISTING=19 E_MOUNT_FULL_PATH=20 E_BAD_SIZE=21 E_INVALID_NUMBER=22 E_INVALID_KEY=23 E_INITIAL_KEY=24 E_UPGRADE_KEY=25 E_BAD_TYPE=26 E_INV_SERVER_ADDR=27 E_DATALESS_EOL=28 E_DUP_ROOT_DEVICE=29 E_INST_TYPE_FIRST=30 E_DUP_BOOT_DEVICE=31 E_INV_PROM_UPDATE=32 E_INV_BACKUP_IDENT=33 E_INV_LAYOUT_CONSTRAINT=34 E_ISABITS=35 # fatal_error() # Purpose: print appropriate error according to ${1} # Input: ${1} - error code # fatal_error() { echo "" if [ "${profile_ln}" -a "${profile_ln}" -ne 0 ]; then line_number=${profile_ln} read_file="${profile_file}" else line_number=${ln} read_file="${in_file}" fi echo "Error in file \"${read_file}\", line ${line_number}" echo " ${line}" echo -n "ERROR: " case "${1}" in ${E_EXCESS_ARGS}) echo "Too many arguments for this keyword" ;; ${E_LACK_ARGS}) echo "Insufficient arguments for this keyword" ;; ${E_CMP_LACK_ARGS}) echo "Insufficient arguments for match key: ${cmp_err_rulename}" ;; ${E_PROBE_NOT_FOUND}) echo "Probe function \"probe_${probe_name}\" undefined" ;; ${E_CMP_NOT_FOUND}) echo "Match key: ${key} undefined" ;; ${E_CLASS_NOT_FOUND}) echo "Profile missing: ${profile}" ;; ${E_FINISH_NOT_FOUND}) echo "Finish script missing: ${finish}" ;; ${E_BEGIN_NOT_FOUND}) echo "Begin script missing: ${begin}" ;; ${E_NO_BEGIN_TO_DERIVE}) echo "Missing begin script for derived profile" ;; ${E_DUP_INST_TYPE}) echo "Duplicate install type specified" ;; ${E_INST_TYPE_FIRST}) echo "First specified keyword must be \"install_type\"" ;; ${E_DUP_ROOT_DEVICE}) echo "Duplicate root_device specified" ;; ${E_DUP_BOOT_DEVICE}) echo "Duplicate boot_device specified" ;; ${E_INV_BACKUP_IDENT}) echo "Invalid backup media identifier specified" ;; ${E_INV_LAYOUT_CONSTRAINT}) echo "Invalid layout constraint specified" ;; ${E_INV_INST_TYPE}) echo "Invalid install type specified" ;; ${E_NO_INST_TYPE}) echo "No install type specified" ;; ${E_INV_SERVER_ADDR}) echo "Invalid server address specified" ;; ${E_DUP_SYS_TYPE}) echo "Duplicate system type specified" ;; ${E_INV_SYS_TYPE}) echo "Invalid system type specified" ;; ${E_DUP_PART_TYPE}) echo "Duplicate partitioning specified" ;; ${E_INV_PART_TYPE}) echo "Invalid partitioning specified" ;; ${E_INV_OPTION}) echo "Third argument must be 'add' or 'delete'" ;; ${E_BAD_SIZE}) echo "Size \"${size}\" is invalid" ;; ${E_MOUNT_FULL_PATH}) echo "Mount point \"${mount}\" must begin with a '/'" ;; ${E_AUTO_EXISTING}) echo -n "A \"preserved\" filesystem cannot be \"auto\" sized" echo ", use \"existing\"" ;; ${E_BAD_DEVICE_SPEC}) echo "Device \"${device_name}\" is badly specified" ;; ${E_INVALID_NUMBER}) echo "The argument is not a number" ;; ${E_INVALID_KEY}) echo "Invalid keyword" ;; ${E_INITIAL_KEY}) echo "This keyword can only be used with an install_type of initial_install" ;; ${E_UPGRADE_KEY}) echo "This keyword can only be used with an install_type of upgrade" ;; ${E_BAD_TYPE}) echo "Type \"${type}\" is invalid" ;; ${E_INV_PROM_UPDATE}) echo "Invalid prom update value specified" ;; ${E_X86BOOT_NO_DEVICE}) echo "Fdisk partition type \"x86boot\" requires a device name" ;; esac echo exit 1 } # warning_msg() # Purpose: print warning message # Input: ${1} - warning code # warning_msg() { echo "" if [ "${profile_ln}" -a "${profile_ln}" -ne 0 ]; then line_number=${profile_ln} read_file="${profile_file}" else line_number=${ln} read_file="${in_file}" fi echo "Warning in file \"${read_file}\", line ${line_number}" echo " ${line}" echo -n "WARNING: " case "${1}" in ${E_EXCESS_ARGS}) echo "Too many arguments for this keyword" ;; ${E_DATALESS_EOL}) echo "SunSoft plans to remove support for the dataless client system" echo -n " " echo "type after Solaris 2.5. You can use this system type now, but in" echo -n " " echo "future releases you will need to select a different option." ;; esac echo "" } # get_functions() # Purpose: find all the function headers within the file ${1} # get_functions() { while read first rest ; do case ${first} in \#*) # comment continue ;; "") # blank line continue ;; esac # take out comments at end of line, and white space before # comment. this does have the side effect of not allowing # any '#' to be in the grammar, but that is acceptable. tmp_rest=`echo ${rest} | sed 's/[ ]*\#.*$//'` if [ -z "${tmp_rest}" ]; then set -- "" shift else set -- ${first} ${tmp_rest} fi line="${first} ${tmp_rest}" if echo ${line}|grep '[a-zA-Z_][a-zA-Z0-9_]*[ ]*()' >/dev/null then func=`expr "$line" : '\([a-zA-Z_][a-zA-Z0-9_]*\)[ ]*()'` echo ${func} if [ ${DEBUG} -eq 1 ]; then echo ${func} > /dev/tty fi fi done < ${1} } # create_derived_file() # Purpose: create the derived file which will have comments and # blank lines stripped # Input: ${1} - input file name # ${2} - output file name # create_derived_file() { awk -F\# '{print $1}' ${1} | awk 'NF != 0 {print}' \ | sed 's/^[ ]*//g' > ${2} } # append_checksum() # Purpose: append a checksum to the end of the file # Inputs: ${1} - input file name # Returns: 0 - okay # 1 - error # append_checksum() { in_file="${1}" chksum=`/bin/sum ${in_file} | /bin/awk '{print $1}'` echo "# version=2 checksum=${chksum}" >> ${in_file} if [ $? -ne 0 ]; then return 1 fi return 0 } # convert_args # Purpose: this function takes arguments and see's if they have single # quotes arount them. If they do, it concatenates all # arguments between each set of "'"'s with _'s instead of spaces. # Inputs: any args # convert_args() { # if no 's then get out if echo $* | grep -v \' > /dev/null 2>&1 then echo $* return fi # because of all the funkiness of handling "'" s, put it in a file if [ ! -f "${CONV_TMP_FILE}" ]; then cat << \FOOBAR > "${CONV_TMP_FILE}" BEGIN { stderr="cat 1>&2" } { i = 1 var="" len=length($0) while (i <= len) { if (substr($0, i, 1) == "'") { if (length(var) > 0) { print var var="" } i++ while (substr($0, i, 1) != "'" && i <= len) { if (substr($0, i, 1) == " ") { var=var "_" } else { var=var substr($0, i, 1) } i++ } if ( i > len ) { print "Mis-matched \"'\" quotes <" $0 ">" | stderr exit 1 } } else { if (length(var) > 0) { print var var="" } while (substr($0, i, 1) != " " && i <= len) { var=var substr($0, i, 1) i++ } } i++ } if (length(var) > 0) print var } FOOBAR fi echo "$*" | nawk -f ${CONV_TMP_FILE} } # check_arg_cnt() # Purpose: XXX hardcoded to check specific rules that have more # then 1 parameter # check_arg_cnt() { if [ "${1}" = "disksize" -a ${2} -ne 3 ]; then cmp_err_rulename=${1} fatal_error ${E_CMP_LACK_ARGS} elif [ "${1}" = "installed" -a ${2} -ne 3 ]; then cmp_err_rulename=${1} fatal_error ${E_CMP_LACK_ARGS} fi } # check_part_name() # Purpose: subroutine to check if string is a valid canonical # fdisk partition name # Input: ${1} - string to be validated # check_part_name() { cnt=`expr "${1}" : 'c[0-9][0-9]*t[0-9][0-9]*d[0-9][0-9]*p[1-4]$'` if [ ${cnt} -eq 0 ]; then cnt=`expr "${1}" : 'c[0-9][0-9]*d[0-9][0-9]*p[1-4]$'` if [ ${cnt} -eq 0 ]; then return 0 fi fi return 1 } # check_slice_name() # Purpose: subroutine to check if string is a valid canonical # slice name # Input: ${1} - string to be validated # check_slice_name() { cnt=`expr "${1}" : 'c[0-9][0-9]*t[0-9][0-9]*d[0-9][0-9]*s[0-7]$'` if [ ${cnt} -eq 0 ]; then cnt=`expr "${1}" : 'c[0-9][0-9]*d[0-9][0-9]*s[0-7]$'` if [ ${cnt} -eq 0 ]; then return 0 fi fi return 1 } # is_slice_name() # Purpose: subroutine determining if string is a valid canonical # slice name # Input: ${1} - string to be validated # is_slice_name() { check_slice_name ${1} if [ $? -eq 0 ]; then device_name=${1} fatal_error ${E_BAD_DEVICE_SPEC} fi } # is_devname() # Purpose: subroutine determining if string is a valid # canonical disk name # Input: ${1} - string to be validated # is_dev_name() { cnt=`expr "${1}" : 'c[0-9][0-9]*t[0-9][0-9]*d[0-9][0-9]*$'` if [ ${cnt} -eq 0 ]; then cnt=`expr "${1}" : 'c[0-9][0-9]*d[0-9][0-9]*$'` if [ ${cnt} -eq 0 ]; then device_name=${1} fatal_error ${E_BAD_DEVICE_SPEC} fi fi } # is_num() # Purpose: Boolean function determining if the string is # comprised entirely of numeric characters # Input: ${1} - string to be validated # is_num() { cnt=`expr "${1}" : '[0-9][0-9]*$'` if [ ${cnt} -eq 0 ]; then return 0 fi return 1 } # check_boot_device() # Purpose: check syntax of boot_device keyword in profile # Input: boot_device # ${1} ${2} # check_boot_device() { # check syntax # valid values: c#[t#]d#s# # c#[t#]d#p# # existing # any check_slice_name ${1} slice=$? check_part_name ${1} part=$? if [ "$slice" -eq 0 -a "$part" -eq 0 -a \ ${1} != "existing" -a ${1} != "any" ]; then device_name=${1} fatal_error ${E_BAD_DEVICE_SPEC} fi # check syntax # valid values: update # preserve if [ "${2}" != "update" -a "${2}" != "preserve" ]; then device_name=${2} fatal_error ${E_INV_PROM_UPDATE} fi } # check_fdisk() # Purpose: check syntax of fdisk keyword in profile # Input: ${1} - # ${2} - # ${3} - # check_fdisk() { # We're doing this backwards (checking field 2 before # checking field 1) because we need `type' to be set # before we can process the size argument. # check syntax # valid values: solaris # dosprimary # x86boot # ### type=`echo ${2} | tr '[A-Z]' '[a-z]'` # lowercase it case "${type}" in solaris | dosprimary | x86boot) ;; *) is_num ${type} if [ $? -eq 0 ]; then cnt=`expr "${type}" : '0x[0-9a-f][0-9a-f]*'` if [ ${cnt} -eq 0 ]; then fatal_error ${E_BAD_TYPE} fi fi ;; esac # check syntax # valid values: rootdisk # all # cx[ty]dz disk=`echo ${1} | tr '[A-z] '[a-z]'` # lowercase it if [ "$type" = "x86boot" ] ; then if [ "$disk"X = "rootdisk"X -o "$disk"X = "all"X ]; then fatal_error ${E_X86BOOT_NO_DEVICE} fi fi if [ "$disk"X != "rootdisk"X -a "$disk"X != "all"X ]; then is_dev_name ${1} fi # check syntax for non-x86boot partitions # valid values: all # delete # maxfree # ### if [ "${type}" != "x86boot" ] ; then size=`echo ${3} | tr '[A-Z]' '[a-z]'` # lowercase it case "${size}" in all | delete | maxfree) ;; *) is_num ${size} if [ $? -eq 0 ]; then fatal_error ${E_BAD_SIZE} fi ;; esac fi } # check_local_filesys() # Purpose: check syntax of local filesys keyword in profile # Input: # filesys [ [ ] ] # ${1} ${2} [ ${3} ] # # [ preserve [ ] # ${4} ${5} # # [ ] # ${4} # check_local_filesys() { # check syntax # valid values: "any", # "rootdisk.s"# # :/ # cx[ty]dzs# disk=`echo ${1} | tr '[A-Z]' '[a-z]'` # lowercase it if [ "$disk"X != "anyX" ]; then cnt=`expr $disk : 'rootdisk[.]s[0-7]'` if [ ${cnt} -eq 0 ]; then # must be in c0txdys0 form is_slice_name $disk fi fi # check syntax # valid values: auto # all # existing # free # ###:### # ### size=`echo ${2} | tr '[A-Z]' '[a-z]'` # lowercase it case "${size}" in auto | all | existing | free) ;; *) # we have a size, so check it out some # check x:y or just a num dash=`expr ${size} : '[0-9]*\(:\)[0-9]*'` t_start=`expr ${size} : '\([0-9]*\):[0-9]*'` if [ ! "${t_start}" ]; then # if the start cyl is not there, must be a num is_num ${size} if [ $? -eq 0 ]; then fatal_error ${E_BAD_SIZE} fi fi ;; esac # check syntax # valid values: swap # unnamed # overlap # ignore # mount=`echo ${3} | tr '[A-Z]' '[a-z]'` # lowercase it case "${mount}" in swap | unnamed | overlap | ignore) ;; *) if [ -n "${3}" ]; then # expr would take "/" as being a division, # so special case this first_let=`expr "${3}"X : '\(.\)[.]*'` if [ "${first_let}" != "/" ]; then fatal_error ${E_MOUNT_FULL_PATH} fi fi ;; esac } # check_remote_filesys() # Purpose: check syntax of remote filesys keyword in profile # Inputs: $* are all the arguments on the remote filesys line # # filesys |"-" [ ] [ ] # ${1} ${2} [ ${3} ] [ ${4} ] # check_remote_filesys() { # check syntax # valid values: - # #.#.#.# if [ "${2}"X != "-"X ]; then cnt=`expr ${2} : '[0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*[.][0-9][0-9]*'` if [ ${cnt} -eq 0 ]; then fatal_error ${E_INV_SERVER_ADDR} fi fi # check syntax # valid values: mount=`echo ${3} | tr '[A-Z]' '[a-z]'` # lowercase it first_let=`expr "${3}"X : '\(.\)[.]*'` if [ "${first_let}" != "/" ]; then fatal_error ${E_MOUNT_FULL_PATH} fi } # check_type() # Purpose: make sure the keyword is appropriate for the install_type # specified (fatal exit with error message if not) # Input: ${1} - 'I' or 'U' specifiying if the command is install # or upgrade specific check_type() { if [ "${INSTALL}"X = "INITIAL_INSTALLX" ]; then if [ "${1}" = "U" ]; then fatal_error ${E_UPGRADE_KEY} fi elif [ "${INSTALL}"X = "UPGRADEX" ]; then if [ "${1}" = "I" ]; then fatal_error ${E_INITIAL_KEY} fi fi } # check_profile_file() # Purpose: syntax check the profile # Input: ${1} - input file name # check_profile_file() { profile_ln=0 INSTALL="" ROOTDEV="" BOOTDEV="" SYSTEM="" PRODUCT="" PARTITION="" META="" while read first rest ; do profile_ln=`expr ${profile_ln} + 1` case ${first} in \#*) # comment continue ;; "") # blank line continue ;; esac # take out comments at end of line, and white space before # comment. this does have the side effect of not allowing # any '#' to be in the grammar, but that is acceptable. tmp_rest=`echo ${rest} | sed 's/[ ]*\#.*$//'` if [ -z "${tmp_rest}" ]; then set -- "" shift else set -- ${tmp_rest} fi # set current line being evaluated for error reporting line="${first} ${tmp_rest}" keyword=`echo ${first} | tr '[a-z]' '[A-Z]'` # uppercase it # process the keyword case ${keyword} in BACKUP_MEDIA) # validate argument count if [ $# -gt 2 ]; then fatal_error ${E_EXCESS_ARGS} elif [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi # uppercase the identifier IDENTIFIER=`echo ${1} | tr '[a-z]' '[A-Z]'` case ${IDENTIFIER} in LOCAL_TAPE | LOCAL_DISKETTE | \ LOCAL_FILESYSTEM | REMOTE_SYSTEM | \ REMOTE_FILESYSTEM) ;; *) fatal_error ${E_INV_BACKUP_IDENT} ;; esac check_type "U" ;; LAYOUT_CONSTRAINT) # validate argument count if [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi # uppercase the identifier IDENTIFIER=`echo ${2} | tr '[a-z]' '[A-Z]'` case ${IDENTIFIER} in MOVABLE | AVAILABLE | COLLAPSE) if [ $# -gt 2 ]; then fatal_error ${E_EXCESS_ARGS} fi ;; CHANGEABLE) if [ $# -eq 3 ]; then is_num ${3} if [ $? -eq 0 ]; then fatal_error ${E_INVALID_NUMBER} fi elif [ $# -gt 3 ]; then fatal_error ${E_EXCESS_ARGS} fi ;; *) fatal_error ${E_INV_LAYOUT_CONSTRAINT} ;; esac is_slice_name ${1} check_type "U" ;; CLIENT_ARCH) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi check_type "I" ;; CLIENT_SWAP) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_num ${1} if [ $? -eq 0 ]; then fatal_error ${E_INVALID_NUMBER} fi check_type "I" ;; CLIENT_ROOT) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_num ${1} if [ $? -eq 0 ]; then fatal_error ${E_INVALID_NUMBER} fi check_type "I" ;; CLUSTER) # validate argument count if [ $# -gt 2 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} elif [ $# -eq 2 ]; then # uppercase the action field ACTION=`echo ${2} | tr '[a-z]' '[A-Z]'` if [ "${ACTION}" != "ADD" -a \ "${ACTION}" != "DELETE" ]; then fatal_error ${E_INV_OPTION} echo $? fi fi ;; DONTUSE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_dev_name ${1} check_type "I" ;; FDISK) # validate arguments if [ $# -gt 3 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 3 -a $2 != "x86boot" ]; then fatal_error ${E_LACK_ARGS} fi check_fdisk $* check_type "I" ;; FILESYS) # validate arguments if [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi cnt=`expr ${1} : '..*:/..*'` if [ ${cnt} -gt 0 ]; then if [ $# -gt 4 ]; then fatal_error ${E_EXCESS_ARGS} elif [ $# -lt 3 ]; then fatal_error ${E_LACK_ARGS} fi check_remote_filesys $* else # validate argument count if [ $# -gt 5 ]; then fatal_error ${E_EXCESS_ARGS} elif [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi check_local_filesys $* fi check_type "I" ;; INSTALL_TYPE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi # check for duplicate specification if [ "${INSTALL}X" != "X" ]; then fatal_error ${E_DUP_INST_TYPE} fi # check for valid value INSTALL=`echo ${1} | tr '[a-z]' '[A-Z]'` if [ "${INSTALL}" != "INITIAL_INSTALL" -a \ "${INSTALL}" != "UPGRADE" ]; then fatal_error ${E_INV_INST_TYPE} fi ;; LOCALE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi ;; GEO) # validate argument count if [ $# -gt 1 ] ; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ] ; then fatal_error ${E_LACK_ARGS} fi ;; NOREBOOT) # validate argument count if [ $# -gt 0 ]; then warning_msg ${E_EXCESS_ARGS} fi check_type "I" ;; NUM_CLIENTS) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_num ${1} if [ $? -eq 0 ]; then fatal_error ${E_INVALID_NUMBER} fi check_type "I" ;; PACKAGE) # validate argument count if [ $# -gt 2 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} elif [ $# -eq 2 ]; then # uppercase the action field ACTION=`echo ${2} | tr '[a-z]' '[A-Z]'` if [ "${ACTION}" != "ADD" -a \ "${ACTION}" != "DELETE" ]; then fatal_error ${E_INV_OPTION} fi fi ;; PARTITIONING) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi # check for valid value PARTITION=`echo ${1} | tr '[a-z]' '[A-Z]'` if [ "${PARTITION}" != "DEFAULT" -a \ "${PARTITION}" != "EXISTING" -a \ "${PARTITION}" != "EXPLICIT" ]; then fatal_error ${E_INV_PART_TYPE} fi check_type "I" ;; SWAP_SIZE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_nums ${1} if [ $? -eq 0 ]; then fatal_error ${E_BAD_SIZE} fi check_type "I" ;; SYSTEM_TYPE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi # check for duplicate system_type if [ "${SYSTEM}X" != "X" ]; then fatal_error ${E_DUP_SYS_TYPE} fi # check for valid value SYSTEM=`echo ${1} | tr '[a-z]' '[A-Z]'` if [ "${SYSTEM}" = "DATALESS" ]; then warning_msg ${E_DATALESS_EOL}; elif [ "${SYSTEM}" != "STANDALONE" -a \ "${SYSTEM}" != "SERVER" ]; then fatal_error ${E_INV_SYS_TYPE} fi check_type "I" ;; USEDISK) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi is_dev_name ${1} check_type "I" ;; ROOT_DEVICE) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi # check for duplicate root_device if [ "${ROOTDEV}X" != "X" ]; then fatal_error ${E_DUP_ROOT_DEVICE} fi is_slice_name ${1} ROOTDEV=${1} ;; BOOT_DEVICE) # validate argument count if [ $# -gt 2 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi # check for duplicate boot_device if [ "${BOOTDEV}X" != "X" ]; then fatal_error ${E_DUP_BOOT_DEVICE} fi check_boot_device $* check_type "I" BOOTDEV=${1} ;; ISA_BITS) # validate argument count if [ $# -gt 1 ]; then warning_msg ${E_EXCESS_ARGS} elif [ $# -lt 1 ]; then fatal_error ${E_LACK_ARGS} fi ;; *) # default fatal_error ${E_INVALID_KEY} ;; esac # check for install_type first if [ "${INSTALL}X" = "X" ]; then fatal_error ${E_INST_TYPE_FIRST} fi done # fix the variable line up for any possible warning messages. line="profile ${profile}" if [ "${INSTALL}X" = "X" ];then fatal_error ${E_NO_INST_TYPE} fi profile_ln=0 } # check_rule_file() # Purpose: check syntax of input file (rules) and create derived # file # Input: ${1} - input file name # check_rule_file() { # remove any previously existing profile list file echo > ${PROF_TMP_FILE} # read each rule one at a time, since we don't have to worry about # being in a subshell of the main shell here. in_file="${1}" ln=0 while read first rest; do ln=`expr ${ln} + 1` case ${first} in \#*) # comment continue ;; "") # blank line continue ;; esac # take out comments at end of line this does have the side # effect of not allowing any '#' to be in the grammar, but # that is acceptable. rule=`echo ${first} ${rest} | sed 's/\#.*$//'` # now, for each rule that we have to parse, break it up into # individual match and mulitple match_key arguments. set -- ${rule} line="${rule}" # we need at least 2 args on a probe line... if [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi # if probe function, then run it if [ ${1}"X" = "probeX" ]; then probe_name=${2} # find the probe function in ${CHECK_PROBE} or # ${CUSTOM_PROBES} we can't force the { to be on the # same line, unfortunately grep "probe_${probe_name}[ ]*()" ${CHECK_PROBE} \ >/dev/null rc1=$? # if we found it alread, don't look anymore if [ $rc1 -ne 0 ]; then if [ "${CUSTOM_PROBES}" ]; then grep "probe_${probe_name}[ ]*()" \ ${CUSTOM_PROBES} >/dev/null 2>&1 rc2=$? else rc2=1 fi else rc2=0 fi if [ $rc1 -ne 0 -a $rc2 -ne 0 ]; then fatal_error ${E_PROBE_NOT_FOUND} fi continue fi if [ $# -lt 2 ]; then fatal_error ${E_LACK_ARGS} fi # not a probe...so it must be a compare. # grab the begin, profile, and end scripts/profiles eval `echo ${rule} | \ awk '{printf( "begin=%s; profile=%s; finish=%s", \ $(NF - 2), $(NF - 1), $NF)}'` if [ ${DEBUG} -eq 1 ]; then echo begin=${begin} profile=${profile} finish=${finish} fi # strip the line of the last three arguments... # ("begin", "profile", and "end").. to give only # match/match_key section of the rule matches=`echo ${rule} | \ awk '{ for (i = 1; i < NF - 2; i++) printf("%s ",$i) }'` set -- ${matches} if [ $# -lt 2 ]; then cmp_err_rulename=${1} fatal_error ${E_CMP_LACK_ARGS} fi # split the matches into separate variables, # independant of # of args for easy parsing... ... # it might seem gorpy, but it simplifies the # handling the arguments and leaves the compare # routines free to do what they will with the # arguments. eval `echo ${matches} | awk -F'&&' ' BEGIN {count = 0} { for (i = 1; i <= NF; i++) if ($i != "") { count++ cmd_var = var"_"count printf("%s=\"%s\";",cmd_var,$i) } } END {printf("tot_cmps=%s", count)}' \ var=${CMP_VAR}` # because of previous checks, we must have at least 1 # compare by the time we get here (good syntax is unknown yet) saverc=1 # start with no match cmp_num=0 # make all the compare matches. # NOTE: this loop is running in a subshell, so make sure # you check the exit status of this subshell (after # the loop completes) to determine the exit status # of the main shell while test ${cmp_num} -lt ${tot_cmps} ; do not_flag=0 cmp_num=`expr ${cmp_num} + 1` comp=`eval echo $"${CMP_VAR}_${cmp_num}"` set -- ${comp} if [ "${1}"X = "!"X ]; then not_flag=1 shift fi # check should have made sure there are at least 2 # arguments. set -- `convert_args $*` key=${1} first_arg=${2} # basic check for multi-arg rule cnt check_arg_cnt ${key} $# # run the comparison function; find the probe function # in ${CHECK_PROBE} can't force the { to be on the same # line, unfortunately grep "cmp_${key}[ ]*()" ${CHECK_PROBE} > /dev/null rc1=$? # if we found it already, don't look anymore if [ $rc1 -ne 0 ]; then if [ "${CUSTOM_PROBES}" ]; then grep "cmp_${key}[ ]*()" \ ${CUSTOM_PROBES} > /dev/null rc2=$? else rc2=1 fi else rc2=0 fi if [ $rc1 -ne 0 -a $rc2 -ne 0 ]; then fatal_error ${E_CMP_NOT_FOUND} fi done # if we get here... then all we have left to check for is # the begin, profile, and finish scripts if [ "${begin}" != "-" -a ! -f "${begin}" ]; then fatal_error ${E_BEGIN_NOT_FOUND} fi # profile type case "${profile}" in "-") # null ;; "--") # suppress Solstart - treat as null ;; "=") # derived, must have begin if [ ! -f ${begin} ]; then fatal_error ${E_NO_BEGIN_TO_DERIVE} fi ;; *) # a file name if [ ! -f ${profile} ]; then fatal_error ${E_CLASS_NOT_FOUND} fi ;; esac if [ "${finish}" != "-" -a ! -f ${finish} ]; then fatal_error ${E_FINISH_NOT_FOUND} fi # check input file using check_input file # a "-" means no profile, so don't check it if [ "${profile}" != "-" -a "${profile}" != "--" \ -a "${profile}" != "=" ]; then # only check the profile if it hasn't been # checked before; look for an exact match exist=`egrep -c "^${profile}$" ${PROF_TMP_FILE}` if [ ${exist} -eq 0 ]; then echo "Validating profile ${profile}..." echo ${profile} >> ${PROF_TMP_FILE} profile_file="${profile}" export profile_file check_profile_file < ${profile} fi fi done < ${in_file} estatus=$? rm -f ${PROF_TMP_FILE} if [ ${estatus} -ne 0 ]; then exit 1 fi } usage() { echo "Usage: ${myname} [-r ] [-p ]" exit 1 } ################### # MAIN ################### CHECK_PROBE=/usr/sbin/install.d/chkprobe # # Parse command line options. All options must be by a seperated by a space # while [ "${1}"x != "x" ] ; do case ${1} in -r) # explicit rules file specified if [ ! "${2}" ]; then usage fi RULES=${2} if [ ! -f ${RULES} ]; then echo "No rules file \"${RULES}\" found" exit 1 fi shift 2 ;; -p) if [ ! "${2}" ]; then usage fi CDROM=${2} i_dir=`echo ${CDROM}/Solaris*/Tools/Boot/usr/sbin/install.d` if [ ! -f ${i_dir}/chkprobe ]; then echo "ERROR: ${2} is not a valid Solaris 2.x CD image" exit 1 fi PATH=${i_dir}:${PATH} export PATH CHECK_PROBE=${i_dir}/chkprobe shift 2 ;; *) # -anything else is an unknown argument usage ;; esac done # see if we are trying a different rules file if [ ! "${RULES}" ]; then RULES=${STD_RULES} fi # don't define CUSTOM_PROBES, if none exists if [ ! -f "${CUSTOM_PROBES}" ]; then CUSTOM_PROBES="" fi if [ ! -x "${CHECK_PROBE}" ]; then echo "ERROR: Unable to execute /usr/sbin/chkprobe" usage fi egrep -s probe_installed ${CHECK_PROBE} if [ $? -ne 0 ]; then echo "ERROR: The path to the Solaris CD image is required" echo "Use the -p option." usage fi # check rule file using check_rule_file echo "Validating ${RULES}..." check_rule_file ${RULES} if [ $? -ne 0 ]; then exit 1 fi if [ "${RULES}" = "${STD_RULES}" ]; then create_derived_file ${RULES} ${RULES}.ok append_checksum ${RULES}.ok [ $? -ne 0 ] && exit 1 if [ "${CUSTOM_PROBES}" ]; then create_derived_file ${CUSTOM_PROBES} ${CUSTOM_PROBES}.ok append_checksum ${CUSTOM_PROBES}.ok chmod +x ${CUSTOM_PROBES}.ok fi [ $? -ne 0 ] && exit 1 else # only create a .ok file when checking the standard rules file echo "${RULES}.ok file not created" fi rm -f /tmp/*.$$ # get rid of tmp files.... echo "The custom JumpStart configuration is ok." exit 0