Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief LCF posting
0003  *
0004  * @file cmd_lcf.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 <string.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <memory.h>
0038 #include <sys/param.h>
0039 
0040 #include <ndrstandard.h>
0041 #include <ndebug.h>
0042 
0043 #include <ndrx.h>
0044 #include <ndrxdcmn.h>
0045 #include <atmi_int.h>
0046 #include <gencall.h>
0047 #include <errno.h>
0048 #include <lcf.h>
0049 #include <linenoise.h>
0050 
0051 #include "nclopt.h"
0052 
0053 #include <exhash.h>
0054 #include <utlist.h>
0055 #include <userlog.h>
0056 #include <lcfint.h>
0057 
0058 /*---------------------------Externs------------------------------------*/
0059 /*---------------------------Macros-------------------------------------*/
0060 #define PAGE_1          1       /**< page 1 infos */
0061 #define PAGE_2          2       /**< page 2 infos */
0062 #define PAGE_3          3       /**< page 3 infos */
0063 /*---------------------------Enums--------------------------------------*/
0064 /*---------------------------Typedefs-----------------------------------*/
0065 /*---------------------------Globals------------------------------------*/
0066 /*---------------------------Statics------------------------------------*/
0067 
0068 exprivate linenoiseCompletions *M_lc;   /**< params to callback */
0069 exprivate char *M_lc_buf; /**< params to callback */
0070 exprivate int  M_lc_buf_len; /**< params to callback */
0071 
0072 /**
0073  * Perform stock Enduro/X stock LCF command initialization
0074  * @return EXSUCCEED/EXFAIL
0075  */
0076 expublic int ndrx_xadmin_lcf_init(void)
0077 {
0078     int ret = EXSUCCEED;
0079     
0080     ndrx_lcf_reg_xadmin_t xcmd;
0081     
0082     /* Disable LCF command */
0083     memset(&xcmd, 0, sizeof(xcmd));
0084     
0085     xcmd.version = NDRX_LCF_XCMD_VERSION;
0086     xcmd.command = NDRX_LCF_CMD_DISABLE;
0087     NDRX_STRCPY_SAFE(xcmd.cmdstr, NDRX_LCF_CMDSTR_DISABLE);
0088     xcmd.dfltslot = 0;
0089     
0090     /* first argument is mandatory */
0091     NDRX_STRCPY_SAFE(xcmd.helpstr, "Disable published command");
0092 
0093     if (EXSUCCEED!=ndrx_lcf_xadmin_add_int(&xcmd))
0094     {
0095         NDRX_LOG(log_error, "Failed to register %d [%s] LCF command: %s",
0096                 xcmd.command, xcmd.cmdstr, Nstrerror(Nerror));
0097         EXFAIL_OUT(ret);
0098     }
0099     
0100     /* logrotate: */
0101     memset(&xcmd, 0, sizeof(xcmd));
0102     
0103     xcmd.version = NDRX_LCF_XCMD_VERSION;
0104     xcmd.command = NDRX_LCF_CMD_LOGROTATE;
0105     NDRX_STRCPY_SAFE(xcmd.cmdstr, NDRX_LCF_CMDSTR_LOGROTATE);
0106     xcmd.dfltslot = NDRX_LCF_SLOT_LOGROTATE;
0107     xcmd.dfltflags =NDRX_LCF_FLAG_ALL|NDRX_LCF_FLAG_DOSTARTUPEXP;
0108     NDRX_STRCPY_SAFE(xcmd.helpstr, "Perform logrotate");
0109 
0110     if (EXSUCCEED!=ndrx_lcf_xadmin_add_int(&xcmd))
0111     {
0112         NDRX_LOG(log_error, "Failed to register %d [%s] LCF command: %s",
0113                 xcmd.command, xcmd.cmdstr, Nstrerror(Nerror));
0114         EXFAIL_OUT(ret);
0115     }
0116         
0117     /* logger change: */
0118     memset(&xcmd, 0, sizeof(xcmd));
0119     
0120     xcmd.version = NDRX_LCF_XCMD_VERSION;
0121     xcmd.command = NDRX_LCF_CMD_LOGCHG;
0122     NDRX_STRCPY_SAFE(xcmd.cmdstr, NDRX_LCF_CMDSTR_LOGCHG);
0123     xcmd.dfltslot = NDRX_LCF_SLOT_LOGCHG;
0124     
0125     /* first argument is mandatory */
0126     xcmd.dfltflags = NDRX_LCF_FLAG_ARGA;
0127     NDRX_STRCPY_SAFE(xcmd.helpstr, "Change logging settings");
0128 
0129     if (EXSUCCEED!=ndrx_lcf_xadmin_add_int(&xcmd))
0130     {
0131         NDRX_LOG(log_error, "Failed to register %d [%s] LCF command: %s",
0132                 xcmd.command, xcmd.cmdstr, Nstrerror(Nerror));
0133         EXFAIL_OUT(ret);
0134     }
0135     
0136 out:
0137     return ret;
0138 }
0139 
0140 /**
0141  * Print LCF commands callback
0142  * @param xcmd LCF xadmin command
0143  */
0144 exprivate void lcf_print_cmds(ndrx_lcf_reg_xadminh_t *xcmd)
0145 {
0146     
0147     fprintf(stdout, "\t\t%s\t%s (dslot: %d)\n", xcmd->cmdstr, 
0148             xcmd->xcmd.helpstr, xcmd->xcmd.dfltslot);
0149 
0150     if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ARGA)
0151     {
0152         fprintf(stdout, "\t\t\t-A parameter is mandatory\n");
0153     }
0154     
0155     if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ARGB)
0156     {
0157         fprintf(stdout, "\t\t\t-B parameter is mandatory\n");
0158     }
0159     
0160     if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ALL)
0161     {
0162         fprintf(stdout, "\t\t\tApplies to all binaries (-A by default)\n");
0163     }
0164     
0165     if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_DOSTARTUP)
0166     {
0167         fprintf(stdout, "\t\t\tCommand also executes at startup of binaries\n");
0168     }
0169     
0170     if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_DOSTARTUPEXP)
0171     {
0172         fprintf(stdout, "\t\t\tCommand also executes at startup of binaries with expiry\n");
0173     }
0174     
0175 }
0176 
0177 /**
0178  * Complete the command here
0179  * @param xcmd
0180  */
0181 exprivate void cmd_lcf_completion_add(ndrx_lcf_reg_xadminh_t *xcmd)
0182 {
0183     char tmpbuf[128];
0184     snprintf(tmpbuf, sizeof(tmpbuf), "lcf %s", xcmd->cmdstr);
0185     
0186     if (0==strncmp(tmpbuf, M_lc_buf, M_lc_buf_len))
0187     {
0188         linenoiseAddCompletion(M_lc, tmpbuf);
0189     }
0190 }
0191 
0192 /**
0193  * Add completions for lcf
0194  * @param lc completion handler
0195  * @return 
0196  */
0197 expublic int cmd_lcf_completion(linenoiseCompletions *lc, char *buf)
0198 {
0199     M_lc=lc;
0200     M_lc_buf=buf;
0201     M_lc_buf_len=strlen(buf);
0202     ndrx_lcf_xadmin_list(cmd_lcf_completion_add);
0203     
0204     return EXSUCCEED;
0205 }
0206 
0207 /**
0208  * Return the list of LCF commands registered with xadmin
0209  * @return 
0210  */
0211 expublic int cmd_lcf_help(void)
0212 {
0213     fprintf(stdout, "\tPublished COMMANDs:\n");
0214     
0215     ndrx_lcf_xadmin_list(lcf_print_cmds);
0216     
0217     fprintf(stdout, "\n");
0218     
0219     return EXSUCCEED;
0220 }
0221 
0222 /**
0223  * Print lcf data
0224  */
0225 expublic void print_lcf_data(int page)
0226 {
0227     int i, j;
0228     char flagsstr[64];
0229     ndrx_lcf_command_t *cur;
0230     char cmdstr[8+1];
0231     
0232 static const struct {
0233     long flag;
0234     char *flagstr;
0235 
0236 } flag_map[] = {
0237     {  NDRX_LCF_FLAG_PID, "p" },
0238     {  NDRX_LCF_FLAG_BIN, "b" }, 
0239     {  NDRX_LCF_FLAG_ALL, "a" }, 
0240     {  NDRX_LCF_FLAG_ARGA, "A" }, 
0241     {  NDRX_LCF_FLAG_ARGB, "B" }, 
0242     {  NDRX_LCF_FLAG_DOREX, "r" }, 
0243     {  NDRX_LCF_FLAG_DOSTARTUP, "n" }, 
0244     {  NDRX_LCF_FLAG_DOSTARTUPEXP, "e" }
0245 };
0246 
0247     if (PAGE_1==page)
0248     {
0249         fprintf(stderr, "SLOT  CID COMMAND  FLAGS    PROCID           #SEEN #APPL #FAIL      AGE FEEDBACK\n");
0250         fprintf(stderr, "---- ---- -------- -------- ---------------- ----- ----- ----- -------- --------\n");
0251     }
0252     else if (PAGE_2==page)
0253     {
0254         fprintf(stderr, "SLOT  CID COMMAND  ARG_A                                      ARG_B\n");
0255         fprintf(stderr, "---- ---- -------  ------------------------------------------ ------------------\n");
0256     }
0257     else if (PAGE_3==page)
0258     {
0259         fprintf(stderr, "SLOT  CID COMMAND  FEEDBACKMSG\n");
0260         fprintf(stderr, "---- ---- -------  -------------------------------------------------------------\n");
0261     }
0262     
0263     if (EXSUCCEED!=ndrx_lcf_read_lock())
0264     {
0265         NDRX_LOG(log_error, "Failed to lock shm for read.");
0266         goto out;
0267     }
0268     
0269     /* loop over the shm... */
0270     
0271     for (i=0; i<ndrx_G_libnstd_cfg.lcfmax; i++)
0272     {
0273         cur=&ndrx_G_shmcfg->commands[i];
0274         
0275         
0276         if (NDRX_LCF_CMD_DISABLE==cur->command)
0277         {
0278             /* no more details for disabled command */
0279             fprintf(stdout, "%4d %4d %-8.8s\n",
0280                     i, 
0281                     cur->command, 
0282                     NDRX_LCF_CMDSTR_DISABLE);
0283         }
0284         else if (PAGE_1==page)
0285         {
0286             char procid[16+1];
0287             
0288             /* build flags string */
0289             flagsstr[0] = EXEOS;
0290             
0291             for (j=0; j<N_DIM(flag_map); j++)
0292             {
0293                 if (cur->flags & flag_map[j].flag)
0294                 {
0295                     NDRX_STRCAT_S(flagsstr, sizeof(flagsstr), flag_map[j].flagstr);
0296                 }
0297             }
0298             
0299             fprintf(stdout, "%4d %4d %-8.8s %-8.8s %-16.16s %5.5s %5.5s %5.5s %8.8s %8ld\n",
0300                     i, 
0301                     cur->command, 
0302                     ndrx_decode_str(cur->cmdstr, cmdstr, sizeof(cmdstr)),
0303                     flagsstr, 
0304                     ndrx_decode_str(cur->procid, procid, sizeof(procid)),
0305                     ndrx_decode_num(cur->seen,    0, 0, 1),
0306                     ndrx_decode_num(cur->applied, 1, 0, 1),
0307                     ndrx_decode_num(cur->failed, 2, 0, 1),
0308                     ndrx_decode_msec(ndrx_stopwatch_get_delta(&cur->publtim), 0, 0, 2),
0309                     cur->fbackcode);
0310             
0311         }
0312         else if (PAGE_2==page)
0313         {
0314             char arg_a[42+1];
0315             char arg_b[18+1];
0316             
0317             fprintf(stdout, "%4d %4d %-8.8s %-42.42s %-18.18s\n",
0318                     i, 
0319                     cur->command, 
0320                     ndrx_decode_str(cur->cmdstr, cmdstr, sizeof(cmdstr)),
0321                     ndrx_decode_str(cur->arg_a, arg_a, sizeof(arg_a)),
0322                     ndrx_decode_str(cur->arg_b, arg_b, sizeof(arg_b))
0323                     );            
0324         }
0325         else if (PAGE_3==page)
0326         {
0327             char fbackmsg[61+1];
0328             
0329             fprintf(stdout, "%4d %4d %-8.8s %-61.61s\n",
0330                     i, 
0331                     cur->command, 
0332                     ndrx_decode_str(cur->cmdstr, cmdstr, sizeof(cmdstr)),
0333                     ndrx_decode_str(cur->fbackmsg, fbackmsg, sizeof(fbackmsg))
0334                     );
0335         }
0336     }
0337     
0338     ndrx_lcf_read_unlock();
0339 out:
0340     return;
0341 }
0342 
0343 /**
0344  * Print or set the LCF command
0345  * @param p_cmd_map
0346  * @param argc
0347  * @param argv
0348  * @return SUCCEED
0349  */
0350 expublic int cmd_lcf(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0351 {
0352     int ret = EXSUCCEED;
0353     char pid[NDRX_NAME_MAX]="";
0354     char binary[NDRX_NAME_MAX]="";
0355     int all = EXFALSE;
0356     
0357     int regex = EXFALSE;
0358     int exec_start = EXFALSE;
0359     int exec_start_exp = EXFALSE;
0360     char arg_a[PATH_MAX+1]="";
0361     char arg_b[NDRX_NAME_MAX+1]="";
0362     short slot=EXFAIL;
0363     
0364     /* if no arguments given, then it is print */
0365     ncloptmap_t clopt[] =
0366     {
0367         {'A', BFLD_STRING, arg_a, sizeof(arg_a), 
0368                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Argument a to COMMAND"},
0369         {'B', BFLD_STRING, arg_b, sizeof(arg_b), 
0370                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Argument b to COMMAND"},
0371         {'p', BFLD_STRING, pid, sizeof(pid), 
0372                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "PID"},
0373         {'b', BFLD_STRING, binary, sizeof(binary), 
0374                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Executable binary name"},
0375         {'r', BFLD_SHORT, (void *)&regex, 0, 
0376                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "PID or Binary name is regexp"}, 
0377         {'a', BFLD_SHORT, (void *)&all, 0, 
0378                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Apply to all binaries"}, 
0379         {'n', BFLD_SHORT, (void *)&exec_start, 0, 
0380                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Apply at startup"},
0381         {'e', BFLD_SHORT, (void *)&exec_start_exp, 0, 
0382                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Apply at startup with expiry"},
0383         {'s', BFLD_SHORT, (void *)&slot, 0, 
0384                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Slot number to which publish"},
0385         {0}
0386     };
0387     
0388     _Nunset_error();
0389     
0390     /* Check the argument count... if no args are given, then print current
0391      * LCF table, If args are given, parse them up...
0392      */
0393     if (NULL==ndrx_G_shmcfg)
0394     {
0395         /* LCF not loaded...! */
0396         _Nset_error_fmt(NESYSTEM, "LCF Commands disabled");
0397     }
0398     
0399     if (1==argc || (2==argc && 0==strcmp(argv[1], "-1")))
0400     {
0401         print_lcf_data(PAGE_1);
0402     }
0403     else if (2==argc && 0==strcmp(argv[1], "-2"))
0404     {
0405         print_lcf_data(PAGE_2);
0406     }
0407     else if (2==argc && 0==strcmp(argv[1], "-3"))
0408     {
0409         print_lcf_data(PAGE_3);
0410     }
0411     else
0412     {
0413         ndrx_lcf_reg_xadminh_t *xcmd = ndrx_lcf_xadmin_find_int(argv[1]);
0414         ndrx_lcf_command_t cmd;
0415                 
0416         if (NULL==xcmd)
0417         {
0418             _Nset_error_fmt(NESUPPORT, "Command [%s] not found", argv[1]);
0419             EXFAIL_OUT(ret);
0420         }
0421         
0422         memset(&cmd, 0, sizeof(cmd));
0423         
0424         /* start the next arg, as we strip off the sub-command */
0425         if (nstd_parse_clopt(clopt, EXTRUE,  argc-1, argv+1, EXFALSE))
0426         {
0427             _Nset_error_fmt(NEINVAL, "Failed to parse CLI args");
0428             EXFAIL_OUT(ret);
0429         }
0430         
0431         /* decide the target, cli has more power over the default */
0432         if (EXEOS!=pid[0] && EXEOS!=binary[0])
0433         {
0434             _Nset_error_fmt(NEINVAL, "-p and -b cannot be mixed");
0435             EXFAIL_OUT(ret);
0436         }
0437         
0438         /* makes no sense to mix binary with -A (all) flag */
0439         if ( (EXEOS!=pid[0] || EXEOS!=binary[0]) && all )
0440         {
0441             _Nset_error_fmt(NEINVAL, "-p or -b cannot be mixed with -a");
0442             EXFAIL_OUT(ret);
0443         }
0444         
0445         if (EXEOS!=pid[0])
0446         {
0447             NDRX_STRCPY_SAFE(cmd.procid, pid);
0448             cmd.flags|=NDRX_LCF_FLAG_PID;
0449         }
0450         else if (EXEOS!=binary[0])
0451         {
0452             NDRX_STRCPY_SAFE(cmd.procid, binary);
0453             cmd.flags|=NDRX_LCF_FLAG_BIN;
0454         }
0455         else if (all)
0456         {
0457             cmd.flags|=NDRX_LCF_FLAG_ALL;
0458         }
0459         else
0460         {
0461             cmd.flags|= (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ALL);
0462         }
0463         
0464         /* Except this rule does not affect disable command */
0465         if (EXEOS==cmd.procid[0] && !(cmd.flags & NDRX_LCF_FLAG_ALL) &&
0466                 NDRX_LCF_CMD_DISABLE!=xcmd->xcmd.command)
0467         {
0468             _Nset_error_fmt(NEINVAL, "There is no process target for command (missing -a/-p/-b and not defaults)");
0469             EXFAIL_OUT(ret);
0470         }
0471         
0472         /* Check the mandatory arguments */
0473         
0474         if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ARGA && EXEOS==arg_a[0])
0475         {
0476             _Nset_error_fmt(NEINVAL, "-a argument is required for command");
0477             EXFAIL_OUT(ret);
0478         }
0479         
0480         if (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_ARGB && EXEOS==arg_b[0])
0481         {
0482             _Nset_error_fmt(NEINVAL, "-b argument is required for command");
0483             EXFAIL_OUT(ret);
0484         }
0485         
0486         NDRX_STRCPY_SAFE(cmd.arg_a, arg_a);
0487         NDRX_STRCPY_SAFE(cmd.arg_b, arg_b);
0488         
0489         /* add regexp flags  */
0490         
0491         if (regex)
0492         {
0493             cmd.flags|=NDRX_LCF_FLAG_DOREX;
0494         }
0495         
0496         /* copy defaults */
0497         
0498         cmd.flags|= (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_DOSTARTUP);
0499         
0500         if (exec_start)
0501         {
0502             cmd.flags|=NDRX_LCF_FLAG_DOSTARTUP;
0503         }
0504         
0505         cmd.flags|= (xcmd->xcmd.dfltflags & NDRX_LCF_FLAG_DOSTARTUPEXP);
0506         
0507         if (exec_start_exp)
0508         {
0509             cmd.flags|=NDRX_LCF_FLAG_DOSTARTUPEXP;
0510         }
0511         
0512         if (EXFAIL==slot)
0513         {
0514             slot = xcmd->xcmd.dfltslot;
0515         }
0516         
0517         cmd.version=NDRX_LCF_LCMD_VERSION;
0518         cmd.command = xcmd->xcmd.command;
0519         NDRX_STRCPY_SAFE(cmd.cmdstr, xcmd->cmdstr);
0520         
0521         /* OK let it publish */
0522         if (EXSUCCEED!=ndrx_lcf_publish(slot, &cmd))
0523         {
0524             EXFAIL_OUT(ret);
0525         }
0526         
0527         /* Looks good */
0528         fprintf(stderr, "OK\n");
0529     }
0530     
0531 out:
0532     
0533     if (EXSUCCEED!=ret)
0534     {
0535         fprintf(stderr, "fail, code: %d: %s\n", Nerror, Nstrerror(Nerror));
0536     }
0537 
0538     return ret;
0539 }
0540 
0541 /**
0542  * Print shared memory configuration.
0543  * ndrx_load_common_env() must have attached to shmcfg as whole online operations
0544  * depends on this.
0545  */
0546 expublic int cmd_shmcfg(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0547 {
0548     printf("shmcfgver_lcf = %u\n", (unsigned)ndrx_G_shmcfg->shmcfgver_lcf);
0549     printf("use_ddr = %d\n", ndrx_G_shmcfg->use_ddr);
0550     printf("ddr_page = %u\n", (unsigned)ndrx_G_shmcfg->ddr_page);
0551     printf("ddr_ver1 = %u\n", (unsigned)ndrx_G_shmcfg->ddr_ver1);
0552     printf("is_mmon = %u\n", (unsigned)ndrx_G_shmcfg->is_mmon);
0553     return EXSUCCEED;
0554 }
0555 
0556 /* vim: set ts=4 sw=4 et smartindent: */