blob: 81f4cafad084f7eff06a90406adc14cd319efa7e [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*/
Denys Vlasenkoa091d452010-06-24 05:05:12 +020010//config:config SMEMCAP
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020011//config: bool "smemcap (2.5 kb)"
Denys Vlasenkoa091d452010-06-24 05:05:12 +020012//config: default y
13//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020014//config: smemcap is a tool for capturing process data for smem,
15//config: a memory usage statistic tool.
Denys Vlasenkoa091d452010-06-24 05:05:12 +020016
Denys Vlasenko0c4dbd42017-09-18 16:28:43 +020017//applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP))
18
19//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
20
Denys Vlasenkoa091d452010-06-24 05:05:12 +020021#include "libbb.h"
Denys Vlasenkod184a722011-09-22 12:45:14 +020022#include "bb_archive.h"
Denys Vlasenkoa091d452010-06-24 05:05:12 +020023
24struct fileblock {
25 struct fileblock *next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020026 char data[TAR_BLOCK_SIZE];
Denys Vlasenkoa091d452010-06-24 05:05:12 +020027};
28
29static void writeheader(const char *path, struct stat *sb, int type)
30{
Denys Vlasenko52827e32010-06-26 18:21:36 +020031 struct tar_header_t header;
Denys Vlasenkoa091d452010-06-24 05:05:12 +020032 int i, sum;
33
Denys Vlasenko52827e32010-06-26 18:21:36 +020034 memset(&header, 0, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020035 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;
Denys Vlasenko5a0d8992010-09-12 17:13:29 +020043 strcpy(header.magic, "ustar "); /* like GNU tar */
Denys Vlasenkoa091d452010-06-24 05:05:12 +020044
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;
Denys Vlasenko52827e32010-06-26 18:21:36 +020052 for (i = 0; i < TAR_BLOCK_SIZE; i++)
Denys Vlasenkoa091d452010-06-24 05:05:12 +020053 sum += ((unsigned char*)&header)[i];
54 sprintf(header.chksum, "%06o", sum);
55
Denys Vlasenko52827e32010-06-26 18:21:36 +020056 xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020057}
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 = xopen(path, O_RDONLY);
69 do {
70 cur = xzalloc(sizeof(*cur));
71 *prev = cur;
72 prev = &cur->next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020073 r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020074 if (r > 0)
75 size += r;
Denys Vlasenko52827e32010-06-26 18:21:36 +020076 } while (r == TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020077
78 /* write archive header */
79 fstat(fd, &s);
80 close(fd);
81 s.st_size = size;
82 writeheader(path, &s, '0');
83
84 /* dump file contents */
Denys Vlasenko52827e32010-06-26 18:21:36 +020085 for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
86 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020087 start = cur;
88 cur = cur->next;
89 free(start);
90 }
91}
92
93static void archivejoin(const char *sub, const char *name)
94{
95 char path[sizeof(long long)*3 + sizeof("/cmdline")];
96 sprintf(path, "%s/%s", sub, name);
97 archivefile(path);
98}
99
100//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
101//usage:#define smemcap_full_usage "\n\n"
102//usage: "Collect memory usage data in /proc and write it to stdout"
103
104int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
105int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
106{
107 DIR *d;
108 struct dirent *de;
109
110 xchdir("/proc");
111 d = xopendir(".");
112
113 archivefile("meminfo");
114 archivefile("version");
115 while ((de = readdir(d)) != NULL) {
116 if (isdigit(de->d_name[0])) {
117 struct stat s;
118 memset(&s, 0, sizeof(s));
119 s.st_mode = 0555;
120 writeheader(de->d_name, &s, '5');
121 archivejoin(de->d_name, "smaps");
122 archivejoin(de->d_name, "cmdline");
123 archivejoin(de->d_name, "stat");
124 }
125 }
126
Alexander Shishkincbfeaac2010-10-21 23:44:47 +0300127 if (ENABLE_FEATURE_CLEAN_UP)
128 closedir(d);
129
Denys Vlasenkoa091d452010-06-24 05:05:12 +0200130 return EXIT_SUCCESS;
131}