blob: 2f8ab192e2101c8445cee79c9299534d3b482ed1 [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 */
Denys Vlasenko270becc2018-08-30 11:49:51 +020068 fd = open(path, O_RDONLY);
Andre Goddard Rosa9a2621a2018-08-26 17:37:30 +020069 if (fd == -1) {
70 /* skip vanished processes between dir listing and traversal */
71 return;
72 }
Denys Vlasenkoa091d452010-06-24 05:05:12 +020073 do {
74 cur = xzalloc(sizeof(*cur));
75 *prev = cur;
76 prev = &cur->next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020077 r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020078 if (r > 0)
79 size += r;
Denys Vlasenko52827e32010-06-26 18:21:36 +020080 } while (r == TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020081
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 */
Denys Vlasenko52827e32010-06-26 18:21:36 +020089 for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
90 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020091 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
Alexander Shishkincbfeaac2010-10-21 23:44:47 +0300131 if (ENABLE_FEATURE_CLEAN_UP)
132 closedir(d);
133
Denys Vlasenkoa091d452010-06-24 05:05:12 +0200134 return EXIT_SUCCESS;
135}