hush: if we did match "LINENO" or "OPTIND", stop further comparisons
[oweals/busybox.git] / procps / smemcap.c
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 //config:config SMEMCAP
11 //config:       bool "smemcap (2.5 kb)"
12 //config:       default y
13 //config:       help
14 //config:       smemcap is a tool for capturing process data for smem,
15 //config:       a memory usage statistic tool.
16
17 //applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP))
18
19 //kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
20
21 #include "libbb.h"
22 #include "bb_archive.h"
23
24 struct fileblock {
25         struct fileblock *next;
26         char data[TAR_BLOCK_SIZE];
27 };
28
29 static void writeheader(const char *path, struct stat *sb, int type)
30 {
31         struct tar_header_t header;
32         int i, sum;
33
34         memset(&header, 0, TAR_BLOCK_SIZE);
35         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;
43         strcpy(header.magic, "ustar  "); /* like GNU tar */
44
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;
52         for (i = 0; i < TAR_BLOCK_SIZE; i++)
53                 sum += ((unsigned char*)&header)[i];
54         sprintf(header.chksum, "%06o", sum);
55
56         xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE);
57 }
58
59 static 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;
73                 r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
74                 if (r > 0)
75                         size += r;
76         } while (r == TAR_BLOCK_SIZE);
77
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 */
85         for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
86                 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
87                 start = cur;
88                 cur = cur->next;
89                 free(start);
90         }
91 }
92
93 static 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
104 int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
105 int 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
127         if (ENABLE_FEATURE_CLEAN_UP)
128                 closedir(d);
129
130         return EXIT_SUCCESS;
131 }