18 #include <ndb_global.h>
24 #include <BaseString.hpp>
25 #include <InputStream.hpp>
38 #include <sys/resource.h>
43 fprintf(f,
"define process\n");
44 fprintf(f,
"id: %d\n",
m_id);
65 props.get(
"id", (Uint32 *) &m_id);
66 props.get(
"name", m_name);
67 props.get(
"group", m_group);
68 props.get(
"env", m_env);
69 props.get(
"path", m_path);
70 props.get(
"args", m_args);
71 props.get(
"cwd", m_cwd);
72 props.get(
"owner", m_owner);
73 props.get(
"type", m_type);
74 props.get(
"runas", m_runas);
76 props.get(
"stdin", m_stdin);
77 props.get(
"stdout", m_stdout);
78 props.get(
"stderr", m_stderr);
79 props.get(
"ulimit", m_ulimit);
80 props.get(
"shutdown", m_shutdown_options);
83 if(strcasecmp(m_type.c_str(),
"temporary") == 0){
84 m_processType = TEMPORARY;
87 logger.critical(
"Process type must be 'temporary' on windows");
90 m_processType = PERMANENT;
103 if(m_processType == TEMPORARY){
111 assert(!isRunning());
121 if (is_bad_pid(m_pid)) {
131 if (!(proc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, m_pid)))
133 logger.debug(
"Cannot OpenProcess with pid: %d, error: %d",
134 m_pid, GetLastError());
139 if (GetExitCodeProcess(proc, &exitcode) && exitcode != STILL_ACTIVE)
148 int s =
kill((pid_t)-m_pid, 0);
153 logger.critical(
"Not enough privileges to control pid %d\n", m_pid);
160 logger.critical(
"Cannot not control pid %d: %s\n", m_pid, strerror(errno));
171 if (!is_bad_pid(m_pid)) {
172 logger.critical(
"Reading pid while having valid process (%d)", m_pid);
176 char filename[PATH_MAX*2+1];
180 memset(buf, 0,
sizeof(buf));
184 f = fopen(filename,
"r");
191 size_t r = fread(buf, 1,
sizeof(buf), f);
194 m_pid = strtol(buf, (
char **)NULL, 0);
203 inline int mkstemp(
char *tmp)
209 fd = _open(tmp, _O_CREAT|_O_RDWR|_O_TEXT|_O_TRUNC, _S_IREAD|_S_IWRITE);
216 char tmpfilename[PATH_MAX+1+4+8];
217 char filename[PATH_MAX*2+1];
223 int fd = mkstemp(tmpfilename);
225 logger.error(
"Cannot open `%s': %s\n", tmpfilename, strerror(errno));
232 logger.error(
"Cannot open `%s': %s\n", tmpfilename, strerror(errno));
236 fprintf(f,
"%d", pid);
243 if(rename(tmpfilename, filename) == -1){
244 logger.error(
"Unable to rename from %s to %s", tmpfilename, filename);
251 setup_environment(
const char *env) {
254 for(
int i = 0; p[
i] != NULL;
i++){
262 #ifdef HAVE_GETRLIMIT
265 pair.
split(list,
":");
266 if(list.size() != 2){
267 logger.error(
"Unable to process ulimit: split >%s< list.size()=%d",
268 pair.
c_str(), list.size());
273 rlim_t value = RLIM_INFINITY;
274 if(!(list[1].trim() ==
"unlimited")){
275 value = atoi(list[1].c_str());
279 #define _RLIMIT_FIX(x) { res = getrlimit(x,&rlp); if(!res){ rlp.rlim_cur = value; res = setrlimit(x, &rlp); }}
281 if(list[0].trim() ==
"c"){
282 _RLIMIT_FIX(RLIMIT_CORE);
283 }
else if(list[0] ==
"d"){
284 _RLIMIT_FIX(RLIMIT_DATA);
285 }
else if(list[0] ==
"f"){
286 _RLIMIT_FIX(RLIMIT_FSIZE);
287 }
else if(list[0] ==
"n"){
288 _RLIMIT_FIX(RLIMIT_NOFILE);
289 }
else if(list[0] ==
"s"){
290 _RLIMIT_FIX(RLIMIT_STACK);
291 }
else if(list[0] ==
"t"){
292 _RLIMIT_FIX(RLIMIT_CPU);
298 logger.error(
"Unable to process ulimit: %s res=%d error=%d(%s)",
299 pair.
c_str(), res, errno, strerror(errno));
307 const int S_IRUSR = _S_IREAD, S_IWUSR = _S_IWRITE;
315 logger.error(
"Could not argify new environment");
319 for(
int i = 0; ptr[
i] != NULL;
i++) {
323 char *str1 = strdup(ptr[i]);
327 *strchr(str1,
'=') = 0;
329 bs.
assfmt(
"%s=%s", str1, str2 ? str2 :
"");
336 CPCD::Process::do_exec() {
342 save_environment(m_env.c_str(), saved);
345 setup_environment(m_env.c_str());
349 if(strlen(m_cwd.c_str()) > 0) {
354 logger.critical(
"Couldn't getcwd before spawn");
357 int err = chdir(m_cwd.c_str());
360 logger.error(
"%s: %s\n", m_cwd.c_str(), strerror(errno));
366 m_ulimit.split(ulimit);
367 for(i = 0; i<ulimit.size(); i++){
368 if(ulimit[i].trim().length() > 0 && set_ulimit(ulimit[i]) != 0){
374 const char *nul = IF_WIN(
"nul:",
"/dev/null");
375 int fdnull = open(nul, O_RDWR, 0);
377 logger.error(
"Cannot open `%s': %s\n", nul, strerror(errno));
381 BaseString * redirects[] = { &m_stdin, &m_stdout, &m_stderr };
386 for (i = 0; i < 3; i++) {
388 std_dups[
i] = dup(i);
390 if (redirects[i]->empty()) {
397 if((* redirects[i]) ==
"2>&1" && i == 2){
406 int mode = S_IRUSR | S_IWUSR ;
410 flags |= O_WRONLY | O_CREAT | O_APPEND;
412 int f = fds[
i]= open(redirects[i]->c_str(), flags, mode);
414 logger.error(
"Cannot redirect %ld to/from '%s' : %s\n", i,
415 redirects[i]->c_str(), strerror(errno));
426 for(i = STDERR_FILENO+1; (int)i < getdtablesize(); i++)
429 execv(m_path.c_str(), argv);
433 logger.error(
"Exec failed: %s\n", strerror(errno));
438 FILE *fpipe = _popen(
"sh -c 'cygpath -w `which sh`'",
"rt");
441 require(fgets(buf, MAX_PATH - 1, fpipe));
450 shcmd.
assfmt(
"%s -c '%s %s'", sh.
c_str(), m_path.c_str(), m_args.c_str());
452 PROCESS_INFORMATION pi = {0};
453 STARTUPINFO si = {
sizeof(STARTUPINFO), 0};
455 si.dwFlags |= STARTF_USESTDHANDLES;
456 si.hStdInput = (HANDLE)_get_osfhandle(0);
457 si.hStdOutput = (HANDLE)_get_osfhandle(1);
458 si.hStdError = (HANDLE)_get_osfhandle(2);
460 if(!CreateProcessA(sh.
c_str(),
461 (LPSTR)shcmd.
c_str(),
472 DWORD err = GetLastError();
474 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
475 FORMAT_MESSAGE_FROM_SYSTEM |
476 FORMAT_MESSAGE_IGNORE_INSERTS,
479 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
483 logger.error(
"CreateProcess failed, error: %d, message: '%s'",
489 HANDLE proc = pi.hProcess;
493 require(m_job = CreateJobObject(0, 0));
494 require(AssignProcessToJobObject(m_job, proc));
497 ResumeThread(pi.hThread);
498 CloseHandle(pi.hThread);
504 logger.critical(
"Couldn't go back to saved cwd after spawn()");
505 logger.critical(
"errno: %d, strerror: %s", errno, strerror(errno));
510 for(i = 0; i < 3; i++) {
511 dup2(std_dups[i], i);
515 for (i = 0; i < saved.size(); i++) {
516 putenv(saved[i].c_str());
519 logger.debug(
"'%s' has been started", shcmd.
c_str());
522 BOOL result = GetExitCodeProcess(proc, &exitcode);
524 if (result && exitcode != 259) {
526 logger.warning(
"Process terminated early");
529 int pid = GetProcessId(proc);
531 logger.critical(
"GetProcessId failed, error: %d!", GetLastError());
533 logger.debug(
"new pid %d", pid);
563 logger.info(
"Starting %d: %s", m_id, m_name.c_str());
567 switch(m_processType){
574 switch(pid = fork()) {
578 if(runas(m_runas.c_str()) == 0){
579 signal(SIGCHLD, SIG_DFL);
585 logger.error(
"Cannot fork: %s\n", strerror(errno));
590 logger.debug(
"Started temporary %d : pid=%d", m_id, pid);
605 signal(SIGCHLD, SIG_IGN);
606 switch(pid = fork()) {
610 if(runas(m_runas.c_str()) != 0){
613 signal(SIGCHLD, SIG_DFL);
619 logger.error(
"Cannot fork: %s\n", strerror(errno));
624 logger.debug(
"Started permanent %d : pid=%d", m_id, pid);
630 logger.error(
"Cannot fork: %s\n", strerror(errno));
641 logger.critical(
"Unknown process type");
645 while(readPid() < 0){
650 pid_t pgid = IF_WIN(-1, getpgid(pid));
652 if(pgid != -1 && pgid != m_pid){
653 logger.error(
"pgid and m_pid don't match: %d %d (%d)", pgid, m_pid, pid);
668 char filename[PATH_MAX*2+1];
672 if (is_bad_pid(m_pid))
674 logger.critical(
"Stopping process with bogus pid: %d id: %d",
684 if(m_shutdown_options ==
"SIGKILL")
690 logger.debug(
"Sent SIGTERM to pid %d", (
int)-m_pid);
693 logger.debug(
"kill pid: %d : %s", (
int)-m_pid, strerror(errno));
699 ret =
kill(-m_pid, SIGKILL);
702 logger.debug(
"Sent SIGKILL to pid %d", (
int)-m_pid);
705 logger.debug(
"kill pid: %d : %s\n", (
int)-m_pid, strerror(errno));
714 require(proc = OpenProcess(PROCESS_QUERY_INFORMATION, 0, m_pid));
715 require(IsProcessInJob(proc, m_job, &truth));
716 require(truth == TRUE);
717 require(CloseHandle(proc));
719 require(TerminateJobObject(m_job, 37));
720 require(CloseHandle(m_job));