smemcap.c 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. smemcap - a tool for meaningful memory reporting
  3. Copyright 2008-2009 Matt Mackall <mpm@selenic.com>
  4. This software may be used and distributed according to the terms of
  5. the GNU General Public License version 2 or later, incorporated
  6. herein by reference.
  7. */
  8. //config:config SMEMCAP
  9. //config: bool "smemcap (2.5 kb)"
  10. //config: default y
  11. //config: help
  12. //config: smemcap is a tool for capturing process data for smem,
  13. //config: a memory usage statistic tool.
  14. //applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP))
  15. //kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o
  16. #include "libbb.h"
  17. #include "bb_archive.h"
  18. struct fileblock {
  19. struct fileblock *next;
  20. char data[TAR_BLOCK_SIZE];
  21. };
  22. static void writeheader(const char *path, struct stat *sb, int type)
  23. {
  24. struct tar_header_t header;
  25. memset(&header, 0, TAR_BLOCK_SIZE);
  26. strcpy(header.name, path);
  27. sprintf(header.mode, "%o", sb->st_mode & 0777);
  28. /* careful to not overflow fields! */
  29. sprintf(header.uid, "%o", sb->st_uid & 07777777);
  30. sprintf(header.gid, "%o", sb->st_gid & 07777777);
  31. sprintf(header.size, "%o", (unsigned)sb->st_size);
  32. sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL);
  33. header.typeflag = type;
  34. chksum_and_xwrite_tar_header(STDOUT_FILENO, &header);
  35. }
  36. static void archivefile(const char *path)
  37. {
  38. struct fileblock *start, *cur;
  39. struct fileblock **prev = &start;
  40. int fd, r;
  41. unsigned size = 0;
  42. struct stat s;
  43. /* buffer the file */
  44. fd = open(path, O_RDONLY);
  45. if (fd == -1) {
  46. /* skip vanished processes between dir listing and traversal */
  47. return;
  48. }
  49. do {
  50. cur = xzalloc(sizeof(*cur));
  51. *prev = cur;
  52. prev = &cur->next;
  53. r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
  54. if (r > 0)
  55. size += r;
  56. } while (r == TAR_BLOCK_SIZE);
  57. /* write archive header */
  58. fstat(fd, &s);
  59. close(fd);
  60. s.st_size = size;
  61. writeheader(path, &s, '0');
  62. /* dump file contents */
  63. for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
  64. xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
  65. start = cur;
  66. cur = cur->next;
  67. free(start);
  68. }
  69. }
  70. static void archivejoin(const char *sub, const char *name)
  71. {
  72. char path[sizeof(long long)*3 + sizeof("/cmdline")];
  73. sprintf(path, "%s/%s", sub, name);
  74. archivefile(path);
  75. }
  76. //usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
  77. //usage:#define smemcap_full_usage "\n\n"
  78. //usage: "Collect memory usage data in /proc and write it to stdout"
  79. int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  80. int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
  81. {
  82. DIR *d;
  83. struct dirent *de;
  84. xchdir("/proc");
  85. d = xopendir(".");
  86. archivefile("meminfo");
  87. archivefile("version");
  88. while ((de = readdir(d)) != NULL) {
  89. if (isdigit(de->d_name[0])) {
  90. struct stat s;
  91. memset(&s, 0, sizeof(s));
  92. s.st_mode = 0555;
  93. writeheader(de->d_name, &s, '5');
  94. archivejoin(de->d_name, "smaps");
  95. archivejoin(de->d_name, "cmdline");
  96. archivejoin(de->d_name, "stat");
  97. }
  98. }
  99. if (ENABLE_FEATURE_CLEAN_UP)
  100. closedir(d);
  101. return EXIT_SUCCESS;
  102. }