~ubuntu-branches/ubuntu/hoary/lpr/hoary

« back to all changes in this revision

Viewing changes to pac/pac.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-03-15 14:54:38 UTC
  • Revision ID: james.westby@ubuntu.com-20030315145438-3n1sxzrmv1g34n4t
Tags: upstream-2000.05.07
ImportĀ upstreamĀ versionĀ 2000.05.07

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: pac.c,v 1.9 1997/07/17 09:08:43 deraadt Exp $ */
 
2
/*      $NetBSD: pac.c,v 1.7 1996/03/21 18:21:20 jtc Exp $      */
 
3
 
 
4
/*
 
5
 * Copyright (c) 1983, 1993
 
6
 *      The Regents of the University of California.  All rights reserved.
 
7
 *
 
8
 *
 
9
 * Redistribution and use in source and binary forms, with or without
 
10
 * modification, are permitted provided that the following conditions
 
11
 * are met:
 
12
 * 1. Redistributions of source code must retain the above copyright
 
13
 *    notice, this list of conditions and the following disclaimer.
 
14
 * 2. Redistributions in binary form must reproduce the above copyright
 
15
 *    notice, this list of conditions and the following disclaimer in the
 
16
 *    documentation and/or other materials provided with the distribution.
 
17
 * 3. All advertising materials mentioning features or use of this software
 
18
 *    must display the following acknowledgement:
 
19
 *      This product includes software developed by the University of
 
20
 *      California, Berkeley and its contributors.
 
21
 * 4. Neither the name of the University nor the names of its contributors
 
22
 *    may be used to endorse or promote products derived from this software
 
23
 *    without specific prior written permission.
 
24
 *
 
25
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
26
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
27
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
28
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
29
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
30
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
31
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
32
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
33
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
34
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
35
 * SUCH DAMAGE.
 
36
 */
 
37
 
 
38
#ifndef lint
 
39
static char copyright[] =
 
40
"@(#) Copyright (c) 1983, 1993\n\
 
41
        The Regents of the University of California.  All rights reserved.\n";
 
42
#endif /* not lint */
 
43
 
 
44
#ifndef lint
 
45
#if 0
 
46
static char sccsid[] = "@(#)pac.c       8.1 (Berkeley) 6/6/93";
 
47
#else
 
48
static char rcsid[] = "$OpenBSD: pac.c,v 1.9 1997/07/17 09:08:43 deraadt Exp $";
 
49
#endif
 
50
#endif /* not lint */
 
51
 
 
52
/*
 
53
 * Do Printer accounting summary.
 
54
 * Currently, usage is
 
55
 *      pac [-Pprinter] [-pprice] [-s] [-r] [-c] [-m] [user ...]
 
56
 * to print the usage information for the named people.
 
57
 */
 
58
 
 
59
#include <sys/param.h>
 
60
 
 
61
#include <dirent.h>
 
62
#include <stdlib.h>
 
63
#include <unistd.h>
 
64
#include <stdio.h>
 
65
#include <string.h>
 
66
#include "lp.h"
 
67
#include "lp.local.h"
 
68
 
 
69
static char     *acctfile;      /* accounting file (input data) */
 
70
static int       allflag = 1;   /* Get stats on everybody */
 
71
static int       errs;
 
72
static int       hcount;        /* Count of hash entries */
 
73
static int       mflag = 0;     /* disregard machine names */
 
74
static int       pflag = 0;     /* 1 if -p on cmd line */
 
75
static float     price = 0.02;  /* cost per page (or what ever) */
 
76
static long      price100;      /* per-page cost in 100th of a cent */
 
77
static int       reverse;       /* Reverse sort order */
 
78
static int       sort;          /* Sort by cost */
 
79
static char     *sumfile;       /* summary file */
 
80
static int       summarize;     /* Compress accounting file */
 
81
 
 
82
uid_t   uid, euid;
 
83
 
 
84
/*
 
85
 * Grossness follows:
 
86
 *  Names to be accumulated are hashed into the following
 
87
 *  table.
 
88
 */
 
89
 
 
90
#define HSHSIZE 97                      /* Number of hash buckets */
 
