/* * conf.c - syslogd implementation for windows, configuration reader * * Created by Alexander Yaworsky * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ /* define SYSLOG_CONF_DIR where syslog.host should be */ #include #include #include #include #include #include #include #ifndef SYSLOG_CONF_DIR static char syslog_conf_dir[] = "."; #else static char syslog_conf_dir[] = SYSLOG_CONF_DIR; #endif /* options and their default values */ gboolean use_dns = TRUE; int mark_interval = 0; gchar *mark_message = "-- MARK --"; int hold = 3; gchar *logdir = NULL; /* sources, destinations, filters and logpaths */ struct logpath_names { gchar *source; gchar *filter; gchar *destination; }; GList *sources = NULL; GList *destinations = NULL; GList *filters = NULL; GList *logpaths = NULL; GList *purger_dirs = NULL; /* Glib markup wrapper data */ static gchar *encoding = NULL; static gboolean prolog_expected = TRUE; /* parser data */ static struct filter *current_filter = NULL; /****************************************************************************** * create_source * * read attributes of element, initialize source structure and append * it to the list of sources */ static void create_source( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; struct source *source = g_malloc( sizeof(struct source) ); source->name = NULL; source->type = ST_UNDEFINED; memset( &source->udp, 0, sizeof(source->udp) ); source->udp.sin_family = AF_INET; source->udp.sin_port = htons( SYSLOG_PORT ); for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "name" ) == 0 ) source->name = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "type" ) == 0 ) { if( strcmp( aval, "internal" ) == 0 ) source->type = ST_INTERNAL; else if( strcmp( aval, "udp" ) == 0 ) source->type = ST_UDP; } else if( strcmp( aname, "interface" ) == 0 ) { struct hostent *he = gethostbyname( aval ); if( !he ) { ERR( "Cannot resolve hostname %s; error %lu\n", aval, WSAGetLastError() ); g_free( source ); return; } memcpy( &source->udp.sin_addr.s_addr, he->h_addr, he->h_length ); } else if( strcmp( aname, "port" ) == 0 ) source->udp.sin_port = htons( strtoul( aval, NULL, 0 ) ); else if( strcmp( aname, "encoding" ) == 0 ) source->encoding = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); } if( !source->name ) ERR( "Undefined source name at line %d\n", line_number ); if( ST_UNDEFINED == source->type ) ERR( "Undefined source type at line %d\n", line_number ); if( (!source->name) || ST_UNDEFINED == source->type ) { g_free( source ); return; } sources = g_list_append( sources, source ); } /****************************************************************************** * init_file_dest * * read attributes of element and initialize destination structure */ static gboolean init_file_dest( struct destination *dest, int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; /* set nonzero defaults */ dest->u.file.ifempty = TRUE; for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "file" ) == 0 ) dest->u.file.name_pattern = normalize_pathname( aval ); else if( strcmp( aname, "rotate" ) == 0 ) { if( strcmp( aval, "daily" ) == 0 ) dest->u.file.rotate = RP_DAILY; else if( strcmp( aval, "weekly" ) == 0 ) dest->u.file.rotate = RP_WEEKLY; else if( strcmp( aval, "monthly" ) == 0 ) dest->u.file.rotate = RP_MONTHLY; else { ERR( "Invalid rotation period at line %d\n", line_number ); dest->u.file.rotate = RP_INVALID; } } else if( strcmp( aname, "size" ) == 0 ) { char *endptr; dest->u.file.size = strtoul( aval, &endptr, 0 ); if( 'k' == *endptr ) dest->u.file.size *= 1024; else if( 'M' == *endptr ) dest->u.file.size *= 1024 * 1024; } else if( strcmp( aname, "backlogs" ) == 0 ) dest->u.file.backlogs = strtoul( aval, NULL, 0 ); else if( strcmp( aname, "ifempty" ) == 0 ) { if( strcmp( aval, "yes" ) == 0 ) dest->u.file.ifempty = TRUE; else if( strcmp( aval, "no" ) == 0 ) dest->u.file.ifempty = FALSE; else { dest->u.file.ifempty = TRUE; ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d; assumed \"yes\"\n", aval, aname, line_number ); } } else if( strcmp( aname, "olddir" ) == 0 ) dest->u.file.olddir = normalize_pathname( aval ); else if( strcmp( aname, "compresscmd" ) == 0 ) dest->u.file.compresscmd = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "compressoptions" ) == 0 ) dest->u.file.compressoptions = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); } if( !dest->u.file.name_pattern ) ERR( "Undefined destination file at line %d\n", line_number ); if( (!dest->u.file.name_pattern) || RP_INVALID == dest->u.file.rotate ) { if( dest->u.file.name_pattern ) g_free( dest->u.file.name_pattern ); if( dest->u.file.olddir ) g_free( dest->u.file.olddir ); if( dest->u.file.compresscmd ) g_free( dest->u.file.compresscmd ); if( dest->u.file.compressoptions ) g_free( dest->u.file.compressoptions ); return FALSE; } if( dest->u.file.compresscmd && !dest->u.file.compressoptions ) dest->u.file.compressoptions = g_strdup( "$PATHNAME" ); return init_destination_file( dest ); } /****************************************************************************** * init_relay_dest * * read attributes of element and initialize destination structure */ static gboolean init_relay_dest( struct destination *dest, int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "collector" ) == 0 ) dest->u.relay.collector = g_strdup( aval ); else if( strcmp( aname, "omit_hostname" ) == 0 ) { if( strcmp( aval, "yes" ) == 0 ) dest->u.relay.omit_hostname = TRUE; else if( strcmp( aval, "no" ) == 0 ) dest->u.relay.omit_hostname = FALSE; else { dest->u.relay.omit_hostname = FALSE; ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d; assumed \"no\"\n", aval, aname, line_number ); } } } if( !dest->u.relay.collector ) { ERR( "Undefined destination relay at line %d\n", line_number ); return FALSE; } return init_destination_relay( dest ); } /****************************************************************************** * create_destination * * read attributes of element, initialize destination structure and append * it to the list of destinations */ static void create_destination( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { gboolean r = FALSE; const gchar **attr_names; const gchar **attr_values; const gchar *aname; struct destination *dest = g_malloc0( sizeof(struct destination) ); /* at first, we must determine destination type for selection of type-specific structure that we'll fill later; also, look for 'name' and 'encoding' attributes and set corresponding fields in destination structure */ dest->type = DT_UNDEFINED; attr_names = attribute_names; attr_values = attribute_values; for( ; (aname = *attr_names) != NULL; attr_names++, attr_values++ ) { const gchar *aval = *attr_values; if( strcmp( aname, "name" ) == 0 ) dest->name = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "encoding" ) == 0 ) dest->encoding = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "file" ) == 0 ) dest->type = DT_FILE; else if( strcmp( aname, "collector" ) == 0 ) dest->type = DT_RELAY; } if( !dest->name ) { ERR( "Undefined destination name at line %d\n", line_number ); g_free( dest ); return; } switch( dest->type ) { case DT_FILE: r = init_file_dest( dest, line_number, attribute_names, attribute_values ); break; case DT_RELAY: r = init_relay_dest( dest, line_number, attribute_names, attribute_values ); break; default: ERR( "Undefined destination type at line %d\n", line_number ); break; } if( !r ) { /* FIXME: call fini method? */ g_free( dest->name ); g_free( dest ); return; } destinations = g_list_append( destinations, dest ); } /****************************************************************************** * create_filter * * read attributes of element and initialize filter structure; * save pointer to the structure in current_filter */ static void create_filter( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; current_filter = g_malloc0( sizeof(struct filter) ); for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { if( strcmp( aname, "name" ) == 0 ) current_filter->name = g_locale_from_utf8( *attribute_values, -1, NULL, NULL, NULL ); } if( !current_filter->name ) { ERR( "Undefined filter name at line %d\n", line_number ); g_free( current_filter ); current_filter = NULL; } } /****************************************************************************** * init_filter * * parse sub-element of 'filter' and fill the structure current_filter */ static void init_filter( int line_number, const gchar* element_name, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname, *aval; int val = -1; if( strcmp( element_name, "facility" ) == 0 ) { for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { aval = *attribute_values; if( strcmp( aname, "value" ) == 0 ) { val = strtol( aval, NULL, 0 ); if( val < 0 || val >= LOG_NFACILITIES ) { ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d\n", aval, aname, line_number ); return; } } else if( strcmp( aname, "name" ) == 0 ) { CODE *c; for( c = facilitynames; c->c_name; c++ ) if( strcmp( aval, c->c_name ) == 0 ) { val = LOG_FAC( c->c_val ); break; } if( !c->c_name ) { ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d\n", aval, aname, line_number ); return; } } } if( -1 == val ) { ERR( "Undefined facility at line %d\n", line_number ); return; } current_filter->facilities[ val ] = TRUE; return; } if( strcmp( element_name, "priority" ) == 0 ) { for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { aval = *attribute_values; if( strcmp( aname, "value" ) == 0 ) { val = strtol( aval, NULL, 0 ); if( val < 0 || val >= 8 ) { ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d\n", aval, aname, line_number ); return; } } else if( strcmp( aname, "name" ) == 0 ) { CODE *c; for( c = prioritynames; c->c_name; c++ ) if( strcmp( aval, c->c_name ) == 0 ) { val = LOG_PRI( c->c_val ); break; } if( !c->c_name ) { ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d\n", aval, aname, line_number ); return; } } } if( -1 == val ) { ERR( "Undefined priority at line %d\n", line_number ); return; } current_filter->priorities[ val ] = TRUE; return; } } /****************************************************************************** * create_logpath * * read attributes of element, initialize logpath_names structure and append * if to the list of filters; * logpath_names will be replaced with logpath structures after all the * configuration has been read */ static void create_logpath( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; struct logpath_names *logpath = g_malloc0( sizeof(struct logpath_names) ); for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "source" ) == 0 ) logpath->source = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "filter" ) == 0 ) logpath->filter = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "destination" ) == 0 ) logpath->destination = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); } if( !logpath->source ) ERR( "Undefined log path source at line %d\n", line_number ); if( !logpath->destination ) ERR( "Undefined log path destination at line %d\n", line_number ); if( (!logpath->source) || (!logpath->destination) ) { if( logpath->source ) g_free( logpath->source ); if( logpath->filter ) g_free( logpath->filter ); if( logpath->destination ) g_free( logpath->destination ); g_free( logpath ); return; } logpaths = g_list_append( logpaths, logpath ); } /****************************************************************************** * read_options * * read attributes of element and set corresponding options */ static void read_options( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "dns" ) == 0 ) { if( strcmp( aval, "yes" ) == 0 ) use_dns = TRUE; else if( strcmp( aval, "no" ) == 0 ) use_dns = FALSE; else ERR( "Invalid value \"%s\" of attribute \"%s\" at line %d\n", aval, aname, line_number ); } else if( strcmp( aname, "mark_interval" ) == 0 ) mark_interval = strtoul( aval, NULL, 0 ); else if( strcmp( aname, "mark_message" ) == 0 ) mark_message = g_locale_from_utf8( aval, -1, NULL, NULL, NULL ); else if( strcmp( aname, "hold" ) == 0 ) { hold = strtoul( aval, NULL, 0 ); if( hold < 1 ) hold = 1; } else if( strcmp( aname, "logdir" ) == 0 ) logdir = normalize_pathname( aval ); } } /****************************************************************************** * create_purger_dir * * read attributes of element, initialize purger_dir structure and append * it to the list of directories */ static void create_purger_dir( int line_number, const gchar** attribute_names, const gchar** attribute_values ) { const gchar *aname; struct purger_dir *pdir = g_malloc0( sizeof(struct purger_dir) ); for( ; (aname = *attribute_names) != NULL; attribute_names++, attribute_values++ ) { const gchar *aval = *attribute_values; if( strcmp( aname, "directory" ) == 0 ) pdir->directory = normalize_pathname( aval ); else if( strcmp( aname, "keep_days" ) == 0 ) pdir->keep_days = strtoul( aval, NULL, 0 ); } if( !pdir->directory ) ERR( "Undefined purge directory at line %d\n", line_number ); if( !pdir->keep_days ) ERR( "Undefined keep_days parameter at line %d\n", line_number ); if( (!pdir->directory) || (!pdir->keep_days) ) { if( pdir->directory ) g_free( pdir->directory ); g_free( pdir ); return; } purger_dirs = g_list_append( purger_dirs, pdir ); } /****************************************************************************** * xml_start_element * * parse configuration elements */ static void xml_start_element (GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { int line_number; prolog_expected = FALSE; g_markup_parse_context_get_position( context, &line_number, NULL ); /* top-level elements */ if( strcmp( element_name, "source" ) == 0 ) { create_source( line_number, attribute_names, attribute_values ); } else if( strcmp( element_name, "destination" ) == 0 ) { create_destination( line_number, attribute_names, attribute_values ); } else if( strcmp( element_name, "filter" ) == 0 ) { create_filter( line_number, attribute_names, attribute_values ); } else if( strcmp( element_name, "logpath" ) == 0 ) { create_logpath( line_number, attribute_names, attribute_values ); } else if( strcmp( element_name, "options" ) == 0 ) { read_options( line_number, attribute_names, attribute_values ); } else if( strcmp( element_name, "purge" ) == 0 ) { create_purger_dir( line_number, attribute_names, attribute_values ); } else if( current_filter ) { /* sub-elements of filter */ init_filter( line_number, element_name, attribute_names, attribute_values ); } } /****************************************************************************** * xml_end_element */ static void xml_end_element (GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error) { if( strcmp( element_name, "filter" ) == 0 ) { if( current_filter ) { /* append filter to the list */ filters = g_list_append( filters, current_filter ); current_filter = NULL; } } } /****************************************************************************** * xml_passthrough * * look for encoding name */ static void xml_passthrough (GMarkupParseContext *context, const gchar *passthrough_text, gsize text_len, gpointer user_data, GError **error) { const gchar *startptr, *endptr; if( !prolog_expected ) return; startptr = g_strstr_len( passthrough_text, text_len, "" ); if( !endptr ) goto parsed; text_len = endptr - startptr; startptr = g_strstr_len( startptr, text_len, "encoding=\"" ); if( !startptr ) goto parsed; startptr += 10; endptr = strchr( startptr, '"' ); if( !endptr ) goto parsed; if( strncmp( startptr, "windows-", 8 ) == 0 ) { gchar *p; startptr += 8; p = g_strndup( startptr, endptr - startptr ); if( !p ) goto parsed; encoding = g_strdup_printf( "CP%s", p ); g_free( p ); } else encoding = g_strndup( startptr, endptr - startptr ); parsed: prolog_expected = FALSE; } /****************************************************************************** * create_conversion_descriptors * * helper function for resolve_logpaths; */ static void create_conversion_descriptors( struct logpath* logpath ) { if( logpath->source->encoding || logpath->destination->encoding ) { char *source_encoding = logpath->source->encoding? logpath->source->encoding : "UTF-8"; char *destination_encoding = logpath->destination->encoding? logpath->destination->encoding : "UTF-8"; if( strcasecmp( source_encoding, destination_encoding ) != 0 ) { logpath->src2dest_cd = g_iconv_open( destination_encoding, source_encoding ); if( logpath->src2dest_cd == (GIConv) -1 ) { ERR( "Cannot convert messages from %s to %s\n", source_encoding, destination_encoding ); } else { TRACE( "Log path %s-%s: converting messages from %s to %s\n", logpath->source->name, logpath->destination->name, source_encoding, destination_encoding ); } } if( strcasecmp( "ASCII", destination_encoding ) != 0 ) { logpath->ascii2dest_cd = g_iconv_open( destination_encoding, source_encoding ); if( logpath->ascii2dest_cd == (GIConv) -1 ) { ERR( "Cannot convert messages from ASCII to %s\n", destination_encoding ); } else { TRACE( "Log path %s-%s: converting messages from ASCII to %s\n", logpath->source->name, logpath->destination->name, destination_encoding ); } } } if( logpath->source->encoding ) { const gchar *destination_encoding; g_get_charset( &destination_encoding ); if( strcasecmp( logpath->source->encoding, destination_encoding ) != 0 ) { logpath->src2locale_cd = g_iconv_open( destination_encoding, logpath->source->encoding ); if( logpath->src2locale_cd == (GIConv) -1 ) { ERR( "Cannot convert locale parts from %s to %s\n", logpath->source->encoding, destination_encoding ); } else { TRACE( "Log path %s-%s: converting locale parts from %s to %s\n", logpath->source->name, logpath->destination->name, logpath->source->encoding, destination_encoding ); } } } } /****************************************************************************** * resolve_logpaths * * replace logpath_names structures */ static void resolve_logpaths() { GList *paths = NULL; GList *path_item; struct logpath *logpath = NULL; for( path_item = logpaths; path_item; path_item = path_item->next ) { struct logpath_names *names = path_item->data; GList *item; g_free( logpath ); logpath = g_malloc( sizeof(struct logpath) ); logpath->src2dest_cd = (GIConv) -1; logpath->ascii2dest_cd = (GIConv) -1; logpath->src2locale_cd = (GIConv) -1; /* find source */ for( item = sources; item; item = item->next ) { struct source *s = item->data; if( strcmp( s->name, names->source ) == 0 ) break; } if( !item ) { ERR( "Undefined source \"%s\" in log path\n", names->source ); continue; } logpath->source = item->data; /* find destination */ for( item = destinations; item; item = item->next ) { struct destination *d = item->data; if( strcmp( d->name, names->destination ) == 0 ) break; } if( !item ) { ERR( "Undefined destination \"%s\" in log path\n", names->destination ); continue; } logpath->destination = item->data; /* find filter */ if( !names->filter ) logpath->filter = NULL; else { for( item = filters; item; item = item->next ) { struct filter *f = item->data; if( strcmp( f->name, names->filter ) == 0 ) break; } if( item ) logpath->filter = item->data; else logpath->filter = NULL; } create_conversion_descriptors( logpath ); /* add item to paths */ paths = g_list_append( paths, logpath ); logpath = NULL; } /* free list */ for( path_item = logpaths; path_item; path_item = path_item->next ) { struct logpath_names *names = path_item->data; g_free( names->source ); g_free( names->destination ); if( names->filter ) g_free( names->filter ); g_free( names ); } g_list_free( logpaths ); /* set new list */ logpaths = paths; } /****************************************************************************** * dump_configuration */ static void dump_configuration() { # ifdef HAVE_DEBUG GList *item; TRACE( "Sources:\n" ); for( item = sources; item; item = item->next ) { struct source *s = item->data; TRACE( "\tname=%s\ttype=%s\tencoding=%s\tinterface=%d:%d:%d:%d\tport=%d\n", s->name, (s->type == ST_INTERNAL)? "internal" : ((s->type == ST_UDP)? "udp" : "undefined"), s->encoding? s->encoding : "UTF-8", s->udp.sin_addr.S_un.S_un_b.s_b1, s->udp.sin_addr.S_un.S_un_b.s_b2, s->udp.sin_addr.S_un.S_un_b.s_b3, s->udp.sin_addr.S_un.S_un_b.s_b4, ntohs( s->udp.sin_port ) ); } TRACE( "Destinations:\n" ); for( item = destinations; item; item = item->next ) { struct destination *d = item->data; switch( d->type ) { case DT_FILE: TRACE( "\tname=%s\tencoding=%s\tfile=%s\n" "\t\trotate=%s size=%d backlogs=%d ifempty=%s\n" "\t\tolddir=%s compresscmd=%s\n", d->name, d->encoding? d->encoding : "UTF-8", d->u.file.name_pattern, (d->u.file.rotate == RP_DAILY)? "daily" : (d->u.file.rotate == RP_WEEKLY)? "weekly" : (d->u.file.rotate == RP_MONTHLY)? "monthly" : "undefined", d->u.file.size, d->u.file.backlogs, d->u.file.ifempty? "yes" : "no", d->u.file.olddir? d->u.file.olddir : "NULL", d->u.file.compresscmd? d->u.file.compresscmd : "NULL" ); break; case DT_RELAY: TRACE( "\tname=%s\tencoding=%s\tcollector=%s\n" "\t\tomit_hostname=%s\n", d->name, d->encoding? d->encoding : "UTF-8", d->u.relay.collector, d->u.relay.omit_hostname? "yes" : "no" ); break; default: break; } } TRACE( "Filters:\n" ); for( item = filters; item; item = item->next ) { struct filter *f = item->data; int i; TRACE( "\tname=%s\n", f->name ); TRACE( "\tfacilities:\n" ); for( i = 0; i < LOG_NFACILITIES; i++ ) if( f->facilities[i] ) TRACE( "\t\t%s\n", get_facility_name( i ) ); TRACE( "\tpriorities:\n" ); for( i = 0; i < 8; i++ ) if( f->priorities[i] ) TRACE( "\t\t%s\n", get_priority_name( i ) ); } TRACE( "Log paths:\n" ); for( item = logpaths; item; item = item->next ) { struct logpath *p = item->data; TRACE( "\tsource=%s\tfilter=%s\tdestination=%s\n", p->source->name, p->filter? p->filter->name : "NULL", p->destination->name ); } TRACE( "Purge directories:\n" ); for( item = purger_dirs; item; item = item->next ) { struct purger_dir *p = item->data; TRACE( "\tdirectory=%s\tkeep_days=%d\n", p->directory, p->keep_days ); } TRACE( "Options:\n" ); TRACE( "\tuse_dns=%d\n", (int) use_dns ); TRACE( "\tmark_interval=%d\n", mark_interval ); TRACE( "\tmark_message=%s\n", mark_message ); TRACE( "\thold=%d\n", hold ); TRACE( "\tlogdir=%s\n", logdir? logdir : "NULL" ); # endif /* HAVE_DEBUG */ } /****************************************************************************** * read_configuration */ gboolean read_configuration() { gboolean ret = FALSE; GMarkupParser parser = { xml_start_element, xml_end_element, NULL, xml_passthrough, NULL }; gchar *pathname; FILE *fd = NULL; GMarkupParseContext *ctx = NULL; char buffer[256]; GError *error = NULL; TRACE_ENTER( "\n" ); if( conf_file_name ) pathname = g_strdup( conf_file_name ); else if( '\\' == syslog_conf_dir[0] || '/' == syslog_conf_dir[0] || ':' == syslog_conf_dir[1] ) /* absolute path */ pathname = g_build_filename( syslog_conf_dir, "syslog.conf", NULL ); else /* relative path */ pathname = g_build_filename( g_path_get_dirname( __argv[0] ), syslog_conf_dir, "syslog.conf", NULL ); fd = fopen( pathname, "r" ); if( !fd ) { ERR( "Cannot open configuration file %s: %s\n", pathname, strerror(errno) ); goto done; } ctx = g_markup_parse_context_new( &parser, 0, NULL, NULL ); if( !ctx ) { ERR( "Failed g_markup_parse_context_new\n" ); goto done; } while( fgets( buffer, sizeof(buffer), fd ) ) { gchar *encoded = NULL; gchar *parser_input; gboolean r; /* wrapper for Glib's XML parser: determine encoding in xml_passthrough and convert data fed to the parser to UTF-8 */ if( encoding ) { encoded = g_convert( buffer, -1, "UTF-8", encoding, NULL, NULL, &error ); if( !encoded ) goto done; parser_input = encoded; } else parser_input = buffer; r = g_markup_parse_context_parse( ctx, parser_input, strlen( parser_input ), &error ); if( encoded ) g_free( encoded ); if( !r ) goto done; } if( !feof( fd ) ) { ERR( "Cannot read configuration file %s: %s\n", pathname, strerror(errno) ); goto done; } resolve_logpaths(); dump_configuration(); if( !logdir ) { ERR( "logdir is not defined\n" ); goto done; } ret = TRUE; done: if( error ) { gchar *locale_msg = g_locale_from_utf8( error->message, -1, NULL, NULL, NULL ); if( locale_msg ) { ERR( "%s\n", locale_msg ); g_free( locale_msg ); } g_error_free( error ); } if( ctx ) g_markup_parse_context_free( ctx ); if( fd ) fclose( fd ); g_free( pathname ); TRACE_LEAVE( "done; ret=%d\n", (int) ret ); return ret; }