blob: 7dc1601998b299b68dde6d120e49b3856a31bafc [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
Denys Vlasenkob9f2d9f2011-01-18 13:58:01 +010011//applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP))
Denys Vlasenkoa091d452010-06-24 05:05:12 +020012
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"
Tanguy Pruvot8a6c2c22012-04-28 00:24:09 +020023#include "bb_archive.h"
Denys Vlasenkoa091d452010-06-24 05:05:12 +020024
25struct fileblock {
26 struct fileblock *next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020027 char data[TAR_BLOCK_SIZE];
Denys Vlasenkoa091d452010-06-24 05:05:12 +020028};
29
30static void writeheader(const char *path, struct stat *sb, int type)
31{
Denys Vlasenko52827e32010-06-26 18:21:36 +020032 struct tar_header_t header;
Denys Vlasenkoa091d452010-06-24 05:05:12 +020033 int i, sum;
34
Denys Vlasenko52827e32010-06-26 18:21:36 +020035 memset(&header, 0, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020036 strcpy(header.name, path);
37 sprintf(header.mode, "%o", sb->st_mode & 0777);
38 /* careful to not overflow fields! */
maxwen27116ba2015-08-14 21:41:28 +020039#ifdef BIONIC_L
40 sprintf(header.uid, "%uo", sb->st_uid & 07777777);
41 sprintf(header.gid, "%uo", sb->st_gid & 07777777);
42#elif defined(__BIONIC__)
43 sprintf(header.uid, "%lo", sb->st_uid & 07777777);
44 sprintf(header.gid, "%lo", sb->st_gid & 07777777);
45#else
Denys Vlasenkoa091d452010-06-24 05:05:12 +020046 sprintf(header.uid, "%o", sb->st_uid & 07777777);
47 sprintf(header.gid, "%o", sb->st_gid & 07777777);
maxwen27116ba2015-08-14 21:41:28 +020048#endif
Denys Vlasenkoa091d452010-06-24 05:05:12 +020049 sprintf(header.size, "%o", (unsigned)sb->st_size);
50 sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
51 header.typeflag = type;
Denys Vlasenko5a0d8992010-09-12 17:13:29 +020052 strcpy(header.magic, "ustar "); /* like GNU tar */
Denys Vlasenkoa091d452010-06-24 05:05:12 +020053
54 /* Calculate and store the checksum (the sum of all of the bytes of
55 * the header). The checksum field must be filled with blanks for the
56 * calculation. The checksum field is formatted differently from the
57 * other fields: it has 6 digits, a NUL, then a space -- rather than
58 * digits, followed by a NUL like the other fields... */
59 header.chksum[7] = ' ';
60 sum = ' ' * 7;
Denys Vlasenko52827e32010-06-26 18:21:36 +020061 for (i = 0; i < TAR_BLOCK_SIZE; i++)
Denys Vlasenkoa091d452010-06-24 05:05:12 +020062 sum += ((unsigned char*)&header)[i];
63 sprintf(header.chksum, "%06o", sum);
64
Denys Vlasenko52827e32010-06-26 18:21:36 +020065 xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020066}
67
68static void archivefile(const char *path)
69{
70 struct fileblock *start, *cur;
71 struct fileblock **prev = &start;
72 int fd, r;
73 unsigned size = 0;
74 struct stat s;
75
76 /* buffer the file */
77 fd = xopen(path, O_RDONLY);
78 do {
79 cur = xzalloc(sizeof(*cur));
80 *prev = cur;
81 prev = &cur->next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020082 r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020083 if (r > 0)
84 size += r;
Denys Vlasenko52827e32010-06-26 18:21:36 +020085 } while (r == TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020086
87 /* write archive header */
88 fstat(fd, &s);
89 close(fd);
90 s.st_size = size;
91 writeheader(path, &s, '0');
92
93 /* dump file contents */
Denys Vlasenko52827e32010-06-26 18:21:36 +020094 for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
95 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020096 start = cur;
97 cur = cur->next;
98 free(start);
99 }
100}
101
102static void archivejoin(const char *sub, const char *name)
103{
104 char path[sizeof(long long)*3 + sizeof("/cmdline")];
105 sprintf(path, "%s/%s", sub, name);
106 archivefile(path);
107}
108
109//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
110//usage:#define smemcap_full_usage "\n\n"
111//usage: "Collect memory usage data in /proc and write it to stdout"
112
113int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
114int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
115{
116 DIR *d;
117 struct dirent *de;
118
119 xchdir("/proc");
120 d = xopendir(".");
121
122 archivefile("meminfo");
123 archivefile("version");
124 while ((de = readdir(d)) != NULL) {
125 if (isdigit(de->d_name[0])) {
126 struct stat s;
127 memset(&s, 0, sizeof(s));
128 s.st_mode = 0555;
129 writeheader(de->d_name, &s, '5');
130 archivejoin(de->d_name, "smaps");
131 archivejoin(de->d_name, "cmdline");
132 archivejoin(de->d_name, "stat");
133 }
134 }
135
Alexander Shishkincbfeaac2010-10-21 23:44:47 +0300136 if (ENABLE_FEATURE_CLEAN_UP)
137 closedir(d);
138
Denys Vlasenkoa091d452010-06-24 05:05:12 +0200139 return EXIT_SUCCESS;
140}