smemcap.c 3.5 KB

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