diff options
author | kx <kx@radix.pro> | 2023-03-24 03:51:10 +0300 |
---|---|---|
committer | kx <kx@radix.pro> | 2023-03-24 03:51:10 +0300 |
commit | 05d292b208dfe01324826b4c87bbc4da3389a0d5 (patch) | |
tree | b10a2269e9320785f3b61189e75f6778fa167986 /cgitcgi/repolist.c | |
parent | 40ab18a661ff6ada40e73969be293918d346a2f5 (diff) | |
download | cgit-ui-05d292b208dfe01324826b4c87bbc4da3389a0d5.tar.xz |
Version 0.1.7
Diffstat (limited to 'cgitcgi/repolist.c')
-rw-r--r-- | cgitcgi/repolist.c | 878 |
1 files changed, 878 insertions, 0 deletions
diff --git a/cgitcgi/repolist.c b/cgitcgi/repolist.c new file mode 100644 index 0000000..c0208a0 --- /dev/null +++ b/cgitcgi/repolist.c @@ -0,0 +1,878 @@ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#include <stdint.h> +#include <dirent.h> +#include <sys/stat.h> /* chmod(2) */ +#include <sys/file.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <limits.h> +#include <string.h> /* strdup(3) */ +#include <libgen.h> /* basename(3) */ +#include <ctype.h> /* tolower(3) */ +#include <errno.h> +#include <time.h> +#include <sys/time.h> +#include <pwd.h> +#include <grp.h> +#include <stdarg.h> +#include <unistd.h> + +#include <defs.h> +#include <cscm/bcf.h> + +#include <dlist.h> +#include <strbuf.h> +#include <repolist.h> +#include <wrapper.h> + + +#define RLIST_ERRMSG_SIZE 4096 + +void rlist_error( const char *fmt, ... ) +{ + va_list arg_ptr; + char buf[RLIST_ERRMSG_SIZE]; + char msg[RLIST_ERRMSG_SIZE]; + char *format = "%s: %s\n"; + + va_start( arg_ptr, fmt ); + + vsnprintf( msg, RLIST_ERRMSG_SIZE, (const void *)fmt, arg_ptr ); + + va_end( arg_ptr ); /* Reset variable arguments. */ + + snprintf( buf, RLIST_ERRMSG_SIZE, format, "rlist", msg ); + + (void)write( STDERR_FILENO, buf, strlen( buf ) ); + + exit( 1 ); +} + +rlist_errfunc rlist_fatal = rlist_error; + + +struct dlist *config = NULL; + +static void *bcf = NULL; + +static size_t read_bcf( void ) +{ + int fd; + struct stat st; + void *addr; + + fd = shm_open( CGIT_SHM_BCF, O_RDONLY, S_IRUSR | S_IWUSR ); + if( fd == -1 ) + { + rlist_fatal( "Canot open SHM/%s data", "cgit.bcf" ); + return 0; + } + if( !fstat( fd, (struct stat *)&st ) ) + { + addr = mmap( NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if( addr != MAP_FAILED ) + { + bcf = malloc( (size_t)st.st_size ); + if( !bcf ) + { + (void)munmap( addr, (size_t)st.st_size ); + rlist_fatal( "Canot allocate memory for SHM/%s data", "cgit.bcf" ); + return 0; + } + memcpy( bcf, addr, (size_t)st.st_size ); + (void)munmap( addr, (size_t)st.st_size ); + return (size_t)st.st_size; + } + else + { + rlist_fatal( "Canot mmap SHM/%s data", "cgit.bcf" ); + return 0; + } + } + else + { + rlist_fatal( "Canot stat SHM/%s data", "cgit.bcf" ); + return 0; + } +} + + +static void check_bcf_ident( const void *bf, size_t size ) +{ + Bcf32_fhdr *fhdr = (Bcf32_fhdr *)bf; + + if( !fhdr ) + rlist_fatal( "Invalid address of SHM/%s data", "cgit.bcf" ); + + if( (size_t)fhdr->b_fsize != size ) + rlist_fatal( "Binary Config SHM/%s: invalid size", "cgit.bcf" ); + if( memcmp( fhdr->b_ident, BCFMAG, (size_t)SZBCFMAG ) ) + rlist_fatal( "Binary Config SHM/%s: invalid MAGIC number", "cgit.bcf" ); + if( fhdr->b_ident[BI_CLASS] != BCF_CLASS_32 ) + rlist_fatal( "Binary Config SHM/%s: invalid objects class", "cgit.bcf" ); +#if __BYTE_ORDER == __LITTLE_ENDIAN + if( fhdr->b_ident[BI_DATA] != BCF_DATA_LSB ) + rlist_fatal( "Binary Config SHM/%s: invalid byte-order", "cgit.bcf" ); +#else + if( fhdr->b_ident[BI_DATA] != BCF_DATA_MSB ) + rlist_fatal( "Binary Config SHM/%s: invalid byte-order", "cgit.bcf" ); +#endif + if( fhdr->b_ident[BI_VERSION] != BV_CURRENT ) + rlist_fatal( "Binary Config SHM/%s: invalid version", "cgit.bcf" ); +} + + +/*************************************************************** + Print config file functions: + */ +static void __print_global_variable( void *data, void *user_data ) +{ + struct variable *variable = (struct variable *)data; + struct strbuf *sb = (struct strbuf *)user_data; + + if( !variable || !sb ) return; + + switch( variable->type ) + { + case DT_NUMERICAL: + strbuf_addf( sb, " %s = %d;\n", variable->name, variable->_v.val ); + break; + case DT_PATH: + strbuf_addf( sb, " %s = '%s';\n", variable->name, variable->_v.vptr ); + break; + case DT_STRING: + strbuf_addf( sb, " %s = \"%s\";\n", variable->name, variable->_v.vptr ); + break; + default: + break; + } +} + +static void print_global_variables( struct strbuf *sb, struct dlist *list ) +{ + if( list ) { dlist_foreach( list, __print_global_variable, (void *)sb ); } +} + +static void __print_repo_variable( void *data, void *user_data ) +{ + struct variable *variable = (struct variable *)data; + struct strbuf *sb = (struct strbuf *)user_data; + + if( !variable || !sb ) return; + + switch( variable->type ) + { + case DT_NUMERICAL: + strbuf_addf( sb, " %s = %d;\n", variable->name, variable->_v.val ); + break; + case DT_PATH: + strbuf_addf( sb, " %s = '%s';\n", variable->name, variable->_v.vptr ); + break; + case DT_STRING: + strbuf_addf( sb, " %s = \"%s\";\n", variable->name, variable->_v.vptr ); + break; + default: + break; + } +} + +static void print_repo_variables( struct strbuf *sb, struct dlist *list ) +{ + if( list ) { dlist_foreach( list, __print_repo_variable, (void *)sb ); } +} + +static void __print_repo( void *data, void *user_data ) +{ + struct repo *repo = (struct repo *)data; + struct strbuf *sb = (struct strbuf *)user_data; + + if( !repo || !sb ) return; + + strbuf_addf( sb, " repo '%s' {\n", repo->path ); + if( repo->list ) + { + print_repo_variables( sb, repo->list ); + } + strbuf_addf( sb, " }\n\n" ); +} + +static void print_repos( struct strbuf *sb, struct dlist *list ) +{ + if( list ) { dlist_foreach( list, __print_repo, (void *)sb ); } +} + +static void __print_section( void *data, void *user_data ) +{ + struct section *section = (struct section *)data; + struct strbuf *sb = (struct strbuf *)user_data; + + if( !section || !sb ) return; + + if( section->list ) + { + if( section->type == ST_REPOS ) + { + strbuf_addf( sb, "section \"%s\" {\n\n", section->name ); + print_repos( sb, section->list ); + strbuf_addf( sb, "}\n\n" ); + } + else if( section->type == ST_GLOBAL ) + { + strbuf_addf( sb, "section \".global\" {\n" ); + print_global_variables( sb, section->list ); + strbuf_addf( sb, "}\n\n" ); + } + } +} + +void print_config( struct strbuf *sb, struct dlist *list ) +{ + strbuf_addf( sb, "<pre><code class='language-C'>\n" ); + strbuf_addf( sb, "/*******************************************************\n" ); + strbuf_addf( sb, " Global variables are propagate into repo sections but\n" ); + strbuf_addf( sb, " their values overrides by correspond repo variables.\n" ); + strbuf_addf( sb, " */\n\n" ); + if( list ) { dlist_foreach( list, __print_section, (void *)sb ); } + strbuf_addf( sb, "</code></pre>\n" ); +} +/* + End of print config file functions. + ***************************************************************/ + + +/************************** + lookup variable in repo: + */ +static int __compare_variables_by_name( const void *a, const void *b ) +{ + struct variable *va = (struct variable *)a; + struct variable *vb = (struct variable *)b; + + if( !va || !vb ) return -1; + + return strcmp( (const char *)va->name, (const char *)vb->name ); +} + +struct variable *lookup( struct repo *repo, struct variable *variable ) +{ + struct dlist *found = NULL; + + if( !repo || !repo->list ) return NULL; + + found = dlist_find_data( repo->list, __compare_variables_by_name, (const void *)variable ); + if( found ) + return (struct variable *)(found->data); + return NULL; +} + +struct variable *lookup_global( struct section *section, struct variable *variable ) +{ + struct dlist *found = NULL; + + if( !section || !section->list ) return NULL; + + found = dlist_find_data( section->list, __compare_variables_by_name, (const void *)variable ); + if( found ) + return (struct variable *)(found->data); + return NULL; +} + +/************** + lookup repo: + */ +struct repo *lookup_repo( struct dlist *config, const char *path ) +{ + struct dlist *list = NULL; + + if( !config || !path ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + struct repo *repo = (struct repo *)rlist->data; + if( !strcmp( (const char *)repo->path, path ) ) + return repo; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return NULL; +} + +/***************** + lookup section: + */ +struct section *lookup_section( struct dlist *config, const char *name ) +{ + struct dlist *list = NULL; + + if( !config || !name ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section && section->type == ST_REPOS && !strcmp( (const char *)section->name, name ) ) + return section; + + list = dlist_next( list ); + } + + return NULL; +} + +/************************ + lookup global section: + */ +struct section *lookup_global_section( struct dlist *config ) +{ + struct dlist *list = NULL; + + if( !config ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section && section->type == ST_GLOBAL ) + return section; + + list = dlist_next( list ); + } + + return NULL; +} + +/****************** + repolist length: + */ +int repolist_length( struct dlist *config ) +{ + struct dlist *list = NULL; + int length = 0; + + if( !config ) return length; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + ++length; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return length; +} + +/*************** + repolist nth: + */ +struct repo *repolist_nth( struct dlist *config, int n ) +{ + struct dlist *list = NULL; + int length = 0; + + if( !config || n < 0 ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + if( length == n ) + { + struct repo *repo = (struct repo *)rlist->data; + return repo; + } + ++length; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return NULL; +} + +/************************** + repo position in config: + */ +int repo_position( struct dlist *config, struct repo *repo ) +{ + struct dlist *list = NULL; + int position = -1; + + if( !config || !repo ) return position; + + position = 0; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + if( (struct repo *)rlist->data == repo ) + { + return position; + } + ++position; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return -1; +} + + +/************************************** + parent section node of repolist nth: + */ +struct dlist *parent_section_node_repolist_nth( struct dlist *config, int n ) +{ + struct dlist *list = NULL; + int length = 0; + + if( !config || n < 0 ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + if( length == n ) + { + return list; + } + ++length; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return NULL; +} + +/************************************ + parent rlist node of repolist nth: + */ +struct dlist *parent_rlist_node_repolist_nth( struct dlist *config, int n ) +{ + struct dlist *list = NULL; + int length = 0; + + if( !config || n < 0 ) return NULL; + + list = config; + while( list ) + { + struct section *section = (struct section *)list->data; + + if( section->type == ST_REPOS ) + { + struct dlist *rlist = section->list; + while( rlist ) + { + if( length == n ) + { + return rlist; + } + ++length; + rlist = dlist_next( rlist ); + } + } + list = dlist_next( list ); + } + + return NULL; +} + + + +/********************************************** + Provide all global variables into each repo + if that variable is not present in the repo: + */ +static void __provide_foreach_data( void *data, void *user_data ) +{ + struct variable *variable = (struct variable *)data; + struct repo *repo = (struct repo *)user_data; + + if( !repo || !variable ) return; + + if( !lookup( repo, variable ) ) + { + struct variable *var = (struct variable *)xmalloc( sizeof(struct variable) ); + memcpy( (void *)var, (void *)variable, sizeof(struct variable) ); + repo->list = dlist_append( repo->list, (void *)var ); + } +} + +static void __provide_foreach_repos( void *data, void *user_data ) +{ + struct section *global = (struct section *)user_data; + + if( !global || !global->list ) return; + + dlist_foreach( global->list, __provide_foreach_data, data ); +} + +static void __provide_foreach_sections( void *data, void *user_data ) +{ + struct section *section = (struct section *)data; + if( !section || section->type == ST_GLOBAL || !section->list ) return; + + dlist_foreach( section->list, __provide_foreach_repos, user_data ); +} + +static void provide_global_data( struct dlist *tree, struct section *global ) +{ + if( tree ) { dlist_foreach( tree, __provide_foreach_sections, (void *)global ); } +} +/* + **********************************************/ + +/********************************************** + Free REPO list functions: + */ +static void __free_variable( void *data, void *user_data ) +{ + struct variable *variable = (struct variable *)data; + if( variable ) free( variable ); +} + +static void free_variables( struct dlist *list ) +{ + if( list ) { dlist_free( list, __free_variable ); } +} + +static void __free_repo( void *data, void *user_data ) +{ + struct repo *repo = (struct repo *)data; + if( !repo ) return; + if( repo->list ) { free_variables( repo->list ); } + free( repo ); +} + +static void free_repos( struct dlist *list ) +{ + if( list ) { dlist_free( list, __free_repo ); } +} + +static void __free_section( void *data, void *user_data ) +{ + struct section *section = (struct section *)data; + if( !section ) return; + + if( section->list ) + { + if( section->type == ST_GLOBAL ) + free_variables( section->list ); + else if( section->type == ST_REPOS ) + free_repos( section->list ); + } + free( section ); +} + +static void free_repolist( struct dlist *list ) +{ + if( list ) { dlist_free( list, __free_section ); } +} +/* + **********************************************/ + +void free_config( void ) +{ + free_repolist( config ); config = NULL; + if( bcf ) { free( bcf ); bcf = NULL; } +} + +static struct dlist *read_repolist( const void *bf ) +{ + struct dlist *tree = NULL; + Bcf32_fhdr *fhdr = NULL; + unsigned char *ftab, *stab; + + ftab = (unsigned char *)bf; + fhdr = (Bcf32_fhdr *)ftab; + + if( !fhdr ) + return tree; + + stab = (unsigned char *)(ftab + (int)fhdr->b_stoff); + +#if __DEBUG__ == 1 + fprintf( stderr, "BCF: header's size in bytes: %d\n", fhdr->b_hsize ); + fprintf( stderr, "BCF: Whole BCF file size in bytes: %d\n", fhdr->b_fsize ); + fprintf( stderr, "BCF: section header table’s file offset in bytes: %d\n", fhdr->b_shoff ); + fprintf( stderr, "BCF: section header's size in bytes: %d\n", fhdr->b_shentsize ); + fprintf( stderr, "BCF: number of entries in section headers table: %d\n", fhdr->b_shnum ); + fprintf( stderr, "BCF: repository header table’s file offset in bytes: %d\n", fhdr->b_rhoff ); + fprintf( stderr, "BCF: repository header's size in bytes: %d\n", fhdr->b_rhentsize ); + fprintf( stderr, "BCF: number of entries in repository headers table: %d\n", fhdr->b_rhnum ); + fprintf( stderr, "BCF: data entries table’s file offset in bytes: %d\n", fhdr->b_dtoff ); + fprintf( stderr, "BCF: data entry's size in bytes: %d\n", fhdr->b_dtentsize ); + fprintf( stderr, "BCF: number of entries in data entries table: %d\n", fhdr->b_dtnum ); + fprintf( stderr, "BCF: string table’s file offset in bytes: %d\n\n", fhdr->b_stoff ); +#endif + + { + Bcf32_shdr *shdr = NULL; + int s = 0; + + struct section *global = NULL; + + shdr = (Bcf32_shdr *)((unsigned char *)bf + (int)fhdr->b_shoff); + + while( s < fhdr->b_shnum ) + { +#if __DEBUG__ == 1 + fprintf( stderr, "SECTION: s_name: %s\n", shdr->s_name ); + fprintf( stderr, "SECTION: s_type: %d\n", shdr->s_type ); + fprintf( stderr, "SECTION: s_shdr (offset in string table): %d\n", shdr->s_shdr ); + fprintf( stderr, "SECTION: s_sdata (file offset to data): %d\n", shdr->s_sdata ); + fprintf( stderr, "SECTION: s_dnum (number of data entries): %d\n", shdr->s_dnum ); + fprintf( stderr, "SECTION: name: \"%s\"\n\n", stab + (int)shdr->s_shdr ); +#endif + + if( shdr->s_type == ST_GLOBAL ) + { + Bcf32_dntr *dntr = NULL; + int d = 0; + + struct section *sec = NULL; + sec = (struct section *)xmalloc( sizeof(struct section) ); + sec->type = ST_GLOBAL; + sec->name = (unsigned char *)(stab + (int)shdr->s_shdr); /*do not allocate, all in bcf */ + tree = dlist_append( tree, (void *)sec ); + global = sec; + + dntr = (Bcf32_dntr *)(ftab + (int)shdr->s_sdata); + + while( d < shdr->s_dnum ) + { +#if __DEBUG__ == 1 + fprintf( stderr, "DATA: d_name: %s\n", stab + (int)dntr->d_name ); +#endif + + switch( dntr->d_type ) + { + case DT_NUMERICAL: +#if __DEBUG__ == 1 + fprintf( stderr, "DATA: _v.d_value: %d\n\n", dntr->_v.d_value ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_NUMERICAL; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.val = (int)dntr->_v.d_value; + sec->list = dlist_append( sec->list, (void *)var ); + } + break; + case DT_PATH: +#if __DEBUG__ == 1 + fprintf( stderr, "DATA: _v.d_valptr (path): '%s';\n\n", stab + (int)dntr->_v.d_valptr ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_PATH; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr); + sec->list = dlist_append( sec->list, (void *)var ); + } + break; + case DT_STRING: +#if __DEBUG__ == 1 + fprintf( stderr, "DATA: _v.d_valptr (string): \"%s\";\n\n", stab + (int)dntr->_v.d_valptr ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_STRING; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr); + sec->list = dlist_append( sec->list, (void *)var ); + } + break; + default: + break; + } + + ++d; + ++dntr; + + } /* End of while( global data ) */ + + } + else if( shdr->s_type == ST_REPOS ) + { + Bcf32_rhdr *rhdr = NULL; + int r = 0; + + struct section *sec = NULL; + sec = (struct section *)xmalloc( sizeof(struct section) ); + sec->type = ST_REPOS; + sec->name = (unsigned char *)(stab + (int)shdr->s_shdr); /*do not allocate, all in bcf */ + tree = dlist_append( tree, (void *)sec ); + + rhdr = (Bcf32_rhdr *)(ftab + (int)shdr->s_sdata); + + while( r < shdr->s_dnum ) + { + int d = 0; + Bcf32_dntr *dntr = NULL; + + struct repo *repo = NULL; + repo = (struct repo *)xmalloc( sizeof(struct repo) ); + repo->path = (unsigned char *)(stab + (int)rhdr->r_rhdr); /*do not allocate, all in bcf */ + sec->list = dlist_append( sec->list, (void *)repo ); + +#if __DEBUG__ == 1 + fprintf( stderr, "REPO: path: %s\n", stab + (int)rhdr->r_rhdr ); +#endif + dntr = (Bcf32_dntr *)(ftab + (int)rhdr->r_rdata); + + while( d < rhdr->r_dnum ) + { +#if __DEBUG__ == 1 + fprintf( stderr, "REPO's DATA: d_name: %s\n", stab + (int)dntr->d_name ); +#endif + switch( dntr->d_type ) + { + case DT_NUMERICAL: +#if __DEBUG__ == 1 + fprintf( stderr, "REPO's DATA: _v.d_value: %d\n\n", dntr->_v.d_value ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_NUMERICAL; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.val = (int)dntr->_v.d_value; + repo->list = dlist_append( repo->list, (void *)var ); + } + break; + case DT_PATH: +#if __DEBUG__ == 1 + fprintf( stderr, "REPO's DATA: _v.d_valptr (path): '%s';\n\n", stab + (int)dntr->_v.d_valptr ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_PATH; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr); + repo->list = dlist_append( repo->list, (void *)var ); + } + break; + case DT_STRING: +#if __DEBUG__ == 1 + fprintf( stderr, "REPO's DATA: _v.d_valptr (string): \"%s\";\n\n", stab + (int)dntr->_v.d_valptr ); +#endif + { + struct variable *var = NULL; + var = (struct variable *)xmalloc( sizeof(struct variable) ); + var->type = DT_STRING; + var->name = (unsigned char *)(stab + (int)dntr->d_name); /*do not allocate, all in bcf */ + var->_v.vptr = (unsigned char *)(stab + (int)dntr->_v.d_valptr); + repo->list = dlist_append( repo->list, (void *)var ); + } + break; + default: + break; + } + + ++d; + ++dntr; + + } /* End of while( repo data ) */ + + ++r; + ++rhdr; + + } /* End of while( repos ) */ + +#if __DEBUG__ == 1 + fprintf( stderr, "\n" ); +#endif + } + else + { + rlist_fatal( "Invalid section in the SHM/%s data", "cgit.bcf" ); +#if __DEBUG__ == 1 + fprintf( stderr, "SECTION: empty\n" ); +#endif + } + + ++s; + ++shdr; + + } /* End of while( sections ) */ + + if( global ) + provide_global_data( tree, global ); + } + + return tree; +} + + +struct dlist *read_config( void ) +{ + size_t bsize = 0; + + if( (bsize = read_bcf()) ) + { + check_bcf_ident( bcf, bsize ); /* fatal on error */ + return read_repolist( bcf ); + } + + return NULL; +} |