xref: /illumos-gate/usr/src/cmd/acct/runacct.sh (revision 47b4653e9ff2a8aebb64f9e357713fd04108674b)
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
37PATH=/usr/lib/acct:/usr/bin:/usr/sbin
38export 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
46cd ${_adm}
47#		"make sure that 2 crons weren't started, or leftover problems"
48date  > ${_nite}/lock1
49chmod 400 ${_nite}/lock1
50ln ${_nite}/lock1 ${_nite}/lock
51if 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
58fi
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 }'`
63if [ "$_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
75fi
76
77
78case $# in
790)
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
1001)
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
1082)
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	;;
125esac
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"
131while [ 1 ]
132do
133case "`cat ${_statefile}`" in
134SETUP)
135
136cd ${_adm}
137
138(date ; ls -l fee pacct* ${_wtmpx}* ) >> ${_active}
139
140#	"switch current pacct file"
141turnacct switch
142_rc=$?
143if 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
150fi
151
152#	" give pacct files unique names for easy restart "
153for _i in pacct?*
154do
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}
171done
172
173
174#	"add current time on end"
175if 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
182fi
183closewtmp	# fudge a DEAD_PROCESS for /var/wtmpx
184cp ${_wtmpx} ${_nite}/${_date}.wtmpx
185acctwtmp "runacct" ${_nite}/${_date}.wtmpx
186nulladm ${_wtmpx}
187utmp2wtmp	# fudge active user from utmpx to wtmpx
188
189echo "files setups complete" >> ${_active}
190echo "WTMPFIX" > ${_statefile}
191;;
192
193WTMPFIX)
194#	"verify the integrity of the wtmpx file"
195#	"wtmpfix will automatically fix date changes"
196cd ${_nite}
197nulladm tmpwtmp wtmperror
198wtmpfix < ${_date}.wtmpx > tmpwtmp 2>wtmperror
199if 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
207fi
208
209echo "wtmpx processing complete" >> ${_active}
210echo "CONNECT" > ${_statefile}
211;;
212
213
214CONNECT)
215#	"produce connect records"
216#	"the lineuse and reboots files are used by prdaily"
217cd ${_nite}
218nulladm lineuse reboots log ctacct.${_date}
219acctcon -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#
225if 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}
229fi
230
231echo "connect acctg complete" >> ${_active}
232echo "PROCESS" > ${_statefile}
233;;
234
235
236PROCESS)
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
242cd ${_nite}
243for _Spacct in ${_adm}/Spacct*.${_date}
244do
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
257done
258echo "all process actg complete for ${_date}" >> ${_active}
259echo "MERGE" > ${_statefile}
260;;
261
262
263MERGE)
264cd ${_nite}
265#	"merge ctacct and ptacct files together"
266acctmerg ptacct*.${_date} < ctacct.${_date} > daytacct
267
268echo "tacct merge to create daytacct complete" >> ${_active}
269echo "FEES" > ${_statefile}
270;;
271
272
273FEES)
274cd ${_nite}
275#	"merge in fees"
276if 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
281else
282	echo "no fees" >> ${_active}
283fi
284echo "DISK" > ${_statefile}
285;;
286
287
288DISK)
289cd ${_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"
292if 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}
298else
299	echo "no disk records" >> ${_active}
300fi
301echo "MERGETACCT" > ${_statefile}
302;;
303
304MERGETACCT)
305cd ${_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"
309cp nite/daytacct sum/tacct${_date}
310if test ! -r sum/tacct; then
311	echo "WARNING: recreating ${_adm}/sum/tacct " >> ${_active}
312	nulladm sum/tacct
313fi
314
315#	"merge in todays tacct with the summary tacct"
316rm -f sum/tacctprev
317cp sum/tacct sum/tacctprev
318acctmerg sum/tacctprev  < sum/tacct${_date} > sum/tacct
319
320echo "updated sum/tacct" >> ${_active}
321echo "CMS" > ${_statefile}
322;;
323
324
325CMS)
326cd ${_adm}/acct
327#	"do command summaries"
328nulladm sum/daycms
329if test ! -r sum/cms; then
330	nulladm sum/cms
331	echo "WARNING: recreating ${_adm}/sum/cms " >> ${_active}
332fi
333cp sum/cms sum/cmsprev
334acctcms ${_adm}/Spacct*.${_date}  > sum/daycms
335acctcms -s sum/daycms sum/cmsprev  > sum/cms
336acctcms -a -s sum/daycms | sed -n 1,56p  > nite/daycms
337acctcms -a -s sum/cms | sed -n 1,56p  > nite/cms
338lastlogin
339echo "command summaries complete" >> ${_active}
340echo "USEREXIT" > ${_statefile}
341;;
342
343
344USEREXIT)
345#	"any installation dependant accounting programs should be run here"
346[ -s /usr/lib/acct/runacct.local ] && /usr/lib/acct/runacct.local
347
348echo "CLEANUP" > ${_statefile}
349;;
350
351
352CLEANUP)
353cd ${_adm}/acct
354#	" finally clear files; could be done next morning if desired"
355nulladm ${_adm}/fee
356rm -f ${_adm}/Spacct*.${_date}
357#	"put reports onto a file"
358prdaily >> sum/rprt${_date};
359rm -f nite/lock*
360rm -f nite/ptacct*.${_date} nite/ctacct.${_date}
361mv -f nite/${_date}.wtmpx nite/owtmpx
362rm -f nite/wtmperror${_date} nite/active${_date} nite/tmpwtmp
363echo "system accounting completed at `date`" >> ${_active}
364echo "********** SYSTEM ACCOUNTING COMPLETED `date` **********" | logger -p daemon.notice
365echo "COMPLETE" > ${_statefile}
366exit 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	;;
377esac
378done
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