diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-24 05:05:12 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-24 05:05:12 +0200 |
commit | a091d45c3beb767ce9cb530ab0a81aee1238495d (patch) | |
tree | 5b2cb2fb16f05275c193f983fc61466b3fa03b15 /procps/smemcap.c | |
parent | dd8adde3866ac22bd510348b733bb29e1662ac6d (diff) |
smemcap: new applet
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'procps/smemcap.c')
-rw-r--r-- | procps/smemcap.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/procps/smemcap.c b/procps/smemcap.c new file mode 100644 index 000000000..cdcc891a1 --- /dev/null +++ b/procps/smemcap.c @@ -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; +} |