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#include "unarchive.h" 24 25struct fileblock { 26 struct fileblock *next; 27 char data[TAR_BLOCK_SIZE]; 28}; 29 30static void writeheader(const char *path, struct stat *sb, int type) 31{ 32 struct tar_header_t header; 33 int i, sum; 34 35 memset(&header, 0, TAR_BLOCK_SIZE); 36 strcpy(header.name, path); 37 sprintf(header.mode, "%o", sb->st_mode & 0777); 38 /* careful to not overflow fields! */ 39 sprintf(header.uid, "%o", sb->st_uid & 07777777); 40 sprintf(header.gid, "%o", sb->st_gid & 07777777); 41 sprintf(header.size, "%o", (unsigned)sb->st_size); 42 sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL); 43 header.typeflag = type; 44 //strcpy(header.magic, "ustar "); - do we want to be standard-compliant? 45 46 /* Calculate and store the checksum (the sum of all of the bytes of 47 * the header). The checksum field must be filled with blanks for the 48 * calculation. The checksum field is formatted differently from the 49 * other fields: it has 6 digits, a NUL, then a space -- rather than 50 * digits, followed by a NUL like the other fields... */ 51 header.chksum[7] = ' '; 52 sum = ' ' * 7; 53 for (i = 0; i < TAR_BLOCK_SIZE; i++) 54 sum += ((unsigned char*)&header)[i]; 55 sprintf(header.chksum, "%06o", sum); 56 57 xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE); 58} 59 60static void archivefile(const char *path) 61{ 62 struct fileblock *start, *cur; 63 struct fileblock **prev = &start; 64 int fd, r; 65 unsigned size = 0; 66 struct stat s; 67 68 /* buffer the file */ 69 fd = xopen(path, O_RDONLY); 70 do { 71 cur = xzalloc(sizeof(*cur)); 72 *prev = cur; 73 prev = &cur->next; 74 r = full_read(fd, cur->data, TAR_BLOCK_SIZE); 75 if (r > 0) 76 size += r; 77 } while (r == TAR_BLOCK_SIZE); 78 79 /* write archive header */ 80 fstat(fd, &s); 81 close(fd); 82 s.st_size = size; 83 writeheader(path, &s, '0'); 84 85 /* dump file contents */ 86 for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) { 87 xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE); 88 start = cur; 89 cur = cur->next; 90 free(start); 91 } 92} 93 94static void archivejoin(const char *sub, const char *name) 95{ 96 char path[sizeof(long long)*3 + sizeof("/cmdline")]; 97 sprintf(path, "%s/%s", sub, name); 98 archivefile(path); 99} 100 101//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR" 102//usage:#define smemcap_full_usage "\n\n" 103//usage: "Collect memory usage data in /proc and write it to stdout" 104 105int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 106int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) 107{ 108 DIR *d; 109 struct dirent *de; 110 111 xchdir("/proc"); 112 d = xopendir("."); 113 114 archivefile("meminfo"); 115 archivefile("version"); 116 while ((de = readdir(d)) != NULL) { 117 if (isdigit(de->d_name[0])) { 118 struct stat s; 119 memset(&s, 0, sizeof(s)); 120 s.st_mode = 0555; 121 writeheader(de->d_name, &s, '5'); 122 archivejoin(de->d_name, "smaps"); 123 archivejoin(de->d_name, "cmdline"); 124 archivejoin(de->d_name, "stat"); 125 } 126 } 127 128 return EXIT_SUCCESS; 129} 130