Home | History | Annotate | Download | only in acct
      1 #!/sbin/sh
      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 #       Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
     23 #         All Rights Reserved
     24 #	Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     25 #	Use is subject to license terms.
     26 
     27 
     28 #ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.9	*/
     29 #       "nitely accounting shell, should be run from cron (adm) at 4am"
     30 #	"does process, connect, disk, and fee accounting"
     31 #	"prepares command summaries"
     32 #	"shell is restartable and provides reasonable diagnostics"
     33 _adm=/var/adm
     34 _nite=/var/adm/acct/nite
     35 _sum=/var/adm/acct/sum
     36 _wtmpx=/var/adm/wtmpx
     37 PATH=/usr/lib/acct:/usr/bin:/usr/sbin
     38 export PATH
     39 _statefile=${_nite}/statefile
     40 _active=${_nite}/active
     41 _lastdate=${_nite}/lastdate
     42 _date="`date +%m%d`"
     43 _errormsg="\n\n************ ACCT ERRORS : see  ${_active}${_date}********\n\n"
     44 _MIN_BLKS=500
     45 
     46 cd ${_adm}
     47 #		"make sure that 2 crons weren't started, or leftover problems"
     48 date  > ${_nite}/lock1
     49 chmod 400 ${_nite}/lock1
     50 ln ${_nite}/lock1 ${_nite}/lock
     51 if test $? -ne 0; then
     52 	_lnkerr="\n\n*********** 2 CRONS or ACCT PROBLEMS***********\n\n\n"
     53 	(date ; echo "$_lnkerr" ) | logger -p daemon.err
     54 	echo "$_lnkerr" | mailx adm root
     55 	echo "ERROR: locks found, run aborted" >> ${_active}
     56 	rm -f ${_nite}/lock*
     57 	exit 1
     58 fi
     59 
     60 # Check to see if there is enough space in /var/adm to do nitely accounting
     61 #
     62 _blocks=`df $_adm | sed 's/.*://' | awk '{ print $1 }'`
     63 if [ "$_blocks" -le $_MIN_BLKS ];then
     64 	echo "runacct: Insufficient space in $_adm ($_blocks blks); \c"
     65 	echo "Terminating procedure"
     66 	( echo "runacct: Insufficient space in $_adm ($_blocks blks); \c"
     67 	echo "Terminating procedure" ) > /tmp/accounting_tmpfile 
     68 	cat /tmp/accounting_tmpfile >> ${_active} 
     69         cat /tmp/accounting_tmpfile | logger -p daemon.err   
     70         mailx root adm < /tmp/accounting_tmpfile 
     71         rm /tmp/accounting_tmpfile 
     72 
     73 	rm -f ${_nite}/lock*
     74 	exit 1
     75 fi
     76 
     77 
     78 case $# in
     79 0)
     80 #	"as called by the cron each day"
     81 	if test ! -r ${_lastdate} ; then
     82 		echo "0000" > ${_lastdate}
     83 	fi
     84 	if test "${_date}" = "`cat ${_lastdate}`"; then
     85 		(date; echo "${_errormsg}") | logger -p daemon.err
     86 		echo "${_errormsg}" | mailx root adm
     87 		echo "ERROR: acctg already run for `date`: check ${_lastdate}" >> ${_active}
     88 		rm -f ${_nite}/lock*
     89 		mv ${_active} ${_active}${_date}
     90 		exit 1
     91 	fi
     92 	echo ${_date} > ${_lastdate}
     93 	echo "SETUP" > ${_statefile}
     94 	nulladm ${_active}
     95 	echo ${_date} > ${_active}    # debuging
     96 	echo "\n\n\n\n\n**********  SYSTEM ACCOUNTING STARTED `date`  **********\n\n\n\n\n" | logger -p daemon.notice
     97 	echo ${_date} > ${_active}    # debuging
     98 	;;
     99 
    100 1)
    101 #	"runacct MMDD  (date)  will restart at current state"
    102 	_date=$1
    103 	_errormsg="\n\n************ ACCT ERRORS : see  ${_active}${_date}********\n\n"
    104 	echo "restarting acctg for ${_date} at `cat ${_statefile}`" >> ${_active}
    105 	echo "\n\n\n\n\n********** SYSTEM ACCOUNTING RESTARTED `date` **********\n\n\n\n\n" | logger -p daemon.notice
    106 	;;
    107 
    108 2)
    109 #	"runacct MMDD STATE  restart at specified state"
    110 	_date=$1
    111 	_errormsg="\n\n************ ACCT ERRORS : see  ${_active}${_date}********\n\n"
    112 	echo "restarting acctg for ${_date} at $2" >> ${_active}
    113 	echo "previous state was `cat ${_statefile}`" >> ${_active}
    114 	echo "$2" > ${_statefile}
    115 	echo "\n\n\n\n\n********** SYSTEM ACCOUNTING RESTARTED `date` **********\n\n\n\n\n" | logger -p daemon.notice
    116 	;;
    117 *)
    118 	(date; echo "${_errormsg}") | logger -p daemon.err
    119 	echo "${_errormsg}" | mailx root adm
    120 	echo "ERROR: runacct called with invalid arguments" > ${_active}
    121 	rm -f ${_nite}/lock*
    122 	mv ${_active} ${_active}${_date}
    123 	exit 1
    124 	;;
    125 esac
    126 
    127 
    128 #	"processing is broken down into seperate, restartable states"
    129 #	"the statefile is updated at the end of each state so that the"
    130 #	"next loop through the while statement switches to the next state"
    131 while [ 1 ]
    132 do
    133 case "`cat ${_statefile}`" in
    134 SETUP)
    135 
    136 cd ${_adm}
    137 
    138 (date ; ls -l fee pacct* ${_wtmpx}* ) >> ${_active}
    139 
    140 #	"switch current pacct file"
    141 turnacct switch
    142 _rc=$?
    143 if test ${_rc} -ne 0; then
    144 	(date ; echo "${_errormsg}" ) | logger -p daemon.err
    145 	echo "${_errormsg}" | mailx root adm
    146 	echo "ERROR: turnacct switch returned rc=${_rc}" >> ${_active}
    147 	rm -f ${_nite}/lock*
    148 	mv ${_active} ${_active}${_date}
    149 	exit 1
    150 fi
    151 
    152 #	" give pacct files unique names for easy restart "
    153 for _i in pacct?*
    154 do
    155 	if [ "${_i}" = "pacct?*" ]
    156 	then
    157 		rm -f ${_nite}/lock*
    158 		mv ${_active} ${_active}${_date}
    159 		exit 1
    160 	fi
    161 	if test -r S${_i}.${_date} ; then
    162 		 (date ; echo "${_errormsg}" ) | logger -p daemon.err
    163 		echo "${_errormsg}" | mailx root adm
    164 		echo "ERROR: S${_i}.${_date} already exists" >> ${_active}
    165 		echo "file setups probably already run" >> ${_active}
    166 		rm -f ${_nite}/lock*
    167 		mv ${_active} ${_active}${_date}
    168 		exit 1
    169 	fi
    170 	mv ${_i} S${_i}.${_date}
    171 done
    172 
    173 
    174 #	"add current time on end"
    175 if test -r ${_nite}/wtmpx.${_date} ; then
    176 	(date ; echo "${_errormsg}" ) | logger -p daemon.err
    177 	echo "${_errormsg}" | mailx root adm
    178 	echo "ERROR: ${_nite}/wtmpx.${_date} already exists: run setup manually" > ${_active}
    179 	rm -f ${_nite}/lock*
    180 	mv ${_active} ${_active}${_date}
    181 	exit 1
    182 fi
    183 closewtmp	# fudge a DEAD_PROCESS for /var/wtmpx
    184 cp ${_wtmpx} ${_nite}/${_date}.wtmpx
    185 acctwtmp "runacct" ${_nite}/${_date}.wtmpx
    186 nulladm ${_wtmpx}
    187 utmp2wtmp	# fudge active user from utmpx to wtmpx
    188 
    189 echo "files setups complete" >> ${_active}
    190 echo "WTMPFIX" > ${_statefile}
    191 ;;
    192 
    193 WTMPFIX)
    194 #	"verify the integrity of the wtmpx file"
    195 #	"wtmpfix will automatically fix date changes"
    196 cd ${_nite}
    197 nulladm tmpwtmp wtmperror
    198 wtmpfix < ${_date}.wtmpx > tmpwtmp 2>wtmperror
    199 if test $? -ne 0 ; then
    200 	(date ; echo "${_errormsg}") | mailx root adm
    201 	echo "${_errormsg}" | logger -p daemon.err
    202 	echo "ERROR: wtmpfix errors see ${_nite}/wtmperror${_date}" >> ${_active}
    203 	rm -f ${_nite}/lock*
    204 	mv ${_active} ${_active}${_date}
    205 	mv wtmperror wtmperror${_date}
    206 	exit 1
    207 fi
    208 
    209 echo "wtmpx processing complete" >> ${_active}
    210 echo "CONNECT" > ${_statefile}
    211 ;;
    212 
    213 
    214 CONNECT)
    215 #	"produce connect records"
    216 #	"the lineuse and reboots files are used by prdaily"
    217 cd ${_nite}
    218 nulladm lineuse reboots log ctacct.${_date}
    219 acctcon -l lineuse -o reboots < tmpwtmp  2> log > ctacct.${_date}
    220 
    221 # if the following test is true, then pnpsplit complained about
    222 # the year and holidays not being up to date.  This used to be
    223 # a fatal error, but now it will continue to process the accounting.
    224 # 
    225 if test -s log ; then 
    226 	(date ; cat ${_nite}/log) | mailx adm root
    227 	echo "\n\n************ ACCT ERRORS : see  ${_nite}log********\n\n" | logger -p daemon.err
    228 	cat ${_nite}/log >> ${_active}${_date}
    229 fi
    230 
    231 echo "connect acctg complete" >> ${_active}
    232 echo "PROCESS" > ${_statefile}
    233 ;;
    234 
    235 
    236 PROCESS)
    237 #	"correlate Spacct and ptacct files by number"
    238 #	"will not process Spacct file if corresponding ptacct exists"
    239 #	"remove the ptacct file to rurun the Spacct file"
    240 #	"if death occurs here, rerunacct should remove last ptacct file"
    241 
    242 cd ${_nite}
    243 for _Spacct in ${_adm}/Spacct*.${_date}
    244 do
    245 	_ptacct=`basename ${_Spacct} | sed 's/Sp/pt/'`
    246 	if test -s ${_ptacct}; then
    247 		echo "WARNING: accounting already run for ${_Spacct}" \
    248 			>> ${_active}
    249 		echo "WARNING: remove ${_nite}/${_ptacct} to rerun" \
    250 			>> ${_active}
    251 	else
    252 		nulladm ${_ptacct}
    253 		acctprc < ${_Spacct} > ${_ptacct}
    254 	
    255 		echo "process acctg complete for ${_Spacct}" >> ${_active}
    256 	fi
    257 done
    258 echo "all process actg complete for ${_date}" >> ${_active}
    259 echo "MERGE" > ${_statefile}
    260 ;;
    261 
    262 
    263 MERGE)
    264 cd ${_nite}
    265 #	"merge ctacct and ptacct files together"
    266 acctmerg ptacct*.${_date} < ctacct.${_date} > daytacct
    267 
    268 echo "tacct merge to create daytacct complete" >> ${_active}
    269 echo "FEES" > ${_statefile}
    270 ;;
    271 
    272 
    273 FEES)
    274 cd ${_nite}
    275 #	"merge in fees"
    276 if test -s ${_adm}/fee; then
    277 	cp daytacct tmpdayt
    278 	sort +0n +2 ${_adm}/fee | acctmerg -i | acctmerg tmpdayt  > daytacct
    279 	echo "merged fees" >> ${_active}
    280 	rm -f tmpdayt
    281 else
    282 	echo "no fees" >> ${_active}
    283 fi
    284 echo "DISK" > ${_statefile}
    285 ;;
    286 
    287 
    288 DISK)
    289 cd ${_nite}
    290 #	"the last act of any disk acct procedure should be to mv its"
    291 #	"entire output file to disktacct, where it will be picked up"
    292 if test -r disktacct; then
    293 	cp daytacct tmpdayt
    294 	acctmerg disktacct  < tmpdayt > daytacct
    295 	echo "merged disk records" >> ${_active}
    296 	rm -f tmpdayt
    297 	mv disktacct /tmp/disktacct.${_date}
    298 else
    299 	echo "no disk records" >> ${_active}
    300 fi
    301 echo "MERGETACCT" > ${_statefile}
    302 ;;
    303 
    304 MERGETACCT)
    305 cd ${_adm}/acct
    306 #	"save each days tacct file in sum/tacct.${_date}"
    307 #	"if sum/tacct gets corrupted or lost, could recreate easily"
    308 #	"the monthly acctg procedure should remove all sum/tacct files"
    309 cp nite/daytacct sum/tacct${_date}
    310 if test ! -r sum/tacct; then
    311 	echo "WARNING: recreating ${_adm}/sum/tacct " >> ${_active}
    312 	nulladm sum/tacct
    313 fi
    314 
    315 #	"merge in todays tacct with the summary tacct"
    316 rm -f sum/tacctprev
    317 cp sum/tacct sum/tacctprev
    318 acctmerg sum/tacctprev  < sum/tacct${_date} > sum/tacct
    319 
    320 echo "updated sum/tacct" >> ${_active}
    321 echo "CMS" > ${_statefile}
    322 ;;
    323 
    324 
    325 CMS)
    326 cd ${_adm}/acct
    327 #	"do command summaries"
    328 nulladm sum/daycms
    329 if test ! -r sum/cms; then
    330 	nulladm sum/cms
    331 	echo "WARNING: recreating ${_adm}/sum/cms " >> ${_active}
    332 fi
    333 cp sum/cms sum/cmsprev
    334 acctcms ${_adm}/Spacct*.${_date}  > sum/daycms
    335 acctcms -s sum/daycms sum/cmsprev  > sum/cms
    336 acctcms -a -s sum/daycms | sed -n 1,56p  > nite/daycms
    337 acctcms -a -s sum/cms | sed -n 1,56p  > nite/cms
    338 lastlogin 
    339 echo "command summaries complete" >> ${_active}
    340 echo "USEREXIT" > ${_statefile}
    341 ;;
    342 
    343 
    344 USEREXIT)
    345 #	"any installation dependant accounting programs should be run here"
    346 [ -s /usr/lib/acct/runacct.local ] && /usr/lib/acct/runacct.local
    347 
    348 echo "CLEANUP" > ${_statefile}
    349 ;;
    350 
    351 
    352 CLEANUP)
    353 cd ${_adm}/acct
    354 #	" finally clear files; could be done next morning if desired"
    355 nulladm ${_adm}/fee
    356 rm -f ${_adm}/Spacct*.${_date}
    357 #	"put reports onto a file"
    358 prdaily >> sum/rprt${_date};
    359 rm -f nite/lock*
    360 rm -f nite/ptacct*.${_date} nite/ctacct.${_date}
    361 mv -f nite/${_date}.wtmpx nite/owtmpx
    362 rm -f nite/wtmperror${_date} nite/active${_date} nite/tmpwtmp
    363 echo "system accounting completed at `date`" >> ${_active}
    364 echo "********** SYSTEM ACCOUNTING COMPLETED `date` **********" | logger -p daemon.notice
    365 echo "COMPLETE" > ${_statefile}
    366 exit 0
    367 ;;
    368 
    369 *)
    370 	(date;echo "${_errormsg}") | logger -p daemon.err
    371 	echo "${_errormsg}" | mailx adm root
    372 	echo "ERROR: invalid state, check ${_statefile}" >> active
    373 	rm -f ${_nite}/lock*
    374 	mv ${_active} ${_active}${_date}
    375 	exit 1
    376 	;;
    377 esac
    378 done
    379 
    380 
    381 #	" runacct is normally called with no arguments from the cron"
    382 #	" it checks its own locks to make sure that 2 crons or previous"
    383 #	" problems have not occured"
    384 
    385 #	" runacct uses the statefile to record its progress"
    386 #	" each state updates the statefile upon completion"
    387 #	" then the next loop though the while picks up the new state"
    388 
    389 #	" to restart this shell,  check the active file for diagnostics"
    390 #	" fix up any corrupted data (ie. bad pacct or wtmpx files)"
    391 #	" if runacct detected the error it removes the locks"
    392 #	" remove the locks if necessary, otherwise runacct will complain"
    393 #	" the lastdate file should be removed or changed"
    394 #	" restart runacct at current state with:  runacct MMDD"
    395 #	" to override the statefile: runacct MMDD STATE"
    396 
    397 
    398 #	" if runacct has been executed after the latest failure"
    399 #	" ie. it ran ok today but failed yesterday"
    400 #	" the statefile will not be correct"
    401 #	" check the active files and restart properly"
    402 
    403 #	" if runacct failed in the PROCESS state, remove the last"
    404 #	" ptacct file because it may not be complete"
    405 
    406 #	" if shell has failed several days, do SETUP manually"
    407 #	" then rerun runacct once for each day failed"
    408 #	" could use fwtmp here to split up wtmpx file correctly"
    409 
    410 #	" normally not a good idea to restart the SETUP state"
    411 #	" should be done manually, or just cleanup first"
    412 
    413 
    414 #	" FILE USAGE:	all files in /var/adm/acct/nite unless specified"
    415 
    416 #	" statefile	records progess of runacct"
    417 #	" lastdate	last day runacct ran in date +%m%d format"
    418 #	" lock lock1	controls serial use of runacct"
    419 #	" active	place for all descriptive and error messages"
    420 #	" fd2log	fd2 output for runacct ( see cron entry ) "
    421 #	" MMDD.wtmpx    owtmpx yesterdays wtmpx file"
    422 #	" tmpwtmp	yesterdays wtmp corrected by wtmpfix"
    423 #	" wtmperror	place for wtmpfix error messages"
    424 #	" lineuse	lineusage report used in prdaily"
    425 #	" reboots	reboots report used in prdaily"
    426 #	" log		place for error messages from acctcon1"
    427 #	" ctacct.MMDD	connect tacct records for MMDD"
    428 #	" ptacct.n.MMDD	process tacct records n files for MMDD"
    429 #	" daytacct	total tacct records for this days accounting"
    430 #	" disktacct	disk tacct records produced by disk shell"
    431 #	" daycms	ascii daily command summary used by prdaily"
    432 #	" cms		acsii total command summary used by prdaily"
    433 
    434 #	" following files in /var/adm directory"
    435 
    436 #	" fee		output from chargefee program"
    437 #	" pacct		active pacct file"
    438 #	" pacctn	switched pacct files"
    439 #	" Spacctn.MMDD	pacct files for MMDD after SETUP state"
    440 #	" wtmpx		active wtmpx file"
    441 
    442 #	" following files in /var/adm/acct/sum"
    443 
    444 #	" loginlog	output of lastlogin used in prdaily"
    445 #	" tacct		total tacct file for current fiscal"
    446 #	" tacct.MMDD	tacct file for day MMDD"
    447 #	" cms		total cms file for current fiscal"
    448 #	" rprt.MMDD	output of prdaily program"
    449 #	" MMDD.wtmpx	saved copy of wtmpx for MMDD"
    450 #	" pacct.MMDD	concatenated version of all pacct files for MMDD"
    451 #	" cmsprev	total cms file without latest update"
    452 #	" tacctprev	total tacct file without latest update"
    453 #	" daycms	cms files for todays usage"
    454