pac.c revision 27618
11553Srgrimes/* 21553Srgrimes * Copyright (c) 1983, 1993 31553Srgrimes * The Regents of the University of California. All rights reserved. 41553Srgrimes * 51553Srgrimes * 61553Srgrimes * Redistribution and use in source and binary forms, with or without 71553Srgrimes * modification, are permitted provided that the following conditions 81553Srgrimes * are met: 91553Srgrimes * 1. Redistributions of source code must retain the above copyright 101553Srgrimes * notice, this list of conditions and the following disclaimer. 111553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121553Srgrimes * notice, this list of conditions and the following disclaimer in the 131553Srgrimes * documentation and/or other materials provided with the distribution. 141553Srgrimes * 3. All advertising materials mentioning features or use of this software 151553Srgrimes * must display the following acknowledgement: 161553Srgrimes * This product includes software developed by the University of 171553Srgrimes * California, Berkeley and its contributors. 181553Srgrimes * 4. Neither the name of the University nor the names of its contributors 191553Srgrimes * may be used to endorse or promote products derived from this software 201553Srgrimes * without specific prior written permission. 211553Srgrimes * 221553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251553Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321553Srgrimes * SUCH DAMAGE. 331553Srgrimes */ 341553Srgrimes 351553Srgrimes#ifndef lint 361553Srgrimesstatic char copyright[] = 371553Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 381553Srgrimes The Regents of the University of California. All rights reserved.\n"; 391553Srgrimes#endif /* not lint */ 401553Srgrimes 411553Srgrimes#ifndef lint 421553Srgrimesstatic char sccsid[] = "@(#)pac.c 8.1 (Berkeley) 6/6/93"; 431553Srgrimes#endif /* not lint */ 441553Srgrimes 451553Srgrimes/* 461553Srgrimes * Do Printer accounting summary. 471553Srgrimes * Currently, usage is 481553Srgrimes * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...] 491553Srgrimes * to print the usage information for the named people. 501553Srgrimes */ 511553Srgrimes 521553Srgrimes#include <sys/param.h> 531553Srgrimes 541553Srgrimes#include <dirent.h> 551553Srgrimes#include <stdlib.h> 561553Srgrimes#include <stdio.h> 571553Srgrimes#include <string.h> 581553Srgrimes#include "lp.h" 591553Srgrimes#include "lp.local.h" 601553Srgrimes 611553Srgrimesstatic char *acctfile; /* accounting file (input data) */ 621553Srgrimesstatic int allflag = 1; /* Get stats on everybody */ 631553Srgrimesstatic int errs; 641553Srgrimesstatic int hcount; /* Count of hash entries */ 651553Srgrimesstatic int mflag = 0; /* disregard machine names */ 661553Srgrimesstatic int pflag = 0; /* 1 if -p on cmd line */ 671553Srgrimesstatic float price = 0.02; /* cost per page (or what ever) */ 681553Srgrimesstatic long price100; /* per-page cost in 100th of a cent */ 691553Srgrimesstatic int reverse; /* Reverse sort order */ 701553Srgrimesstatic int sort; /* Sort by cost */ 711553Srgrimesstatic char *sumfile; /* summary file */ 721553Srgrimesstatic int summarize; /* Compress accounting file */ 731553Srgrimes 7427618Simpuid_t uid, euid; 7527618Simp 761553Srgrimes/* 771553Srgrimes * Grossness follows: 781553Srgrimes * Names to be accumulated are hashed into the following 791553Srgrimes * table. 801553Srgrimes */ 811553Srgrimes 821553Srgrimes#define HSHSIZE 97 /* Number of hash buckets */ 831553Srgrimes 841553Srgrimesstruct hent { 851553Srgrimes struct hent *h_link; /* Forward hash link */ 861553Srgrimes char *h_name; /* Name of this user */ 871553Srgrimes float h_feetpages; /* Feet or pages of paper */ 881553Srgrimes int h_count; /* Number of runs */ 891553Srgrimes}; 901553Srgrimes 911553Srgrimesstatic struct hent *hashtab[HSHSIZE]; /* Hash table proper */ 921553Srgrimes 931553Srgrimesstatic void account __P((FILE *)); 941553Srgrimesstatic int any __P((int, char [])); 951553Srgrimesstatic int chkprinter __P((char *)); 961553Srgrimesstatic void dumpit __P((void)); 971553Srgrimesstatic int hash __P((char [])); 981553Srgrimesstatic struct hent *enter __P((char [])); 991553Srgrimesstatic struct hent *lookup __P((char [])); 1001553Srgrimesstatic int qucmp __P((const void *, const void *)); 1011553Srgrimesstatic void rewrite __P((void)); 1021553Srgrimes 10319202Simpint 1041553Srgrimesmain(argc, argv) 1051553Srgrimes int argc; 1061553Srgrimes char **argv; 1071553Srgrimes{ 1081553Srgrimes register FILE *acct; 1091553Srgrimes register char *cp; 1101553Srgrimes 11127618Simp euid = geteuid(); /* these aren't used in pac(1) */ 11227618Simp uid = getuid(); 1131553Srgrimes while (--argc) { 1141553Srgrimes cp = *++argv; 1151553Srgrimes if (*cp++ == '-') { 1161553Srgrimes switch(*cp++) { 1171553Srgrimes case 'P': 1181553Srgrimes /* 1191553Srgrimes * Printer name. 1201553Srgrimes */ 1211553Srgrimes printer = cp; 1221553Srgrimes continue; 1231553Srgrimes 1241553Srgrimes case 'p': 1251553Srgrimes /* 1261553Srgrimes * get the price. 1271553Srgrimes */ 1281553Srgrimes price = atof(cp); 1291553Srgrimes pflag = 1; 1301553Srgrimes continue; 1311553Srgrimes 1321553Srgrimes case 's': 1331553Srgrimes /* 1341553Srgrimes * Summarize and compress accounting file. 1351553Srgrimes */ 1361553Srgrimes summarize++; 1371553Srgrimes continue; 1381553Srgrimes 1391553Srgrimes case 'c': 1401553Srgrimes /* 1411553Srgrimes * Sort by cost. 1421553Srgrimes */ 1431553Srgrimes sort++; 1441553Srgrimes continue; 1451553Srgrimes 1461553Srgrimes case 'm': 1471553Srgrimes /* 1481553Srgrimes * disregard machine names for each user 1491553Srgrimes */ 1501553Srgrimes mflag = 1; 1511553Srgrimes continue; 1521553Srgrimes 1531553Srgrimes case 'r': 1541553Srgrimes /* 1551553Srgrimes * Reverse sorting order. 1561553Srgrimes */ 1571553Srgrimes reverse++; 1581553Srgrimes continue; 1591553Srgrimes 1601553Srgrimes default: 1611553Srgrimesfprintf(stderr, 1621553Srgrimes "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n"); 1631553Srgrimes exit(1); 1641553Srgrimes } 1651553Srgrimes } 1661553Srgrimes (void) enter(--cp); 1671553Srgrimes allflag = 0; 1681553Srgrimes } 1691553Srgrimes if (printer == NULL && (printer = getenv("PRINTER")) == NULL) 1701553Srgrimes printer = DEFLP; 1711553Srgrimes if (!chkprinter(printer)) { 1721553Srgrimes printf("pac: unknown printer %s\n", printer); 1731553Srgrimes exit(2); 1741553Srgrimes } 1751553Srgrimes 1761553Srgrimes if ((acct = fopen(acctfile, "r")) == NULL) { 1771553Srgrimes perror(acctfile); 1781553Srgrimes exit(1); 1791553Srgrimes } 1801553Srgrimes account(acct); 1811553Srgrimes fclose(acct); 1821553Srgrimes if ((acct = fopen(sumfile, "r")) != NULL) { 1831553Srgrimes account(acct); 1841553Srgrimes fclose(acct); 1851553Srgrimes } 1861553Srgrimes if (summarize) 1871553Srgrimes rewrite(); 1881553Srgrimes else 1891553Srgrimes dumpit(); 1901553Srgrimes exit(errs); 1911553Srgrimes} 1921553Srgrimes 1931553Srgrimes/* 1941553Srgrimes * Read the entire accounting file, accumulating statistics 1951553Srgrimes * for the users that we have in the hash table. If allflag 1961553Srgrimes * is set, then just gather the facts on everyone. 1971553Srgrimes * Note that we must accomodate both the active and summary file 1981553Srgrimes * formats here. 1991553Srgrimes * Host names are ignored if the -m flag is present. 2001553Srgrimes */ 2011553Srgrimesstatic void 2021553Srgrimesaccount(acct) 2031553Srgrimes register FILE *acct; 2041553Srgrimes{ 2051553Srgrimes char linebuf[BUFSIZ]; 2061553Srgrimes double t; 2071553Srgrimes register char *cp, *cp2; 2081553Srgrimes register struct hent *hp; 2091553Srgrimes register int ic; 2101553Srgrimes 2111553Srgrimes while (fgets(linebuf, BUFSIZ, acct) != NULL) { 2121553Srgrimes cp = linebuf; 2139560Speter while (any(*cp, " \t")) 2141553Srgrimes cp++; 2151553Srgrimes t = atof(cp); 2161553Srgrimes while (any(*cp, ".0123456789")) 2171553Srgrimes cp++; 2181553Srgrimes while (any(*cp, " \t")) 2191553Srgrimes cp++; 2201553Srgrimes for (cp2 = cp; !any(*cp2, " \t\n"); cp2++) 2211553Srgrimes ; 2221553Srgrimes ic = atoi(cp2); 2231553Srgrimes *cp2 = '\0'; 2241553Srgrimes if (mflag && index(cp, ':')) 2251553Srgrimes cp = index(cp, ':') + 1; 2261553Srgrimes hp = lookup(cp); 2271553Srgrimes if (hp == NULL) { 2281553Srgrimes if (!allflag) 2291553Srgrimes continue; 2301553Srgrimes hp = enter(cp); 2311553Srgrimes } 2321553Srgrimes hp->h_feetpages += t; 2331553Srgrimes if (ic) 2341553Srgrimes hp->h_count += ic; 2351553Srgrimes else 2361553Srgrimes hp->h_count++; 2371553Srgrimes } 2381553Srgrimes} 2391553Srgrimes 2401553Srgrimes/* 2411553Srgrimes * Sort the hashed entries by name or footage 2421553Srgrimes * and print it all out. 2431553Srgrimes */ 2441553Srgrimesstatic void 2451553Srgrimesdumpit() 2461553Srgrimes{ 2471553Srgrimes struct hent **base; 2481553Srgrimes register struct hent *hp, **ap; 2491553Srgrimes register int hno, c, runs; 2501553Srgrimes float feet; 2511553Srgrimes 2521553Srgrimes hp = hashtab[0]; 2531553Srgrimes hno = 1; 2541553Srgrimes base = (struct hent **) calloc(sizeof hp, hcount); 2551553Srgrimes for (ap = base, c = hcount; c--; ap++) { 2561553Srgrimes while (hp == NULL) 2571553Srgrimes hp = hashtab[hno++]; 2581553Srgrimes *ap = hp; 2591553Srgrimes hp = hp->h_link; 2601553Srgrimes } 2611553Srgrimes qsort(base, hcount, sizeof hp, qucmp); 2621553Srgrimes printf(" Login pages/feet runs price\n"); 2631553Srgrimes feet = 0.0; 2641553Srgrimes runs = 0; 2651553Srgrimes for (ap = base, c = hcount; c--; ap++) { 2661553Srgrimes hp = *ap; 2671553Srgrimes runs += hp->h_count; 2681553Srgrimes feet += hp->h_feetpages; 2691553Srgrimes printf("%-24s %7.2f %4d $%6.2f\n", hp->h_name, 2701553Srgrimes hp->h_feetpages, hp->h_count, hp->h_feetpages * price); 2711553Srgrimes } 2721553Srgrimes if (allflag) { 2731553Srgrimes printf("\n"); 2748857Srgrimes printf("%-24s %7.2f %4d $%6.2f\n", "total", feet, 2751553Srgrimes runs, feet * price); 2761553Srgrimes } 2771553Srgrimes} 2781553Srgrimes 2791553Srgrimes/* 2801553Srgrimes * Rewrite the summary file with the summary information we have accumulated. 2811553Srgrimes */ 2821553Srgrimesstatic void 2831553Srgrimesrewrite() 2841553Srgrimes{ 2851553Srgrimes register struct hent *hp; 2861553Srgrimes register int i; 2871553Srgrimes register FILE *acctf; 2881553Srgrimes 2891553Srgrimes if ((acctf = fopen(sumfile, "w")) == NULL) { 2901553Srgrimes perror(sumfile); 2911553Srgrimes errs++; 2921553Srgrimes return; 2931553Srgrimes } 2941553Srgrimes for (i = 0; i < HSHSIZE; i++) { 2951553Srgrimes hp = hashtab[i]; 2961553Srgrimes while (hp != NULL) { 2971553Srgrimes fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages, 2981553Srgrimes hp->h_name, hp->h_count); 2991553Srgrimes hp = hp->h_link; 3001553Srgrimes } 3011553Srgrimes } 3021553Srgrimes fflush(acctf); 3031553Srgrimes if (ferror(acctf)) { 3041553Srgrimes perror(sumfile); 3051553Srgrimes errs++; 3061553Srgrimes } 3071553Srgrimes fclose(acctf); 3081553Srgrimes if ((acctf = fopen(acctfile, "w")) == NULL) 3091553Srgrimes perror(acctfile); 3101553Srgrimes else 3111553Srgrimes fclose(acctf); 3121553Srgrimes} 3131553Srgrimes 3141553Srgrimes/* 3151553Srgrimes * Hashing routines. 3161553Srgrimes */ 3171553Srgrimes 3181553Srgrimes/* 3191553Srgrimes * Enter the name into the hash table and return the pointer allocated. 3201553Srgrimes */ 3211553Srgrimes 3221553Srgrimesstatic struct hent * 3231553Srgrimesenter(name) 3241553Srgrimes char name[]; 3251553Srgrimes{ 3261553Srgrimes register struct hent *hp; 3271553Srgrimes register int h; 3281553Srgrimes 3291553Srgrimes if ((hp = lookup(name)) != NULL) 3301553Srgrimes return(hp); 3311553Srgrimes h = hash(name); 3321553Srgrimes hcount++; 3331553Srgrimes hp = (struct hent *) calloc(sizeof *hp, 1); 3341553Srgrimes hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1); 3351553Srgrimes strcpy(hp->h_name, name); 3361553Srgrimes hp->h_feetpages = 0.0; 3371553Srgrimes hp->h_count = 0; 3381553Srgrimes hp->h_link = hashtab[h]; 3391553Srgrimes hashtab[h] = hp; 3401553Srgrimes return(hp); 3411553Srgrimes} 3421553Srgrimes 3431553Srgrimes/* 3441553Srgrimes * Lookup a name in the hash table and return a pointer 3451553Srgrimes * to it. 3461553Srgrimes */ 3471553Srgrimes 3481553Srgrimesstatic struct hent * 3491553Srgrimeslookup(name) 3501553Srgrimes char name[]; 3511553Srgrimes{ 3521553Srgrimes register int h; 3531553Srgrimes register struct hent *hp; 3541553Srgrimes 3551553Srgrimes h = hash(name); 3561553Srgrimes for (hp = hashtab[h]; hp != NULL; hp = hp->h_link) 3571553Srgrimes if (strcmp(hp->h_name, name) == 0) 3581553Srgrimes return(hp); 3591553Srgrimes return(NULL); 3601553Srgrimes} 3611553Srgrimes 3621553Srgrimes/* 3631553Srgrimes * Hash the passed name and return the index in 3641553Srgrimes * the hash table to begin the search. 3651553Srgrimes */ 3661553Srgrimesstatic int 3671553Srgrimeshash(name) 3681553Srgrimes char name[]; 3691553Srgrimes{ 3701553Srgrimes register int h; 3711553Srgrimes register char *cp; 3721553Srgrimes 3731553Srgrimes for (cp = name, h = 0; *cp; h = (h << 2) + *cp++) 3741553Srgrimes ; 3751553Srgrimes return((h & 0x7fffffff) % HSHSIZE); 3761553Srgrimes} 3771553Srgrimes 3781553Srgrimes/* 3791553Srgrimes * Other stuff 3801553Srgrimes */ 3811553Srgrimesstatic int 3821553Srgrimesany(ch, str) 3831553Srgrimes int ch; 3841553Srgrimes char str[]; 3851553Srgrimes{ 3861553Srgrimes register int c = ch; 3871553Srgrimes register char *cp = str; 3881553Srgrimes 3891553Srgrimes while (*cp) 3901553Srgrimes if (*cp++ == c) 3911553Srgrimes return(1); 3921553Srgrimes return(0); 3931553Srgrimes} 3941553Srgrimes 3951553Srgrimes/* 3961553Srgrimes * The qsort comparison routine. 3971553Srgrimes * The comparison is ascii collating order 3981553Srgrimes * or by feet of typesetter film, according to sort. 3991553Srgrimes */ 4001553Srgrimesstatic int 4011553Srgrimesqucmp(a, b) 4021553Srgrimes const void *a, *b; 4031553Srgrimes{ 4041553Srgrimes register struct hent *h1, *h2; 4051553Srgrimes register int r; 4061553Srgrimes 4071553Srgrimes h1 = *(struct hent **)a; 4081553Srgrimes h2 = *(struct hent **)b; 4091553Srgrimes if (sort) 4101553Srgrimes r = h1->h_feetpages < h2->h_feetpages ? 4111553Srgrimes -1 : h1->h_feetpages > h2->h_feetpages; 4121553Srgrimes else 4131553Srgrimes r = strcmp(h1->h_name, h2->h_name); 4141553Srgrimes return(reverse ? -r : r); 4151553Srgrimes} 4161553Srgrimes 4171553Srgrimes/* 4181553Srgrimes * Perform lookup for printer name or abbreviation -- 4191553Srgrimes */ 4201553Srgrimesstatic int 4211553Srgrimeschkprinter(s) 4221553Srgrimes register char *s; 4231553Srgrimes{ 4241553Srgrimes int stat; 4251553Srgrimes 4261553Srgrimes if ((stat = cgetent(&bp, printcapdb, s)) == -2) { 4271553Srgrimes printf("pac: can't open printer description file\n"); 4281553Srgrimes exit(3); 4291553Srgrimes } else if (stat == -1) 4301553Srgrimes return(0); 4311553Srgrimes else if (stat == -3) 4321553Srgrimes fatal("potential reference loop detected in printcap file"); 4331553Srgrimes 4341553Srgrimes if (cgetstr(bp, "af", &acctfile) == -1) { 4351553Srgrimes printf("accounting not enabled for printer %s\n", printer); 4361553Srgrimes exit(2); 4371553Srgrimes } 4381553Srgrimes if (!pflag && (cgetnum(bp, "pc", &price100) == 0)) 4391553Srgrimes price = price100/10000.0; 4401553Srgrimes sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); 4411553Srgrimes if (sumfile == NULL) { 4421553Srgrimes perror("pac"); 4431553Srgrimes exit(1); 4441553Srgrimes } 4451553Srgrimes strcpy(sumfile, acctfile); 4461553Srgrimes strcat(sumfile, "_sum"); 4471553Srgrimes return(1); 4481553Srgrimes} 449