Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro X administration utility.
0003  *
0004  * @file xadmin.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 #include <unistd.h>
0040 
0041 #include <ndrstandard.h>
0042 #include <ndebug.h>
0043 #include <nstd_shm.h>
0044 
0045 #include "ndrx.h"
0046 #include "cconfig.h"
0047 #include <ndrxdcmn.h>
0048 #include <gencall.h>
0049 #include <errno.h>
0050 #include <sys_unix.h>
0051 #include <inicfg.h>
0052 #include <utlist.h>
0053 #include <linenoise.h>
0054 /*---------------------------Externs------------------------------------*/
0055 extern const char ndrx_G_resource_ndrx_config[];
0056 extern int ndrx_G_ctrl_d; /* feedback from linenoise, ctrl+d EOF pressed */
0057 
0058 /*---------------------------Macros-------------------------------------*/
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 /* Command line arguments */
0063 exprivate int M_argc;
0064 exprivate char **M_argv;
0065 
0066 /* Final command buffer  */
0067 expublic int G_cmd_argc_raw; /* raw strings in argv */
0068 
0069 expublic ndrx_inicfg_section_keyval_t *G_xadmin_config = NULL;
0070 expublic char G_xadmin_config_file[PATH_MAX+1] = {EXEOS};
0071 
0072 /* if we read from stdin: */
0073 expublic char *G_cmd_argv[MAX_ARGS]; /* Assume max 50 arguments */
0074 exprivate char M_buffer[CMD_MAX];
0075 exprivate char M_buffer_prev[CMD_MAX]={EXEOS};  /* Previous command (for interactive terminal) */
0076 exprivate int M_quit_requested = EXFALSE;       /* Mark the system state that we want exit! */
0077 
0078 /*---------------------------Statics------------------------------------*/
0079 /*---------------------------Prototypes---------------------------------*/
0080 
0081 exprivate int cmd_quit(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0082 exprivate int cmd_echo(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0083 exprivate int cmd_ver(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0084 exprivate int cmd_idle(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0085 exprivate int cmd_help(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0086 exprivate int cmd_stat(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0087 exprivate int cmd_poller(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0088 exprivate int cmd_shms(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0089 exprivate int cmd_pmode(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next);
0090 
0091 /**
0092  * Initialize command mapping table
0093  */
0094 cmd_mapping_t M_command_map[] = 
0095 {
0096     {"quit",    cmd_quit,  EXFAIL,              0,  0, 
0097                 "Quit from command line utility"
0098                 , NULL},
0099     {"q",       cmd_quit,  EXFAIL,              0,  0, 
0100                 "Alias for `quit'"
0101                 , NULL},
0102     {"exit",    cmd_quit,  EXFAIL,              0,  0, 
0103                 "Alias for `quit'"
0104                 , NULL},
0105     {"echo",    cmd_echo,  EXFAIL,              1,  0, 
0106                 "Echo text back to terminal"
0107                 , NULL},
0108     {"idle",    cmd_idle,  EXFAIL,              0,  2, 
0109                 "Enter daemon process in idle state (if not started)"
0110                 , NULL},
0111     {"help",    cmd_help,  EXFAIL,              1,  0, 
0112                 "Print help (this output)\n"
0113                 "\t args: help [command]"
0114                 , NULL},
0115     {"h",       cmd_help,  EXFAIL,              1,  0, 
0116                 "Alias for `help'"
0117                 , NULL},
0118     {"info",    cmd_help,  EXFAIL,              1,  0, 
0119                 "Alias for `help'"
0120                 , NULL},
0121     {"stat",    cmd_stat,  EXFAIL,              0,  2, 
0122                 "Prints general status information"
0123                 , NULL},
0124     {"ldcf",    cmd_ldcf,  NDRXD_COM_LDCF_RQ,   0,  1, 
0125                 "Load configuration"
0126                 , NULL},
0127     {"start",   cmd_start, NDRXD_COM_START_RQ,  1,  1, 
0128                 "Start application domain\n"
0129                 "\t Also loads configuration automatically.\n"
0130                 "\t args: start [-y]  [(-s <server>) | (-i <srvid>) | (-g <procgrp>)]"
0131                 , NULL},
0132     {"psc",     cmd_psc,   NDRXD_COM_PSC_RQ,    1,  1, 
0133                 "Print services\n"
0134                 "\t args: psc [-s]\n"
0135                 "\t -s : print full service name", 
0136                 NULL},
0137     {"stop",    cmd_stop,  NDRXD_COM_STOP_RQ,   1,  2, 
0138                 "Stop application domain\n"
0139                 "\t args: stop [-y] [(-s <server>) | (-i <srvid>) | (-g <procgrp>)] [-k] [-f] [-l]"
0140                 , NULL},
0141     {"down",    cmd_fdown, EXFAIL,              1,  0, 
0142                 "Force App Server shutdown & resources cleanup\n"
0143                 "\tUsage: down [OPTION]...\n"
0144                 "\tOptional arguments: \n"
0145                 "\t\t -y\tDo not ask for confirmation\n"
0146                 "\t\t -u\tRemove user resources by username", 
0147                 NULL},
0148     {"udown",    cmd_udown, EXFAIL,             1,  0, 
0149                 "Remove resources by username\n"
0150                 "\tUsage: udown [OPTION]...\n"
0151                 "\tOptional arguments: \n"
0152                 "\t\t -y\tDo not ask for confirmation"
0153                 , NULL},
0154     {"cat",     cmd_cat,    NDRXD_COM_AT_RQ,    0,  1, 
0155                 "Attached to ndrxd user session in progress"
0156                 , NULL},
0157     {"reload",  cmd_reload,NDRXD_COM_RELOAD_RQ, 0,  1, 
0158                 "Load new configuration"
0159                 , NULL},
0160     {"testcfg", cmd_testcfg,NDRXD_COM_TESTCFG_RQ,0,  1, 
0161                 "Test new configuration"
0162                 , NULL},
0163     {"unadv",   cmd_unadv,NDRXD_COM_XADUNADV_RQ, 1,  1,
0164                 "Un-advertise service.\n"
0165                 "\t args: unadv -i server_id -s service_name"
0166                 , NULL},
0167     {"readv",   cmd_unadv,NDRXD_COM_XADREADV_RQ, 1,  1,
0168                 "Re-advertise service.\n"
0169                 "\t args: readv -i server_id -s service_name\n"
0170                 "\t might be usable if service Q was unlinked"
0171                 , NULL},
0172     {"restart", cmd_r,    EXFAIL,                1,  2, 
0173                 "Restart app or service (invokes start & stop with same args!)"
0174                 , NULL},
0175     {"r",       cmd_r,    EXFAIL,                1,  2, 
0176                 "Alias for `restart'"
0177                 , NULL},
0178     {"-v",      cmd_ver,  EXFAIL,                0,  0, 
0179                 "Print version info"
0180                 , NULL},
0181     {"ver",     cmd_ver,  EXFAIL,                0,  0, 
0182                 "Print version info, same as -v"
0183                 , NULL},
0184     {"ppm",     cmd_ppm,  NDRXD_COM_XAPPM_RQ,    1,  2, 
0185                 "Print process model\n"
0186                 "\tUsage ppm [OPTION]...\n"
0187                 "\t\t -2\tPrint Page 2"
0188                 ,NULL},
0189     {"psvc",cmd_shm_psvc,NDRXD_COM_XASHM_PSVC_RQ,1,  1, 
0190                 "Shared mem, print services\n"
0191                 "\t args: psvc [-r]\n"
0192                 "\t -r : for System V or Poll mode print resource identifers (msgid or pid)"
0193                 ,NULL},
0194     {"psrv",cmd_shm_psrv,NDRXD_COM_XASHM_PSRV_RQ,0,  1, 
0195                 "Shared mem, print servers"
0196                 , NULL},
0197     {"cabort",cmd_cabort,NDRXD_COM_XACABORT_RQ,  1,  1, 
0198                 "Abort app shutdown or startup.\n"
0199                 "\t args: abort [-y]"
0200                 , NULL},
0201     {"sreload", cmd_sreload, NDRXD_COM_SRELOAD_RQ,1,  1, 
0202                 "Restarts server instance by instance\n"
0203                 "\t Args: sreload [-y] [(-s <server>) | (-i <srvid>) | (-g <procgrp>)]"
0204                 , NULL},
0205     {"sr", cmd_sreload, NDRXD_COM_SRELOAD_RQ,    1,  1, 
0206                 "Alias for `sreload'"
0207                 , NULL},
0208     {"pq",cmd_pq,NDRXD_COM_XAPQ_RQ,              0,  1, 
0209                 "Print service queues"
0210                 , NULL},
0211     {"pqa",cmd_pqa,  EXFAIL,                     1,  2, 
0212                 "Print all queues\n"
0213                 "\t args: pqa [-a]\n"
0214                 "\t -a - print all queues "
0215                 "(incl. other local systems)"
0216                 , NULL},
0217     /* New XA commands: printtrans (pt), abort, commit, exsting abort move to: sabort (start/stop) 
0218      * abort + install ctrl+c handler 
0219      */
0220     {"pt",        cmd_pt,EXFAIL,                 0,  1, 
0221                 "Print transactions"
0222                 , NULL},
0223     {"printtrans",cmd_pt,EXFAIL,                 0,  1, 
0224                 "Alias for `pt'"
0225                 , NULL},
0226     {"abort",     cmd_abort,EXFAIL,              1,  1, 
0227                 "Abort transaction\n"
0228                 "\t args: abort -t <RM Ref> -x <XID> [-g <Group No>] [-y]"
0229                 , NULL},
0230     {"aborttrans",cmd_abort,EXFAIL,              1,  1, 
0231                 "Alias for `abort'"
0232                 , NULL},
0233     {"commit",     cmd_commit,EXFAIL,            1,  1, 
0234                 "Commit transaction\n"
0235                 "\t args: commit -t <RM Ref> -x <XID> [-y]"
0236                 , NULL},
0237     {"committrans",cmd_commit,EXFAIL,            1,  1, 
0238                 "Alias for `commit'"
0239                 , NULL},
0240     {"recoverlocal",cmd_recoverlocal,EXFAIL,     1,  1, 
0241                 "Print local local in-doubt transactions\n"
0242                 "\t args: recoverlocal [-s <TM SERVICE>] [-p]\n"
0243                 "\t -s - TMSRV which to query for transactions\n"
0244                 "\t -p - Parse XID and print details"
0245                 , NULL},
0246     {"commitlocal",cmd_commitlocal,EXFAIL,       1,  1, 
0247                 "Commit local in-doubt transaction\n"
0248                 "\t args: commitlocal [-s <TM SERVICE> [-x <XID>]] [-y] [-p]\n"
0249                 "\t -s - TMSRV which serves transaction\n"
0250                 "\t -x - particular XID\n"
0251                 "\t -y - confirm\n"
0252                 "\t -p - Parse XID and print details"
0253                 , NULL},
0254     {"abortlocal",cmd_abortlocal,EXFAIL,         1,  1, 
0255                 "Abort local in-doubt transaction\n"
0256                 "\t args: abortlocal [-s <TM SERVICE> [-x <XID>]] [-y] [-p]\n"
0257                 "\t -x - particular XID\n"
0258                 "\t -y - confirm\n"
0259                 "\t -p - Parse XID and print details"
0260                 , NULL},
0261     {"forgetlocal",cmd_forgetlocal,EXFAIL,       1,  1, 
0262                 "Abort local in-doubt transaction\n"
0263                 "\t args: forgetlocal [-s <TM SERVICE> [-x <XID>]] [-y] [-p]\n"
0264                 "\t -x - particular XID\n"
0265                 "\t -y - confirm\n"
0266                 "\t -p - Parse XID and print details"
0267                 , NULL},
0268     {"pe",        cmd_pe,NDRXD_COM_PE_RQ,        0,  1, 
0269                 "Print env (from ndrxd)"
0270                 , NULL},
0271     {"printenv",  cmd_pe,NDRXD_COM_PE_RQ,        1,  1, 
0272                 "Alias for `pe'"
0273                 , NULL},
0274     {"set",       cmd_set,NDRXD_COM_SET_RQ,      1,  1, 
0275                 "Set env variable. \n"
0276                 "\t Format: VAR=SOME VALUE (will be contact with spaces)"
0277                 , NULL},
0278     {"unset",     cmd_unset,NDRXD_COM_UNSET_RQ,  1,  1, 
0279                 "Set env variable. Forma: VAR"
0280                 , NULL},
0281     {"pc",        cmd_pc,EXFAIL,                 0,  1, 
0282                 "Print clients"
0283                 , NULL},
0284     {"sc",        cmd_sc,EXFAIL,                 1,  1, 
0285                 "Stop client\n"
0286                 "\t args: sc (-t <Tag> [-s <Subsection (default -)]) | (-g <procgrp>) [-w <wait in millis>]"
0287                 , NULL},
0288     {"bc",        cmd_bc,EXFAIL,                 1,  1, 
0289                 "Boot(start) client\n"
0290                 "\t args: bc (-t <Tag> [-s <Subsection (default -)]) | (-g <procgrp>) [-w <wait in millis>]"
0291                 , NULL},
0292     {"rc",        cmd_rc,EXFAIL,                 1,  1, 
0293                 "Reload/Restart clients one-by-one\n"
0294                 "\t args: rc (-t <Tag> [-s <Subsection (default -)]) | (-g <procgrp>) [-w <wait in millis>]"
0295                 , NULL},
0296     {"mqlc",      cmd_mqlc,EXFAIL,               0,  1, 
0297                 "List persistent queue configuration"
0298                 , NULL},
0299     {"mqlq",      cmd_mqlq,EXFAIL,               0,  1, 
0300                 "List persistent queues (active/dynamic)"
0301                 , NULL},
0302     {"mqrc",      cmd_mqrc,EXFAIL,               0,  1, 
0303                 "Reload TMQ config"
0304                 , NULL},
0305     {"mqlm",      cmd_mqlm,EXFAIL,               1,  1, 
0306                 "List messages in q\n"
0307                 "\t args: mqlm -s <QSpace> -q <QName>"
0308                 , NULL},
0309     {"mqdm",      cmd_mqdm,EXFAIL,               1,  1, 
0310                 "Dump/peek message to stdout\n"
0311                 "\t args: mqdm -n <Cluster node id> -i <Server ID> -m <Message ID>"
0312                 , NULL},
0313     {"mqch",      cmd_mqch,EXFAIL,               1,  1, 
0314                 "Change queue config (runtime only)\n"
0315                 "\t args: mqch -n <Cluster node id> -i <Server ID> -q <Q def (conf format)>"
0316                 , NULL},
0317     {"mqrm",      cmd_mqrm,EXFAIL,               1,  1, 
0318                 "Remove message from Q space\n"
0319                 "\t args: mqrm -n <Cluster node id> -i <Server ID> -m <Message ID>"
0320                 , NULL},
0321     {"mqmv",      cmd_mqmv,EXFAIL,               1,  1, 
0322                 "Move message to different qspace/qname\n"
0323                 "\t args: mqmv -n <Source cluster node id> -i <Source server ID>\n"
0324                 "\t -m <Source Message ID> -s <Dest qspace> -q <Dest qname>"
0325                 , NULL},
0326     {"killall",   cmd_killall,EXFAIL,            1,  0, 
0327                 "Kill all processes (in ps -efww) matching the name\n"
0328                 "\t args: killall <name1> <name2> ... <nameN>"
0329                 , NULL},
0330     {"qrm",       cmd_qrm,EXFAIL,                1,  0, 
0331                 "Remove specific queue\n"
0332                 "\t args: qrm <qname1> <qname2> ... <qnameN>"
0333                 , NULL},
0334     {"qrmall",    cmd_qrmall,EXFAIL,             1,  0, 
0335                 "Remove queue matching the substring \n"
0336                 "\t args: qrmall <substr1> <substr2> ... <substrN>"
0337                 , NULL},
0338     {"provision", cmd_provision,EXFAIL,          1,  0, 
0339                 "Prepare initial Enduro/X instance environment \n"
0340                 "\t args: provision [-d] [-v<param1>=<value1>] ... [-v<paramN>=<valueN>]"
0341                , NULL},
0342     {"gen",       cmd_gen,EXFAIL,                1,  0, 
0343                 "Generate sources\n"
0344                  "\t args: gen <target> <type> [-d] "
0345                  "[-v<param1>=<value1>] ... [-v<paramN>=<valueN>]\n"
0346                  "\t tagets/types available:"
0347                 , cmd_gen_help},
0348     {"cs",        cmd_cs,EXFAIL,                 1,  1, 
0349                 "Cache show\n"
0350                 "\t args: cs <cache_db_name>|-d <cache_db_name>"
0351                 , NULL},
0352     {"cacheshow", cmd_cs,EXFAIL,                 1,  1, 
0353                 "Alias for `cs' "
0354                 , NULL},
0355     {"cd",        cmd_cd,EXFAIL,                 1,  1, 
0356                 "Dump message in cache\n"
0357                 "\t args: cd -d <dbname> -k <key> [-i interpret_result]"
0358                 , NULL},
0359     {"cachedump", cmd_cd,EXFAIL,                 1,  1, 
0360                 "Alias for `cd' "
0361                 , NULL},
0362     {"ci",        cmd_ci,EXFAIL,                 1,  1, 
0363                 "Invalidate cache\n"
0364                 "\t args: ci -d <dbname> [-k <key>][-r use_regexp]"
0365                 , NULL},
0366     {"cacheinval",cmd_ci,EXFAIL,                 1,  1, 
0367                 "Alias for `ci' "
0368                 , NULL},
0369 #if defined(EX_USE_SYSVQ) || defined(EX_USE_SVAPOLL)
0370     {"svmaps",    cmd_svmaps,EXFAIL,             1,  0, 
0371                 "Print System V Queue mapping tables\n"
0372                 "\tUsage: svmaps [OPTION]...\n"
0373                 "\tOptional arguments: \n"
0374                 "\t\t -p\tPrint Posix to System V table (default)\n"
0375                 "\t\t -s\tPrint System V to Posix table\n"
0376                 "\t\t -a\tPrint all entries (lots of records...)\n"
0377                 "\t\t -i\tPrint in use entries (default)\n"
0378                 "\t\t -w\tPrint entries which were used but now free",
0379                 NULL},
0380 #endif
0381     {"svqids",    cmd_svqids,EXFAIL,            1,  0, 
0382                 "Print System V user queue ids\n"
0383                 "\tUsage: svqids [-i] [-k]\n"
0384                 "\tOptional arguments: \n"
0385                 "\t\t -i Print System V Resource IDs only\n"
0386                 "\t\t -k Print System V Resource Keys only"
0387                 , NULL},
0388     {"svsemids",  cmd_svsemids,EXFAIL,          1,  0, 
0389                 "Print System V user semaphore ids\n"
0390                 "\tUsage: svsemids [-i] [-k]\n"
0391                 "\tOptional arguments: \n"
0392                 "\t\t -i Print System V Resource IDs only\n"
0393                 "\t\t -k Print System V Resource Keys only"
0394                 , NULL},
0395     {"pubfdb",    cmd_pubfdb,EXFAIL,            0,  0, 
0396                 "Print UBF custom fields (from DB)"
0397                 , NULL},
0398     {"poller",    cmd_poller,EXFAIL,            0,  0, 
0399                 "Print active poller sub-system"
0400                 , NULL},
0401     {"shms",      cmd_shms,EXFAIL,              0,  0, 
0402                 "Print shared memory segments"
0403                 , NULL},
0404     {"pmode",     cmd_pmode,EXFAIL,             0,  0, 
0405                 "Print Enduro/X build environment (ndrx_config.h)"
0406                 , NULL},
0407     {"ps",        cmd_ps,EXFAIL,                1,  0, 
0408                 "List processes\n"
0409                 "\tUsage: ps [OPTION]...\n"
0410                 "\tOptional arguments: \n"
0411                 "\t\t -a FILTER1\tFirst filter (grep style)\n"
0412                 "\t\t -b FILTER2\tSecond filter\n"
0413                 "\t\t -c FILTER3\tThird filter\n"
0414                 "\t\t -d FILTER4\tForth filter\n"
0415                 "\t\t -r FILTER_REX\tPosix regexp filter\n"
0416                 "\t\t -p\tPrint PIDs only\n"
0417                 "\t\t -m\tPrint memory stats (pid), -p mode only (pid:rss:vsz in kb)\n"
0418                 "\t\t -x PID\tExclude specific pid"
0419                 , NULL},
0420     {"appconfig", cmd_appconfig,  NDRXD_COM_APPCONFIG_RQ,   1,  1, 
0421                 "Change/get ndrxd application cfg dynamically\n"
0422                 "\tUsage: appconfig SETTING [NEWVALUE]\n"
0423                 "\tPossible SETTING values: \n"
0424                 "\t\t sanity\tSanity check period (seconds), number\n"
0425                 "\t\t checkpm\tProcess model check sanity cycles, number\n"
0426                 "\t\t brrefresh\tNumber of sanity units to send full bridge refreshes\n"
0427                 "\t\t restart_min\tNumber of sanity units after which respawn died server\n"
0428                 "\t\t restart_step\tNumber of sanity units increment for died server respawn\n"
0429                 "\t\t restart_max\tMax number of sanity units for died server respawn\n"
0430                 "\t\t restart_to_check\tNumber of seconds for ndrxd to learn about\n"
0431                     "\t\t\tsystem after recovery start of ndrxd\n"
0432                 "\t\t gather_pq_stats\tGather queue stats, Y/N\n"
0433                 "\t\t rqaddrttl\tNumber of seconds for System V Request Address\n"
0434                     "\t\t\tto live with out servers"
0435                 , NULL},
0436     {"dping", cmd_dping,EXFAIL,                1,  1,  
0437                 "Ping `ndrxd' process\n"
0438                 "\tUsage: dping [OPTION]...\n"
0439                 "\tOptional arguments: \n"
0440                 "\t\t -c\tNumber of pings (default 4)"
0441                 , NULL},
0442     {"dpid", cmd_dpid,EXFAIL,                   0,  1,  
0443                 "Print ndrxd PID from pid file"
0444                 , NULL},
0445     {"dsleep", cmd_dsleep,NDRXD_COM_DSLEEP_RQ,  1,  1,  
0446                 "Put ndrxd in sleep (disable activity for time period), for debug\n"
0447                 "\tUsage: dsleep SLEEP_SECONDS"
0448                 , NULL},
0449     {"mibget",     cmd_mibget,EXFAIL,           1,  1, 
0450                 "Dump message in cache\n"
0451                 "\t args: mibget -c <T_CLASS> [-m]\n"
0452                 "\t\t -m\tMachine output\n"
0453                 "\t\t -c\tT_CLIENT|T_DOMAIN|T_MACHINE|T_QUEUE|T_SERVER|T_SERVICE|T_SVCGRP|T_BRCON"
0454                 , NULL},
0455     {"lcf",     cmd_lcf, EXFAIL,                1,  0, 
0456                 "Latent Command management\n"
0457                 "\tUsage: lcf [COMMAND] [OPTION]...\n"
0458                 "\tWhen COMMAND is not present, binary prints the shared memory output\n"
0459                 "\tBuilt in COMMANDs:\n"
0460                 "\t\t -1\tPrint page 1 of LCF memory (default) \n"
0461                 "\t\t -2\tPrint page 2 of LCF memory\n"
0462                 "\t\t -3\tPrint page 3 of LCF memory\n"
0463                 "\tOptional arguments: \n"
0464                 "\t\t -p\tApply to PID\n"
0465                 "\t\t -b\tApply to BINARY\n"
0466                 "\t\t -r\tPID or BINARY is regular expression\n"
0467                 "\t\t -a\tApply to all binaries in application domain\n"
0468                 "\t\t -n\tExecute COMMAND on binary startup\n"
0469                 "\t\t -e\tExecute COMMAND on binary startup with command expiry\n"
0470                 "\t\t -s <SLOT>\tSlot number for command\n"
0471                 "\t\t -A\tArgument A to COMMAND\n"
0472                 "\t\t -B\tArgument B to COMMAND"
0473                 , cmd_lcf_help},
0474     {"shmcfg",  cmd_shmcfg,EXFAIL,             0,  0, 
0475                 "Print shared memory current configuration"
0476                 , NULL},
0477     {"prtsvc",  cmd_prtsvc,   EXFAIL,    1,  1, 
0478                 "Print routing services\n"
0479                 "\tUsage: prtsvc [OPTION]...\n"
0480                 "\tOptional arguments: \n"
0481                 "\t\t -a\tPrint all slots\n"
0482                 "\t\t -i\tPrint in use slots\n"
0483                 "\t\t -w\tPrint was in use slots",
0484                 NULL},
0485     {"psg",     cmd_psg,EXFAIL,              1,  0, 
0486                 "Print singleton groups"
0487                 "\tUsage: psg [OPTION]...\n"
0488                 "\tOptional arguments: \n"
0489                 "\t\t -a\tPrint all singleton groups (including unused)\n"
0490                 , NULL},
0491     {"mmon",    cmd_mmon,EXFAIL,             0,  0, 
0492                 "Enable maintenace mode"
0493                 , NULL},
0494     {"mmoff",    cmd_mmoff,EXFAIL,           0,  0, 
0495                 "Disable maintenace mode"
0496                 , NULL},
0497 };
0498 
0499 /*
0500  * List of commands that does not require init
0501  */
0502 char *M_noinit[] = {
0503     "provision"
0504     ,"help"
0505     ,"h"
0506     ,"killall"
0507     ,"-v"
0508     ,"ver"
0509     ,"udown"
0510     ,"gen"
0511     ,"ps"
0512     ,"pmode"
0513 };
0514 
0515 /**
0516  * Common call arguments - all commands (even not related) must be listed here!
0517  */
0518 gencall_args_t G_call_args[] =
0519 {
0520     {NDRXD_COM_LDCF_RQ,     NULL,           simple_output,  EXTRUE},/*0*/
0521     {NDRXD_COM_LDCF_RP,     NULL,           NULL,           EXFALSE},/*1*/
0522     {NDRXD_COM_START_RQ,    ss_rsp_process, simple_output,  EXTRUE},/*2*/
0523     {NDRXD_COM_START_RP,    NULL,           NULL,           EXFALSE},/*3*/
0524     {NDRXD_COM_SVCINFO_RQ,  NULL,           NULL,           EXFALSE},/*4*/
0525     {NDRXD_COM_SVCINFO_RP,  NULL,           NULL,           EXFALSE},/*5*/
0526     {NDRXD_COM_PMNTIFY_RQ,  NULL,           NULL,           EXFALSE},/*6*/
0527     {NDRXD_COM_PMNTIFY_RP,  NULL,           NULL,           EXFALSE},/*7*/
0528     {NDRXD_COM_PSC_RQ,      psc_rsp_process,simple_output,  EXTRUE},/*8*/
0529     {NDRXD_COM_PSC_RP,      NULL,           NULL,           EXFALSE},/*9*/
0530     {NDRXD_COM_STOP_RQ,     ss_rsp_process, simple_output,  EXTRUE},/*10*/
0531     {NDRXD_COM_STOP_RP,     NULL,           NULL,           EXFALSE},/*11*/
0532     {NDRXD_COM_SRVSTOP_RQ,  NULL,           NULL,           EXFALSE},/*12*/
0533     {NDRXD_COM_SRVSTOP_RP,  NULL,           NULL,           EXFALSE},/*13*/
0534     {NDRXD_COM_AT_RQ,       at_rsp_process, simple_output,  EXTRUE},/*14*/
0535     {NDRXD_COM_AT_RP,       NULL,           NULL,           EXFALSE},/*15*/
0536     {NDRXD_COM_RELOAD_RQ,reload_rsp_process,simple_output,  EXTRUE},/*16*/
0537     {NDRXD_COM_RELOAD_RP,   NULL,           NULL,           EXFALSE},/*17*/
0538     {NDRXD_COM_TESTCFG_RQ,reload_rsp_process,simple_output,  EXTRUE},/*18*/
0539     {NDRXD_COM_TESTCFG_RP,   NULL,          NULL,           EXFALSE},/*19*/
0540     {NDRXD_COM_SRVINFO_RQ,   NULL,          NULL,           EXFALSE},/*20*/
0541     {NDRXD_COM_SRVINFO_RP,   NULL,          NULL,           EXFALSE},/*21*/
0542     {NDRXD_COM_SRVUNADV_RQ,   NULL,         NULL,           EXFALSE},/*22*/
0543     {NDRXD_COM_SRVUNADV_RP,   NULL,         NULL,           EXFALSE},/*23*/
0544     {NDRXD_COM_XADUNADV_RQ,   NULL,         simple_output,  EXTRUE},/*24*/
0545     {NDRXD_COM_XADUNADV_RP,   NULL,         NULL,           EXFALSE},/*25*/
0546     {NDRXD_COM_NXDUNADV_RQ,   NULL,         NULL,           EXFALSE},/*26*/
0547     {NDRXD_COM_NXDUNADV_RP,   NULL,         NULL,           EXFALSE},/*27*/
0548     {NDRXD_COM_SRVADV_RQ,     NULL,         NULL,           EXFALSE},/*28*/
0549     {NDRXD_COM_SRVADV_RP,     NULL,         NULL,           EXFALSE},/*29*/
0550     {NDRXD_COM_XAPPM_RQ,      ppm_rsp_process,simple_output,EXTRUE}, /*30*/
0551     {NDRXD_COM_XAPPM_RP,      NULL,         NULL,         EXFALSE},/*31*/
0552     {NDRXD_COM_XASHM_PSVC_RQ, shm_psvc_rsp_process,simple_output,EXTRUE},/*31*/
0553     {NDRXD_COM_XASHM_PSVC_RP, NULL,         NULL,         EXFALSE},/*32*/
0554     {NDRXD_COM_XASHM_PSRV_RQ, shm_psrv_rsp_process,simple_output,EXTRUE},/*33*/
0555     {NDRXD_COM_XASHM_PSRV_RP, NULL,         NULL,         EXFALSE},/*34*/
0556     {NDRXD_COM_NXDREADV_RQ,   NULL,         NULL,         EXFALSE},/*36*/
0557     {NDRXD_COM_NXDREADV_RP,   NULL,         NULL,         EXFALSE},/*37*/
0558     {NDRXD_COM_XADREADV_RQ,   NULL,         simple_output,EXTRUE },/*38*/
0559     {NDRXD_COM_XADREADV_RP,   NULL,         NULL,         EXFALSE}, /*39*/
0560     {NDRXD_COM_XACABORT_RQ,    NULL,         simple_output,EXTRUE },/*40*/
0561     {NDRXD_COM_XAABORT_RP,    NULL,         NULL,         EXFALSE}, /*41*/
0562     {NDRXD_COM_BRCON_RQ,      NULL,         NULL,         EXFALSE},/*42*/
0563     {NDRXD_COM_BRCON_RP,      NULL,         NULL,         EXFALSE},/*43*/
0564     {NDRXD_COM_BRDISCON_RQ,   NULL,         NULL,         EXFALSE},/*44*/
0565     {NDRXD_COM_BRDISCON_RP,   NULL,         NULL,         EXFALSE},/*45*/
0566     {NDRXD_COM_BRREFERSH_RQ,  NULL,         NULL,         EXFALSE},/*46*/
0567     {NDRXD_COM_BRREFERSH_RP,  NULL,         NULL,         EXFALSE},/*47*/
0568     {NDRXD_COM_BRCLOCK_RQ,    NULL,         NULL,         EXFALSE},/*48*/
0569     {NDRXD_COM_BRCLOCK_RP,    NULL,         NULL,         EXFALSE},/*49*/
0570     {NDRXD_COM_SRVGETBRS_RQ,  NULL,         NULL,         EXFALSE},/*50*/
0571     {NDRXD_COM_SRVGETBRS_RP,  NULL,         NULL,         EXFALSE},/*51*/
0572     {NDRXD_COM_SRVPING_RQ,    NULL,         NULL,         EXFALSE},/*52*/
0573     {NDRXD_COM_SRVPING_RP,    NULL,         NULL,         EXFALSE}, /*53*/
0574     {NDRXD_COM_SRELOAD_RQ,    ss_rsp_process, simple_output,EXTRUE},/*54*/
0575     {NDRXD_COM_SRELOAD_RP,    NULL,           NULL,        EXFALSE},/*55*/
0576     {NDRXD_COM_XAPQ_RQ,       pq_rsp_process,simple_output,EXTRUE},/*56*/
0577     {NDRXD_COM_XAPQ_RP,       NULL,         NULL,         EXFALSE},/*57*/
0578     {NDRXD_COM_PE_RQ,         pe_rsp_process,simple_output,EXTRUE},/*58*/
0579     {NDRXD_COM_PE_RP,         NULL,         NULL,         EXFALSE},/*59*/
0580     {NDRXD_COM_SET_RQ,NULL,simple_output,                 EXTRUE},/*60*/
0581     {NDRXD_COM_SET_RP,        NULL,         NULL,         EXFALSE},/*61*/
0582     {NDRXD_COM_UNSET_RQ,NULL,simple_output,               EXTRUE},/*62*/
0583     {NDRXD_COM_UNSET_RP,       NULL,        NULL,         EXFALSE},/*63*/
0584     {NDRXD_COM_SRELOADI_RQ,    NULL,        NULL,         EXFALSE},/*64*/
0585     {NDRXD_COM_SRELOADI_RP,    NULL,        NULL,         EXFALSE},/*65*/
0586     {NDRXD_COM_SRELOAD_RQ,appconfig_rsp_process, simple_output,EXTRUE},/*66*/
0587     {NDRXD_COM_SRELOAD_RP,    NULL,           NULL,       EXFALSE},/*67*/
0588     {NDRXD_COM_DPING_RQ,    NULL, simple_output,          EXTRUE},/*68*/
0589     {NDRXD_COM_DPING_RP,    NULL,           NULL,         EXFALSE},/*69*/
0590     {NDRXD_COM_DSLEEP_RQ,    NULL, simple_output,          EXTRUE},/*70*/
0591     {NDRXD_COM_DSLEEP_RP,    NULL,           NULL,         EXFALSE}/*71*/
0592 };
0593 
0594 /**
0595  * Display EnduroX Version string
0596  */
0597 exprivate int cmd_ver(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0598 {
0599     printf(NDRX_VERSION
0600         "\n");
0601     return EXSUCCEED;
0602 }
0603 
0604 /**
0605  * Show help/command summary
0606  * @param p_cmd_map
0607  * @param argc
0608  * @param argv
0609  * @return SUCCEED
0610  */
0611 exprivate int cmd_help(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0612 {
0613     int i;
0614     cmd_mapping_t *p;
0615     /**/
0616     printf("COMMAND\tDESCR\n");
0617     printf("-------\t------------------------------------------------------------------------\n");
0618     for (i=0; i<N_DIM(M_command_map); i++)
0619     {
0620         p = &M_command_map[i];
0621         if ((argc>1 && 0==strcmp(p->cmd, argv[1])) || 1==argc)
0622         {
0623             if (NULL==p->p_add_help)
0624             {
0625                 printf("%s\t%s\n\n", p->cmd, p->help);
0626             }
0627             else
0628             {
0629                 printf("%s\t%s\n", p->cmd, p->help);
0630             }
0631             
0632             if (p->p_add_help)
0633             {
0634                 p->p_add_help();
0635             }
0636         }
0637     }
0638     return EXSUCCEED;
0639 }
0640 
0641 /**
0642  * Generate completion list
0643  * @param buf buffer with keys request
0644  * @param lc list to fill
0645  */
0646 exprivate void completion_handler(const char *buf, linenoiseCompletions *lc) 
0647 {
0648     int i;
0649     char tmp[128];
0650     int len;
0651     int is_help=EXFALSE;
0652     
0653     len = strlen(buf);
0654     
0655     if (0==strncmp(buf, "help", 4))
0656     {
0657         is_help=EXTRUE;
0658         for (i=0; i<N_DIM(M_command_map); i++)
0659         {
0660             snprintf(tmp, sizeof(tmp), "help %s", M_command_map[i].cmd);
0661             
0662             if (0==strncmp(tmp, buf, len))
0663             {
0664                 linenoiseAddCompletion(lc,tmp);
0665             }
0666             
0667         }
0668     }
0669     else for (i=0; i<N_DIM(M_command_map); i++)
0670     {
0671         if (0==strncmp(M_command_map[i].cmd, buf, len))
0672         {
0673             linenoiseAddCompletion(lc,M_command_map[i].cmd);
0674         }
0675     }
0676     
0677     if (!is_help)
0678     {
0679         /* Add also LCF... */
0680         cmd_lcf_completion(lc, (char *)buf);
0681     }
0682 }
0683 
0684 
0685 /**
0686  * Start idle instance (if backend does not exists!)
0687  * @param p_cmd_map
0688  * @param argc
0689  * @param argv
0690  * @return SUCCEED
0691  */
0692 exprivate int cmd_idle(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0693 {
0694     int ret=EXSUCCEED;
0695 
0696     if (!is_ndrxd_running(NULL, EXFALSE) && NDRXD_STAT_NOT_STARTED==G_config.ndrxd_stat)
0697     {
0698         ret = start_daemon_idle();
0699     }
0700     else
0701     {
0702         fprintf(stderr, "Cannot start idle in current state!\n");
0703     }
0704             
0705     return ret;
0706 }
0707 
0708 /**
0709  * prints current status info
0710  * @param p_cmd_map
0711  * @param argc
0712  * @param argv
0713  * @return SUCCEED
0714  */
0715 exprivate int cmd_stat(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0716 {
0717     int ret=EXSUCCEED;
0718 #define _STATUS_FMT     "STATUS: %s\n"
0719 
0720     /* Test current status... */
0721     is_ndrxd_running(NULL, EXFALSE);
0722     
0723     if (NDRXD_STAT_NOT_STARTED==G_config.ndrxd_stat)
0724     {
0725         printf(_STATUS_FMT, "Not started");
0726     }
0727     else if (NDRXD_STAT_MALFUNCTION==G_config.ndrxd_stat)
0728     {
0729         printf(_STATUS_FMT, "Malfunction");
0730     }
0731     else
0732     {
0733         printf(_STATUS_FMT, "Running OK");
0734     }
0735     
0736     /* This is not used!
0737     printf("IDLE  : %s\n", G_config.is_idle?"YES":"NO");
0738     */
0739     return ret;
0740 }
0741 
0742 
0743 /**
0744  * Quit command 
0745  * @param p_cmd_map
0746  * @param argc
0747  * @param argv
0748  * @return SUCCEED
0749  */
0750 exprivate int cmd_quit(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0751 {
0752     NDRX_LOG(log_debug, "cmd_quit called");
0753     M_quit_requested = EXTRUE;
0754     *p_have_next = EXFALSE;
0755     return EXSUCCEED;
0756 }
0757 
0758 /**
0759  * echo command
0760  * @param p_cmd_map
0761  * @param argc
0762  * @param argv
0763  * @return SUCCEED
0764  */
0765 exprivate int cmd_echo(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0766 {
0767     int i;
0768     NDRX_LOG(log_debug, "cmd_echo called");
0769 
0770     for (i=1; i< argc; i++)
0771     {
0772         printf("%s ", argv[i]);
0773     }
0774     
0775     printf("\n");
0776 
0777     return EXSUCCEED;
0778 }
0779 
0780 /**
0781  * Print current poller sub-system
0782  * @param p_cmd_map
0783  * @param argc
0784  * @param argv
0785  * @return SUCCEED
0786  */
0787 exprivate int cmd_poller(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0788 {
0789     printf("%s\n", ndrx_epoll_mode());
0790     return EXSUCCEED;
0791 }
0792 
0793 /**
0794  * List shared mems if any...
0795  * @param p_cmd_map
0796  * @param argc
0797  * @param argv
0798  * @return SUCCEED
0799  */
0800 exprivate int cmd_shms(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0801 {
0802     string_list_t* elt = NULL;
0803 
0804     string_list_t * list = ndrx_shm_shms_list(G_config.ipckey);
0805     
0806     LL_FOREACH(list, elt)
0807     {
0808         printf("%s\n", elt->qname);
0809     }
0810     
0811     if (NULL!=list)
0812     {
0813         ndrx_string_list_free(list);
0814     }
0815 
0816     return EXSUCCEED;
0817 }
0818 
0819 /**
0820  * Print build mode
0821  * @param p_cmd_map
0822  * @param argc
0823  * @param argv
0824  * @return SUCCEED
0825  */
0826 exprivate int cmd_pmode(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0827 {
0828     printf("%s\n", ndrx_G_resource_ndrx_config);
0829     return EXSUCCEED;
0830 }
0831 
0832 /**
0833  * Simple output
0834  * @param buf
0835  */
0836 expublic void simple_output(char *buf)
0837 {
0838     fprintf(stderr, "%s", buf);
0839     fprintf(stderr, "\n");
0840 }
0841 
0842 /**
0843  * Checks is terminal tty.
0844  * @return 
0845  */
0846 exprivate int is_tty()
0847 {
0848     return isatty(0);
0849 }
0850 
0851 /**
0852  * Reads the command either from command line or from stdin.
0853  * If from stdin, then command gets splitted.
0854  * @return SUCCEED/FAIL
0855  */
0856 exprivate int get_cmd(int *p_have_next)
0857 {
0858     int ret=EXSUCCEED;
0859     int i;
0860 
0861     G_cmd_argc_raw = 0;
0862 
0863     if (M_argc > 1)
0864     {
0865         /* Operate with command line args */   
0866         for (i=1; i< M_argc && G_cmd_argc_raw<MAX_ARGS; i++)
0867         {
0868             /* Migrate to raw format: */
0869             NDRX_STRCPY_SAFE_DST(G_cmd_argv[i-1], M_argv[i], MAX_ARG_LEN);
0870             G_cmd_argc_raw++;
0871         }
0872         
0873         *p_have_next = EXFALSE;
0874         
0875     }
0876     else /* Operate with stdin. */
0877     {
0878         char *p;
0879         int len;
0880         memset(M_buffer, 0, sizeof(M_buffer));
0881 
0882         /* Welcome only if it is terminal */
0883         if (is_tty())
0884         {
0885             /* in this case it is interactive session 
0886              * also we shall save the history file
0887              * to home folder?
0888              */
0889             char *line;
0890             char banner[128];
0891             
0892             snprintf(banner, sizeof(banner), "NDRX %s> ", ndrx_xadmin_nodeid());
0893 
0894             line = linenoise(banner);
0895             
0896             if (NULL!=line)
0897             {
0898                 NDRX_STRCPY_SAFE(M_buffer, line);
0899                 linenoiseHistoryAdd(line);
0900             }
0901             
0902             NDRX_FREE(line);
0903             
0904             /* Feature #782 */
0905             if (ndrx_G_ctrl_d)
0906             {
0907                 M_quit_requested=EXTRUE;
0908             }
0909         }
0910         else
0911         {
0912             /* We should get something! */
0913             while (NULL==fgets(M_buffer, sizeof(M_buffer), stdin))
0914             {
0915                 /* if we do not have tty, then exit */
0916                 if (!is_tty())
0917                 {
0918                     /* do not have next */
0919                     *p_have_next = EXFALSE;
0920                     goto out;
0921                 }
0922             }
0923         }
0924 
0925         /* strip off trailing newline */
0926         len = strlen(M_buffer);
0927         if (len > 0 && '\n'==M_buffer[len-1])
0928             M_buffer[len-1] = EXEOS;
0929         
0930         /* Allow repeated commands */
0931         if (is_tty())
0932         {
0933             if (EXEOS!=M_buffer_prev[0] && '/' == M_buffer[0])
0934             {
0935                 NDRX_STRCPY_SAFE(M_buffer, M_buffer_prev);
0936             }
0937             else if (EXEOS!=M_buffer[0])
0938             {
0939                 NDRX_STRCPY_SAFE(M_buffer_prev, M_buffer);
0940             }
0941         }
0942         
0943         /* preserve values in quotes... as atomic values */
0944         for (p = ndrx_strtokblk ( M_buffer, ARG_DEILIM, "'\""), i=0; 
0945                 NULL!=p && G_cmd_argc_raw<MAX_ARGS; p = ndrx_strtokblk (NULL, ARG_DEILIM, "'\""), i++)
0946         {
0947             NDRX_STRCPY_SAFE_DST(G_cmd_argv[G_cmd_argc_raw], p, MAX_ARG_LEN);
0948             G_cmd_argc_raw++;
0949             
0950         }
0951         /* We have next from stdin, if not quit command executed last */
0952         if (!M_quit_requested)
0953         {
0954             *p_have_next = EXTRUE;
0955         }
0956         else
0957         {
0958             *p_have_next = EXFALSE;
0959         }
0960     }
0961 out:
0962     return ret;
0963 }
0964 
0965 
0966 /**
0967  * Process requested command buffer.
0968  * The command by itself should be found in first argument
0969  * @return SUCCEED/FAIL
0970  */
0971 expublic int process_command_buffer(int *p_have_next)
0972 {
0973     int ret=EXSUCCEED;
0974     int i;
0975     cmd_mapping_t *map=NULL;
0976 
0977     
0978     for (i=0; i< N_DIM(M_command_map); i++)
0979     {
0980         if (0==strcmp(G_cmd_argv[0], M_command_map[i].cmd))
0981         {
0982             map = &M_command_map[i];
0983             break;
0984         }
0985     }
0986 
0987     if (NULL==map)
0988     {
0989         fprintf(stderr, "Command `%s' not found!\n", G_cmd_argv[0]);
0990         EXFAIL_OUT(ret);
0991     }
0992     else
0993     {
0994         /* check min/max args */
0995         if (!map->has_args && G_cmd_argc_raw > 1)
0996         {
0997             fprintf(stderr, "No arguments expected for command!\n");
0998             EXFAIL_OUT(ret);
0999         }
1000         else if ( (NDRX_XADMIN_RPLYQREQ==map->reqidle || NDRX_XADMIN_IDLEREQ==map->reqidle)
1001                 && EXFAIL==ndrx_xadmin_open_rply_q())
1002         {
1003             EXFAIL_OUT(ret);
1004         }
1005         else if (NDRX_XADMIN_IDLEREQ==map->reqidle
1006                 && !is_ndrxd_running(NULL, EXFALSE) && EXFAIL==ndrx_start_idle())
1007         {
1008             EXFAIL_OUT(ret);
1009         }
1010         else
1011         {
1012             /* execute function 
1013             fprintf(stderr, "exec: %s\n", M_cmd_argv[0]); */
1014             ret = M_command_map[i].p_exec_command(&M_command_map[i],
1015                                     G_cmd_argc_raw, (char **)G_cmd_argv, p_have_next);
1016         }
1017     }
1018 out:
1019     
1020     return ret;
1021 }
1022 
1023 /**
1024  * Un-initialize the process
1025  * @param [in] leave_shm Leave shared memory open
1026  * @return 
1027  */
1028 expublic int un_init(int closeshm)
1029 {
1030     NDRX_LOG(log_debug, "into un-init");
1031     if (G_config.ndrxd_q != (mqd_t)EXFAIL)
1032     {
1033         NDRX_LOG(log_debug, "Closing ndrxd_q: %p",
1034             (void *)((long)G_config.ndrxd_q));
1035         ndrx_mq_close(G_config.ndrxd_q);
1036         G_config.ndrxd_q = (mqd_t)EXFAIL;
1037     }
1038 
1039     if (G_config.reply_queue != (mqd_t)EXFAIL)
1040     {
1041         NDRX_LOG(log_debug, "Closing reply_queue: %p",
1042             ((void *)(long)G_config.reply_queue));
1043 
1044         ndrx_mq_close(G_config.reply_queue);
1045 
1046         NDRX_LOG(log_debug, "Unlinking [%s]",
1047             G_config.reply_queue_str);
1048         ndrx_mq_unlink(G_config.reply_queue_str);
1049         G_config.reply_queue = (mqd_t)EXFAIL;
1050     }
1051     
1052     /* In any case if session was open... */
1053     tpterm();
1054     
1055     if (closeshm)
1056     {
1057         /* close any additional shared resources */
1058         ndrx_xadmin_shm_close();
1059     }
1060     
1061     return EXSUCCEED;
1062 }
1063 
1064 /**
1065  * Start idle instance.
1066  * Caller must ensure that backend is not running.
1067  * @return
1068  */
1069 expublic int ndrx_start_idle(void)
1070 {
1071     int ret=EXSUCCEED;
1072 
1073     /* Start idle instance, if background process is not running. */
1074     if (NDRXD_STAT_NOT_STARTED==G_config.ndrxd_stat)
1075     {
1076         ret = start_daemon_idle();
1077     }
1078     else if (NDRXD_STAT_MALFUNCTION==G_config.ndrxd_stat)
1079     {
1080         fprintf(stderr, "Enduro/X back-end (ndrxd) malfunction - see logs!\n");
1081     }
1082 out:
1083     return ret;
1084 }
1085 
1086 /**
1087  * Get the file & tests does it exists or not
1088  * @param buf
1089  * @param size
1090  * @param path1
1091  * @param path2
1092  * @return TRUE/FALSE
1093  */
1094 exprivate int get_file(char *buf, size_t size, char *path1, char *path2)
1095 {
1096     if (NULL!=path1 && NULL!=path2)
1097     {
1098         snprintf(buf, size, "%s/%s", path1, path2);
1099     }
1100     else if (NULL!=path1)
1101     {
1102         /* snprintf(buf, size, "%s", path1); */
1103         NDRX_STRCPY_SAFE_DST(buf, path1, size);
1104     }
1105     else
1106     {
1107         return EXFALSE;
1108     }
1109     
1110     return ndrx_file_exists(buf);
1111 }
1112 
1113 /**
1114  * Initialize Client (and possible start idle back-end)
1115  * @return
1116  */
1117 expublic int ndrx_init(int need_init)
1118 {
1119     int ret=EXSUCCEED;
1120     int i;
1121     ndrx_inicfg_t *cfg = NULL;
1122 
1123     if (need_init)
1124     {
1125         if (EXSUCCEED!=(ret = load_env_config()))
1126         {
1127             goto out;
1128         }
1129     }
1130     
1131     /* Initialize memory for arg array */
1132     for (i=0; i<MAX_ARGS; i++)
1133     {
1134         G_cmd_argv[i] = NDRX_MALLOC(MAX_ARG_LEN);
1135         if (NULL==G_cmd_argv[i])
1136         {
1137             NDRX_LOG(log_error, "Failed to initialise clp array:% s", 
1138                     strerror(errno));
1139             ret=EXFAIL;
1140             goto out;
1141         }
1142     }
1143     
1144     /* TODO: Load any config files used by xadmin... 
1145      * - Try some global var NDRX_XADMIN_CONFIG
1146      * - Try ~/.xadmin.config
1147      * - Try /etc/xadmin.config
1148      * 
1149      * If found, use the NDRX_CCTAG, and load the config in global variables
1150      * so that other commands can use it later.
1151      * The section would be  [@xadmin].
1152      * 
1153      * The "provision" and "gen" command will use this.
1154      */
1155     
1156     if (get_file(G_xadmin_config_file, sizeof(G_xadmin_config_file), 
1157             getenv(CONF_NDRX_XADMIN_CONFIG), "xadmin.config") ||
1158         get_file(G_xadmin_config_file, sizeof(G_xadmin_config_file), 
1159             getenv("HOME"), ".xadmin.config") ||
1160         get_file(G_xadmin_config_file, sizeof(G_xadmin_config_file),
1161             "/etc/xadmin.config", NULL))
1162     {
1163         char cfg_section[128];
1164         char *cctag = getenv(NDRX_CCTAG);
1165         
1166         if (NULL==cctag)
1167         {
1168             NDRX_STRCPY_SAFE(cfg_section, "@xadmin");
1169         }
1170         else
1171         {
1172             snprintf(cfg_section, sizeof(cfg_section), "@xadmin/%s", cctag);
1173         }
1174         
1175         /* load the configuration file */
1176         if (NULL==(cfg=ndrx_inicfg_new()))
1177         {
1178             NDRX_LOG(log_error, "Failed to create inicfg: %s", Nstrerror(Nerror));
1179             EXFAIL_OUT(ret);
1180         }
1181         
1182         /* Add config file 
1183          * Looks like global section does not needs to be parsed here.
1184          */
1185         if (EXSUCCEED!=ndrx_inicfg_add(cfg, G_xadmin_config_file, NULL))
1186         {
1187              NDRX_LOG(log_error, "Failed to add resource [%s]: %s", 
1188                     G_xadmin_config_file, Nstrerror(Nerror));
1189             EXFAIL_OUT(ret);       
1190         }
1191         
1192         /* Get the section... */
1193         if (EXSUCCEED!=ndrx_inicfg_get_subsect(cfg, NULL, cfg_section, &G_xadmin_config))
1194         {
1195             NDRX_LOG(log_error, "Failed to resolve config: %s", Nstrerror(Nerror));
1196             EXFAIL_OUT(ret);    
1197         }
1198     }
1199     
1200     if (EXSUCCEED!=cmd_gen_load_scripts())
1201     {
1202         NDRX_LOG(log_error, "Failed to load gen scripts");
1203         EXFAIL_OUT(ret);    
1204     }
1205     
1206     /* setup console handler */
1207     
1208     linenoiseSetCompletionCallback(completion_handler);
1209     if (!linenoiseHistorySetMaxLen(100))
1210     {
1211         NDRX_LOG(log_error, "Failed to setup Console input history: %s", 
1212                 strerror(errno));
1213         EXFAIL_OUT(ret);
1214     }
1215     
1216     /* pull-in LCFs only at later stage...
1217      * so that we process none at startup, to have some management if
1218      * commands are broken
1219      */
1220     if (EXSUCCEED!=ndrx_xadmin_lcf_init())
1221     {
1222         NDRX_LOG(log_error, "Failed to register LCF commands");
1223         EXFAIL_OUT(ret);
1224     }
1225     
1226 out:
1227 
1228     if (NULL!=cfg)
1229     {
1230         ndrx_inicfg_free(cfg);
1231     }
1232 
1233     return ret;
1234 }
1235 /*
1236  * Main Entry point..
1237  */
1238 int main(int argc, char** argv) {
1239 
1240     int have_next = 1;
1241     int ret=EXSUCCEED;
1242     int need_init = EXTRUE;
1243     /* Command line arguments */
1244     M_argc = argc;
1245     M_argv = argv;
1246 
1247     /* NDRX_EMPTY_DEBUG; ?*/
1248     
1249     if (argc>1)
1250     {
1251         int i = 0;
1252         while (i< N_DIM(M_noinit))
1253         {
1254             if (0==strcmp(M_noinit[i], argv[1]))
1255             {
1256                 need_init=EXFALSE;
1257                 break;
1258             }
1259             
1260             i++;
1261         }
1262     }
1263     
1264     if (EXFAIL==ndrx_init(need_init))
1265     {
1266         NDRX_LOG(log_error, "Failed to initialize!");
1267         fprintf(stderr, "Failed to initialize!\n");
1268         EXFAIL_OUT(ret);
1269     }
1270 
1271     /* signal(SIGCHLD, sign_chld_handler);
1272      * there is no need to handle child signal.
1273      * Firstly if we are not parent of ndrxd
1274      * we will never receive it.
1275      * Secondly even if we are parent, we make
1276      * status checks at certain moments
1277      * and these monoments involve direct process
1278      * testing - we do not rely on signal.
1279      * */
1280     signal(SIGCHLD, SIG_IGN);
1281     
1282     /* Print the copyright notice: */
1283     if (is_tty())
1284     {
1285         NDRX_BANNER("");
1286     }
1287 
1288     /* Main command loop */
1289     while(EXSUCCEED==ret && have_next)
1290     {
1291         /* Get the command */
1292         if (EXFAIL==(ret = get_cmd(&have_next)))
1293         {
1294             NDRX_LOG(log_error, "Failed to get command!");
1295             ret=EXFAIL;
1296             goto out;
1297         }
1298         /* Now process command buffer */
1299         if (G_cmd_argc_raw > 0 &&
1300             EXSUCCEED!=process_command_buffer(&have_next) &&
1301                 /* stop processing if not tty or do not have next */
1302                 (!have_next || !isatty(0)))
1303         {
1304             ret=EXFAIL;
1305             goto out;
1306         }
1307         
1308     }
1309 
1310 out:
1311 
1312     if (need_init)
1313     {
1314         un_init(EXTRUE);
1315     }
1316 /*
1317     fprintf(stderr, "xadmin normal shutdown (%d)\n", ret);
1318 */
1319     return ret;
1320 }
1321 
1322 /* vim: set ts=4 sw=4 et smartindent: */