Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Implementation for start & stop commands.
0003  *
0004  * @file cmd_startstop.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 
0044 #include <ndrx.h>
0045 #include <ndrxdcmn.h>
0046 #include <atmi_int.h>
0047 #include <gencall.h>
0048 #include <nclopt.h>
0049 #include <lcfint.h>
0050 #include <singlegrp.h>
0051 
0052 /*---------------------------Externs------------------------------------*/
0053 /*---------------------------Macros-------------------------------------*/
0054 /*---------------------------Enums--------------------------------------*/
0055 /*---------------------------Typedefs-----------------------------------*/
0056 /*---------------------------Globals------------------------------------*/
0057 /*---------------------------Statics------------------------------------*/
0058 /*---------------------------Prototypes---------------------------------*/
0059 
0060 
0061 /**
0062  * Return process state in human understandable string.
0063  * @param state
0064  * @return static test from console output
0065  */
0066 exprivate char *proc_state_to_str(long state, short msg_type)
0067 {
0068     static char *started = "Started";
0069     static char *not_started = "Not started";
0070     static char *died = "Died";
0071     static char *shutdown = "Shutdown succeeded";
0072     static char *stopping = "Shutdown in progress";
0073     static char *nosuchfile = "No such file or directory";
0074     static char *eaccess = "Access denied";
0075     static char *ebadfile = "Bad executable";
0076     static char *elimits = "Limits exceeded";
0077     static char *stillstarting = "Still starting";
0078     static char *eargslim = "Cli args on env params too long";
0079     static char *eenv= "Environment setup failure";
0080     static char *esys= "System failure";
0081     static char *restart= "Restarting";
0082     static char *ewait= "Waiting on group lock";
0083     static char unknown[256];
0084     char *ret;
0085 
0086     switch (state)
0087     {
0088         case NDRXD_PM_NOT_STARTED:
0089             ret = not_started;
0090             break;
0091         case NDRXD_PM_RUNNING_OK:
0092             ret = started;
0093             break;
0094         case NDRXD_PM_DIED:
0095             ret = died;
0096             break;
0097         case NDRXD_PM_STARTING:
0098             ret = stillstarting;
0099             break;
0100         case NDRXD_PM_EXIT:
0101             /* Binaries might exit with fail at startup... */
0102             if (NDRXD_CALL_TYPE_PM_STOPPED==msg_type)
0103             {
0104                 ret = shutdown;
0105             }
0106             else
0107             {
0108                 ret = died;
0109             }   
0110             break;
0111         case NDRXD_PM_ENOENT:
0112             ret = nosuchfile;
0113             break;
0114         case NDRXD_PM_EACCESS:
0115             ret = eaccess;
0116             break;
0117         case NDRXD_PM_EBADFILE:
0118             ret = ebadfile;
0119             break;
0120         case NDRXD_PM_ELIMIT:
0121             ret = elimits;
0122             break;
0123         case NDRXD_PM_STOPPING:
0124             ret = stopping;
0125             break;
0126         case NDRXD_PM_EARGSLIM:
0127             ret = eargslim;
0128             break;
0129         case NDRXD_PM_EENV:
0130             ret = eenv;
0131             break;
0132         case NDRXD_PM_ESYSTEM:
0133             ret = esys;
0134             break;
0135         case NDRXD_PM_RESTART:
0136             ret = restart;
0137             break;
0138         case NDRXD_PM_WAIT:
0139             ret = ewait;
0140             break;
0141         default:
0142             snprintf(unknown, sizeof(unknown), "Unknown state (%ld)", state);
0143             ret = unknown;
0144             break;
0145     }
0146     
0147     return ret;
0148 }
0149 /**
0150  * Process response back.
0151  * @param reply
0152  * @param reply_len
0153  * @return
0154  */
0155 expublic int ss_rsp_process(command_reply_t *reply, size_t reply_len)
0156 {
0157     command_reply_pm_t * pm_info = (command_reply_pm_t*)reply;
0158 
0159     switch (reply->msg_type)
0160     {
0161         case NDRXD_CALL_TYPE_PM_STARTING:
0162             fprintf(stderr, "exec %s %s :\n\t",
0163                 pm_info->binary_name, pm_info->clopt);
0164             break;
0165         case NDRXD_CALL_TYPE_PM_STARTED:
0166             fprintf(stderr, "process id=%d ... %s.\n",pm_info->pid,
0167                 proc_state_to_str(pm_info->state, reply->msg_type)
0168                 );
0169             break;
0170         case NDRXD_CALL_TYPE_PM_STOPPING:
0171             fprintf(stderr, "Server executable = %s\tId = %d :\t",
0172                 pm_info->binary_name, pm_info->srvid);
0173             break;
0174         case  NDRXD_CALL_TYPE_PM_STOPPED:
0175             fprintf(stderr, "%s.\n",
0176                 proc_state_to_str(pm_info->state, reply->msg_type)
0177                 );
0178             break;
0179         case NDRXD_CALL_TYPE_GENERIC:
0180                 if (NDRXD_COM_STOP_RP==reply->command)
0181                     fprintf(stderr, "Shutdown finished. %ld processes stopped.\n",
0182                                     reply->userfld1);
0183                 else if (NDRXD_COM_SRELOAD_RP==reply->command)
0184                     fprintf(stderr, "Reload finished. %ld processes reloaded.\n",
0185                                     reply->userfld1);
0186                 else
0187                     fprintf(stderr, "Startup finished. %ld processes started.\n",
0188                                     reply->userfld1);
0189             break;
0190         default:
0191             NDRX_LOG(log_error, "Ignoring unknown message!");
0192             break;
0193     }
0194     return EXSUCCEED;
0195 }
0196 
0197 /**
0198  * Start application.
0199  * This uses feedback function to report progress..
0200  * @param p_cmd_map
0201  * @param argc
0202  * @param argv
0203  * @return SUCCEED
0204  */
0205 expublic int cmd_start(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0206 {
0207     int ret=EXSUCCEED;
0208     command_startstop_t call;
0209     short srvid=EXFAIL;
0210     char srvnm[MAXTIDENT+1]={EXEOS};
0211     char procgrp[MAXTIDENT+1]={EXEOS};
0212     short confirm = EXFALSE;
0213     short keep_running_ndrxd;
0214     int ids=0;
0215     short include_lp=EXFALSE;
0216 
0217     ncloptmap_t clopt[] =
0218     {
0219         {'i', BFLD_SHORT, (void *)&srvid, 0, 
0220                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server ID"},
0221         {'s', BFLD_STRING, (void *)srvnm, sizeof(srvnm), 
0222                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server name"},
0223         {'g', BFLD_STRING, (void *)procgrp, sizeof(procgrp), 
0224                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Process group"},
0225         {'L', BFLD_SHORT,  (void *)&include_lp, 0, 
0226                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, 
0227                                 "Include lock provider of the process group"},
0228         {'y', BFLD_SHORT, (void *)&confirm, 0, 
0229                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Confirm"},
0230         {'k', BFLD_SHORT, (void *)&keep_running_ndrxd, 0, 
0231                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Keep ndrxd running"},
0232         {0}
0233     };
0234         
0235     if (argc>=2 && '-'!=argv[1][0])
0236     {
0237         NDRX_STRCPY_SAFE(srvnm, argv[1]);
0238     }
0239     else
0240     {
0241         /* parse command line */
0242         if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0243         {
0244             fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0245             EXFAIL_OUT(ret);
0246         }
0247     }
0248     
0249     memset(&call, 0, sizeof(call));
0250 
0251     if (EXFAIL!=srvid)
0252     {
0253         ids++;
0254     }
0255 
0256     if (EXEOS!=srvnm[0])
0257     {
0258         ids++;
0259     }
0260 
0261     if (EXEOS!=procgrp[0])
0262     {
0263         ids++;
0264     }
0265 
0266     if (ids>1)
0267     {
0268         fprintf(stderr, "-i, -s and -g cannot be combined!\n");
0269         EXFAIL_OUT(ret);
0270     }
0271     
0272     /* ask for -y for -g too: */
0273     if (EXFAIL==srvid && EXEOS==srvnm[0] && EXEOS==procgrp[0] &&
0274           !ndrx_chk_confirm("Are you sure you want to start application?", confirm))
0275     {
0276         EXFAIL_OUT(ret);
0277     }
0278     
0279     /* prepare for call */
0280     call.srvid = srvid;
0281     NDRX_STRCPY_SAFE(call.binary_name, srvnm);
0282     NDRX_STRCPY_SAFE(call.procgrp, procgrp);
0283 
0284     if (include_lp)
0285     {
0286         call.flags|=NDRXD_CALL_FLAGS_LP2GRP;
0287     }
0288 
0289     ret=cmd_generic_listcall(p_cmd_map->ndrxd_cmd, NDRXD_SRC_ADMIN,
0290                         NDRXD_CALL_TYPE_GENERIC,
0291                         (command_call_t *)&call, sizeof(call),
0292                         G_config.reply_queue_str,
0293                         G_config.reply_queue,
0294                         G_config.ndrxd_q,
0295                         G_config.ndrxd_q_str,
0296                         argc, argv,
0297                         p_have_next,
0298                         G_call_args,
0299                         EXFALSE,
0300                         G_config.listcall_flags);
0301 out:
0302     return ret;
0303 }
0304 
0305 /**
0306  * Shutdown application server.
0307  * TODO: xadmin stop -i -1 makes stop to all domain!
0308  * If there was full shutdown, then we should disconnect from shared memory
0309  * resources too...
0310  * @param p_cmd_map
0311  * @param argc
0312  * @param argv
0313  * @param p_have_next
0314  * @return 
0315  */
0316 expublic int cmd_stop(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0317 {
0318     int ret=EXSUCCEED;
0319     command_startstop_t call;
0320     short srvid=EXFAIL;
0321     char srvnm[MAXTIDENT+1]={EXEOS};
0322     char procgrp[MAXTIDENT+1]={EXEOS};
0323     short confirm = EXFALSE;
0324     short keep_running_ndrxd = EXFALSE;
0325     short force_off = EXFALSE;  /* force shutdown (for malfunction/no pid instances) */
0326     short dummy;
0327     short keep_lcf=EXFALSE;
0328     pid_t pid = EXFAIL;
0329     int ids=0;
0330     short include_lp=EXFALSE;
0331 
0332     ncloptmap_t clopt[] =
0333     {
0334         {'i', BFLD_SHORT, (void *)&srvid, 0, 
0335                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server ID"},
0336         {'s', BFLD_STRING, (void *)srvnm, sizeof(srvnm), 
0337                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server name"},
0338         {'y', BFLD_SHORT, (void *)&confirm, 0, 
0339                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Confirm"},
0340         {'g', BFLD_STRING, (void *)procgrp, sizeof(procgrp), 
0341                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Process group"},
0342         {'L', BFLD_SHORT,  (void *)&include_lp, 0, 
0343                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, 
0344                                 "Include lock provider of the process group"},
0345         {'c', BFLD_SHORT, (void *)&dummy, 0, 
0346                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Left for compatibility"},
0347         {'k', BFLD_SHORT, (void *)&keep_running_ndrxd, 0, 
0348                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Keep ndrxd running"},
0349         {'f', BFLD_SHORT, (void *)&force_off, 0, 
0350                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Force shutdown"},
0351         {'l', BFLD_SHORT, (void *)&keep_lcf, 0, 
0352                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Keep lcf commands"},
0353 
0354         {0}
0355     };
0356         
0357     if (argc>=2 && '-'!=argv[1][0])
0358     {
0359         NDRX_STRCPY_SAFE(srvnm, argv[1]);
0360     }
0361     else
0362     {
0363         /* parse command line */
0364         if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0365         {
0366             fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0367             EXFAIL_OUT(ret);
0368         }
0369     }
0370     
0371     memset(&call, 0, sizeof(call));
0372     
0373     if (EXFAIL!=srvid)
0374     {
0375         ids++;
0376     }
0377 
0378     if (EXEOS!=srvnm[0])
0379     {
0380         ids++;
0381     }
0382 
0383     if (EXEOS!=procgrp[0])
0384     {
0385         ids++;
0386     }
0387 
0388     if (ids>1)
0389     {
0390         fprintf(stderr, "-i, -s and -g cannot be combined!\n");
0391         EXFAIL_OUT(ret);
0392     }
0393     
0394     if (EXFAIL!=srvid || EXEOS!=srvnm[0] || EXEOS!=procgrp[0])
0395     {
0396         keep_running_ndrxd = EXTRUE;
0397     }
0398     
0399     if (EXFAIL==srvid && EXEOS==srvnm[0] && EXEOS==procgrp[0] &&
0400           !ndrx_chk_confirm("Are you sure you want to stop application?", confirm))
0401     {
0402         EXFAIL_OUT(ret);
0403     }
0404     
0405     /* prepare for call */
0406     if (keep_running_ndrxd)
0407     {
0408         call.complete_shutdown = EXFALSE;
0409     }
0410     else
0411     {
0412         /* do full shutdown by default */
0413         call.complete_shutdown = EXTRUE;
0414     }
0415     
0416     if (call.complete_shutdown && !is_ndrxd_running(&pid, EXFALSE) && !force_off)
0417     {
0418         fprintf(stderr, "WARNING ! `ndrxd' daemon is in `%s', use -f "
0419                 "to force shutdown!\n",
0420                 NDRXD_STAT_NOT_STARTED==G_config.ndrxd_stat?"not started":"malfunction");
0421 
0422         NDRX_LOG(log_warn, "WARNING ! `ndrxd' daemon is in `%s' state, use -f "
0423                 "to force shutdown!\n",
0424                 NDRXD_STAT_NOT_STARTED==G_config.ndrxd_stat?"not started":"malfunction");
0425         EXFAIL_OUT(ret);
0426     }
0427     
0428     call.srvid = srvid;
0429     NDRX_STRCPY_SAFE(call.binary_name, srvnm);
0430     NDRX_STRCPY_SAFE(call.procgrp, procgrp);
0431     if (include_lp)
0432     {
0433         call.flags|=NDRXD_CALL_FLAGS_LP2GRP;
0434     }
0435 
0436     ret=cmd_generic_listcall(p_cmd_map->ndrxd_cmd, NDRXD_SRC_ADMIN,
0437                     NDRXD_CALL_TYPE_GENERIC,
0438                     (command_call_t *)&call, sizeof(call),
0439                     G_config.reply_queue_str,
0440                     G_config.reply_queue,
0441                     G_config.ndrxd_q,
0442                     G_config.ndrxd_q_str,
0443                     argc, argv,
0444                     p_have_next,
0445                     G_call_args,
0446                     EXFALSE,
0447                     G_config.listcall_flags);
0448     
0449     /* Do not wait in case if sending was not successful */
0450     if (call.complete_shutdown && (EXSUCCEED==ret || force_off))
0451     {
0452         NDRX_LOG(log_debug, "About to un-init after shutdown");
0453         un_init(EXTRUE);
0454         NDRX_LOG(log_debug, "Un-init completed (after shutdown)");
0455         /* TODO: 
0456          * how about some sleep here to allow the ndrxd to kill shared resources
0457          * before user might want to move forward with next commands which open
0458          * shm resources. Thus we can get some race conditions here.
0459          * Maybe monitor until the all resources are unlinked...
0460          * or at least pid is dead.
0461          */
0462         
0463         if (EXFAIL!=pid)
0464         {
0465             /* monitor the pid */
0466             while (EXSUCCEED==kill(pid, 0))
0467             {
0468                 /* have some usleep -> for aix needs to check sigchilds... */
0469                 usleep(100000);
0470                 /* zap any childs..
0471                 sign_chld_handler(0);*/
0472             }
0473             /* shutdown is ok */
0474             ret = EXSUCCEED;
0475         }
0476         else
0477         {
0478             /* no info of pid, so have some sleep */
0479             sleep(1);
0480         }
0481         
0482         /* 
0483          * clean up the commands... 
0484          */
0485         if (!keep_lcf)
0486         {
0487             ndrx_lcf_reset();
0488         }
0489 
0490         /* Reset all singlegrp infos */
0491         ndrx_sg_reset();
0492     }
0493 
0494 out:
0495     return ret;
0496 }
0497 
0498 /**
0499  * restart app or server.
0500  * Invokes stop & start in sequence.
0501  * @param p_cmd_map
0502  * @param argc
0503  * @param argv
0504  * @param p_have_next
0505  * @return 
0506  */
0507 expublic int cmd_r(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0508 {
0509     int ret=EXSUCCEED;
0510     short srvid=EXFAIL;
0511     char srvnm[MAXTIDENT+1]={EXEOS};
0512     char procgrp[MAXTIDENT+1]={EXEOS};
0513     short confirm = EXFALSE;
0514     short keep_running_ndrxd = EXFALSE;
0515     int ids=0;
0516     short include_lp=EXFALSE;
0517 
0518     /* just verify that content is ok: */
0519     ncloptmap_t clopt[] =
0520     {
0521         {'i', BFLD_SHORT, (void *)&srvid, 0, 
0522                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server ID"},
0523         {'s', BFLD_STRING, (void *)srvnm, sizeof(srvnm), 
0524                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server name"},
0525         {'g', BFLD_STRING, (void *)procgrp, sizeof(procgrp), 
0526                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Process group"},
0527         {'L', BFLD_SHORT,  (void *)&include_lp, 0, 
0528                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, 
0529                                 "Include lock provider of the process group"},
0530         {'y', BFLD_SHORT, (void *)&confirm, 0, 
0531                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Confirm"},
0532         {'k', BFLD_SHORT, (void *)&keep_running_ndrxd, 0, 
0533                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Keep ndrxd running"},
0534         {0}
0535     };
0536         
0537     if (argc>=2 && '-'!=argv[1][0])
0538     {
0539         NDRX_STRCPY_SAFE(srvnm, argv[1]);
0540     }
0541     else
0542     {
0543         /* parse command line */
0544         if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0545         {
0546             fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0547             EXFAIL_OUT(ret);
0548         }
0549     }
0550     
0551     NDRX_LOG(log_info, "Shutting down...");
0552     strcpy(argv[0], "stop");
0553     if (EXSUCCEED==(ret=process_command_buffer(EXFALSE)))
0554     {
0555         if (!keep_running_ndrxd && EXEOS==srvnm[0] && EXFAIL==srvid)
0556         {
0557             sleep(2);
0558         }
0559         NDRX_LOG(log_debug, "Starting up...");
0560         strcpy(argv[0], "start"); 
0561         ret=process_command_buffer(EXFALSE);
0562     }
0563     
0564 out:
0565     return ret;
0566 }
0567 
0568 
0569 
0570 /**
0571  * Abort app domain startup or shutdown.
0572  * @param p_cmd_map
0573  * @param argc
0574  * @param argv
0575  * @return SUCCEED
0576  */
0577 expublic int cmd_cabort(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0578 {
0579     command_call_t call;
0580     memset(&call, 0, sizeof(call));
0581     int ret=EXSUCCEED;
0582 
0583     if (!chk_confirm_clopt("Are you sure you want to abort app domain start/stop?", argc, argv))
0584     {
0585         ret=EXFAIL;
0586         goto out;
0587     }
0588 
0589     ret=cmd_generic_listcall(p_cmd_map->ndrxd_cmd, NDRXD_SRC_ADMIN,
0590                         NDRXD_CALL_TYPE_GENERIC,
0591                         &call, sizeof(call),
0592                         G_config.reply_queue_str,
0593                         G_config.reply_queue,
0594                         G_config.ndrxd_q,
0595                         G_config.ndrxd_q_str,
0596                         argc, argv,
0597                         p_have_next,
0598                         G_call_args,
0599                         EXFALSE,
0600                         G_config.listcall_flags);
0601 out:
0602     return ret;
0603 }
0604 
0605 
0606 /**
0607  * Reload services (sequental service restart)
0608  * @param p_cmd_map
0609  * @param argc
0610  * @param argv
0611  * @return SUCCEED
0612  */
0613 expublic int cmd_sreload(cmd_mapping_t *p_cmd_map, int argc, char **argv, int *p_have_next)
0614 {
0615     int ret=EXSUCCEED;
0616     command_startstop_t call;
0617     short srvid=EXFAIL;
0618     char srvnm[MAXTIDENT+1]={EXEOS};
0619     char procgrp[MAXTIDENT+1]={EXEOS};
0620     short confirm = EXFALSE;
0621     int ids=0;
0622     short include_lp=EXFALSE;
0623     ncloptmap_t clopt[] =
0624     {
0625         {'i', BFLD_SHORT, (void *)&srvid, 0, 
0626                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server ID"},
0627         {'s', BFLD_STRING, (void *)srvnm, sizeof(srvnm), 
0628                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Server name"},
0629         {'g', BFLD_STRING, (void *)procgrp, sizeof(procgrp), 
0630                                 NCLOPT_OPT|NCLOPT_HAVE_VALUE, "Process group"},
0631         {'L', BFLD_SHORT,  (void *)&include_lp, 0, 
0632                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, 
0633                                 "Include lock provider of the process group"},
0634         {'y', BFLD_SHORT, (void *)&confirm, 0, 
0635                                 NCLOPT_OPT|NCLOPT_TRUEBOOL, "Confirm"},
0636         {0}
0637     };
0638         
0639     if (argc>=2 && '-'!=argv[1][0])
0640     {
0641         NDRX_STRCPY_SAFE(srvnm, argv[1]);
0642     }
0643     else
0644     {
0645         /* parse command line */
0646         if (nstd_parse_clopt(clopt, EXTRUE,  argc, argv, EXFALSE))
0647         {
0648             fprintf(stderr, XADMIN_INVALID_OPTIONS_MSG);
0649             EXFAIL_OUT(ret);
0650         }
0651     }
0652     
0653     memset(&call, 0, sizeof(call));
0654     
0655     if (EXFAIL!=srvid)
0656     {
0657         ids++;
0658     }
0659 
0660     if (EXEOS!=srvnm[0])
0661     {
0662         ids++;
0663     }
0664 
0665     if (EXEOS!=procgrp[0])
0666     {
0667         ids++;
0668     }
0669 
0670     if (ids>1)
0671     {
0672         fprintf(stderr, "-i, -s and -g cannot be combined!\n");
0673         EXFAIL_OUT(ret);
0674     }
0675     
0676     if (EXFAIL==srvid && EXEOS==srvnm[0] && EXEOS==procgrp[0] &&
0677           !ndrx_chk_confirm("Are you sure you want to start application?", confirm))
0678     {
0679         EXFAIL_OUT(ret);
0680     }
0681     
0682     /* prepare for call */
0683     call.srvid = srvid;
0684     NDRX_STRCPY_SAFE(call.binary_name, srvnm);
0685     NDRX_STRCPY_SAFE(call.procgrp, procgrp);
0686 
0687     if (include_lp)
0688     {
0689         call.flags|=NDRXD_CALL_FLAGS_LP2GRP;
0690     }
0691 
0692     ret=cmd_generic_listcall(p_cmd_map->ndrxd_cmd, NDRXD_SRC_ADMIN,
0693                         NDRXD_CALL_TYPE_GENERIC,
0694                         (command_call_t *)&call, sizeof(call),
0695                         G_config.reply_queue_str,
0696                         G_config.reply_queue,
0697                         G_config.ndrxd_q,
0698                         G_config.ndrxd_q_str,
0699                         argc, argv,
0700                         p_have_next,
0701                         G_call_args,
0702                         EXFALSE,
0703                         G_config.listcall_flags);
0704 out:
0705     return ret;
0706 }
0707 /* vim: set ts=4 sw=4 et smartindent: */