Process.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:12k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include <ndb_global.h>
  14. #include <BaseString.hpp>
  15. #include <InputStream.hpp>
  16. #include "common.hpp"
  17. #include "CPCD.hpp"
  18. #include <pwd.h>
  19. #ifdef HAVE_GETRLIMIT
  20. #include <sys/resource.h>
  21. #endif
  22. void
  23. CPCD::Process::print(FILE * f){
  24.   fprintf(f, "define processn");
  25.   fprintf(f, "id: %dn",    m_id);
  26.   fprintf(f, "name: %sn",  m_name.c_str()  ? m_name.c_str()  : "");
  27.   fprintf(f, "group: %sn", m_group.c_str() ? m_group.c_str() : "");
  28.   fprintf(f, "env: %sn",   m_env.c_str()   ? m_env.c_str()   : "");
  29.   fprintf(f, "path: %sn",  m_path.c_str()  ? m_path.c_str()  : "");
  30.   fprintf(f, "args: %sn",  m_args.c_str()  ? m_args.c_str()  : "");
  31.   fprintf(f, "type: %sn",  m_type.c_str()  ? m_type.c_str()  : "");
  32.   fprintf(f, "cwd: %sn",   m_cwd.c_str()   ? m_cwd.c_str()   : "");
  33.   fprintf(f, "owner: %sn", m_owner.c_str() ? m_owner.c_str() : "");
  34.   fprintf(f, "runas: %sn", m_runas.c_str() ? m_runas.c_str() : "");
  35.   fprintf(f, "stdin: %sn", m_stdin.c_str() ? m_stdin.c_str() : "");
  36.   fprintf(f, "stdout: %sn", m_stdout.c_str() ? m_stdout.c_str() : "");
  37.   fprintf(f, "stderr: %sn", m_stderr.c_str() ? m_stderr.c_str() : "");
  38.   fprintf(f, "ulimit: %sn", m_ulimit.c_str() ? m_ulimit.c_str() : "");
  39.   fprintf(f, "shutdown: %sn", m_shutdown_options.c_str() ? 
  40.   m_shutdown_options.c_str() : "");
  41. }
  42. CPCD::Process::Process(const Properties & props, class CPCD *cpcd) {
  43.   m_id = -1;
  44.   m_pid = -1;
  45.   props.get("id", (Uint32 *) &m_id);
  46.   props.get("name", m_name);
  47.   props.get("group", m_group);
  48.   props.get("env", m_env);
  49.   props.get("path", m_path);
  50.   props.get("args", m_args);
  51.   props.get("cwd", m_cwd);
  52.   props.get("owner", m_owner);
  53.   props.get("type", m_type);
  54.   props.get("runas", m_runas);
  55.   props.get("stdin", m_stdin);
  56.   props.get("stdout", m_stdout);
  57.   props.get("stderr", m_stderr);
  58.   props.get("ulimit", m_ulimit);
  59.   props.get("shutdown", m_shutdown_options);
  60.   m_status = STOPPED;
  61.   if(strcasecmp(m_type.c_str(), "temporary") == 0){
  62.     m_processType = TEMPORARY;
  63.   } else {
  64.     m_processType = PERMANENT;
  65.   }
  66.   
  67.   m_cpcd = cpcd;
  68. }
  69. void
  70. CPCD::Process::monitor() { 
  71.   switch(m_status) {
  72.   case STARTING:
  73.     break;
  74.   case RUNNING:
  75.     if(!isRunning()){
  76.       m_cpcd->report(m_id, CPCEvent::ET_PROC_STATE_STOPPED);
  77.       if(m_processType == TEMPORARY){
  78. m_status = STOPPED;
  79.       } else {
  80. start();
  81.       }
  82.     }
  83.     break;
  84.   case STOPPED:
  85.     assert(!isRunning());
  86.     break;
  87.   case STOPPING:
  88.     break;
  89.   }
  90. }
  91. bool
  92. CPCD::Process::isRunning() {
  93.   if(m_pid <= 1){
  94.     //logger.critical("isRunning(%d) invalid pid: %d", m_id, m_pid);
  95.     return false;
  96.   }
  97.   /* Check if there actually exists a process with such a pid */
  98.   errno = 0;
  99.   int s = kill((pid_t)-m_pid, 0); /* Sending "signal" 0 to a process only
  100.    * checkes if the process actually exists */
  101.   if(s != 0) {
  102.     switch(errno) {
  103.     case EPERM:
  104.       logger.critical("Not enough privileges to control pid %dn", m_pid);
  105.       break;
  106.     case ESRCH:
  107.       /* The pid in the file does not exist, which probably means that it
  108.  has died, or the file contains garbage for some other reason */
  109.       break;
  110.     default:
  111.       logger.critical("Cannot not control pid %d: %sn", m_pid, strerror(errno));
  112.       break;
  113.     }
  114.     return false;
  115.   } 
  116.   return true;
  117. }
  118. int
  119. CPCD::Process::readPid() {
  120.   if(m_pid != -1){
  121.     logger.critical("Reading pid while != -1(%d)", m_pid);
  122.     return m_pid;
  123.   }
  124.   char filename[PATH_MAX*2+1];
  125.   char buf[1024];
  126.   FILE *f;
  127.   memset(buf, 0, sizeof(buf));
  128.   
  129.   BaseString::snprintf(filename, sizeof(filename), "%d", m_id);
  130.   
  131.   f = fopen(filename, "r");
  132.   
  133.   if(f == NULL){
  134.     return -1; /* File didn't exist */
  135.   }
  136.   
  137.   errno = 0;
  138.   size_t r = fread(buf, 1, sizeof(buf), f);
  139.   fclose(f);
  140.   if(r > 0)
  141.     m_pid = strtol(buf, (char **)NULL, 0);
  142.   
  143.   if(errno == 0){
  144.     return m_pid;
  145.   }
  146.   
  147.   return -1;
  148. }
  149. int
  150. CPCD::Process::writePid(int pid) {
  151.   char tmpfilename[PATH_MAX+1+4+8];
  152.   char filename[PATH_MAX*2+1];
  153.   FILE *f;
  154.   BaseString::snprintf(tmpfilename, sizeof(tmpfilename), "tmp.XXXXXX");
  155.   BaseString::snprintf(filename, sizeof(filename), "%d", m_id);
  156.   
  157.   int fd = mkstemp(tmpfilename);
  158.   if(fd < 0) {
  159.     logger.error("Cannot open `%s': %sn", tmpfilename, strerror(errno));
  160.     return -1; /* Couldn't open file */
  161.   }
  162.   f = fdopen(fd, "w");
  163.   if(f == NULL) {
  164.     logger.error("Cannot open `%s': %sn", tmpfilename, strerror(errno));
  165.     return -1; /* Couldn't open file */
  166.   }
  167.   fprintf(f, "%d", pid);
  168.   fclose(f);
  169.   if(rename(tmpfilename, filename) == -1){
  170.     logger.error("Unable to rename from %s to %s", tmpfilename, filename);
  171.     return -1;
  172.   }
  173.   return 0;
  174. }
  175. static void
  176. setup_environment(const char *env) {
  177.   char **p;
  178.   p = BaseString::argify("", env);
  179.   for(int i = 0; p[i] != NULL; i++){
  180.     /*int res = */ putenv(p[i]);
  181.   }
  182. }
  183. static
  184. int
  185. set_ulimit(const BaseString & pair){
  186. #ifdef HAVE_GETRLIMIT
  187.   errno = 0;
  188.   Vector<BaseString> list;
  189.   pair.split(list, ":");
  190.   if(list.size() != 2){
  191.     logger.error("Unable to process ulimit: split >%s< list.size()=%d", 
  192.  pair.c_str(), list.size());
  193.     return -1;
  194.   }
  195.   
  196.   int res;
  197.   rlim_t value = RLIM_INFINITY;
  198.   if(!(list[1].trim() == "unlimited")){
  199.     value = atoi(list[1].c_str());
  200.   }
  201.   struct rlimit rlp;
  202. #define _RLIMIT_FIX(x) { res = getrlimit(x,&rlp); if(!res){ rlp.rlim_cur = value; res = setrlimit(x, &rlp); }}
  203.   
  204.   if(list[0].trim() == "c"){
  205.     _RLIMIT_FIX(RLIMIT_CORE);
  206.   } else if(list[0] == "d"){
  207.     _RLIMIT_FIX(RLIMIT_DATA);
  208.   } else if(list[0] == "f"){
  209.     _RLIMIT_FIX(RLIMIT_FSIZE);
  210.   } else if(list[0] == "n"){
  211.     _RLIMIT_FIX(RLIMIT_NOFILE);
  212.   } else if(list[0] == "s"){
  213.     _RLIMIT_FIX(RLIMIT_STACK);
  214.   } else if(list[0] == "t"){
  215.     _RLIMIT_FIX(RLIMIT_CPU);
  216.   } else {
  217.     res= -11;
  218.     errno = EINVAL;
  219.   }
  220.   if(res){
  221.     logger.error("Unable to process ulimit: %s res=%d error=%d(%s)", 
  222.  pair.c_str(), res, errno, strerror(errno));
  223.     return -1;
  224.   }
  225. #endif
  226.   return 0;
  227. }
  228. void
  229. CPCD::Process::do_exec() {
  230.   size_t i; 
  231.   setup_environment(m_env.c_str());
  232.   char **argv = BaseString::argify(m_path.c_str(), m_args.c_str());
  233.   if(strlen(m_cwd.c_str()) > 0) {
  234.     int err = chdir(m_cwd.c_str());
  235.     if(err == -1) {
  236.       BaseString err;
  237.       logger.error("%s: %sn", m_cwd.c_str(), strerror(errno));
  238.       _exit(1);
  239.     }
  240.   }
  241.   Vector<BaseString> ulimit;
  242.   m_ulimit.split(ulimit);
  243.   for(i = 0; i<ulimit.size(); i++){
  244.     if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){
  245.       _exit(1);
  246.     }
  247.   }
  248.   int fd = open("/dev/null", O_RDWR, 0);
  249.   if(fd == -1) {
  250.     logger.error("Cannot open `/dev/null': %sn", strerror(errno));
  251.     _exit(1);
  252.   }
  253.   
  254.   BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr };
  255.   int fds[3];
  256.   for(i = 0; i<3; i++){
  257.     if(redirects[i]->empty()){
  258. #ifndef DEBUG
  259.       dup2(fd, i);
  260. #endif
  261.       continue;
  262.     }
  263.     
  264.     if((* redirects[i]) == "2>&1" && i == 2){
  265.       dup2(fds[1], 2);
  266.       continue;
  267.     }
  268.     
  269.     /**
  270.      * Make file
  271.      */
  272.     int flags = 0;
  273.     int mode = S_IRUSR | S_IWUSR ;
  274.     if(i == 0){
  275.       flags |= O_RDONLY;
  276.     } else {
  277.       flags |= O_WRONLY | O_CREAT | O_APPEND;
  278.     }
  279.     int f = fds[i]= open(redirects[i]->c_str(), flags, mode);
  280.     if(f == -1){
  281.       logger.error("Cannot redirect %d to/from '%s' : %sn", i, 
  282.    redirects[i]->c_str(), strerror(errno));
  283.       _exit(1);
  284.     }
  285.     dup2(f, i);
  286.   }
  287.   /* Close all filedescriptors */
  288.   for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++)
  289.     close(i);
  290.   execv(m_path.c_str(), argv);
  291.   /* XXX If we reach this point, an error has occurred, but it's kind of hard
  292.    * to report it, because we've closed all files... So we should probably
  293.    * create a new logger here */
  294.   logger.error("Exec failed: %sn", strerror(errno));
  295.   /* NOTREACHED */
  296. }
  297. int
  298. CPCD::Process::start() {
  299.   /* We need to fork() twice, so that the second child (grandchild?) can
  300.    * become a daemon. The original child then writes the pid file,
  301.    * so that the monitor knows the pid of the new process, and then
  302.    * exit()s. That way, the monitor process can pickup the pid, and
  303.    * the running process is a daemon.
  304.    *
  305.    * This is a bit tricky but has the following advantages:
  306.    *  - the cpcd can die, and "reconnect" to the monitored clients
  307.    *    without restarting them.
  308.    *  - the cpcd does not have to wait() for the childs. init(1) will
  309.    *    take care of that.
  310.    */
  311.   logger.info("Starting %d: %s", m_id, m_name.c_str());
  312.   m_status = STARTING;
  313.     
  314.   int pid = -1;
  315.   switch(m_processType){
  316.   case TEMPORARY:{
  317.     /**
  318.      * Simple fork
  319.      * don't ignore child
  320.      */
  321.     switch(pid = fork()) {
  322.     case 0: /* Child */
  323.       setsid();
  324.       writePid(getpgrp());
  325.       if(runas(m_runas.c_str()) == 0){
  326.         signal(SIGCHLD, SIG_DFL);
  327. do_exec();
  328.       }
  329.       _exit(1);
  330.       break;
  331.     case -1: /* Error */
  332.       logger.error("Cannot fork: %sn", strerror(errno));
  333.       m_status = STOPPED;
  334.       return -1;
  335.       break;
  336.     default: /* Parent */
  337.       logger.debug("Started temporary %d : pid=%d", m_id, pid);
  338.       m_cpcd->report(m_id, CPCEvent::ET_PROC_STATE_RUNNING);
  339.       break;
  340.     }
  341.     break;
  342.   }
  343.   case PERMANENT:{
  344.     /**
  345.      * PERMANENT
  346.      */
  347.     switch(fork()) {
  348.     case 0: /* Child */
  349.       signal(SIGCHLD, SIG_IGN);
  350.       switch(pid = fork()) {
  351.       case 0: /* Child */
  352. setsid();
  353. writePid(getpgrp());
  354. if(runas(m_runas.c_str()) != 0){
  355.   _exit(1);
  356. }
  357.         signal(SIGCHLD, SIG_DFL);
  358. do_exec();
  359. _exit(1);
  360. /* NOTREACHED */
  361. break;
  362.       case -1: /* Error */
  363. logger.error("Cannot fork: %sn", strerror(errno));
  364. writePid(-1);
  365. _exit(1);
  366. break;
  367.       default: /* Parent */
  368. logger.debug("Started permanent %d : pid=%d", m_id, pid);
  369. _exit(0);
  370. break;
  371.       }
  372.       break;
  373.     case -1: /* Error */
  374.       logger.error("Cannot fork: %sn", strerror(errno));
  375.       m_status = STOPPED;
  376.       return -1;
  377.       break;
  378.     default: /* Parent */
  379.       m_cpcd->report(m_id, CPCEvent::ET_PROC_STATE_RUNNING);
  380.       break;
  381.     }
  382.     break;
  383.   }
  384.   default:
  385.     logger.critical("Unknown process type");
  386.     return -1;
  387.   }
  388.   while(readPid() < 0){
  389.     sched_yield();
  390.   }
  391.   
  392.   errno = 0;
  393.   pid_t pgid = getpgid(pid);
  394.   
  395.   if(pgid != -1 && pgid != m_pid){
  396.     logger.error("pgid and m_pid don't match: %d %d (%d)", pgid, m_pid, pid);
  397.   }
  398.   
  399.   if(isRunning()){
  400.     m_status = RUNNING;
  401.     return 0;
  402.   }
  403.   m_status = STOPPED;
  404.   return -1;
  405. }
  406. void
  407. CPCD::Process::stop() {
  408.   char filename[PATH_MAX*2+1];
  409.   BaseString::snprintf(filename, sizeof(filename), "%d", m_id);
  410.   unlink(filename);
  411.   
  412.   if(m_pid <= 1){
  413.     logger.critical("Stopping process with bogus pid: %d id: %d", 
  414.     m_pid, m_id);
  415.     return;
  416.   }
  417.   m_status = STOPPING;
  418.   
  419.   errno = 0;
  420.   int signo= SIGTERM;
  421.   if(m_shutdown_options == "SIGKILL")
  422.     signo= SIGKILL;
  423.   int ret = kill(-m_pid, signo);
  424.   switch(ret) {
  425.   case 0:
  426.     logger.debug("Sent SIGTERM to pid %d", (int)-m_pid);
  427.     break;
  428.   default:
  429.     logger.debug("kill pid: %d : %s", (int)-m_pid, strerror(errno));
  430.     break;
  431.   }
  432.   
  433.   if(isRunning()){
  434.     errno = 0;
  435.     ret = kill(-m_pid, SIGKILL);
  436.     switch(ret) {
  437.     case 0:
  438.       logger.debug("Sent SIGKILL to pid %d", (int)-m_pid);
  439.       break;
  440.     default:
  441.       logger.debug("kill pid: %d : %sn", (int)-m_pid, strerror(errno));
  442.       break;
  443.     }
  444.   } 
  445.   
  446.   m_pid = -1;
  447.   m_status = STOPPED;
  448. }