#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "rtc.h"
#include "_crle.h"
#include "msg.h"
#define MAXNBKTS 10007
static const int hashsize[] = {
3, 7, 13, 31, 53, 67, 83, 97,
101, 151, 211, 251, 307, 353, 401, 457, 503,
557, 601, 653, 701, 751, 809, 859, 907, 953,
1009, 1103, 1201, 1301, 1409, 1511, 1601, 1709, 1801,
1901, 2003, 2111, 2203, 2309, 2411, 2503, 2609, 2707,
2801, 2903, 3001, 3109, 3203, 3301, 3407, 3511, 3607,
3701, 3803, 3907, 4001, 5003, 6101, 7001, 8101, 9001,
MAXNBKTS
};
int
genconfig(Crle_desc *crle)
{
int ndx, bkt;
size_t size, hashoff = 0, stroff = 0, objoff = 0;
size_t diroff = 0, fileoff = 0, envoff = 0;
size_t fltroff = 0, flteoff = 0;
Addr addr;
Rtc_id *id;
Rtc_head *head;
Word *hashtbl, *hashbkt, *hashchn, hashbkts = 0;
char *strtbl, *_strtbl;
Rtc_obj *objtbl;
Rtc_dir *dirtbl;
Rtc_file *filetbl;
Rtc_env *envtbl;
Rtc_fltr *fltrtbl;
Rtc_flte *fltetbl, * _fltetbl;
Hash_tbl *stbl = crle->c_strtbl;
Hash_ent *ent;
size = S_ROUND(sizeof (Rtc_head), sizeof (Word));
if (crle->c_hashstrnum) {
hashoff = size;
crle->c_hashstrnum++;
for (ndx = 0; ndx < (sizeof (hashsize) / sizeof (int)); ndx++) {
if (crle->c_hashstrnum > hashsize[ndx])
continue;
hashbkts = hashsize[ndx];
break;
}
if (hashbkts == 0)
hashbkts = MAXNBKTS;
size += ((2 + hashbkts + crle->c_hashstrnum) * sizeof (Word));
size = S_ROUND(size, sizeof (Lword));
objoff = size;
size += (crle->c_hashstrnum *
S_ROUND(sizeof (Rtc_obj), sizeof (Lword)));
fileoff = size;
size += S_ROUND((crle->c_filenum * sizeof (Rtc_file)),
sizeof (Word));
diroff = size;
size += S_ROUND((crle->c_dirnum * sizeof (Rtc_dir)),
sizeof (Word));
}
if (crle->c_envnum) {
envoff = size;
size += S_ROUND(((crle->c_envnum + 1) * sizeof (Rtc_env)),
sizeof (Word));
}
if (crle->c_fltrnum) {
fltroff = size;
size += S_ROUND(((crle->c_fltrnum + 1) * sizeof (Rtc_fltr)),
sizeof (Word));
flteoff = size;
size += S_ROUND((crle->c_fltenum * sizeof (Rtc_flte)),
sizeof (Word));
}
if (crle->c_strsize) {
stroff = size;
size += S_ROUND(crle->c_strsize, sizeof (Word));
}
if (crle->c_flags & CRLE_ADDID)
size += sizeof (Rtc_id);
if (ftruncate(crle->c_tempfd, size) == -1) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
crle->c_name, crle->c_tempname, strerror(err));
(void) close(crle->c_tempfd);
return (1);
}
if ((addr = (Addr)mmap(0, size, (PROT_READ | PROT_WRITE), MAP_SHARED,
crle->c_tempfd, 0)) == (Addr)-1) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_MMAP),
crle->c_name, crle->c_tempname, strerror(err));
(void) close(crle->c_tempfd);
return (1);
}
crle->c_tempaddr = addr;
crle->c_tempsize = size;
if (crle->c_flags & CRLE_ADDID) {
static const Rtc_id id_template = {
RTC_ID_MAG0, RTC_ID_MAG1, RTC_ID_MAG2, RTC_ID_MAG3,
M_CLASS, M_DATA, M_MACH,
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
id = (Rtc_id *) addr;
*id = id_template;
addr += sizeof (Rtc_id);
} else {
id = NULL;
}
crle->c_tempheadaddr = addr;
head = (Rtc_head *)addr;
head->ch_hash = hashoff;
hashtbl = (Word *)(CAST_PTRINT(char *, head->ch_hash) + addr);
head->ch_obj = objoff;
objtbl = (Rtc_obj *)(CAST_PTRINT(char *, head->ch_obj) + addr);
objtbl = (Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1), sizeof (Lword));
head->ch_file = fileoff;
filetbl = (Rtc_file *)(CAST_PTRINT(char *, head->ch_file) + addr);
head->ch_dir = diroff;
dirtbl = (Rtc_dir *)(CAST_PTRINT(char *, head->ch_dir) + addr);
head->ch_env = envoff;
envtbl = (Rtc_env *)(CAST_PTRINT(char *, head->ch_env) + addr);
head->ch_fltr = fltroff;
fltrtbl = (Rtc_fltr *)(CAST_PTRINT(char *, head->ch_fltr) + addr);
head->ch_flte = flteoff;
fltetbl = _fltetbl = (Rtc_flte *)(CAST_PTRINT(char *, head->ch_flte) +
addr);
head->ch_str = stroff;
strtbl = _strtbl = (char *)(CAST_PTRINT(char *, head->ch_str) + addr);
head->ch_version = RTC_VER_CURRENT;
if (crle->c_flags & CRLE_ALTER)
head->ch_cnflags |= RTC_HDR_ALTER;
if (crle->c_flags & CRLE_DUMP) {
head->ch_cnflags |= RTC_HDR_IGNORE;
head->ch_dlflags = crle->c_dlflags;
}
#ifdef _ELF64
head->ch_cnflags |= RTC_HDR_64;
#endif
head->ch_cnflags |= RTC_HDR_UPM;
if (crle->c_hashstrnum) {
hashtbl[0] = hashbkts;
hashtbl[1] = crle->c_hashstrnum;
hashbkt = &hashtbl[2];
hashchn = &hashtbl[2 + hashbkts];
(void) memset(hashchn, 0, (crle->c_hashstrnum * sizeof (Word)));
(void) memset(dirtbl, 0, (strtbl - (char *)dirtbl));
for (ndx = 1, bkt = 0; bkt < stbl->t_size; bkt++) {
for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
Word hashval;
Hash_obj *obj = ent->e_obj;
char *dir = (char *)ent->e_key;
Rtc_dir *_dirtbl;
if ((obj == NULL) ||
((obj->o_flags & RTC_OBJ_DIRENT) == 0))
continue;
objtbl->co_hash = ent->e_hash;
objtbl->co_id = ent->e_id;
objtbl->co_flags = obj->o_flags | ent->e_flags;
objtbl->co_info = obj->o_info;
ent->e_cobj = objtbl;
objtbl->co_name = (Addr)(_strtbl - strtbl);
(void) strcpy(_strtbl, dir);
_strtbl += strlen(dir) + 1;
_dirtbl = &dirtbl[ent->e_id - 1];
_dirtbl->cd_file =
CAST_PTRINT(Word, ((char *)filetbl- addr));
_dirtbl->cd_obj =
CAST_PTRINT(Word, ((char *)objtbl - addr));
filetbl = (Rtc_file *)((char *)filetbl +
((ent->e_cnt + 1) * sizeof (Rtc_file)));
hashval = ent->e_hash % hashbkts;
hashchn[ndx] = hashbkt[hashval];
hashbkt[hashval] = ndx++;
objtbl =
(Rtc_obj *)S_ROUND((uintptr_t)(objtbl + 1),
sizeof (Lword));
}
}
for (bkt = 0; bkt < stbl->t_size; bkt++) {
for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
Word hashval;
Hash_obj *obj = ent->e_obj;
char *file = (char *)ent->e_key;
char *_str;
Rtc_dir *_dirtbl;
Rtc_file *_filetbl;
int _id;
if ((obj == NULL) ||
(obj->o_flags & RTC_OBJ_DIRENT) ||
(ent->e_off))
continue;
objtbl->co_hash = ent->e_hash;
objtbl->co_id = ent->e_id;
objtbl->co_flags = obj->o_flags | ent->e_flags;
objtbl->co_info = obj->o_info;
ent->e_cobj = objtbl;
objtbl->co_name = (Addr)(_strtbl - strtbl);
(void) strcpy(_strtbl, file);
_strtbl += strlen(file) + 1;
_dirtbl = &dirtbl[ent->e_id - 1];
_filetbl = (Rtc_file *)(CAST_PTRINT(char *,
_dirtbl->cd_file) + addr);
_id = --ent->e_dir->e_cnt;
_filetbl[_id].cf_obj =
CAST_PTRINT(Word, ((char *)objtbl - addr));
if ((objtbl->co_flags & RTC_OBJ_ALTER) &&
(obj->o_calter == 0)) {
_str = obj->o_alter;
objtbl->co_alter = obj->o_calter =
(Addr)(_strtbl - strtbl);
(void) strcpy(_strtbl, _str);
_strtbl += strlen(_str) + 1;
} else
objtbl->co_alter = obj->o_calter;
if ((objtbl->co_flags &
(RTC_OBJ_APP | RTC_OBJ_REALPTH)) ==
(RTC_OBJ_APP | RTC_OBJ_REALPTH))
head->ch_app = _filetbl[_id].cf_obj;
hashval = ent->e_hash % hashbkts;
hashchn[ndx] = hashbkt[hashval];
hashbkt[hashval] = ndx++;
objtbl = (Rtc_obj *)
S_ROUND((uintptr_t)(objtbl + 1),
sizeof (Lword));
}
}
for (bkt = 0; bkt < stbl->t_size; bkt++) {
for (ent = stbl->t_entry[bkt]; ent; ent = ent->e_next) {
Word hashval;
Hash_obj * obj = ent->e_obj;
Rtc_dir * _dirtbl;
Rtc_file * _filetbl;
int _id;
if (ent->e_off == 0)
continue;
objtbl->co_hash = ent->e_hash;
objtbl->co_id = ent->e_id;
objtbl->co_flags = obj->o_flags | ent->e_flags;
objtbl->co_info = obj->o_info;
objtbl->co_alter = obj->o_calter;
ent->e_cobj = objtbl;
objtbl->co_name = (Addr)(CAST_PTRINT(char *,
ent->e_path->e_cobj->co_name) + ent->e_off);
_dirtbl = &dirtbl[ent->e_id - 1];
_filetbl = (Rtc_file *)
(CAST_PTRINT(char *, _dirtbl->cd_file) +
addr);
_id = --ent->e_dir->e_cnt;
_filetbl[_id].cf_obj =
CAST_PTRINT(Word, ((char *)objtbl - addr));
hashval = ent->e_hash % hashbkts;
hashchn[ndx] = hashbkt[hashval];
hashbkt[hashval] = ndx++;
objtbl = (Rtc_obj *)
S_ROUND((uintptr_t)(objtbl + 1),
sizeof (Lword));
}
}
}
if (crle->c_edlibpath) {
head->ch_edlibpath = head->ch_str + (_strtbl - strtbl);
(void) strcpy(_strtbl, crle->c_edlibpath);
_strtbl += strlen((char *)crle->c_edlibpath) + 1;
} else
head->ch_edlibpath = 0;
head->ch_adlibpath = 0;
if (crle->c_eslibpath) {
head->ch_eslibpath = head->ch_str + (_strtbl - strtbl);
(void) strcpy(_strtbl, crle->c_eslibpath);
_strtbl += strlen((char *)crle->c_eslibpath) + 1;
} else
head->ch_eslibpath = 0;
head->ch_aslibpath = 0;
if (crle->c_envnum) {
Env_desc *env;
Aliste idx;
for (APLIST_TRAVERSE(crle->c_env, idx, env)) {
envtbl->env_str = head->ch_str + (_strtbl - strtbl);
envtbl->env_flags = env->e_flags;
(void) strcpy(_strtbl, env->e_str);
_strtbl += env->e_totsz;
envtbl++;
}
envtbl->env_str = 0;
envtbl->env_flags = 0;
}
if (crle->c_fltrnum) {
Flt_desc *flt;
Aliste idx1;
for (APLIST_TRAVERSE(crle->c_flt, idx1, flt)) {
Hash_ent *flte;
Aliste idx2;
fltrtbl->fr_filter = flt->f_fent->e_cobj->co_name;
fltrtbl->fr_string = _strtbl - strtbl;
(void) strcpy(_strtbl, flt->f_str);
_strtbl += flt->f_strsz;
fltrtbl->fr_filtee = (Word)
((uintptr_t)_fltetbl - (uintptr_t)fltetbl);
for (APLIST_TRAVERSE(flt->f_filtee, idx2, flte)) {
_fltetbl->fe_filtee = flte->e_cobj->co_name;
_fltetbl++;
}
_fltetbl->fe_filtee = 0;
_fltetbl++, fltrtbl++;
}
fltrtbl->fr_filter = 0;
fltrtbl->fr_filtee = 0;
}
(void) close(crle->c_tempfd);
if (msync((void *)crle->c_tempaddr, crle->c_tempsize, MS_ASYNC) == -1) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
crle->c_name, crle->c_tempname, strerror(err));
return (1);
}
return (0);
}
int
updateconfig(Crle_desc * crle)
{
Rtc_head *head = (Rtc_head *)crle->c_tempheadaddr;
if (crle->c_flags & CRLE_DUMP) {
head->ch_cnflags &= ~RTC_HDR_IGNORE;
if (msync((void *)crle->c_tempaddr, crle->c_tempsize,
MS_ASYNC) == -1) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_TRUNC),
crle->c_name, crle->c_tempname, strerror(err));
return (1);
}
}
if (crle->c_flags & CRLE_EXISTS)
(void) unlink(crle->c_confil);
if (crle->c_flags & CRLE_DIFFDEV) {
int fd;
if ((fd = open(crle->c_confil, (O_RDWR | O_CREAT | O_TRUNC),
0666)) == -1) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
crle->c_name, crle->c_confil, strerror(err));
return (1);
}
if (write(fd, (void *)crle->c_tempaddr, crle->c_tempsize) !=
crle->c_tempsize) {
int err = errno;
(void) fprintf(stderr, MSG_INTL(MSG_SYS_WRITE),
crle->c_name, crle->c_confil, strerror(err));
return (1);
}
(void) close(fd);
(void) unlink(crle->c_tempname);
} else
(void) rename(crle->c_tempname, crle->c_confil);
return (0);
}