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