2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * @(#) Copyright (c) 1983, 1993 The Regents of the University of California. All rights reserved.
35 * @(#)pac.c 8.1 (Berkeley) 6/6/93
36 * $FreeBSD: src/usr.sbin/lpr/pac/pac.c,v 1.10.2.4 2002/04/26 18:17:52 gad Exp $
37 * $DragonFly: src/usr.sbin/lpr/pac/pac.c,v 1.4 2004/12/18 22:48:03 swildner Exp $
41 * Do Printer accounting summary.
43 * pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
44 * to print the usage information for the named people.
47 #include <sys/param.h>
58 static char *acctfile
; /* accounting file (input data) */
59 static int allflag
= 1; /* Get stats on everybody */
61 static size_t hcount
; /* Count of hash entries */
62 static int mflag
= 0; /* disregard machine names */
63 static int pflag
= 0; /* 1 if -p on cmd line */
64 static float price
= 0.02; /* cost per page (or what ever) */
65 static int reverse
; /* Reverse sort order */
66 static int sort
; /* Sort by cost */
67 static char *sumfile
; /* summary file */
68 static int summarize
; /* Compress accounting file */
74 * Names to be accumulated are hashed into the following
78 #define HSHSIZE 97 /* Number of hash buckets */
81 struct hent
*h_link
; /* Forward hash link */
82 char *h_name
; /* Name of this user */
83 float h_feetpages
; /* Feet or pages of paper */
84 int h_count
; /* Number of runs */
87 static struct hent
*hashtab
[HSHSIZE
]; /* Hash table proper */
89 int main(int argc
, char **_argv
);
90 static void account(FILE *_acctf
);
91 static int any(int _ch
, const char _str
[]);
92 static int chkprinter(const char *_ptrname
);
93 static void dumpit(void);
94 static int hash(const char _name
[]);
95 static struct hent
*enter(const char _name
[]);
96 static struct hent
*lookup(const char _name
[]);
97 static int qucmp(const void *_a
, const void *_b
);
98 static void rewrite(void);
99 static void usage(void);
102 main(int argc
, char **argv
)
105 const char *cp
, *printer
;
108 euid
= geteuid(); /* these aren't used in pac(1) */
131 * Summarize and compress accounting file.
145 * disregard machine names for each user
152 * Reverse sorting order.
164 if (printer
== NULL
&& (printer
= getenv("PRINTER")) == NULL
)
166 if (!chkprinter(printer
)) {
167 printf("pac: unknown printer %s\n", printer
);
171 if ((acctf
= fopen(acctfile
, "r")) == NULL
) {
177 if ((acctf
= fopen(sumfile
, "r")) != NULL
) {
192 "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
197 * Read the entire accounting file, accumulating statistics
198 * for the users that we have in the hash table. If allflag
199 * is set, then just gather the facts on everyone.
200 * Note that we must accomodate both the active and summary file
202 * Host names are ignored if the -m flag is present.
207 char linebuf
[BUFSIZ
];
213 while (fgets(linebuf
, BUFSIZ
, acctf
) != NULL
) {
215 while (any(*cp
, " \t"))
218 while (any(*cp
, ".0123456789"))
220 while (any(*cp
, " \t"))
222 for (cp2
= cp
; !any(*cp2
, " \t\n"); cp2
++)
226 if (mflag
&& strchr(cp
, ':'))
227 cp
= strchr(cp
, ':') + 1;
234 hp
->h_feetpages
+= t
;
243 * Sort the hashed entries by name or footage
244 * and print it all out.
250 struct hent
*hp
, **ap
;
257 base
= (struct hent
**) calloc(sizeof hp
, hcount
);
258 for (ap
= base
, c
= hcount
; c
--; ap
++) {
264 qsort(base
, hcount
, sizeof hp
, qucmp
);
265 printf(" Login pages/feet runs price\n");
268 for (ap
= base
, c
= hcount
; c
--; ap
++) {
271 feet
+= hp
->h_feetpages
;
272 printf("%-24s %7.2f %4d $%6.2f\n", hp
->h_name
,
273 hp
->h_feetpages
, hp
->h_count
, hp
->h_feetpages
* price
);
277 printf("%-24s %7.2f %4d $%6.2f\n", "total", feet
,
283 * Rewrite the summary file with the summary information we have accumulated.
292 if ((acctf
= fopen(sumfile
, "w")) == NULL
) {
297 for (i
= 0; i
< HSHSIZE
; i
++) {
300 fprintf(acctf
, "%7.2f\t%s\t%d\n", hp
->h_feetpages
,
301 hp
->h_name
, hp
->h_count
);
311 if ((acctf
= fopen(acctfile
, "w")) == NULL
)
312 warn("%s", acctfile
);
322 * Enter the name into the hash table and return the pointer allocated.
326 enter(const char name
[])
331 if ((hp
= lookup(name
)) != NULL
)
335 hp
= (struct hent
*) calloc(sizeof *hp
, (size_t)1);
336 hp
->h_name
= (char *) calloc(sizeof(char), strlen(name
)+1);
337 strcpy(hp
->h_name
, name
);
338 hp
->h_feetpages
= 0.0;
340 hp
->h_link
= hashtab
[h
];
346 * Lookup a name in the hash table and return a pointer
351 lookup(const char name
[])
357 for (hp
= hashtab
[h
]; hp
!= NULL
; hp
= hp
->h_link
)
358 if (strcmp(hp
->h_name
, name
) == 0)
364 * Hash the passed name and return the index in
365 * the hash table to begin the search.
368 hash(const char name
[])
373 for (cp
= name
, h
= 0; *cp
; h
= (h
<< 2) + *cp
++)
375 return((h
& 0x7fffffff) % HSHSIZE
);
382 any(int ch
, const char str
[])
385 const char *cp
= str
;
394 * The qsort comparison routine.
395 * The comparison is ascii collating order
396 * or by feet of typesetter film, according to sort.
399 qucmp(const void *a
, const void *b
)
401 const struct hent
*h1
, *h2
;
404 h1
= *(const struct hent
* const *)a
;
405 h2
= *(const struct hent
* const *)b
;
407 r
= h1
->h_feetpages
< h2
->h_feetpages
?
408 -1 : h1
->h_feetpages
> h2
->h_feetpages
;
410 r
= strcmp(h1
->h_name
, h2
->h_name
);
411 return(reverse
? -r
: r
);
415 * Perform lookup for printer name or abbreviation --
418 chkprinter(const char *ptrname
)
421 struct printer myprinter
, *pp
= &myprinter
;
423 init_printer(&myprinter
);
424 stat
= getprintcap(ptrname
, pp
);
427 printf("pac: getprintcap: %s\n", pcaperr(stat
));
429 case PCAPERR_NOTFOUND
:
432 fatal(pp
, "%s", pcaperr(stat
));
434 if ((acctfile
= pp
->acct_file
) == NULL
)
435 errx(3, "accounting not enabled for printer %s", ptrname
);
436 if (!pflag
&& pp
->price100
)
437 price
= pp
->price100
/10000.0;
438 sumfile
= (char *) calloc(sizeof(char), strlen(acctfile
)+5);
440 errx(1, "calloc failed");
441 strcpy(sumfile
, acctfile
);
442 strcat(sumfile
, "_sum");