#!/bin/sh # #pragma ident "@(#)rm_install_client.sh 1.40 11/03/16 SMI" # # Copyright (c) 1991, 2011, Oracle and/or its affiliates. All rights reserved. # # Description: # cleanup a server that previosly had add_install_client run on it # # # # Constants # SIGHUP=1 SIGINT=2 SIGQUIT=3 SIGTERM=15 VERSION="5.0" # # Variables # SERVER=`uname -n` CLIENT_NAME="" DHCP_CLIENT_ID="" KARCH="" TmpANS=/tmp/tmpans.$$ # if the LOCKFILE string is changed it MUST also be # changed in add_install_client # LOCKFILE=/tmp/.install_client.lck LOCKFILE_CREATED= # make sure path is ok PATH=/usr/bin:/usr/etc:/usr/sbin:${PATH} # tr may fail in some locales. Hence set the env LANG=C and LC_ALL=C TR='env LC_ALL=C LANG=C /bin/tr' # # cleanup_and_exit # # Purpose : Remove lock file and exit # # Arguments : # $1 - exit code # cleanup_and_exit () { rm -f $TmpANS if [ -n "$LOCKFILE_CREATED" ] ; then rm -f $LOCKFILE fi exit $1 } abort() { echo "${myname}: Aborted" cleanup_and_exit 1 } usage () { echo "Usage: ${myname} clientname" echo echo "DHCP clients:" echo " ${myname} platform name" echo " ${myname} ethernet address" echo " ${myname} -f boot file name" cleanup_and_exit 1 } # Files Modified by the script # Functions: # dirname might not be installed on this (4.X) machine dirname () { expr ${1-.}'/' : '\(/\)[^/]*//*$' \ \| ${1-.}'/' : '\(.*[^/]\)//*[^/][^/]*//*$' \ \| . } # # Find the sources that the nsswitch.conf(4) file defines for the given database # # Takes a single argument, database. # # e.g. - get_sources hosts # # Returns a list of sources on stdout # get_sources() { egrep "^${1}:" /etc/nsswitch.conf 2>/dev/null | \ sed -e '/^$/d' \ -e '/^#/d' \ -e 's/.*://' \ -e 's/\[.*return\].*$//' \ -e 's/\[.*\].*$//' | \ awk '{ for(i=1; i <= NF; i++) { print $i } }' } # # Determine if the given database is served by the given source # # Takes two arguments, database, and service: # # e.g. - db_in_source hosts files # # Returns the status: # 0 - database in listed source. # 1 - database not in listed source. # db_in_source() { echo `get_sources "${1}"` | grep "\<${2}\>" > /dev/null 2>&1 return $? } # # Lookup the given key in the specified database, returns data retrieved, plus # the source that returned it. # # Retuires two arguments: database and key # # e.g. - lookup hosts binky # # above example will return data for binky and the source it was found in, if # it is found. # # Has two optional arguments: type_of_lookup and source # # e.g. - lookup hosts 129.152.221.35 byaddr files # # above example will return data for host 129.152.221.35 using an address lookup # in files only. # lookup() { D="${1}" K="${2}" T="${3}" S="${4}" ANS="" status=0 if [ ! -z "${S}" ]; then srcs="${S}" else srcs=`get_sources "${D}"` fi for i in ${srcs}; do SRC=${i} case "${i}" in compat) ;; dns) if [ ${HAVE_DNS} -ne 0 ]; then NS="DNS" NS_NAME="domain name service" if [ "${D}" = "hosts" ]; then ANS=`nslookup ${K} | sed '/^;;/d' 2>&1` echo "${ANS}" | grep '^\*\*\*' > /dev/null 2>&1 if [ $? -eq 0 ]; then status=1 else status=0 fi if [ ${status} -eq 0 ]; then break fi fi fi ;; files) NS="local" NS_NAME="file" case "${D}" in bootparams) dbfile=/etc/bootparams key="^\<${K}\>" ;; ethers) dbfile=/etc/ethers key="^[ ]*[^# ].*\<${K}\>" [ "${T}" = "byaddr" ] && key="^\<${K}\>" ;; hosts) dbfile=/etc/hosts key="^[ ]*[^# ].*\<${K}\>" [ "${T}" = "byaddr" ] && key="^\<${K}\>" ;; esac if [ -f "${dbfile}" ]; then match_pattern "${K}" "${dbfile}" status=$? if [ ${status} -eq 0 ]; then ANS=`echo "${ANS}" | sed -e 's/#.*$//'` break fi fi ;; nis) if [ ${HAVE_NIS} -ne 0 ]; then NS="NIS" NS_NAME="map" case "${D}" in bootparams) mapname=${D} ;; ethers) mapname=${D}.byname [ "${T}" = "byaddr" ] && mapname=${D}.byaddr ;; hosts) mapname=${D}.byname [ "${T}" = "byaddr" ] && mapname=${D}.byaddr [ "${T}" = "byuser" ] && mapname=${D}.byuser ;; esac ANS=`ypmatch "${K}" "${mapname}" 2>/dev/null` status=$? if [ ${status} -eq 0 ]; then ANS=`echo "${ANS}" | sed -e 's/#.*$//'` break fi fi ;; nisplus) if [ ${HAVE_NISPLUS} -ne 0 ]; then NS="NIS+" NS_NAME="table" case "${D}" in bootparams) keyname=name ;; ethers) keyname=name [ "${T}" = "byaddr" ] && keyname=addr ;; hosts) keyname=name [ "${T}" = "bycname" ] && keyname=cname [ "${T}" = "byaddr" ] && keyname=addr ;; esac ANS=`nismatch "${keyname}=${K}" "${D}.org_dir" 2>/dev/null` status=$? if [ ${status} -eq 0 ]; then ANS=`echo "${ANS}" | sed -e 's/#.*$//'` break fi fi ;; *) NS="Unknown" NS_NAME="Unknown" SRC="Unknown" ANS="" status=1 ;; esac done ANS=`echo "$ANS" | sed -e 's/#.*$//'` echo "status=${status}; SRC=${SRC}; ANS=\"${ANS}\"; NS=\"${NS}\"; NS_NAME=\"${NS_NAME}\"" } init_lookup() { HAVE_DNS=0 HAVE_NIS=0 HAVE_NISPLUS=0 # # figure out what options the server has for its database(s) # if [ -f /etc/resolv.conf ]; then # DNS Available for host lookups. HAVE_DNS=1 fi if [ -f /var/nis/NIS_COLD_START ]; then # NIS+_client HAVE_NISPLUS=1 fi if ( ps -ef | grep "[ /]nisd" > /dev/null ); then # NIS+_server HAVE_NISPLUS=1 fi if ( ps -ef | grep "[ /]ypserv" > /dev/null ); then # NIS_server HAVE_NIS=1 fi if ( ps -ef | grep "[ /]ypbind" > /dev/null ); then # NIS_client HAVE_NIS=1 fi } # set the HOST_NAME variable, return status of match get_hostname() { HOST_NAME="" if [ ${Iam} = "FIVEX" ]; then eval `lookup hosts "${1}" byname "${2}"` else # FOURX if [ $NS = "NIS+" ]; then ANS=`nismatch ${1} hosts.org_dir 2>/dev/null` status=$? elif [ $NS = "NIS" ]; then ANS=`ypmatch ${1} hosts 2>/dev/null` status=$? else match_pattern "${1}" "/etc/hosts" status=$? fi fi if [ $status -eq 0 ]; then if [ $NS = "NIS+" ]; then HOST_NAME=`echo ${ANS} | \ (read cname name addr junk; echo $name)` elif [ $NS = "NIS" ]; then HOST_NAME=`echo ${ANS} | \ (read addr name junk; echo $name)` elif [ $NS = "DNS" ]; then HOST_NAME=`echo ${ANS} | sed -e 's/^Server:.*Name://' |\ (read name junk; echo $name)` else HOST_NAME=`echo ${ANS} | \ (read addr name junk; echo $name)` fi fi return $status } # set the HOST_ADDR variable, return status of match get_hostaddr() { HOST_ADDR="" if [ ${Iam} = "FIVEX" ]; then eval `lookup hosts "${1}" byname "${2}"` else # FOURX if [ $NS = "NIS+" ]; then ANS=`nismatch ${1} hosts.org_dir 2>/dev/null` status=$? elif [ $NS = "NIS" ]; then ANS=`ypmatch ${1} hosts 2>/dev/null` status=$? else match_pattern "${1}" "/etc/hosts" status=$? fi fi if [ $status -eq 0 ]; then if [ $NS = "NIS+" ]; then HOST_ADDR=`echo ${ANS} | \ (read cname name addr junk; echo $addr)` elif [ $NS = "NIS" ]; then HOST_ADDR=`echo ${ANS} | \ (read addr name junk; echo $addr)` elif [ $NS = "DNS" ]; then HOST_ADDR=`echo ${ANS} | sed -e 's/^Server:.*Address://' |\ (read addr junk; echo $addr)` else HOST_ADDR=`echo ${ANS} | \ (read addr name junk; echo $addr)` fi fi return $status } # convert any host alias to real client name get_realname() { get_hostname ${CLIENT_NAME} if [ ! "${HOST_NAME}" ]; then echo "Error: unknown client \"${CLIENT_NAME}\"" cleanup_and_exit 1 fi CLIENT_NAME=${HOST_NAME} } # # $1 == pattern to search for # $2 == database to search # match_pattern() { ANS= status=0 Found="no" if [ "${2}" = "/etc/bootparams" ] then key="^\<${1}\>" else key="^[ ]*[^# ].*\<${1}\>" fi grep "${key}" "${2}" 2>/dev/null | while read Line do for KEY in `echo $Line` do if [ "$Found" != "yes" ] ; then if [ "$1" = "$KEY" ] ; then echo $Line > $TmpANS Found="yes" fi fi done done if [ -f $TmpANS ] ; then ANS=`cat ${TmpANS}` rm -f $TmpANS else status=1 fi return $status } # # main # myname=$0 ID=`id` USER=`expr "${ID}" : 'uid=\([^(]*\).*'` trap abort $SIGHUP $SIGINT $SIGQUIT $SIGTERM if [ "${USER}" != "0" ]; then echo "You must be root to run $0" cleanup_and_exit 1 fi # # Lock file to prevent simultaneous access of system files # (/etc/bootparams, /etc/ethers, etc.) # # This is not the best solution, race conditions still exist, # but it is better than nothing. The lock file is created here # and removed in the cleanup_and_exit() function. # if [ ! -f $LOCKFILE ] ; then LOCKFILE_CREATED=yes echo $$ > $LOCKFILE else echo "There is an existing install client lock file, ${LOCKFILE}," echo "which indicates that process `cat $LOCKFILE` is executing" echo "either an add_install_client or a rm_install_client. If this" echo "is not the case, delete the lock file, $LOCKFILE, and " echo "execute $myname again. Otherwise, wait until the lockfile is" echo "removed and re-run $myname." cleanup_and_exit 2 fi # Set the umask. # umask 022 if [ -f /etc/vfstab ]; then Iam="FIVEX"; Opts_df="-k" Opts_ps="-e" Opts_ps_pid="-e" Cmd_bpd="/usr/sbin/rpc.bootparamd" elif [ -f /etc/fstab ]; then Iam="FOURX"; Opts_df="" Opts_ps="-ax" Opts_ps_pid="-x" Cmd_bpd="/usr/etc/rpc.bootparamd" else echo "${myname}: no /etc/fstab or /etc/vfstab, bailing out" cleanup_and_exit 1 fi # Parse the command line options. All options must be seperated by a space # while [ "X$1" != "X" ] ; do case $1 in -f) BOOT_FILE="$2"; if [ ! "$BOOT_FILE" ] ; then usage; fi shift 2;; [a-zA-Z0-9]*) # Must be the client name, ethernet addr, or platform name # ought to be the last thing if [ $# -ne 1 ] ; then usage; fi NAME="$1"; shift $# ;; *) # then all else is spurious usage ; ;; esac done if [ "X$BOOT_FILE" != "X" -a "X$NAME" != "X" ] ; then usage fi if [ "X$BOOT_FILE" = "X" -a "X$NAME" = "X" ] ; then usage fi Bootdir=/tftpboot Real_Bootdir=$Bootdir if [ -h $Bootdir ] ; then CurrentPwd=`pwd` cd $Bootdir Real_Bootdir=`pwd` cd $CurrentPwd fi # # If they are asking to delete a specific boot file, handle it here so we # don't have to deal with it later. # if [ "X$BOOT_FILE" != "X" ]; then if [ -h "${Bootdir}/$BOOT_FILE" ] ; then if [ -f "${Bootdir}/$BOOT_FILE" ] ; then # See if we're the only person pointing to the referenced # boot file. bftarg=`/bin/ls -l ${Bootdir}/bootfile | sed -e 's/^.*-> //g'` if [ "`ls -l ${Bootdir} |grep -w ${bftarg} |wc -l`" -eq 2 ]; then # Yes, we are echo "Removing ${Bootdir}/${bftarg}" rm -f ${Bootdir}/${bftarg} fi else # The target of the link no longer exists echo "WARNING: Bootfile \"$BOOT_FILE\" is a dangling symlink." echo " The inetboot file it referenced no longer exists." echo fi elif [ -f "${Bootdir}/$BOOT_FILE" ] ; then # It's not a symlink - it's just a file. This shouldn't # happen, but we'll blow it away anyway. echo "WARNING: Boot file \"$BOOT_FILE\" should be a symlink, but is" echo " a file." echo else echo "ERROR: Requested boot file \"$BOOT_FILE\" doesn't exist or" echo " isn't a file." cleanup_and_exit 1 fi echo "Removing boot file \"$BOOT_FILE\"" rm -f ${Bootdir}/$BOOT_FILE cleanup_and_exit 0 fi # Try to parse the argument as each of the three argument types (client name, # ethernet address, or DHCP class name. We can only validate the ethernet # address, because the others don't have forms that lend themselves to easy # validation. CLIENT_NAME="$NAME"; ETHER_ADDR=`expr "$NAME" : '\([0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\:[0-9a-fA-F][0-9a-fA-F]*\)'` if [ "X${ETHER_ADDR}" != "X" ] ; then DHCP_CLIENT_ID=01`echo "${ETHER_ADDR}" | ${TR} '[a-z]' '[A-Z]' | awk -F: ' { for (i = 1; i <= 6 ; i++) if (length($i) == 1) { printf("0%s", $i) } else { printf("%s", $i); } }'` fi DHCP_CLASS_NAME=`echo "$NAME" |sed -e 's/,/./g'` # # See if there's a cleanup file corresponding to the passed DHCP class name # or ethernet address # if [ "X${DHCP_CLIENT_ID}" != "X" -a \ -f "${Bootdir}/rm.${DHCP_CLIENT_ID}" ] ; then CLIENT_TYPE=DHCPEther CLEAN=${Bootdir}/rm.${DHCP_CLIENT_ID} elif [ -f "${Bootdir}/rm.${DHCP_CLASS_NAME}" ] ; then CLIENT_TYPE=DHCPClass CLEAN=${Bootdir}/rm.${DHCP_CLASS_NAME} else CLIENT_TYPE=RARP # We have to determin the name for the clean file later, after # we've gotten the IP address CLEAN="${Bootdir}/rm.${IP_ADDR}" fi # # no check to see if cdrom is mounted, since it may not be a real CDROM # Someone might copy all/part of it to some disk someplace. # We do not care, as long as they maintain # the hierarchy structure and RUN THIS COMMAND FROM THAT HIERARCHY. # # (1) find the path of the hierarchy. # it may be absolute path # it may be some relative path # it may be given in PATH case ${myname} in /*) # absolute path, or found via $PATH (shells turn into abs path) CDROM=`dirname ${myname}` myname=`expr ${myname} : '.*/\(.*\)' ` ;; ../*) # relative path from "../", so we do a bit of clean up CDROM=`pwd`/`dirname ${myname}` CDROM=`(cd ${CDROM} ; pwd )` myname=`expr ${myname} : '.*/\(.*\)' ` ;; ./*) # relative path from "./", toss the "./" longname=`dirname ${myname}` CDROM=`pwd`/` expr ${longname} : '\.\/\(.*\)' ` # get rid of any strange appendages, like "/" or dot-dots CDROM=`(cd ${CDROM} ; pwd )` myname=`expr ${myname} : '.*/\(.*\)' ` ;; *) # name found via "." in $PATH CDROM=`pwd` ;; esac # # figure out what the server is using for its database(s) # if [ ${Iam} = "FOURX" ]; then if [ -f /var/nis/NIS_COLD_START ]; then # NIS+_client NS="NIS+" NS_NAME="table" elif ( ps ${Opts_ps} | grep "[ /]nisd" > /dev/null ); then # NIS+_server NS="NIS+" NS_NAME="table" elif ( ps ${Opts_ps} | grep "[ /]ypserv" > /dev/null ); then # NIS_server NS="NIS" NS_NAME="map" elif ( ps ${Opts_ps} | grep "[ /]ypbind" > /dev/null ); then # NIS_client NS="NIS" NS_NAME="map" else NS="local" NS_NAME="file" fi else # FIVEX init_lookup fi if [ "X$CLIENT_TYPE" = "XRARP" ] ; then get_realname # # Check to see if IP and ETHER address and BOOTPARAMS have # been determined # # # find the IP_ADDR of this client, if not known, complain, as this # is needed to find the /tftpboot/config. file # get_hostaddr ${CLIENT_NAME} IP_ADDR=${HOST_ADDR} if [ ! "${IP_ADDR}" ]; then echo "${myname}: ERROR: cannot find IP address for $CLIENT_NAME" echo "The client name may be misspelled, or this system may have been" echo "reconfigured after add_install_client was run." echo "Enter $CLIENT_NAME IP address into the $NS $NS_NAME" echo "then run ${myname} again." cleanup_and_exit 1 fi # config filename IP address is not the HEXIP, (for client's sake) CLEAN="${Bootdir}/rm.${IP_ADDR}" if [ ! -f "${CLEAN}" ]; then # Back in the mists of RARP time, Intel clients stored their # boot files in /rplboot. Look in /rplboot if we don't find # it in /tftpboot. Intel DHCP clients never stored files in # /rplboot. Bootdir=/rplboot Real_Bootdir=$Bootdir if [ -h $Bootdir ] ; then CurrentPwd=`pwd` cd $Bootdir Real_Bootdir=`pwd` cd $CurrentPwd fi CLEAN="${Bootdir}/rm.${IP_ADDR}" if [ ! -f "${CLEAN}" ]; then echo "${myname}: the file \"rm.${IP_ADDR}\" does not exist in" echo "/tftpboot or /rplboot, cannot do cleanup for \"${CLIENT_NAME}\"" cleanup_and_exit 1 fi fi egrep -s "^${CLIENT_NAME}[ ]" /etc/bootparams if [ $? -eq 0 ]; then rm -f /etc/bootparams.old cp /etc/bootparams /etc/bootparams.old # Save old one echo "removing ${CLIENT_NAME} from bootparams" ( echo "g/^${CLIENT_NAME}[ ]/d" ; echo w; echo q ) | \ ed /etc/bootparams > /dev/null fi if [ -f /etc/bootparams -a ! -s /etc/bootparams ]; then echo "removing /etc/bootparams, since it is empty" rm /etc/bootparams fi fi . ${CLEAN} rm -f ${CLEAN} cnt=`ls ${Real_Bootdir} | wc -l` case ${Bootdir} in /tftpboot) if [ ${cnt} -eq 1 -a -h ${Real_Bootdir}/tftpboot ]; then if [ "${Bootdir}" = "${Real_Bootdir}" ] ; then echo "removing /tftpboot" rm ${Bootdir}/tftpboot rmdir ${Bootdir} else echo "removing ${Real_Bootdir}/tftpboot" rm ${Real_Bootdir}/tftpboot fi # If smf not present on the system, then clean up inetd.conf if [ ! -f /lib/svc/share/smf_include.sh ]; then # clean up inetd.conf if grep '^tftp[ ]' /etc/inetd.conf > /dev/null ; then # found it, so it must be enabled, use ed to fix it echo "disabling tftp in /etc/inetd.conf" ( echo "/^tftp/" ; echo "s/^/#/" ; echo "w"; echo "w"; echo "q" ) | \ ed -s /etc/inetd.conf >/dev/null # send a HUP to tell it to re-read inetd.conf pid=`ps ${Opts_ps_pid} |grep '[ /]inetd' | ( read pid junk ; echo $pid )` kill -HUP $pid fi fi fi ;; /rplboot) if [ ${cnt} -eq 0 ]; then if [ "${Bootdir}" = "${Real_Bootdir}" ] ; then echo "removing $Bootdir" rmdir ${Bootdir} fi # kill the daemon if no longer anybody's server. pid=`ps ${Opts_ps_pid} |grep '[ /]rpld' | ( read pid junk; echo $pid )` echo "No longer a rpl server. Terminating rpld." kill -TERM $pid fi ;; esac if [ "X$CLIENT_TYPE" = "XDHCPEther" ] ; then echo "To disable ${ETHER_ADDR} in the DHCP server," echo " remove the entry with Client ID ${DHCP_CLIENT_ID}" fi cleanup_and_exit 0