~ubuntu-branches/ubuntu/karmic/libzorpll/karmic-proposed

« back to all changes in this revision

Viewing changes to src/log.c

  • Committer: Bazaar Package Importer
  • Author(s): Magosányi Árpád (mag)
  • Date: 2004-07-25 11:40:41 UTC
  • Revision ID: james.westby@ubuntu.com-20040725114041-s3eqjb975e4j3q0x
Tags: upstream-2.0.26.24
Import upstream version 2.0.26.24

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *
 
3
 * Copyright (c) 2000,2001,2002 BalaBit IT Ltd, Budapest, Hungary
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 *
 
19
 * $Id: log.c,v 1.40.2.8 2003/09/16 19:40:28 sasa Exp $
 
20
 *
 
21
 * Author  : Bazsi
 
22
 * Auditor : kisza
 
23
 * Last audited version: 1.7
 
24
 * Notes:
 
25
 *
 
26
 ***************************************************************************/
 
27
 
 
28
#include <zorp/log.h>
 
29
#include <zorp/thread.h>
 
30
#include <zorp/error.h>
 
31
 
 
32
#include <stdarg.h>
 
33
#include <stdio.h>
 
34
#include <fcntl.h>
 
35
#ifdef HAVE_UNISTD_H
 
36
  #include <unistd.h>
 
37
#endif
 
38
#include <string.h>
 
39
#include <ctype.h>
 
40
#include <stdlib.h>
 
41
#include <sys/types.h>
 
42
#ifdef HAVE_SYS_TIME_H
 
43
  #include <sys/time.h>
 
44
#endif
 
45
#include <time.h>
 
46
 
 
47
#ifdef G_OS_WIN32
 
48
#  include <windef.h>
 
49
#  include <winbase.h>
 
50
#else
 
51
#  include <sys/socket.h>
 
52
#  include <sys/un.h>
 
53
#endif
 
54
 
 
55
#undef G_LOG_DOMAIN
 
56
#define G_LOG_DOMAIN "Zorp"
 
57
 
 
58
#define SYSLOG_SOCKET "/dev/log"
 
59
 
 
60
GHashTable *class_hash = NULL;
 
61
GStaticRWLock log_lock = G_STATIC_RW_LOCK_INIT;
 
62
unsigned int verbose_level = 3;
 
63
unsigned int log_tags = 0;
 
64
gchar *logspec = NULL;
 
65
gchar *syslog_tag = NULL;
 
66
unsigned int syslog_fd = -1;
 
67
gboolean stderr_syslog = FALSE;
 
68
 
 
69
gchar fake_session_id[256] = "noname/nosession";
 
70
 
 
71
static GMainContext *context = NULL;
 
72
 
 
73
#ifndef G_OS_WIN32
 
74
/*
 
75
 * This is a private reimplementation of syslog() as that one had a
 
76
 * mysterious bug in it and my bug reports were ignored.
 
77
 */
 
78
 
 
79
/**
 
80
 * z_open_syslog:
 
81
 * @tag: program name used in log messages
 
82
 *
 
83
 * Analogous to openlog(), open the syslog() connection to local syslogd. 
 
84
 *
 
85
 * Returns: whether
 
86
 **/
 
87
gboolean
 
88
z_open_syslog(gchar *tag)
 
89
{
 
90
  struct sockaddr_un s_un;
 
91
  
 
92
  syslog_tag = tag;
 
93
  syslog_fd = socket(AF_UNIX, SOCK_STREAM, 0);
 
94
  
 
95
  if (syslog_fd == -1)
 
96
    {
 
97
      return FALSE;
 
98
    }
 
99
  
 
100
  s_un.sun_family = AF_UNIX;
 
101
  strcpy(s_un.sun_path, SYSLOG_SOCKET);
 
102
  if (connect(syslog_fd, (struct sockaddr *) &s_un, sizeof(s_un)) == -1)
 
103
    {
 
104
      close(syslog_fd);
 
105
      syslog_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
 
106
      if (connect(syslog_fd, (struct sockaddr *) &s_un, sizeof(s_un)) == -1)
 
107
        {
 
108
          close(syslog_fd);
 
109
          syslog_fd = -1;
 
110
          return FALSE;
 
111
        }
 
112
    }
 
113
  return TRUE;
 
114
}
 
