Back to home page

Enduro/X

 
 

    


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