6 Star 13 Fork 3

Gitee 极速下载/atop

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/Atoptool/atop
克隆/下载
atophide.c 19.49 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
/*
** 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 program copies an input raw logfile to an output raw logfile,
** while offering the possibility to select a subset of the samples
** (begin time and/or end time) and to anonymize the samples
** (subsitute command names/arguments, host name, logical volume names,
** etcetera by place holders).
** ==========================================================================
** Author: Gerlof Langeveld
** E-mail: gerlof.langeveld@atoptool.nl
** Initial: July 2023
** --------------------------------------------------------------------------
** Copyright (C) 2023 Gerlof Langeveld
**
** 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.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
** --------------------------------------------------------------------------
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <string.h>
#include <regex.h>
#include <zlib.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdarg.h>
#include "atop.h"
#include "photosyst.h"
#include "photoproc.h"
#include "rawlog.h"
// struct to register fakenames that are assigned
// to the original names
//
struct standin {
char *origname;
char *fakename;
struct standin *next;
};
// function prototypes
//
static int openin(char *);
static void readin(int, void *, int);
static int openout(char *);
static void writeout(int, void *, int);
static void writesamp(int, struct rawrecord *,
void *, int, void *, int, int,
void *, int, void *, int);
static int getrawsstat(int, struct sstat *, int);
static int getrawtstat(int, struct tstat *, int, int);
static void testcompval(int, char *);
static void anonymize(struct sstat *, struct tstat *, int);
static char *findstandin(struct standin **, unsigned long *, char *, char *);
// command names that will not be anonymized (in alphabetical order)
//
static char *allowedcoms[] = {
"^0anacron$",
"^agetty$", "^anacron$", "^atd$", "^atop", "^auditd$",
"^avahi-", "^awk$",
"^basename$", "^bash$", "^bc$", "^bunzip2$", "^bzip2$",
"^cat$", "^chmod$", "^chmod$", "^chown$", "^chromium",
"^chronyc$", "^chronyd$", "^cp$", "^cpio$", "^crond$",
"^csh$", "^cut$",
"^date$", "^dbus", "^dd$", "^df$", "^diff$",
"^dig$", "^dircolors$", "^dirname$", "^dnf$",
"^echo$", "^expr$",
"^file$", "^find$", "^firefox$", "^firewalld$",
"^gawk$", "^git$", "^grep$", "^grepconf.sh$",
"^gunzip$", "^gzip$",
"^head$", "^head$", "^host$", "^hostname$", "^hostnamectl$",
"^id$", "^ip$", "^iptables$", "^irqbalance$",
"^kill$", "^ksh$",
"^ldconfig$", "^less$", "^ln$", "^locale$", "^locate$",
"^logger$", "^logrotate$", "^ls$", "^lsmd$",
"^man$", "^make$", "^mcelog$", "^mkdate$", "^mkdir$", "^mktemp$",
"^modprobe$", "^more$", "^mount$", "^mv$",
"^netatop", "^NetworkManager$", "^nice$", "^nl$",
"^oom_",
"^pr$", "^ps$", "^pwd$", "^python$", "^python3$",
"^qemu-kvm$",
"^readlink$", "^rm$", "^rmdir$", "^rpcbind$", "^rpc.imapd$",
"^rpm$", "^rsyslogd$",
"^scp$", "^sed$", "^sh$", "^sleep$", "^smartd$", "^sort$",
"^ss$", "^ssh$", "^sshd$", "^stat$", "^su$", "^sudo$",
"^systemctl$", "^systemd",
"^tail$", "^tar$", "^tclsh$", "^tee$", "^thunderbird$",
"^top$", "^touch$", "^tr$", "^tuned$",
"^udevd", "^uname$", "^uniq$", "^unxz$", "^updatedb$",
"^usecpu$", "^usemem$",
"^vi$", "^vim$", "^vmtoolsd$",
"^wc$", "^which$",
"^xargs$", "^xz$", "^xzcat$",
"^yum$",
"^zcat$", "^zgrep$",
};
static regex_t *compreg; // compiled REs of allowed command names
int
main(int argc, char *argv[])
{
struct rawheader rh;
struct rawrecord rr;
struct sstat sstat;
struct tstat *tstatp;
struct cstat *cstatp;
char *istatp;
int ifd, ofd=0, writecnt = 0, anonflag = 0;
int i, c, numallowedcoms = sizeof allowedcoms/sizeof(char *);
char *infile, *outfile;
time_t begintime = 0, endtime = 0;
// verify the command line arguments:
// mandatory input and output filename
//
if (argc < 3)
prusage(argv[0]);
while ((c = getopt(argc, argv, "ab:e:")) != EOF)
{
switch (c)
{
case 'a': // anonymize
anonflag = 1;
break;
case 'b': // begin time
if ( !getbranchtime(optarg, &begintime) )
prusage(argv[0]);
break;
case 'e': // end time
if ( !getbranchtime(optarg, &endtime) )
prusage(argv[0]);
break;
default:
prusage(argv[0]);
break;
}
}
if (optind >= argc)
prusage(argv[0]);
infile = argv[optind++];
if (optind >= argc)
prusage(argv[0]);
outfile = argv[optind++];
// open the input file and verify magic number
//
if ( (ifd = openin(infile)) == -1)
{
prusage(argv[0]);
exit(2);
}
readin(ifd, &rh, sizeof rh);
if (rh.magic != MYMAGIC)
{
fprintf(stderr,
"File %s does not contain atop/atopsar data "
"(wrong magic number)\n", infile);
exit(3);
}
if (rh.sstatlen != sizeof(struct sstat) ||
rh.tstatlen != sizeof(struct tstat) ||
rh.rawheadlen != sizeof(struct rawheader) ||
rh.rawreclen != sizeof(struct rawrecord) )
{
fprintf(stderr,
"File %s created with incompatible version of atop "
"or created on other CPU architecture\n", infile);
exit(3);
}
// handle the output file
//
if (strcmp(infile, outfile) == 0)
{
fprintf(stderr,
"Input file and output file should not be identical!\n");
exit(12);
}
if (anonflag) // anonymize wanted?
{
// allocate space for compiled command REs and compile all REs
//
compreg = malloc(sizeof(regex_t) * numallowedcoms);
ptrverify(compreg, "Malloc failed for regex\n");
for (i=0; i < numallowedcoms; i++)
regcomp(&compreg[i], allowedcoms[i], REG_NOSUB);
// anonymize host name
//
memset(rh.utsname.nodename, '\0', sizeof rh.utsname.nodename);
strcpy(rh.utsname.nodename, "anonymized");
}
// read recorded samples and copy to output file
//
while ( read(ifd, &rr, rh.rawreclen) == rh.rawreclen)
{
// skip records that are recorded before specified begin time
//
if (begintime && begintime > rr.curtime)
{
(void) lseek(ifd, rr.scomplen, SEEK_CUR);
(void) lseek(ifd, rr.pcomplen, SEEK_CUR);
(void) lseek(ifd, rr.ccomplen, SEEK_CUR);
(void) lseek(ifd, rr.icomplen, SEEK_CUR);
continue;
}
// skip records that are recorded after specified end time
//
if (endtime && endtime < rr.curtime)
break;
// open the output file and write the rawheader once
//
if (writecnt++ == 0)
{
if ( (ofd = openout(outfile)) == -1)
{
prusage(argv[0]);
exit(4);
}
writeout(ofd, &rh, sizeof rh);
}
// read compressed system-level statistics and decompress
//
if ( !getrawsstat(ifd, &sstat, rr.scomplen) )
exit(7);
// read compressed process-level statistics and decompress
//
tstatp = malloc(sizeof(struct tstat) * rr.ndeviat);
ptrverify(tstatp,
"Malloc failed for %d stored tasks\n", rr.ndeviat);
if ( !getrawtstat(ifd, tstatp, rr.pcomplen, rr.ndeviat) )
exit(7);
// get compressed cgroup-level statistics
//
cstatp = malloc(rr.ccomplen);
ptrverify(cstatp, "Malloc failed for compressed pidlist\n");
readin(ifd, cstatp, rr.ccomplen);
// get compressed pidlist
//
istatp = malloc(rr.icomplen);
ptrverify(istatp, "Malloc failed for compressed pidlist\n");
readin(ifd, istatp, rr.icomplen);
// anonymize command lines and hostname
//
if (anonflag)
anonymize(&sstat, tstatp, rr.ndeviat);
// write record header, system-level stats, process-level stats,
// cgroup-level stats and pidlist
//
writesamp(ofd, &rr, &sstat, sizeof sstat,
tstatp, sizeof *tstatp, rr.ndeviat,
cstatp, rr.ccomplen,
istatp, rr.icomplen);
// cleanup
//
free(tstatp);
free(cstatp);
free(istatp);
}
// close files
//
close(ifd);
printf("Samples written: %d", writecnt);
if (writecnt == 0)
printf(" -- no output file created!\n");
else
printf("\n");
return 0;
}
// Funtion to anonymize the command lines and host name
//
static struct standin *lvmhead;
static unsigned long lvmsequence;
static struct standin *nfshead;
static unsigned long nfssequence;
static struct standin *cmdhead;
static unsigned long cmdsequence;
static void
anonymize(struct sstat *ssp, struct tstat *tsp, int ntask)
{
int i, r, numallowedcoms = sizeof allowedcoms/sizeof(char *);
char *standin, *p;
// anonimize system-level stats
// - logical volume names
//
for (i=0; i < ssp->dsk.nlvm; i++)
{
standin = findstandin(&lvmhead, &lvmsequence,
"logvol", ssp->dsk.lvm[i].name);
memset(ssp->dsk.lvm[i].name, '\0', MAXDKNAM);
strncpy(ssp->dsk.lvm[i].name, standin, MAXDKNAM-1);
}
// anonimize system-level stats
// - NFS mounted shares
//
for (i=0; i < ssp->nfs.nfsmounts.nrmounts; i++)
{
standin = findstandin(&nfshead, &nfssequence,
"nfsmnt", ssp->nfs.nfsmounts.nfsmnt[i].mountdev);
memset(ssp->nfs.nfsmounts.nfsmnt[i].mountdev, '\0',
sizeof ssp->nfs.nfsmounts.nfsmnt[i].mountdev);
strncpy(ssp->nfs.nfsmounts.nfsmnt[i].mountdev, standin,
sizeof ssp->nfs.nfsmounts.nfsmnt[i].mountdev - 1);
}
// anonymize process-level stats
// - preserve all kernel processes (i.e. processes without memory)
// - all command line arguments will be removed
// - selected command names will be kept
// (mainly standard commands and daemons)
//
for (i=0; i < ntask; i++, tsp++)
{
// preserve kernel processes
//
if (tsp->mem.vmem == 0 && tsp->gen.state != 'E')
continue;
// remove command line arguments
//
if ( (p = strchr(tsp->gen.cmdline, ' ')) )
memset(p, '\0', CMDLEN-(p-tsp->gen.cmdline));
// check all allowed names
//
for (r=0; r < numallowedcoms; r++)
{
// allowed name recognized: leave loop
//
if (regexec(&compreg[r], tsp->gen.name, 0, NULL, 0) == 0)
break;
}
// when command name does not appear to be allowed,
// replace command name by fake name
//
if (r == numallowedcoms)
{
standin = findstandin(&cmdhead, &cmdsequence,
"prog", tsp->gen.name);
memset(tsp->gen.name, '\0', PNAMLEN+1);
strncpy(tsp->gen.name, standin, PNAMLEN);
memset(tsp->gen.cmdline, '\0', CMDLEN+1);
strncpy(tsp->gen.cmdline, standin, CMDLEN);
}
}
}
// Function that searches for the original name and returns
// an anonymized replacement string.
// When the original string does not exist yet, a replacement
// string will be generated by using the prefix followed by a
// 5-digit sequence number. That replacement string is stored
// together with the original string for a subsequent search.
//
static char *
findstandin(struct standin **head, unsigned long *sequence,
char *prefix, char *origp)
{
struct standin *sp;
// first check if the original string can be found in the linked list
//
for (sp = *head; sp; sp = sp->next)
{
if ( strcmp(sp->origname, origp) == 0)
return sp->fakename; // found!
}
// original name not known yet
// create a new entry in the linked list
//
sp = malloc(sizeof *sp);
ptrverify(sp, "Malloc failed for standin struct\n");
sp->origname = malloc(strlen(origp)+1);
sp->fakename = malloc(strlen(prefix)+6);
ptrverify(sp->origname, "Malloc failed for standin orig\n");
ptrverify(sp->fakename, "Malloc failed for standin fake\n");
strcpy(sp->origname, origp);
snprintf(sp->fakename, strlen(prefix)+6, "%s%05lu", prefix, (*sequence)++);
sp->next = *head;
*head = sp;
return sp->fakename;
}
// Function that opens an existing raw file and
// verifies the magic number
//
static int
openin(char *infile)
{
int rawfd;
/*
** open raw file for reading
*/
if ( (rawfd = open(infile, O_RDONLY)) == -1)
{
fprintf(stderr, "%s - ", infile);
perror("open for reading");
return -1;
}
return rawfd;
}
// Function that reads a chunk of bytes from
// the input raw file
//
static void
readin(int rawfd, void *buf, int size)
{
/*
** read the requested chunk and verify
*/
if ( read(rawfd, buf, size) < size)
{
fprintf(stderr, "can not read raw file\n");
close(rawfd);
exit(9);
}
}
// Function that creates a raw log for output
//
static int
openout(char *outfile)
{
int rawfd;
/*
** create new output file
*/
if ( (rawfd = creat(outfile, 0666)) == -1)
{
fprintf(stderr, "%s - ", outfile);
perror("create raw output file");
return -1;
}
return rawfd;
}
// Function that reads a chunk of bytes from
// the input raw file
//
static void
writeout(int rawfd, void *buf, int size)
{
/*
** write the provided chunk and verify
*/
if ( write(rawfd, buf, size) < size)
{
fprintf(stderr, "can not write raw file\n");
close(rawfd);
exit(10);
}
}
// Function that shows the usage message
//
void
prusage(char *name)
{
fprintf(stderr,
"Usage: %s [-a] [-b YYYYMMDDhhmm] [-e YYYYMMDDhhmm] "
"rawin rawout\n\n", name);
fprintf(stderr,
"\t-a\tanonymize command names, host name, "
"logical volume names, etc\n");
fprintf(stderr,
"\t-b\twrite output from specified begin time\n");
fprintf(stderr,
"\t-e\twrite output until specified end time\n");
exit(1);
}
// Function to read the system-level statistics from the current offset
//
static int
getrawsstat(int rawfd, struct sstat *sp, int complen)
{
Byte *compbuf;
unsigned long uncomplen = sizeof(struct sstat);
int rv;
compbuf = malloc(complen);
ptrverify(compbuf, "Malloc failed for reading compressed sysstats\n");
if ( read(rawfd, compbuf, complen) < complen)
{
free(compbuf);
fprintf(stderr,
"Failed to read %d bytes for system\n", complen);
return 0;
}
rv = uncompress((Byte *)sp, &uncomplen, compbuf, complen);
testcompval(rv, "uncompress");
free(compbuf);
return 1;
}
// Function to read the process-level statistics from the current offset
//
static int
getrawtstat(int rawfd, struct tstat *pp, int complen, int ndeviat)
{
Byte *compbuf;
unsigned long uncomplen = sizeof(struct tstat) * ndeviat;
int rv;
compbuf = malloc(complen);
ptrverify(compbuf, "Malloc failed for reading compressed procstats\n");
if ( read(rawfd, compbuf, complen) < complen)
{
free(compbuf);
fprintf(stderr,
"Failed to read %d bytes for tasks\n", complen);
return 0;
}
rv = uncompress((Byte *)pp, &uncomplen, compbuf, complen);
testcompval(rv, "uncompress");
free(compbuf);
return 1;
}
#if 0
// Function to read the cgroup-level statistics
// from the current offset
//
static struct cstat *
getrawcstat(int rawfd, unsigned long ccomplen, unsigned long coriglen)
{
Byte *ccompbuf, *corigbuf;
int rv;
/*
** read all cstat structs
*/
ccompbuf = malloc(ccomplen);
corigbuf = malloc(coriglen);
ptrverify(ccompbuf, "Malloc failed for reading compressed cgroups\n");
ptrverify(corigbuf, "Malloc failed for decompressing cgroups\n");
readin(rawfd, ccompbuf, ccomplen);
rv = uncompress((Byte *)corigbuf, &coriglen, ccompbuf, ccomplen);
testcompval(rv, "uncompress cgroups");
free(ccompbuf);
return (struct cstat *)corigbuf;
}
#endif
// Function to write a new output sample from the current offset
//
static void
writesamp(int ofd, struct rawrecord *rr,
void *sstat, int sstatlen,
void *tstat, int tstatlen, int ntask,
void *cstat, int cstatlen,
void *istat, int istatlen)
{
int rv;
Byte scompbuf[sstatlen], *pcompbuf;
unsigned long scomplen = sizeof scompbuf;
unsigned long pcomplen = tstatlen * ntask;
/*
** compress system- and process-level statistics
*/
rv = compress(scompbuf, &scomplen,
(Byte *)sstat, (unsigned long)sstatlen);
testcompval(rv, "compress");
pcompbuf = malloc(pcomplen);
ptrverify(pcompbuf, "Malloc failed for compression buffer\n");
rv = compress(pcompbuf, &pcomplen, (Byte *)tstat,
(unsigned long)pcomplen);
testcompval(rv, "compress");
rr->scomplen = scomplen;
rr->pcomplen = pcomplen;
if ( write(ofd, rr, sizeof *rr) == -1)
{
perror("write raw record");
exit(7);
}
/*
** write compressed system status structure to file
*/
if ( write(ofd, scompbuf, scomplen) == -1)
{
perror("write raw status record");
exit(7);
}
/*
** write compressed list of process status structures to file
*/
if ( write(ofd, pcompbuf, pcomplen) == -1)
{
perror("write raw process records");
exit(7);
}
free(pcompbuf);
/*
** write compressed cgroup status structures to file
*/
if ( write(ofd, cstat, cstatlen) == -1)
{
perror("write raw cgroup records");
exit(7);
}
/*
** write compressed PID list
*/
if ( write(ofd, istat, istatlen) == -1)
{
perror("write raw pidlist");
exit(7);
}
}
// check success of (de)compression
//
static void
testcompval(int rv, char *func)
{
switch (rv)
{
case Z_OK:
case Z_STREAM_END:
case Z_NEED_DICT:
break;
case Z_MEM_ERROR:
fprintf(stderr, "%s: failed due to lack of memory\n", func);
exit(7);
case Z_BUF_ERROR:
fprintf(stderr, "%s: failed due to lack of room in buffer\n",
func);
exit(7);
case Z_DATA_ERROR:
fprintf(stderr,
"%s: failed due to corrupted/incomplete data\n", func);
exit(7);
default:
fprintf(stderr,
"%s: unexpected error %d\n", func, rv);
exit(7);
}
}
// generic pointer verification after malloc
//
void
ptrverify(const void *ptr, const char *errormsg, ...)
{
if (!ptr)
{
va_list args;
va_start(args, errormsg);
vfprintf(stderr, errormsg, args);
va_end (args);
exit(13);
}
}
// Convert a string in format YYYYMMDDhhmm into an epoch time value.
//
// Arguments: String with date-time in format YYYYMMDDhhmm
// Pointer to time_t containing 0 or current epoch time.
//
// Return-value: 0 - Wrong input-format
// 1 - Success
//
int
getbranchtime(char *itim, time_t *newtime)
{
register int ilen = strlen(itim);
time_t epoch;
struct tm tm;
memset(&tm, 0, sizeof tm);
/*
** verify length of input string
*/
if (ilen != 12)
return 0; // wrong date-time format
/*
** check string syntax for absolute time specified as
** YYYYMMDDhhmm
*/
if ( sscanf(itim, "%4d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon,
&tm.tm_mday, &tm.tm_hour, &tm.tm_min) != 5)
return 0;
tm.tm_year -= 1900;
tm.tm_mon -= 1;
if (tm.tm_year < 100 || tm.tm_mon < 0 || tm.tm_mon > 11 ||
tm.tm_mday < 1 || tm.tm_mday > 31 ||
tm.tm_hour < 0 || tm.tm_hour > 23 ||
tm.tm_min < 0 || tm.tm_min > 59 )
{
return 0; // wrong date-time format
}
tm.tm_isdst = -1;
if ((epoch = mktime(&tm)) == -1)
return 0; // wrong date-time format
// correct date-time format
*newtime = epoch;
return 1;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/mirrors/atop.git
git@gitee.com:mirrors/atop.git
mirrors
atop
atop
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891