astfd.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2009, Digium, Inc.
  5. *
  6. * Tilghman Lesher <tlesher@digium.com>
  7. *
  8. * See http://www.asterisk.org for more information about
  9. * the Asterisk project. Please do not directly contact
  10. * any of the maintainers of this project for assistance;
  11. * the project provides a web site, mailing lists and IRC
  12. * channels for your use.
  13. *
  14. * This program is free software, distributed under the terms of
  15. * the GNU General Public License Version 2. See the LICENSE file
  16. * at the top of the source tree.
  17. */
  18. /*! \file
  19. *
  20. * \brief Debugging routines for file descriptor leaks
  21. *
  22. * \author Tilghman Lesher <tlesher@digium.com>
  23. */
  24. #include "asterisk.h"
  25. #ifdef DEBUG_FD_LEAKS
  26. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <stddef.h>
  30. #include <time.h>
  31. #include <sys/time.h>
  32. #include <sys/resource.h>
  33. #include "asterisk/cli.h"
  34. #include "asterisk/logger.h"
  35. #include "asterisk/options.h"
  36. #include "asterisk/lock.h"
  37. #include "asterisk/strings.h"
  38. #include "asterisk/unaligned.h"
  39. static struct fdleaks {
  40. char file[40];
  41. int line;
  42. char function[25];
  43. char callname[10];
  44. char callargs[60];
  45. unsigned int isopen:1;
  46. } fdleaks[1024] = { { "", }, };
  47. #define COPY(dst, src) \
  48. do { \
  49. int dlen = sizeof(dst), slen = strlen(src); \
  50. if (slen + 1 > dlen) { \
  51. char *slash = strrchr(src, '/'); \
  52. if (slash) { \
  53. ast_copy_string(dst, slash + 1, dlen); \
  54. } else { \
  55. ast_copy_string(dst, src + slen - dlen + 1, dlen); \
  56. } \
  57. } else { \
  58. ast_copy_string(dst, src, dlen); \
  59. } \
  60. } while (0)
  61. #define STORE_COMMON(offset, name, ...) \
  62. COPY(fdleaks[offset].file, file); \
  63. fdleaks[offset].line = line; \
  64. COPY(fdleaks[offset].function, func); \
  65. strcpy(fdleaks[offset].callname, name); \
  66. snprintf(fdleaks[offset].callargs, sizeof(fdleaks[offset].callargs), __VA_ARGS__); \
  67. fdleaks[offset].isopen = 1;
  68. #undef open
  69. int __ast_fdleak_open(const char *file, int line, const char *func, const char *path, int flags, ...)
  70. {
  71. int res;
  72. va_list ap;
  73. int mode;
  74. if (flags & O_CREAT) {
  75. va_start(ap, flags);
  76. mode = va_arg(ap, int);
  77. va_end(ap);
  78. res = open(path, flags, mode);
  79. if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
  80. char sflags[80];
  81. snprintf(sflags, sizeof(sflags), "O_CREAT%s%s%s%s%s%s%s%s",
  82. flags & O_APPEND ? "|O_APPEND" : "",
  83. flags & O_EXCL ? "|O_EXCL" : "",
  84. flags & O_NONBLOCK ? "|O_NONBLOCK" : "",
  85. flags & O_TRUNC ? "|O_TRUNC" : "",
  86. flags & O_RDWR ? "|O_RDWR" : "",
  87. flags & O_RDONLY ? "|O_RDONLY" : "",
  88. flags & O_WRONLY ? "|O_WRONLY" : "",
  89. "");
  90. flags &= ~(O_CREAT | O_APPEND | O_EXCL | O_NONBLOCK | O_TRUNC | O_RDWR | O_RDONLY | O_WRONLY);
  91. if (flags) {
  92. STORE_COMMON(res, "open", "\"%s\",%s|%d,%04o", path, sflags, flags, mode);
  93. } else {
  94. STORE_COMMON(res, "open", "\"%s\",%s,%04o", path, sflags, mode);
  95. }
  96. }
  97. } else {
  98. res = open(path, flags);
  99. if (res > -1 && res < (sizeof(fdleaks) / sizeof(fdleaks[0]))) {
  100. STORE_COMMON(res, "open", "\"%s\",%d", path, flags);
  101. }
  102. }
  103. return res;
  104. }
  105. #undef pipe
  106. int __ast_fdleak_pipe(int *fds, const char *file, int line, const char *func)
  107. {
  108. int i, res = pipe(fds);
  109. if (res) {
  110. return res;
  111. }
  112. for (i = 0; i < 2; i++) {
  113. STORE_COMMON(fds[i], "pipe", "{%d,%d}", fds[0], fds[1]);
  114. }
  115. return 0;
  116. }
  117. #undef socket
  118. int __ast_fdleak_socket(int domain, int type, int protocol, const char *file, int line, const char *func)
  119. {
  120. char sdomain[20], stype[20], *sproto = NULL;
  121. struct protoent *pe;
  122. int res = socket(domain, type, protocol);
  123. if (res < 0 || res > 1023) {
  124. return res;
  125. }
  126. if ((pe = getprotobynumber(protocol))) {
  127. sproto = pe->p_name;
  128. }
  129. if (domain == PF_UNIX) {
  130. ast_copy_string(sdomain, "PF_UNIX", sizeof(sdomain));
  131. } else if (domain == PF_INET) {
  132. ast_copy_string(sdomain, "PF_INET", sizeof(sdomain));
  133. } else {
  134. snprintf(sdomain, sizeof(sdomain), "%d", domain);
  135. }
  136. if (type == SOCK_DGRAM) {
  137. ast_copy_string(stype, "SOCK_DGRAM", sizeof(stype));
  138. if (protocol == 0) {
  139. sproto = "udp";
  140. }
  141. } else if (type == SOCK_STREAM) {
  142. ast_copy_string(stype, "SOCK_STREAM", sizeof(stype));
  143. if (protocol == 0) {
  144. sproto = "tcp";
  145. }
  146. } else {
  147. snprintf(stype, sizeof(stype), "%d", type);
  148. }
  149. if (sproto) {
  150. STORE_COMMON(res, "socket", "%s,%s,\"%s\"", sdomain, stype, sproto);
  151. } else {
  152. STORE_COMMON(res, "socket", "%s,%s,\"%d\"", sdomain, stype, protocol);
  153. }
  154. return res;
  155. }
  156. #undef close
  157. int __ast_fdleak_close(int fd)
  158. {
  159. int res = close(fd);
  160. if (!res && fd > -1 && fd < 1024) {
  161. fdleaks[fd].isopen = 0;
  162. }
  163. return res;
  164. }
  165. #undef fopen
  166. FILE *__ast_fdleak_fopen(const char *path, const char *mode, const char *file, int line, const char *func)
  167. {
  168. FILE *res = fopen(path, mode);
  169. int fd;
  170. if (!res) {
  171. return res;
  172. }
  173. fd = fileno(res);
  174. STORE_COMMON(fd, "fopen", "\"%s\",\"%s\"", path, mode);
  175. return res;
  176. }
  177. #undef fclose
  178. int __ast_fdleak_fclose(FILE *ptr)
  179. {
  180. int fd, res;
  181. if (!ptr) {
  182. return fclose(ptr);
  183. }
  184. fd = fileno(ptr);
  185. if ((res = fclose(ptr)) || fd < 0 || fd > 1023) {
  186. return res;
  187. }
  188. fdleaks[fd].isopen = 0;
  189. return res;
  190. }
  191. #undef dup2
  192. int __ast_fdleak_dup2(int oldfd, int newfd, const char *file, int line, const char *func)
  193. {
  194. int res = dup2(oldfd, newfd);
  195. if (res < 0 || res > 1023) {
  196. return res;
  197. }
  198. STORE_COMMON(res, "dup2", "%d,%d", oldfd, newfd);
  199. return res;
  200. }
  201. #undef dup
  202. int __ast_fdleak_dup(int oldfd, const char *file, int line, const char *func)
  203. {
  204. int res = dup(oldfd);
  205. if (res < 0 || res > 1023) {
  206. return res;
  207. }
  208. STORE_COMMON(res, "dup2", "%d", oldfd);
  209. return res;
  210. }
  211. static char *handle_show_fd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  212. {
  213. int i;
  214. char line[24];
  215. struct rlimit rl;
  216. switch (cmd) {
  217. case CLI_INIT:
  218. e->command = "core show fd";
  219. e->usage =
  220. "Usage: core show fd\n"
  221. " List all file descriptors currently in use and where\n"
  222. " each was opened, and with what command.\n";
  223. return NULL;
  224. case CLI_GENERATE:
  225. return NULL;
  226. }
  227. getrlimit(RLIMIT_FSIZE, &rl);
  228. if (rl.rlim_cur == RLIM_INFINITY || rl.rlim_max == RLIM_INFINITY) {
  229. ast_copy_string(line, "unlimited", sizeof(line));
  230. } else {
  231. snprintf(line, sizeof(line), "%d/%d", (int) rl.rlim_cur, (int) rl.rlim_max);
  232. }
  233. ast_cli(a->fd, "Current maxfiles: %s\n", line);
  234. for (i = 0; i < 1024; i++) {
  235. if (fdleaks[i].isopen) {
  236. snprintf(line, sizeof(line), "%d", fdleaks[i].line);
  237. ast_cli(a->fd, "%5d %15s:%-7.7s (%-25s): %s(%s)\n", i, fdleaks[i].file, line, fdleaks[i].function, fdleaks[i].callname, fdleaks[i].callargs);
  238. }
  239. }
  240. return CLI_SUCCESS;
  241. }
  242. static struct ast_cli_entry cli_show_fd = AST_CLI_DEFINE(handle_show_fd, "Show open file descriptors");
  243. int ast_fd_init(void)
  244. {
  245. return ast_cli_register(&cli_show_fd);
  246. }
  247. #else /* !defined(DEBUG_FD_LEAKS) */
  248. int ast_fd_init(void)
  249. {
  250. return 0;
  251. }
  252. #endif /* defined(DEBUG_FD_LEAKS) */