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-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 <stdio.h>
0036 #include <stdlib.h>
0037 #include <string.h>
0038 #include <errno.h>
0039 #include <regex.h>
0040 #include <utlist.h>
0041 #include <unistd.h>    /* for getopt */
0042 
0043 #include <ndebug.h>
0044 #include <atmi.h>
0045 #include <atmi_int.h>
0046 #include <typed_buf.h>
0047 #include <ndrstandard.h>
0048 #include <ubf.h>
0049 #include <Exfields.h>
0050 #include <nclopt.h>
0051 #include <signal.h>
0052 #include "cpmsrv.h"
0053 #include "userlog.h"
0054 #include <exregex.h>
0055 #include <exhash.h>
0056 #include <singlegrp.h>
0057 #include <lcfint.h>
0058 
0059 /*---------------------------Externs------------------------------------*/
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     if (EXSUCCEED!=Bget(p_ub, EX_CPMCOMMAND, 0, cmd, &len))
0093     {
0094         NDRX_LOG(log_error, "missing EX_CPMCOMMAND!");
0095         EXFAIL_OUT(ret);
0096     }
0097     
0098     NDRX_LOG(log_info, "Got command: [%s]", cmd);
0099     
0100     if (0==strcmp(cmd, "bc") || 0==strcmp(cmd, "sc") || 0==strcmp(cmd, "rc"))
0101     {
0102         /* get tag & subsect */
0103         len=sizeof(tag);
0104         Bget(p_ub, EX_CPMTAG, 0, tag, &len);
0105         len=sizeof(subsect);
0106         Bget(p_ub, EX_CPMSUBSECT, 0, subsect, &len);
0107         
0108         if (EXEOS==subsect[0])
0109         {
0110             NDRX_STRCPY_SAFE(subsect, "-");
0111         }
0112     }
0113     else if (0==strcmp(cmd, "pc"))
0114     {
0115         /* Just print the stuff */
0116     }
0117     else 
0118     {
0119         Bchg(p_ub, EX_CPMOUTPUT, 0, "Invalid command!", 0L);
0120         EXFAIL_OUT(ret);
0121     }
0122     
0123     if (EXSUCCEED!=load_config())
0124     {
0125         Bchg(p_ub, EX_CPMOUTPUT, 0, "Failed to load/parse configuration file!", 0L);
0126         EXFAIL_OUT(ret);
0127     }
0128     
0129     if (0==strcmp(cmd, "bc"))
0130     {
0131         /* boot the process (just mark for startup) */
0132         if (EXSUCCEED!=cpm_bc(p_ub, p_svc->cd))
0133         {
0134             EXFAIL_OUT(ret);
0135         }
0136     } 
0137     else if (0==strcmp(cmd, "sc"))
0138     {
0139         /* stop the client process */
0140         if (EXSUCCEED!=cpm_sc(p_ub, p_svc->cd))
0141         {
0142             EXFAIL_OUT(ret);
0143         }
0144     }
0145     else if (0==strcmp(cmd, "pc"))
0146     {
0147         /* Just print the stuff */
0148         cpm_pc(p_ub, p_svc->cd);
0149     }
0150     else if (0==strcmp(cmd, "rc"))
0151     {
0152         /* Just print the stuff */
0153         cpm_rc(p_ub, p_svc->cd);
0154     }
0155 
0156 out:
0157     tpreturn(  ret==EXSUCCEED?TPSUCCESS:TPFAIL,
0158                 0,
0159                 (char *)p_ub,
0160                 0L,
0161                 0L);
0162 }
0163 
0164 /**
0165  * Do initialization
0166  */
0167 int NDRX_INTEGRA(tpsvrinit)(int argc, char **argv)
0168 {
0169     int ret=EXSUCCEED;
0170     int  c;
0171     sigset_t blockMask;
0172     NDRX_LOG(log_debug, "tpsvrinit called");
0173     
0174     /* Get the env */
0175     if (NULL==(G_config.config_file = getenv(CONF_NDRX_CONFIG)))
0176     {
0177         NDRX_LOG(log_error, "%s missing env", CONF_NDRX_CONFIG);
0178         userlog("%s missing env", CONF_NDRX_CONFIG);
0179         EXFAIL_OUT(ret);
0180     }
0181     
0182     G_config.chk_interval = EXFAIL;
0183     G_config.kill_interval = EXFAIL;
0184     
0185     /* Parse command line  */
0186     while ((c = getopt(argc, argv, "i:k:")) != -1)
0187     {
0188 
0189         if (optarg)
0190         {
0191             NDRX_LOG(log_debug, "%c = [%s]", c, optarg);
0192         }
0193         else
0194         {
0195             NDRX_LOG(log_debug, "got %c", c);
0196         }
0197 
0198         switch(c)
0199         {
0200             case 'i': 
0201                 G_config.chk_interval = atoi(optarg);
0202                 break;
0203             case 'k': 
0204                 G_config.kill_interval = atoi(optarg);
0205                 break;
0206             default:
0207                 /*return FAIL;*/
0208                 break;
0209         }
0210     }
0211     
0212     if (EXFAIL==G_config.chk_interval)
0213     {
0214         G_config.chk_interval = CLT_CHK_INTERVAL_DEFAULT;
0215     }
0216     
0217     /* Bug #293 - was not setting kill interval correclty... */
0218     if (EXFAIL==G_config.kill_interval)
0219     {
0220         G_config.kill_interval = CLT_KILL_INTERVAL_DEFAULT;
0221     }
0222 
0223     /* do not want signals... was we will wait for pid
0224      * in threaded and non threaded mode.
0225      */
0226     sigemptyset(&blockMask);
0227     sigaddset(&blockMask, SIGCHLD);
0228     
0229     if (sigprocmask(SIG_BLOCK, &blockMask, NULL) == -1)
0230     {
0231         NDRX_LOG(log_always, "%s: sigprocmask failed: %s",
0232                 __func__, strerror(errno));
0233     }
0234 
0235     if (EXSUCCEED!=cpm_sigchld_init())
0236     {
0237         NDRX_LOG(log_error, "Failed to init signal thread");
0238         EXFAIL_OUT(ret);
0239     }
0240     
0241     /* attach to the shared memory */
0242     if (EXSUCCEED!=ndrx_cltshm_init(EXFALSE))
0243     {
0244         NDRX_LOG(log_error, "Failed to open client shared memory segment!");
0245         EXFAIL_OUT(ret);
0246     }
0247     
0248     /* Load initial config */
0249     if (EXSUCCEED!=load_config())
0250     {
0251         NDRX_LOG(log_error, "Failed to load client config!");
0252         EXFAIL_OUT(ret);
0253     }
0254     
0255     if (EXSUCCEED!=tpadvertise(NDRX_SVC_CPM, CPMSVC))
0256     {
0257         NDRX_LOG(log_error, "Failed to initialize CPMSVC!");
0258         EXFAIL_OUT(ret);
0259     }
0260     
0261     /* Register callback timer */
0262     if (EXSUCCEED!=tpext_addperiodcb(G_config.chk_interval, cpm_callback_timer))
0263     {
0264         ret=EXFAIL;
0265         NDRX_LOG(log_error, "tpext_addperiodcb failed: %s",
0266                         tpstrerror(tperrno));
0267     }
0268     
0269     NDRX_LOG(log_info, "Config file: [%s]", G_config.config_file );
0270     NDRX_LOG(log_info, "Process checking interval (-i): [%d]", G_config.chk_interval);
0271     NDRX_LOG(log_info, "Process kill interval (-i): [%d]", G_config.kill_interval);
0272     
0273     /* Process the timer now.... */
0274     cpm_start_all(); /* Mark all to be started */
0275     
0276     /* sync with SHM.... */
0277     if (EXSUCCEED!=ndrx_cpm_sync_from_shm())
0278     {
0279         NDRX_LOG(log_error, "Failed to sync current status with shared memory!");
0280         EXFAIL_OUT(ret);
0281     }
0282     
0283     cpm_callback_timer(); /* Start them all. */
0284     
0285 out:
0286     return ret;
0287 }
0288 
0289 /**
0290  * Do de-initialization
0291  */
0292 void NDRX_INTEGRA(tpsvrdone)(void)
0293 {
0294     
0295     NDRX_LOG(log_debug, "tpsvrdone called - shutting down client processes...");
0296     
0297     cpm_killall();
0298     cpm_sigchld_uninit();
0299     ndrx_cltshm_detach();
0300     ndrx_cltshm_remove(EXFALSE);
0301 
0302 }
0303 
0304 /**
0305  * Callback function for periodic timer
0306  * We need a timer here cause SIGCHILD causes poller interrupts.
0307  * @return 
0308  */
0309 exprivate int cpm_callback_timer(void)
0310 {
0311     int ret = EXSUCCEED;
0312     int i;
0313     cpm_process_t *c = NULL;
0314     cpm_process_t *ct = NULL;
0315     static int first = EXTRUE;
0316     static ndrx_stopwatch_t t;
0317     int nrgrps = ndrx_G_libnstd_cfg.pgmax;
0318     int sg_groups[nrgrps];
0319     
0320     if (first)
0321     {
0322         first = EXFALSE;
0323         ndrx_stopwatch_reset(&t);
0324     }
0325 
0326     if (ndrx_stopwatch_get_delta_sec(&t) < G_config.chk_interval)
0327     {
0328         goto out;
0329     }
0330     
0331     ndrx_stopwatch_reset(&t);
0332     
0333     NDRX_LOG(log_debug, "cpm_callback_timer() enter");
0334 
0335     /* Take a group snapshoot
0336      * Check lock here only once, as spawning is quick (no wait on status...)
0337      * if in-order group, check that servers are booted in first place and only then
0338      * boot this group of clients.
0339      */
0340     ndrx_sg_get_lock_snapshoot(sg_groups, &nrgrps, NDRX_SG_SRVBOOTCHK);
0341 
0342     /* Mark config as not refreshed */
0343     EXHASH_ITER(hh, G_clt_config, c, ct)
0344     {
0345         NDRX_LOG(log_debug, "%s/%s req %d cur %d", 
0346                 c->tag, c->subsect, c->dyn.req_state, c->dyn.cur_state);
0347         
0348         if ((CLT_STATE_NOTRUN==c->dyn.cur_state ||
0349                 CLT_STATE_STARTING==c->dyn.cur_state ||
0350                 CLT_STATE_WAIT==c->dyn.cur_state)  &&
0351                 CLT_STATE_STARTED==c->dyn.req_state)
0352         {
0353             /* check the group state... */
0354             if (c->stat.procgrp_no > 0 
0355                 && ndrx_ndrxconf_procgroups_is_singleton(ndrx_G_procgroups_config
0356                     , c->stat.procgrp_no)
0357                 && !sg_groups[c->stat.procgrp_no-1])
0358             {
0359                 if (CLT_STATE_WAIT!=c->dyn.cur_state)
0360                 {
0361                     /* can do without lock, as no threads may set
0362                      * other status, as process is not running
0363                      */
0364                     c->dyn.cur_state=CLT_STATE_WAIT;
0365                     cpm_set_cur_time(c);
0366                 }
0367             }
0368             else
0369             {
0370                 /* Try to boot the process... */
0371                 cpm_exec(c);
0372             }
0373         }
0374         else if (CLT_STATE_STARTED==c->dyn.cur_state && 
0375                 (EXFAIL!=c->stat.rssmax || EXFAIL!=c->stat.vszmax)
0376                 )
0377         {
0378             /* Check for memory limits if defined... */
0379             ndrx_proc_info_t inf;
0380             
0381             /* perform tests..., read current settings */
0382             if (EXSUCCEED==ndrx_proc_get_infos(c->dyn.pid, &inf))
0383             {
0384                 int reached = EXFALSE;
0385                 char memtype[4];
0386                 long lim_val;
0387                 long lim_max;
0388                 
0389                 if (c->stat.rssmax!=EXFAIL &&
0390                         inf.rss * NDRX_STOR_KBYTE > c->stat.rssmax)
0391                 {
0392                     reached = EXTRUE;
0393                     lim_val = inf.rss * NDRX_STOR_KBYTE;
0394                     lim_max = c->stat.rssmax;
0395                     NDRX_STRCPY_SAFE(memtype, "RSS");
0396                 }
0397                 else if (c->stat.vszmax!=EXFAIL &&
0398                         inf.vsz * NDRX_STOR_KBYTE > c->stat.vszmax)
0399                 {
0400                     reached = EXTRUE;
0401                     lim_val = inf.vsz * NDRX_STOR_KBYTE;
0402                     lim_max = c->stat.vszmax;
0403                     NDRX_STRCPY_SAFE(memtype, "VSZ");
0404                 }
0405                 
0406                 if (reached)
0407                 {
0408                     char limitbuf[256];
0409                     char valuebuf[256];
0410                     
0411                     ndrx_storage_encode(lim_max, limitbuf, sizeof(limitbuf));
0412                     ndrx_storage_encode(lim_val, valuebuf, sizeof(valuebuf));
0413                     
0414                     NDRX_LOG(log_error, "Client pid = %d, cmdline [%s] "
0415                             "%s memory limit reached: "
0416                             "configured max: %s in system found: %s - restarting...",
0417                             (int)c->dyn.pid, c->stat.command_line,
0418                             memtype, limitbuf, valuebuf);
0419                     
0420                     userlog("Client pid = %d, cmdline [%s] "
0421                             "%s memory limit reached: "
0422                             "configured max: %s in system found: %s - restarting...",
0423                             (int)c->dyn.pid, c->stat.command_line,
0424                             memtype, limitbuf, valuebuf);
0425                     
0426                     /* gently kill the client... */
0427                     cpm_kill(c);
0428                     
0429                     /* at next check we will boot it back... */
0430                 }
0431             }
0432             else
0433             {
0434                 
0435                 /* TODO: For shared memory mode, we shall handle exit
0436                  * statuses here too. Because if cpmsrv reboots, it will not
0437                  * be a parent of existing clients, thus change statuses here too
0438                  */
0439                 
0440                 /* ignore error as not critical for system running
0441                  * the process might be just exited 
0442                  */
0443                 NDRX_LOG(log_warn, "Client pid = %d, cmdline [%s]: "
0444                             "failed to read memory usage - ignore",
0445                             (int)c->dyn.pid, c->stat.command_line);
0446             }
0447             
0448         } /* started & require mem test... */
0449        
0450         cpm_pidtest(c, sg_groups);
0451        
0452     } /* hash loop */
0453 
0454     /* mark groups as booted.. */
0455     for (i=0; i<nrgrps; i++)
0456     {
0457         if (sg_groups[i] && !ndrx_sg_bootflag_clt_get(i+1))
0458         {
0459             NDRX_LOG(log_debug, "Marking singleton group %d as clients booted", i);
0460             ndrx_sg_bootflag_clt_set(i+1);
0461         }
0462     }
0463     
0464 out:
0465     return EXSUCCEED;
0466 }
0467 
0468 /**
0469  * Send message user.
0470  * @param p_ub
0471  * @param cd
0472  * @param msg
0473  */
0474 exprivate void cpm_send_msg(UBFH *p_ub, int cd, char *msg)
0475 {
0476     long revent;
0477     
0478     Bchg(p_ub, EX_CPMOUTPUT, 0, msg, 0L);
0479     
0480     if (EXFAIL == tpsend(cd,
0481                         (char *)p_ub,
0482                         0L,
0483                         0,
0484                         &revent))
0485     {
0486         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0487                             tpstrerror(tperrno), revent);
0488     }
0489     else
0490     {
0491         NDRX_LOG(log_debug,"sent ok");
0492     }
0493 }
0494 
0495 /**
0496  * Stop single client
0497  * @param p_ub
0498  * @param cd
0499  * @param tag
0500  * @param subsect
0501  * @param c
0502  * @return EXSUCCEED/EXFAIL
0503  */
0504 exprivate int cpm_sc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0505         cpm_process_t * c, int *p_nr_proc)
0506 {
0507     int ret = EXSUCCEED;
0508     long revent;
0509     char debug[256];
0510     
0511     c = cpm_client_get(tag, subsect);
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         c->dyn.req_state = CLT_STATE_NOTRUN;
0527         
0528         if (CLT_STATE_STARTED ==  c->dyn.cur_state)
0529         {
0530             if (EXSUCCEED==cpm_kill(c)) 
0531             {
0532                 snprintf(debug, sizeof(debug), "Client process %s/%s stopped", 
0533                         tag, subsect);
0534                 NDRX_LOG(log_info, "%s", debug);
0535                 Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0536             }
0537             else
0538             {
0539                 snprintf(debug, sizeof(debug), "Failed to stop %s/%s!", 
0540                         tag, subsect);
0541                 NDRX_LOG(log_info, "%s", debug);
0542                 Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0543             }
0544         }
0545         else
0546         {
0547             snprintf(debug, sizeof(debug), "Client process %s/%s not running already...", 
0548                     tag, subsect);
0549             NDRX_LOG(log_info, "%s", debug);
0550             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0551         }
0552     }
0553 out:
0554 
0555     if (EXFAIL == tpsend(cd,
0556                         (char *)p_ub,
0557                         0L,
0558                         0,
0559                         &revent))
0560     {
0561         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0562                             tpstrerror(tperrno), revent);
0563     }
0564     else
0565     {
0566         NDRX_LOG(log_debug,"sent ok");
0567     }
0568 
0569                 
0570     return ret;
0571 }
0572 
0573 /**
0574  * Reboot the client
0575  * @param p_ub
0576  * @param cd
0577  * @param tag
0578  * @param subsect
0579  * @param c
0580  * @return 
0581  */
0582 exprivate int cpm_rc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0583         cpm_process_t * c, int *p_nr_proc)
0584 {   
0585     int ret = EXSUCCEED;
0586     int dum;
0587     /* will do over those binary which are request to be started... */
0588     if (CLT_STATE_STARTED ==  c->dyn.req_state)
0589     {
0590         (*p_nr_proc)++;
0591         /* restart if any running... */
0592         NDRX_LOG(log_debug, "[%s]/[%s] running - restarting...", tag, subsect);
0593         
0594         NDRX_LOG(log_debug, "About to stop...");
0595         if (EXSUCCEED!=cpm_sc_obj(p_ub, cd, tag, subsect, c, &dum))
0596         {
0597             NDRX_LOG(log_error, "Failed to stop [%s]/[%s]", tag, subsect);
0598             EXFAIL_OUT(ret);
0599         }
0600         
0601         NDRX_LOG(log_debug, "About to start...");
0602         if (EXSUCCEED!=cpm_bc_obj(p_ub, cd, tag, subsect, c, &dum))
0603         {
0604             NDRX_LOG(log_error, "Failed to start [%s]/[%s]", tag, subsect);
0605             EXFAIL_OUT(ret);
0606         }
0607         
0608         
0609     }
0610 out:
0611     return ret;
0612 }
0613 
0614 /**
0615  * Process single object and send the results to client
0616  * @param p_ub
0617  * @param tag
0618  * @param subsect
0619  * @param c
0620  * @return 
0621  */
0622 exprivate int cpm_bc_obj(UBFH *p_ub, int cd, char *tag, char *subsect, 
0623         cpm_process_t * c, int *p_nr_proc)
0624 {
0625     int ret = EXSUCCEED;
0626     long revent;
0627     char debug[256];
0628     
0629     NDRX_LOG(log_debug, "Into %s: p_ub=%p, cd=%d, tag=[%s] subsect=[%s], c=%p",
0630             __func__, p_ub, cd, tag, subsect, c);
0631     
0632     if (NULL==c)
0633     {
0634         snprintf(debug, sizeof(debug), "Client process %s/%s not found!", 
0635                 tag, subsect);
0636         NDRX_LOG(log_error, "%s", debug);
0637         userlog("%s!", debug);
0638         Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0639         EXFAIL_OUT(ret);
0640     }
0641     else
0642     {
0643         (*p_nr_proc)++;
0644         
0645         if (CLT_STATE_STARTED != c->dyn.cur_state)
0646         {
0647             snprintf(debug, sizeof(debug), "Client process %s/%s marked for start", 
0648                     tag, subsect);
0649             NDRX_LOG(log_info, "%s", debug);
0650             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0651 
0652             c->dyn.cur_state = CLT_STATE_STARTING;
0653             c->dyn.req_state = CLT_STATE_STARTED;
0654         }
0655         else
0656         {
0657             snprintf(debug, sizeof(debug), "Process %s/%s already marked "
0658                                 "for startup or running...", tag, subsect);
0659             NDRX_LOG(log_info, "%s", debug);
0660             Bchg(p_ub, EX_CPMOUTPUT, 0, debug, 0L);
0661         }
0662     }
0663     
0664 out:
0665          
0666     if (EXFAIL == tpsend(cd,
0667                         (char *)p_ub,
0668                         0L,
0669                         0,
0670                         &revent))
0671     {
0672         NDRX_LOG(log_error, "Send data failed [%s] %ld",
0673                             tpstrerror(tperrno), revent);
0674     }
0675     else
0676     {
0677         NDRX_LOG(log_debug,"sent ok");
0678     }
0679 
0680                 
0681     return ret;
0682 }
0683 
0684 /**
0685  * Start/Stop client the client process
0686  * @param p_ub
0687  * @param cd
0688  * @return 
0689  */
0690 exprivate int cpm_bcscrc(UBFH *p_ub, int cd, 
0691         int(*p_func)(UBFH *, int, char*, char*,cpm_process_t *, int *p_nr_proc), 
0692         char *finish_msg)
0693 {
0694     long twait = 0;
0695     int ret = EXSUCCEED;
0696     char msg[256];
0697     cpm_process_t *c = NULL, *ct = NULL;
0698     BFLDLEN tmp_len;
0699     char tag[CPM_TAG_LEN+1]={EXEOS};
0700     char subsect[CPM_SUBSECT_LEN+1]={EXEOS};
0701     char procgrp[MAXTIDENT+1]={EXEOS};
0702     
0703     char regex_tag[CPM_TAG_LEN * 2 + 2 + 1]; /* all symbols can be escaped, 
0704                                             * have ^$ start/end and EOS */
0705     char regex_subsect[CPM_SUBSECT_LEN * 2 + 2 + 1];
0706     
0707     regex_t r_comp_tag;
0708     int r_comp_tag_alloc = EXFALSE;
0709     
0710     regex_t r_comp_subsect;
0711     int r_comp_subsect_alloc = EXFALSE;
0712     
0713     int nr_proc = 0;
0714     
0715     tmp_len=sizeof(tag);
0716     Bget(p_ub, EX_CPMTAG, 0, tag, &tmp_len);
0717 
0718     tmp_len=sizeof(procgrp);
0719     Bget(p_ub, EX_CPMPROCGRP, 0, procgrp, &tmp_len);
0720     
0721     if (EXSUCCEED!=Bget(p_ub, EX_CPMSUBSECT, 0, subsect, 0L))
0722     {
0723         NDRX_STRCPY_SAFE(subsect, "-");
0724     }
0725     
0726     Bget(p_ub, EX_CPMWAIT, 0, (char *)&twait, 0L);
0727     if (EXEOS!=procgrp[0])
0728     {
0729         /* resolve process group */
0730         ndrx_procgroup_t* p_grp=ndrx_ndrxconf_procgroups_resolvenm(ndrx_G_procgroups_config, 
0731             procgrp);
0732 
0733         if (NULL==p_grp)
0734         {
0735             snprintf(msg, sizeof(msg), "Process group [%s] not found", procgrp);
0736             cpm_send_msg(p_ub, cd, msg);
0737             EXFAIL_OUT(ret);
0738         }
0739 
0740         /* loop over, match & execute... */
0741         EXHASH_ITER(hh, G_clt_config, c, ct)
0742         {
0743             if (c->stat.procgrp_no==p_grp->grpno)
0744             {
0745                 int cur_nr_proc = nr_proc;
0746                 NDRX_LOG(log_debug, "[%s]/[%s] procgrp_no %d - matched", 
0747                     c->tag, c->subsect, c->stat.procgrp_no);
0748                 
0749                 if (EXSUCCEED!=p_func(p_ub, cd, c->tag, c->subsect, c, &nr_proc))
0750                 {
0751                     NDRX_LOG(log_error, "Matched process [%s]/[%s] procgrp_no %d failed to start/stop",
0752                             c->tag, c->subsect, c->stat.procgrp_no);
0753                 }
0754 
0755                 if (cur_nr_proc!=nr_proc && twait > 0)
0756                 {
0757                     NDRX_LOG(log_debug, "Sleeping %d millisec", twait);
0758                     usleep(twait*1000);
0759                 }
0760             }
0761             else
0762             {
0763                 NDRX_LOG(log_debug, "[%s]/[%s] procgrp_no %d - NOT matched group %d", 
0764                     c->tag, c->subsect, c->stat.procgrp_no, p_grp->grpno);
0765             }
0766         }
0767         snprintf(msg, sizeof(msg), "%d client(s) %s.", nr_proc, finish_msg);
0768         cpm_send_msg(p_ub, cd, msg);
0769     }
0770     else if (NULL==strchr(tag,CLT_WILDCARD) && NULL==strchr(subsect, CLT_WILDCARD))
0771     {
0772         c = cpm_client_get(tag, subsect);
0773         /* Bug #428 */
0774         if (NULL!=c)
0775         {
0776             if (EXSUCCEED!=(p_func(p_ub, cd, tag, subsect, c, &nr_proc)))
0777             {
0778                 NDRX_LOG(log_error, "%s: cpm_bc_obj failed", __func__);
0779                 EXFAIL_OUT(ret);
0780             }
0781         }
0782         else
0783         {
0784             snprintf(msg, sizeof(msg), "Client process %s/%s not found",
0785                     tag, subsect);
0786             cpm_send_msg(p_ub, cd, msg);
0787         }
0788     }
0789     else
0790     {
0791         /* Expand to regular expressions... */
0792         ndrx_regasc_cpyesc(regex_tag, tag, '^', '$', '%', ".*");
0793         NDRX_LOG(log_debug, "Got regex tag: [%s]", tag);
0794         if (EXSUCCEED!=ndrx_regcomp(&r_comp_tag, regex_tag))
0795         {
0796             NDRX_LOG(log_error, "Failed to compile regexp of tag!");
0797             
0798             snprintf(msg, sizeof(msg), "Failed to compile regexp of tag[%s]!",
0799                     regex_tag);    
0800             cpm_send_msg(p_ub, cd, msg);
0801         }
0802         r_comp_tag_alloc=EXTRUE;
0803         
0804         ndrx_regasc_cpyesc(regex_subsect, subsect, '^', '$', '%', ".*");
0805         NDRX_LOG(log_debug, "Got regex subsect: [%s]", subsect);
0806         
0807         if (EXSUCCEED!=ndrx_regcomp(&r_comp_subsect, regex_subsect))
0808         {
0809             NDRX_LOG(log_error, "Failed to compile regexp of subsect!");
0810             
0811             snprintf(msg, sizeof(msg), "Failed to compile regexp of subsect[%s]!",
0812                     regex_subsect);
0813             cpm_send_msg(p_ub, cd, msg);
0814         }
0815         r_comp_subsect_alloc=EXTRUE;
0816         
0817         /* loop over the hash */
0818         EXHASH_ITER(hh, G_clt_config, c, ct)
0819         {
0820             if (EXSUCCEED==ndrx_regexec(&r_comp_tag, c->tag) && 
0821                     EXSUCCEED==ndrx_regexec(&r_comp_subsect, c->subsect))
0822             {
0823                 int cur_nr_proc = nr_proc;
0824                 NDRX_LOG(log_debug, "[%s]/[%s] - matched", c->tag, c->subsect);
0825                 
0826                 if (EXSUCCEED!=p_func(p_ub, cd, c->tag, c->subsect, c, &nr_proc))
0827                 {
0828                     NDRX_LOG(log_error, "Matched process [%s]/[%s] failed to start/stop",
0829                             c->tag, c->subsect);
0830                 }
0831                 
0832                 if (cur_nr_proc!=nr_proc && twait > 0)
0833                 {
0834                     NDRX_LOG(log_debug, "Sleeping %d millisec", twait);
0835                     usleep(twait*1000);
0836                 }
0837             }
0838             else
0839             {
0840                 NDRX_LOG(log_debug, "[%s]/[%s] - NOT matched", c->tag, c->subsect);
0841             }
0842         }
0843         snprintf(msg, sizeof(msg), "%d client(s) %s.", nr_proc, finish_msg);
0844         cpm_send_msg(p_ub, cd, msg);
0845     }
0846         
0847 out:
0848                 
0849     if (r_comp_tag_alloc)
0850     {
0851         ndrx_regfree(&r_comp_tag);
0852     }
0853 
0854     if (r_comp_subsect_alloc)
0855     {
0856         ndrx_regfree(&r_comp_subsect);
0857     }
0858 
0859     return ret;
0860 }
0861 
0862 /**
0863  * Boot client
0864  * @param p_ub
0865  * @param cd
0866  * @return 
0867  */
0868 exprivate int cpm_bc(UBFH *p_ub, int cd)
0869 {
0870     NDRX_LOG(log_debug, "Into %s", __func__);
0871     return cpm_bcscrc(p_ub, cd, cpm_bc_obj, "marked for start");
0872 }
0873 
0874 
0875 /**
0876  * Stop the client process
0877  * @param p_ub
0878  * @param cd
0879  * @return 
0880  */
0881 exprivate int cpm_sc(UBFH *p_ub, int cd)
0882 {   
0883     NDRX_LOG(log_debug, "Into %s", __func__);
0884     return cpm_bcscrc(p_ub, cd, cpm_sc_obj, "stopped");
0885 }
0886 
0887 /**
0888  * Print clients
0889  * @param p_ub
0890  * @param cd - call descriptor
0891  * @return 
0892  */
0893 exprivate int cpm_pc(UBFH *p_ub, int cd)
0894 {
0895     int ret = EXSUCCEED;
0896     long revent;
0897     cpm_process_t *c = NULL;
0898     cpm_process_t *ct = NULL;
0899     char output[256];
0900     char buffer [80];
0901     struct tm timeinfo;
0902     int len;
0903     
0904     NDRX_LOG(log_info, "cpm_pc: listing clients");
0905     /* Remove dead un-needed processes (killed & not in new config) */
0906     EXHASH_ITER(hh, G_clt_config, c, ct)
0907     {
0908         NDRX_LOG(log_info, "cpm_pc: %s/%s", c->tag, c->subsect);
0909         
0910         buffer[0]=EXEOS;
0911 
0912         if (c->stat.procgrp_no > 0)
0913         {
0914             ndrx_procgroup_t* p_grp=ndrx_ndrxconf_procgroups_resolveno(ndrx_G_procgroups_config, 
0915                 c->stat.procgrp_no);
0916 
0917             NDRX_STRCPY_SAFE(buffer, "process group");
0918             /* can be null, as for existing processes config validity of cpmsrv is not enforced */
0919             if (NULL!=p_grp)
0920             {
0921                 len = strlen(buffer);
0922                 snprintf(buffer+len, sizeof(buffer)-len, " %s ", p_grp->grpname);
0923             }
0924 
0925             len = strlen(buffer);
0926             snprintf(buffer+len, sizeof(buffer)-len, "(no %d), ", c->stat.procgrp_no);
0927         }
0928 
0929         len = strlen(buffer);
0930         localtime_r (&c->dyn.stattime, &timeinfo);
0931         strftime (buffer+len, sizeof(buffer)-len, "%c", (&timeinfo));
0932     
0933         if (CLT_STATE_STARTED == c->dyn.cur_state)
0934         {
0935             snprintf(output, sizeof(output), "%s/%s - running pid %d (%s)",
0936                                 c->tag, c->subsect, c->dyn.pid, buffer);
0937         }
0938         else if (CLT_STATE_STARTING == c->dyn.cur_state && 
0939                 c->dyn.req_state != CLT_STATE_NOTRUN)
0940         {
0941             snprintf(output, sizeof(output), "%s/%s - starting (%s)",c->tag, 
0942                     c->subsect, buffer);
0943         }
0944         else if (CLT_STATE_WAIT == c->dyn.cur_state && 
0945                 c->dyn.req_state != CLT_STATE_NOTRUN)
0946         {
0947             snprintf(output, sizeof(output), "%s/%s - waiting on group lock (%s)",c->tag, 
0948                     c->subsect, buffer);
0949         }
0950         else if (c->dyn.was_started && (c->dyn.req_state == CLT_STATE_STARTED) )
0951         {
0952             snprintf(output, sizeof(output), "%s/%s - dead %d (%s)", c->tag, c->subsect, 
0953                     c->dyn.exit_status, buffer);
0954         }
0955         else if (c->dyn.was_started && (c->dyn.req_state == CLT_STATE_NOTRUN) )
0956         {
0957             snprintf(output, sizeof(output), "%s/%s - shutdown (%s)", c->tag, c->subsect, 
0958                     buffer);
0959         }
0960         else
0961         {
0962             snprintf(output, sizeof(output), "%s/%s - not started", c->tag, c->subsect);
0963         }
0964         
0965         if (EXSUCCEED!=Bchg(p_ub, EX_CPMOUTPUT, 0, output, 0L))
0966         {
0967             NDRX_LOG(log_error, "Failed to read fields: [%s]", 
0968                 Bstrerror(Berror));
0969             EXFAIL_OUT(ret);
0970         }
0971         
0972         if (EXFAIL == tpsend(cd,
0973                             (char *)p_ub,
0974                             0L,
0975                             0,
0976                             &revent))
0977         {
0978             NDRX_LOG(log_error, "Send data failed [%s] %ld",
0979                                 tpstrerror(tperrno), revent);
0980             EXFAIL_OUT(ret);
0981         }
0982         else
0983         {
0984             NDRX_LOG(log_debug,"sent ok");
0985         }
0986     }
0987     
0988 out:
0989 
0990     return ret;
0991 }
0992 
0993 /**
0994  * Reload clients (restart one by one)
0995  * @param p_ub
0996  * @param cd
0997  * @return 
0998  */
0999 exprivate int cpm_rc(UBFH *p_ub, int cd)
1000 {   
1001     NDRX_LOG(log_debug, "Into %s", __func__);
1002     return cpm_bcscrc(p_ub, cd, cpm_rc_obj, "restarted");
1003 }
1004 /* vim: set ts=4 sw=4 et smartindent: */