1 /* 2 Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. 3 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License, version 2.0, 7 as published by the Free Software Foundation. 8 9 This program is also distributed with certain software (including 10 but not limited to OpenSSL) that is licensed under separate terms, 11 as designated in a particular file or component or in included license 12 documentation. The authors of MySQL hereby grant you an additional 13 permission to link the program and your derivative works with the 14 separately licensed software that they have included with MySQL. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License, version 2.0, for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program; if not, write to the Free Software 23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 */ 25 26 27 #ifndef NDB_PROCESS_HPP 28 #define NDB_PROCESS_HPP 29 30 #include <portlib/NdbSleep.h> 31 32 class NdbProcess 33 { 34 #ifdef _WIN32 35 typedef DWORD pid_t; 36 #endif 37 pid_t m_pid; 38 BaseString m_name; 39 public: 40 getpid()41 static pid_t getpid() 42 { 43 #ifdef _WIN32 44 return GetCurrentProcessid(); 45 #else 46 return ::getpid(); 47 #endif 48 } 49 50 class Args 51 { 52 Vector<BaseString> m_args; 53 public: 54 add(const char * str)55 void add(const char* str) 56 { 57 m_args.push_back(str); 58 } 59 add(const char * str,const char * str2)60 void add(const char* str, const char* str2) 61 { 62 BaseString tmp; 63 tmp.assfmt("%s%s", str, str2); 64 m_args.push_back(tmp); 65 } 66 add(const char * str,int val)67 void add(const char* str, int val) 68 { 69 BaseString tmp; 70 tmp.assfmt("%s%d", str, val); 71 m_args.push_back(tmp); 72 } 73 add(const Args & args)74 void add(const Args & args) 75 { 76 for (unsigned i = 0; i < args.m_args.size(); i++) 77 add(args.m_args[i].c_str()); 78 } 79 args(void) const80 const Vector<BaseString>& args(void) const 81 { 82 return m_args; 83 } 84 85 }; 86 create(const BaseString & name,const BaseString & path,const BaseString & cwd,const Args & args)87 static NdbProcess* create(const BaseString& name, 88 const BaseString& path, 89 const BaseString& cwd, 90 const Args& args) 91 { 92 NdbProcess* proc = new NdbProcess(name); 93 if (!proc) 94 { 95 fprintf(stderr, "Failed to allocate memory for new process\n"); 96 return NULL; 97 } 98 99 // Check existence of cwd 100 if (cwd.c_str() && access(cwd.c_str(), F_OK) != 0) 101 { 102 fprintf(stderr, 103 "The specified working directory '%s' does not exist\n", 104 cwd.c_str()); 105 delete proc; 106 return NULL; 107 } 108 109 if (!start_process(proc->m_pid, path.c_str(), cwd.c_str(), args)) 110 { 111 fprintf(stderr, 112 "Failed to create process '%s'\n", name.c_str()); 113 delete proc; 114 return NULL; 115 } 116 return proc; 117 } 118 stop(void)119 bool stop(void) 120 { 121 int ret = kill(m_pid, 9); 122 if (ret != 0) 123 { 124 fprintf(stderr, 125 "Failed to kill process %d, ret: %d, errno: %d\n", 126 m_pid, ret, errno); 127 return false; 128 } 129 printf("Stopped process %d\n", m_pid); 130 return true; 131 } 132 wait(int & ret,int timeout=0)133 bool wait(int& ret, int timeout = 0) 134 { 135 int retries = 0; 136 int status; 137 while (true) 138 { 139 pid_t ret_pid = waitpid(m_pid, &status, WNOHANG); 140 if (ret_pid == -1) 141 { 142 fprintf(stderr, 143 "Error occurred when waiting for process %d, ret: %d, errno: %d\n", 144 m_pid, status, errno); 145 return false; 146 } 147 148 if (ret_pid == m_pid) 149 { 150 if (WIFEXITED(status)) 151 ret = WEXITSTATUS(status); 152 else if (WIFSIGNALED(status)) 153 ret = WTERMSIG(status); 154 else 155 ret = 37; // Unknown exit status 156 157 printf("Got process %d, status: %d, ret: %d\n", m_pid, status, ret); 158 return true; 159 } 160 161 if (timeout == 0) 162 return false; 163 164 if (retries++ > timeout*10) 165 { 166 fprintf(stderr, 167 "Timeout when waiting for process %d\n", m_pid); 168 return false; 169 } 170 NdbSleep_MilliSleep(10); 171 } 172 require(false); // Never reached 173 } 174 175 private: 176 NdbProcess(BaseString name)177 NdbProcess(BaseString name) : 178 m_name(name) 179 { 180 m_pid = -1; 181 } 182 start_process(pid_t & pid,const char * path,const char * cwd,const Args & args)183 static bool start_process(pid_t& pid, const char* path, 184 const char* cwd, 185 const Args& args) 186 { 187 #ifdef _WIN32 188 #else 189 int retries = 5; 190 pid_t tmp; 191 while ((tmp = fork()) == -1) 192 { 193 fprintf(stderr, "Warning: 'fork' failed, errno: %d - ", errno); 194 if (retries--) 195 { 196 fprintf(stderr, "retrying in 1 second...\n"); 197 NdbSleep_SecSleep(1); 198 continue; 199 } 200 fprintf(stderr, "giving up...\n"); 201 return false; 202 } 203 204 if (tmp) 205 { 206 pid = tmp; 207 printf("Started process: %d\n", pid); 208 return true; 209 } 210 require(tmp == 0); 211 212 if (cwd && chdir(cwd) != 0) 213 { 214 fprintf(stderr, "Failed to change directory to '%s', errno: %d\n", cwd, errno); 215 exit(1); 216 } 217 218 // Concatenate arguments 219 BaseString args_str; 220 args_str.assign(args.args(), " "); 221 222 char **argv = BaseString::argify(path, args_str.c_str()); 223 //printf("name: %s\n", path); 224 execv(path, argv); 225 226 fprintf(stderr, "execv failed, errno: %d\n", errno); 227 exit(1); 228 #endif 229 } 230 }; 231 232 #endif 233