115
 
 
116
/**
 
117
 * z_close_syslog:
 
118
 * @syslog_fd: syslog connection to close
 
119
 *
 
120
 * Close the connection to the local syslogd. The syslog connection is
 
121
 * specified by the @syslog_fd argument to avoid races.
 
122
 * 
 
123
 * Returns: whether the operation was succesful
 
124
 **/
 
125
gboolean
 
126
z_close_syslog(int syslog_fd)
 
127
{
 
128
  if (syslog_fd != -1)
 
129
    {
 
130
      close(syslog_fd);
 
131
      return TRUE;
 
132
    }
 
133
  return FALSE;
 
134
}
 
135
 
 
136
/**
 
137
 * z_send_syslog:
 
138
 * @pri: syslog priority 
 
139
 * @msg: syslog message
 
140
 *
 
141
 * Send the specified message to syslog.
 
142
 **/
 
143
gboolean
 
144
z_send_syslog(gint pri, const gchar *msg)
 
145
{
 
146
  gchar buf[1024];
 
147
  gchar timestamp[32];
 
148
  time_t now;
 
149
  struct tm t;
 
150
  gint len, rc = 0, attempt = 0;
 
151
  int sfd = syslog_fd;
 
152
  static GStaticMutex lock = G_STATIC_MUTEX_INIT;
 
153
  
 
154
  now = time(NULL);
 
155
  localtime_r(&now, &t);
 
156
  
 
157
  strftime(timestamp, sizeof(timestamp), "%h %e %H:%M:%S", &t);
 
158
  
 
159
  g_snprintf(buf, sizeof(buf), "<%d>%s %s[%d]: %s\n", pri, timestamp, syslog_tag, (int) getpid(), msg);
 
160
  len = strlen(buf) + 1;
 
161
  do
 
162
    {
 
163
      attempt++;
 
164
      if (sfd != -1)
 
165
        rc = write(sfd, buf, len);
 
166
      if (sfd == -1 || (rc == -1 && errno != EINTR && errno != EAGAIN))
 
167
        {
 
168
          g_static_mutex_lock(&lock);
 
169
          if (sfd == syslog_fd)
 
170
            {
 
171
              z_open_syslog(syslog_tag);
 
172
              z_close_syslog(sfd);
 
173
            }
 
174
            
 
175
          sfd = syslog_fd;
 
176
          g_static_mutex_unlock(&lock);
 
177
        }
 
178
    }    
 
179
  while (rc == -1 && attempt <= 1);
 
180
  return TRUE;
 
181
}
 
182
#else
 
183
 
 
184
gboolean
 
185
z_close_syslog(int syslog_fd)
 
186
{
 
187
  return TRUE;
 
188
}
 
189
 
 
190
#endif
 
191
 
 
192
/**
 
193
 * z_log_enabled:
 
194
 * @class: log message class
 
195
 * @level: log message level
 
196
 *
 
197
 * Checks if a message with a given class/level combination would actually
 
198
 * be written to the log. It can be used prior to constructing complex log
 
199
 * messages to decide whether the messages need to be constucted at all.
 
200
 * All results are cached, thus the second invocation will not parse the 
 
201
 * log specifications again.
 
202
 *
 
203
 * Returns: TRUE if the log would be written, FALSE otherwise
 
204
 **/
 
205
gboolean
 
206
z_log_enabled(gchar *class, int level)
 
207
{
 
208
  gint verbose;
 
209
 
 
210
  g_static_rw_lock_reader_lock(&log_lock);
 
211
  if (!class_hash)
 
212
    {
 
213
      g_static_rw_lock_reader_unlock(&log_lock);
 
214
      return TRUE;
 
215
    }
 
216
  verbose = GPOINTER_TO_UINT(g_hash_table_lookup(class_hash, class));
 
217
  g_static_rw_lock_reader_unlock(&log_lock);
 
218
  if (!verbose)
 
219
    {
 
220
      verbose = z_log_register_class(class);
 
221
      if (verbose >= 0)
 
222
        {
 
223
          g_static_rw_lock_writer_lock(&log_lock);
 
224
          g_hash_table_insert(class_hash, class, GUINT_TO_POINTER(verbose + 1));
 
225
          g_static_rw_lock_writer_unlock(&log_lock);
 
226
        }
 
227
      else
 
228
        {
 
229
          g_log(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "Invalid syntax in logspec line, class=%s", class);
 
230
          /* hack to let this message out */
 
231
#ifdef G_OS_WIN32
 
232
          Sleep(1000);
 
233
#else
 
234
          sleep(1);
 
235
#endif
 
236
          exit(1);
 
237
        }
 
238
    }
 
239
  else
 
240
    verbose--;
 
241
  
 
242
  return (level <= verbose);
 
243
}
 
