blob: 2f1897dae0987f21881d19fd38c903a7467d668a [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
Denys Vlasenko52827e32010-06-26 18:21:36 +020033 memset(&header, 0, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020034 strcpy(header.name, path);
35 sprintf(header.mode, "%o", sb->st_mode & 0777);
36 /* careful to not overflow fields! */
37 sprintf(header.uid, "%o", sb->st_uid & 07777777);
38 sprintf(header.gid, "%o", sb->st_gid & 07777777);
39 sprintf(header.size, "%o", (unsigned)sb->st_size);
40 sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
41 header.typeflag = type;
Denys Vlasenko62d5a1e2021-08-20 17:58:49 +020042 chksum_and_xwrite_tar_header(STDOUT_FILENO, &header);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020043}
44
45static void archivefile(const char *path)
46{
47 struct fileblock *start, *cur;
48 struct fileblock **prev = &start;
49 int fd, r;
50 unsigned size = 0;
51 struct stat s;
52
53 /* buffer the file */
Denys Vlasenko270becc2018-08-30 11:49:51 +020054 fd = open(path, O_RDONLY);
Andre Goddard Rosa9a2621a2018-08-26 17:37:30 +020055 if (fd == -1) {
56 /* skip vanished processes between dir listing and traversal */
57 return;
58 }
Denys Vlasenkoa091d452010-06-24 05:05:12 +020059 do {
60 cur = xzalloc(sizeof(*cur));
61 *prev = cur;
62 prev = &cur->next;
Denys Vlasenko52827e32010-06-26 18:21:36 +020063 r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020064 if (r > 0)
65 size += r;
Denys Vlasenko52827e32010-06-26 18:21:36 +020066 } while (r == TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020067
68 /* write archive header */
69 fstat(fd, &s);
70 close(fd);
71 s.st_size = size;
72 writeheader(path, &s, '0');
73
74 /* dump file contents */
Denys Vlasenko52827e32010-06-26 18:21:36 +020075 for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
76 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
Denys Vlasenkoa091d452010-06-24 05:05:12 +020077 start = cur;
78 cur = cur->next;
79 free(start);
80 }
81}
82
83static void archivejoin(const char *sub, const char *name)
84{
85 char path[sizeof(long long)*3 + sizeof("/cmdline")];
86 sprintf(path, "%s/%s", sub, name);
87 archivefile(path);
88}
89
90//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
91//usage:#define smemcap_full_usage "\n\n"
92//usage: "Collect memory usage data in /proc and write it to stdout"
93
94int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
95int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
96{
97 DIR *d;
98 struct dirent *de;
99
100 xchdir("/proc");
101 d = xopendir(".");
102
103 archivefile("meminfo");
104 archivefile("version");
105 while ((de = readdir(d)) != NULL) {
106 if (isdigit(de->d_name[0])) {
107 struct stat s;
108 memset(&s, 0, sizeof(s));
109 s.st_mode = 0555;
110 writeheader(de->d_name, &s, '5');
111 archivejoin(de->d_name, "smaps");
112 archivejoin(de->d_name, "cmdline");
113 archivejoin(de->d_name, "stat");
114 }
115 }
116
Alexander Shishkincbfeaac2010-10-21 23:44:47 +0300117 if (ENABLE_FEATURE_CLEAN_UP)
118 closedir(d);
119
Denys Vlasenkoa091d452010-06-24 05:05:12 +0200120 return EXIT_SUCCESS;
121}