busybox/procps/smemcap.c
<<
>>
Prefs
   1/*
   2 smemcap - a tool for meaningful memory reporting
   3
   4 Copyright 2008-2009 Matt Mackall <mpm@selenic.com>
   5
   6 This software may be used and distributed according to the terms of
   7 the GNU General Public License version 2 or later, incorporated
   8 herein by reference.
   9*/
  10
  11//applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP))
  12
  13//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
  14
  15//config:config SMEMCAP
  16//config:       bool "smemcap"
  17//config:       default y
  18//config:       help
  19//config:         smemcap is a tool for capturing process data for smem,
  20//config:         a memory usage statistic tool.
  21
  22#include "libbb.h"
  23#include "archive.h"
  24
  25struct fileblock {
  26        struct fileblock *next;
  27        char data[TAR_BLOCK_SIZE];
  28};
  29
  30static void writeheader(const char *path, struct stat *sb, int type)
  31{
  32        struct tar_header_t header;
  33        int i, sum;
  34
  35        memset(&header, 0, TAR_BLOCK_SIZE);
  36        strcpy(header.name, path);
  37        sprintf(header.mode, "%o", sb->st_mode & 0777);
  38        /* careful to not overflow fields! */
  39        sprintf(header.uid, "%o", sb->st_uid & 07777777);
  40        sprintf(header.gid, "%o", sb->st_gid & 07777777);
  41        sprintf(header.size, "%o", (unsigned)sb->st_size);
  42        sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
  43        header.typeflag = type;
  44        strcpy(header.magic, "ustar  "); /* like GNU tar */
  45
  46        /* Calculate and store the checksum (the sum of all of the bytes of
  47         * the header). The checksum field must be filled with blanks for the
  48         * calculation. The checksum field is formatted differently from the
  49         * other fields: it has 6 digits, a NUL, then a space -- rather than
  50         * digits, followed by a NUL like the other fields... */
  51        header.chksum[7] = ' ';
  52        sum = ' ' * 7;
  53        for (i = 0; i < TAR_BLOCK_SIZE; i++)
  54                sum += ((unsigned char*)&header)[i];
  55        sprintf(header.chksum, "%06o", sum);
  56
  57        xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE);
  58}
  59
  60static void archivefile(const char *path)
  61{
  62        struct fileblock *start, *cur;
  63        struct fileblock **prev = &start;
  64        int fd, r;
  65        unsigned size = 0;
  66        struct stat s;
  67
  68        /* buffer the file */
  69        fd = xopen(path, O_RDONLY);
  70        do {
  71                cur = xzalloc(sizeof(*cur));
  72                *prev = cur;
  73                prev = &cur->next;
  74                r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
  75                if (r > 0)
  76                        size += r;
  77        } while (r == TAR_BLOCK_SIZE);
  78
  79        /* write archive header */
  80        fstat(fd, &s);
  81        close(fd);
  82        s.st_size = size;
  83        writeheader(path, &s, '0');
  84
  85        /* dump file contents */
  86        for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
  87                xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
  88                start = cur;
  89                cur = cur->next;
  90                free(start);
  91        }
  92}
  93
  94static void archivejoin(const char *sub, const char *name)
  95{
  96        char path[sizeof(long long)*3 + sizeof("/cmdline")];
  97        sprintf(path, "%s/%s", sub, name);
  98        archivefile(path);
  99}
 100
 101//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
 102//usage:#define smemcap_full_usage "\n\n"
 103//usage:       "Collect memory usage data in /proc and write it to stdout"
 104
 105int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 106int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
 107{
 108        DIR *d;
 109        struct dirent *de;
 110
 111        xchdir("/proc");
 112        d = xopendir(".");
 113
 114        archivefile("meminfo");
 115        archivefile("version");
 116        while ((de = readdir(d)) != NULL) {
 117                if (isdigit(de->d_name[0])) {
 118                        struct stat s;
 119                        memset(&s, 0, sizeof(s));
 120                        s.st_mode = 0555;
 121                        writeheader(de->d_name, &s, '5');
 122                        archivejoin(de->d_name, "smaps");
 123                        archivejoin(de->d_name, "cmdline");
 124                        archivejoin(de->d_name, "stat");
 125                }
 126        }
 127
 128        if (ENABLE_FEATURE_CLEAN_UP)
 129                closedir(d);
 130
 131        return EXIT_SUCCESS;
 132}
 133