ntpd: step correction to variables had wrong sign, fixing
[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
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 }