Home | History | Annotate | Download | only in acct
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * 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 
     25 /*
     26  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     27  * Use is subject to license terms.
     28  */
     29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     30 
     31 /*
     32  *	acctmerg [-a] [-i] [-p] [-t] [-u] [-v] [file...]
     33  *	-a	output in tacct.h/ascii (instead of tacct.h)
     34  *	-i	input is in tacct.h/ascii (instead of tacct.h)
     35  *	-p	print input files with no processing
     36  *	-t	output single record that totals all input
     37  *	-u	summarize by uid, rather than uid/name
     38  *	-v	output in verbose tacct.h/ascii
     39  *	reads std input and 0-NFILE files, all in tacct.h format,
     40  *	sorted by uid/name.
     41  *	merge/adds all records with same uid/name (or same uid if -u,
     42  *	or all records if -t], writes to std. output
     43  *	(still in tacct.h format)
     44  *	note that this can be used to summarize the std input
     45  */
     46 
     47 #include <stdio.h>
     48 #include <sys/types.h>
     49 #include <sys/param.h>
     50 #include "acctdef.h"
     51 #include <stdlib.h>
     52 
     53 int	nfile;			/* index of last used in fl */
     54 FILE	*fl[NFILE]	= {stdin};
     55 
     56 struct	tacct tb[NFILE];	/* current record from each file */
     57 struct	tacct	tt = {
     58 	0,
     59 	"TOTAL"
     60 };
     61 int	asciiout;
     62 int	asciiinp;
     63 int	printonly;
     64 int	totalonly;
     65 int	uidsum;
     66 int	verbose;
     67 
     68 int 	exitcode = 0;
     69 
     70 void prtacct(struct tacct *);
     71 struct tacct *getleast(void);
     72 void output(struct tacct *);
     73 void tacctadd(struct tacct *, struct tacct *);
     74 void sumcurr(struct tacct *);
     75 
     76 int
     77 main(int argc, char **argv)
     78 {
     79 	int i;
     80 	struct tacct *tp;
     81 
     82 	while (--argc > 0) {
     83 		if (**++argv == '-')
     84 			switch (*++*argv) {
     85 			case 'a':
     86 				asciiout++;
     87 				continue;
     88 			case 'i':
     89 				asciiinp++;
     90 				continue;
     91 			case 'p':
     92 				printonly++;
     93 				continue;
     94 			case 't':
     95 				totalonly++;
     96 				continue;
     97 			case 'u':
     98 				uidsum++;
     99 				continue;
    100 			case 'v':
    101 				verbose++;
    102 				asciiout++;
    103 				continue;
    104 			}
    105 		else {
    106 			if (++nfile >= NFILE) {
    107 				fprintf(stderr, "acctmerg: >%d files\n", NFILE);
    108 				exit(1);
    109 			}
    110 			if ((fl[nfile] = fopen(*argv, "r")) == NULL) {
    111 				fprintf(stderr, "acctmerg: can't open %s\n", *argv);
    112 				exitcode = 1;
    113 				/*	exit(1); 	*/
    114 			}
    115 		}
    116 	}
    117 
    118 	if (printonly) {
    119 		for (i = 0; i <= nfile; i++)
    120 			while (getnext(i))
    121 				prtacct(&tb[i]);
    122 		exit(exitcode);
    123 	}
    124 
    125 	for (i = 0; i <= nfile; i++)
    126 		if(getnext(i) == 0) {
    127 			fprintf(stderr,"acctmerg: read error file %d.  File may be empty.\n", i);
    128 			exitcode = 2;
    129 
    130 		}
    131 
    132 	while ((tp = getleast()) != NULL)	/* get least uid of all files, */
    133 		sumcurr(tp);			/* sum all entries for that uid, */
    134 	if (totalonly)				/* and write the 'summed' record */
    135 		output(&tt);
    136 
    137 	exit(exitcode);
    138 }
    139 
    140 /*
    141  *	getleast returns ptr to least (lowest uid)  element of current
    142  *	avail, NULL if none left; always returns 1st of equals
    143  */
    144 struct tacct *
    145 getleast(void)
    146 {
    147 	struct tacct *tp, *least;
    148 
    149 	least = NULL;
    150 	for (tp = tb; tp <= &tb[nfile]; tp++) {
    151 		if (tp->ta_name[0] == '\0')
    152 			continue;
    153 		if (least == NULL ||
    154 			tp->ta_uid < least->ta_uid ||
    155 			((tp->ta_uid == least->ta_uid) &&
    156 			!uidsum &&
    157 			(strncmp(tp->ta_name, least->ta_name, NSZ) < 0)))
    158 			least = tp;
    159 	}
    160 	return(least);
    161 }
    162 
    163 /*
    164  *	sumcurr sums all entries with same uid/name (into tp->tacct record)
    165  *	writes it out, gets new entry
    166  */
    167 void
    168 sumcurr(struct tacct *tp)
    169 {
    170 	struct tacct tc;
    171 	char *memcpy();
    172 
    173 	memcpy(&tc, tp, sizeof(struct tacct));
    174 	tacctadd(&tt, tp);	/* gets total of all uids */
    175 	getnext(tp-&tb[0]);	/* get next one in same file */
    176 	while (tp <= &tb[nfile])
    177 		if (tp->ta_name[0] != '\0' &&
    178 			tp->ta_uid == tc.ta_uid &&
    179 			(uidsum || EQN(tp->ta_name, tc.ta_name))) {
    180 			tacctadd(&tc, tp);
    181 			tacctadd(&tt, tp);
    182 			getnext(tp-&tb[0]);
    183 		} else
    184 			tp++;	/* look at next file */
    185 	if (!totalonly)
    186 		output(&tc);
    187 }
    188 
    189 void
    190 tacctadd(struct tacct *t1, struct tacct *t2)
    191 {
    192 	t1->ta_cpu[0] = t1->ta_cpu[0] + t2->ta_cpu[0];
    193 	t1->ta_cpu[1] = t1->ta_cpu[1] + t2->ta_cpu[1];
    194 	t1->ta_kcore[0] = t1->ta_kcore[0] + t2->ta_kcore[0];
    195 	t1->ta_kcore[1] = t1->ta_kcore[1] + t2->ta_kcore[1];
    196 	t1->ta_con[0] = t1->ta_con[0] + t2->ta_con[0];
    197 	t1->ta_con[1] = t1->ta_con[1] + t2->ta_con[1];
    198 	t1->ta_du = t1->ta_du + t2->ta_du;
    199 	t1->ta_pc += t2->ta_pc;
    200 	t1->ta_sc += t2->ta_sc;
    201 	t1->ta_dc += t2->ta_dc;
    202 	t1->ta_fee += t2->ta_fee;
    203 }
    204 
    205 void
    206 output(struct tacct *tp)
    207 {
    208 	if (asciiout)
    209 		prtacct(tp);
    210 	else
    211 		fwrite(tp, sizeof(*tp), 1, stdout);
    212 }
    213 
    214 /*
    215  *	getnext reads next record from stream i, returns 1 if one existed
    216  */
    217 int
    218 getnext(int i)
    219 {
    220 	struct tacct *tp;
    221 
    222 	tp = &tb[i];
    223 	tp->ta_name[0] = '\0';
    224 	if (fl[i] == NULL)
    225 		return(0);
    226 	if (asciiinp) {
    227 		if (fscanf(fl[i],
    228 			"%ld\t%s\t%e %e %e %e %e %e %e %lu\t%hu\t%hu\t%hu",
    229 			&tp->ta_uid,
    230 			tp->ta_name,
    231 			&tp->ta_cpu[0], &tp->ta_cpu[1],
    232 			&tp->ta_kcore[0], &tp->ta_kcore[1],
    233 			&tp->ta_con[0], &tp->ta_con[1],
    234 			&tp->ta_du,
    235 			&tp->ta_pc,
    236 			&tp->ta_sc,
    237 			&tp->ta_dc,
    238 			&tp->ta_fee) != EOF)
    239 			return(1);
    240 	} else {
    241 		if (fread(tp, sizeof(*tp), 1, fl[i]) == 1)
    242 			return(1);
    243 	}
    244 	fclose(fl[i]);
    245 	fl[i] = NULL;
    246 	return(0);
    247 }
    248 
    249 char fmt[] = "%ld\t%.*s\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%.0f\t%lu\t%hu\t%hu\t%hu\n";
    250 char fmtv[] = "%ld\t%.*s\t%e %e %e %e %e %e %e %lu %hu\t%hu\t%hu\n";
    251 
    252 void
    253 prtacct(struct tacct *tp)
    254 {
    255 	printf(verbose ? fmtv : fmt,
    256 	    tp->ta_uid,
    257 	    OUTPUT_NSZ,
    258 	    tp->ta_name,
    259 	    tp->ta_cpu[0], tp->ta_cpu[1],
    260 	    tp->ta_kcore[0], tp->ta_kcore[1],
    261 	    tp->ta_con[0], tp->ta_con[1],
    262 	    tp->ta_du,
    263 	    tp->ta_pc,
    264 	    tp->ta_sc,
    265 	    tp->ta_dc,
    266 	    tp->ta_fee);
    267 }
    268