91
 
 
92
struct hent {
 
93
        struct  hent *h_link;           /* Forward hash link */
 
94
        char    *h_name;                /* Name of this user */
 
95
        float   h_feetpages;            /* Feet or pages of paper */
 
96
        int     h_count;                /* Number of runs */
 
97
};
 
98
 
 
99
static struct   hent    *hashtab[HSHSIZE];      /* Hash table proper */
 
100
 
 
101
static void     account __P((FILE *));
 
102
static int      any __P((int, char []));
 
103
static int      chkprinter __P((char *));
 
104
static void     dumpit __P((void));
 
105
static int      hash __P((char []));
 
106
static struct   hent *enter __P((char []));
 
107
static struct   hent *lookup __P((char []));
 
108
static int      qucmp __P((const void *, const void *));
 
109
static void     rewrite __P((void));
 
110
 
 
111
int
 
112
main(argc, argv)
 
113
        int argc;
 
114
        char **argv;
 
115
{
 
116
        register FILE *acct;
 
117
        register char *cp;
 
118
 
 
119
        euid = geteuid();       /* these aren't used in pac(1) */
 
120
        uid = getuid();
 
121
        while (--argc) {
 
122
                cp = *++argv;
 
123
                if (*cp++ == '-') {
 
124
                        switch(*cp++) {
 
125
                        case 'P':
 
126
                                /*
 
127
                                 * Printer name.
 
128
                                 */
 
129
                                printer = cp;
 
130
                                continue;
 
131
 
 
132
                        case 'p':
 
133
                                /*
 
134
                                 * get the price.
 
135
                                 */
 
136
                                price = atof(cp);
 
137
                                pflag = 1;
 
138
                                continue;
 
139
 
 
140
                        case 's':
 
141
                                /*
 
142
                                 * Summarize and compress accounting file.
 
143
                                 */
 
144
                                summarize++;
 
145
                                continue;
 
146
 
 
147
                        case 'c':
 
148
                                /*
 
149
                                 * Sort by cost.
 
150
                                 */
 
151
                                sort++;
 
152
                                continue;
 
153
 
 
154
                        case 'm':
 
155
                                /*
 
156
                                 * disregard machine names for each user
 
157
                                 */
 
158
                                mflag = 1;
 
159
                                continue;
 
160
 
 
161
                        case 'r':
 
162
                                /*
 
163
                                 * Reverse sorting order.
 
164
                                 */
 
165
                                reverse++;
 
166
                                continue;
 
167
 
 
168
                        default:
 
169
fprintf(stderr,
 
170
    "usage: pac [-Pprinter] [-pprice] [-s] [-c] [-r] [-m] [user ...]\n");
 
171
                                exit(1);
 
172
                        }
 
173
                }
 
174
                (void) enter(--cp);
 
175
                allflag = 0;
 
176
        }
 
177
        if (printer == NULL) {
 
178
                char *p;
 
179
 
 
180
                printer = DEFLP;
 
181
                if ((p = getenv("PRINTER")) != NULL)
 
182
                        printer = p;
 
183
        }
 
184
        if (!chkprinter(printer)) {
 
185
                printf("pac: unknown printer %s\n", printer);
 
186
                exit(2);
 
187
        }
 
188
 
 
189
        if ((acct = fopen(acctfile, "r")) == NULL) {
 
190
                perror(acctfile);
 
191
                exit(1);
 
192
        }
 
193
        account(acct);
 
194
        fclose(acct);
 
195
        if ((acct = fopen(sumfile, "r")) != NULL) {
 
196
                account(acct);
 
197
                fclose(acct);
 
198
        }
 
199
        if (summarize)
 
200
                rewrite();
 
201
        else
 
202
                dumpit();
 
203
        exit(errs);
 
204
}
 
205
 
 
206
/*
 
207
 * Read the entire accounting file, accumulating statistics
 
208
 * for the users that we have in the hash table.  If allflag
 
209
 * is set, then just gather the facts on everyone.
 
210
 * Note that we must accomodate both the active and summary file
 
211
 * formats here.
 
212
 * Host names are ignored if the -m flag is present.
 
213
 */
 
214
static void
 
215
account(acct)
 
216
        register FILE *acct;
 
