clsync
error.c
Go to the documentation of this file.
1 /*
2  clsync - file tree sync utility based on inotify/kqueue
3 
4  Copyright (C) 2013-2014 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /*
21  * This file implements way to output debugging information. It's supposed
22  * to be slow but convenient functions.
23  */
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <syslog.h>
31 #include <pthread.h> /* pthread_self() */
32 #include <sys/types.h> /* getpid() */
33 #include <unistd.h> /* getpid() */
34 
35 #include "macros.h"
36 #include "configuration.h"
37 
38 #include "error.h"
39 #include "pthreadex.h" /* pthread_*_shared() */
40 
41 #ifdef BACKTRACE_SUPPORT
42 #include <execinfo.h>
43 #endif
44 
45 static int zero = 0;
46 static int three = 3;
47 
48 static int *outputmethod = &zero;
49 static int *debug = &zero;
50 static int *quiet = &zero;
51 static int *verbose = &three;
52 
53 pthread_mutex_t *error_mutex_p = NULL;
54 
55 static int printf_stderr ( const char *fmt, ... )
56 {
57  va_list args;
58  int rc;
59  va_start ( args, fmt );
60  rc = vfprintf ( stderr, fmt, args );
61  va_end ( args );
62  return rc;
63 }
64 
65 static int printf_stdout ( const char *fmt, ... )
66 {
67  va_list args;
68  int rc;
69  va_start ( args, fmt );
70  rc = vfprintf ( stdout, fmt, args );
71  va_end ( args );
72  return rc;
73 }
74 
75 static int vprintf_stderr ( const char *fmt, va_list args )
76 {
77  return vfprintf ( stderr, fmt, args );
78 }
79 
80 static int vprintf_stdout ( const char *fmt, va_list args )
81 {
82  return vfprintf ( stdout, fmt, args );
83 }
84 
85 
86 static void flush_stderr ( int level )
87 {
88  ( void ) level;
89  fprintf ( stderr, "\n" );
90  fflush ( stderr );
91 }
92 
93 static void flush_stdout ( int level )
94 {
95  ( void ) level;
96  fprintf ( stdout, "\n" );
97  fflush ( stdout );
98 }
99 
100 
101 static char _syslog_buffer[SYSLOG_BUFSIZ + 1] = {0};
103 
104 static int vsyslog_buf ( const char *fmt, va_list args )
105 {
106  int len;
107  size_t size;
109 #ifdef VERYPARANOID
110 
111  if (
112  ( size > SYSLOG_BUFSIZ ) ||
113  ( _syslog_buffer_filled + size > SYSLOG_BUFSIZ ) ||
115  ) {
116  fprintf ( stderr, "Security problem while vsyslog_buf(): "
117  "_syslog_buffer_filled == %lu; "
118  "size == %lu; "
119  "SYSLOG_BUFSIZ == "XTOSTR ( SYSLOG_BUFSIZ ) "\n",
120  _syslog_buffer_filled, size );
121  exit ( ENOBUFS );
122  }
123 
124 #endif
125 
126  if ( !size )
127  return 0;
128 
129  len = vsnprintf (
131  size,
132  fmt,
133  args
134  );
135 
136  if ( len > 0 ) {
137  _syslog_buffer_filled += len;
138 
141  }
142 
143  return 0;
144 }
145 
146 static int syslog_buf ( const char *fmt, ... )
147 {
148  va_list args;
149  int rc;
150  va_start ( args, fmt );
151  rc = vsyslog_buf ( fmt, args );
152  va_end ( args );
153  return rc;
154 }
155 
156 static void syslog_flush ( int level )
157 {
158  syslog ( level, "%s", _syslog_buffer );
160 }
161 
162 typedef int ( *outfunct_t ) ( const char *format, ... );
163 typedef int ( *voutfunct_t ) ( const char *format, va_list ap );
164 typedef void ( *flushfunct_t ) ( int level );
165 
166 static outfunct_t outfunct[] = {
170 };
171 
172 static voutfunct_t voutfunct[] = {
176 };
177 
182 };
183 
184 void _critical ( const char *const function_name, const char *fmt, ... )
185 {
186  if ( *quiet )
187  return;
188 
189  struct timespec abs_time;
190  clock_gettime ( CLOCK_REALTIME, &abs_time );
191  abs_time.tv_sec += 1;
192 
193  if ( error_mutex_p != NULL )
194  pthread_mutex_timedlock ( error_mutex_p, &abs_time );
195 
196  outputmethod_t method = *outputmethod;
197  {
198  va_list args;
199  pthread_t thread = pthread_self();
200  pid_t pid = getpid();
201  outfunct[method] ( "Critical (pid: %u; thread: %p): %s(): ", pid, thread, function_name );
202  va_start ( args, fmt );
203  voutfunct[method] ( fmt, args );
204  va_end ( args );
205  outfunct[method] ( " (current errno %i: %s)", errno, strerror ( errno ) );
206  flushfunct[method] ( LOG_CRIT );
207  }
208 #ifdef BACKTRACE_SUPPORT
209  {
210  void *buf[BACKTRACE_LENGTH];
211  char **strings;
212  int backtrace_len = backtrace ( ( void ** ) buf, BACKTRACE_LENGTH );
213  strings = backtrace_symbols ( buf, backtrace_len );
214 
215  if ( strings == NULL ) {
216  outfunct[method] ( "_critical(): Got error, but cannot print the backtrace. Current errno: %u: %s\n",
217  errno, strerror ( errno ) );
218  flushfunct[method] ( LOG_CRIT );
219  pthread_mutex_unlock ( error_mutex_p );
220  exit ( EXIT_FAILURE );
221  }
222 
223  for ( int j = 1; j < backtrace_len; j++ ) {
224  outfunct[method] ( " %s", strings[j] );
225  flushfunct[method] ( LOG_CRIT );
226  }
227  }
228 #endif
229 
230  if ( error_mutex_p != NULL )
231  pthread_mutex_unlock ( error_mutex_p );
232 
233  error_deinit();
234  exit ( errno );
235  return;
236 }
237 
238 void _error ( const char *const function_name, const char *fmt, ... )
239 {
240  va_list args;
241 
242  if ( *quiet )
243  return;
244 
245  if ( *verbose < 1 )
246  return;
247 
248  if ( error_mutex_p != NULL )
250 
251  pthread_t thread = pthread_self();
252  pid_t pid = getpid();
253  outputmethod_t method = *outputmethod;
254  outfunct[method] ( *debug ? "Error (pid: %u; thread: %p): %s(): " : "Error: ", pid, thread, function_name );
255  va_start ( args, fmt );
256  voutfunct[method] ( fmt, args );
257  va_end ( args );
258 
259  if ( errno )
260  outfunct[method] ( " (%i: %s)", errno, strerror ( errno ) );
261 
262  flushfunct[method] ( LOG_ERR );
263 
264  if ( error_mutex_p != NULL )
265  pthread_mutex_unlock ( error_mutex_p );
266 
267  return;
268 }
269 
270 void _info ( const char *const function_name, const char *fmt, ... )
271 {
272  va_list args;
273 
274  if ( *quiet )
275  return;
276 
277  if ( *verbose < 3 )
278  return;
279 
280  if ( error_mutex_p != NULL )
282 
283  pthread_t thread = pthread_self();
284  pid_t pid = getpid();
285  outputmethod_t method = *outputmethod;
286  outfunct[method] ( *debug ? "Info (pid: %u; thread: %p): %s(): " : "Info: ", pid, thread, function_name );
287  va_start ( args, fmt );
288  voutfunct[method] ( fmt, args );
289  va_end ( args );
290  flushfunct[method] ( LOG_INFO );
291 
292  if ( error_mutex_p != NULL )
293  pthread_mutex_unlock ( error_mutex_p );
294 
295  return;
296 }
297 
298 void _warning ( const char *const function_name, const char *fmt, ... )
299 {
300  va_list args;
301 
302  if ( *quiet )
303  return;
304 
305  if ( *verbose < 2 )
306  return;
307 
308  if ( error_mutex_p != NULL )
310 
311  pthread_t thread = pthread_self();
312  pid_t pid = getpid();
313  outputmethod_t method = *outputmethod;
314  outfunct[method] ( *debug ? "Warning (pid: %u; thread: %p): %s(): " : "Warning: ", pid, thread, function_name );
315  va_start ( args, fmt );
316  voutfunct[method] ( fmt, args );
317  va_end ( args );
318  flushfunct[method] ( LOG_WARNING );
319 
320  if ( error_mutex_p != NULL )
321  pthread_mutex_unlock ( error_mutex_p );
322 
323  return;
324 }
325 
326 #ifdef _DEBUG_SUPPORT
327 void _debug ( int debug_level, const char *const function_name, const char *fmt, ... )
328 {
329  va_list args;
330 
331  if ( *quiet )
332  return;
333 
334  if ( debug_level > *debug )
335  return;
336 
337  if ( error_mutex_p != NULL )
339 
340  pthread_t thread = pthread_self();
341  pid_t pid = getpid();
342  outputmethod_t method = *outputmethod;
343  outfunct[method] ( "Debug%u (pid: %u; thread: %p): %s(): ", debug_level, pid, thread, function_name );
344  va_start ( args, fmt );
345  voutfunct[method] ( fmt, args );
346  va_end ( args );
347  flushfunct[method] ( LOG_DEBUG );
348 
349  if ( error_mutex_p != NULL )
350  pthread_mutex_unlock ( error_mutex_p );
351 
352  return;
353 }
354 #endif
355 
356 void error_init ( void *_outputmethod, int *_quiet, int *_verbose, int *_debug )
357 {
358  outputmethod = _outputmethod;
359  quiet = _quiet;
360  verbose = _verbose;
361  debug = _debug;
362  openlog ( NULL, SYSLOG_FLAGS, SYSLOG_FACILITY );
363  return;
364 }
365 
367 void error_init_ipc ( ipc_type_t _ipc_type )
368 {
369  static pthread_mutex_t error_mutex = PTHREAD_MUTEX_INITIALIZER;
370  ipc_type = _ipc_type;
371 
372  switch ( ipc_type ) {
373  case IPCT_SHARED:
375  break;
376 
377  case IPCT_PRIVATE:
378  error_mutex_p = &error_mutex;
379  pthread_mutex_init ( error_mutex_p, NULL );
380  break;
381 
382  default:
383  critical ( "Unknown ipc_type: %i", ipc_type );
384  }
385 
386  return;
387 }
388 
390 {
391  switch ( ipc_type ) {
392  case IPCT_SHARED:
394  error_mutex_p = NULL;
395  break;
396 
397  case IPCT_PRIVATE:
398  break;
399  }
400 
401  return;
402 }
403 
IPCT_PRIVATE
@ IPCT_PRIVATE
Definition: error.h:60
outfunct_t
int(* outfunct_t)(const char *format,...)
Definition: error.c:162
debug
static int * debug
Definition: error.c:49
error_init
void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug)
Definition: error.c:356
voutfunct
static voutfunct_t voutfunct[]
Definition: error.c:172
zero
static int zero
Definition: error.c:45
_warning
void _warning(const char *const function_name, const char *fmt,...)
Definition: error.c:298
_error
void _error(const char *const function_name, const char *fmt,...)
Definition: error.c:238
printf_stderr
static int printf_stderr(const char *fmt,...)
Definition: error.c:55
three
static int three
Definition: error.c:46
error_deinit
void error_deinit()
Definition: error.c:389
outputmethod
outputmethod
Definition: error.h:69
BACKTRACE_LENGTH
#define BACKTRACE_LENGTH
Definition: error.h:23
SYSLOG_FLAGS
#define SYSLOG_FLAGS
Definition: configuration.h:156
OM_SYSLOG
@ OM_SYSLOG
Definition: error.h:72
ipc_type
ipc_type
Definition: error.h:59
macros.h
quiet
static int * quiet
Definition: error.c:50
flushfunct_t
void(* flushfunct_t)(int level)
Definition: error.c:164
printf_stdout
static int printf_stdout(const char *fmt,...)
Definition: error.c:65
vsyslog_buf
static int vsyslog_buf(const char *fmt, va_list args)
Definition: error.c:104
pthreadex.h
_syslog_buffer_filled
size_t _syslog_buffer_filled
Definition: error.c:102
IPCT_SHARED
@ IPCT_SHARED
Definition: error.h:61
pthread_mutex_destroy_shared
int pthread_mutex_destroy_shared(pthread_mutex_t *mutex_p)
Definition: pthreadex.c:36
_critical
void _critical(const char *const function_name, const char *fmt,...)
Definition: error.c:184
error.h
pthread_mutex_init_shared
int pthread_mutex_init_shared(pthread_mutex_t **mutex_p)
Definition: pthreadex.c:25
flush_stderr
static void flush_stderr(int level)
Definition: error.c:86
SYSLOG_BUFSIZ
#define SYSLOG_BUFSIZ
Definition: configuration.h:155
error_init_ipc
void error_init_ipc(ipc_type_t _ipc_type)
Definition: error.c:367
verbose
static int * verbose
Definition: error.c:51
syslog_buf
static int syslog_buf(const char *fmt,...)
Definition: error.c:146
OUTPUT_LOCK_TIMEOUT
#define OUTPUT_LOCK_TIMEOUT
Definition: configuration.h:241
_syslog_buffer
static char _syslog_buffer[(1<< 16)+1]
Definition: error.c:101
error_mutex_p
pthread_mutex_t * error_mutex_p
Definition: error.c:53
outfunct
static outfunct_t outfunct[]
Definition: error.c:166
XTOSTR
#define XTOSTR(a)
Definition: macros.h:45
critical
#define critical(...)
Definition: error.h:32
OM_STDOUT
@ OM_STDOUT
Definition: error.h:71
pthread_mutex_reltimedlock
int pthread_mutex_reltimedlock(pthread_mutex_t *mutex_p, long tv_sec, long tv_nsec)
Definition: pthreadex.c:63
outputmethod_t
enum outputmethod outputmethod_t
Definition: error.h:76
configuration.h
flushfunct
static flushfunct_t flushfunct[]
Definition: error.c:178
vprintf_stdout
static int vprintf_stdout(const char *fmt, va_list args)
Definition: error.c:80
syslog_flush
static void syslog_flush(int level)
Definition: error.c:156
outputmethod
static int * outputmethod
Definition: error.c:48
vprintf_stderr
static int vprintf_stderr(const char *fmt, va_list args)
Definition: error.c:75
_info
void _info(const char *const function_name, const char *fmt,...)
Definition: error.c:270
voutfunct_t
int(* voutfunct_t)(const char *format, va_list ap)
Definition: error.c:163
OM_STDERR
@ OM_STDERR
Definition: error.h:70
flush_stdout
static void flush_stdout(int level)
Definition: error.c:93
ipc_type_t
enum ipc_type ipc_type_t
Definition: error.h:63
ipc_type
ipc_type_t ipc_type
Definition: error.c:366
SYSLOG_FACILITY
#define SYSLOG_FACILITY
Definition: configuration.h:157