244
 
 
245
/**
 
246
 * z_logv:
 
247
 * @class: log message class
 
248
 * @level: log message verbosity level
 
249
 * @format: log message format specified in printf form
 
250
 * @ap: format arguments va_list
 
251
 *
 
252
 * This function sends a message formatted as printf format string and
 
253
 * arguments to the syslog. The associated class/level pair is checked
 
254
 * whether the message really needs to be written.
 
255
 **/
 
256
void
 
257
z_logv(gchar *class, int level, gchar *format, va_list ap)
 
258
{
 
259
  int saved_errno = errno;
 
260
  
 
261
  if (z_log_enabled(class, level))
 
262
    {
 
263
      if (log_tags)
 
264
        {
 
265
          gchar msgbuf[2048];
 
266
          g_vsnprintf(msgbuf, sizeof(msgbuf), format, ap);
 
267
 
 
268
#if ZORPLIB_ENABLE_TRACE
 
269
          g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%p -> %s(%d): %s", g_thread_self(), class, level, msgbuf);
 
270
#else
 
271
          g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%s(%d): %s", class, level, msgbuf);
 
272
#endif
 
273
        }
 
274
      else
 
275
        {
 
276
          g_logv(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format, ap);
 
277
        }
 
278
    }
 
279
  errno = saved_errno;
 
280
}
 
281
 
 
282
/**
 
283
 * z_llog:
 
284
 * @class: log message class
 
285
 * @level: log message verbosity level
 
286
 * @format: log message format specified in printf form
 
287
 *
 
288
 * This message is the same as z_logv() but format string and arguments
 
289
 * are specified directly.
 
290
 **/
 
291
void
 
292
z_llog(gchar *class, int level, gchar *format, ...)
 
293
{
 
294
  va_list l;
 
295
 
 
296
  va_start(l, format);
 
297
  z_logv(class, level, format, l);
 
298
  va_end(l);
 
299
}
 
300
 
 
301
#ifdef G_OS_WIN32
 
302
 
 
303
void z_log(gchar* session_id, gchar* class, int level, gchar* format, ...)
 