217
{
 
218
        char linebuf[BUFSIZ];
 
219
        double t;
 
220
        register char *cp, *cp2;
 
221
        register struct hent *hp;
 
222
        register int ic;
 
223
 
 
224
        while (fgets(linebuf, BUFSIZ, acct) != NULL) {
 
225
                cp = linebuf;
 
226
                while (any(*cp, " \t"))
 
227
                        cp++;
 
228
                t = atof(cp);
 
229
                while (any(*cp, ".0123456789"))
 
230
                        cp++;
 
231
                while (any(*cp, " \t"))
 
232
                        cp++;
 
233
                for (cp2 = cp; !any(*cp2, " \t\n"); cp2++)
 
234
                        ;
 
235
                ic = atoi(cp2);
 
236
                *cp2 = '\0';
 
237
                if (mflag && strchr(cp, ':'))
 
238
                    cp = strchr(cp, ':') + 1;
 
239
                hp = lookup(cp);
 
240
                if (hp == NULL) {
 
241
                        if (!allflag)
 
242
                                continue;
 
243
                        hp = enter(cp);
 
244
                }
 
245
                hp->h_feetpages += t;
 
246
                if (ic)
 
247
                        hp->h_count += ic;
 
248
                else
 
249
                        hp->h_count++;
 
250
        }
 
251
}
 
252
 
 
253
/*
 
254
 * Sort the hashed entries by name or footage
 
255
 * and print it all out.
 
256
 */
 
257
static void
 
258
dumpit()
 
259
{
 
260
        struct hent **base;
 
261
        register struct hent *hp, **ap;
 
262
        register int hno, c, runs;
 
263
        float feet;
 
264
 
 
265
        hp = hashtab[0];
 
266
        hno = 1;
 
267
        base = (struct hent **) calloc(sizeof hp, hcount);
 
268
        for (ap = base, c = hcount; c--; ap++) {
 
269
                while (hp == NULL)
 
270
                        hp = hashtab[hno++];
 
271
                *ap = hp;
 
272
                hp = hp->h_link;
 
273
        }
 
274
        qsort(base, hcount, sizeof hp, qucmp);
 
275
        printf("  Login               pages/feet   runs    price\n");
 
276
        feet = 0.0;
 
277
        runs = 0;
 
278
        for (ap = base, c = hcount; c--; ap++) {
 
279
                hp = *ap;
 
280
                runs += hp->h_count;
 
281
                feet += hp->h_feetpages;
 
282
                printf("%-24s %7.2f %4d   $%6.2f\n", hp->h_name,
 
283
                    hp->h_feetpages, hp->h_count, hp->h_feetpages * price);
 
284
        }
 
285
        if (allflag) {
 
286
                printf("\n");
 
287
                printf("%-24s %7.2f %4d   $%6.2f\n", "total", feet, 
 
288
                    runs, feet * price);
 
289
        }
 
290
}
 
291
 
 
292
/*
 
293
 * Rewrite the summary file with the summary information we have accumulated.
 
294
 */
 
295
static void
 
296
rewrite()
 
297
{
 
298
        register struct hent *hp;
 
299
        register int i;
 
300
        register FILE *acctf;
 
301
 
 
302
        if ((acctf = fopen(sumfile, "w")) == NULL) {
 
303
                perror(sumfile);
 
304
                errs++;
 
305
                return;
 
306
        }
 
307
        for (i = 0; i < HSHSIZE; i++) {
 
308
                hp = hashtab[i];
 
309
                while (hp != NULL) {
 
310
                        fprintf(acctf, "%7.2f\t%s\t%d\n", hp->h_feetpages,
 
311
                            hp->h_name, hp->h_count);
 
312
                        hp = hp->h_link;
 
313
                }
 
314
        }
 
315
        fflush(acctf);
 
316
        if (ferror(acctf)) {
 
317
                perror(sumfile);
 
318
                errs++;
 
319
        }
 
320
        fclose(acctf);
 
321
        if ((acctf = fopen(acctfile, "w")) == NULL)
 
322
                perror(acctfile);
 
323
        else
 
324
                fclose(acctf);
 
325
}
 
326
 
 
327
/*
 
328
 * Hashing routines.
 
329
 */
 
330
 
 
331
/*
 
332
 * Enter the name into the hash table and return the pointer allocated.
 
333
 */
 
