smemcap.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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 = xopen(path, O_RDONLY);
  57. do {
  58. cur = xzalloc(sizeof(*cur));
  59. *prev = cur;
  60. prev = &cur->next;
  61. r = full_read(fd, cur->data, TAR_BLOCK_SIZE);
  62. if (r > 0)
  63. size += r;
  64. } while (r == TAR_BLOCK_SIZE);
  65. /* write archive header */
  66. fstat(fd, &s);
  67. close(fd);
  68. s.st_size = size;
  69. writeheader(path, &s, '0');
  70. /* dump file contents */
  71. for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) {
  72. xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE);
  73. start = cur;
  74. cur = cur->next;
  75. free(start);
  76. }
  77. }
  78. static void archivejoin(const char *sub, const char *name)
  79. {
  80. char path[sizeof(long long)*3 + sizeof("/cmdline")];
  81. sprintf(path, "%s/%s", sub, name);
  82. archivefile(path);
  83. }
  84. //usage:#define smemcap_trivial_usage ">SMEMDATA.TAR"
  85. //usage:#define smemcap_full_usage "\n\n"
  86. //usage: "Collect memory usage data in /proc and write it to stdout"
  87. int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  88. int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
  89. {
  90. DIR *d;
  91. struct dirent *de;
  92. xchdir("/proc");
  93. d = xopendir(".");
  94. archivefile("meminfo");
  95. archivefile("version");
  96. while ((de = readdir(d)) != NULL) {
  97. if (isdigit(de->d_name[0])) {
  98. struct stat s;
  99. memset(&s, 0, sizeof(s));
  100. s.st_mode = 0555;
  101. writeheader(de->d_name, &s, '5');
  102. archivejoin(de->d_name, "smaps");
  103. archivejoin(de->d_name, "cmdline");
  104. archivejoin(de->d_name, "stat");
  105. }
  106. }
  107. if (ENABLE_FEATURE_CLEAN_UP)
  108. closedir(d);
  109. return EXIT_SUCCESS;
  110. }