Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Client configuration
0003  *
0004  * @file cltconfig.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 #include <ndrx_config.h>
0035 #include <string.h>
0036 #include <stdio.h>
0037 #include <stdlib.h>
0038 #include <memory.h>
0039 #include <libxml/xmlreader.h>
0040 #include <errno.h>
0041 
0042 #include <ndrstandard.h>
0043 #include <userlog.h>
0044 #include <atmi.h>
0045 #include <sys/stat.h>
0046 #include <sys/types.h>
0047 #include <nstdutil.h>
0048 #include <exenv.h>
0049 #include <libndrxconf.h>
0050 #include <singlegrp.h>
0051 
0052 #include "cpmsrv.h"
0053 /*---------------------------Externs------------------------------------*/
0054 /*---------------------------Macros-------------------------------------*/
0055 /*---------------------------Enums--------------------------------------*/
0056 /*---------------------------Typedefs-----------------------------------*/
0057 
0058 /*---------------------------Globals------------------------------------*/
0059 
0060 /**
0061  * Active monitor configuration
0062  */
0063 expublic cpm_process_t *G_clt_config=NULL;
0064 
0065 /**
0066  * Global environment groups
0067  */
0068 exprivate ndrx_env_group_t * M_envgrouphash = NULL;
0069 
0070 /**
0071  * Actual process group configuration
0072  */
0073 expublic ndrx_procgroups_t * ndrx_G_procgroups_config = NULL;
0074 
0075 exprivate MUTEX_LOCKDECL(M_config_lock);
0076 /*---------------------------Statics------------------------------------*/
0077 /*---------------------------Prototypes---------------------------------*/
0078 
0079 
0080 /**
0081  * Lock config structure access
0082  */
0083 expublic void cpm_lock_config(void)
0084 {
0085     MUTEX_LOCK_V(M_config_lock);
0086 }
0087 
0088 
0089 /**
0090  * Unlock config access routines
0091  */
0092 expublic void cpm_unlock_config(void)
0093 {
0094     MUTEX_UNLOCK_V(M_config_lock);
0095 }
0096 
0097 
0098 /**
0099  * Get lookup key
0100  * @param key_out
0101  * @param [in] key_outsz \p key_out parameter buffer size
0102  * @param tag
0103  * @param subsect
0104  */
0105 expublic void cpm_get_key(char *key_out, int key_outsz, char *tag, char *subsect)
0106 {
0107     snprintf(key_out, key_outsz, "%s%c%s", tag, NDRX_CPM_SEP, subsect);
0108 }
0109 /**
0110  * Return client by tag & subsect
0111  * @param tag
0112  * @param subsect
0113  * @return ptr to client or NULL (if not found)
0114  */
0115 expublic cpm_process_t * cpm_client_get(char *tag, char *subsect)
0116 {
0117     cpm_process_t *r=NULL;
0118     
0119     char key[CPM_KEY_LEN];
0120     
0121     cpm_get_key(key, sizeof(key), tag, subsect);
0122     
0123     EXHASH_FIND_STR( G_clt_config, key, r);
0124     
0125     if (NULL!=r)
0126     {
0127         return r;
0128     }
0129     else
0130     {
0131         return NULL;
0132     }
0133 }
0134 
0135 /**
0136  * Search for client by 
0137  * @param pid
0138  * @return NULL or clt 
0139  */
0140 expublic cpm_process_t * cpm_get_client_by_pid(pid_t pid)
0141 {
0142     cpm_process_t *c = NULL;
0143     cpm_process_t *ct = NULL;
0144     
0145     /* Mark config as not refreshed */
0146     EXHASH_ITER(hh, G_clt_config, c, ct)
0147     {
0148         if (c->dyn.pid == pid)
0149         {
0150             return c;
0151         }
0152     }
0153     
0154     return NULL;
0155 }
0156 
0157 /**
0158  * Mark all processes to be started.
0159  * @param pid
0160  * @return NULL or clt 
0161  */
0162 expublic cpm_process_t * cpm_start_all(void)
0163 {
0164     cpm_process_t *c = NULL;
0165     cpm_process_t *ct = NULL;
0166     
0167     /* Mark config as not refreshed */
0168     EXHASH_ITER(hh, G_clt_config, c, ct)
0169     {
0170         /* start those marked for autostart... */
0171         if (c->stat.flags & CPM_F_AUTO_START)
0172         {
0173             c->dyn.req_state = CLT_STATE_STARTED;
0174             c->dyn.cur_state = CLT_STATE_STARTING;
0175         }
0176     }
0177     
0178     return NULL;
0179 }
0180 
0181 /**
0182  * Set current time of the status change
0183  * @param p_cltproc
0184  */
0185 expublic void cpm_set_cur_time(cpm_process_t *p_cltproc)
0186 {
0187     time (&p_cltproc->dyn.stattime);
0188 }
0189 
0190 /**
0191  * Parser client entry
0192  * @param doc
0193  * @param cur
0194  * @param srvnm - name of the client
0195  * @return 
0196  */
0197 exprivate int parse_client(xmlDocPtr doc, xmlNodePtr cur)
0198 {
0199     int ret=EXSUCCEED;
0200     xmlAttrPtr attr;
0201     
0202     cpm_process_t cltproc;
0203     cpm_process_t *p_cltproc = NULL;
0204     cpm_process_t *org_cltproc = NULL;
0205     char *p;
0206     cpm_process_t * p_cl;
0207     int loop_subsectfrom;
0208     int loop_subsectto;
0209     int i, genloop;
0210     char *token;
0211     char tmp_command_line[PATH_MAX+1+CPM_TAG_LEN+CPM_SUBSECT_LEN];
0212     ndrx_procgroup_t *p_grp;
0213     memset(&cltproc, 0, sizeof(cpm_process_t));
0214     
0215     cltproc.stat.flags |= CPM_F_KILL_LEVEL_DEFAULT;
0216     cltproc.stat.rssmax = EXFAIL;
0217     cltproc.stat.vszmax = EXFAIL;
0218     
0219     cltproc.stat.subsectfrom = EXFAIL;
0220     cltproc.stat.subsectto = EXFAIL;
0221     
0222     for (attr=cur->properties; attr; attr = attr->next)
0223     {
0224         if (0==strcmp((char *)attr->name, "cmdline"))
0225         {
0226             p = (char *)xmlNodeGetContent(attr->children);
0227             NDRX_STRCPY_SAFE(cltproc.stat.command_line, p);
0228             xmlFree(p);
0229         }
0230         else if (0==strcmp((char *)attr->name, "env"))
0231         {
0232             p = (char *)xmlNodeGetContent(attr->children);
0233             NDRX_STRCPY_SAFE(cltproc.stat.env, p);
0234             xmlFree(p);
0235         }
0236         else if (0==strcmp((char *)attr->name, "cctag"))
0237         {
0238             p = (char *)xmlNodeGetContent(attr->children);
0239             NDRX_STRCPY_SAFE(cltproc.stat.cctag, p);
0240             xmlFree(p);
0241         }
0242         else if (0==strcmp((char *)attr->name, "wd"))
0243         {
0244             p = (char *)xmlNodeGetContent(attr->children);
0245             NDRX_STRCPY_SAFE(cltproc.stat.wd, p);
0246             xmlFree(p);
0247         }
0248         else if (0==strcmp((char *)attr->name, "stdout"))
0249         {
0250             p = (char *)xmlNodeGetContent(attr->children);
0251             NDRX_STRCPY_SAFE(cltproc.stat.log_stdout, p);
0252             xmlFree(p);
0253         }
0254         else if (0==strcmp((char *)attr->name, "stderr"))
0255         {
0256             p = (char *)xmlNodeGetContent(attr->children);
0257             NDRX_STRCPY_SAFE(cltproc.stat.log_stderr, p);
0258             xmlFree(p);
0259         }
0260         else if (0==strcmp((char *)attr->name, "log"))
0261         {
0262             p = (char *)xmlNodeGetContent(attr->children);
0263             /* Install both: */
0264             NDRX_STRCPY_SAFE(cltproc.stat.log_stdout, p);            
0265             NDRX_STRCPY_SAFE(cltproc.stat.log_stderr, p);
0266             xmlFree(p);
0267         }
0268         else if (0==strcmp((char *)attr->name, "autostart"))
0269         {
0270             p = (char *)xmlNodeGetContent(attr->children);
0271             
0272             if ('Y'==*p || 'y'==*p)
0273             {
0274                 cltproc.stat.flags|=CPM_F_AUTO_START;
0275             }
0276             
0277             xmlFree(p);
0278         }
0279         else if (0==strcmp((char*)attr->name, "rssmax"))
0280         {
0281             p = (char *)xmlNodeGetContent(attr->children);
0282 
0283             if (EXSUCCEED!=ndrx_storage_decode(p, &cltproc.stat.rssmax))
0284             {
0285                 NDRX_LOG(log_error, "Failed to parse `rssmax', invalid value");
0286                 EXFAIL_OUT(ret);
0287             }
0288 
0289             NDRX_LOG(log_debug, "rssmax: %ld bytes", cltproc.stat.rssmax);
0290             xmlFree(p);
0291         }
0292         else if (0==strcmp((char*)attr->name, "vszmax"))
0293         {
0294             p = (char *)xmlNodeGetContent(attr->children);
0295 
0296             if (EXSUCCEED!=ndrx_storage_decode(p, &cltproc.stat.vszmax))
0297             {
0298                 NDRX_LOG(log_error, "Failed to parse `vszmax', invalid value");
0299                 EXFAIL_OUT(ret);
0300             }
0301 
0302             NDRX_LOG(log_debug, "vszmax: %ld bytes", cltproc.stat.vszmax);
0303             xmlFree(p);
0304         }
0305         else if (0==strcmp((char*)attr->name, "subsectfrom"))
0306         {
0307             p = (char *)xmlNodeGetContent(attr->children);
0308 
0309             cltproc.stat.subsectfrom = atoi(p);
0310 
0311             NDRX_LOG(log_debug, "subsectfrom: %d", cltproc.stat.subsectfrom);
0312             xmlFree(p);
0313         }
0314         else if (0==strcmp((char*)attr->name, "subsectto"))
0315         {
0316             p = (char *)xmlNodeGetContent(attr->children);
0317 
0318             cltproc.stat.subsectto = atoi(p);
0319 
0320             NDRX_LOG(log_debug, "subsectto: %d", cltproc.stat.subsectto);
0321             xmlFree(p);
0322         }
0323         else if (0==strcmp((char *)attr->name, "klevel"))
0324         {
0325             int d;
0326             p = (char *)xmlNodeGetContent(attr->children);
0327 
0328             d = atoi(p);
0329 
0330             switch (d)
0331             {
0332                 case 2:
0333                     cltproc.stat.flags|=CPM_F_KILL_LEVEL_HIGH;
0334                 case 1:
0335                     cltproc.stat.flags|=CPM_F_KILL_LEVEL_LOW;
0336                     break;
0337                 case 0:
0338                     cltproc.stat.flags&=~CPM_F_KILL_LEVEL_HIGH;
0339                     cltproc.stat.flags&=~CPM_F_KILL_LEVEL_LOW;
0340             }
0341 
0342             xmlFree(p);
0343         }
0344         else if (0==strcmp((char *)attr->name, "procgrp"))
0345         {
0346             /* singleton group no */
0347             p = (char *)xmlNodeGetContent(attr->children);
0348             p_grp = ndrx_ndrxconf_procgroups_resolvenm(ndrx_G_procgroups_config, p);
0349 
0350             if (NULL==p_grp)
0351             {
0352                 NDRX_LOG(log_error, "Process group not defined: [%s]", p);
0353                 userlog("Process group not defined: [%s]", p);
0354                 xmlFree(p);
0355                 EXFAIL_OUT(ret);
0356             }
0357 
0358             cltproc.stat.procgrp_no=p_grp->grpno;
0359             NDRX_LOG(log_debug, "procgrp_no %d", cltproc.stat.procgrp_no);
0360 
0361             xmlFree(p);
0362         }
0363     }
0364     
0365     /* Check the client config... */
0366     if (EXEOS==cltproc.stat.command_line[0])
0367     {
0368         NDRX_LOG(log_error, "No client name at line %hd", cur->line);
0369         userlog("No client name at line %hd", cur->line);
0370         EXFAIL_OUT(ret);
0371     }
0372     
0373     /* parse tags - we should also move out (save the tag to continue with different client) */
0374     cur=cur->children;
0375 
0376     for (; cur; cur=cur->next)
0377     {
0378         if (0==strcmp("envs", (char *)cur->name))
0379         {
0380             if (EXSUCCEED!=ndrx_ndrxconf_envs_parse(doc, cur, &cltproc.stat.envs,
0381                     M_envgrouphash, NULL))
0382             {
0383                 NDRX_LOG(log_error, "Failed to parse environment groups for clients!");
0384                 userlog("Failed to parse environment groups for clients!");
0385                 EXFAIL_OUT(ret);
0386             }
0387         }
0388         else if (0==strcmp("exec", (char *)cur->name))
0389         {
0390            /* Copy stuff from root elem to heap */
0391             
0392             p_cltproc = NDRX_MALLOC(sizeof(cpm_process_t));
0393             if (NULL==p_cltproc)
0394             {
0395                 NDRX_LOG(log_error, "malloc failed for p_cltproc!");
0396                 userlog("malloc failed for p_cltproc!");
0397                 EXFAIL_OUT(ret);
0398             }
0399             
0400             memcpy(p_cltproc, &cltproc, sizeof(cltproc));
0401             p_cltproc->stat.envs = NULL;
0402             
0403             if (EXSUCCEED!=ndrx_ndrxconf_envs_append(&p_cltproc->stat.envs, 
0404                     cltproc.stat.envs))
0405             {
0406                 NDRX_LOG(log_error, "Failed to join envs %p %p", p_cltproc->stat.envs, 
0407                         cltproc.stat.envs);
0408                 userlog("Failed to join envs %p %p", p_cltproc->stat.envs, 
0409                         cltproc.stat.envs);
0410                 EXFAIL_OUT(ret);
0411             }
0412             
0413             /* Now override the config: */
0414             for (attr=cur->properties; attr; attr = attr->next)
0415             {
0416                 if (0==strcmp((char *)attr->name, "tag"))
0417                 {
0418                     p = (char *)xmlNodeGetContent(attr->children);
0419                     NDRX_STRCPY_SAFE(p_cltproc->tag, p);
0420                     xmlFree(p);
0421                 }
0422                 else if (0==strcmp((char *)attr->name, "subsect"))
0423                 {
0424                     /* Optional */
0425                     p = (char *)xmlNodeGetContent(attr->children);
0426                     NDRX_STRCPY_SAFE(p_cltproc->subsect, p);
0427                     xmlFree(p);
0428                 }
0429                 else if (0==strcmp((char *)attr->name, "env"))
0430                 {
0431                      /* Optional */
0432                     p = (char *)xmlNodeGetContent(attr->children);
0433                     NDRX_STRCPY_SAFE(p_cltproc->stat.env, p);
0434                     xmlFree(p);
0435                 }
0436                 else if (0==strcmp((char *)attr->name, "cctag"))
0437                 {
0438                      /* Optional */
0439                     p = (char *)xmlNodeGetContent(attr->children);
0440                     NDRX_STRCPY_SAFE(p_cltproc->stat.cctag, p);
0441                     xmlFree(p);
0442                 }
0443                 else if (0==strcmp((char *)attr->name, "wd"))
0444                 {
0445                      /* Optional */
0446                     p = (char *)xmlNodeGetContent(attr->children);
0447                     NDRX_STRCPY_SAFE(p_cltproc->stat.wd, p);
0448                     xmlFree(p);
0449                 }
0450                 else if (0==strcmp((char *)attr->name, "stdout"))
0451                 {
0452                     p = (char *)xmlNodeGetContent(attr->children);
0453                     NDRX_STRCPY_SAFE(p_cltproc->stat.log_stdout, p);
0454                     xmlFree(p);
0455                 }
0456                 else if (0==strcmp((char *)attr->name, "stderr"))
0457                 {
0458                     p = (char *)xmlNodeGetContent(attr->children);
0459                     NDRX_STRCPY_SAFE(p_cltproc->stat.log_stderr, p);
0460                     xmlFree(p);
0461                 }
0462                 else if (0==strcmp((char *)attr->name, "log"))
0463                 {
0464                     p = (char *)xmlNodeGetContent(attr->children);
0465                     /* Install both: */
0466                     NDRX_STRCPY_SAFE(p_cltproc->stat.log_stdout, p);
0467                     NDRX_STRCPY_SAFE(p_cltproc->stat.log_stderr, p);
0468                     xmlFree(p);
0469                 }
0470                 else if (0==strcmp((char *)attr->name, "autostart"))
0471                 {
0472                     p = (char *)xmlNodeGetContent(attr->children);
0473 
0474                     if ('Y'==*p || 'y'==*p)
0475                     {
0476                         p_cltproc->stat.flags|=CPM_F_AUTO_START;
0477                     }
0478 
0479                     xmlFree(p);
0480                 }
0481                 else if (0==strcmp((char*)attr->name, "rssmax"))
0482                 {
0483                     p = (char *)xmlNodeGetContent(attr->children);
0484 
0485                     if (EXSUCCEED!=ndrx_storage_decode(p, &p_cltproc->stat.rssmax))
0486                     {
0487                         NDRX_LOG(log_error, "Failed to parse `rssmax', invalid value");
0488                         EXFAIL_OUT(ret);
0489                     }
0490 
0491                     NDRX_LOG(log_debug, "rssmax: %ld bytes", p_cltproc->stat.rssmax);
0492                     xmlFree(p);
0493                 }
0494                 else if (0==strcmp((char*)attr->name, "vszmax"))
0495                 {
0496                     p = (char *)xmlNodeGetContent(attr->children);
0497 
0498                     if (EXSUCCEED!=ndrx_storage_decode(p, &p_cltproc->stat.vszmax))
0499                     {
0500                         NDRX_LOG(log_error, "Failed to parse `vszmax', invalid value");
0501                         EXFAIL_OUT(ret);
0502                     }
0503 
0504                     NDRX_LOG(log_debug, "vszmax: %ld bytes", p_cltproc->stat.vszmax);
0505                     xmlFree(p);
0506                 }
0507                 else if (0==strcmp((char*)attr->name, "subsectfrom"))
0508                 {
0509                     p = (char *)xmlNodeGetContent(attr->children);
0510 
0511                     p_cltproc->stat.subsectfrom = atoi(p);
0512 
0513                     NDRX_LOG(log_debug, "subsectfrom: %d", p_cltproc->stat.subsectfrom);
0514                     xmlFree(p);
0515                 }
0516                 else if (0==strcmp((char*)attr->name, "subsectto"))
0517                 {
0518                     p = (char *)xmlNodeGetContent(attr->children);
0519 
0520                     p_cltproc->stat.subsectto = atoi(p);
0521 
0522                     NDRX_LOG(log_debug, "subsectto: %d", p_cltproc->stat.subsectto);
0523                     xmlFree(p);
0524                 }
0525                 else if (0==strcmp((char *)attr->name, "klevel"))
0526                 {
0527                     int d;
0528                     p = (char *)xmlNodeGetContent(attr->children);
0529 
0530                     d = atoi(p);
0531                     
0532                     switch (d)
0533                     {
0534                         case 2:
0535                             p_cltproc->stat.flags|=CPM_F_KILL_LEVEL_HIGH;
0536                         case 1:
0537                             p_cltproc->stat.flags|=CPM_F_KILL_LEVEL_LOW;
0538                             break;
0539                             
0540                         case 0:
0541                             p_cltproc->stat.flags&=~CPM_F_KILL_LEVEL_HIGH;
0542                             p_cltproc->stat.flags&=~CPM_F_KILL_LEVEL_LOW;
0543                     }
0544 
0545                     xmlFree(p);
0546                 }
0547                 else if (0==strcmp((char *)attr->name, "procgrp"))
0548                 {
0549                     /* singleton group no */
0550                     p = (char *)xmlNodeGetContent(attr->children);
0551                     p_grp = ndrx_ndrxconf_procgroups_resolvenm(ndrx_G_procgroups_config, p);
0552 
0553                     if (NULL==p_grp)
0554                     {
0555                         NDRX_LOG(log_error, "Process group not defined: [%s]", p);
0556                         userlog("Process group not defined: [%s]", p);
0557                         xmlFree(p);
0558                         EXFAIL_OUT(ret);
0559                     }
0560 
0561                     p_cltproc->stat.procgrp_no=p_grp->grpno;
0562                     NDRX_LOG(log_debug, "procgrp_no %d", p_cltproc->stat.procgrp_no);
0563 
0564                     xmlFree(p);
0565                 }
0566             }
0567             
0568             NDRX_LOG(log_debug, "klevel = low=%d high=%d", 
0569                     p_cltproc->stat.flags & CPM_F_KILL_LEVEL_LOW,
0570                     p_cltproc->stat.flags & CPM_F_KILL_LEVEL_HIGH
0571                     );
0572 
0573             /* Check the client config... */
0574             if (EXEOS==p_cltproc->tag[0])
0575             {
0576                 NDRX_LOG(log_error, "Missing tag at line %hd", cur->line);
0577                 userlog("Missing tag at line %hd", cur->line);
0578                 EXFAIL_OUT(ret);
0579             }
0580             
0581             if (p_cltproc->stat.subsectfrom > EXFAIL && 
0582                     p_cltproc->stat.subsectto < p_cltproc->stat.subsectfrom)
0583             {
0584                 NDRX_LOG(log_error, "Invalid subsectfrom/subsectto (<) for [%s] "
0585                         "range at line %hd", p_cltproc->tag, cur->line);
0586                 userlog("Invalid subsectfrom/subsectto (<) for [%s] "
0587                         "range at line %hd", p_cltproc->tag, cur->line);
0588                 EXFAIL_OUT(ret);
0589             }
0590             
0591             if (p_cltproc->stat.subsectto > EXFAIL && p_cltproc->stat.subsectfrom < 0)
0592             {
0593                 NDRX_LOG(log_error, "Invalid config: subsectto (%d) > -1 && "
0594                         "subsectfrom(%d) < 0 for [%s] "
0595                         "range at line %hd", p_cltproc->stat.subsectto, 
0596                         p_cltproc->stat.subsectfrom, 
0597                         p_cltproc->tag, cur->line);
0598                 userlog("Invalid config: subsectto (%d) > -1 && "
0599                         "subsectfrom(%d) < 0 for [%s] "
0600                         "range at line %hd", p_cltproc->stat.subsectto, 
0601                         p_cltproc->stat.subsectfrom, 
0602                         p_cltproc->tag, cur->line);
0603                 EXFAIL_OUT(ret);
0604             }
0605             
0606             if (p_cltproc->stat.subsectfrom > EXFAIL)
0607             {
0608                 genloop = EXTRUE;
0609                 loop_subsectfrom = p_cltproc->stat.subsectfrom;
0610                 loop_subsectto = p_cltproc->stat.subsectto;
0611                 org_cltproc = p_cltproc;
0612             }
0613             else
0614             {
0615                 genloop = EXFALSE;
0616                 
0617                 loop_subsectfrom = 0;
0618                 loop_subsectto = 0;
0619             }
0620             
0621             for (i=loop_subsectfrom; i<loop_subsectto+1; i++)
0622             {
0623                 if (genloop)
0624                 {
0625                     /* Allocate new memory block for  */
0626                     p_cltproc = NDRX_MALLOC(sizeof(cpm_process_t));
0627                     if (NULL==p_cltproc)
0628                     {
0629                         NDRX_LOG(log_error, "malloc failed for p_cltproc (2) at %d!", i);
0630                         userlog("malloc failed for p_cltproc (2) at %d!", i);
0631                         EXFAIL_OUT(ret);
0632                     }
0633                     
0634                     memcpy(p_cltproc, org_cltproc, sizeof(cltproc));
0635                     
0636                     snprintf(p_cltproc->subsect, sizeof(p_cltproc->subsect), 
0637                             "%d", i);
0638                 }
0639                 else
0640                 {
0641                     /* Default the subsect */
0642                     if (EXEOS==p_cltproc->subsect[0])
0643                     {
0644                         NDRX_STRCPY_SAFE(p_cltproc->subsect, "-");
0645                     }
0646                 }
0647                 
0648                 /* Render the final command line */
0649                 if (EXSUCCEED!=setenv(NDRX_CLTTAG, p_cltproc->tag, 1))
0650                 {
0651                     NDRX_LOG(log_error, "Failed to set %s on line %hd", 
0652                             NDRX_CLTTAG, cur->line);
0653                     userlog("Failed to set %s on line %hd", 
0654                             NDRX_CLTTAG, cur->line);
0655                     EXFAIL_OUT(ret);
0656                 }
0657 
0658                 if (EXSUCCEED!=setenv(NDRX_CLTSUBSECT, p_cltproc->subsect, 1))
0659                 {
0660                     NDRX_LOG(log_error, "Failed to set %s on line %hd", 
0661                             NDRX_CLTSUBSECT, cur->line);
0662                     userlog("Failed to set %s on line %hd", 
0663                             NDRX_CLTSUBSECT, cur->line);
0664                     EXFAIL_OUT(ret);   
0665                 }
0666 
0667                 /* format the command line (final) */
0668                 ndrx_str_env_subs_len(p_cltproc->stat.command_line, 
0669                         sizeof(p_cltproc->stat.command_line));
0670                 ndrx_str_env_subs_len(p_cltproc->stat.env, 
0671                         sizeof(p_cltproc->stat.env));
0672                 ndrx_str_env_subs_len(p_cltproc->stat.cctag, 
0673                         sizeof(p_cltproc->stat.cctag));
0674                 ndrx_str_env_subs_len(p_cltproc->stat.wd, 
0675                         sizeof(p_cltproc->stat.wd)); /* working dir */
0676                 /* Expand the logfile path... */
0677                 ndrx_str_env_subs_len(p_cltproc->stat.log_stdout, 
0678                         sizeof(p_cltproc->stat.log_stdout));
0679                 ndrx_str_env_subs_len(p_cltproc->stat.log_stderr, 
0680                         sizeof(p_cltproc->stat.log_stderr));
0681                 
0682                 /* update the process name / hint */
0683 
0684                 NDRX_STRCPY_SAFE(tmp_command_line, p_cltproc->stat.command_line);
0685                 
0686                 token = ndrx_strtokblk(tmp_command_line, NDRX_CMDLINE_SEP, NDRX_CMDLINE_QUOTES);
0687                 
0688                 if (NULL==token)
0689                 {
0690                     NDRX_LOG(log_error, "Invalid command line [%s]", tmp_command_line);
0691                     EXFAIL_OUT(ret);
0692                 }
0693                 
0694                 NDRX_STRCPY_SAFE(p_cltproc->stat.procname, token);
0695                 
0696                 /* add to hash list */
0697                 cpm_get_key(p_cltproc->key, sizeof(p_cltproc->key), 
0698                         p_cltproc->tag, p_cltproc->subsect);
0699 
0700                 /* Try to lookup... */
0701                 p_cl  = cpm_client_get(p_cltproc->tag, p_cltproc->subsect);
0702 
0703                 if (NULL==p_cl)
0704                 {
0705 
0706                     /* Set the time of config load... */
0707                     cpm_set_cur_time(p_cltproc);
0708 
0709                     /* Add to hashlist */
0710                     p_cltproc->is_cfg_refresh = EXTRUE;
0711 
0712                     /* Try to get from hash, if found update the infos but keep the PID */
0713 
0714                     NDRX_LOG(log_info, "Adding %s/%s [%s] to process list", 
0715                             p_cltproc->tag, p_cltproc->subsect, p_cltproc->stat.command_line);
0716                     EXHASH_ADD_STR( G_clt_config, key, p_cltproc );
0717                 }
0718                 else
0719                 {
0720                     NDRX_LOG(log_info, "Refreshing %s/%s [%s] ...", 
0721                             p_cltproc->tag, p_cltproc->subsect, 
0722                             p_cltproc->stat.command_line);
0723                     
0724                     p_cl->is_cfg_refresh = EXTRUE;
0725 
0726 
0727                     /* this will make use of newly allocated env */
0728                     memcpy(&p_cl->stat, &p_cltproc->stat, sizeof(p_cl->stat));
0729 
0730                     p_cl->stat.envs = NULL;
0731 
0732                     if (EXSUCCEED!=ndrx_ndrxconf_envs_append(&p_cl->stat.envs, 
0733                             p_cltproc->stat.envs))
0734                     {
0735                         NDRX_LOG(log_error, "Failed to join envs %p %p", 
0736                                 &p_cl->stat.envs, p_cltproc->stat.envs);
0737                         userlog("Failed to join envs %p %p", "Failed to join envs %p %p", 
0738                                 &p_cl->stat.envs, 
0739                                 p_cltproc->stat.envs);
0740                         EXFAIL_OUT(ret);
0741                     }
0742 
0743                     /* free up current env... */
0744                     ndrx_ndrxconf_envs_envs_free(&p_cltproc->stat.envs);
0745 
0746                     NDRX_FREE(p_cltproc);
0747                 }
0748             } /* for subsectfrom -> subsectto */
0749             
0750             if (genloop)
0751             {
0752                 /* free up first tag client */
0753                 NDRX_FREE(org_cltproc);
0754             }
0755         }
0756     }
0757     
0758 out:
0759 
0760     if (EXFAIL==ret && p_cltproc)
0761     {
0762         NDRX_FREE(p_cltproc);
0763     }
0764 
0765     /* free up envs of the temp process */
0766     if (NULL!=cltproc.stat.envs)
0767     {
0768         ndrx_ndrxconf_envs_envs_free(&cltproc.stat.envs);
0769     }
0770 
0771     return ret;
0772 }
0773 
0774 /**
0775  * parse client entries
0776  * @param doc XML document
0777  * @param cur current cursor pointing to <envs> tag
0778  * @return EXSUCCEED/EXFAIL
0779  */
0780 exprivate int parse_envs(xmlDocPtr doc, xmlNodePtr cur)
0781 {
0782     int ret=EXSUCCEED;
0783 
0784     if (EXSUCCEED!=ndrx_ndrxconf_envs_group_parse(doc, cur, &M_envgrouphash))
0785     {
0786         NDRX_LOG(log_error, "Failed to parse environment groups for clients!");
0787         userlog("Failed to parse environment groups for clients!");
0788         EXFAIL_OUT(ret);
0789     }
0790     
0791 out:    
0792     return ret;
0793 }
0794 
0795 /**
0796  * parse client entries
0797  * @param doc
0798  * @param cur
0799  * @return
0800  */
0801 exprivate int parse_clients(xmlDocPtr doc, xmlNodePtr cur)
0802 {
0803     int ret=EXSUCCEED;
0804 
0805     for (; cur ; cur=cur->next)
0806     {
0807         if (0==strcmp((char*)cur->name, "client"))
0808         {
0809             /* Get the client name */
0810             if (EXSUCCEED!=parse_client(doc, cur))
0811             {
0812                 ret=EXFAIL;
0813                 goto out;
0814             }
0815         }
0816         else if (0==strcmp((char*)cur->name, "envs")
0817                 && EXSUCCEED!=parse_envs(doc, cur))
0818         {
0819             EXFAIL_OUT(ret);
0820         }
0821     }
0822 out:
0823 
0824     if (NULL!=M_envgrouphash)
0825     {
0826        ndrx_ndrxconf_envs_groups_free(&M_envgrouphash);
0827     }
0828     
0829     return ret;
0830 }
0831 
0832 /**
0833  * Parse config out...
0834  * @param doc
0835  * @param cur
0836  * @param config_file_short configuration file name
0837  * @return
0838  */
0839 exprivate int parse_config(xmlDocPtr doc, xmlNodePtr cur, char *config_file_short)
0840 {
0841     int ret=EXSUCCEED;
0842     ndrx_procgroups_t *tmp_conf=NULL;
0843     ndrx_ndrxconf_err_t err;
0844 
0845     if (NULL==cur)
0846     {
0847         NDRX_LOG(log_error, "Empty config?");
0848         ret=EXFAIL;
0849         goto out;
0850     }
0851 
0852     /* Loop over root elements */
0853     do
0854     {
0855         /* Parse client */
0856         if (0==strcmp((char*)cur->name, "clients")
0857                 && EXSUCCEED!=parse_clients(doc, cur->children))
0858         {
0859             EXFAIL_OUT(ret);
0860         }
0861         else if (0==strcmp((char*)cur->name, "procgroups"))
0862         {
0863             ret=ndrx_ndrxconf_procgroups_parse(&tmp_conf,
0864                     doc, cur->children,
0865                     config_file_short, &err);
0866 
0867             if (EXSUCCEED!=ret)
0868             {
0869                 EXFAIL_OUT(ret);
0870             }
0871 
0872             /* apply new configuration */
0873             if (NULL!=ndrx_G_procgroups_config)
0874             {
0875                 ndrx_ndrxconf_procgroups_free(ndrx_G_procgroups_config);
0876             }
0877 
0878             ndrx_G_procgroups_config=tmp_conf;
0879             tmp_conf=NULL;
0880         }
0881         
0882         cur=cur->next;
0883     } while (cur);
0884     
0885 out:
0886 
0887     if (NULL!=tmp_conf)
0888     {
0889         ndrx_ndrxconf_procgroups_free(tmp_conf);
0890     }
0891     
0892     return ret;
0893 }
0894 
0895 /**
0896  * Parses & Loads the platform configuration file.
0897  *
0898  * This initially loads the configuration int internal represtation of the
0899  * configuration file. After that from this info we will build work structures.
0900  */
0901 expublic int load_xml_config(char *config_file)
0902 {
0903     int ret=EXSUCCEED;
0904     xmlDocPtr doc;
0905     xmlNodePtr root;
0906     
0907     doc = xmlReadFile(config_file, NULL, XML_PARSE_NOENT);
0908 
0909     if (!doc)
0910     {
0911         NDRX_LOG(log_error, "Failed to open or parse %s", config_file);
0912         ret=EXFAIL;
0913         goto out;
0914     }
0915 
0916     /* Get root element */
0917     if (!(root = xmlDocGetRootElement(doc)))
0918     {
0919         NDRX_LOG(log_error, "Failed to get root XML element");
0920         ret=EXFAIL;
0921         goto out;
0922     }
0923 
0924     /* Step into first childer */
0925     ret=parse_config(doc, root->children, ndrx_basename(config_file));
0926     
0927 out:
0928 
0929     if (NULL!=doc)
0930     {
0931         /*free the document */
0932         xmlFreeDoc(doc);
0933         /*
0934          *Free the global variables that may
0935          *have been allocated by the parser.
0936          */
0937         xmlCleanupParser();
0938     }
0939 
0940     return ret;
0941 }
0942 
0943 /**
0944  * Load the active configuration.
0945  * @return EXSUCCEED/EXFAIL
0946  */
0947 expublic int load_config(void)
0948 {
0949     int ret = EXSUCCEED;
0950     cpm_process_t *c = NULL;
0951     cpm_process_t *ct = NULL;
0952     
0953     static struct stat prev_attr;
0954     static struct stat attr;
0955 
0956     static int first = EXTRUE;
0957     int was_locked = EXFALSE;
0958     
0959     /* Test for the file time stamp changes */
0960     
0961     if (first)
0962     {
0963         memset(&prev_attr, 0, sizeof(prev_attr));
0964         first = EXFALSE;
0965     }
0966     
0967     memset(&attr, 0, sizeof(attr));
0968     
0969     if (EXSUCCEED!=stat(G_config.config_file, &attr))
0970     {
0971         NDRX_LOG(log_error, "Config file error [%s]: [%s]",
0972                 G_config.config_file, strerror(errno));
0973         userlog("Config file error [%s]: [%s]",
0974                 G_config.config_file, strerror(errno));
0975         EXFAIL_OUT(ret);
0976     }
0977     
0978     if (0!=memcmp(&attr.st_mtime, &prev_attr.st_mtime, sizeof(attr.st_mtime)))
0979     {
0980         prev_attr = attr;
0981     }
0982     else
0983     {
0984         /* config not changed. */
0985         goto out;
0986     }
0987     
0988     /* Mark config as not refreshed */
0989     EXHASH_ITER(hh, G_clt_config, c, ct)
0990     {
0991         c->is_cfg_refresh = EXFALSE;
0992     }
0993 
0994     /* Lock so that background thread cannot access the 
0995      * config during the changes in struct... 
0996      * Bug #108 01/04/2015, mvitolin
0997      */
0998     cpm_lock_config();
0999     was_locked = EXTRUE;
1000     
1001     if (EXSUCCEED!=load_xml_config(G_config.config_file))
1002     {
1003         NDRX_LOG(log_error, "Failed to parse config");
1004         userlog("Failed to parse config");
1005         EXFAIL_OUT(ret);
1006     }
1007     
1008     /* Remove dead un-needed processes (killed & not in new config) */
1009     EXHASH_ITER(hh, G_clt_config, c, ct)
1010     {
1011         if (!c->is_cfg_refresh && CLT_STATE_NOTRUN==c->dyn.cur_state)
1012         {
1013             NDRX_LOG(log_error, "Removing process: [%s]", c->stat.command_line);
1014             
1015             /* clean up environments... */
1016             if (NULL!=c->stat.envs)
1017             {
1018                 ndrx_ndrxconf_envs_envs_free(&c->stat.envs);
1019             }
1020             
1021             EXHASH_DEL(G_clt_config, c);
1022             NDRX_FREE(c);
1023         }
1024     }
1025     
1026 out:
1027 
1028     if (was_locked)
1029     {
1030         cpm_unlock_config();
1031     }
1032     return ret;    
1033 }
1034 
1035 /* vim: set ts=4 sw=4 et smartindent: */