error.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. voltlogger_oscilloscope
  3. Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
  4. This program is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation, either version 3 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. /*
  16. * This file implements way to output debugging information. It's supposed
  17. * to be slow but convenient functions.
  18. */
  19. #include "configuration.h"
  20. #include <stdlib.h>
  21. #include <execinfo.h>
  22. #include <stdio.h>
  23. #include <errno.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include <syslog.h>
  27. #include <pthread.h> /* pthread_self() */
  28. #include <sys/types.h> /* getpid() */
  29. #include <unistd.h> /* getpid() */
  30. #include "error.h"
  31. #include "pthreadex.h"
  32. static int zero = 0;
  33. static int three = 3;
  34. static int *outputmethod = &zero;
  35. static int *debug = &zero;
  36. static int *quiet = &zero;
  37. static int *verbose = &three;
  38. pthread_mutex_t *error_mutex_p = NULL;
  39. static int printf_stderr(const char *fmt, ...) {
  40. va_list args;
  41. int rc;
  42. va_start(args, fmt);
  43. rc = vfprintf(stderr, fmt, args);
  44. va_end(args);
  45. return rc;
  46. }
  47. static int printf_stdout(const char *fmt, ...) {
  48. va_list args;
  49. int rc;
  50. va_start(args, fmt);
  51. rc = vfprintf(stdout, fmt, args);
  52. va_end(args);
  53. return rc;
  54. }
  55. static int vprintf_stderr(const char *fmt, va_list args) {
  56. return vfprintf(stderr, fmt, args);
  57. }
  58. static int vprintf_stdout(const char *fmt, va_list args) {
  59. return vfprintf(stdout, fmt, args);
  60. }
  61. static void flush_stderr(int level) {
  62. fprintf(stderr, "\n");
  63. fflush(stderr);
  64. }
  65. static void flush_stdout(int level) {
  66. fprintf(stdout, "\n");
  67. fflush(stdout);
  68. }
  69. static char _syslog_buffer[SYSLOG_BUFSIZ+1] = {0};
  70. size_t _syslog_buffer_filled = 0;
  71. static int vsyslog_buf(const char *fmt, va_list args) {
  72. int len;
  73. size_t size;
  74. size = SYSLOG_BUFSIZ - _syslog_buffer_filled;
  75. #ifdef VERYPARANOID
  76. if (
  77. ( size > SYSLOG_BUFSIZ) ||
  78. (_syslog_buffer_filled + size > SYSLOG_BUFSIZ) ||
  79. (_syslog_buffer_filled > SYSLOG_BUFSIZ)
  80. ) {
  81. fprintf(stderr, "Security problem while vsyslog_buf(): "
  82. "_syslog_buffer_filled == %lu; "
  83. "size == %lu; "
  84. "SYSLOG_BUFSIZ == "XTOSTR(SYSLOG_BUFSIZ)"\n",
  85. _syslog_buffer_filled, size);
  86. exit(ENOBUFS);
  87. }
  88. #endif
  89. if (!size)
  90. return 0;
  91. len = vsnprintf (
  92. &_syslog_buffer[_syslog_buffer_filled],
  93. size,
  94. fmt,
  95. args
  96. );
  97. if (len>0) {
  98. _syslog_buffer_filled += len;
  99. if (_syslog_buffer_filled > SYSLOG_BUFSIZ)
  100. _syslog_buffer_filled = SYSLOG_BUFSIZ;
  101. }
  102. return 0;
  103. }
  104. static int syslog_buf(const char *fmt, ...) {
  105. va_list args;
  106. int rc;
  107. va_start(args, fmt);
  108. rc = vsyslog_buf(fmt, args);
  109. va_end(args);
  110. return rc;
  111. }
  112. static void syslog_flush(int level) {
  113. syslog(level, "%s", _syslog_buffer);
  114. _syslog_buffer_filled = 0;
  115. }
  116. typedef int *( *outfunct_t)(const char *format, ...);
  117. typedef int *( *voutfunct_t)(const char *format, va_list ap);
  118. typedef void *(*flushfunct_t)(int level);
  119. static outfunct_t outfunct[] = {
  120. [OM_STDERR] = (outfunct_t)printf_stderr,
  121. [OM_STDOUT] = (outfunct_t)printf_stdout,
  122. [OM_SYSLOG] = (outfunct_t)syslog_buf,
  123. };
  124. static voutfunct_t voutfunct[] = {
  125. [OM_STDERR] = (voutfunct_t)vprintf_stderr,
  126. [OM_STDOUT] = (voutfunct_t)vprintf_stdout,
  127. [OM_SYSLOG] = (voutfunct_t)vsyslog_buf,
  128. };
  129. static flushfunct_t flushfunct[] = {
  130. [OM_STDERR] = (flushfunct_t)flush_stderr,
  131. [OM_STDOUT] = (flushfunct_t)flush_stdout,
  132. [OM_SYSLOG] = (flushfunct_t)syslog_flush,
  133. };
  134. void _critical(const char *const function_name, const char *fmt, ...) {
  135. if (*quiet)
  136. return;
  137. struct timespec abs_time;
  138. clock_gettime(CLOCK_REALTIME , &abs_time);
  139. abs_time.tv_sec += 1;
  140. if (error_mutex_p != NULL)
  141. pthread_mutex_timedlock(error_mutex_p, &abs_time);
  142. outputmethod_t method = *outputmethod;
  143. {
  144. va_list args;
  145. pthread_t thread = pthread_self();
  146. pid_t pid = getpid();
  147. outfunct[method]("Critical (pid: %u; thread: %p): %s(): ", pid, thread, function_name);
  148. va_start(args, fmt);
  149. voutfunct[method](fmt, args);
  150. va_end(args);
  151. outfunct[method](" (current errno %i: %s)", errno, strerror(errno));
  152. flushfunct[method](LOG_CRIT);
  153. }
  154. #ifdef BACKTRACE_SUPPORT
  155. {
  156. void *buf[BACKTRACE_LENGTH];
  157. char **strings;
  158. int backtrace_len = backtrace((void **)buf, BACKTRACE_LENGTH);
  159. strings = backtrace_symbols(buf, backtrace_len);
  160. if (strings == NULL) {
  161. outfunct[method]("_critical(): Got error, but cannot print the backtrace. Current errno: %u: %s\n",
  162. errno, strerror(errno));
  163. flushfunct[method](LOG_CRIT);
  164. pthread_mutex_unlock(error_mutex_p);
  165. exit(EXIT_FAILURE);
  166. }
  167. for (int j = 1; j < backtrace_len; j++) {
  168. outfunct[method](" %s", strings[j]);
  169. flushfunct[method](LOG_CRIT);
  170. }
  171. }
  172. #endif
  173. if (error_mutex_p != NULL)
  174. pthread_mutex_unlock(error_mutex_p);
  175. error_deinit();
  176. exit(errno);
  177. return;
  178. }
  179. void _error(const char *const function_name, const char *fmt, ...) {
  180. va_list args;
  181. if (*quiet)
  182. return;
  183. if (*verbose < 1)
  184. return;
  185. if (error_mutex_p != NULL)
  186. pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
  187. pthread_t thread = pthread_self();
  188. pid_t pid = getpid();
  189. outputmethod_t method = *outputmethod;
  190. outfunct[method](*debug ? "Error (pid: %u; thread: %p): %s(): " : "Error: ", pid, thread, function_name);
  191. va_start(args, fmt);
  192. voutfunct[method](fmt, args);
  193. va_end(args);
  194. if (errno)
  195. outfunct[method](" (%i: %s)", errno, strerror(errno));
  196. flushfunct[method](LOG_ERR);
  197. if (error_mutex_p != NULL)
  198. pthread_mutex_unlock(error_mutex_p);
  199. return;
  200. }
  201. void _info(const char *const function_name, const char *fmt, ...) {
  202. va_list args;
  203. if (*quiet)
  204. return;
  205. if (*verbose < 3)
  206. return;
  207. if (error_mutex_p != NULL)
  208. pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
  209. pthread_t thread = pthread_self();
  210. pid_t pid = getpid();
  211. outputmethod_t method = *outputmethod;
  212. outfunct[method](*debug ? "Info (pid: %u; thread: %p): %s(): " : "Info: ", pid, thread, function_name);
  213. va_start(args, fmt);
  214. voutfunct[method](fmt, args);
  215. va_end(args);
  216. flushfunct[method](LOG_INFO);
  217. if (error_mutex_p != NULL)
  218. pthread_mutex_unlock(error_mutex_p);
  219. return;
  220. }
  221. void _warning(const char *const function_name, const char *fmt, ...) {
  222. va_list args;
  223. if (*quiet)
  224. return;
  225. if (*verbose < 2)
  226. return;
  227. if (error_mutex_p != NULL)
  228. pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
  229. pthread_t thread = pthread_self();
  230. pid_t pid = getpid();
  231. outputmethod_t method = *outputmethod;
  232. outfunct[method](*debug ? "Warning (pid: %u; thread: %p): %s(): " : "Warning: ", pid, thread, function_name);
  233. va_start(args, fmt);
  234. voutfunct[method](fmt, args);
  235. va_end(args);
  236. flushfunct[method](LOG_WARNING);
  237. if (error_mutex_p != NULL)
  238. pthread_mutex_unlock(error_mutex_p);
  239. return;
  240. }
  241. #ifdef _DEBUG_SUPPORT
  242. void _debug(int debug_level, const char *const function_name, const char *fmt, ...) {
  243. va_list args;
  244. if (*quiet)
  245. return;
  246. if (debug_level > *debug)
  247. return;
  248. if (error_mutex_p != NULL)
  249. pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
  250. pthread_t thread = pthread_self();
  251. pid_t pid = getpid();
  252. outputmethod_t method = *outputmethod;
  253. outfunct[method]("Debug%u (pid: %u; thread: %p): %s(): ", debug_level, pid, thread, function_name);
  254. va_start(args, fmt);
  255. voutfunct[method](fmt, args);
  256. va_end(args);
  257. flushfunct[method](LOG_DEBUG);
  258. if (error_mutex_p != NULL)
  259. pthread_mutex_unlock(error_mutex_p);
  260. return;
  261. }
  262. #endif
  263. void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug) {
  264. outputmethod = _outputmethod;
  265. quiet = _quiet;
  266. verbose = _verbose;
  267. debug = _debug;
  268. openlog(NULL, SYSLOG_FLAGS, SYSLOG_FACILITY);
  269. return;
  270. }
  271. ipc_type_t ipc_type;
  272. void error_init_ipc(ipc_type_t _ipc_type) {
  273. static pthread_mutex_t error_mutex = PTHREAD_MUTEX_INITIALIZER;
  274. ipc_type = _ipc_type;
  275. switch (ipc_type) {
  276. case IPCT_PRIVATE:
  277. error_mutex_p = &error_mutex;
  278. pthread_mutex_init(error_mutex_p, NULL);
  279. break;
  280. default:
  281. critical ("Unknown ipc_type: %i", ipc_type);
  282. }
  283. return;
  284. }
  285. void error_deinit() {
  286. switch (ipc_type) {
  287. case IPCT_PRIVATE:
  288. break;
  289. default:
  290. critical ("Unknown ipc_type: %i", ipc_type);
  291. }
  292. return;
  293. }