Back to home page

Enduro/X

 
 

    


0001 /* 
0002 ** Client Process Monitor Server
0003 **
0004 ** @file cpmsrv.c
0005 ** 
0006 ** -----------------------------------------------------------------------------
0007 ** Enduro/X Middleware Platform for Distributed Transaction Processing
0008 ** Copyright (C) 2015, Mavimax, Ltd. All Rights Reserved.
0009 ** This software is released under one of the following licenses:
0010 ** GPL or Mavimax's license for commercial use.
0011 ** -----------------------------------------------------------------------------
0012 ** GPL license:
0013 ** 
0014 ** This program is free software; you can redistribute it and/or modify it under
0015 ** the terms of the GNU General Public License as published by the Free Software
0016 ** Foundation; either version 2 of the License, or (at your option) any later
0017 ** version.
0018 **
0019 ** This program is distributed in the hope that it will be useful, but WITHOUT ANY
0020 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0021 ** PARTICULAR PURPOSE. See the GNU General Public License for more details.
0022 **
0023 ** You should have received a copy of the GNU General Public License along with
0024 ** this program; if not, write to the Free Software Foundation, Inc., 59 Temple
0025 ** Place, Suite 330, Boston, MA 02111-1307 USA
0026 **
0027 ** -----------------------------------------------------------------------------
0028 ** A commercial use license is available from Mavimax, Ltd
0029 ** contact@mavimax.com
0030 ** -----------------------------------------------------------------------------
0031 */
0032 #include <ndrx_config.h>
0033 #include <stdio.h>
0034 #include <stdlib.h>
0035 #include <string.h>
0036 #include <errno.h>
0037 #include <regex.h>
0038 #include <utlist.h>
0039 
0040 #ifdef HAVE_GETOPT_H
0041 #include <getopt.h>
0042 #endif
0043 
0044 #include <ndebug.h>
0045 #include <atmi.h>
0046 #include <atmi_int.h>
0047 #include <typed_buf.h>
0048 #include <ndrstandard.h>
0049 #include <ubf.h>
0050 #include <Exfields.h>
0051 #include <nclopt.h>
0052 #include <signal.h>
0053 #include "cpmsrv.h"
0054 #include "userlog.h"
0055 #include <exregex.h>
0056   
0057 /*---------------------------Externs------------------------------------*/
0058 extern int optind, optopt, opterr;
0059 extern char *optarg;
0060 /*---------------------------Macros-------------------------------------*/
0061 /*---------------------------Enums--------------------------------------*/
0062 /*---------------------------Typedefs-----------------------------------*/
0063 /*---------------------------Globals------------------------------------*/
0064 expublic cpmsrv_config_t G_config;
0065 /*---------------------------Statics------------------------------------*/
0066 /*---------------------------Prototypes---------------------------------*/
0067 exprivate int cpm_callback_timer(void);
0068 exprivate int cpm_bc(UBFH *p_ub, int cd);
0069 exprivate int cpm_sc(UBFH *p_ub, int cd);
0070 exprivate int cpm_pc(UBFH *p_ub, int cd);
0071 exprivate int cpm_rc(UBFH *p_ub, int cd);
0072 
0073 exprivate int cpm_bc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, cpm_process_t * c, int *p_nr_proc);
0074 exprivate int cpm_sc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, cpm_process_t * c, int *p_nr_proc);
0075 exprivate int cpm_rc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, cpm_process_t * c, int *p_nr_proc);
0076 
0077 /**
0078  * Client Process Monitor, main thread entry 
0079  * @param p_svc
0080  */
0081 void CPMSVC (TPSVCINFO *p_svc)
0082 {
0083     int ret=EXSUCCEED;
0084     UBFH *p_ub = (UBFH *)p_svc->data;
0085     char cmd[2+1];
0086     char tag[CPM_TAG_LEN]={EXEOS};
0087     char subsect[CPM_SUBSECT_LEN]={EXEOS};
0088     BFLDLEN len = sizeof(cmd);
0089     
0090     p_ub = (UBFH *)tprealloc ((char *)p_ub, Bsizeof (p_ub) + 4096);
0091     
0092     
0093     if (EXSUCCEED!=Bget(p_ub, EX_CPMCOMMAND, 0, cmd, &len))
0094     {
0095         NDRX_LOG(log_error, "missing EX_CPMCOMMAND!");
0096         EXFAIL_OUT(ret);
0097     }
0098     
0099     NDRX_LOG(log_info, "Got command: [%s]", cmd);
0100     
0101     if (0==strcmp(cmd, "bc") || 0==strcmp(cmd, "sc") || 0==strcmp(cmd, "rc"))
0102     {
0103         /* get tag & subsect */
0104         len=sizeof(tag);
0105         Bget(p_ub, EX_CPMTAG, 0, tag, &len);
0106         len=sizeof(subsect);
0107         Bget(p_ub, EX_CPMSUBSECT, 0, subsect, &len);
0108         
0109         if (EXEOS==subsect[0])
0110         {
0111             NDRX_STRCPY_SAFE(subsect, "-");
0112         }
0113     }
0114     else if (0==strcmp(cmd, "pc"))
0115     {
0116         /* Just print the stuff */
0117     }
0118     else 
0119     {
0120         Bchg(p_ub, EX_CPMOUTPUT, 0, "Invalid command!", 0L);
0121         EXFAIL_OUT(ret);
0122     }
0123     
0124     if (EXSUCCEED!=load_config())
0125     {
0126         Bchg(p_ub, EX_CPMOUTPUT, 0, "Failed to load/parse configuration file!", 0L);
0127         EXFAIL_OUT(ret);
0128     }
0129     
0130     if (0==strcmp(cmd, "bc"))
0131     {
0132         /* boot the process (just mark for startup) */
0133         if (EXSUCCEED!=cpm_bc(p_ub, p_svc->cd))
0134         {
0135             EXFAIL_OUT(ret);
0136         }
0137     } 
0138     else if (0==strcmp(cmd, "sc"))
0139     {
0140         /* stop the client process */
0141         if (EXSUCCEED!=cpm_sc(p_ub, p_svc->cd))
0142         {
0143             EXFAIL_OUT(ret);
0144         }
0145     }
0146     else if (0==strcmp(cmd, "pc"))
0147     {
0148         /* Just print the stuff */
0149         cpm_pc(p_ub, p_svc->cd);
0150     }
0151     else if (0==strcmp(cmd, "rc"))
0152     {
0153         /* Just print the stuff */
0154         cpm_rc(p_ub, p_svc->cd);
0155     }
0156 
0157 out:
0158     tpreturn(  ret==EXSUCCEED?TPSUCCESS:TPFAIL,
0159                 0,
0160                 (char *)p_ub,
0161                 0L,
0162                 0L);
0163 }
0164 
0165 /**
0166  * Do initialization
0167  */
0168 int NDRX_INTEGRA(tpsvrinit)(int argc, char **argv)
0169 {
0170     int ret=EXSUCCEED;
0171     signed char c;
0172     struct sigaction sa;
0173     sigset_t wanted; 
0174     NDRX_LOG(log_debug, "tpsvrinit called");
0175     
0176     /* Get the env */
0177     if (NULL==(G_config.config_file = getenv(CONF_NDRX_CONFIG)))
0178     {
0179         NDRX_LOG(log_error, "%s missing env", CONF_NDRX_CONFIG);
0180         userlog("%s missing env", CONF_NDRX_CONFIG);
0181         EXFAIL_OUT(ret);
0182     }
0183     
0184     G_config.chk_interval = EXFAIL;
0185     G_config.kill_interval = EXFAIL;
0186     
0187     /* Parse command line  */
0188     while ((c = getopt(argc, argv, "i:k:")) != -1)
0189     {
0190         NDRX_LOG(log_debug, "%c = [%s]", c, optarg);
0191         switch(c)
0192         {
0193             case 'i': 
0194                 G_config.chk_interval = atoi(optarg);
0195                 break;
0196             case 'k': 
0197                 G_config.kill_interval = atoi(optarg);
0198                 break;
0199             default:
0200                 /*return FAIL;*/
0201                 break;
0202         }
0203     }
0204     
0205     if (EXFAIL==G_config.chk_interval)
0206     {
0207         G_config.chk_interval = CLT_CHK_INTERVAL_DEFAULT;
0208     }
0209     
0210     /* Bug #293 - was not setting kill interval correclty... */
0211     if (EXFAIL==G_config.kill_interval)
0212     {
0213         G_config.kill_interval = CLT_KILL_INTERVAL_DEFAULT;
0214     }
0215 #if 0
0216     /* < seems with out this, sigaction on linux does not work... >*/
0217     sigemptyset(&wanted); 
0218 
0219     sigaddset(&wanted, SIGCHLD); 
0220     if (EXSUCCEED!=pthread_sigmask(SIG_UNBLOCK, &wanted, NULL) )
0221     {
0222         NDRX_LOG(log_error, "pthread_sigmask failed for SIGCHLD: %s", strerror(errno));
0223         EXFAIL_OUT(ret);
0224     }
0225     /* </ seems with out this, sigaction on linux does not work... >*/
0226     
0227     sa.sa_handler = sign_chld_handler;
0228     sigemptyset (&sa.sa_mask);
0229     sa.sa_flags = SA_RESTART;
0230     if (EXFAIL==sigaction (SIGCHLD, &sa, 0))
0231     {
0232         NDRX_LOG(log_error, "sigaction failed for SIGCHLD: %s", strerror(errno));
0233         EXFAIL_OUT(ret);
0234     }
0235 #endif
0236 
0237 #ifndef EX_CPM_NO_THREADS
0238     ndrxd_sigchld_init();
0239 #endif
0240     /* signal(SIGCHLD, sign_chld_handler); */
0241     
0242     /* Load initial config */
0243     if (EXSUCCEED!=load_config())
0244     {
0245         NDRX_LOG(log_error, "Failed to load client config!");
0246         EXFAIL_OUT(ret);
0247     }
0248     
0249     if (EXSUCCEED!=tpadvertise(NDRX_SVC_CPM, CPMSVC))
0250     {
0251         NDRX_LOG(log_error, "Failed to initialize CPMSVC!");
0252         EXFAIL_OUT(ret);
0253     }
0254     
0255     /* Register callback timer */
0256     if (EXSUCCEED!=tpext_addperiodcb(G_config.chk_interval, cpm_callback_timer))
0257     {
0258             ret=EXFAIL;
0259             NDRX_LOG(log_error, "tpext_addperiodcb failed: %s",
0260                             tpstrerror(tperrno));
0261     }
0262     
0263     NDRX_LOG(log_info, "Config file: [%s]", G_config.config_file );
0264     NDRX_LOG(log_info, "Process checking interval (-i): [%d]", G_config.chk_interval);
0265     NDRX_LOG(log_info, "Process kill interval (-i): [%d]", G_config.kill_interval);
0266     
0267     /* Process the timer now.... */
0268     cpm_start_all(); /* Mark all to be started */
0269     cpm_callback_timer(); /* Start them all. */
0270     
0271 out:
0272     return ret;
0273 }
0274 
0275 /**
0276  * Do de-initialization
0277  */
0278 void NDRX_INTEGRA(tpsvrdone)(void)
0279 {
0280     cpm_process_t *c = NULL;
0281     cpm_process_t *ct = NULL;
0282     
0283     NDRX_LOG(log_debug, "tpsvrdone called - shutting down client processes...");
0284     
0285     cpm_killall();
0286     
0287 #ifndef EX_CPM_NO_THREADS
0288     ndrxd_sigchld_uninit();
0289 #endif
0290 
0291 }
0292 
0293 /**
0294  * Callback function for periodic timer
0295  * We need a timer here cause SIGCHILD causes poller interrupts.
0296  * @return 
0297  */
0298 exprivate int cpm_callback_timer(void)
0299 {
0300     int ret = EXSUCCEED;
0301     cpm_process_t *c = NULL;
0302     cpm_process_t *ct = NULL;
0303     static int first = EXTRUE;
0304     static ndrx_stopwatch_t t;
0305     
0306     if (first)
0307     {
0308         first = EXFALSE;
0309         ndrx_stopwatch_reset(&t);
0310     }
0311 
0312 #ifdef EX_CPM_NO_THREADS
0313     /* Process any dead child... */
0314     sign_chld_handler(SIGCHLD);
0315 #endif
0316     
0317     if (ndrx_stopwatch_get_delta_sec(&t) < G_config.chk_interval)
0318     {
0319         goto out;
0320     }
0321     
0322     ndrx_stopwatch_reset(&t);
0323     
0324     
0325     NDRX_LOG(log_debug, "cpm_callback_timer() enter");
0326             
0327     /* Mark config as not refreshed */
0328     EXHASH_ITER(hh, G_clt_config, c, ct)
0329     {
0330         NDRX_LOG(log_debug, "%s/%s req %d cur %d", 
0331                 c->tag, c->subsect, c->dyn.req_state, c->dyn.cur_state);
0332         
0333         if ((CLT_STATE_NOTRUN==c->dyn.cur_state ||
0334                 CLT_STATE_STARTING==c->dyn.cur_state)  &&
0335                 CLT_STATE_STARTED==c->dyn.req_state)
0336         {
0337             /* Try to boot the process... */
0338             cpm_exec(c);
0339         }
0340     }
0341     /* handle any signal 
0342     sign_chld_handler(SIGCHLD); */
0343     
0344 out:
0345     return EXSUCCEED;
0346 }
0347 
0348 /**
0349  * Send message user.
0350  * @param p_ub
0351  * @param cd
0352  * @param msg
0353  */
0354 exprivate void cpm_send_msg(UBFH *p_ub, int cd, char *msg)
0355 {
0356     long revent;
0357     
0358     Bchg(p_ub, EX_CPMOUTPUT, 0, msg, 0L);
0359     
0360     if (EXFAIL == tpsend(cd,
0361                         (char *)p_ub,
0362                         0L,
0363                         0,
0364                         &revent))
0365     {
0366         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0367                             tpstrerror(tperrno), revent);
0368     }
0369     else
0370     {
0371         NDRX_LOG(log_debug,"sent ok");
0372     }
0373 }
0374 
0375 /**
0376  * Stop single client
0377  * @param p_ub
0378  * @param cd
0379  * @param tag
0380  * @param subsect
0381  * @param c
0382  * @return EXSUCCEED/EXFAIL
0383  */
0384 exprivate int cpm_sc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0385         cpm_process_t * c, int *p_nr_proc)
0386 {
0387     int ret = EXSUCCEED;
0388     long revent;
0389     char debug[256];
0390     
0391     c = cpm_client_get(tag, subsect);
0392     
0393     if (NULL==c)
0394     {
0395         snprintf(debug, sizeof(debug), "Client process %s/%s not found!", 
0396                 tag, subsect);
0397         NDRX_LOG(log_error, "%s", debug);
0398         userlog("%s!", debug);
0399         Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0400         EXFAIL_OUT(ret);
0401     }
0402     else
0403     {
0404         (*p_nr_proc)++;
0405         
0406         c->dyn.req_state = CLT_STATE_NOTRUN;
0407         
0408         if (CLT_STATE_STARTED ==  c->dyn.cur_state)
0409         {
0410             if (EXSUCCEED==cpm_kill(c))
0411             {
0412                 snprintf(debug, sizeof(debug), "Client process %s/%s stopped", 
0413                         tag, subsect);
0414                 NDRX_LOG(log_info, "%s", debug);
0415                 Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0416             }
0417             else
0418             {
0419                 snprintf(debug, sizeof(debug), "Failed to stop %s/%s!", 
0420                         tag, subsect);
0421                 NDRX_LOG(log_info, "%s", debug);
0422                 Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0423             }
0424         }
0425         else
0426         {
0427             snprintf(debug, sizeof(debug), "Client process %s/%s not running already...", 
0428                     tag, subsect);
0429             NDRX_LOG(log_info, "%s", debug);
0430             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0431         }
0432     }
0433 out:
0434 
0435     if (EXFAIL == tpsend(cd,
0436                         (char *)p_ub,
0437                         0L,
0438                         0,
0439                         &revent))
0440     {
0441         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0442                             tpstrerror(tperrno), revent);
0443     }
0444     else
0445     {
0446         NDRX_LOG(log_debug,"sent ok");
0447     }
0448 
0449                 
0450     return ret;
0451 }
0452 
0453 /**
0454  * Reboot the client
0455  * @param p_ub
0456  * @param cd
0457  * @param tag
0458  * @param subsect
0459  * @param c
0460  * @return 
0461  */
0462 exprivate int cpm_rc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0463         cpm_process_t * c, int *p_nr_proc)
0464 {   
0465     int ret = EXSUCCEED;
0466     int dum;
0467     /* will do over those binary which are request to be started... */
0468     if (CLT_STATE_STARTED ==  c->dyn.req_state)
0469     {
0470         (*p_nr_proc)++;
0471         /* restart if any running... */
0472         NDRX_LOG(log_debug, "[%s]/[%s] running - restarting...", tag, subsect);
0473         
0474         NDRX_LOG(log_debug, "About to stop...");
0475         if (EXSUCCEED!=cpm_sc_obj(p_ub, cd, tag, subsect, c, &dum))
0476         {
0477             NDRX_LOG(log_error, "Failed to stop [%s]/[%s]", tag, subsect);
0478             EXFAIL_OUT(ret);
0479         }
0480         
0481         NDRX_LOG(log_debug, "About to start...");
0482         if (EXSUCCEED!=cpm_bc_obj(p_ub, cd, tag, subsect, c, &dum))
0483         {
0484             NDRX_LOG(log_error, "Failed to start [%s]/[%s]", tag, subsect);
0485             EXFAIL_OUT(ret);
0486         }
0487         
0488         
0489     }
0490 out:
0491     return ret;
0492 }
0493 
0494 /**
0495  * Process single object and send the results to client
0496  * @param p_ub
0497  * @param tag
0498  * @param subsect
0499  * @param c
0500  * @return 
0501  */
0502 exprivate int cpm_bc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0503         cpm_process_t * c, int *p_nr_proc)
0504 {
0505     int ret = EXSUCCEED;
0506     long revent;
0507     char debug[256];
0508     
0509     NDRX_LOG(log_debug, "Into %s: p_ub=%p, cd=%d, tag=[%s] subsect=[%s], c=%p",
0510             __func__, p_ub, cd, tag, subsect, c);
0511     
0512     if (NULL==c)
0513     {
0514         snprintf(debug, sizeof(debug), "Client process %s/%s not found!", 
0515                 tag, subsect);
0516         NDRX_LOG(log_error, "%s", debug);
0517         userlog("%s!", debug);
0518         Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0519         EXFAIL_OUT(ret);
0520     }
0521     else
0522     {
0523         (*p_nr_proc)++;
0524         
0525         if (CLT_STATE_STARTED != c->dyn.cur_state)
0526         {
0527             snprintf(debug, sizeof(debug), "Client process %s/%s marked for start", 
0528                     tag, subsect);
0529             NDRX_LOG(log_info, "%s", debug);
0530             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0531 
0532             c->dyn.cur_state = CLT_STATE_STARTING;
0533             c->dyn.req_state = CLT_STATE_STARTED;
0534         }
0535         else
0536         {
0537             snprintf(debug, sizeof(debug), "Process %s/%s already marked "
0538                                 "for startup or running...", tag, subsect);
0539             NDRX_LOG(log_info, "%s", debug);
0540             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0541         }
0542     }
0543     
0544 out:
0545          
0546     if (EXFAIL == tpsend(cd,
0547                         (char *)p_ub,
0548                         0L,
0549                         0,
0550                         &revent))
0551     {
0552         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0553                             tpstrerror(tperrno), revent);
0554     }
0555     else
0556     {
0557         NDRX_LOG(log_debug,"sent ok");
0558     }
0559 
0560                 
0561     return ret;
0562 }
0563 
0564 /**
0565  * Start/Stop client the client process
0566  * @param p_ub
0567  * @param cd
0568  * @return 
0569  */
0570 exprivate int cpm_bcscrc(UBFH *p_ub, int cd, 
0571         int(*p_func)(UBFH *, int, char*, char*,cpm_process_t *, int *p_nr_proc), 
0572         char *finish_msg)
0573 {
0574     long twait = 0;
0575     int ret = EXSUCCEED;
0576     char msg[256];
0577     cpm_process_t *c = NULL, *ct = NULL;
0578     
0579     char tag[CPM_TAG_LEN+1];
0580     char subsect[CPM_SUBSECT_LEN+1];
0581     
0582     char regex_tag[CPM_TAG_LEN * 2 + 2 + 1]; /* all symbols can be escaped, 
0583                                             * have ^$ start/end and EOS */
0584     char regex_subsect[CPM_SUBSECT_LEN * 2 + 2 + 1];
0585     
0586     regex_t r_comp_tag;
0587     int r_comp_tag_alloc = EXFALSE;
0588     
0589     regex_t r_comp_subsect;
0590     int r_comp_subsect_alloc = EXFALSE;
0591     
0592     int nr_proc = 0;
0593     
0594     if (EXSUCCEED!=Bget(p_ub, EX_CPMTAG, 0, tag, 0L))
0595     {
0596         NDRX_LOG(log_error, "Missing EX_CPMTAG!");
0597     }
0598     
0599     if (EXSUCCEED!=Bget(p_ub, EX_CPMSUBSECT, 0, subsect, 0L))
0600     {
0601         NDRX_STRCPY_SAFE(subsect, "-");
0602     }
0603     
0604     Bget(p_ub, EX_CPMWAIT, 0, (char *)&twait, 0L);
0605     
0606     if (NULL==strchr(tag,CLT_WILDCARD) && NULL==strchr(subsect, CLT_WILDCARD))
0607     {
0608         c = cpm_client_get(tag, subsect);
0609         if (EXSUCCEED!=(p_func(p_ub, cd, tag, subsect, c, &nr_proc)))
0610         {
0611             NDRX_LOG(log_error, "%s: cpm_bc_obj failed", __func__);
0612             EXFAIL_OUT(ret);
0613         }
0614     }
0615     else
0616     {
0617         /* Expand to regular expressions... */
0618         ndrx_regasc_cpyesc(regex_tag, tag, '^', '$', '%', ".*");
0619         NDRX_LOG(log_debug, "Got regex tag: [%s]", tag);
0620         if (EXSUCCEED!=ndrx_regcomp(&r_comp_tag, regex_tag))
0621         {
0622             NDRX_LOG(log_error, "Failed to compile regexp of tag!");
0623             
0624             snprintf(msg, sizeof(msg), "Failed to compile regexp of tag[%s]!",
0625                     regex_tag);    
0626             cpm_send_msg(p_ub, cd, msg);
0627         }
0628         r_comp_tag_alloc=EXTRUE;
0629         
0630         
0631         ndrx_regasc_cpyesc(regex_subsect, subsect, '^', '$', '%', ".*");
0632         NDRX_LOG(log_debug, "Got regex subsect: [%s]", subsect);
0633         
0634         if (EXSUCCEED!=ndrx_regcomp(&r_comp_subsect, regex_subsect))
0635         {
0636             NDRX_LOG(log_error, "Failed to compile regexp of subsect!");
0637             
0638             snprintf(msg, sizeof(msg), "Failed to compile regexp of subsect[%s]!",
0639                     regex_subsect);
0640             cpm_send_msg(p_ub, cd, msg);
0641         }
0642         r_comp_subsect_alloc=EXTRUE;
0643         
0644         /* loop over the hash */
0645         EXHASH_ITER(hh, G_clt_config, c, ct)
0646         {
0647             if (EXSUCCEED==ndrx_regexec(&r_comp_tag, c->tag) && 
0648                     EXSUCCEED==ndrx_regexec(&r_comp_subsect, c->subsect))
0649             {
0650                 int cur_nr_proc = nr_proc;
0651                 NDRX_LOG(log_debug, "[%s]/[%s] - matched", c->tag, c->subsect);
0652                 
0653                 
0654                 if (EXSUCCEED!=p_func(p_ub, cd, c->tag, c->subsect, c, &nr_proc))
0655                 {
0656                     NDRX_LOG(log_error, "Matched process [%s]/[%s] failed to start/stop",
0657                             c->tag, c->subsect);
0658                 }
0659                 
0660                 if (cur_nr_proc!=nr_proc && twait > 0)
0661                 {
0662                     NDRX_LOG(log_debug, "Sleeping %d millisec", twait);
0663                     usleep(twait*1000);
0664                 }
0665             }
0666             else
0667             {
0668                 NDRX_LOG(log_debug, "[%s]/[%s] - NOT matched", c->tag, c->subsect);
0669             }
0670         }
0671         snprintf(msg, sizeof(msg), "%d client(s) %s.", nr_proc, finish_msg);
0672         cpm_send_msg(p_ub, cd, msg);
0673     }
0674         
0675 out:
0676                 
0677     if (r_comp_tag_alloc)
0678     {
0679         ndrx_regfree(&r_comp_tag);
0680     }
0681 
0682     if (r_comp_subsect_alloc)
0683     {
0684         ndrx_regfree(&r_comp_subsect);
0685     }
0686 
0687     return ret;
0688 }
0689 
0690 /**
0691  * Boot client
0692  * @param p_ub
0693  * @param cd
0694  * @return 
0695  */
0696 exprivate int cpm_bc(UBFH *p_ub, int cd)
0697 {
0698     NDRX_LOG(log_debug, "Into %s", __func__);
0699     return cpm_bcscrc(p_ub, cd, cpm_bc_obj, "marked for started");
0700 }
0701 
0702 
0703 /**
0704  * Stop the client process
0705  * @param p_ub
0706  * @param cd
0707  * @return 
0708  */
0709 exprivate int cpm_sc(UBFH *p_ub, int cd)
0710 {   
0711     NDRX_LOG(log_debug, "Into %s", __func__);
0712     return cpm_bcscrc(p_ub, cd, cpm_sc_obj, "stopped");
0713 }
0714 
0715 /**
0716  * Print clients
0717  * @param p_ub
0718  * @param cd - call descriptor
0719  * @return 
0720  */
0721 exprivate int cpm_pc(UBFH *p_ub, int cd)
0722 {
0723     int ret = EXSUCCEED;
0724     long revent;
0725     cpm_process_t *c = NULL;
0726     cpm_process_t *ct = NULL;
0727     char output[256];
0728     char buffer [80];
0729     struct tm * timeinfo;
0730     
0731     NDRX_LOG(log_info, "cpm_pc: listing clients");
0732     /* Remove dead un-needed processes (killed & not in new config) */
0733     EXHASH_ITER(hh, G_clt_config, c, ct)
0734     {
0735         
0736         NDRX_LOG(log_info, "cpm_pc: %s/%s", c->tag, c->subsect);
0737         
0738         timeinfo = localtime (&c->dyn.stattime);
0739         strftime (buffer,80,"%c",timeinfo);
0740     
0741         if (CLT_STATE_STARTED == c->dyn.cur_state)
0742         {
0743             snprintf(output, sizeof(output), "%s/%s - running pid %d (%s)",
0744                                 c->tag, c->subsect, c->dyn.pid, buffer);
0745         }
0746         else if (CLT_STATE_STARTING == c->dyn.cur_state && 
0747                 c->dyn.req_state != CLT_STATE_NOTRUN)
0748         {
0749             snprintf(output, sizeof(output), "%s/%s - starting (%s)",c->tag, 
0750                     c->subsect, buffer);
0751         }
0752         else if (c->dyn.was_started && (c->dyn.req_state == CLT_STATE_STARTED) )
0753         {
0754             snprintf(output, sizeof(output), "%s/%s - dead %d (%s)", c->tag, c->subsect, 
0755                     c->dyn.exit_status, buffer);
0756         }
0757         else if (c->dyn.was_started && (c->dyn.req_state == CLT_STATE_NOTRUN) )
0758         {
0759             snprintf(output, sizeof(output), "%s/%s - shutdown (%s)", c->tag, c->subsect, 
0760                     buffer);
0761         }
0762         else
0763         {
0764             snprintf(output, sizeof(output), "%s/%s - not started", c->tag, c->subsect);
0765         }
0766         
0767         if (EXSUCCEED!=Bchg(p_ub, EX_CPMOUTPUT, 0, output, 0L))
0768         {
0769             NDRX_LOG(log_error, "Failed to read fields: [%s]", 
0770                 Bstrerror(Berror));
0771             EXFAIL_OUT(ret);
0772         }
0773         
0774         if (EXFAIL == tpsend(cd,
0775                             (char *)p_ub,
0776                             0L,
0777                             0,
0778                             &revent))
0779         {
0780             NDRX_LOG(log_error, "Send data failed [%s] %ld",
0781                                 tpstrerror(tperrno), revent);
0782             EXFAIL_OUT(ret);
0783         }
0784         else
0785         {
0786             NDRX_LOG(log_debug,"sent ok");
0787         }
0788     }
0789     
0790 out:
0791 
0792     return ret;
0793 }
0794 
0795 /**
0796  * Reload clients (restart one by one)
0797  * @param p_ub
0798  * @param cd
0799  * @return 
0800  */
0801 exprivate int cpm_rc(UBFH *p_ub, int cd)
0802 {   
0803     NDRX_LOG(log_debug, "Into %s", __func__);
0804     return cpm_bcscrc(p_ub, cd, cpm_rc_obj, "restarted");
0805 }