304
{
 
305
  va_list l;
 
306
  gchar msgbuf[2048];
 
307
 
 
308
  va_start(l, format);
 
309
 
 
310
  g_vsnprintf(msgbuf, sizeof(msgbuf), format, l);
 
311
 
 
312
  g_log(G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%p -> %s(%d): %s", g_thread_self(), class, level, msgbuf);
 
313
/*
 
314
  if (session_id == NULL || *((char *) session_id) == 0)
 
315
    z_llog(class, level, "(%s %s): ", format, z_log_session_id(session_id) , l);
 
316
  else
 
317
    z_llog(class, level, "(%s %s): ", format, (char *) session_id , l);
 
318
*/
 
319
  va_end(l);
 
320
}
 
321
/*
 
322
void z_proxy_log(ZProxy *self, gchar* class, int level, char* format, ...)
 
323
{
 
324
  va_list l;
 
325
  va_start(l, format);
 
326
 
 
327
  z_log(((ZProxy *)self)->session_id, class, level, format,  l)
 
328
 
 
329
  va_end(l);
 
330
}
 
331
*/
 
332
#endif
 
333
 
 
334
#ifndef G_OS_WIN32
 
335
/**
 
336
 * z_log_func:
 
337
 * @log_domain: GLIB log domain
 
338
 * @log_flags: GLIB log flags
 
339
 * @message: message
 
340
 * @user_data: not used 
 
341
 *
 
342
 * This function is registered as a GLib log handler and sends all GLIB
 
343
 * messages to messages to syslog. Zorp itself does not use GLIB logging
 
344
 * it calls z_log() directly.
 
345
 **/
 
346
static void
 
347
z_log_func(const gchar *log_domain,
 
348
           GLogLevelFlags log_flags,
 
349
           const gchar *message,
 
350
           gpointer user_data)
 
351
{
 
352
  int pri = LOG_INFO;
 
353
  if (log_flags & G_LOG_LEVEL_DEBUG)
 
354
    pri = LOG_DEBUG;
 
355
  else if (log_flags & G_LOG_LEVEL_WARNING)
 
356
    pri = LOG_WARNING;
 
357
  else if (log_flags & G_LOG_LEVEL_ERROR)
 
358
    pri = LOG_ERR;
 
359
 
 
360
  z_send_syslog(pri | ZORP_SYSLOG_FACILITY, message);
 
361
}
 
362
 
 
363
#else
 
364
 
 
365
/*+ log handler function to send Win32 debug message +*/
 
366
static void
 
367
z_log_win32_debugmsg(const gchar *log_domain,
 
368
                 GLogLevelFlags  log_flags,
 
369
                    const gchar *message,
 
370
                       gpointer  user_data)
 
371
{
 
372
  OutputDebugString(message);
 
373
  OutputDebugString("\n");
 
374
}
 
375
 
 
376
#endif
 
377
 
 
378
/**
 
379
 * z_fetch_stderr:
 
380
 * @channel: the read end of the STDERR pipe
 
381
 * @condition: the I/O condition triggering this callback
 
382
 * @arg: not used
 
383
 *
 
384
 * This function is registered as a read callback of the STDERR pipe to 
 
385
 * fetch messages sent to stderr. It fetches messages line-by-line and
 
386
 * uses z_log() to send messages to log.
 
387
 *
 
388
 * Returns: TRUE to indicate further reading is needed, FALSE otherwise
 
389
 **/
 
390
gboolean
 
391
z_fetch_stderr(GIOChannel *channel, GIOCondition condition, gpointer arg)
 
392
{
 
393
  gchar *line = NULL;
 
394
  GIOStatus status = G_IO_STATUS_NORMAL;
 
395
  GError *err = NULL;
 
396
 
 
397
  status = g_io_channel_read_line(channel, &line, NULL, NULL, &err);
 
398
  
 
399
  switch (status)
 
400
    {
 
401
    case G_IO_STATUS_NORMAL:
 
402
      z_log(NULL, CORE_STDERR, 3, "%s", line);
 
403
      break;
 
404
    case G_IO_STATUS_AGAIN:
 
405
      break;
 
406
    case G_IO_STATUS_EOF:
 
407
      /*LOG
 
408
        This message arrive when a program using Zorp library
 
409
        closing his stderr.
 
410
       */
 
411
      z_log(NULL, CORE_STDERR, 4, "The program close its stderr. No further stderr logging will be performed.");
 
412
      return FALSE;
 
413
    default:
 
414
      /*LOG
 
415
        This message is attempt when zorplib cannot read from
 
416
        program stderr stream.
 
417
       */
 
418
      z_log(NULL, CORE_STDERR, 3, "Cannot read from stderr; result='%s'", (err != NULL) ? ((err)->message) : ("Unknown error"));
 
419
      return FALSE;
 
420
    }
 
421
  g_free(line);
 
422
  return TRUE;
 
423
}
 
424
 
 
425
/**
 
426
 * z_log_source_new:
 
427
 * @fd: read side of the stderr pipe
 
428
 *
 
429
 * Creates the source watching the stderr pipe.
 
430
 **/
 
431
void
 
432
z_log_source_new(gint fd)
 
433
{
 
434
  GIOChannel *channel;
 
435
  GSource *source;
 
436
  
 
437
  channel = g_io_channel_unix_new(fd);
 
438
  g_io_channel_set_encoding(channel, NULL, NULL);
 
439
  g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
 
440
  source = g_io_create_watch(channel, G_IO_IN);
 
441
  g_source_set_callback(source, (GSourceFunc) z_fetch_stderr, NULL, NULL);
 
442
  g_source_attach(source, context);
 
443
  g_source_unref(source);
 
444
}
 
445
 
 
446
/**
 
447
 * z_log_glob_match:
 
448
 * @glob: 
 
449
 * @class:
 
450
 *
 
451
 *
 
452
 **/
 
453
static gboolean
 
454
z_log_glob_match(const gchar *glob, const gchar *class)
 
455
{
 
456
  gchar *p1, *p2;
 
457
  gint len1, len2;
 
458
 
 
459
  p1 = strchr(glob, '.');
 
460
  p2 = strchr(class, '.');
 
461
 
 
462
  while (p1 && p2)
 
463
    {
 
464
      len1 = p1 - glob;
 
465
      len2 = p2 - class;
 
466
      if (((len1 != 1) || (memcmp(glob, "*", 1) != 0)) &&
 
467
          ((len1 != len2) || memcmp(glob, class, len1) != 0))
 
468
        return FALSE;
 
469
      glob = p1 + 1;
 
470
      class = p2 + 1;
 
471
 
 
472
      p1 = strchr(glob, '.');
 
473
      p2 = strchr(class, '.');
 
474
    }
 
475
  if (p1)
 
476
    len1 = p1 - glob;
 
477
  else
 
478
    len1 = strlen(glob);
 
479
  if (p2)
 
480
    len2 = p2 - class;
 
481
  else
 
482
    len2 = strlen(class);
 
483
  if (((len1 != 1) || (memcmp(glob, "*", 1) != 0)) &&
 
484
      ((len1 != len2) || memcmp(glob, class, len1) != 0))
 
485
    return FALSE;
 
486
  glob += len1;
 
487
  class += len2;
 
488
  if (strlen(glob) > strlen(class))
 
489
    return FALSE;
 
490
  return TRUE;
 
491
}
 
492
 
 
493
/**
 
494
 * z_log_register_class:
 
495
 * @class: message class 
 
496
 **/
 
497
int
 
498
z_log_register_class(gchar *class)
 
499
{
 
500
  const gchar *src = logspec;
 
501
  gint level = verbose_level, new_level;
 
502
  
 
503
  while (*src)
 
504
    {
 
505
      const gchar *glob, *num;
 
506
      gchar *colon, *end;
 
507
 
 
508
      while (*src == ',' || *src == ' ')
 
509
        src++;
 
510
 
 
511
      glob = src;
 
512
      while (isalnum((guchar) (*src)) || *src == '.' || *src == '*')
 
513
        src++;
 
514
 
 
515
      if (*src != ':')
 
516
        {
 
517
          /* invalid log spec */
 
518
          return -1;
 
519
        }
 
520
      colon = (gchar *) src;
 
521
      src++;
 
522
      num = src;
 
523
 
 
524
      *colon = 0;
 
525
      new_level = strtoul(num, &end, 10);
 
526
      if (z_log_glob_match(glob, class))
 
527
        level = new_level;
 
528
      *colon = ':';
 
529
      src = end;
 
530
      while (*src && *src != ',')
 
531
        src++;
 
532
    }
 
533
  return level;
 
534
}
 
535
 
 
536
/**
 
537
 * z_log_clear_hash:
 
538
 *
 
539
 * Clear the log-spec hash. It is called after changing the verbosity level.
 
540
 * FIXME: this contains a race condition.
 
541
 **/
 
542
void
 
543
z_log_clear_hash()
 
544
{
 
545
  g_static_rw_lock_writer_lock(&log_lock);
 
546
  g_hash_table_destroy(class_hash);
 
547
  class_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
548
  g_static_rw_lock_writer_unlock(&log_lock);
 
549
}
 
550
 
 
551
/**
 
552
 * z_log_session_id:
 
553
 * @session_id: default session_id
 
554
 *
 
555
 * This helper function is used by the z_log() macro to get the current
 
556
 * session id. If the argument is NULL the session_id assigned to the
 
557
 * current thread is used, otherwise the value of the argument is returned.
 
558
 **/
 
559
const gchar *
 
560
z_log_session_id(const gchar *session_id)
 
561
{
 
562
  if (session_id == NULL || session_id[0] == 0)
 
563
    {
 
564
      ZThread *thread = z_thread_self();
 
565
      if (thread == NULL)
 
566
        return fake_session_id;
 
567
      else
 
568
        return thread->name;
 
569
    }
 
570
  return session_id;
 
571
}
 
572
 
 
573
/**
 
574
 * z_log_run:
 
575
 * @user_data: thread data pointer, assumed to point to the stderr fd
 
576
 *
 
577
 * STDERR reading thread function.
 
578
 **/
 
579
void *
 
580
z_log_run(gpointer user_data)
 
581
{
 
582
  GMainContext *c, *old_context;
 
583
  gint *fd = (gint *)user_data;
 
584
  
 
585
  old_context = context = g_main_context_new();
 
586
  g_main_context_acquire(context);
 
587
  z_log_source_new(*fd);
 
588
 
 
589
  do
 
590
    {
 
591
      c = context;
 
592
  
 
593
      if (c)
 
594
        g_main_context_iteration(c, TRUE);
 
595
    }
 
596
  while (c);
 
597
 
 
598
  g_main_context_release(old_context);
 
599
  g_main_context_unref(old_context);
 
600
  return NULL;
 
601
}
 
602
 
 
603
/**
 
604
 * z_log-init:
 
605
 * @ls: log specification
 
606
 * @syslog_name: the program name to appear in syslogs
 
607
 * @flags: log flags (ZLF_* macros)
 
608
 *
 
609
 * Initialize the logging subsystem according to the options
 
610
 * in specified in the @flags parameter.
 
611
 **/
 
612
void
 
613
z_log_init(const gchar *ls, const gchar *syslog_name, guint flags)
 
614
{
 
615
  logspec = (gchar *) (ls ? ls : "");
 
616
  log_tags = !!(flags & ZLF_TAGS);
 
617
  class_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
618
 
 
619
  if (flags & ZLF_SYSLOG)
 
620
    {
 
621
  
 
622
#ifndef G_OS_WIN32
 
623
 
 
624
      static int grab[2];
 
625
      
 
626
      z_open_syslog((char *)syslog_name);
 
627
      g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_func, NULL);
 
628
      
 
629
      if (flags & ZLF_STDERR)
 
630
        {
 
631
          if (pipe(grab) < 0)
 
632
            {
 
633
              /*LOG
 
634
                This message is appear when cannot create
 
635
                pipe. The possible couse is zorp weaok on fd.
 
636
               */
 
637
              z_log(NULL, CORE_ERROR, 3, "Error creating stderr-syslog pipe;");
 
638
              return;
 
639
            }
 
640
          stderr_syslog = TRUE;
 
641
          dup2(grab[1], 1);
 
642
          dup2(grab[1], 2);
 
643
          if (grab[1] != 2 && grab[1] != 1)
 
644
            close(grab[1]);
 
645
          
 
646
          if (~flags & ZLF_THREAD)
 
647
            {
 
648
              context = g_main_context_default();
 
649
              if (!g_main_context_acquire(context))
 
650
                {
 
651
                  context = g_main_context_new();
 
652
                  g_main_context_acquire(context);
 
653
                }
 
654
              g_main_context_ref(context);
 
655
              z_log_source_new(grab[0]);
 
656
            }
 
657
          else
 
658
            z_thread_new("Log thread", z_log_run, &grab[0]);
 
659
        }
 
660
 
 
661
#else
 
662
 
 
663
      g_log_set_handler(G_LOG_DOMAIN, 0xff, z_log_win32_debugmsg, NULL);
 
664
 
 
665
#endif
 
666
    }
 
667
}
 
668
 
 
669
/**
 
670
 * z_log_destroy:
 
671
 *
 
672
 * Deinitialize the logging subsystem.
 
673
 **/
 
674
void
 
675
z_log_destroy(void)
 
676
{
 
677
  GMainContext *c;
 
678
#ifndef G_OS_WIN32  
 
679
  if (stderr_syslog)
 
680
    {
 
681
      close(1);
 
682
      close(2);
 
683
    }
 
684
#endif
 
685
  g_static_rw_lock_writer_lock(&log_lock);
 
686
  g_hash_table_destroy(class_hash);
 
687
  class_hash = NULL;
 
688
  g_static_rw_lock_writer_unlock(&log_lock);
 
689
  z_close_syslog(syslog_fd);
 
690
  
 
691
  c = context;
 
692
  context = NULL;
 
693
  g_main_context_wakeup(c);
 
694
}