static char rcsid[] = "@(#)$Id: shared.c,v 1.67 2006/06/29 17:26:41 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.67 $ $State: Exp $ * * Author: Kari Hurtta (was hurtta+elm@ozone.FMI.FI) *****************************************************************************/ /* * This file is compiled only if dlopen() is available, so * that file does not need to be guarded with #ifdef */ #include "headers.h" DEBUG_VAR(Debug,__FILE__,"dl"); #include "shared_imp.h" #include "connection_imp.h" #include "rc_imp.h" #include "save_opts.h" #include "s_me.h" #include "cs_imp.h" #include "ss_imp.h" #include "s_elm.h" #include #ifndef ANSI_C extern int errno; #endif #if ANSI_C #define S_(x) static x; #else #define S_(x) #endif struct shared_FT * shared_folder_types = NULL; int shared_folder_type_count = 0; /* FIXME -- is shared_SE_option_types really needed */ struct shared_SEOT * shared_SE_option_types = NULL; int shared_SE_option_type_count = 0; struct shared_CST * shared_CS_types = NULL; int shared_CS_type_count = 0; struct shared_MCF * shared_MCF_types = NULL; int shared_MCF_type_count = 0; int use_sharedfunc P_((char **value, int enter, int lineno, char *filename)); struct ImpInfo **library_list = NULL; int library_list_count = 0; static char * give_shname P_((const char *tag)); static char * give_shname(tag) CONST char *tag; { char * ret = elm_message(FRM("%s/%s%s%s"), SHARED_DIR, SHARED_LIBPREFIX, tag, SHARED_LIBSUFFIX); DPRINT(Debug,4,(&Debug,"use-*-library %s => %s\n",tag,ret)); return ret; } S_(RC_post_init_f no_rc_post_init) static void no_rc_post_init(errors) int *errors; { /* Nothing */ } static wants_rand_bits_f no_wants_rand_bits; static void no_wants_rand_bits (buf,size,entropy_bits) CONST char *buf; int size; int entropy_bits; { /* Nothing */ } struct ImpInfo * give_impinfo(tag) CONST char * tag; { int i; for (i = 0; i < library_list_count; i++) { if (0 == strcmp(library_list[i]->tag,tag)) return library_list[i]; } library_list = safe_realloc(library_list, (i+1) * sizeof(library_list[0])); library_list[i] = safe_malloc(sizeof (* library_list[i]) ); bzero((void *)library_list[i], sizeof (* library_list[i])); library_list[i]->valid = 0; library_list[i]->tag = safe_strdup(tag); library_list[i]->shname = give_shname(tag); library_list[i]->handle = NULL; library_list[i]->base_lists_updated = 0; library_list[i]->regs = NULL; library_list[i]->regs_count = 0; library_list[i]->rc_options = NULL; library_list[i]->rc_option_count = 0; library_list[i]->rc_post_init = no_rc_post_init; library_list[i]->wants_rand_bits = no_wants_rand_bits; library_list_count = i+1; return library_list[i]; } int give_rnum(I,var) struct ImpInfo * I; struct dt_shared_info *var; { int i; int k; for (i = 0; i < I->regs_count; i++) if (I->regs[i].var == var) return i; DPRINT(Debug,7,(&Debug, "give_rnum: Adding var %p to %s => rnum=%d\n", var,I->shname,i)); I->regs = safe_realloc(I->regs, (I->regs_count+1) * sizeof (I->regs[0])); I->regs[i].var = var; I->regs[i].valid = 0; I->regs[i].updated = 0; I->regs[i].r.dummy = NULL; DPRINT(Debug,10,(&Debug, "give_rnum: [%p]->regs[%d].valid=%d\n", I,i,I->regs[i].valid)); if (SHARED_LOADER_magic != var->loader->magic) panic("SHARED PANIC",__FILE__,__LINE__, "give_rnum", "Bad magic bumber",0); var->loader->func_zero(var,& (I->regs[i]) ); I->regs_count = i+1; for (k = 0; k < var->shared_list_len; k++) if (var->shared_list[k] == I) goto found; DPRINT(Debug,7,(&Debug, "give_rnum: Adding %s to var %p shared_list (index %d)\n", I->shname,var,k)); var->shared_list = safe_realloc(var->shared_list, (k+1) * sizeof (var->shared_list[0])); var->shared_list[k] = I; var->shared_list_len = k+1; found: DPRINT(Debug,7,(&Debug, "give_rnum=%d [var %p]\n",i,var)); return i; } void load_code0(I) struct ImpInfo *I; { if (! I->handle) { DPRINT(Debug,4,(&Debug," ... library loading %s\n", I->shname)); I->handle = dlopen(I->shname,RTLD_NOW); if (! I->handle) { lib_error(CATGETS(elm_msg_cat, MeSet, MeDLopen0Error, "library %s: %s: %s"), I->tag, I->shname, dlerror()); I->valid = 0; return; } } if (! I->base_lists_updated) { /* union hack to avoid warnings about casting * between pointer-to-object and pointer-to-function */ union F8 { void * ptr; provides_RC_options_f * f8; } f8; union F9 { void * ptr; RC_post_init_f * f9; } f9; union F10 { void * ptr; wants_rand_bits_f * f10; } f10; /* F11 reserved */ f8.ptr = dlsym( I->handle, "provides_RC_options"); f9.ptr = dlsym( I->handle, "RC_post_init"); f10.ptr = dlsym( I->handle, "wants_rand_bits"); if (!f8.f8) { DPRINT(Debug,7,(&Debug, " ... NO provides_RC_options\n")); } if (!f9.f9) { DPRINT(Debug,7,(&Debug, " ... NO RC_post_init\n")); } if (!f10.f10) { DPRINT(Debug,7,(&Debug, " ... NO wants_rand_bits\n")); } if (f8.f8) { int count; size_t s_res8; struct rc_save_info_rec * res8 = f8.f8(&count, &s_res8); if (s_res8 != sizeof (*res8)) { DPRINT(Debug,1,(&Debug,"... struct rc_save_info_rec mismatch: %d should be %d\n", s_res8,sizeof (*res8))); } else { DPRINT(Debug,7,(&Debug," ... provides_RC_options: count %d\n", count)); I->rc_options = res8; I->rc_option_count = count; } } if (f9.f9) { I->rc_post_init = f9.f9; DPRINT(Debug,7,(&Debug," ... RC_post_init\n")); } if (f10.f10) { I->wants_rand_bits = f10.f10; DPRINT(Debug,7,(&Debug," ... wants_rand_bits\n")); } I->base_lists_updated = 1; } /* TODO: Other bookkeeping */ } int reg_code1(I,r) struct ImpInfo *I; int r; { int res; if (SHARED_LOADER_magic != I->regs[r].var->loader->magic) panic("SHARED PANIC",__FILE__,__LINE__, "reg_code1", "Bad magic bumber",0); res = I->regs[r].valid; if ( I->regs[r].valid && ! I->regs[r].updated ) { DPRINT(Debug,7,(&Debug,"reg_code1: Checking library %s ... [%d var %p]\n", I->shname,r,I->regs[r].var)); res = I->regs[r].var->loader->func_reg(I, r); I->regs[r].updated = 1; DPRINT(Debug,7,(&Debug,"reg_code1: ... %s result = %d [%d var %p] valid = %d\n", I->shname,res,r,I->regs[r].var, I->regs[r].valid)); } else { DPRINT(Debug,7,(&Debug, "reg_code1: Skipping library %s ... [%d var %p] valid=%d updated=%d\n", I->shname,r,I->regs[r].var, I->regs[r].valid, I->regs[r].updated)); } return res; } static void load_code P_((int idx)); static void load_code(idx) int idx; { DPRINT(Debug,4,(&Debug,"library [%d] - processing %s ... \n", idx, library_list[idx]->shname)); load_code0(library_list[idx]); } static void unreg1 P_((struct ImpInfo * I, int r)); static void unreg1(I,r) struct ImpInfo * I; int r; { if (SHARED_LOADER_magic != I->regs[r].var->loader->magic) panic("SHARED PANIC",__FILE__,__LINE__, "unreg1", "Bad magic bumber",0); I->regs[r].var->loader-> func_unreg(I, r); I->regs[r].valid = 0; I->regs[r].updated = 0; DPRINT(Debug,10,(&Debug, "unreg1: [%p]->regs[%d].valid=%d\n", I,r,I->regs[r].valid)); } static void unload_code P_((int idx)); static void unload_code(idx) int idx; { if (library_list[idx]->regs_count > 0) { int i; for (i = 0; i < library_list[idx]->regs_count; i++) { if (library_list[idx]->regs[i].valid && library_list[idx]->regs[i].updated) { unreg1(library_list[idx],i); } } } /* TODO: Other bookkeeping */ if (library_list[idx]->handle) { DPRINT(Debug,4,(&Debug,"library [%d] - unloading %s\n", idx,library_list[idx]->shname)); dlclose(library_list[idx]->handle); library_list[idx]->handle = NULL; } } int tag_ok(name) CONST char *name; { if ('\0' == *name) return 0; if (strspn(name,"abcdefghijklmnopqrstuvwxyz") < 3) return 0; return strlen(name) == strspn(name, "abcdefghijklmnopqrstuvwxyz0123456789-"); } static int libraries_loaded = 0; static int locate_and_load_library P_((const char *prefix)); static int locate_and_load_library(prefix) CONST char *prefix; { int i; for (i = 0; i < library_list_count; i++) { if (0 == strcmp(library_list[i]->tag,prefix)) { /* Do not update libraries_loaded because this loads only one library */ if (library_list[i]->valid && !libraries_loaded) load_code(i); if (library_list[i]->valid) { int r; for (r = 0; r < library_list[i]->regs_count; r++) reg_code1(library_list[i],r); } return i; } } return -1; } void load_shared_libs() { int i; if (libraries_loaded) return; for (i = 0; i < library_list_count; i++) { if (library_list[i]->valid) load_code(i); /* NOTE: This do not load variable specific code ... */ } libraries_loaded = 1; } void load_shared_libs1(var) struct dt_shared_info *var; { int i; if (var->libraries_loaded) return; DPRINT(Debug,7,(&Debug,"Loading [var %p] ...\n",var)); for (i = 0; i < var->shared_list_len; i++) { if (var->shared_list[i]->valid) load_code0(var->shared_list[i]); if (var->shared_list[i]->valid) { int r = give_rnum(var->shared_list[i],var); DPRINT(Debug,7,(&Debug, "Prosessing [var %p] %d, %s : valid=%d => r=%d\n", var, i, var->shared_list[i]->shname, var->shared_list[i]->valid, r)); reg_code1(var->shared_list[i],r); } else { DPRINT(Debug,7,(&Debug, "Skipping [var %p] %d, %s : valid=%d\n", var, i, var->shared_list[i]->shname, var->shared_list[i]->valid)); } } DPRINT(Debug,7,(&Debug,"Loading [var %p] done.\n",var)); var->libraries_loaded = 1; } void register_hidden_library(parent,lib) struct dt_shared_info *parent; struct dt_shared_info *lib; { if (lib->hidden_var) panic("SHARED PANIC",__FILE__,__LINE__, "process_lib_reg", "register_hidden_library have children or already registered",0); lib->hidden_var = parent->hidden_var; parent->hidden_var = lib; } static int process_lib_reg P_((struct rc_save_info_rec *r, char *value, int lineno, char *filename)); static int process_lib_reg(r,value,lineno,filename) struct rc_save_info_rec *r; char *value; int lineno; char *filename; { int ret = 1; struct dt_shared_info *S = r->val.shared; char * temp = safe_strdup(value); char *p; if (S->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "process_lib_reg", "Bad magic bumber (1)",0); for (p = strtok(temp," "); p; p = strtok(NULL," ")) { if (!tag_ok(p)) { lib_error(CATGETS(elm_msg_cat, MeSet, MeInvalidUseXLib, "%s: %s: Invalid name"), r->name,p); ret = 0; } else { struct ImpInfo * I = give_impinfo(p); int rnum = give_rnum(I,S); /* We do not load code here with dlopen, because we cant load code only when it is needed. */ if (0 == access(I->shname,ACCESS_EXISTS)) { struct dt_shared_info *S1; I->valid = 1; libraries_loaded = 0; /* Rescan... */ I->regs[rnum].valid = 1; S->libraries_loaded = 0; DPRINT(Debug,10,(&Debug, "process_lib_reg: [%p]->regs[%d].valid=%d\n", I,rnum,I->regs[rnum].valid)); for (S1 = S->hidden_var; S1; S1 = S1->hidden_var) { int rnum = give_rnum(I,S1); I->regs[rnum].valid = 1; S->libraries_loaded = 0; DPRINT(Debug,10,(&Debug, "process_lib_reg: [%p]->regs[%d].valid=%d (hidden)\n", I,rnum,I->regs[rnum].valid)); } } else { int err = errno; lib_error(CATGETS(elm_msg_cat, MeSet, MeNonExistUseXLib, "%s: %s: %s: %s"), r->name,I->tag,I->shname, error_description(err)); ret = 0; } } } free(temp); return ret; } S_(rc_parse_line dt_SHARED_parse_line) static int dt_SHARED_parse_line(r,lcl,value,lineno,filename, negate) struct rc_save_info_rec *r; int lcl; char *value; int lineno; char *filename; int negate; { int i; if (negate) { lib_error(CATGETS(elm_msg_cat, ElmSet, ElmBadNegate, "!%s is not supported in line %d in \"%s\" file"), r->name,lineno,filename); return 0; } if (r->val.shared->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_parse_line", "Bad magic bumber (1)",0); for (i = 0; i < r->val.shared->shared_list_len; i++) { int j; for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) { if (r->val.shared->shared_list[i]->regs[j].var->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_parse_line", "Bad magic bumber (2)",0); if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) { r->val.shared->shared_list[i]->regs[j].valid = 0; DPRINT(Debug,10,(&Debug, "dt_SHARED_parse_line: [%p]->regs[%d].valid=%d\n", r->val.shared->shared_list[i], j, r->val.shared->shared_list[i]->regs[j].valid)); goto found1; } } panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_parse_line", "No info on list",0); found1:; } return process_lib_reg(r,value,lineno,filename); } S_(rc_parse_cline dt_SHARED_parse_cline) static int dt_SHARED_parse_cline(r,lcl,value,lineno,filename) struct rc_save_info_rec *r; int lcl; char *value; int lineno; char *filename; { return process_lib_reg(r,value,lineno,filename); } S_(rc_print_value dt_SHARED_print_value) static void dt_SHARED_print_value(F,r,comment) FILE *F; struct rc_save_info_rec *r; int comment; { int i; int len=0; if (r->val.shared->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_print_value", "Bad magic bumber (1)",0); if (comment) fprintf(F, "### "); fprintf(F, "%s =", r->name); for (i = 0; i < r->val.shared->shared_list_len; i++) { int j; for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) { if (r->val.shared->shared_list[i]->regs[j].var->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_print_value", "Bad magic bumber (2)",0); if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) { goto found1; } } panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_print_value", "No info on list",0); found1: if (r->val.shared->shared_list[i]->regs[j].valid) { char * s = r->val.shared->shared_list[i]->tag; if (strlen(s) + len > 72) { if (!comment) fprintf(F, "\n\t"); else fprintf(F, "\n###\t"); len = 8; } else { fprintf(F, " "); ++len; } fprintf(F, "%s", s); len += strlen(s); } } fprintf(F,"\n"); } S_(rc_get_value dt_SHARED_get_value) static char * dt_SHARED_get_value(r) struct rc_save_info_rec *r; { /* static pointer to buffer accross invocations */ static char * return_buffer = NULL; int i; int len=0; return_buffer = strmcpy(return_buffer,""); /* Reset result */ if (r->val.shared->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_get_value", "Bad magic bumber (1)",0); for (i = 0; i < r->val.shared->shared_list_len; i++) { int j; for (j = 0; j < r->val.shared->shared_list[i]->regs_count; j++) { if (r->val.shared->shared_list[i]->regs[j].var->loader->magic != SHARED_LOADER_magic) panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_get_value", "Bad magic bumber (2)",0); if (r->val.shared == r->val.shared->shared_list[i]->regs[j].var) { goto found1; } } panic("SHARED PANIC",__FILE__,__LINE__, "dt_SHARED_get_value", "No info on list",0); found1: if (r->val.shared->shared_list[i]->regs[j].valid) { char * s = r->val.shared->shared_list[i]->tag; if (return_buffer[0]) return_buffer = strmcat(return_buffer," "); return_buffer = strmcat(return_buffer,s); } } return return_buffer; } struct rc_type rc_DT_SHARED = { RCTYPE_magic, dt_SHARED_parse_line, dt_SHARED_parse_cline, dt_SHARED_print_value, dt_SHARED_get_value }; int verify_shared_index(i) struct ImpInfo *i; { if (i->handle && i->valid) return 1; return 0; } struct SE_option_type * get_option_type(prefix) CONST char *prefix; { int i; int idx1 = locate_and_load_library(prefix); for (i = 0; i < shared_SE_option_type_count; i++) { struct ImpInfo *I = shared_SE_option_types[i].imp_idx; if (library_list[idx1] == I) { if (! I->handle) { lib_error(CATGETS(elm_msg_cat, MeSet, MeInvalidOptionTag, "Options %s:* ignored -- code not loaded"), prefix); return NULL; } return shared_SE_option_types[i].T; } } lib_error(CATGETS(elm_msg_cat, MeSet, MeInvalidOptionTag, "Options %s:* ignored -- code not loaded"), prefix); return NULL; } void mark_shared_changed(A) void *A; { int i; for (i = 0; i < library_list_count; i++) { int x; if (!library_list[i]->handle) continue; for (x = 0; x < library_list[i]->rc_option_count; x++) { if (library_list[i]->rc_options[x].val.dummy == A) { mark_XX(& (library_list[i]->rc_options[x])); } } } } void mark_fshared_changed(A) option_func *A; { int i; for (i = 0; i < library_list_count; i++) { int x; if (!library_list[i]->handle) continue; for (x = 0; x < library_list[i]->rc_option_count; x++) { if (library_list[i]->rc_options[x].func_val == A) { mark_XX(& (library_list[i]->rc_options[x])); } } } } int give_options(tag,rc_options,rc_option_count) char *tag; struct rc_save_info_rec ** rc_options; int * rc_option_count; { int idx1 = locate_and_load_library(tag); *rc_options = NULL; *rc_option_count = 0; if (idx1 < 0 || !library_list[idx1]->handle) return 0; *rc_options = library_list[idx1]->rc_options; *rc_option_count = library_list[idx1]->rc_option_count; return 1; } static void seed_rand_bits1(const char *buf, int size, int entropy_bits); static void seed_rand_bits1(buf,size,entropy_bits) CONST char *buf; int size; int entropy_bits; { int i; DPRINT(Debug,10,(&Debug, "Seeding random generator %d bytes (%d entropy bits)\n", size,entropy_bits)); if (entropy_bits > size*8) panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits1", "Impossible entropy",0); /* Only seed libraries which are loaded */ for (i = 0; i < library_list_count; i++) { if (library_list[i]->handle) { /* We should perhaps mangle data so same bits are not given to different modules */ library_list[i]->wants_rand_bits(buf,size,entropy_bits); } } } void seed_rand_bits(buf,size,entropy_bits) CONST char *buf; int size; int entropy_bits; { static char buffer[1024]; static int byte_count = 0; static int entropy_count = 0; DPRINT(Debug,10,(&Debug, "Got random generator %d bytes (%d entropy bits)\n", size,entropy_bits)); if (entropy_bits > size*8) panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits", "Impossible entropy",0); if (size > sizeof buffer) seed_rand_bits1(buf,size,entropy_bits); else { int i; if (size + byte_count > sizeof buffer) { seed_rand_bits1(buffer,byte_count,entropy_count); byte_count = 0; entropy_count = 0; } /* We can just XOR bits ... */ for (i = 0; i < size; i++) buffer[byte_count++] ^= buf[i]; if (byte_count > sizeof buffer) panic("SHARED PANIC",__FILE__,__LINE__,"seed_rand_bits", "Overflow",0); entropy_count += entropy_bits; if (entropy_count > 16 && library_list_count) { seed_rand_bits1(buffer,byte_count,entropy_count); byte_count = 0; entropy_count = 0; } } } void post_init_shared_options(errors) int *errors; { int i; /* Automatically move libraries out from use-library ... */ /* load generic ... */ load_shared_libs1(&use_shared_all); /* unreg possible registered but no longer valid... */ for (i = 0; i < library_list_count; i++) { int j; for (j = 0; j < library_list[i]->regs_count; j++) { if (! library_list[i]->regs[j].valid && library_list[i]->regs[j].updated) { unreg1(library_list[i],j); } } } /* Unload possible loaded but no longer valid... */ for (i = 0; i < library_list_count; i++) { if (!library_list[i]->valid) { DPRINT(Debug,4,(&Debug,"Unloading no longer valid library %s\n", library_list[i]->tag)); unload_code(i); } } /* Only post_init libraries which are loaded (other do not have options) */ for (i = 0; i < library_list_count; i++) { if (library_list[i]->handle && library_list[i]->rc_option_count > 0) { library_list[i]->rc_post_init(errors); } } } void print_local_shared_options(F,global) FILE *F; int global; { int i; /* We want print options of all shared libs */ load_shared_libs(); for (i = 0; i < library_list_count; i++) { if (library_list[i]->handle && library_list[i]->rc_option_count > 0) { int x; fprintf(F,"\n"); elm_fprintf(F, CATGETS(elm_msg_cat, MeSet, MeElmrcSection, "# Options for %s section (shared library)\n#\n\n"), library_list[i]->tag); fprintf(F,"%s:\n", library_list[i]->tag); DPRINT(Debug,8,(&Debug, " -- library %s -- %d options\n", library_list[i]->tag, library_list[i]->rc_option_count)); for (x = 0; x < library_list[i]->rc_option_count; x++) { int local_value; /** skip system-only options **/ if (!global & (library_list[i]->rc_options[x].flags & FL_SYS) ) { DPRINT(Debug,8,(&Debug, "shlib/option %d -- \"%s\" system-only, flags=%0x\n", x,library_list[i]->rc_options[x].name, save_info[x].flags )); continue; } if (global & !(library_list[i]->rc_options[x].flags & FL_SYS) && !(library_list[i]->rc_options[x].flags & FL_CHANGED)) { DPRINT(Debug,8,(&Debug, "shlib/option %d -- \"%s\" user option, flags=%0x\n", x,library_list[i]->rc_options[x].name, save_info[x].flags )); continue; } if (global) local_value = library_list[i]->rc_options[x].flags & FL_CHANGED; else local_value = library_list[i]->rc_options[x].flags & FL_LOCAL; if (RCTYPE_magic != library_list[i]->rc_options[x].dt_type->magic) { DPRINT(Debug,1,(&Debug, "shlib/option %d -- \"%s\" BAD, flags=%0x (library=%s)\n", x,library_list[i]->rc_options[x].name, save_info[x].flags, library_list[i]->tag)); panic("RC PANIC",__FILE__,__LINE__, "print_local_shared_options", "Bad config item type",0); } library_list[i]-> rc_options[x].dt_type-> print_value(F, & library_list[i]->rc_options[x], !local_value); } } } } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */