Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

600 lines
13 KiB
C

static char sccsid[] = "@(#)20 1.16.1.4 src/bos/usr/bin/que/pac.c, cmdque, bos411, 9428A410j 3/30/94 10:01:50";
/*
* COMPONENT_NAME: (CMDQUE) Queueing system
*
* FUNCTIONS: pac
*
* ORIGINS: 26, 27
*
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
* combined with the aggregated modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1989, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
/* static char sccsid[] = "pac.c 5.2 (Berkeley) 10/30/85"; */
/*
* Do Printer accounting summary.
* Currently, usage is
* pac [-Pprinter] [-pprice] [-qfilename] [-s] [-r] [-c] [-m] [user ...]
* to print the usage information for the named people.
*/
#define QCNFG_FILE "/etc/qconfig"
/*
* Copyright (c) 1983 Regents of the University of California.\n\
All rights reserved.\n";
*/
#define _ILS_MACROS
#include <IN/standard.h>
#include "common.h"
#include "accrec.h"
#include <stdio.h>
#include <IN/AFdefs.h>
#include <IN/FSdefs.h>
#include <sys/param.h>
#include <stdlib.h>
#include <locale.h>
#include <monetary.h>
#include <fcntl.h>
#include <sys/limits.h>
#include <sys/errno.h>
#include <ctype.h>
#include "pac_msg.h"
nl_catd catd;
#define MSGSTR(num,str) catgets(catd,MS_PAC,num,str) /*MSG*/
#define MONSIZE 20
char *printer; /* printer name */
char *acctfile; /* accounting file (input data) */
char sumfile[MAXPATHLEN]; /* summary file */
float price = 0.02; /* cost per page (or what ever) */
int allflag = 1; /* Get stats on everybody */
int sort; /* Sort by cost */
int summarize; /* Compress accounting file */
int reverse; /* Reverse sort order */
int hcount; /* Count of hash entries */
int mflag = 0; /* disregard machine names */
int pflag = 0; /* 1 if -p on cmd line */
int qflag = 0; /* 1 if -q on cmd line */
int price100; /* per-page cost in 100th of a cent */
char *index();
int pgetnum();
char *progname = "pac";
char *stripstr();
/*
* Grossness follows:
* Names to be accumulated are hashed into the following
* table.
*/
#define HSHSIZE 97 /* Number of hash buckets */
struct hent {
struct hent *h_link; /* Forward hash link */
char *h_name; /* Name of this user */
float h_feetpages; /* Feet or pages of paper */
int h_count; /* Number of runs */
};
struct hent *hashtab[HSHSIZE]; /* Hash table proper */
struct hent *enter();
struct hent *lookup();
struct q *qlist;
struct q *pac_config();
#define NIL ((struct hent *) 0) /* The big zero */
char *pgetstr();
static void rewrite();
static void dumpit();
static void account();
extern struct q *default_queue(), *get_queue();
extern void resetQCBFile();
extern struct q *rcfg();
int jul=0; /* Debugging flag */
struct lconv *l_conv;
main(argc, argv)
int argc;
char **argv;
{
register FILE *acct;
register char *cp;
char str[MONSIZE];
char *alt_price; /* default price in qconfig file */
char *qconfig = QCNFG_FILE;
struct q *qptr;
(void) setlocale (LC_ALL,"");
catd = catopen(MF_PAC, NL_CAT_LOCALE);
l_conv = localeconv();
while (--argc) {
cp = *++argv;
if (*cp++ == '-') {
switch(*cp++) {
case 'P':
/*
* Printer name.
*/
printer = cp;
continue;
case 'p':
/*
* get the price.
*/
strcpy(str,stripstr(cp));
price = atof(str);
pflag = 1;
continue;
case 'q':
/*
* new qconfig file
*/
qflag++;
qconfig = cp;
continue;
case 's':
/*
* Summarize and compress accounting file.
*/
summarize++;
continue;
case 'c':
/*
* Sort by cost.
*/
sort++;
continue;
#ifdef DEBUG
case 'j':
jul = 1;
continue;
#endif /* DEBUG */
case 'm':
/*
* disregard machine names for each user
*/
mflag = 1;
continue;
case 'r':
/*
* Reverse sorting order.
*/
reverse++;
continue;
default:
usage();
}
}
(void) enter(--cp);
allflag = 0;
}
if (!qflag)
{
resetQCBFile();
qlist = readconfig(0);
}
else
qlist = pac_config(qconfig);
/* DETERMINE default printer name */
if (printer == NULL) {
qptr = default_queue(qlist);
if ( qptr == NULL )
syserr((int)EXITBAD,MSGSTR(BADENV,"Invalid PRINTER or LPDEST environment variable."));
else printer = qptr->q_name;
}
else {
qptr = get_queue(printer,qlist);
if (qptr == NULL)
syserr((int)EXITBAD,MSGSTR(BADQNAM,"Invalid queue name: %s"),printer);
}
acctfile = qptr->q_acctf;
if ( *acctfile ) {
strcpy(sumfile, acctfile);
strcat(sumfile, "_sum");
}
else
syserr((int)EXITBAD,MSGSTR(NOACCT,"No accounting file specified for queue: %s."),printer);
if (jul)
printf("acctfile is:%s\n",acctfile);
if ((acct = fopen(acctfile, "r")) == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGACCT,"Problem opening account file. Errno = %d"),errno);
account(acct);
fclose(acct);
if ((acct = fopen(sumfile, "r")) == NULL) {
if (errno != ENOENT)
syserr((int)EXITFATAL, MSGSTR(MSGSUMM,"Problem opening summary file. Errno = %d"),errno);
} else {
account(acct);
fclose(acct);
}
if (summarize)
rewrite();
else
dumpit();
qexit((int)EXITOK);
}
/*
* NAME: account
*
* FUNCTION:
* Read the entire accounting file, accumulating statistics
* for the users that we have in the hash table. If allflag
* is set, then just gather the facts on everyone.
* Note that we must accomodate both the active and summary file
* formats here.
* Host names are ignored if the -m flag is present.
*
* EXECUTION ENVIRONMENT: user level
*
* RETURNS: void
*/
static void
account(acct)
register FILE *acct;
{
struct acctrec a_rec;
register char *cp;
register struct hent *hp;
if (jul)
printf ("Doing Accounting\n");
while (fread((void *)&a_rec, (size_t)sizeof(struct acctrec),(size_t)1,acct) == 1) {
if (jul)
{
printf("record read in:\n");
printf("from: %s\nacctdate: %x pages: %d Jobs: %d\n",
a_rec.from,
a_rec.acctdate,
a_rec.pages,
a_rec.numjobs);
}
if (mflag && index(a_rec.from, '@'))
{
cp = index(a_rec.from, '@');
*cp = '\0';
}
if (jul) printf ("Doing lookup\n");
hp = lookup(a_rec.from);
if (jul) printf ("return from lookup: %d\n",hp);
if (hp == NIL) {
if (!allflag)
continue;
hp = enter(a_rec.from);
}
hp->h_feetpages += a_rec.pages;
hp->h_count += a_rec.numjobs;
}
}
/*
* NAME: dumpit
*
* FUNCTION:
* Sort the hashed entries by name or footage
* and print it all out.
*
* RETURNS: none
*/
static void
dumpit()
{
struct hent **base;
register struct hent *hp, **ap;
register int hno, c, runs;
float feet;
int qucmp(struct hent **left, struct hent **right);
char s[MONSIZE];
hp = hashtab[0];
hno = 1;
base = (struct hent **) calloc((size_t)sizeof(hp), (size_t)hcount);
for (ap = base, c = hcount; c--; ap++) {
while (hp == NIL)
hp = hashtab[hno++];
*ap = hp;
hp = hp->h_link;
}
qsort((void *)base, (size_t)hcount, (size_t)sizeof(hp), (int(*)(const void *, const void *))qucmp);
printf(MSGSTR(HEADER," Login pages/feet runs price\n"));
feet = 0.0;
runs = 0;
for (ap = base, c = hcount; c--; ap++) {
hp = *ap;
runs += hp->h_count;
feet += hp->h_feetpages;
strfmon(s,MONSIZE,"%20a",hp->h_feetpages * price);
printf("%-24s %7.2f %4d %s\n", hp->h_name,
hp->h_feetpages, hp->h_count, s);
}
if (allflag) {
strfmon(s,MONSIZE,"%20a",feet * price);
printf("\n");
printf("%-24s %7.2f %4d %s\n", MSGSTR(TOTAL,"total"), feet,
runs, s);
}
}
/*
* NAME: rewrite
*
* FUNCTION:
* Rewrite the summary file with the summary
* information we have accumulated.
*
* RETURNS: NONE
*/
static void
rewrite()
{
register struct hent *hp;
register int i;
register FILE *acctf;
long cur_date;
struct acctrec a_rec;
if ((acctf = fopen(sumfile, "w")) == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGSUMM,"Problem opening summary file. Errno = %d"),errno);
cur_date = time(0);
for (i = 0; i < HSHSIZE; i++) {
hp = hashtab[i];
while (hp != NULL) {
strcpy (a_rec.from,hp->h_name);
a_rec.acctdate = cur_date;
a_rec.pages = hp->h_feetpages;
a_rec.numjobs = hp->h_count;
if (fwrite((void *)&a_rec, (size_t)sizeof(struct acctrec),(size_t)1,acctf) != 1)
syserr((int)EXITFATAL,MSGSTR(MSGSUMM,"Problem writing to summary file. Errno = %d"),errno);
hp = hp->h_link;
}
}
fflush(acctf);
if (ferror(acctf))
syserr((int)EXITFATAL,MSGSTR(MSGWACC,"Problem writing to account file. Errno = %d"),errno);
fclose(acctf);
if ((acctf = fopen(acctfile, "w")) == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGACCT,"Problem opening account file. Errno = %d"),errno);
else
fclose(acctf);
}
/*
* Hashing routines.
*/
/*
* NAME: enter
*
* FUNCTION:
* Enter the name into the hash table
*
* RETURNS: return the pointer allocated.
*/
struct hent *
enter(name)
char name[];
{
register struct hent *hp;
register int h;
if (jul) printf ("entering : %s\n",name);
if ((hp = lookup(name)) != NIL)
return(hp);
if (jul) printf ("hashing : %s\n",name);
h = hash(name);
hcount++;
hp = (struct hent *) calloc((size_t)sizeof(*hp), (size_t)1);
hp->h_name = (char *) calloc((size_t)sizeof(char), (size_t)(strlen(name)+1));
strcpy(hp->h_name, name);
hp->h_feetpages = 0.0;
hp->h_count = 0;
hp->h_link = hashtab[h];
hashtab[h] = hp;
return(hp);
}
/*
* NAME: lookup
*
* FUNCTION:
* Lookup a name in the hash table
*
* RETURNS: return the pointer to the found routine, null if not found.
*/
struct hent *
lookup(name)
char name[];
{
register int h;
register struct hent *hp;
h = hash(name);
for (hp = hashtab[h]; hp != NIL; hp = hp->h_link)
if (strcmp(hp->h_name, name) == 0)
return(hp);
return(NIL);
}
/*
* NAME: hash
*
* FUNCTION and RETURNS:
* Hash the passed name and return the index in
* the hash table to begin the search.
*/
hash(name)
char name[];
{
register int h;
register char *cp;
for (cp = name, h = 0; *cp; h = (h << 2) + *cp++)
;
return((h & 0x7fffffff) % HSHSIZE);
}
/*
* NAME: qncmp
*
* FUNCTION:
* The qsort comparison routine.
* The comparison is ascii collating order
* or by feet of typesetter film, according to sort.
* RETURNS:
*/
qucmp(struct hent **left, struct hent **right)
{
register struct hent *h1, *h2;
register int r;
h1 = *left;
h2 = *right;
if (sort)
r = h1->h_feetpages < h2->h_feetpages ? -1 :
h1->h_feetpages > h2->h_feetpages;
else
r = strcmp(h1->h_name, h2->h_name);
return(reverse ? -r : r);
}
/*
* NAME: usage
*
* FUNCTION:
* Prints the usage message and exits;
* RETURNS:
*/
usage()
{
sysuse( TRUE,
MSGSTR(USAGE,"[-PPrinter] [-pPrice] [-qFileName] [-s] [-c] [-r] [-m] [User ...]"),
(char *)0
);
}
/*
* Function stripstr removes all non-digit except for the decimal point
* from the users input string.
*/
char *stripstr(cp)
char *cp;
{
char *p = cp;
char newstr[MONSIZE];
int i=0;
while( *p != '\0')
{
if (isdigit(*p))
newstr[i++] = *p;
else if (*p == l_conv->mon_decimal_point[0])
newstr[i++] = l_conv->decimal_point[0];
p++;
}
return(newstr);
}
/*
* NAME: pac_config
*
* FUNCTION:
* Parse user supplied qconfig file
* RETURNS:
* qlist
*/
struct q *pac_config(PacConfig)
char *PacConfig;
{
int pid, got, fd;
int status = 0;
static char PacBconfig[] ="/tmp/qconfig.bin.XXXXXX";
mktemp(PacBconfig);
switch( (pid = fork()) )
{
case -1:
syserr((int)EXITFATAL,MSGSTR(MSGFORK,"Cannot fork for %s."),DIGEST);
case 0: /* child */
execl(DIGEST,"digest",PacConfig,PacBconfig,0);
syserr((int)EXITFATAL,MSGSTR(MSGEXEC,
"Cannot exec digester %s."),DIGEST);
default: /* parent */
got=waitpid(pid,&status,0);
if(status) {
syserr((int)EXITFATAL,MSGSTR(MSGDIGE,
"Error from digester %s, status = %d, rv = %d."),
DIGEST,status,got);
}
resetQCBFile();
openPacQCBFile(PacBconfig);
qlist = rcfg(PacBconfig);
unlink(PacBconfig);
if (qlist == NULL)
syserr((int)EXITFATAL,MSGSTR(MSGNADA,
"Nothing read from %s. Errno = %d."),PacBconfig,errno);
return(qlist);
}
}