2009-11-19 02:48:48 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2009-11-19 02:48:48 +03:00
# include <string.h>
# include <stdio.h>
# include <errno.h>
# include <assert.h>
# include <stdlib.h>
# include "conf-parser.h"
# include "util.h"
# include "macro.h"
2009-11-19 04:51:44 +03:00
# include "strv.h"
2010-01-20 21:19:53 +03:00
# include "log.h"
2009-11-19 02:48:48 +03:00
# define COMMENTS "#;\n"
# define LINE_MAX 4096
/* Run the user supplied parser for an assignment */
static int next_assignment (
const char * filename ,
unsigned line ,
const char * section ,
const ConfigItem * t ,
const char * lvalue ,
const char * rvalue ,
void * userdata ) {
assert ( filename ) ;
assert ( t ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
for ( ; t - > parse ; t + + ) {
if ( t - > lvalue & & ! streq ( lvalue , t - > lvalue ) )
continue ;
if ( t - > section & & ! section )
continue ;
if ( t - > section & & ! streq ( section , t - > section ) )
continue ;
return t - > parse ( filename , line , section , lvalue , rvalue , t - > data , userdata ) ;
}
2010-01-27 02:19:06 +03:00
log_info ( " [%s:%u] Unknown lvalue '%s' in section '%s'. Ignoring. " , filename , line , lvalue , strna ( section ) ) ;
return 0 ;
2009-11-19 02:48:48 +03:00
}
/* Parse a variable assignment line */
2010-01-19 04:56:37 +03:00
static int parse_line ( const char * filename , unsigned line , char * * section , const char * const * sections , const ConfigItem * t , char * l , void * userdata ) {
2010-01-28 00:38:48 +03:00
char * e ;
2009-11-19 02:48:48 +03:00
2010-01-28 00:38:48 +03:00
l = strstrip ( l ) ;
2009-11-19 02:48:48 +03:00
2010-01-28 00:38:48 +03:00
if ( ! * l )
2009-11-19 02:48:48 +03:00
return 0 ;
2010-01-27 07:30:38 +03:00
2010-01-28 00:38:48 +03:00
if ( strchr ( COMMENTS , * l ) )
2010-01-27 07:30:38 +03:00
return 0 ;
2009-11-19 02:48:48 +03:00
2010-01-28 00:38:48 +03:00
if ( startswith ( l , " .include " ) ) {
char * fn ;
2009-11-19 02:48:48 +03:00
int r ;
2010-01-28 00:38:48 +03:00
if ( ! ( fn = file_in_same_dir ( filename , strstrip ( l + 9 ) ) ) )
return - ENOMEM ;
2009-11-19 02:48:48 +03:00
2010-01-26 23:39:06 +03:00
r = config_parse ( fn , NULL , sections , t , userdata ) ;
2010-01-28 00:38:48 +03:00
free ( fn ) ;
2009-11-19 02:48:48 +03:00
return r ;
}
2010-01-28 00:38:48 +03:00
if ( * l = = ' [ ' ) {
2009-11-19 02:48:48 +03:00
size_t k ;
char * n ;
2010-01-28 00:38:48 +03:00
k = strlen ( l ) ;
2009-11-19 02:48:48 +03:00
assert ( k > 0 ) ;
2010-01-28 00:38:48 +03:00
if ( l [ k - 1 ] ! = ' ] ' ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Invalid section header. " , filename , line ) ;
2009-11-19 02:48:48 +03:00
return - EBADMSG ;
}
2010-01-28 00:38:48 +03:00
if ( ! ( n = strndup ( l + 1 , k - 2 ) ) )
2009-11-19 02:48:48 +03:00
return - ENOMEM ;
2010-01-28 00:38:48 +03:00
if ( sections & & ! strv_contains ( ( char * * ) sections , n ) ) {
free ( n ) ;
return - EBADMSG ;
2010-01-19 04:56:37 +03:00
}
2009-11-19 02:48:48 +03:00
free ( * section ) ;
* section = n ;
return 0 ;
}
2010-01-28 00:38:48 +03:00
if ( ! ( e = strchr ( l , ' = ' ) ) ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Missing '='. " , filename , line ) ;
2009-11-19 02:48:48 +03:00
return - EBADMSG ;
}
* e = 0 ;
e + + ;
2010-01-28 00:38:48 +03:00
return next_assignment ( filename , line , * section , t , strstrip ( l ) , strstrip ( e ) , userdata ) ;
2009-11-19 02:48:48 +03:00
}
/* Go through the file and parse each line */
2010-01-26 23:39:06 +03:00
int config_parse ( const char * filename , FILE * f , const char * const * sections , const ConfigItem * t , void * userdata ) {
2009-11-19 02:48:48 +03:00
unsigned line = 0 ;
char * section = NULL ;
int r ;
2010-04-06 04:36:41 +04:00
bool ours = false ;
2009-11-19 02:48:48 +03:00
assert ( filename ) ;
assert ( t ) ;
2010-01-26 23:39:06 +03:00
if ( ! f ) {
if ( ! ( f = fopen ( filename , " re " ) ) ) {
r = - errno ;
log_error ( " Failed to open configuration file '%s': %s " , filename , strerror ( - r ) ) ;
goto finish ;
}
2010-04-06 04:36:41 +04:00
ours = true ;
2009-11-19 02:48:48 +03:00
}
while ( ! feof ( f ) ) {
char l [ LINE_MAX ] ;
if ( ! fgets ( l , sizeof ( l ) , f ) ) {
if ( feof ( f ) )
break ;
r = - errno ;
2010-01-20 21:19:53 +03:00
log_error ( " Failed to read configuration file '%s': %s " , filename , strerror ( - r ) ) ;
2009-11-19 02:48:48 +03:00
goto finish ;
}
2010-01-19 04:56:37 +03:00
if ( ( r = parse_line ( filename , + + line , & section , sections , t , l , userdata ) ) < 0 )
2009-11-19 02:48:48 +03:00
goto finish ;
}
r = 0 ;
finish :
free ( section ) ;
2010-04-06 04:36:41 +04:00
if ( f & & ours )
2009-11-19 02:48:48 +03:00
fclose ( f ) ;
return r ;
}
int config_parse_int (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
int * i = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atoi ( rvalue , i ) ) < 0 ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Failed to parse numeric value: %s " , filename , line , rvalue ) ;
2009-11-19 02:48:48 +03:00
return r ;
}
return 0 ;
}
int config_parse_unsigned (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
unsigned * u = data ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atou ( rvalue , u ) ) < 0 ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Failed to parse numeric value: %s " , filename , line , rvalue ) ;
2009-11-19 02:48:48 +03:00
return r ;
}
return 0 ;
}
int config_parse_size (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
size_t * sz = data ;
unsigned u ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atou ( rvalue , & u ) ) < 0 ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Failed to parse numeric value: %s " , filename , line , rvalue ) ;
2009-11-19 02:48:48 +03:00
return r ;
}
* sz = ( size_t ) u ;
return 0 ;
}
int config_parse_bool (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
int k ;
bool * b = data ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( k = parse_boolean ( rvalue ) ) < 0 ) {
2010-01-20 21:19:53 +03:00
log_error ( " [%s:%u] Failed to parse boolean value: %s " , filename , line , rvalue ) ;
2009-11-19 02:48:48 +03:00
return k ;
}
* b = ! ! k ;
return 0 ;
}
int config_parse_string (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
char * * s = data ;
char * n ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( * rvalue ) {
if ( ! ( n = strdup ( rvalue ) ) )
return - ENOMEM ;
} else
n = NULL ;
free ( * s ) ;
* s = n ;
return 0 ;
}
2009-11-19 04:51:44 +03:00
2010-01-26 06:18:44 +03:00
int config_parse_path (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
char * * s = data ;
char * n ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( * rvalue ! = ' / ' ) {
log_error ( " [%s:%u] Not an absolute path: %s " , filename , line , rvalue ) ;
return - EINVAL ;
}
if ( ! ( n = strdup ( rvalue ) ) )
return - ENOMEM ;
free ( * s ) ;
* s = n ;
return 0 ;
}
2009-11-19 04:51:44 +03:00
int config_parse_strv (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
char * * * sv = data ;
char * * n ;
char * w ;
unsigned k ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
k = strv_length ( * sv ) ;
2010-01-26 06:18:44 +03:00
FOREACH_WORD_QUOTED ( w , l , rvalue , state )
2009-11-19 04:51:44 +03:00
k + + ;
if ( ! ( n = new ( char * , k + 1 ) ) )
return - ENOMEM ;
2010-04-06 04:37:47 +04:00
if ( * sv )
for ( k = 0 ; ( * sv ) [ k ] ; k + + )
n [ k ] = ( * sv ) [ k ] ;
2010-04-06 23:52:35 +04:00
else
k = 0 ;
2010-04-06 04:37:47 +04:00
2010-01-26 06:18:44 +03:00
FOREACH_WORD_QUOTED ( w , l , rvalue , state )
2009-11-19 04:51:44 +03:00
if ( ! ( n [ k + + ] = strndup ( w , l ) ) )
goto fail ;
n [ k ] = NULL ;
free ( * sv ) ;
* sv = n ;
return 0 ;
fail :
for ( ; k > 0 ; k - - )
free ( n [ k - 1 ] ) ;
2010-01-26 06:18:44 +03:00
free ( n ) ;
2009-11-19 04:51:44 +03:00
return - ENOMEM ;
}