Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X Common-Config
0003  *
0004  * @file cconfig.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <ndrstandard.h>
0037 #include <time.h>
0038 #include <sys/time.h>
0039 #include <stdlib.h>
0040 #include <string.h>
0041 #include <stdio.h>
0042 #include <utlist.h>
0043 #include <nstdutil.h>
0044 #include <ndrx_ini.h>
0045 #include <inicfg.h>
0046 #include <nerror.h>
0047 #include <ndebug.h>
0048 #include <nstd_int.h>
0049 #include <sys_unix.h>
0050 #include <errno.h>
0051 #include <inicfg.h>
0052 #include <cconfig.h>
0053 #include <nerror.h>
0054 #include <userlog.h>
0055 #include <expluginbase.h>
0056 /*---------------------------Externs------------------------------------*/
0057 /*---------------------------Macros-------------------------------------*/
0058 /* #define CCONFIG_ENABLE_DEBUG */
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 /* These should be semaphore mutex globals... */
0063 ndrx_inicfg_t *G_cconfig = NULL; /* Common-config handler */
0064 char *G_cctag = NULL;
0065 int G_tried_to_load = EXFALSE; /* did we try to load the config? */
0066 
0067 /** API specifc flags */
0068 expublic long ndrx_G_apiflags = 0;
0069 
0070 /*---------------------------Statics------------------------------------*/
0071 
0072 exprivate char *M_sections[] = {NDRX_CONF_SECTION_GLOBAL, 
0073                         NDRX_CONF_SECTION_DEBUG, 
0074                         NDRX_CONF_SECTION_QUEUE, 
0075                         NDRX_CONF_SECTION_CACHE,
0076                         NDRX_CONF_SECTION_CACHEDB,
0077                         NDRX_CONF_SECTION_UBFDB,
0078                         NULL};
0079 
0080 /* for first pass load only global! */
0081 exprivate char *M_sections_first_pass[] = {NDRX_CONF_SECTION_GLOBAL,
0082                         NULL};
0083 
0084 exprivate MUTEX_LOCKDECL(M_load_lock);
0085 /*---------------------------Prototypes---------------------------------*/
0086 
0087 exprivate int _ndrx_cconfig_load_pass(ndrx_inicfg_t **cfg, int is_internal, 
0088         char **section_start_with);
0089 
0090 /**
0091  * Split up the CCTAG (by tokens)
0092  * and lookup data by any of the tags 
0093  * @param section
0094  * @return 
0095  */
0096 expublic int ndrx_cconfig_get_cf(ndrx_inicfg_t *cfg, char *section, 
0097         ndrx_inicfg_section_keyval_t **out)
0098 {
0099     int ret = EXSUCCEED;
0100     int len;
0101     char *tmp1 = NULL; /* lookup section  */
0102     char *tmp2 = NULL; /* token cctag */
0103     char *saveptr1;
0104     char *token_cctag;
0105     
0106     _Nunset_error();
0107     
0108     if (NULL==cfg)
0109     {
0110         _Nset_error_fmt(NEINVAL, "%s: `cfg' cannot be NULL!", __func__);
0111         EXFAIL_OUT(ret);
0112     }
0113     
0114     if (NULL==section)
0115     {
0116         _Nset_error_fmt(NEINVAL, "%s: `section' cannot be NULL!", __func__);
0117         EXFAIL_OUT(ret);
0118     }
0119     
0120     /*  if we have CC tag, with sample value "RM1/DBG2"
0121      * Then lookup will take in this order:
0122      * [@debug/RM1]
0123      * [@debug/DBG2]
0124      */
0125     if (NULL!=G_cctag && 0!=strcmp(G_cctag, NDRX_INICFG_SUBSECT_SPERATOR_STR))
0126     {
0127         len = strlen(section);
0128         if (NULL!=G_cctag)
0129         {
0130             len+=strlen(G_cctag);
0131         }
0132 
0133         if (NULL==(tmp1 = NDRX_MALLOC(len+2))) /* 1 for eos, another for seperator */
0134         {
0135             userlog("%s: tmp1 malloc failed: %s", __func__, strerror(errno));
0136             EXFAIL_OUT(ret);
0137         }
0138 
0139 
0140         if (NULL==(tmp2 = NDRX_MALLOC(strlen(G_cctag)+1)))
0141         {
0142             userlog("%s: tmp2 malloc failed: %s", __func__, strerror(errno));
0143             EXFAIL_OUT(ret);
0144         }
0145 
0146         strcpy(tmp2, G_cctag);
0147 
0148 
0149         token_cctag = strtok_r(tmp2, NDRX_INICFG_SUBSECT_SPERATOR_STR, &saveptr1);
0150 
0151         while( token_cctag != NULL )
0152         {
0153             strcpy(tmp1, section);
0154             strcat(tmp1, NDRX_INICFG_SUBSECT_SPERATOR_STR);
0155             strcat(tmp1, token_cctag);
0156 
0157             if (EXSUCCEED!=ndrx_inicfg_get_subsect_int(cfg, 
0158                                 NULL,  /* all config files */
0159                                 tmp1,  /* global section */
0160                                 out))
0161             {
0162                 userlog("%s: %s", __func__, Nstrerror(Nerror));
0163                 EXFAIL_OUT(ret);
0164             }
0165             
0166             token_cctag = strtok_r(NULL, NDRX_INICFG_SUBSECT_SPERATOR_STR, &saveptr1);
0167         }
0168     }/* Direct lookup if no cctag */
0169     else if (EXSUCCEED!=ndrx_inicfg_get_subsect(cfg, 
0170                                 NULL,  /* all config files */
0171                                 section,  /* global section */
0172                                 out))
0173     {
0174         userlog("%s: %s", __func__, Nstrerror(Nerror));
0175         EXFAIL_OUT(ret);
0176     }
0177     
0178 out:
0179 
0180     if (NULL!=tmp1)
0181     {
0182         NDRX_FREE(tmp1);
0183     }
0184 
0185     if (NULL!=tmp2)
0186     {
0187         NDRX_FREE(tmp2);
0188     }
0189 
0190     return ret;
0191 }
0192 
0193 /**
0194  * Get the Enduro/X config
0195  * @param section
0196  * @param out
0197  * @return 
0198  */
0199 expublic int ndrx_cconfig_get(char *section, ndrx_inicfg_section_keyval_t **out)
0200 {
0201     return ndrx_cconfig_get_cf(G_cconfig, section,  out);
0202 }
0203 
0204 /**
0205  * Two pass config load orchestrator
0206  * First pass will load global variables (environment)
0207  * Second pass will allow to reference for example other variable from global
0208  * section.
0209  * Firstly we will load dummy value (${XXX} not substituted as empty), but second
0210  * pass will once again load the actual resolved values.
0211  * @param cfg
0212  * @param is_internal
0213  * @param section_start_with - array of sections, which name starts with given string.
0214  *  In that case load only matched sections.
0215  * @return 
0216  */
0217 exprivate int _ndrx_cconfig_load(ndrx_inicfg_t **cfg, int is_internal, char **section_start_with)
0218 {
0219     int ret = EXSUCCEED;
0220     
0221     if (is_internal)
0222     {
0223         ndrx_inicfg_t *cfg_first_pass = NULL;
0224         /* two pass loading */
0225         
0226         /* first pass will go with dummy config, then we make it free... 
0227          * and we are interested only in global section
0228          */
0229         if (EXSUCCEED!=_ndrx_cconfig_load_pass(&cfg_first_pass, EXTRUE, 
0230                 M_sections_first_pass))
0231         {
0232             userlog("Failed to load first pass config!");
0233             EXFAIL_OUT(ret);
0234         }
0235         
0236         /* release the config 
0237          * Load second pass only when first was ok i.e. present.
0238          */
0239         if (NULL!=cfg_first_pass)
0240         {
0241             ndrx_inicfg_free(cfg_first_pass);
0242             ret = _ndrx_cconfig_load_pass(cfg, EXTRUE, M_sections);
0243         }
0244         
0245     }
0246     else
0247     {
0248         /* single pass */
0249         ret = _ndrx_cconfig_load_pass(cfg, EXFALSE, section_start_with);
0250     }
0251     
0252 out:
0253     return ret;
0254 }
0255 
0256 /**
0257  * Load config (for Enduro/X only)
0258  * @return 
0259  */
0260 exprivate int _ndrx_cconfig_load_pass(ndrx_inicfg_t **cfg, int is_internal, 
0261         char **section_start_with)
0262 {
0263     int ret = EXSUCCEED;
0264     int slot = 0;
0265     int have_config = EXFALSE;
0266     char fn[] = "ndrx_cconfig_load";
0267     char *config_resources[]= { NULL, 
0268                           NULL, 
0269                           NULL, 
0270                           NULL, 
0271                           NULL, 
0272                           NULL, 
0273                           NULL};
0274     
0275     if (NULL!=*cfg)
0276     {
0277         /* config already loaded... */
0278         return EXSUCCEED;
0279     }
0280     
0281     ndrx_inicfg_section_keyval_t *keyvals = NULL, *keyvals_iter = NULL, 
0282                 *keyvals_iter_tmp = NULL;
0283     
0284     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG5)))
0285     {
0286         slot++;
0287     }
0288     
0289     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG4)))
0290     {
0291         slot++;
0292     }
0293     
0294     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG3)))
0295     {
0296         slot++;
0297     }
0298     
0299     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG2)))
0300     {
0301         slot++;
0302     }
0303     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG1)))
0304     {
0305         slot++;
0306     }
0307     if (NULL!=(config_resources[slot] = getenv(NDRX_CCONFIG)))
0308     {
0309         slot++;
0310     }
0311         
0312     /* Check if envs are set before try to load */
0313     if (NULL==(*cfg = ndrx_inicfg_new2(EXTRUE)))
0314     {
0315         userlog("%s: %s", fn, Nstrerror(Nerror));
0316         EXFAIL_OUT(ret);
0317     }
0318     
0319     /* Load the stuff */
0320     slot = 0;
0321 
0322     while (NULL!=config_resources[slot])
0323     {
0324 #ifdef CCONFIG_ENABLE_DEBUG
0325         userlog("have config at slot [%d] [%s]", slot, config_resources[slot]);
0326 #endif
0327         NDRX_LOG_EARLY(log_debug, "have config at slot [%d] [%s]", 
0328                 slot, config_resources[slot]);
0329         
0330         have_config = EXTRUE;
0331         
0332         if (EXSUCCEED!=ndrx_inicfg_add(*cfg, config_resources[slot], section_start_with))
0333         {
0334             userlog("%s: %s", fn, Nstrerror(Nerror));
0335             EXFAIL_OUT(ret);
0336         }
0337         
0338         slot++;
0339     }
0340 
0341     if (NULL==config_resources[0])
0342     {
0343         have_config = EXFALSE;
0344         goto out;
0345     }
0346     
0347     if (is_internal)
0348     {
0349         /* Get globals & transfer to setenv() */
0350         if (EXSUCCEED!=ndrx_cconfig_get_cf(*cfg, NDRX_CONF_SECTION_GLOBAL, &keyvals))
0351         {
0352             userlog("%s: %s lookup failed: %s", fn, 
0353                     NDRX_CONF_SECTION_GLOBAL, Nstrerror(Nerror));
0354             EXFAIL_OUT(ret);
0355         }
0356 
0357         /* Loop over and load the stuff... */
0358         EXHASH_ITER(hh, keyvals, keyvals_iter, keyvals_iter_tmp)
0359         {   
0360 #ifdef CCONFIG_ENABLE_DEBUG
0361             userlog("settings %s=%s", keyvals_iter->key, keyvals_iter->val);
0362 #endif
0363 
0364             if (EXSUCCEED!=setenv(keyvals_iter->key, keyvals_iter->val, EXTRUE))
0365             {
0366                 userlog("%s: failed to set %s=%s: %s", fn, 
0367                     keyvals_iter->key, keyvals_iter->val, strerror(errno));
0368                 EXFAIL_OUT(ret);
0369             }
0370 #ifdef CCONFIG_ENABLE_DEBUG
0371             userlog("test value %s\n", getenv(keyvals_iter->key));
0372 #endif
0373         }
0374     }
0375     
0376 out:
0377 
0378     if (NULL!=keyvals)
0379     {
0380         ndrx_keyval_hash_free(keyvals);
0381         keyvals = NULL;
0382     }
0383     if (EXSUCCEED!=ret || !have_config)
0384     {
0385         if (NULL!=*cfg)
0386         {
0387 #ifdef CCONFIG_ENABLE_DEBUG
0388         userlog("Removing config %p", *cfg);
0389 #endif
0390             ndrx_inicfg_free(*cfg);
0391             *cfg = NULL;
0392         }
0393     }
0394     
0395     if (EXSUCCEED==ret && is_internal)
0396     {
0397         G_tried_to_load = EXTRUE;
0398     }
0399 
0400     /* Add some debug on config load */
0401     NDRX_LOG_EARLY(log_debug, "%s: ret: %d is_internal: %d G_tried_to_load: %d",
0402             __func__, ret, is_internal, G_tried_to_load);
0403 
0404     return ret;
0405 }
0406 
0407 /**
0408  * Load API flags
0409  * @return EXSUCCEED/EXFAIL
0410  */
0411 exprivate int ndrx_apiflags_load(void)
0412 {
0413     int ret = EXSUCCEED;
0414     char *p = getenv(CONF_NDRX_APIFLAGS);
0415     ndrx_stdcfgstr_t* parsed=NULL, *el;
0416     
0417     if (NULL!=p)
0418     {
0419         if (EXSUCCEED!=ndrx_stdcfgstr_parse(p, &parsed))
0420         {
0421             NDRX_LOG_EARLY(log_error, "Failed to parse %s=[%s]",
0422                     CONF_NDRX_APIFLAGS, p);
0423             EXFAIL_OUT(ret);
0424         }
0425         
0426         /* loop over the settings list... */
0427         DL_FOREACH(parsed, el)
0428         {
0429             if (0==strcmp(el->key, NDRX_APIFLAGS_JSONESCAPE_CODE))
0430             {
0431                 NDRX_LOG_EARLY(log_debug, "%s found - C escape json strings",
0432                         NDRX_APIFLAGS_JSONESCAPE_CODE);
0433                 ndrx_G_apiflags|=NDRX_APIFLAGS_JSONESCAPE;
0434             }
0435             else if (0==strcmp(el->key, NDRX_APIFLAGS_UBFPTRPARSE_CODE))
0436             {
0437                 NDRX_LOG_EARLY(log_info, "%s found - parse BFLD_PTR addresses on import",
0438                         NDRX_APIFLAGS_UBFPTRPARSE_CODE);
0439                 ndrx_G_apiflags|=NDRX_APIFLAGS_UBFPTRPARSE;
0440             }
0441             else if (0==strcmp(el->key, NDRX_APIFLAGS_UBFDUPFIDOK_CODE))
0442             {
0443                 NDRX_LOG_EARLY(log_info, "%s UBF table duplicate field id OK",
0444                         NDRX_APIFLAGS_UBFDUPFIDOK_CODE);
0445                 ndrx_G_apiflags|=NDRX_APIFLAGS_UBFDUPFIDOK;
0446             }
0447         }
0448     }
0449     
0450 out:
0451     
0452     if (NULL!=parsed)
0453     {
0454         ndrx_stdcfgstr_free(parsed);
0455     }
0456 
0457     return ret;
0458 }
0459 
0460 /**
0461  * Internal for Enduro/X - load the config
0462  * @return 
0463  */
0464 expublic int ndrx_cconfig_load(void)
0465 {
0466     /* this might be called from debug... */
0467     static int first = EXTRUE;
0468     static int first_ret = EXSUCCEED;
0469     int do_reply = EXFALSE;
0470     if (first)
0471     {
0472         /* protect against multi-threading */
0473         MUTEX_LOCK_V(M_load_lock);
0474         
0475         /* Lock the debug... */
0476         ndrx_dbg_intlock_set();
0477         
0478         /* if still is not set... */
0479         if (first)
0480         {
0481             /* basically at this point we must load the plugins.. */
0482             ndrx_plugins_load();
0483             
0484             if (NULL==G_cctag)
0485             {
0486                 G_cctag = getenv(NDRX_CCTAG);
0487                 
0488                 NDRX_LOG_EARLY(log_debug, "CC tag set to: [%s]", 
0489                         (G_cctag?G_cctag:""));
0490             }
0491 
0492             first_ret = _ndrx_cconfig_load(&G_cconfig, EXTRUE, NULL);
0493             first = EXFALSE;
0494             /* Load after the ini have been processed, so that
0495              * these can be set in [@global] section
0496              */
0497             ndrx_apiflags_load();
0498         }
0499         
0500         /* Do this outside the lock... */
0501         ndrx_dbg_intlock_unset(&do_reply);
0502         
0503         MUTEX_UNLOCK_V(M_load_lock);
0504         
0505     }
0506     
0507     /* to avoid deadlocks, do this ouside any load locking */
0508     if (do_reply)
0509     {
0510         ndrx_dbg_reply_memlog_all();
0511     }
0512     
0513     return first_ret;
0514 }
0515 
0516 /**
0517  * General for user (make config out of the Enduro/X cfg files)
0518  * Use shared config
0519  * @param cfg double ptr to config object
0520  * @return 
0521  */
0522 expublic int ndrx_cconfig_load_general(ndrx_inicfg_t **cfg)
0523 {
0524     if (NULL==G_cctag)
0525     {
0526         G_cctag = getenv(NDRX_CCTAG);
0527     }
0528     
0529     return _ndrx_cconfig_load(cfg, EXFALSE, NULL);
0530 }
0531 
0532 /**
0533  * Load configuration file sections.
0534  */
0535 expublic int ndrx_cconfig_load_sections(ndrx_inicfg_t **cfg, char **section_start_with)
0536 {
0537     if (NULL==G_cctag)
0538     {
0539         G_cctag = getenv(NDRX_CCTAG);
0540     }
0541     
0542     return _ndrx_cconfig_load(cfg, EXFALSE, NULL);
0543 }
0544 
0545 /**
0546  * Reload Enduro/X CConfig
0547  * @return 
0548  */
0549 expublic int ndrx_cconfig_reload(void)
0550 {
0551     char fn[]="ndrx_cconfig_reload";
0552     if (EXSUCCEED!=ndrx_inicfg_reload(G_cconfig, M_sections))
0553     {
0554         userlog("%s: %s lookup to reload: %s", fn, 
0555                 NDRX_CONF_SECTION_GLOBAL, Nstrerror(Nerror));
0556         return EXFAIL;
0557     }
0558 
0559     return EXSUCCEED;
0560 }
0561 
0562 /**
0563  * Access to to atmi lib env globals
0564  * @return 
0565  */
0566 expublic ndrx_inicfg_t *ndrx_get_G_cconfig(void)
0567 {
0568 #ifdef CCONFIG_ENABLE_DEBUG
0569     userlog("returning G_cconfig %p", G_cconfig);
0570 #endif
0571     if (!G_tried_to_load)
0572     {
0573         /* try to load */
0574         ndrx_cconfig_load();
0575     }
0576     return G_cconfig;
0577 }
0578 /* vim: set ts=4 sw=4 et smartindent: */