0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
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 <sys_mqueue.h>
0040 #include <sys/resource.h>
0041 #include <sys/wait.h>
0042 #include <libxml/xmlreader.h>
0043 #include <errno.h>
0044 #include <signal.h>
0045 #include <unistd.h>
0046 #include <sys/stat.h>
0047 #include <sys/types.h>
0048 #include <fcntl.h>
0049
0050 #include <ndrstandard.h>
0051 #include <userlog.h>
0052 #include <atmi.h>
0053 #include <libndrxconf.h>
0054 #include <ndrxdiag.h>
0055
0056 #include "cpmsrv.h"
0057 #include "../libatmisrv/srv_int.h"
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069 #define LOCKED_DEBUG(lev, fmt, ...) MUTEX_LOCK_V(M_forklock);\
0070 NDRX_LOG(lev, fmt, ##__VA_ARGS__);\
0071 MUTEX_UNLOCK_V(M_forklock);
0072
0073
0074
0075
0076
0077 exprivate pthread_t M_signal_thread;
0078 exprivate int M_signal_thread_set = EXFALSE;
0079 exprivate MUTEX_LOCKDECL(M_forklock);
0080 exprivate volatile int M_shutdown = EXFALSE;
0081
0082
0083
0084
0085
0086
0087 exprivate void handle_child(pid_t chldpid, int stat_loc)
0088 {
0089 cpm_process_t * c = cpm_get_client_by_pid(chldpid);
0090
0091
0092
0093
0094
0095 cpm_lock_config();
0096
0097 if (NULL!=c)
0098 {
0099 c->dyn.cur_state = CLT_STATE_NOTRUN;
0100
0101
0102
0103
0104 MUTEX_LOCK_V(M_forklock);
0105
0106 ndrx_cltshm_setpos(c->key, EXFAIL, NDRX_CPM_MAP_WASUSED, NULL);
0107
0108 c->dyn.exit_status = stat_loc;
0109
0110
0111 cpm_set_cur_time(c);
0112 MUTEX_UNLOCK_V(M_forklock);
0113 }
0114
0115 cpm_unlock_config();
0116 }
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128 exprivate void * check_child_exit(void *arg)
0129 {
0130 pid_t chldpid;
0131 int stat_loc;
0132 sigset_t blockMask;
0133 int sig;
0134 struct rusage rusage;
0135 int old;
0136
0137 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old);
0138
0139 sigemptyset(&blockMask);
0140 sigaddset(&blockMask, SIGCHLD);
0141
0142 LOCKED_DEBUG(log_debug, "check_child_exit - enter...");
0143 while (!M_shutdown)
0144 {
0145
0146
0147
0148 #if !(EX_OS_DARWIN && EX_LSB_RELEASE_VER_MAJOR<23)
0149 LOCKED_DEBUG(log_debug, "about to sigwait()");
0150
0151
0152 if (EXSUCCEED!=sigwait(&blockMask, &sig))
0153 {
0154 LOCKED_DEBUG(log_warn, "sigwait failed:(%s)", strerror(errno));
0155
0156 }
0157 #endif
0158
0159 if (M_shutdown)
0160 {
0161 break;
0162 }
0163
0164 LOCKED_DEBUG(log_debug, "about to wait()");
0165
0166 #if (EX_OS_DARWIN && EX_LSB_RELEASE_VER_MAJOR<23)
0167
0168
0169
0170 while (1)
0171 {
0172 chldpid = (pid_t)waitpid(-1, &stat_loc, WUNTRACED);
0173 int err;
0174
0175 if (EXFAIL==chldpid)
0176 {
0177 if (err!=ECHILD)
0178 {
0179 userlog("waitpid failed: %s", tpstrerror(err));
0180 }
0181 sleep(1);
0182 }
0183 else
0184 {
0185 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old);
0186 handle_child(chldpid, stat_loc);
0187 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
0188 }
0189 }
0190 #else
0191 while ((chldpid = wait3(&stat_loc, WNOHANG|WUNTRACED, &rusage)) > 0)
0192 {
0193 handle_child(chldpid, stat_loc);
0194 }
0195 #endif
0196
0197 }
0198
0199 LOCKED_DEBUG(log_debug, "check_child_exit terminated");
0200
0201 return NULL;
0202 }
0203
0204
0205
0206
0207
0208
0209 expublic int cpm_sigchld_init(void)
0210 {
0211 int ret = EXSUCCEED;
0212 pthread_attr_t pthread_custom_attr;
0213 char *fn = "cpm_sigchld_init";
0214
0215 NDRX_LOG(log_debug, "%s - enter", fn);
0216
0217 pthread_attr_init(&pthread_custom_attr);
0218
0219
0220 ndrx_platf_stack_set(&pthread_custom_attr);
0221 if (EXSUCCEED!=pthread_create(&M_signal_thread, &pthread_custom_attr,
0222 check_child_exit, NULL))
0223 {
0224 NDRX_PLATF_DIAG(NDRX_DIAG_PTHREAD_CREATE, errno, "cpm_sigchld_init");
0225 EXFAIL_OUT(ret);
0226 }
0227
0228 M_signal_thread_set = EXTRUE;
0229 out:
0230 return ret;
0231 }
0232
0233
0234
0235
0236
0237
0238 expublic void cpm_sigchld_uninit(void)
0239 {
0240 char *fn = "cpm_sigchld_uninit";
0241 int err;
0242 NDRX_LOG(log_debug, "%s - enter", fn);
0243
0244 if (!M_signal_thread_set)
0245 {
0246 NDRX_LOG(log_debug, "Signal thread was not initialised, nothing todo...");
0247 goto out;
0248 }
0249
0250
0251 NDRX_LOG(log_debug, "About to cancel signal thread");
0252
0253
0254
0255
0256 M_shutdown = EXTRUE;
0257
0258 #if (EX_OS_DARWIN && EX_LSB_RELEASE_VER_MAJOR<23)
0259 if (EXSUCCEED!=pthread_cancel(M_signal_thread))
0260 {
0261 NDRX_LOG(log_error, "Failed to kill poll signal thread: %s", strerror(errno));
0262 }
0263 #else
0264 if (EXSUCCEED!=(err=pthread_kill(M_signal_thread, SIGCHLD)))
0265 {
0266 NDRX_LOG(log_error, "Failed to kill poll signal thread: %s", strerror(err));
0267 }
0268 #endif
0269 else
0270 {
0271 if (EXSUCCEED!=pthread_join(M_signal_thread, NULL))
0272 {
0273 NDRX_LOG(log_error, "Failed to join pthread_join() signal thread: %s",
0274 strerror(errno));
0275 }
0276 }
0277
0278 M_signal_thread_set = EXFALSE;
0279 NDRX_LOG(log_debug, "finished ok");
0280 out:
0281 return;
0282 }
0283
0284
0285
0286
0287
0288
0289 expublic void cpm_pidtest(cpm_process_t *c, int *sg_groups)
0290 {
0291
0292
0293
0294 if (NULL!=sg_groups
0295 && c->stat.procgrp_no>0
0296 && ndrx_ndrxconf_procgroups_is_singleton(ndrx_G_procgroups_config,
0297 c->stat.procgrp_no)
0298 && !sg_groups[c->stat.procgrp_no-1] &&
0299 CLT_STATE_STARTED==c->dyn.cur_state)
0300 {
0301 NDRX_LOG(log_error, "Singleton process group %d lock lost for "
0302 "%s/%s pid %d, killing immediatelly",
0303 c->stat.procgrp_no, c->tag, c->subsect, (int)c->dyn.pid);
0304 kill(c->dyn.pid, SIGKILL);
0305 }
0306
0307 if (CLT_STATE_STARTED==c->dyn.cur_state && c->dyn.shm_read)
0308 {
0309
0310
0311
0312
0313
0314 if (!ndrx_sys_is_process_running_by_pid(c->dyn.pid))
0315 {
0316 NDRX_LOG(log_info, "Process [%s]/%d exited by pid test",
0317 c->stat.command_line, (int)c->dyn.pid);
0318
0319 ndrx_cltshm_setpos(c->key, EXFAIL, NDRX_CPM_MAP_WASUSED, NULL);
0320
0321 if (CLT_STATE_NOTRUN==c->dyn.req_state )
0322 {
0323 c->dyn.exit_status = 0;
0324 }
0325 else
0326 {
0327 c->dyn.exit_status = EXFAIL;
0328 }
0329
0330 c->dyn.cur_state = CLT_STATE_NOTRUN;
0331
0332
0333 cpm_set_cur_time(c);
0334 }
0335 }
0336 }
0337
0338
0339
0340
0341
0342 expublic int cpm_killall(void)
0343 {
0344 int ret = EXSUCCEED;
0345 cpm_process_t *c = NULL, *ct = NULL;
0346 int is_any_running;
0347 ndrx_stopwatch_t t;
0348 char *sig_str[3]={"SIGINT","SIGTERM", "SIGKILL"};
0349 int sig[3]={SIGINT,SIGTERM, SIGKILL};
0350 int i;
0351 int was_chld_kill;
0352 string_list_t* cltchildren = NULL;
0353
0354 for (i=0; i<3; i++)
0355 {
0356 NDRX_LOG(log_warn, "Terminating all with %s", sig_str[i]);
0357
0358 EXHASH_ITER(hh, G_clt_config, c, ct)
0359 {
0360
0361
0362
0363 cpm_pidtest(c, NULL);
0364
0365 if (CLT_STATE_STARTED==c->dyn.cur_state)
0366 {
0367 NDRX_LOG(log_warn, "Killing: %s/%s/%d with %s",
0368 c->tag, c->subsect, c->dyn.pid, sig_str[i]);
0369
0370
0371
0372
0373
0374 was_chld_kill = EXFALSE;
0375 if ((SIGKILL==sig[i] && (c->stat.flags & CPM_F_KILL_LEVEL_LOW)) ||
0376 c->stat.flags & CPM_F_KILL_LEVEL_HIGH)
0377 {
0378 was_chld_kill = EXTRUE;
0379 ndrx_proc_children_get_recursive(&cltchildren, c->dyn.pid);
0380 }
0381
0382 kill(c->dyn.pid, sig[i]);
0383
0384 if (was_chld_kill)
0385 {
0386 ndrx_proc_kill_list(cltchildren);
0387 ndrx_string_list_free(cltchildren);
0388 cltchildren=NULL;
0389 }
0390 }
0391 }
0392
0393 if (i<2)
0394 {
0395
0396 ndrx_stopwatch_reset(&t);
0397 do
0398 {
0399 is_any_running = EXFALSE;
0400 EXHASH_ITER(hh, G_clt_config, c, ct)
0401 {
0402 if (CLT_STATE_STARTED==c->dyn.cur_state)
0403 {
0404 is_any_running = EXTRUE;
0405 break;
0406 }
0407 }
0408
0409 if (is_any_running)
0410 {
0411 usleep(CLT_STEP_INTERVAL_ALL);
0412 }
0413 }
0414 while (is_any_running &&
0415 ndrx_stopwatch_get_delta_sec(&t) < G_config.kill_interval);
0416 }
0417 }
0418
0419 NDRX_LOG(log_debug, "cpm_killall done");
0420 return EXSUCCEED;
0421 }
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 expublic int cpm_kill(cpm_process_t *c)
0432 {
0433 int ret = EXSUCCEED;
0434 ndrx_stopwatch_t t;
0435 string_list_t* cltchildren = NULL;
0436
0437 NDRX_LOG(log_warn, "Stopping %s/%s - %s", c->tag, c->subsect, c->stat.command_line);
0438
0439
0440 if (c->stat.flags & CPM_F_KILL_LEVEL_HIGH)
0441 {
0442 ndrx_proc_children_get_recursive(&cltchildren, c->dyn.pid);
0443 }
0444
0445 kill(c->dyn.pid, SIGINT);
0446
0447 if (c->stat.flags & CPM_F_KILL_LEVEL_HIGH)
0448 {
0449 ndrx_proc_kill_list(cltchildren);
0450 ndrx_string_list_free(cltchildren);
0451 cltchildren=NULL;
0452 }
0453
0454 ndrx_stopwatch_reset(&t);
0455 do
0456 {
0457 if (CLT_STATE_STARTED==c->dyn.cur_state)
0458 {
0459 usleep(CLT_STEP_INTERVAL);
0460 }
0461 } while (CLT_STATE_STARTED==c->dyn.cur_state &&
0462 ndrx_stopwatch_get_delta_sec(&t) < G_config.kill_interval);
0463
0464 if (CLT_STATE_STARTED!=c->dyn.cur_state)
0465 goto out;
0466
0467 NDRX_LOG(log_warn, "%s/%s Did not react on SIGINT, continue with SIGTERM",
0468 c->tag, c->subsect);
0469
0470
0471 if (c->stat.flags & CPM_F_KILL_LEVEL_HIGH)
0472 {
0473 ndrx_proc_children_get_recursive(&cltchildren, c->dyn.pid);
0474 }
0475
0476 kill(c->dyn.pid, SIGTERM);
0477
0478 if (c->stat.flags & CPM_F_KILL_LEVEL_HIGH)
0479 {
0480 ndrx_proc_kill_list(cltchildren);
0481 ndrx_string_list_free(cltchildren);
0482 cltchildren=NULL;
0483 }
0484
0485
0486 ndrx_stopwatch_reset(&t);
0487 do
0488 {
0489
0490
0491 cpm_pidtest(c, NULL);
0492 if (CLT_STATE_STARTED==c->dyn.cur_state)
0493 {
0494 usleep(CLT_STEP_INTERVAL);
0495 }
0496 } while (CLT_STATE_STARTED==c->dyn.cur_state &&
0497 ndrx_stopwatch_get_delta_sec(&t) < G_config.kill_interval);
0498
0499 if (CLT_STATE_STARTED!=c->dyn.cur_state)
0500 goto out;
0501
0502 NDRX_LOG(log_warn, "%s/%s Did not react on SIGTERM, kill with -9",
0503 c->tag, c->subsect);
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513 if (c->stat.flags & CPM_F_KILL_LEVEL_LOW)
0514 {
0515 ndrx_proc_children_get_recursive(&cltchildren, c->dyn.pid);
0516 }
0517
0518 kill(c->dyn.pid, SIGKILL);
0519
0520 if (c->stat.flags & CPM_F_KILL_LEVEL_LOW)
0521 {
0522 ndrx_proc_kill_list(cltchildren);
0523 ndrx_string_list_free(cltchildren);
0524 cltchildren=NULL;
0525 }
0526
0527 ndrx_stopwatch_reset(&t);
0528 do
0529 {
0530 if (CLT_STATE_STARTED==c->dyn.cur_state)
0531 {
0532 usleep(CLT_STEP_INTERVAL);
0533
0534 }
0535 }
0536 while (CLT_STATE_STARTED==c->dyn.cur_state &&
0537 ndrx_stopwatch_get_delta_sec(&t) < G_config.kill_interval);
0538
0539 if (CLT_STATE_STARTED!=c->dyn.cur_state)
0540 goto out;
0541
0542 NDRX_LOG(log_warn, "%s/%s Did not react on SIGKILL, giving up...",
0543 c->tag, c->subsect);
0544
0545 out:
0546 return ret;
0547 }
0548
0549
0550
0551
0552
0553
0554 expublic int cpm_exec(cpm_process_t *c)
0555 {
0556 pid_t pid;
0557 char cmd_str[PATH_MAX];
0558 char *cmd[PATH_MAX];
0559 char *token;
0560 int numargs = 0;
0561 int fd_stdout;
0562 int fd_stderr;
0563 int fd;
0564 int ret = EXSUCCEED;
0565 char tmp[256];
0566
0567 NDRX_LOG(log_warn, "*********processing for startup %s *********",
0568 c->stat.command_line);
0569
0570 c->dyn.was_started = EXTRUE;
0571 c->dyn.shm_read = EXFALSE;
0572
0573 MUTEX_LOCK_V(M_forklock);
0574 pid = ndrx_fork();
0575
0576
0577
0578
0579 if( pid == 0)
0580 {
0581
0582
0583
0584
0585
0586 signal(SIGCHLD, SIG_DFL);
0587
0588
0589 usleep(9000);
0590
0591
0592
0593
0594 unsetenv(CONF_NDRX_SVPROCNAME);
0595 unsetenv(CONF_NDRX_SVCLOPT);
0596 unsetenv(CONF_NDRX_SVPPID);
0597 unsetenv(CONF_NDRX_SVSRVID);
0598
0599
0600
0601
0602 if (EXSUCCEED!=setenv(NDRX_CLTTAG, c->tag, EXTRUE))
0603 {
0604 NDRX_LOG(log_error, "Cannot set [%s] to [%s]: %s",
0605 NDRX_CLTTAG, c->tag, strerror(errno));
0606 userlog("Cannot set [%s] to [%s]: %s",
0607 NDRX_CLTTAG, c->tag, strerror(errno));
0608 exit(1);
0609 }
0610
0611
0612 if (EXSUCCEED!=setenv(NDRX_CLTSUBSECT, c->subsect, EXTRUE))
0613 {
0614 NDRX_LOG(log_error, "Cannot set [%s] to [%s]: %s",
0615 NDRX_CLTSUBSECT, c->subsect, strerror(errno));
0616 userlog("Cannot set [%s] to [%s]: %s",
0617 NDRX_CLTSUBSECT, c->subsect, strerror(errno));
0618 exit(1);
0619 }
0620
0621 if (c->stat.procgrp_no > 0)
0622 {
0623 snprintf(tmp, sizeof(tmp), "%d", c->stat.procgrp_no);
0624 if (EXSUCCEED!=setenv(CONF_NDRX_PROCGRP_NO, tmp, EXTRUE))
0625 {
0626 NDRX_LOG(log_error, "Cannot set [%s] to [%s]: %s",
0627 CONF_NDRX_PROCGRP_NO, c->tag, strerror(errno));
0628 userlog("Cannot set [%s] to [%s]: %s",
0629 CONF_NDRX_PROCGRP_NO, c->tag, strerror(errno));
0630 exit(1);
0631 }
0632 }
0633
0634 NDRX_STRCPY_SAFE(cmd_str, c->stat.command_line);
0635
0636 token = ndrx_strtokblk(cmd_str, NDRX_CMDLINE_SEP, NDRX_CMDLINE_QUOTES);
0637 while( token != NULL )
0638 {
0639 cmd[numargs] = token;
0640 token = ndrx_strtokblk( NULL, NDRX_CMDLINE_SEP, NDRX_CMDLINE_QUOTES);
0641 numargs++;
0642 }
0643 cmd[numargs] = NULL;
0644
0645
0646 if (EXEOS!=c->stat.env[0])
0647 {
0648 if (EXSUCCEED!=ndrx_load_new_env(c->stat.env))
0649 {
0650 userlog("Failed to load custom env from: %s!", c->stat.env);
0651 exit(1);
0652 }
0653 }
0654
0655 if (EXEOS!=c->stat.cctag[0])
0656 {
0657 if (EXSUCCEED!=setenv(NDRX_CCTAG, c->stat.cctag, EXTRUE))
0658 {
0659 userlog("Cannot set [%s] to [%s]: %s",
0660 NDRX_CCTAG, c->stat.cctag, strerror(errno));
0661 exit(1);
0662 }
0663 }
0664
0665
0666 if (EXSUCCEED!=ndrx_ndrxconf_envs_apply(c->stat.envs))
0667 {
0668 userlog("Cannot load XML env for %s/%s: %s",
0669 NDRX_CCTAG, c->tag,c->subsect, strerror(errno));
0670 exit(1);
0671 }
0672
0673
0674 if (EXEOS!=c->stat.wd[0])
0675 {
0676 if (EXSUCCEED!=chdir(c->stat.wd))
0677 {
0678 int err = errno;
0679
0680 NDRX_LOG(log_error, "Failed to change working diretory: %s - %s!",
0681 c->stat.wd, strerror(err));
0682 userlog("Failed to change working diretory: %s - %s!",
0683 c->stat.wd, strerror(err));
0684 exit(1);
0685 }
0686 }
0687
0688
0689 if (EXEOS!=c->stat.log_stdout[0] &&
0690 EXFAIL!=(fd_stdout = open(c->stat.log_stdout,
0691 O_WRONLY| O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)))
0692 {
0693 dup2(fd_stdout, 1);
0694 close(fd_stdout);
0695 }
0696
0697 if (EXEOS!=c->stat.log_stderr[0] &&
0698 EXFAIL!=(fd_stderr = open(c->stat.log_stderr,
0699 O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)))
0700 {
0701 dup2(fd_stderr, 2);
0702 close(fd_stderr);
0703 }
0704
0705
0706 if (EXFAIL!=(fd = open("/dev/null", O_RDWR)))
0707 {
0708 dup2(fd, 0);
0709 close(fd);
0710 }
0711
0712 if (EXEOS!=c->stat.log_stderr[0] && EXSUCCEED!=setenv(CONF_NDRX_DFLTLOG,
0713 c->stat.log_stderr, EXTRUE))
0714 {
0715 userlog("Failed to set client [%s] env: %s", CONF_NDRX_DFLTLOG, strerror(errno));
0716 }
0717
0718
0719
0720
0721
0722
0723 signal(SIGINT, SIG_DFL);
0724 signal(SIGTERM, SIG_DFL);
0725
0726 if (EXSUCCEED != execvp (cmd[0], cmd))
0727 {
0728 int err = errno;
0729 NDRX_LOG(log_error, "Failed to start client, error: %d, %s",
0730 err, strerror(err));
0731 exit (err);
0732 }
0733 }
0734 else if (EXFAIL!=pid)
0735 {
0736 MUTEX_UNLOCK_V(M_forklock);
0737 cpm_set_cur_time(c);
0738 c->dyn.pid = pid;
0739 c->dyn.cur_state = CLT_STATE_STARTED;
0740
0741
0742
0743
0744 if (EXSUCCEED!=ndrx_cltshm_setpos(c->key, c->dyn.pid,
0745 NDRX_CPM_MAP_ISUSED|NDRX_CPM_MAP_WASUSED|NDRX_CPM_MAP_CPMPROC,
0746 c->stat.procname))
0747 {
0748 NDRX_LOG(log_error, "Failed to register client in CPM SHM/mem full, check %s param",
0749 CONF_NDRX_CLTMAX);
0750 userlog("Failed to register client in CPM SHM/mem full, check %s param",
0751 CONF_NDRX_CLTMAX);
0752 }
0753 }
0754 else
0755 {
0756 MUTEX_UNLOCK_V(M_forklock);
0757 userlog("Failed to fork: %s", strerror(errno));
0758 }
0759
0760 out:
0761 return ret;
0762 }
0763