@ -134,7 +134,7 @@ static ares_status_t parse_sort(ares__buf_t *buf, struct apattern *pat)
ares__buf_tag ( buf ) ;
/* Consume ip address */
if ( ares__buf_consume_charset ( buf , ip_charset , sizeof ( ip_charset ) ) = = 0 ) {
if ( ares__buf_consume_charset ( buf , ip_charset , sizeof ( ip_charset ) - 1 ) = = 0 ) {
return ARES_EBADSTR ;
}
@ -162,8 +162,8 @@ static ares_status_t parse_sort(ares__buf_t *buf, struct apattern *pat)
ares__buf_tag ( buf ) ;
/* Consume mask */
if ( ares__buf_consume_charset ( buf , ipv4_charset , sizeof ( ipv4_charset ) ) = =
0 ) {
if ( ares__buf_consume_charset ( buf , ipv4_charset ,
sizeof ( ipv4_charset ) - 1 ) = = 0 ) {
return ARES_EBADSTR ;
}
@ -241,7 +241,7 @@ ares_status_t ares__parse_sortlist(struct apattern **sortlist, size_t *nsort,
/* Split on space or semicolon */
status = ares__buf_split ( buf , ( const unsigned char * ) " ; " , 2 ,
ARES_BUF_SPLIT_NONE , & list ) ;
ARES_BUF_SPLIT_NONE , 0 , & list ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
@ -282,7 +282,8 @@ done:
return status ;
}
static ares_status_t config_search ( ares_sysconfig_t * sysconfig , const char * str )
static ares_status_t config_search ( ares_sysconfig_t * sysconfig , const char * str ,
size_t max_domains )
{
if ( sysconfig - > domains & & sysconfig - > ndomains > 0 ) {
/* if we already have some domains present, free them first */
@ -296,410 +297,518 @@ static ares_status_t config_search(ares_sysconfig_t *sysconfig, const char *str)
return ARES_ENOMEM ;
}
/* Truncate if necessary */
if ( max_domains & & sysconfig - > ndomains > max_domains ) {
size_t i ;
for ( i = max_domains ; i < sysconfig - > ndomains ; i + + ) {
ares_free ( sysconfig - > domains [ i ] ) ;
sysconfig - > domains [ i ] = NULL ;
}
sysconfig - > ndomains = max_domains ;
}
return ARES_SUCCESS ;
}
static ares_status_t config_domain ( ares_sysconfig_t * sysconfig , char * str )
static ares_status_t buf_fetch_string ( ares__buf_t * buf , char * str ,
size_t str_len )
{
char * q ;
/* Set a single search domain. */
q = str ;
while ( * q & & ! ISSPACE ( * q ) ) {
q + + ;
}
* q = ' \0 ' ;
ares_status_t status ;
ares__buf_tag ( buf ) ;
ares__buf_consume ( buf , ares__buf_len ( buf ) ) ;
return config_search ( sysconfig , str ) ;
status = ares__buf_tag_fetch_string ( buf , str , str_len ) ;
return status ;
}
static ares_status_t config_lookup ( ares_sysconfig_t * sysconfig , const char * str ,
const char * bindch , const char * altbindch ,
const char * filech )
static ares_status_t config_lookup ( ares_sysconfig_t * sysconfig ,
ares__buf_t * buf , const char * separators )
{
char lookups [ 3 ] ;
char * l ;
const char * p ;
ares_bool_t found ;
if ( altbindch = = NULL ) {
altbindch = bindch ;
ares_status_t status ;
char lookupstr [ 32 ] ;
size_t lookupstr_cnt = 0 ;
ares__llist_t * lookups = NULL ;
ares__llist_node_t * node ;
size_t separators_len = ares_strlen ( separators ) ;
status = ares__buf_split ( buf , ( const unsigned char * ) separators ,
separators_len , ARES_BUF_SPLIT_TRIM , 0 , & lookups ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
/* Set the lookup order. Only the first letter of each work
* is relevant , and it has to be " b " for DNS or " f " for the
* host file . Ignore everything else .
*/
l = lookups ;
p = str ;
found = ARES_FALSE ;
while ( * p ) {
if ( ( * p = = * bindch | | * p = = * altbindch | | * p = = * filech ) & &
l < lookups + 2 ) {
if ( * p = = * bindch | | * p = = * altbindch ) {
* l + + = ' b ' ;
} else {
* l + + = ' f ' ;
}
found = ARES_TRUE ;
memset ( lookupstr , 0 , sizeof ( lookupstr ) ) ;
for ( node = ares__llist_node_first ( lookups ) ; node ! = NULL ;
node = ares__llist_node_next ( node ) ) {
char value [ 128 ] ;
char ch ;
ares__buf_t * valbuf = ares__llist_node_val ( node ) ;
status = buf_fetch_string ( valbuf , value , sizeof ( value ) ) ;
if ( status ! = ARES_SUCCESS ) {
continue ;
}
while ( * p & & ! ISSPACE ( * p ) & & ( * p ! = ' , ' ) ) {
p + + ;
if ( strcasecmp ( value , " dns " ) = = 0 | | strcasecmp ( value , " bind " ) = = 0 | |
strcasecmp ( value , " resolv " ) = = 0 | | strcasecmp ( value , " resolve " ) = = 0 ) {
ch = ' b ' ;
} else if ( strcasecmp ( value , " files " ) = = 0 | |
strcasecmp ( value , " file " ) = = 0 | |
strcasecmp ( value , " local " ) = = 0 ) {
ch = ' f ' ;
} else {
continue ;
}
while ( * p & & ( ISSPACE ( * p ) | | ( * p = = ' , ' ) ) ) {
p + + ;
/* Look for a duplicate and ignore */
if ( memchr ( lookupstr , ch , lookupstr_cnt ) = = NULL ) {
lookupstr [ lookupstr_cnt + + ] = ch ;
}
}
if ( ! found ) {
return ARES_ENOTINITIALIZED ;
if ( lookupstr_cnt ) {
ares_free ( sysconfig - > lookups ) ;
sysconfig - > lookups = ares_strdup ( lookupstr ) ;
if ( sysconfig - > lookups = = NULL ) {
return ARES_ENOMEM ;
}
}
* l = ' \0 ' ;
ares_free ( sysconfig - > lookups ) ;
sysconfig - > lookups = ares_strdup ( lookups ) ;
if ( sysconfig - > lookups = = NULL ) {
return ARES_ENOMEM ;
status = ARES_SUCCESS ;
done :
if ( status ! = ARES_ENOMEM ) {
status = ARES_SUCCESS ;
}
return ARES_SUCCESS ;
ares__llist_destroy ( lookups ) ;
return status ;
}
static const char * try_option ( const char * p , const char * q , const char * opt )
static ares_status_t process_option ( ares_sysconfig_t * sysconfig ,
ares__buf_t * option )
{
size_t len = ares_strlen ( opt ) ;
return ( ( size_t ) ( q - p ) > = len & & ! strncmp ( p , opt , len ) ) ? & p [ len ] : NULL ;
ares__llist_t * kv = NULL ;
char key [ 32 ] = " " ;
char val [ 32 ] = " " ;
unsigned int valint = 0 ;
ares_status_t status ;
/* Split on : */
status = ares__buf_split ( option , ( const unsigned char * ) " : " , 1 ,
ARES_BUF_SPLIT_TRIM , 2 , & kv ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
status = buf_fetch_string ( ares__llist_first_val ( kv ) , key , sizeof ( key ) ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
if ( ares__llist_len ( kv ) = = 2 ) {
status = buf_fetch_string ( ares__llist_last_val ( kv ) , val , sizeof ( val ) ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
valint = ( unsigned int ) strtoul ( val , NULL , 10 ) ;
}
if ( strcmp ( key , " ndots " ) = = 0 ) {
if ( valint = = 0 ) {
return ARES_EFORMERR ;
}
sysconfig - > ndots = valint ;
} else if ( strcmp ( key , " retrans " ) = = 0 | | strcmp ( key , " timeout " ) = = 0 ) {
if ( valint = = 0 ) {
return ARES_EFORMERR ;
}
sysconfig - > timeout_ms = valint * 1000 ;
} else if ( strcmp ( key , " retry " ) = = 0 | | strcmp ( key , " attempts " ) = = 0 ) {
if ( valint = = 0 ) {
return ARES_EFORMERR ;
}
sysconfig - > tries = valint ;
} else if ( strcmp ( key , " rotate " ) = = 0 ) {
sysconfig - > rotate = ARES_TRUE ;
} else if ( strcmp ( key , " use-vc " ) = = 0 | | strcmp ( key , " usevc " ) = = 0 ) {
sysconfig - > usevc = ARES_TRUE ;
}
done :
ares__llist_destroy ( kv ) ;
return status ;
}
static ares_status_t set_options ( ares_sysconfig_t * sysconfig , const char * str )
{
const char * p ;
const char * q ;
const char * val ;
ares__buf_t * buf = NULL ;
ares__llist_t * options = NULL ;
ares_status_t status ;
ares__llist_node_t * node ;
if ( str = = NULL ) {
return ARES_SUCCESS ;
buf = ares__buf_create_const ( ( const unsigned char * ) str , ares_strlen ( str ) ) ;
if ( buf = = NULL ) {
return ARES_ENOMEM ;
}
p = str ;
while ( * p ) {
q = p ;
while ( * q & & ! ISSPACE ( * q ) ) {
q + + ;
}
val = try_option ( p , q , " ndots: " ) ;
if ( val ) {
sysconfig - > ndots = strtoul ( val , NULL , 10 ) ;
}
status = ares__buf_split ( buf , ( const unsigned char * ) " \t " , 2 ,
ARES_BUF_SPLIT_TRIM , 0 , & options ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
// Outdated option.
val = try_option ( p , q , " retrans: " ) ;
if ( val ) {
sysconfig - > timeout_ms = strtoul ( val , NULL , 10 ) ;
}
for ( node = ares__llist_node_first ( options ) ; node ! = NULL ;
node = ares__llist_node_next ( node ) ) {
ares__buf_t * valbuf = ares__llist_node_val ( node ) ;
val = try_option ( p , q , " timeout: " ) ;
if ( val ) {
sysconfig - > timeout_ms = strtoul ( val , NULL , 10 ) * 1000 ;
status = process_option ( sysconfig , valbuf ) ;
/* Out of memory is the only fatal condition */
if ( status = = ARES_ENOMEM ) {
goto done ;
}
}
// Outdated option.
val = try_option ( p , q , " retry: " ) ;
if ( val ) {
sysconfig - > tries = strtoul ( val , NULL , 10 ) ;
}
status = ARES_SUCCESS ;
val = try_option ( p , q , " attempts: " ) ;
if ( val ) {
sysconfig - > tries = strtoul ( val , NULL , 10 ) ;
}
done :
ares__llist_destroy ( options ) ;
ares__buf_destroy ( buf ) ;
return status ;
}
val = try_option ( p , q , " rotate " ) ;
if ( val ) {
sysconfig - > rotate = ARES_TRUE ;
ares_status_t ares__init_by_environment ( ares_sysconfig_t * sysconfig )
{
const char * localdomain ;
const char * res_options ;
ares_status_t status ;
localdomain = getenv ( " LOCALDOMAIN " ) ;
if ( localdomain ) {
char * temp = ares_strdup ( localdomain ) ;
if ( temp = = NULL ) {
return ARES_ENOMEM ;
}
status = config_search ( sysconfig , temp , 1 ) ;
ares_free ( temp ) ;
if ( status ! = ARES_SUCCESS ) {
return status ;
}
}
p = q ;
while ( ISSPACE ( * p ) ) {
p + + ;
res_options = getenv ( " RES_OPTIONS " ) ;
if ( res_options ) {
status = set_options ( sysconfig , res_options ) ;
if ( status ! = ARES_SUCCESS ) {
return status ;
}
}
return ARES_SUCCESS ;
}
static char * try_config ( char * s , const char * opt , char scc )
/* Configuration Files:
* / etc / resolv . conf
* - All Unix - like systems
* - Comments start with ; or #
* - Lines have a keyword followed by a value that is interpreted specific
* to the keyword :
* - Keywords :
* - nameserver - IP address of nameserver with optional port ( using a :
* prefix ) . If using an ipv6 address and specifying a port , the ipv6
* address must be encapsulated in brackets . For link - local ipv6
* addresses , the interface can also be specified with a % prefix . e . g . :
* " nameserver [fe80::1]:1234%iface "
* This keyword may be specified multiple times .
* - search - whitespace separated list of domains
* - domain - obsolete , same as search except only a single domain
* - lookup / hostresorder - local , bind , file , files
* - sortlist - whitespace separated ip - address / netmask pairs
* - options - options controlling resolver variables
* - ndots : n - set ndots option
* - timeout : n ( retrans : n ) - timeout per query attempt in seconds
* - attempts : n ( retry : n ) - number of times resolver will send query
* - rotate - round - robin selection of name servers
* - use - vc / usevc - force tcp
* / etc / nsswitch . conf
* - Modern Linux , FreeBSD , HP - UX , Solaris
* - Search order set via :
* " hosts: files dns mdns4_minimal mdns4 "
* - files is / etc / hosts
* - dns is dns
* - mdns4_minimal does mdns only if ending in . local
* - mdns4 does not limit to domains ending in . local
* / etc / netsvc . conf
* - AIX
* - Search order set via :
* " hosts = local , bind "
* - bind is dns
* - local is / etc / hosts
* / etc / svc . conf
* - Tru64
* - Same format as / etc / netsvc . conf
* / etc / host . conf
* - Early FreeBSD , Early Linux
* - Not worth supporting , format varied based on system , FreeBSD used
* just a line per search order , Linux used " order " and a comma
* delimited list of " bind " and " hosts "
*/
/* This function will only return ARES_SUCCESS or ARES_ENOMEM. Any other
* conditions are ignored . Users may mess up config files , but we want to
* process anything we can . */
static ares_status_t parse_resolvconf_line ( ares_sysconfig_t * sysconfig ,
ares__buf_t * line )
{
size_t len ;
char * p ;
char * q ;
char option [ 32 ] ;
char value [ 512 ] ;
ares_status_t status = ARES_SUCCESS ;
if ( ! s | | ! opt ) {
/* no line or no option */
return NULL ; /* LCOV_EXCL_LINE */
/* Ignore lines beginning with a comment */
if ( ares__buf_begins_with ( line , ( const unsigned char * ) " # " , 1 ) | |
ares__buf_begins_with ( line , ( const unsigned char * ) " ; " , 1 ) ) {
return ARES_SUCCESS ;
}
/* Hash '#' character is always used as primary comment char, additionally
a not - NUL secondary comment char will be considered when specified . */
ares__buf_tag ( line ) ;
/* trim line comment */
p = s ;
if ( scc ) {
while ( * p & & ( * p ! = ' # ' ) & & ( * p ! = scc ) ) {
p + + ;
}
} else {
while ( * p & & ( * p ! = ' # ' ) ) {
p + + ;
}
/* Shouldn't be possible, but if it happens, ignore the line. */
if ( ares__buf_consume_nonwhitespace ( line ) = = 0 ) {
return ARES_SUCCESS ;
}
* p = ' \0 ' ;
/* trim trailing whitespace */
q = p - 1 ;
while ( ( q > = s ) & & ISSPACE ( * q ) ) {
q - - ;
status = ares__buf_tag_fetch_string ( line , option , sizeof ( option ) ) ;
if ( status ! = ARES_SUCCESS ) {
return ARES_SUCCESS ;
}
* + + q = ' \0 ' ;
/* skip leading whitespace */
p = s ;
while ( * p & & ISSPACE ( * p ) ) {
p + + ;
}
ares__buf_consume_whitespace ( line , ARES_TRUE ) ;
if ( ! * p ) {
/* empty line */
return NULL ;
status = buf_fetch_string ( line , value , sizeof ( value ) ) ;
if ( status ! = ARES_SUCCESS ) {
return ARES_SUCCESS ;
}
if ( ( len = ares_strlen ( opt ) ) = = 0 ) {
/* empty option */
return NULL ; /* LCOV_EXCL_LINE */
ares__str_trim ( value ) ;
if ( * value = = 0 ) {
return ARES_SUCCESS ;
}
if ( strncmp ( p , opt , len ) ! = 0 ) {
/* line and option do not match */
return NULL ;
/* At this point we have a string option and a string value, both trimmed
* of leading and trailing whitespace . Lets try to evaluate them */
if ( strcmp ( option , " domain " ) = = 0 ) {
/* Domain is legacy, don't overwrite an existing config set by search */
if ( sysconfig - > domains = = NULL ) {
status = config_search ( sysconfig , value , 1 ) ;
}
} else if ( strcmp ( option , " lookup " ) = = 0 | |
strcmp ( option , " hostresorder " ) = = 0 ) {
ares__buf_tag_rollback ( line ) ;
status = config_lookup ( sysconfig , line , " \t " ) ;
} else if ( strcmp ( option , " search " ) = = 0 ) {
status = config_search ( sysconfig , value , 0 ) ;
} else if ( strcmp ( option , " nameserver " ) = = 0 ) {
status =
ares__sconfig_append_fromstr ( & sysconfig - > sconfig , value , ARES_TRUE ) ;
} else if ( strcmp ( option , " sortlist " ) = = 0 ) {
/* Ignore all failures except ENOMEM. If the sysadmin set a bad
* sortlist , just ignore the sortlist , don ' t cause an inoperable
* channel */
status =
ares__parse_sortlist ( & sysconfig - > sortlist , & sysconfig - > nsortlist , value ) ;
if ( status ! = ARES_ENOMEM ) {
status = ARES_SUCCESS ;
}
} else if ( strcmp ( option , " options " ) = = 0 ) {
status = set_options ( sysconfig , value ) ;
}
/* skip over given option name */
p + = len ;
return status ;
}
if ( ! * p ) {
/* no option value */
return NULL ; /* LCOV_EXCL_LINE */
/* This function will only return ARES_SUCCESS or ARES_ENOMEM. Any other
* conditions are ignored . Users may mess up config files , but we want to
* process anything we can . */
static ares_status_t parse_nsswitch_line ( ares_sysconfig_t * sysconfig ,
ares__buf_t * line )
{
char option [ 32 ] ;
ares__buf_t * buf ;
ares_status_t status = ARES_SUCCESS ;
ares__llist_t * sects = NULL ;
/* Ignore lines beginning with a comment */
if ( ares__buf_begins_with ( line , ( const unsigned char * ) " # " , 1 ) ) {
return ARES_SUCCESS ;
}
if ( ( opt [ len - 1 ] ! = ' : ' ) & & ( opt [ len - 1 ] ! = ' = ' ) & & ! ISSPACE ( * p ) ) {
/* whitespace between option name and value is mandatory
for given option names which do not end with ' : ' or ' = ' */
return NULL ;
/* database : values (space delimited) */
status = ares__buf_split ( line , ( const unsigned char * ) " : " , 1 ,
ARES_BUF_SPLIT_TRIM , 2 , & sects ) ;
if ( status ! = ARES_SUCCESS | | ares__llist_len ( sects ) ! = 2 ) {
goto done ;
}
/* skip over whitespace */
while ( * p & & ISSPACE ( * p ) ) {
p + + ;
buf = ares__llist_first_val ( sects ) ;
status = buf_fetch_string ( buf , option , sizeof ( option ) ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
if ( ! * p ) {
/* no option value */
return NULL ;
/* Only support "hosts:" */
if ( strcmp ( option , " hosts " ) ! = 0 ) {
goto done ;
}
/* return pointer to option value */
return p ;
/* Values are space separated */
buf = ares__llist_last_val ( sects ) ;
status = config_lookup ( sysconfig , buf , " \t " ) ;
done :
ares__llist_destroy ( sects ) ;
if ( status ! = ARES_ENOMEM ) {
status = ARES_SUCCESS ;
}
return status ;
}
ares_status_t ares__init_by_environment ( ares_sysconfig_t * sysconfig )
/* This function will only return ARES_SUCCESS or ARES_ENOMEM. Any other
* conditions are ignored . Users may mess up config files , but we want to
* process anything we can . */
static ares_status_t parse_svcconf_line ( ares_sysconfig_t * sysconfig ,
ares__buf_t * line )
{
const char * localdomain ;
const char * res_options ;
ares_status_t status ;
char option [ 32 ] ;
ares__buf_t * buf ;
ares_status_t status = ARES_SUCCESS ;
ares__llist_t * sects = NULL ;
localdomain = getenv ( " LOCALDOMAIN " ) ;
if ( localdomain ) {
char * temp = ares_strdup ( localdomain ) ;
if ( temp = = NULL ) {
return ARES_ENOMEM ;
}
status = config_domain ( sysconfig , temp ) ;
ares_free ( temp ) ;
if ( status ! = ARES_SUCCESS ) {
return status ;
}
/* Ignore lines beginning with a comment */
if ( ares__buf_begins_with ( line , ( const unsigned char * ) " # " , 1 ) ) {
return ARES_SUCCESS ;
}
res_options = getenv ( " RES_OPTIONS " ) ;
if ( res_options ) {
status = set_options ( sysconfig , res_option s) ;
if ( status ! = ARES_SUCCESS ) {
return status ;
}
/* database = values (comma delimited)*/
status = ares__buf_split ( line , ( const unsigned char * ) " = " , 1 ,
ARES_BUF_SPLIT_TRIM , 2 , & sects ) ;
if ( status ! = ARES_SUCCESS | | ares__llist_len ( sects ) ! = 2 ) {
goto done ;
}
return ARES_SUCCESS ;
buf = ares__llist_first_val ( sects ) ;
status = buf_fetch_string ( buf , option , sizeof ( option ) ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
/* Only support "hosts=" */
if ( strcmp ( option , " hosts " ) ! = 0 ) {
goto done ;
}
/* Values are comma separated */
buf = ares__llist_last_val ( sects ) ;
status = config_lookup ( sysconfig , buf , " , " ) ;
done :
ares__llist_destroy ( sects ) ;
if ( status ! = ARES_ENOMEM ) {
status = ARES_SUCCESS ;
}
return status ;
}
ares_status_t ares__init_sysconfig_files ( const ares_channel_t * channel ,
ares_sysconfig_t * sysconfig )
typedef ares_status_t ( * line_callback_t ) ( ares_sysconfig_t * sysconfig ,
ares__buf_t * line ) ;
/* Should only return:
* ARES_ENOTFOUND - file not found
* ARES_EFILE - error reading file ( perms )
* ARES_ENOMEM - out of memory
* ARES_SUCCESS - file processed , doesn ' t necessarily mean it was a good
* file , but we ' re not erroring out if we can ' t parse
* something ( or anything at all ) */
static ares_status_t process_config_lines ( const char * filename ,
ares_sysconfig_t * sysconfig ,
line_callback_t cb )
{
char * p ;
FILE * fp = NULL ;
char * line = NULL ;
size_t linesize = 0 ;
int error ;
const char * resolvconf_path ;
ares_status_t status = ARES_SUCCESS ;
ares_status_t status = ARES_SUCCESS ;
ares__llist_node_t * node ;
ares__llist_t * lines = NULL ;
ares__buf_t * buf = NULL ;
/* Support path for resolvconf filename set by ares_init_options */
if ( channel - > resolvconf_path ) {
resolvconf_path = channel - > resolvconf_path ;
} else {
resolvconf_path = PATH_RESOLV_CONF ;
}
fp = fopen ( resolvconf_path , " r " ) ;
if ( fp ) {
while ( ( status = ares__read_line ( fp , & line , & linesize ) ) = = ARES_SUCCESS ) {
if ( ( p = try_config ( line , " domain " , ' ; ' ) ) ) {
status = config_domain ( sysconfig , p ) ;
} else if ( ( p = try_config ( line , " lookup " , ' ; ' ) ) ) {
status = config_lookup ( sysconfig , p , " bind " , NULL , " file " ) ;
} else if ( ( p = try_config ( line , " search " , ' ; ' ) ) ) {
status = config_search ( sysconfig , p ) ;
} else if ( ( p = try_config ( line , " nameserver " , ' ; ' ) ) ) {
status =
ares__sconfig_append_fromstr ( & sysconfig - > sconfig , p , ARES_TRUE ) ;
} else if ( ( p = try_config ( line , " sortlist " , ' ; ' ) ) ) {
/* Ignore all failures except ENOMEM. If the sysadmin set a bad
* sortlist , just ignore the sortlist , don ' t cause an inoperable
* channel */
status =
ares__parse_sortlist ( & sysconfig - > sortlist , & sysconfig - > nsortlist , p ) ;
if ( status ! = ARES_ENOMEM ) {
status = ARES_SUCCESS ;
}
} else if ( ( p = try_config ( line , " options " , ' ; ' ) ) ) {
status = set_options ( sysconfig , p ) ;
} else {
status = ARES_SUCCESS ;
}
if ( status ! = ARES_SUCCESS ) {
fclose ( fp ) ;
goto done ;
}
}
fclose ( fp ) ;
buf = ares__buf_create ( ) ;
if ( buf = = NULL ) {
status = ARES_ENOMEM ;
goto done ;
}
if ( status ! = ARES_EOF ) {
goto done ;
}
} else {
error = ERRNO ;
switch ( error ) {
case ENOENT :
case ESRCH :
break ;
default :
DEBUGF ( fprintf ( stderr , " fopen() failed with error: %d %s \n " , error ,
strerror ( error ) ) ) ;
DEBUGF ( fprintf ( stderr , " Error opening file: %s \n " , PATH_RESOLV_CONF ) ) ;
status = ARES_EFILE ;
goto done ;
}
status = ares__buf_load_file ( filename , buf ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
status = ares__buf_split ( buf , ( const unsigned char * ) " \n " , 1 ,
ARES_BUF_SPLIT_TRIM , 0 , & lines ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
/* Many systems (Solaris, Linux, BSD's) use nsswitch.conf */
fp = fopen ( " /etc/nsswitch.conf " , " r " ) ;
if ( fp ) {
while ( ( status = ares__read_line ( fp , & line , & linesize ) ) = = ARES_SUCCESS ) {
if ( ( p = try_config ( line , " hosts: " , ' \0 ' ) ) ) {
( void ) config_lookup ( sysconfig , p , " dns " , " resolve " , " files " ) ;
}
}
fclose ( fp ) ;
if ( status ! = ARES_EOF ) {
for ( node = ares__llist_node_first ( lines ) ; node ! = NULL ;
node = ares__llist_node_next ( node ) ) {
ares__buf_t * line = ares__llist_node_val ( node ) ;
status = cb ( sysconfig , line ) ;
if ( status ! = ARES_SUCCESS ) {
goto done ;
}
} else {
error = ERRNO ;
switch ( error ) {
case ENOENT :
case ESRCH :
break ;
default :
DEBUGF ( fprintf ( stderr , " fopen() failed with error: %d %s \n " , error ,
strerror ( error ) ) ) ;
DEBUGF (
fprintf ( stderr , " Error opening file: %s \n " , " /etc/nsswitch.conf " ) ) ;
break ;
}
/* ignore error, maybe we will get luck in next if clause */
}
done :
ares__buf_destroy ( buf ) ;
ares__llist_destroy ( lines ) ;
/* Linux / GNU libc 2.x and possibly others have host.conf */
fp = fopen ( " /etc/host.conf " , " r " ) ;
if ( fp ) {
while ( ( status = ares__read_line ( fp , & line , & linesize ) ) = = ARES_SUCCESS ) {
if ( ( p = try_config ( line , " order " , ' \0 ' ) ) ) {
/* ignore errors */
( void ) config_lookup ( sysconfig , p , " bind " , NULL , " hosts " ) ;
}
}
fclose ( fp ) ;
if ( status ! = ARES_EOF ) {
goto done ;
}
} else {
error = ERRNO ;
switch ( error ) {
case ENOENT :
case ESRCH :
break ;
default :
DEBUGF ( fprintf ( stderr , " fopen() failed with error: %d %s \n " , error ,
strerror ( error ) ) ) ;
DEBUGF ( fprintf ( stderr , " Error opening file: %s \n " , " /etc/host.conf " ) ) ;
break ;
}
return status ;
}
ares_status_t ares__init_sysconfig_files ( const ares_channel_t * channel ,
ares_sysconfig_t * sysconfig )
{
ares_status_t status = ARES_SUCCESS ;
/* Resolv.conf */
status = process_config_lines ( ( channel - > resolvconf_path ! = NULL )
? channel - > resolvconf_path
: PATH_RESOLV_CONF ,
sysconfig , parse_resolvconf_line ) ;
if ( status ! = ARES_SUCCESS & & status ! = ARES_ENOTFOUND ) {
goto done ;
}
/* ignore error, maybe we will get luck in next if clause */
/* Nsswitch.conf */
status =
process_config_lines ( " /etc/nsswitch.conf " , sysconfig , parse_nsswitch_line ) ;
if ( status ! = ARES_SUCCESS & & status ! = ARES_ENOTFOUND ) {
goto done ;
}
/* netsvc.conf */
status =
process_config_lines ( " /etc/netsvc.conf " , sysconfig , parse_svcconf_line ) ;
if ( status ! = ARES_SUCCESS & & status ! = ARES_ENOTFOUND ) {
goto done ;
}
/* Tru64 uses /etc/svc.conf */
fp = fopen ( " /etc/svc.conf " , " r " ) ;
if ( fp ) {
while ( ( status = ares__read_line ( fp , & line , & linesize ) ) = = ARES_SUCCESS ) {
if ( ( p = try_config ( line , " hosts= " , ' \0 ' ) ) ) {
/* ignore errors */
( void ) config_lookup ( sysconfig , p , " bind " , NULL , " local " ) ;
}
}
fclose ( fp ) ;
if ( status ! = ARES_EOF ) {
goto done ;
}
} else {
error = ERRNO ;
switch ( error ) {
case ENOENT :
case ESRCH :
break ;
default :
DEBUGF ( fprintf ( stderr , " fopen() failed with error: %d %s \n " , error ,
strerror ( error ) ) ) ;
DEBUGF ( fprintf ( stderr , " Error opening file: %s \n " , " /etc/svc.conf " ) ) ;
break ;
}
/* ignore error */
/* svc.conf */
status = process_config_lines ( " /etc/svc.conf " , sysconfig , parse_svcconf_line ) ;
if ( status ! = ARES_SUCCESS & & status ! = ARES_ENOTFOUND ) {
goto done ;
}
status = ARES_SUCCESS ;
done :
ares_free ( line ) ;
return status ;
}