334
 
 
335
static struct hent *
 
336
enter(name)
 
337
        char name[];
 
338
{
 
339
        register struct hent *hp;
 
340
        register int h;
 
341
 
 
342
        if ((hp = lookup(name)) != NULL)
 
343
                return(hp);
 
344
        h = hash(name);
 
345
        hcount++;
 
346
        hp = (struct hent *) calloc(sizeof *hp, 1);
 
347
        hp->h_name = (char *) calloc(sizeof(char), strlen(name)+1);
 
348
        strcpy(hp->h_name, name);
 
349
        hp->h_feetpages = 0.0;
 
350
        hp->h_count = 0;
 
351
        hp->h_link = hashtab[h];
 
352
        hashtab[h] = hp;
 
353
        return(hp);
 
354
}
 
355
 
 
356
/*
 
357
 * Lookup a name in the hash table and return a pointer
 
358
 * to it.
 
359
 */
 
360
 
 
361
static struct hent *
 
362
lookup(name)
 
363
        char name[];
 
364
{
 
365
        register int h;
 
366
        register struct hent *hp;
 
367
 
 
368
        h = hash(name);
 
369
        for (hp = hashtab[h]; hp != NULL; hp = hp->h_link)
 
370
                if (strcmp(hp->h_name, name) == 0)
 
371
                        return(hp);
 
372
        return(NULL);
 
373
}
 
374
 
 
375
/*
 
376
 * Hash the passed name and return the index in
 
377
 * the hash table to begin the search.
 
378
 */
 
379
static int
 
380
hash(name)
 
381
        char name[];
 
382
{
 
383
        register int h;
 
384
        register char *cp;
 
385
 
 
386
        for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
 
387
                ;
 
388
        return((h & 0x7fffffff) % HSHSIZE);
 
389
}
 
390
 
 
391
/*
 
392
 * Other stuff
 
393
 */
 
394
static int
 
395
any(ch, str)
 
396
        int ch;
 
397
        char str[];
 
398
{
 
399
        register int c = ch;
 
400
        register char *cp = str;
 
401
 
 
402
        while (*cp)
 
403
                if (*cp++ == c)
 
404
                        return(1);
 
405
        return(0);
 
406
}
 
407
 
 
408
/*
 
409
 * The qsort comparison routine.
 
410
 * The comparison is ascii collating order
 
411
 * or by feet of typesetter film, according to sort.
 
412
 */
 
413
static int
 
414
qucmp(a, b)
 
415
        const void *a, *b;
 
416
{
 
417
        register struct hent *h1, *h2;
 
418
        register int r;
 
419
 
 
420
        h1 = *(struct hent **)a;
 
421
        h2 = *(struct hent **)b;
 
422
        if (sort)
 
423
                r = h1->h_feetpages < h2->h_feetpages ?
 
424
                    -1 : h1->h_feetpages > h2->h_feetpages;
 
425
        else
 
426
                r = strcmp(h1->h_name, h2->h_name);
 
427
        return(reverse ? -r : r);
 
428
}
 
429
 
 
430
/*
 
431
 * Perform lookup for printer name or abbreviation --
 
432
 */
 
433
static int
 
434
chkprinter(s)
 
435
        register char *s;
 
436
{
 
437
        int stat;
 
438
 
 
439
        if ((stat = cgetent(&bp, printcapdb, s)) == -2) {
 
440
                printf("pac: can't open printer description file\n");
 
441
                exit(3);
 
442
        } else if (stat == -1)
 
443
                return(0);
 
444
        else if (stat == -3)
 
445
                fatal("potential reference loop detected in printcap file");
 
446
 
 
447
        if (cgetstr(bp, "af", &acctfile) == -1) {
 
448
                printf("accounting not enabled for printer %s\n", printer);
 
449
                exit(2);
 
450
        }
 
451
        if (!pflag && (cgetnum(bp, "pc", &price100) == 0))
 
452
                price = price100/10000.0;
 
453
        sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5);
 
454
        if (sumfile == NULL) {
 
455
                perror("pac");
 
456
                exit(1);
 
457
        }
 
458
        strcpy(sumfile, acctfile);
 
459
        strcat(sumfile, "_sum");
 
460
        return(1);
 
461
}