6 Star 13 Fork 3

Gitee 极速下载 / atop

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/Atoptool/atop
克隆/下载
acctproc.c 26.89 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
/*
** ATOP - System & Process Monitor
**
** The program 'atop' offers the possibility to view the activity of
** the system on system-level as well as process-level.
**
** This source-file contains functions to manipulate with process-accounting
** features (switch it on/off and read the process-accounting records).
** ================================================================
** Author: Gerlof Langeveld
** E-mail: gerlof.langeveld@atoptool.nl
** Date: November 1996
** LINUX-port: June 2000
**
** 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.
*/
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "atop.h"
#include "photoproc.h"
#include "acctproc.h"
#include "atopacctd.h"
#define ACCTDIR "/var/cache/atop.d"
#define ACCTFILE "atop.acct"
#define ACCTENV "ATOPACCT"
static char acctatop; /* boolean: atop's own accounting busy ? */
static off_t acctsize; /* previous size of account file */
static int acctrecsz; /* size of account record */
static int acctversion; /* version of account record layout */
static int acctfd = -1; /* fd of account file (-1 = not open) */
static long curshadowseq; /* current shadow file sequence number */
static long maxshadowrec; /* number of records per shadow file */
static char *pacctdir = PACCTDIR;
static count_t acctexp (comp_t ct);
static int acctvers(int);
static void acctrestarttrial(void);
static void switchshadow(void);
static int atopacctd(int);
/*
** possible process accounting files used by (ps)acct package
*/
struct pacctadm {
char *name;
struct stat stat;
} pacctadm[] = {
{ "/var/log/pacct", {0, }, },
{ "/var/account/pacct", {0, }, },
{ "/var/log/account/pacct", {0, }, }
};
struct pacctadm *pacctcur; // pointer to entry in use
/*
** Semaphore-handling
**
** A semaphore-group with two semaphores is created
**
** 0 - Binary semaphore (mutex) to get access to active atop-counter
**
** 1 - Active atop-counter (inverted).
** This semaphore is initialized at some high value and is
** decremented by every atop-incarnation which uses the private
** accounting-file and incremented as soon as such atop stops again.
** If an atop-incarnation stops and it appears to be the last one
** using the private accounting-file, accounting is stopped
** and the file removed
** (Yes, I know: it's not proper usage of the semaphore-principle).
*/
#define ATOPACCTKEY 3121959
#define ATOPACCTTOT 100
struct sembuf semclaim = {0, -1, SEM_UNDO},
semrelse = {0, +1, SEM_UNDO},
semdecre = {1, -1, SEM_UNDO},
semincre = {1, +1, SEM_UNDO};
struct sembuf semreglock[] = {{0, -1, SEM_UNDO|IPC_NOWAIT},
{1, -1, SEM_UNDO|IPC_NOWAIT}},
semunlock = {1, +1, SEM_UNDO};
/*
** switch on the process-accounting mechanism
**
** return value:
** 0 - activated (success)
** 1 - not activated: unreadable accounting file
** 2 - not activated: empty environment variable ATOPACCT
** 3 - not activated: no access to semaphore group
** 4 - not activated: impossible to create own accounting file
** 5 - not activated: no root privileges
*/
int
acctswon(void)
{
int i, j, sematopid;
static unsigned short vals[] = {1, ATOPACCTTOT};
union {unsigned short *array;} arg = {vals};
struct stat statbuf;
char *ep;
int ret;
/*
** when a particular environment variable is present, atop should
** use a specific accounting-file (as defined by the environment
** variable) or should use no process accounting at all (when
** contents of environment variable is empty)
*/
if ( (ep = getenv(ACCTENV)) )
{
/*
** environment variable exists
*/
if (*ep)
{
/*
** open active account file with the specified name
*/
if (! droprootprivs() )
mcleanstop(42, "failed to drop root privs\n");
if ( (acctfd = open(ep, O_RDONLY) ) == -1)
return 1;
if ( !acctvers(acctfd) )
{
(void) close(acctfd);
acctfd = -1;
return 1;
}
supportflags |= ACCTACTIVE;
return 0;
}
else
{
/*
** no contents
*/
return 2;
}
}
/*
** when the atopacctd daemon is active on this system,
** it should be the preferred way to read the accounting records
*/
if ( (ret = atopacctd(1)) >= 0 )
return ret;
/*
** check if process accounting is already switched on
** for one of the standard accounting-files; in that case we
** open this file and get our info from here ....
*/
for (i=0, j=0; i < sizeof pacctadm/sizeof pacctadm[0]; i++)
{
if ( stat(pacctadm[i].name, &pacctadm[i].stat) == 0)
j++;
}
if (j)
{
/*
** at least one file is present; check if it is really in use
** at this moment for accounting by forking a child-process
** which immediately finishes to force a new accounting-record
*/
if ( fork() == 0 )
exit(0); /* let the child finish */
(void) wait((int *) 0); /* let the parent wait */
for (i=0; i < sizeof pacctadm/sizeof pacctadm[0]; i++)
{
if ( stat(pacctadm[i].name, &statbuf) == 0)
{
/*
** accounting-file has grown?
*/
if (statbuf.st_size > pacctadm[i].stat.st_size)
{
/*
** open active account file
*/
if ( (acctfd = open(pacctadm[i].name,
O_RDONLY) ) == -1)
return 1;
if ( !acctvers(acctfd) )
{
(void) close(acctfd);
acctfd = -1;
return 1;
}
supportflags |= ACCTACTIVE;
pacctcur = &pacctadm[i]; // register current
return 0;
}
}
}
}
/*
** process-accounting is not yet switched on in a standard way;
** check if another atop has switched on accounting already
**
** first try to create a semaphore group exclusively; if this succeeds,
** this is the first atop-incarnation since boot and the semaphore group
** should be initialized`
*/
if ( (sematopid = semget(ATOPACCTKEY, 2, 0600|IPC_CREAT|IPC_EXCL)) >= 0)
(void) semctl(sematopid, 0, SETALL, arg);
else
sematopid = semget(ATOPACCTKEY, 0, 0);
/*
** check if we got access to the semaphore group
*/
if (sematopid == -1)
return 3;
/*
** the semaphore group is opened now; claim exclusive rights
*/
(void) semop(sematopid, &semclaim, 1);
/*
** are we the first to use the accounting-mechanism ?
*/
if (semctl(sematopid, 1, GETVAL, 0) == ATOPACCTTOT)
{
/*
** create a new separate directory below /tmp
** for the accounting file;
** if this directory exists (e.g. previous atop-run killed)
** it will be cleaned and newly created
*/
if ( mkdir(ACCTDIR, 0700) == -1)
{
if (errno == EEXIST)
{
(void) acct(0);
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
}
if ( mkdir(ACCTDIR, 0700) == -1)
{
/*
** persistent failure
*/
(void) semop(sematopid, &semrelse, 1);
return 4;
}
}
/*
** create accounting file in new directory
*/
(void) close( creat(ACCTDIR "/" ACCTFILE, 0600) );
/*
** switch on accounting
*/
if ( acct(ACCTDIR "/" ACCTFILE) < 0)
{
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
(void) semop(sematopid, &semrelse, 1);
return 5;
}
}
/*
** accounting is switched on now;
** open accounting-file
*/
if ( (acctfd = open(ACCTDIR "/" ACCTFILE, O_RDONLY) ) < 0)
{
(void) acct(0);
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
(void) semop(sematopid, &semrelse, 1);
return 1;
}
/*
** accounting successfully switched on
*/
(void) semop(sematopid, &semdecre, 1);
(void) semop(sematopid, &semrelse, 1);
acctatop = 1;
/*
** determine version of accounting-record
*/
if (fstat(acctfd, &statbuf) == -1)
{
(void) acct(0);
(void) close(acctfd);
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
acctfd = -1;
return 1;
}
if (statbuf.st_size == 0) /* no acct record written yet */
{
/*
** let's write one record
*/
if ( fork() == 0 )
exit(0); /* let the child finish */
(void) wait((int *) 0); /* let the parent wait */
}
if ( !acctvers(acctfd) )
{
(void) acct(0);
(void) close(acctfd);
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
acctfd = -1;
return 1;
}
supportflags |= ACCTACTIVE;
return 0;
}
/*
** try to use process accounting via the atopacctd daemon
** swon: 1 - initial switch on
** 0 - switch on again after the atopacct service has been down
*/
static int
atopacctd(int swon)
{
int sempacctpubid;
acctfd = -1; // reset to not being open
/*
** open semaphore group that has been initialized by atopacctd
** semaphore 0: 100 counting down to reflect number of users of atopacctd
** semaphore 1: value 0 is locked and value 1 is unlocked (binary semaphore)
*/
if ( (sempacctpubid = semget(PACCTPUBKEY, 2, 0)) != -1)
{
FILE *cfp;
char shadowpath[128];
struct flock flock;
struct timespec maxsemwait = {3, 0};
if (! droprootprivs() )
mcleanstop(42, "failed to drop root privs\n");
/*
** lock binary semaphore and decrement semaphore 0 (extra user)
*/
if (semtimedop(sempacctpubid, semreglock, 2, &maxsemwait) == -1)
{
regainrootprivs();
return 3;
}
/*
** open the 'current' file, containing the current
** shadow sequence number and maximum number of records
** per shadow file
*/
snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s",
pacctdir, PACCTSHADOWD, PACCTSHADOWC);
if ( (cfp = fopen(shadowpath, "r")) )
{
if (fscanf(cfp, "%ld/%ld",
&curshadowseq, &maxshadowrec) == 2)
{
fclose(cfp);
/*
** open the current shadow file
*/
snprintf(shadowpath, sizeof shadowpath,
PACCTSHADOWF, pacctdir,
PACCTSHADOWD, curshadowseq);
if ( (acctfd = open(shadowpath, O_RDONLY))!=-1)
{
if ( swon && !acctvers(acctfd) )
{
int maxcnt = 40;
if ( fork() == 0 )
exit(0);
(void) wait((int *) 0);
while ( !acctvers(acctfd) &&
--maxcnt)
usleep(50000);
if (!acctversion)
{
(void) close(acctfd);
acctfd = -1;
semop(sempacctpubid,
&semrelse, 1);
semop(sempacctpubid,
&semunlock, 1);
regainrootprivs();
maxshadowrec = 0;
return -1; // try other
}
}
/*
** set read lock on current shadow file
*/
flock.l_type = F_RDLCK;
flock.l_whence = SEEK_SET;
flock.l_start = 0;
flock.l_len = 1;
if ( fcntl(acctfd, F_SETLK, &flock)
!= -1)
{
supportflags |= ACCTACTIVE;
regainrootprivs();
semop(sempacctpubid,
&semunlock, 1);
return 0;
}
(void) close(acctfd);
acctfd = -1;
}
else
{
perror("open shadowpath");
abort();
}
}
else
{
fprintf(stderr,
"fscanf failed on shadow currency\n");
fclose(cfp);
maxshadowrec = 0;
}
}
(void) semop(sempacctpubid, &semrelse, 1);
(void) semop(sempacctpubid, &semunlock, 1);
}
return -1; // try another accounting mechanism
}
/*
** determine the version of the accounting-record layout/length
** and reposition the seek-pointer to the end of the accounting file
*/
static int
acctvers(int fd)
{
struct acct tmprec;
/*
** read first record from accounting file to verify
** the second byte (always contains version number)
*/
if ( read(fd, &tmprec, sizeof tmprec) < sizeof tmprec)
return 0;
switch (tmprec.ac_version & 0x0f)
{
case 2:
acctrecsz = sizeof(struct acct);
acctversion = 2;
break;
case 3:
acctrecsz = sizeof(struct acct_v3);
acctversion = 3;
break;
default:
mcleanstop(8, "Unknown format of process accounting file\n");
}
/*
** accounting successfully switched on
*/
acctsize = acctprocnt() * acctrecsz;
/*
** reposition to actual file-size
*/
(void) lseek(fd, acctsize, SEEK_SET);
return 1;
}
/*
** switch off the process-accounting mechanism
*/
void
acctswoff(void)
{
int sematopid;
struct stat before, after;
/*
** if accounting not supported, skip call
*/
if (acctfd == -1)
return;
/*
** our private accounting-file in use?
*/
if (acctatop)
{
acctatop = 0;
/*
** claim the semaphore to get exclusive rights for
** the accounting-manipulation
*/
sematopid = semget(ATOPACCTKEY, 0, 0);
(void) semop(sematopid, &semclaim, 1);
(void) semop(sematopid, &semincre, 1);
/*
** check if we were the last user of accounting
*/
if (semctl(sematopid, 1, GETVAL, 0) == ATOPACCTTOT)
{
/*
** switch off private accounting
**
** verify if private accounting is still in use to
** avoid that we switch off process accounting that
** has been activated manually in the meantime
*/
(void) fstat(acctfd, &before);
if ( fork() == 0 ) /* create a child and */
exit(0); /* let the child finish */
(void) wait((int *) 0); /* let the parent wait */
(void) fstat(acctfd, &after);
if (after.st_size > before.st_size)
{
/*
** remove the directory and file
*/
regainrootprivs(); /* get root privs again */
(void) acct(0);
(void) unlink(ACCTDIR "/" ACCTFILE);
(void) rmdir(ACCTDIR);
if (! droprootprivs() )
mcleanstop(42,
"failed to drop root privs\n");
}
}
(void) semop(sematopid, &semrelse, 1);
}
/*
** anyhow close the accounting-file again
*/
(void) close(acctfd); /* close account file again */
acctfd = -1;
supportflags &= ~ACCTACTIVE;
}
/*
** get the number of exited processes written
** in the process-account file since the previous sample
*/
unsigned long
acctprocnt(void)
{
struct stat statacc;
/*
** handle atopacctd-based process accounting on bases of
** fixed-chunk shadow files
*/
if (maxshadowrec) // atopacctd has been detected before?
{
unsigned long numrecs = 0;
long newseq;
char shadowpath[128];
FILE *cfp;
/*
** determine the current size of the current shadow file
** (fails if acctfd == -1) and determine if the file
** has not been deleted by stopping the atopacct service
*/
if (fstat(acctfd, &statacc) == -1 || statacc.st_nlink == 0)
{
/* close the previous obsolete shadow file */
(void) close(acctfd);
acctsize = 0;
/* reacquire the current real acctfd */
if (atopacctd(0))
return 0; // reaqcuire failed
if (fstat(acctfd, &statacc) == -1)
return 0;
}
/*
** verify how many new processes are added to the current
** shadow file
*/
numrecs = (statacc.st_size - acctsize) / acctrecsz;
/*
** verify if subsequent shadow files are involved
** (i.e. if the current file is full)
*/
if (statacc.st_size / acctrecsz < maxshadowrec)
return numrecs;
/*
** more shadow files available
** get current shadow file
*/
snprintf(shadowpath, sizeof shadowpath, "%s/%s/%s",
pacctdir, PACCTSHADOWD, PACCTSHADOWC);
if ( (cfp = fopen(shadowpath, "r")) )
{
if (fscanf(cfp, "%ld", &newseq) == 1)
{
fclose(cfp);
}
else
{
fclose(cfp);
return numrecs;
}
}
else
{
return numrecs;
}
if (newseq == curshadowseq)
return numrecs;
snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF,
pacctdir, PACCTSHADOWD, newseq);
/*
** determine the size of newest shadow file
*/
if (stat(shadowpath, &statacc) == -1)
{
fprintf(stderr, "failed to stat the size of newest shadow file\n");
return numrecs;
}
/*
** Check cases like statacc.st_size / acctrecsz > maxshadowrec,
** and atopacctd restarts at the same time, now newseq is zero.
** Omit this interval's statistics by returning zero.
*/
if (newseq > curshadowseq)
{
numrecs += ((newseq - curshadowseq - 1) * maxshadowrec) +
(statacc.st_size / acctrecsz);
}
else
{
numrecs = 0;
}
return numrecs;
}
else
/*
** classic process accounting on bases of directly opened
** process accounting file
*/
{
/*
** determine size of current process accounting file
*/
if (acctfd == -1 || fstat(acctfd, &statacc) == -1)
return 0;
/*
** accounting reset?
*/
if (acctsize > statacc.st_size)
{
/*
** reposition to start of file
*/
(void) lseek(acctfd, 0, SEEK_SET);
acctsize = 0;
}
/*
** using account file managed by (ps)acct package?
*/
if (pacctcur)
{
/*
** check inode of the current file and compare this
** with the inode of the opened file; if not equal,
** a file rotation has taken place and the size of
** the new file has to be added
*/
if ( stat(pacctcur->name, &(pacctcur->stat)) == 0)
{
if (statacc.st_ino != pacctcur->stat.st_ino)
{
return (statacc.st_size - acctsize +
pacctcur->stat.st_size) /
acctrecsz;
}
}
}
return (statacc.st_size - acctsize) / acctrecsz;
}
}
/*
** reposition the seek offset in the process accounting file to skip
** processes that have not been read
*/
void
acctrepos(unsigned int noverflow)
{
/*
** if accounting not supported, skip call
*/
if (acctfd == -1)
return;
if (maxshadowrec)
{
int i;
off_t virtoffset = acctsize + noverflow * acctrecsz;
off_t maxshadowsz = maxshadowrec * acctrecsz;
long switches = virtoffset / maxshadowsz;
acctsize = virtoffset % maxshadowsz;
for (i=0; i < switches; i++)
switchshadow();
(void) lseek(acctfd, acctsize, SEEK_SET);
}
else
{
/*
** just reposition to skip superfluous records
*/
(void) lseek(acctfd, noverflow * acctrecsz, SEEK_CUR);
acctsize += noverflow * acctrecsz;
/*
** when the new seek pointer is beyond the current file size
** and reading from a process accounting file written by
** the (ps)acct package, a logrotation might have taken place
*/
if (pacctcur)
{
struct stat statacc;
/*
** determine the size of the current accounting file
*/
if (fstat(acctfd, &statacc) == -1)
return;
/*
** seek pointer beyond file size and rotated to
** new account file?
*/
if (acctsize > statacc.st_size &&
statacc.st_ino != pacctcur->stat.st_ino)
{
/*
** - close old file
** - open new file
** - adapt acctsize to actual offset in new file
** and seek to that offset
*/
(void) close(acctfd);
if ( (acctfd = open(pacctcur->name,
O_RDONLY) ) == -1)
return; // open failed
acctsize = acctsize - statacc.st_size;
(void) lseek(acctfd, acctsize, SEEK_SET);
if (fstat(acctfd, &statacc) == -1)
return; // no new inode info
}
}
}
}
/*
** read the process records from the process accounting file,
** that are written since the previous cycle
*/
unsigned long
acctphotoproc(struct tstat *accproc, int nrprocs)
{
register int nrexit;
register struct tstat *api;
struct acct acctrec;
struct acct_v3 acctrec_v3;
struct stat statacc;
int filled;
/*
** if accounting not supported, skip call
*/
if (acctfd == -1)
return 0;
/*
** determine the size of the (current) account file
*/
if (fstat(acctfd, &statacc) == -1)
return 0;
/*
** check all exited processes in accounting file
*/
for (nrexit=0, api=accproc; nrexit < nrprocs; )
{
/*
** in case of shadow accounting files, we might have to
** switch from the current accounting file to the next
*/
if (maxshadowrec && acctsize >= statacc.st_size)
{
switchshadow();
/*
** determine the size of the new (current) account file
** and initialize the current offset within that file
*/
if (fstat(acctfd, &statacc) == -1)
return 0;
acctsize = 0;
}
/*
** in case of account file managed by (ps)acct package,
** be aware that a switch to a newer logfile might have
** to be done
*/
if (pacctcur && acctsize >= statacc.st_size)
{
/*
** check inode of the current file and compare this
** with the inode of the opened file; if not equal,
** a file rotation has taken place and the file
** has to be reopened
*/
if ( stat(pacctcur->name, &(pacctcur->stat)) == 0)
{
if (statacc.st_ino != pacctcur->stat.st_ino)
{
(void) close(acctfd);
if ( (acctfd = open(pacctcur->name,
O_RDONLY) ) == -1)
return 0; // open failed
if (fstat(acctfd, &statacc) == -1)
return 0; // no new inode info
acctsize = 0; // reset size new file
}
}
}
/*
** read the next record
*/
switch (acctversion)
{
case 2:
if ( read(acctfd, &acctrec, acctrecsz) < acctrecsz )
break; /* unexpected end of account file */
/*
** fill process info from accounting-record
*/
api->gen.state = 'E';
api->gen.nthr = 1;
api->gen.isproc = 1;
api->gen.pid = 0;
api->gen.tgid = 0;
api->gen.ppid = 0;
api->gen.excode = acctrec.ac_exitcode;
api->gen.ruid = acctrec.ac_uid16;
api->gen.rgid = acctrec.ac_gid16;
api->gen.btime = acctrec.ac_btime;
api->gen.elaps = acctrec.ac_etime;
api->cpu.stime = acctexp(acctrec.ac_stime);
api->cpu.utime = acctexp(acctrec.ac_utime);
api->mem.minflt = acctexp(acctrec.ac_minflt);
api->mem.majflt = acctexp(acctrec.ac_majflt);
api->dsk.rio = acctexp(acctrec.ac_rw);
strncpy(api->gen.name, acctrec.ac_comm, PNAMLEN);
api->gen.name[PNAMLEN] = '\0';
filled = 1;
break;
case 3:
if ( read(acctfd, &acctrec_v3, acctrecsz) < acctrecsz )
break; /* unexpected end of account file */
/*
** fill process info from accounting-record
*/
api->gen.state = 'E';
api->gen.pid = acctrec_v3.ac_pid;
api->gen.tgid = acctrec_v3.ac_pid;
api->gen.ppid = acctrec_v3.ac_ppid;
api->gen.nthr = 1;
api->gen.isproc = 1;
api->gen.excode = acctrec_v3.ac_exitcode;
api->gen.ruid = acctrec_v3.ac_uid;
api->gen.rgid = acctrec_v3.ac_gid;
api->gen.btime = acctrec_v3.ac_btime;
api->gen.elaps = acctrec_v3.ac_etime;
api->cpu.stime = acctexp(acctrec_v3.ac_stime);
api->cpu.utime = acctexp(acctrec_v3.ac_utime);
api->mem.minflt = acctexp(acctrec_v3.ac_minflt);
api->mem.majflt = acctexp(acctrec_v3.ac_majflt);
api->dsk.rio = acctexp(acctrec_v3.ac_rw);
strncpy(api->gen.name, acctrec_v3.ac_comm, PNAMLEN);
api->gen.name[PNAMLEN] = '\0';
filled = 1;
break;
}
if (filled == 1) {
nrexit++;
api++;
acctsize += acctrecsz;
filled = 0;
}
}
if (acctsize > ACCTMAXFILESZ && !maxshadowrec)
acctrestarttrial();
return nrexit;
}
/*
** when the size of the private accounting file exceeds a certain limit,
** it might be useful to stop process accounting, truncate the
** process accounting file to zero and start process accounting again
**
** this will only be done if this atop process is the only one
** that is currently using the accounting file
*/
static void
acctrestarttrial(void)
{
struct stat statacc;
int sematopid;
/*
** not private accounting-file in use?
*/
if (!acctatop)
return; // do not restart
/*
** still remaining records in accounting file that are
** written between the moment that the number of exited
** processes was counted and the moment that all processes
** were read
*/
(void) fstat(acctfd, &statacc);
if (acctsize != statacc.st_size)
return; // do not restart
/*
** claim the semaphore to get exclusive rights for
** the accounting-manipulation
*/
sematopid = semget(ATOPACCTKEY, 0, 0);
(void) semop(sematopid, &semclaim, 1);
/*
** check if there are more users of accounting file
*/
if (semctl(sematopid, 1, GETVAL, 0) < ATOPACCTTOT-1)
{
(void) semop(sematopid, &semrelse, 1);
return; // do not restart
}
/*
** restart is possible
**
** - switch off accounting
** - truncate the file
** - switch on accounting
*/
regainrootprivs(); // get root privs again
(void) acct(0); // switch off accounting
if ( truncate(ACCTDIR "/" ACCTFILE, 0) == 0)
(void) lseek(acctfd, 0, SEEK_SET);
(void) acct(ACCTDIR "/" ACCTFILE);
if (! droprootprivs() )
mcleanstop(42, "failed to drop root privs\n");
acctsize = 0;
(void) semop(sematopid, &semrelse, 1);
}
/*
** expand the special compression-methods
*/
static count_t
acctexp(comp_t ct)
{
count_t exp;
count_t val;
exp = (ct >> 13) & 0x7; /* obtain 3 bits base-8 exponent */
val = ct & 0x1fff; /* obtain 13 bits mantissa */
while (exp-- > 0)
val <<= 3;
return val;
}
/*
** switch to the next accounting shadow file
*/
static void
switchshadow(void)
{
int tmpfd;
char shadowpath[128];
struct flock flock;
/*
** determine path name of new shadow file
*/
curshadowseq++;
snprintf(shadowpath, sizeof shadowpath, PACCTSHADOWF,
pacctdir, PACCTSHADOWD, curshadowseq);
/*
** open new shadow file, while the previous is also kept open
** (to keep the read lock until a read lock is set for the new
** shadow file)
*/
if ( (tmpfd = open(shadowpath, O_RDONLY)) != -1)
{
/*
** set read lock on new shadow file
*/
flock.l_type = F_RDLCK;
flock.l_whence = SEEK_SET;
flock.l_start = 0;
flock.l_len = 1;
if ( fcntl(tmpfd, F_SETLK, &flock) != -1)
{
(void) close(acctfd); // implicit release read lock
acctfd = tmpfd;
return;
}
else
{
(void) close(tmpfd);
}
}
}
/*
** handle the option 'pacctdir' in the /etc/atoprc file
*/
void
do_pacctdir(char *tagname, char *tagvalue)
{
char shadowpath[128];
struct stat dirstat;
/*
** copy the directory pathname to an own buffer
*/
if ( (pacctdir = malloc(strlen(tagvalue)+1)) == NULL )
{
perror("malloc pacctdir");
exit(11);
}
strcpy(pacctdir, tagvalue);
/*
** verify if the atopacctd daemon is active
*/
if ( semget(PACCTPUBKEY, 0, 0) == -1)
{
fprintf(stderr, "Warning: option '%s' specified "
"while atopacctd not running!\n", tagname);
sleep(2);
return;
}
/*
** verify that the topdirectory exists
*/
if ( stat(pacctdir, &dirstat) == -1 )
{
fprintf(stderr, "Warning: option '%s' specified - ", tagname);
perror(pacctdir);
sleep(2);
return;
}
if (! S_ISDIR(dirstat.st_mode) )
{
fprintf(stderr, "Warning: option '%s' specified - ", tagname);
fprintf(stderr, "%s not a directory\n", pacctdir);
sleep(2);
return;
}
/*
** verify that the topdirectory contains the required subdirectory
*/
snprintf(shadowpath, sizeof shadowpath, "%s/%s",
pacctdir, PACCTSHADOWD);
if ( stat(shadowpath, &dirstat) == -1 )
{
fprintf(stderr, "Warning: option '%s' specified - ", tagname);
perror(shadowpath);
sleep(2);
return;
}
if (! S_ISDIR(dirstat.st_mode) )
{
fprintf(stderr, "Warning: option '%s' specified - ", tagname);
fprintf(stderr, "%s not a directory\n", shadowpath);
sleep(2);
return;
}
}
C
1
https://gitee.com/mirrors/atop.git
git@gitee.com:mirrors/atop.git
mirrors
atop
atop
master

搜索帮助