#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 <endian.h>
#include <error.h>
#include <msglog.h>
#include <xalloc.h>
#include <symtab.h>
#include <parse.h>
#include <bconf.h>
#include <defs.h>
extern const char *SHM_BCF;
FILE *bcf = NULL;
char *bcf_fname = NULL;
static void *bcf_shm_address = NULL;
static int bcf_shm_fd = -1;
static int snum, rnum, dnum, global_dnum, global_rnum, indent;
static unsigned char *ftab, *stab = NULL;
static Bcf32_Off stabsz = 0;
static Bcf32_Off shoff; /* section header table’s file offset in bytes */
static Bcf32_Off rhoff; /* repository header table’s file offset in bytes */
static Bcf32_Off dtoff; /* data entries table’s file offset in bytes */
static Bcf32_Off stoff; /* string table’s file offset in bytes */
static Bcf32_fhdr *fhdr;
static Bcf32_shdr *shdr;
static Bcf32_rhdr *rhdr;
static Bcf32_dntr *dntr;
void bcf_shm_free( void )
{
if( bcf_shm_address )
{
struct stat st;
if( !fstat( bcf_shm_fd, (struct stat *)&st ) )
{
(void)munmap( bcf_shm_address, (size_t)st.st_size );
bcf_shm_address = NULL;
bcf_shm_fd = shm_unlink( SHM_BCF );
}
}
bcf_shm_address = NULL;
bcf_shm_fd = -1;
}
/************************************************
Функции создания BCF файла по таблице symlist:
*/
static Bcf32_Off extend_strtab( const char *val )
{
Bcf32_Off off = 1;
Bcf32_Off len = 0;
unsigned char *dest = NULL;
if( !stab )
{
/*************************************
The first string in strtab is equal
to "" for empty strings.
*/
stabsz = (Bcf32_Off)(strlen( val ) + 2);
stab = (unsigned char *)xmalloc( (size_t)stabsz );
(void)strncpy( (char *)&stab[1], val, stabsz - 1 );
return off;
}
else
{
off = stabsz;
len = (Bcf32_Off)(strlen( val ) + 1);
stabsz += len;
stab = (unsigned char *)xrealloc( (void *)stab, (size_t)stabsz );
dest = &stab[off];
(void)strncpy( (char *)dest, val, len );
return off;
}
}
static void count_symbols( int *snum, int *rnum, int *dnum, int *gdts, int *grps, SYMBOL *list )
{
SYMBOL *head = list;
if( !head ) return;
while( head )
{
/************************************
count symbols( head ):
*/
switch( head->type )
{
case STRING:
if( indent == 0 ) *gdts += 1;
*dnum += 1;
break;
case PATH:
if( indent == 0 ) *gdts += 1;
*dnum += 1;
break;
case NUMERICAL:
if( indent == 0 ) *gdts += 1;
*dnum += 1;
break;
case SECTION:
*snum += 1;
break;
case REPO:
if( indent == 0 ) *grps += 1;
*rnum += 1;
break;
default:
break;
}
if( head->list ) { indent += 1; count_symbols( snum, rnum, dnum, gdts, grps, head->list ); }
/*
End of count symbols( head ).
************************************/
head = head->next;
}
}
static void write_global_data( SYMBOL *list )
{
SYMBOL *head = list;
if( !head ) return;
while( head )
{
/************************************
global symbols( head ):
*/
switch( head->type )
{
case STRING:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_STRING;
dntr->_v.d_valptr = extend_strtab( (const char *)head->u.string );
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
break;
case PATH:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_PATH;
dntr->_v.d_valptr = extend_strtab( (const char *)head->u.path );
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
break;
case NUMERICAL:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_NUMERICAL;
dntr->_v.d_value = head->u.value;
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
break;
default:
break;
}
/*
End of global symbols( head ).
************************************/
head = head->next;
}
}
static Bcf32_Half write_repo_data( SYMBOL *list )
{
Bcf32_Half cntr = 0;
SYMBOL *head = list;
if( !head ) return cntr;
while( head )
{
/************************************
symbols( head ):
*/
switch( head->type )
{
case STRING:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_STRING;
dntr->_v.d_valptr = extend_strtab( (const char *)head->u.string );
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
++cntr;
break;
case PATH:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_PATH;
dntr->_v.d_valptr = extend_strtab( (const char *)head->u.path );
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
++cntr;
break;
case NUMERICAL:
dntr->d_name = extend_strtab( (const char *)head->name );
dntr->d_type = DT_NUMERICAL;
dntr->_v.d_value = head->u.value;
dtoff += (Bcf32_Off)sizeof( Bcf32_dntr );
++dntr;
++cntr;
break;
default:
break;
}
/*
End of symbols( head ).
************************************/
head = head->next;
}
return cntr;
}
static void write_global_repos( SYMBOL *list )
{
SYMBOL *head = list;
if( !head ) return;
while( head )
{
/************************************
global symbols( head ):
*/
if( head->type == REPO )
{
rhdr->r_rhdr = extend_strtab( (const char *)head->u.path );
rhdr->r_rdata = dtoff;
rhdr->r_dnum = write_repo_data( head->list );
rhoff += (Bcf32_Off)sizeof( Bcf32_rhdr );
++rhdr;
}
/*
End of global symbols( head ).
************************************/
head = head->next;
}
}
static Bcf32_Half write_repos( SYMBOL *list )
{
Bcf32_Half cntr = 0;
SYMBOL *head = list;
if( !head ) return cntr;
while( head )
{
/************************************
symbols( head ):
*/
if( head->type == REPO )
{
rhdr->r_rhdr = extend_strtab( (const char *)head->u.path );
rhdr->r_rdata = dtoff;
rhdr->r_dnum = write_repo_data( head->list );
rhoff += (Bcf32_Off)sizeof( Bcf32_rhdr );
++rhdr;
++cntr;
}
/*
End of symbols( head ).
************************************/
head = head->next;
}
return cntr;
}
static void write_sections( SYMBOL *list )
{
SYMBOL *head = list;
if( !head ) return;
while( head )
{
/************************************
global symbols( head ):
*/
if( head->type == SECTION )
{
(void)strncpy( (char *)shdr->s_name, SMAG_REPOS, (size_t)SI_NIDENT );
shdr->s_type = ST_REPOS;
shdr->s_shdr = extend_strtab( (const char *)head->u.string );
shdr->s_sdata = rhoff;
shdr->s_dnum = write_repos( head->list );;
shoff += (Bcf32_Off)sizeof( Bcf32_shdr );
++shdr;
}
/*
End of global symbols( head ).
************************************/
head = head->next;
}
}
int write_binary_config( void )
{
int ret = 0;
ftab = NULL;
stab = NULL;
snum = 0, rnum = 0, dnum = 0, global_dnum = 0, global_rnum = 0, indent = 0, stabsz = 0;
fhdr = NULL, shdr = NULL, rhdr = NULL, dntr = NULL;
shoff = 0, rhoff = 0, dtoff = 0, stoff = 0;
count_symbols( &snum, &rnum, &dnum, &global_dnum, &global_rnum, symlist );
if( global_dnum ) snum += 1; /* add .global section for global variables */
if( global_rnum ) snum += 1; /* add noname .repos section for global repositories */
shoff = (Bcf32_Off)sizeof( Bcf32_fhdr );
rhoff = (Bcf32_Off)(shoff + snum * sizeof( Bcf32_shdr ));
dtoff = (Bcf32_Off)(rhoff + rnum * sizeof( Bcf32_rhdr ));
stoff = (Bcf32_Off)(dtoff + dnum * sizeof( Bcf32_dntr ));
ftab = (unsigned char *)xmalloc( (size_t)stoff );
/******************
Fill File Header
*/
fhdr = (Bcf32_fhdr *)ftab;
(void)strncpy( (char *)fhdr->b_ident, BCFMAG, (size_t)SZBCFMAG );
fhdr->b_ident[BI_CLASS] = BCF_CLASS_32;
#if __BYTE_ORDER == __LITTLE_ENDIAN
fhdr->b_ident[BI_DATA] = BCF_DATA_LSB;
#else
fhdr->b_ident[BI_DATA] = BCF_DATA_MSB;
#endif
fhdr->b_ident[BI_VERSION] = BV_CURRENT;
fhdr->b_ident[BI_PAD] = BCF_PAD;
fhdr->b_hsize = (Bcf32_Half)sizeof( Bcf32_fhdr );
fhdr->b_shoff = (Bcf32_Off)shoff;
fhdr->b_shentsize = (Bcf32_Half)sizeof( Bcf32_shdr );
fhdr->b_shnum = (Bcf32_Half)snum;
fhdr->b_rhoff = (Bcf32_Off)rhoff;
fhdr->b_rhentsize = (Bcf32_Half)sizeof( Bcf32_rhdr );
fhdr->b_rhnum = (Bcf32_Half)rnum;
fhdr->b_dtoff = (Bcf32_Off)dtoff;
fhdr->b_dtentsize = (Bcf32_Half)sizeof( Bcf32_dntr );
fhdr->b_dtnum = (Bcf32_Half)dnum;
fhdr->b_stoff = (Bcf32_Off)stoff;
shdr = (Bcf32_shdr *)&ftab[shoff];
rhdr = (Bcf32_rhdr *)&ftab[rhoff];
dntr = (Bcf32_dntr *)&ftab[dtoff];
if( global_dnum )
{
(void)strncpy( (char *)shdr->s_name, SMAG_GLOBAL, (size_t)SI_NIDENT );
shdr->s_type = ST_GLOBAL;
shdr->s_shdr = 0; /* Global section is always a first noname .global section */
shdr->s_sdata = fhdr->b_dtoff;
shdr->s_dnum = (Bcf32_Half)global_dnum;
write_global_data( symlist );
shoff += (Bcf32_Off)sizeof( Bcf32_shdr );
++shdr;
}
if( global_rnum )
{
(void)strncpy( (char *)shdr->s_name, SMAG_REPOS, (size_t)SI_NIDENT );
shdr->s_type = ST_REPOS;
shdr->s_shdr = 0; /* Global repos plased in the second noname .repos section */
shdr->s_sdata = fhdr->b_rhoff;
shdr->s_dnum = (Bcf32_Half)global_rnum;
write_global_repos( symlist );
shoff += (Bcf32_Off)sizeof( Bcf32_shdr );
++shdr;
}
write_sections( symlist );
/**********************
Whole BCF file size:
*/
fhdr->b_fsize = (Bcf32_Word)( stoff + stabsz );
bcf_shm_free();
bcf_shm_fd = shm_open( SHM_BCF, O_CREAT | O_TRUNC | O_RDWR, 0644 );
if( bcf_shm_fd != -1 )
{
(void)ftruncate( bcf_shm_fd, (size_t)fhdr->b_fsize );
bcf_shm_address = mmap( NULL, (size_t)fhdr->b_fsize, PROT_WRITE, MAP_SHARED, bcf_shm_fd, 0 );
if( bcf_shm_address != MAP_FAILED )
{
memcpy( bcf_shm_address, (const void *)ftab, (size_t)stoff );
memcpy( bcf_shm_address + (size_t)stoff, (const void *)stab, (size_t)stabsz );
}
}
if( bcf_fname )
{
bcf = fopen( (const char *)bcf_fname, "w" );
if( !bcf ) { FATAL_ERROR( "Cannot open BCF file: %s", bcf_fname ); }
}
(void)fwrite( (void *)ftab, (size_t)stoff, 1, bcf );
(void)fwrite( (void *)stab, (size_t)stabsz, 1, bcf );
if( bcf_fname )
{
if( bcf ) { fclose( bcf ); bcf = NULL; } /* Do not free bcf_fname[] */
}
if( ftab ) { free( ftab ); ftab = NULL; }
if( stab ) { free( stab ); stab = NULL; }
shoff = 0, rhoff = 0, dtoff = 0, stoff = 0;
fhdr = NULL, shdr = NULL, rhdr = NULL, dntr = NULL;
snum = 0, rnum = 0, dnum = 0, global_dnum = 0, global_rnum = 0, indent = 0, stabsz = 0;
ret = 1; /* success */
return ret;
}