diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-24 05:05:12 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-06-24 05:05:12 +0200 |
commit | a091d45c3beb767ce9cb530ab0a81aee1238495d (patch) | |
tree | 5b2cb2fb16f05275c193f983fc61466b3fa03b15 | |
parent | dd8adde3866ac22bd510348b733bb29e1662ac6d (diff) | |
download | busybox-w32-a091d45c3beb767ce9cb530ab0a81aee1238495d.tar.gz busybox-w32-a091d45c3beb767ce9cb530ab0a81aee1238495d.tar.bz2 busybox-w32-a091d45c3beb767ce9cb530ab0a81aee1238495d.zip |
smemcap: new applet
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | procps/smemcap.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/procps/smemcap.c b/procps/smemcap.c new file mode 100644 index 000000000..cdcc891a1 --- /dev/null +++ b/procps/smemcap.c | |||
@@ -0,0 +1,152 @@ | |||
1 | /* | ||
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 | |||
24 | struct 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 | |||
48 | struct fileblock { | ||
49 | struct fileblock *next; | ||
50 | char data[512]; | ||
51 | }; | ||
52 | |||
53 | static 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 | |||
83 | static 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 | |||
117 | static 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 | |||
128 | int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
129 | int 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 | } | ||