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