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