"Fossies" - the Fresh Open Source Software archive 
Member "atsar_linux-1.7/atsadc/atsadc.c" of archive atsar_linux-1.7.tar.gz:
#include "includes.h"
/*
** System Activity Data Collector
**
** The program 'atsadc' offers the possibility to read statistical counters
** from the /proc (sub)directory and write it periodically to stdout or a file.
** The program has been designed to operate as a framework to which
** new counters can be added very easily (table-driven). It cooperates
** with the reporting program 'atsar' in a similar way as the standard UNIX
** 'sadc' cooperates with 'sar'.
** ================================================================
** Author: Gerlof Langeveld - AT Computing, Nijmegen, Holland
** E-mail: gerlof@ATComputing.nl
** Date: Januar 1995
** LINUX-port: Februar 1999
**
** $Log: atsadc.c,v $
** Revision 1.6 2004/07/08 12:51:40 gerlof
** Adapted for kernel version 2.6.
**
** Revision 1.5 2000/11/07 09:22:42 gerlof
** *** empty log message ***
**
** Revision 1.4 1999/09/01 07:11:47 gerlof
** Ported to Alpha.
**
** Revision 1.3 1999/08/26 06:58:53 gerlof
** Code-cleanup and new code to determine number of cpu's (this modified
** the header of the statistics-file as well).
**
** Revision 1.2 1999/05/18 08:31:30 gerlof
** Back-port from version 2.2 to 2.0.
**
** Revision 1.1 1999/05/05 11:38:27 gerlof
** Initial revision
**
**
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2, or (at your option) any
** later version.
**
** This program is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU General Public License for more details.
*/
static const char rcsid[] = "$Id: atsadc.c,v 1.6 2004/07/08 12:51:40 gerlof Exp $";
/*
** definition of the counters to be read from /proc
*/
extern struct fetchdef oncedef[];
extern int oncecnt; /* number of entries */
extern struct fetchdef sampdef[];
extern int sampcnt; /* number of entries */
/*
** Kernel-version info
*/
struct osrel osrel;
/*
** values of the command-line arguments
*/
char *outfile;
int interval = 0;
int nsamples = 0;
/*
** Function prototypes
*/
void writehdr(int, int, int, int, int);
void prusage(char *);
int numcpus(void);
int
main(int argc, char *argv[])
{
register int i;
char newfile; /* boolean: appended file */
int ofd; /* output file-descriptor */
int cycle; /* count for nr of samples */
struct filehdr filehdr;
struct samphdr samphdr;
struct tms timbuf;
int namosize, namssize;
int varosize, varssize;
register unsigned long tmpoff;
register char *tmpcnt;
struct utsname utsname;
struct timeval tval;
long intervalnano;
long secsnext;
/*
** check if enough parameters have been specified
*/
if ( argc > 1 )
{
if ( isdigit(*argv[1]) ) /* file or timeout as first */
{
interval = atoi(argv[1]);
if (interval <= 0)
prusage(argv[0]);
if ( argc < 3 || !isdigit(*argv[2]) )
prusage(argv[0]);
nsamples = atoi(argv[2]);
if ( argc > 3 )
outfile = argv[3];
}
else
{
outfile = argv[1];
}
}
/*
** open the counter output file (default: stdout)
*/
if ( !outfile )
{
ofd = dup(1);
newfile = 1;
}
else
{
if ( access(outfile, W_OK) == -1 )
{
/*
** check if call during init-switch to state 2
** ----> filename, but no interval
*/
if (!interval)
exit(0); /* ignore call */
/*
** file does not exist yet; create new
*/
if ( (ofd = open(outfile, O_WRONLY|O_CREAT, 0664)) ==-1)
{
perror("create output file");
exit(1);
}
newfile = 1;
}
else
{
/*
** file exists: check if this is a statistics file;
** if it is, seek to the end for appending
*/
if ( (ofd = open(outfile, O_RDWR)) == -1)
{
perror("open output file");
exit(1);
}
if ( read(ofd, &filehdr, sizeof(filehdr)) == -1)
{
perror("verify output file");
exit(1);
}
if ( filehdr.magic != ATMAGIC )
{
fprintf(stderr,
"existing file %s has wrong format\n",
outfile);
exit(6);
}
(void) lseek(ofd, 0, SEEK_END);
newfile = 0;
/*
** write a dummy sample header to indicate
** a system-reboot if started without t and n.
*/
if (!interval)
{
samphdr.curtim = time(0);
samphdr.curlbolt= times(&timbuf);
samphdr.cntsize = 0; /* dummy */
if ( write(ofd, &samphdr, sizeof(samphdr))==-1)
{
perror("write restart");
exit(1);
}
(void) close(ofd);
exit(0);
}
}
}
/*
** determine the kernel-version of this system
*/
uname(&utsname);
sscanf(utsname.release, "%d.%d.%d",
&(osrel.rel), &(osrel.vers), &(osrel.sub));
if ( osrel.rel < 2 )
{
fprintf(stderr, "\nLINUX-version %d.%d not supported!\n",
osrel.rel, osrel.vers);
exit(5);
}
/*
** check total space in file needed for names of kernel
** variables and for the counters themselves
**
** all variable sizes are rounded up to 8-bytes units to avoid
** alignment problems with subsequent variables
*/
for (i=0, namosize=0, varosize=0; i < oncecnt; i++)
{
if (oncedef[i].initcnt)
(oncedef[i].initcnt)(&oncedef[i], &osrel);
if (oncedef[i].cdef.ksize & 7)
oncedef[i].cdef.ksize =
((oncedef[i].cdef.ksize >> 3) + 1) << 3;
varosize += oncedef[i].cdef.ksize * oncedef[i].cdef.kinst;
namosize += strlen(oncedef[i].cdef.kname) + 1;
}
if (namosize & 0x0f) /* not multiple of 16 bytes ?*/
namosize = ((namosize>>4) +1) << 4;
for (i=0, namssize=0, varssize=0; i < sampcnt; i++)
{
if (sampdef[i].initcnt)
(sampdef[i].initcnt)(&sampdef[i], &osrel);
if (sampdef[i].cdef.ksize & 7)
sampdef[i].cdef.ksize =
((sampdef[i].cdef.ksize >> 3) + 1) << 3;
varssize += sampdef[i].cdef.ksize * sampdef[i].cdef.kinst;
namssize += strlen(sampdef[i].cdef.kname) + 1;
}
if (namssize & 0x0f) /* not multiple of 16 bytes ?*/
namssize = ((namssize>>4) +1) << 4;
/*
** write the headers only for a new file or pipe;
** if appending to an existing file, check the consistency and
** take care that the counter-areas keep the same size
*/
if (newfile)
{
writehdr(ofd, namosize, namssize, varosize, varssize);
}
else
{
if ( filehdr.oncecnt != oncecnt ||
filehdr.oncenames != namosize ||
filehdr.oncevars != varosize ||
filehdr.sampcnt != sampcnt ||
filehdr.sampnames != namssize ||
filehdr.sampvars != varssize ||
strcmp(filehdr.utsinfo.release, utsname.release) )
{
fprintf(stderr,
"This existing file cannot be appended\n");
exit(7);
}
}
/*
** allocate a buffer which is big enough to hold all
** counters of one sample
*/
if ( (tmpcnt = (char *) malloc(varssize)) == NULL)
{
perror("cannot malloc");
exit(5);
}
/*
** main loop:
** read all defined statistic structures and
** transfer to file/pipe
*/
gettimeofday(&tval, (struct timezone *) 0);
secsnext = tval.tv_sec;
intervalnano = interval * 1000000;
for (cycle=0; cycle < nsamples; cycle++)
{
/*
** wait for interval
** except for the very first cycle
*/
if (cycle)
{
/* sleep(interval); --> may cause time-deviation */
gettimeofday(&tval, (struct timezone *) 0);
if(tval.tv_sec >= secsnext)
usleep(intervalnano - tval.tv_usec);
else
usleep(intervalnano - tval.tv_usec + 1000000);
secsnext += interval;
}
/*
** gather all counters by calling functions
** defined in sampdef-table
*/
samphdr.curtim = time(0);
samphdr.curlbolt= times(&timbuf);
samphdr.cntsize = varssize;
for (i=0, tmpoff=0; i < sampcnt; i++)
{
(sampdef[i].getcnt)(&sampdef[i], &osrel, tmpcnt+tmpoff);
tmpoff += sampdef[i].cdef.ksize * sampdef[i].cdef.kinst;
}
/*
** write the sample-header and -data
*/
if ( write(ofd, &samphdr, sizeof(samphdr)) < 0)
{
perror("write of sample header");
exit(1);
}
if ( write(ofd, tmpcnt, varssize) < 0)
{
perror("write of sample counters");
exit(1);
}
}
(void) close(ofd);
return 0;
}
/*
** write all static header-info to file/pipe, except the sample data
** ofd - file descriptor of open output file
** namosz - size of total space for 'once' names
** namssz - size of total space for 'samp' names
** varosz - size of total space for 'once' counters
** varssz - size of total space for 'samp' counters
*/
void
writehdr(int ofd, int namosz, int namssz, int varosz, int varssz)
{
register int i;
struct filehdr filehdr;
char *tmpname;
struct countdef *tmpdef;
register unsigned long tmpoff;
register char *tmpcnt;
int oncetot; /* total countdef size */
int samptot; /* total countdef size */
oncetot = oncecnt * sizeof(struct countdef);
samptot = sampcnt * sizeof(struct countdef);
filehdr.magic = ATMAGIC;
filehdr.hdrsize = sizeof(struct filehdr);
filehdr.oncecnt = oncecnt;
filehdr.oncenames = namosz;
filehdr.oncevars = varosz;
filehdr.sampcnt = sampcnt;
filehdr.sampnames = namssz;
filehdr.sampvars = varssz;
filehdr.hertz = HZ;
filehdr.numcpu = numcpus();
uname(&filehdr.utsinfo);
if ( write(ofd, &filehdr, sizeof(filehdr)) < 0)
{
perror("write of header data");
exit(1);
}
/*
** build name table for counters which are only read once
*/
if ( (tmpdef = (struct countdef *) malloc(oncetot)) == NULL)
{
perror("cannot malloc");
exit(5);
}
if ( (tmpname = (char *) malloc(namosz)) == NULL)
{
perror("cannot malloc");
exit(5);
}
for (i=0, tmpoff=0; i < oncecnt; i++)
{
register int len;
len = strlen(oncedef[i].cdef.kname)+1;
memcpy(tmpname+tmpoff, oncedef[i].cdef.kname, len);
(tmpdef+i)->kname = (char *) tmpoff;
(tmpdef+i)->ksize = oncedef[i].cdef.ksize;
(tmpdef+i)->kinst = oncedef[i].cdef.kinst;
tmpoff += len;
}
if ( write(ofd, tmpdef, oncetot) < 0)
{
perror("write of counter definition data");
exit(1);
}
if ( write(ofd, tmpname, namosz) < 0)
{
perror("write of counter names");
exit(1);
}
(void) free(tmpname);
(void) free(tmpdef);
/*
** build name table for counters which are read each sample
*/
if ( (tmpdef = (struct countdef *) malloc(samptot)) == NULL)
{
perror("cannot malloc");
exit(5);
}
if ( (tmpname = (char *) malloc(namssz)) == NULL)
{
perror("cannot malloc");
exit(5);
}
for (i=0, tmpoff=0; i < sampcnt; i++)
{
register int len;
len = strlen(sampdef[i].cdef.kname)+1;
memcpy(tmpname+tmpoff, sampdef[i].cdef.kname, len);
(tmpdef+i)->kname = (char *) tmpoff;
(tmpdef+i)->ksize = sampdef[i].cdef.ksize;
(tmpdef+i)->kinst = sampdef[i].cdef.kinst;
tmpoff += len;
}
if ( write(ofd, tmpdef, samptot) < 0)
{
perror("write of counter definition data");
exit(1);
}
if ( write(ofd, tmpname, namssz) < 0)
{
perror("write of counter names");
exit(1);
}
(void) free(tmpname);
(void) free(tmpdef);
/*
** read only once the non-changing kernel counters
** and transfer to file/pipe
*/
if ( (tmpcnt = (char *) malloc(varosz)) == NULL)
{
perror("cannot malloc");
exit(5);
}
for (i=0, tmpoff=0; i < oncecnt; i++)
{
(oncedef[i].getcnt)(&oncedef[i], &osrel, tmpcnt+tmpoff);
tmpoff += oncedef[i].cdef.ksize * oncedef[i].cdef.kinst;
}
if ( write(ofd, tmpcnt, varosz) < 0)
{
perror("write of counters");
exit(1);
}
(void) free(tmpcnt);
}
/*
** print the usage string and abort
*/
void
prusage(char *pname)
{
fprintf(stderr, "usage: %s [t n] [ofile]\n", pname);
exit(1);
}
/*
** Determine number of cpu's active on this system (return value).
*/
int
numcpus(void)
{
FILE *fp;
int cnt = 0;
char linebuf[1024], fw[80];
/*
** obtain info about number of processors installed by counting
** all lines in the file /proc/stat which start with the
** string "cpu[0-9]" (per-cpu lines); if these lines are not
** present, just one cpu is installed
*/
if ( (fp = fopen("/proc/stat", "r")) == NULL)
return 1; /* assume one cpu */
while ( fgets(linebuf, sizeof(linebuf), fp) != NULL)
{
sscanf(linebuf, "%s ", fw);
if (fw[0] == 'c' && fw[1] == 'p' && fw[2] == 'u' && fw[3] !=0)
cnt++;
}
fclose(fp);
return (cnt > 0 ? cnt : 1);
}