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