2012-05-07 20:55:45 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
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 Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <assert.h>
# include <string.h>
# include <unistd.h>
# include <errno.h>
# include <stdlib.h>
# include <stdio.h>
# include <sys/stat.h>
# include <dirent.h>
# include "macro.h"
# include "util.h"
# include "missing.h"
# include "log.h"
# include "strv.h"
2012-05-07 23:36:12 +04:00
# include "path-util.h"
2012-05-07 20:55:45 +04:00
# include "hashmap.h"
# include "conf-files.h"
2013-02-08 13:22:02 +04:00
static int files_add ( Hashmap * h , const char * root , const char * path , const char * suffix ) {
2013-02-12 02:48:36 +04:00
_cleanup_closedir_ DIR * dir = NULL ;
2013-02-08 13:45:30 +04:00
_cleanup_free_ char * dirpath = NULL ;
2012-05-07 20:55:45 +04:00
2013-02-08 13:45:30 +04:00
if ( asprintf ( & dirpath , " %s%s " , root ? root : " " , path ) < 0 )
return - ENOMEM ;
dir = opendir ( dirpath ) ;
2012-05-07 20:55:45 +04:00
if ( ! dir ) {
if ( errno = = ENOENT )
return 0 ;
return - errno ;
}
for ( ; ; ) {
2012-09-20 00:21:09 +04:00
struct dirent * de ;
union dirent_storage buf ;
2012-05-07 20:55:45 +04:00
char * p ;
2013-02-12 02:48:36 +04:00
int r ;
2012-05-07 20:55:45 +04:00
2013-02-12 02:48:36 +04:00
r = readdir_r ( dir , & buf . de , & de ) ;
if ( r ! = 0 )
return - r ;
2012-05-07 20:55:45 +04:00
if ( ! de )
break ;
if ( ! dirent_is_file_with_suffix ( de , suffix ) )
continue ;
2013-02-12 02:48:36 +04:00
p = strjoin ( dirpath , " / " , de - > d_name , NULL ) ;
if ( ! p )
2013-02-08 13:45:30 +04:00
return - ENOMEM ;
2012-05-07 20:55:45 +04:00
2013-02-12 02:48:36 +04:00
r = hashmap_put ( h , path_get_file_name ( p ) , p ) ;
if ( r = = - EEXIST ) {
log_debug ( " Skipping overridden file: %s. " , p ) ;
free ( p ) ;
} else if ( r < 0 ) {
free ( p ) ;
return r ;
} else if ( r = = 0 ) {
log_debug ( " Duplicate file %s " , p ) ;
2012-05-07 20:55:45 +04:00
free ( p ) ;
}
}
2013-02-08 13:45:30 +04:00
return 0 ;
2012-05-07 20:55:45 +04:00
}
static int base_cmp ( const void * a , const void * b ) {
const char * s1 , * s2 ;
s1 = * ( char * const * ) a ;
s2 = * ( char * const * ) b ;
2012-05-07 23:36:12 +04:00
return strcmp ( path_get_file_name ( s1 ) , path_get_file_name ( s2 ) ) ;
2012-05-07 20:55:45 +04:00
}
2013-02-12 02:48:36 +04:00
static int conf_files_list_strv_internal ( char * * * strv , const char * suffix , const char * root , char * * dirs ) {
Hashmap * fh ;
char * * files , * * p ;
2012-07-25 01:18:25 +04:00
int r ;
2012-05-07 20:55:45 +04:00
2013-02-12 02:48:36 +04:00
assert ( strv ) ;
assert ( suffix ) ;
/* This alters the dirs string array */
if ( ! path_strv_canonicalize_uniq ( dirs ) )
return - ENOMEM ;
2012-05-07 20:55:45 +04:00
fh = hashmap_new ( string_hash_func , string_compare_func ) ;
2013-02-12 02:48:36 +04:00
if ( ! fh )
return - ENOMEM ;
2012-05-07 20:55:45 +04:00
STRV_FOREACH ( p , dirs ) {
2013-02-08 13:22:02 +04:00
r = files_add ( fh , root , * p , suffix ) ;
2013-02-12 02:48:36 +04:00
if ( r = = - ENOMEM ) {
hashmap_free_free ( fh ) ;
return r ;
} else if ( r < 0 )
log_debug ( " Failed to search for files in %s: %s " ,
* p , strerror ( - r ) ) ;
2012-05-07 20:55:45 +04:00
}
files = hashmap_get_strv ( fh ) ;
if ( files = = NULL ) {
2013-02-12 02:48:36 +04:00
hashmap_free_free ( fh ) ;
return - ENOMEM ;
2012-05-07 20:55:45 +04:00
}
2013-02-12 02:48:36 +04:00
2013-10-12 03:33:13 +04:00
qsort_safe ( files , hashmap_size ( fh ) , sizeof ( char * ) , base_cmp ) ;
2013-02-12 02:48:36 +04:00
* strv = files ;
2012-05-07 20:55:45 +04:00
hashmap_free ( fh ) ;
2013-02-12 02:48:36 +04:00
return 0 ;
}
2013-03-29 04:17:24 +04:00
int conf_files_list_strv ( char * * * strv , const char * suffix , const char * root , const char * const * dirs ) {
2013-02-12 02:48:36 +04:00
_cleanup_strv_free_ char * * copy = NULL ;
assert ( strv ) ;
assert ( suffix ) ;
copy = strv_copy ( ( char * * ) dirs ) ;
if ( ! copy )
return - ENOMEM ;
return conf_files_list_strv_internal ( strv , suffix , root , copy ) ;
2012-05-07 20:55:45 +04:00
}
2013-02-08 13:22:02 +04:00
int conf_files_list ( char * * * strv , const char * suffix , const char * root , const char * dir , . . . ) {
2013-10-29 22:53:43 +04:00
char * * dirs ;
2013-02-12 02:48:36 +04:00
assert ( strv ) ;
assert ( suffix ) ;
2012-05-07 20:55:45 +04:00
2013-10-29 22:53:43 +04:00
dirs = strv_from_stdarg_alloca ( dir ) ;
2013-02-12 02:48:36 +04:00
return conf_files_list_strv_internal ( strv , suffix , root , dirs ) ;
}
2012-05-07 20:55:45 +04:00
2013-02-12 02:48:36 +04:00
int conf_files_list_nulstr ( char * * * strv , const char * suffix , const char * root , const char * d ) {
_cleanup_strv_free_ char * * dirs = NULL ;
assert ( strv ) ;
assert ( suffix ) ;
dirs = strv_split_nulstr ( d ) ;
if ( ! dirs )
return - ENOMEM ;
2012-05-07 20:55:45 +04:00
2013-02-12 02:48:36 +04:00
return conf_files_list_strv_internal ( strv , suffix , root , dirs ) ;
2012-05-07 20:55:45 +04:00
}