smemcap: new applet

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2010-06-24 05:05:12 +02:00
parent dd8adde386
commit a091d45c3b

152
procps/smemcap.c Normal file
View File

@ -0,0 +1,152 @@
/*
smemcap - a tool for meaningful memory reporting
Copyright 2008-2009 Matt Mackall <mpm@selenic.com>
This software may be used and distributed according to the terms of
the GNU General Public License version 2 or later, incorporated
herein by reference.
*/
//applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP))
//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
//config:config SMEMCAP
//config: bool "smemcap"
//config: default y
//config: help
//config: smemcap is a tool for capturing process data for smem,
//config: a memory usage statistic tool.
#include "libbb.h"
struct tar_header {
char name[100]; /* 0-99 */
char mode[8]; /* 100-107 */
char uid[8]; /* 108-115 */
char gid[8]; /* 116-123 */
char size[12]; /* 124-135 */
char mtime[12]; /* 136-147 */
char chksum[8]; /* 148-155 */
char typeflag; /* 156-156 */
char linkname[100]; /* 157-256 */
/* POSIX: "ustar" NUL "00" */
/* GNU tar: "ustar " NUL */
/* Normally it's defined as magic[6] followed by
* version[2], but we put them together to save code.
*/
char magic[8]; /* 257-264 */
char uname[32]; /* 265-296 */
char gname[32]; /* 297-328 */
char devmajor[8]; /* 329-336 */
char devminor[8]; /* 337-344 */
char prefix[155]; /* 345-499 */
char padding[12]; /* 500-512 (pad to exactly TAR_512) */
};
struct fileblock {
struct fileblock *next;
char data[512];
};
static void writeheader(const char *path, struct stat *sb, int type)
{
struct tar_header header;
int i, sum;
memset(&header, 0, 512);
strcpy(header.name, path);
sprintf(header.mode, "%o", sb->st_mode & 0777);
/* careful to not overflow fields! */
sprintf(header.uid, "%o", sb->st_uid & 07777777);
sprintf(header.gid, "%o", sb->st_gid & 07777777);
sprintf(header.size, "%o", (unsigned)sb->st_size);
sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
header.typeflag = type;
//strcpy(header.magic, "ustar "); - do we want to be standard-compliant?
/* Calculate and store the checksum (the sum of all of the bytes of
* the header). The checksum field must be filled with blanks for the
* calculation. The checksum field is formatted differently from the
* other fields: it has 6 digits, a NUL, then a space -- rather than
* digits, followed by a NUL like the other fields... */
header.chksum[7] = ' ';
sum = ' ' * 7;
for (i = 0; i < 512; i++)
sum += ((unsigned char*)&header)[i];
sprintf(header.chksum, "%06o", sum);
xwrite(STDOUT_FILENO, &header, 512);
}
static void archivefile(const char *path)
{
struct fileblock *start, *cur;
struct fileblock **prev = &start;
int fd, r;
unsigned size = 0;
struct stat s;
/* buffer the file */
fd = xopen(path, O_RDONLY);
do {
cur = xzalloc(sizeof(*cur));
*prev = cur;
prev = &cur->next;
r = full_read(fd, cur->data, 512);
if (r > 0)
size += r;
} while (r == 512);
/* write archive header */
fstat(fd, &s);
close(fd);
s.st_size = size;
writeheader(path, &s, '0');
/* dump file contents */
for (cur = start; (int)size > 0; size -= 512) {
xwrite(STDOUT_FILENO, cur->data, 512);
start = cur;
cur = cur->next;
free(start);
}
}
static void archivejoin(const char *sub, const char *name)
{
char path[sizeof(long long)*3 + sizeof("/cmdline")];
sprintf(path, "%s/%s", sub, name);
archivefile(path);
}
//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
//usage:#define smemcap_full_usage "\n\n"
//usage: "Collect memory usage data in /proc and write it to stdout"
int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
DIR *d;
struct dirent *de;
xchdir("/proc");
d = xopendir(".");
archivefile("meminfo");
archivefile("version");
while ((de = readdir(d)) != NULL) {
if (isdigit(de->d_name[0])) {
struct stat s;
memset(&s, 0, sizeof(s));
s.st_mode = 0555;
writeheader(de->d_name, &s, '5');
archivejoin(de->d_name, "smaps");
archivejoin(de->d_name, "cmdline");
archivejoin(de->d_name, "stat");
}
}
return EXIT_SUCCESS;
}