#!/bin/sh #------------------------------------------------------------------------------ # /var/install/bin/update-systemfiles - update system files # # Copyright (c) 2002 Frank Meyer # # Creation: 31.07.2004 jed # Last Update: $Id$ # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. #------------------------------------------------------------------------------ # exec 2>./updates-trace-$$.log # set -x # testroot testroot='' pgmname=`basename $0` # include eislib . /var/install/include/eislib #------------------------------------------------------------------------------ # check if numeric value # input : $1 - value # return: 0 - numeric # 1 - no numeric #------------------------------------------------------------------------------ function is_numeric () { echo "$1" | grep -q '^[0-9]*$' } #------------------------------------------------------------------------------ # check if text value # input : $1 - value # return: 0 - text # 1 - no text #------------------------------------------------------------------------------ function is_text () { # used for service and service aliases # space and tab are not allowed # a-z, 0-9, and hyphen (-) would seem a sensible choice. echo "$1" | grep -q '^[[:alnum:]_.-]*$' } #------------------------------------------------------------------------------ # check if inittab-id value # input : $1 - value # return: 0 - id # 1 - no id #------------------------------------------------------------------------------ function is_inittab_id () { # The id is a unique sequence of 1-4 characters which identifies an entry # in inittab. echo "$1" | grep -q '^[[:alnum:]]\{1,4\}$' } #------------------------------------------------------------------------------ # check if runlevel value # input : $1 - runlevel # $2 - action # return: 0 - runlevel # 1 - no runlevel #------------------------------------------------------------------------------ function is_inittab_runlevel () { # The runlevels field may contain multiple characters for different # runlevels. For example, 123 specifies that the process should be # started in runlevels 1, 2, and 3. The runlevels for 'ondemand' # entries may contain an A, B, or C. The runlevels field of 'sysinit', # 'boot', and 'bootwait' entries are ignored. runlevel=0 case "$2" in boot|bootwait|sysinit ) # runlevels will be ignored ;; ondemand ) # allowed runlevels: 0123456ABC tmpstr=`echo "$1"|sed 's/[0-6ABC]*//g'` ;; * ) # allowed runlevels: 0123456 tmpstr=`echo "$1"|sed 's/[0-6]*//g'` ;; esac if [ "$tmpstr" != "" ] then # false runlevel=1 fi return $runlevel } #------------------------------------------------------------------------------ # check if inittab process exists # input : $1 - value # return: 0 - process ok # 1 - process error #------------------------------------------------------------------------------ function check_inittab_process () { process=0 # remove leading + sign procstr=`echo "$1"|sed 's/^\+//g'` # check if file exists and is executable if [ ! -f "$procstr" -o ! -x "$procstr" ] then # false process=1 fi return $process } #------------------------------------------------------------------------------ # check service port and protocol # input : $1 - value port/protocol # return: 0 - values ok # 1 - values error #------------------------------------------------------------------------------ function check_port_and_protocol () { values=0 oldifs="$IFS" IFS='/' set $1 IFS="$oldifs" # service port if ! is_numeric $1 then print_debug -error "parameter $idx - PORT not allowed: $1" values=1 fi # service protocol if [ "$2" != "tcp" -a "$2" != "udp" -a "$2" != "ddp" ] then print_debug -error "parameter $idx - PROTOCOL not allowed: $2" values=1 fi return $values } #------------------------------------------------------------------------------ # check services line # input : $1 - value # return: 0 - ok # 1 - error #------------------------------------------------------------------------------ function check_services_line () { check_services_line_rtc=0 # strip comments line=`echo "$1"|sed 's/\#.*//g'` if [ "$line" != "" ] then echo "$line"|grep -q "^#" if [ $? -ne 0 ] then set $line idx=1 while [ $# -ne 0 -a $check_services_line_rtc -eq 0 ] do case $idx in 1 ) # service name if ! is_text $1 then print_debug -error "parameter $idx - NAME not allowed: $1" check_services_line_rtc=$idx fi ;; 2 ) # service port and protocol if ! check_port_and_protocol $1 then check_services_line_rtc=$idx fi ;; * ) # service alias if ! is_text $1 then print_debug -error "parameter $idx - ALIAS not allowed: $1" check_services_line_rtc=$idx fi ;; esac # next parameter shift idx=`expr $idx + 1` done fi fi return $check_services_line_rtc } #------------------------------------------------------------------------------ # check inittab line # input : $1 - value # return: 0 - ok # 1 - error #------------------------------------------------------------------------------ function check_inittab_line () { # id:runlevels:action:process check_inittab_line_rtc=0 # ignore lines starting with : echo "$1" | grep -q '^:' && return $check_inittab_line_rtc # strip comments line=`echo "$1"|sed 's/\#.*//g'` if [ "$line" != "" ] then echo "$line"|grep -q "^#" if [ $? -ne 0 ] then oldifs="$IFS" IFS=':' set $line IFS="$oldifs" idx=1 while [ $# -ne 0 -a $check_inittab_line_rtc -eq 0 ] do case $idx in 1 ) # inittab id if ! is_inittab_id $1 then print_debug -error "parameter $idx - ID not allowed: $1" check_inittab_line_rtc=$idx fi ;; 2 ) # inittab runlevel if ! is_inittab_runlevel $1 $2 then print_debug -error "parameter $idx - RUNLEVEL not allowed: $1:$2" check_inittab_line_rtc=$idx fi ;; 3 ) # inittab action case "$1" in respawn|wait|once|boot|bootwait|off|ondemand|initdefault|sysinit|powerwait|powerfail|powerokwait|ctrlaltdel|kbrequest ) # ok ;; * ) # error print_debug -error "parameter $idx - ACTION not allowed: $1" check_inittab_line_rtc=$idx ;; esac ;; 4 ) # inittab process if ! check_inittab_process $1 then print_debug -error "parameter $idx - FILE not found or not executable: $1" check_inittab_line_rtc=$idx fi ;; * ) # ignore rest ;; esac # next parameter shift idx=`expr $idx + 1` done fi fi return $check_inittab_line_rtc } #------------------------------------------------------------------------------ # check services file # input : $1 - file name # output: 0 - ok # <>0 - error (line number) #------------------------------------------------------------------------------ function check_services_file () { check_services_file_rtc=0 f_name="$1" idx=1 while read LINE do if ! check_services_line "$LINE" then check_services_file_rtc=$idx # no break, check whole file #break fi idx=`expr $idx + 1` done < $f_name return $check_services_file_rtc } #------------------------------------------------------------------------------ # check inittab file # input : $1 - file name # output: 0 - ok # <>0 - error (line number) #------------------------------------------------------------------------------ function check_inittab_file () { check_inittab_file_rtc=0 f_name="$1" idx=1 while read LINE do if ! check_inittab_line "$LINE" then check_inittab_file_rtc=$idx # no break, check whole file #break fi idx=`expr $idx + 1` done < $f_name return $check_inittab_file_rtc } #------------------------------------------------------------------------------ # print file header # $1 - file name # $2 - package name #------------------------------------------------------------------------------ print_file_header () { f_name="$1" i_str="$2" echo '#----------------------------------------------------------------------' echo "# ${f_name} file generated by '${i_str}'" echo '#' echo "# Creation date: `date '+%d.%m.%Y'` `whoami`" echo '#' echo "# Do not edit this file directly, create a '${f_name}.package-name'" echo "# file and re-run the '${pgmname}' command to update." echo '#----------------------------------------------------------------------' } #------------------------------------------------------------------------------ # print help #------------------------------------------------------------------------------ print_help () { # show help mecho "Usage:" mecho " $pgmname cannot be called directly. Please use one of the following names:" mecho mecho " update-hosts.allow [-debug] package-name -> update /etc/hosts.allow file." mecho " update-hosts.deny [-debug] package-name -> update /etc/hosts.deny file." mecho " update-services [-debug] package-name -> update /etc/services file." mecho " update-inittab [-debug] package-name -> update /etc/inittab file." } #------------------------------------------------------------------------------ # print debug # input: $1 - output string #------------------------------------------------------------------------------ print_debug () { if [ "$debug" = "-debug" ] then mecho $@ fi } #------------------------------------------------------------------------------ # update hosts.allow or hosts.deny file # $1 - file name # $2 - package name #------------------------------------------------------------------------------ update_hosts_allow_deny_file () { fname="$1" fname_tmp=$fname_tmp.$$ istr="$2" ls ${fname}.*|egrep -v ".backup|~" >/dev/null 2>/dev/null if [ $? -eq 0 ] then # backup file /var/install/bin/backup-file -quiet $fname backup # create fname_tmp with same file access permission like fname [ -f $fname ] && cp -p $fname $fname_tmp # create new file (temporary one) { # print header print_file_header "$fname" "$istr" for FN in `ls ${fname}.*|egrep -v ".backup|~"` do cat $FN done } > ${fname_tmp} # copy file, preserve access permissions cp -p ${fname_tmp} ${fname} rm -f ${fname_tmp} fi } #------------------------------------------------------------------------------ # update services file # $1 - file name # $2 - package name #------------------------------------------------------------------------------ # # format of services file: # # service-name port/protocol [aliases ...] # # separator spaces or tabs # ignore blank line # comments start by # # # old style format (port,protocol) is not supported # update_services_file () { fname="$1" fname_tmp=$fname_tmp.$$ istr="$2" src_work=$fname-work-src.$$ dest_work=$fname-work-dest.$$ # check if files exist ls ${fname}.*|egrep -v ".backup|~" >/dev/null 2>/dev/null if [ $? -eq 0 ] then # backup file /var/install/bin/backup-file -quiet $fname backup # create working copy cp $fname.std $src_work # process all files filelist=`ls ${fname}.*|egrep -v ".backup|.std|~"` for FN in $filelist do if check_services_file $FN then # read files line by line while read line do # ignore blank or empty lines echo "$line" | grep -q '^[[:space:]]*$' && continue # ignore comment only lines echo "$line" | grep "^#" > /dev/null if [ $? -ne 0 ] then # get service name and service protocol sname=`echo $line|cut -d" " -f1|sed 's/ //g'` sprotocol=`echo $line|cut -d" " -f2|sed 's/ //g'|sed 's|[0-9]*/||'` if [ "$sname" != "" ] then # remove old entry if exist grep -v "^$sname[[:space:]]*[0-9]*/$sprotocol" $src_work > $dest_work # take result as base for next compare mv $dest_work $src_work fi fi done < $FN else # error in file - skip it filelist=`echo $filelist|sed "s#$FN##g"` mecho -warn "warning: skipping file $FN because of syntax errors." fi done # create fname_tmp with same file access permission like fname cp -p $fname $fname_tmp # create new file (temporary one) { # print header print_file_header "$fname" "$istr" # use standard file cat $src_work for FN in $filelist do cat $FN done } > ${fname_tmp} # copy file, preserve access permissions cp -p ${fname_tmp} ${fname} rm -f ${fname_tmp} # remove working copy rm -f $src_work fi } #------------------------------------------------------------------------------ # update inittab file # $1 - file name # $2 - package name #------------------------------------------------------------------------------ # # format of inittab file: # # id:runlevels:action:process # # separator : # ignore blank line # comments start by # # update_inittab_file () { fname="$1" fname_tmp=$fname_tmp.$$ istr="$2" src_work=$fname-work-src.$$ dest_work=$fname-work-dest.$$ # check if files exist ls ${fname}.*|egrep -v ".backup|~" >/dev/null 2>/dev/null if [ $? -eq 0 ] then # backup file /var/install/bin/backup-file -quiet $fname backup # create working copy cp $fname.std $src_work # process all files filelist=`ls ${fname}.*|egrep -v ".backup|.std|~"` for FN in $filelist do if check_inittab_file $FN then # read files line by line while read line do # ignore blank or empty lines echo "$line" | grep -q '^[[:space:]]*$' && continue # ignore comments echo $line|grep "^#" > /dev/null if [ $? -ne 0 ] then # get id id=`echo $line|cut -d":" -f1|sed 's/ //g'` if [ "$id" != "" ] then # remove old entry if exist grep -v "^$id:" $src_work > $dest_work # take result as base for next compare mv $dest_work $src_work fi fi done < $FN else # error in file - skip it filelist=`echo $filelist|sed "s#$FN##g"` mecho -warn "warning: skipping file $FN because of syntax errors." fi done # create fname_tmp with same file access permission like fname cp -p $fname $fname_tmp # create new file (temporary one) { # print header print_file_header "$fname" "$istr" # use standard file cat $src_work for FN in $filelist do cat $FN done } > ${fname_tmp} # copy file, preserve access permissions cp -p ${fname_tmp} ${fname} rm -f ${fname_tmp} # remove working copy rm -f $src_work fi } #============================================================================== # main #============================================================================== if [ $# -eq 0 ] then # show help print_help else # update files while [ 1 ] do case "$1" in -debug) debug='-debug' shift ;; *) infostr="$1" break ;; esac done case $pgmname in update-hosts.allow|hosts.allow) update_hosts_allow_deny_file $testroot/etc/hosts.allow "$infostr" ;; update-hosts.deny|hosts.deny) update_hosts_allow_deny_file $testroot/etc/hosts.deny "$infostr" ;; update-services|services) update_services_file $testroot/etc/services "$infostr" ;; update-inittab|inittab) update_inittab_file $testroot/etc/inittab "$infostr" if [ "$debug" != "-debug" ] then /sbin/init q >/dev/null 2>/dev/null else mecho -warn "warning: debug mode enabled, inittab configuration will not be reloaded." fi ;; *) mecho -info 'program name not allowed, use one of the following names:' print_help esac fi #============================================================================== # end #==============================================================================