Subject: bin/9996: Program pac does not process accounting file correctly.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <bstark@siemens-psc.com>
List: netbsd-bugs
Date: 04/27/2000 14:14:12
>Number: 9996
>Category: bin
>Synopsis: Program pac does not process accounting file correctly.
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Apr 27 14:15:00 PDT 2000
>Closed-Date:
>Last-Modified:
>Originator: Brian Stark
>Release: NetBSD-1.4X
>Organization:
Siemens Power Transmission and Distribution
Power Systems Control Division
>Environment:
System: NetBSD palomino.siemens-psc.com 1.4X NetBSD 1.4X (PALOMINO) #10: Sat Apr 22 10:49:53 CDT 2000 bstark@palomino.siemens-psc.com:/usr/src/sys/arch/i386/compile/PALOMINO i386
>Description:
The program pac does not process printer accounting files correctly. If you
take a look at the code in pac.c there is a function called account().
This code is responsible for reading the printer accounting file and
expects data in the file to be in the following format:
whitespace
a float value to indicate number of feet/pages
whitespace
an integer to indicate the number of copies
whitespace
hostname
a semi-colon
username
(NOTE: These fields would be on one line, and not spread over multiple
lines -- the above was done for readability)
There are several processing problems in the code. Namely, the integer
for the number of copies is only one character [0..9], and the hostname
and username are not processed correctly at all.
Although I have written some other problem reports on pac, I have not
noticed this problem until now because I have been using the unix-lpr.sh
script that comes with Ghostscript to create my accounting files, and
I have always assumed that the unix-lpr.sh script was doing the write thing.
Now that I have seen how the code works in pac.c, I know that the unix-lpr.sh
script is not putting all of the data that it should in the printer
accounting file.
To illustrate this, here is a sample accounting file with a slight
variation between the first and second lines for comparison in the
output:
palomino:{root}# cat acct
1.00 2 palomino.siemens-psc.com:root
2.00 4palomino.siemens-psc.com:bstark
palomino:{root}# pac -P lp
pages/feet runs price host name and login
---------- ---- -------- ----------------------
1.00 1 $ 0.02 2
2.00 1 $ 0.04 4palomino.siemens-psc.com:bstark
---------- ---- -------- ----------------------
Sum: 3.00 2 $ 0.06
palomino:{root}#
As you can see, the count field is not being processed correctly. Because
of this, the conditional check on variable 'ic' will always fail at the
end of account() and the value for hp->h_count will only be incremented
by 1. This results in incorrect "runs" total on each line.
A side effect of this, is that the price total on each line and the price
summary is not calculated correctly.
>How-To-Repeat:
Create a printer accounting file like the one I created above and execute
pac -P XXX, where XXX is the printer name on your system that has the
printer accounting file defined for it that you just created.
>Fix:
Install my source code changes to the pac.c file. My changes can be
summarized as follows:
* correct processing in function account()
* correct processing in function dumpit()
* remove function any() since it is no longer needed.
In addition, I would like to see some type of comments either in pac.c
itself or in the man page for pac describing the format of the printer
accounting file. This will help others who may try to use the
printer accounting files to understand the correct format of the file.
Once my changes are installed, pac will report the correct information.
Here is a sample run using a larger printer accounting file:
palomino:{root}# pac -P lp
pages/feet runs price host name and login
---------- ---- -------- ----------------------
141.00 142 $ 400.44 palomino.siemens-psc.com:bstark
28.00 29 $ 16.24 palomino.siemens-psc.com:root
---------- ---- -------- ----------------------
Sum: 169.00 171 $ 577.98
palomino:{root}# pac -P lp -m
pages/feet runs price login
---------- ---- -------- ----------------------
141.00 142 $ 400.44 bstark
28.00 29 $ 16.24 root
---------- ---- -------- ----------------------
Sum: 169.00 171 $ 577.98
palomino:{root}# pac -P lp -m -p 0.01
pages/feet runs price login
---------- ---- -------- ----------------------
141.00 142 $ 200.22 bstark
28.00 29 $ 8.12 root
---------- ---- -------- ----------------------
Sum: 169.00 171 $ 288.99
palomino:{root}#
And now, here are the source code changes:
Replace the existing function account() with this one:
static void
account(acct)
FILE *acct;
{
const char *delimiters1 = " \t";
const char *delimiters2 = ":";
/*
* buffer needs to be able to hold a hostname!
*/
char linebuf[MAXHOSTNAMELEN+BUFSIZ+1];
double t;
char *cp, *cp2;
struct hent *hp;
int ic;
memset(&linebuf,'\0',sizeof(linebuf));
while (fgets(linebuf, BUFSIZ, acct) != NULL) {
cp = strtok(linebuf,delimiters1);
t = atof(cp);
cp = strtok(NULL,delimiters1);
ic = atoi(cp);
cp = strtok(NULL,delimiters1);
if (mflag) {
cp = strtok(cp,delimiters2);
cp = strtok(NULL,delimiters2);
}
cp2 = strchr(cp,'\n');
if (cp2)
(*cp2) = '\0';
hp = lookup(cp);
if (hp == NULL) {
if (!allflag)
continue;
hp = enter(cp);
}
hp->h_feetpages += t;
if (ic)
hp->h_count += ic;
else
hp->h_count++;
}
}
Replace the existing dumpit() function with this one:
static void
dumpit()
{
struct hent **base;
struct hent *hp, **ap;
int hno, c, runs;
float feet;
hp = hashtab[0];
hno = 1;
base = (struct hent **) calloc(sizeof hp, hcount);
if (base == NULL)
err(1, "calloc");
for (ap = base, c = hcount; c--; ap++) {
while (hp == NULL)
hp = hashtab[hno++];
*ap = hp;
hp = hp->h_link;
}
qsort(base, hcount, sizeof hp, qucmp);
printf(" pages/feet runs price %s\n",
(mflag ? "login" : "host name and login"));
printf(" ---------- ---- -------- ----------------------\n");
feet = 0.0;
runs = 0;
for (ap = base, c = hcount; c--; ap++) {
hp = *ap;
runs += hp->h_count;
feet += hp->h_feetpages;
printf(" %7.2f %4d $%7.2f %s\n",
hp->h_feetpages, hp->h_count,
hp->h_feetpages * price * hp->h_count,
hp->h_name);
}
if (allflag) {
printf(" ---------- ---- -------- ----------------------\n");
printf("Sum:%7.2f %4d $%7.2f\n", feet, runs,
feet * price * runs);
}
}
Remove function any(), and its prototype since it is no longer needed.
>Release-Note:
>Audit-Trail:
>Unformatted: