blob: cdcc891a1225b8779482eb6979d47efcf5a5b674 [file] [log] [blame]
Denys Vlasenkoa091d452010-06-24 05:05:12 +02001/*
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
24struct tar_header {
25 char name[100]; /* 0-99 */
26 char mode[8]; /* 100-107 */
27 char uid[8]; /* 108-115 */
28 char gid[8]; /* 116-123 */
29 char size[12]; /* 124-135 */
30 char mtime[12]; /* 136-147 */
31 char chksum[8]; /* 148-155 */
32 char typeflag; /* 156-156 */
33 char linkname[100]; /* 157-256 */
34 /* POSIX: "ustar" NUL "00" */
35 /* GNU tar: "ustar " NUL */
36 /* Normally it's defined as magic[6] followed by
37 * version[2], but we put them together to save code.
38 */
39 char magic[8]; /* 257-264 */
40 char uname[32]; /* 265-296 */
41 char gname[32]; /* 297-328 */
42 char devmajor[8]; /* 329-336 */
43 char devminor[8]; /* 337-344 */
44 char prefix[155]; /* 345-499 */
45 char padding[12]; /* 500-512 (pad to exactly TAR_512) */
46};
47
48struct fileblock {
49 struct fileblock *next;
50 char data[512];
51};
52
53static void writeheader(const char *path, struct stat *sb, int type)
54{
55 struct tar_header header;
56 int i, sum;
57
58 memset(&header, 0, 512);
59 strcpy(header.name, path);
60 sprintf(header.mode, "%o", sb->st_mode & 0777);
61 /* careful to not overflow fields! */
62 sprintf(header.uid, "%o", sb->st_uid & 07777777);
63 sprintf(header.gid, "%o", sb->st_gid & 07777777);
64 sprintf(header.size, "%o", (unsigned)sb->st_size);
65 sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
66 header.typeflag = type;
67 //strcpy(header.magic, "ustar "); - do we want to be standard-compliant?
68
69 /* Calculate and store the checksum (the sum of all of the bytes of
70 * the header). The checksum field must be filled with blanks for the
71 * calculation. The checksum field is formatted differently from the
72 * other fields: it has 6 digits, a NUL, then a space -- rather than
73 * digits, followed by a NUL like the other fields... */
74 header.chksum[7] = ' ';
75 sum = ' ' * 7;
76 for (i = 0; i < 512; i++)
77 sum += ((unsigned char*)&header)[i];
78 sprintf(header.chksum, "%06o", sum);
79
80 xwrite(STDOUT_FILENO, &header, 512);
81}
82
83static void archivefile(const char *path)
84{
85 struct fileblock *start, *cur;
86 struct fileblock **prev = &start;
87 int fd, r;
88 unsigned size = 0;
89 struct stat s;
90
91 /* buffer the file */
92 fd = xopen(path, O_RDONLY);
93 do {
94 cur = xzalloc(sizeof(*cur));
95 *prev = cur;
96 prev = &cur->next;
97 r = full_read(fd, cur->data, 512);
98 if (r > 0)
99 size += r;
100 } while (r == 512);
101
102 /* write archive header */
103 fstat(fd, &s);
104 close(fd);
105 s.st_size = size;
106 writeheader(path, &s, '0');
107
108 /* dump file contents */
109 for (cur = start; (int)size > 0; size -= 512) {
110 xwrite(STDOUT_FILENO, cur->data, 512);
111 start = cur;
112 cur = cur->next;
113 free(start);
114 }
115}
116
117static void archivejoin(const char *sub, const char *name)
118{
119 char path[sizeof(long long)*3 + sizeof("/cmdline")];
120 sprintf(path, "%s/%s", sub, name);
121 archivefile(path);
122}
123
124//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
125//usage:#define smemcap_full_usage "\n\n"
126//usage: "Collect memory usage data in /proc and write it to stdout"
127
128int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
129int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
130{
131 DIR *d;
132 struct dirent *de;
133
134 xchdir("/proc");
135 d = xopendir(".");
136
137 archivefile("meminfo");
138 archivefile("version");
139 while ((de = readdir(d)) != NULL) {
140 if (isdigit(de->d_name[0])) {
141 struct stat s;
142 memset(&s, 0, sizeof(s));
143 s.st_mode = 0555;
144 writeheader(de->d_name, &s, '5');
145 archivejoin(de->d_name, "smaps");
146 archivejoin(de->d_name, "cmdline");
147 archivejoin(de->d_name, "stat");
148 }
149 }
150
151 return EXIT_SUCCESS;
152}