1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information
3 
4 #include <rudiments/process.h>
5 #include <rudiments/error.h>
6 #include <rudiments/snooze.h>
7 #include <rudiments/directory.h>
8 #include <rudiments/userentry.h>
9 #include <rudiments/groupentry.h>
10 #include <rudiments/file.h>
11 #include <rudiments/permissions.h>
12 #include <rudiments/charstring.h>
13 #include <rudiments/error.h>
14 #include <rudiments/stdio.h>
15 #ifdef RUDIMENTS_HAVE_CREATE_PROCESS
16 	#include <rudiments/stringbuffer.h>
17 	#include <rudiments/environment.h>
18 	#include <rudiments/bytestring.h>
19 #endif
20 #if defined(RUDIMENTS_HAVE_GENERATECONSOLECTRLEVENT)
21 	#include <rudiments/sys.h>
22 #endif
23 #ifdef RUDIMENTS_HAVE_EXECINFO_H
24 	#include <execinfo.h>
25 #endif
26 
27 
28 #ifndef __USE_XOPEN_EXTENDED
29 	// for getsid()
30 	#define __USE_XOPEN_EXTENDED
31 #endif
32 #ifdef RUDIMENTS_HAVE_GRP_H
33 	#include <grp.h>
34 #endif
35 #ifdef RUDIMENTS_HAVE_UNISTD_H
36 	#include <unistd.h>
37 #endif
38 
39 // for exit()
40 #ifdef RUDIMENTS_HAVE_STDLIB_H
41 	#include <stdlib.h>
42 #endif
43 
44 #ifdef RUDIMENTS_HAVE_WINDOWS_H
45 	#include <windows.h>
46 #endif
47 #ifdef RUDIMENTS_HAVE_TLHELP32_H
48 	#include <tlhelp32.h>
49 #endif
50 #ifdef RUDIMENTS_HAVE_DBGHELP_H
51 	#include <dbghelp.h>
52 #endif
53 
54 // for umask
55 #ifdef RUDIMENTS_HAVE_SYS_STAT_H
56 	#include <sys/stat.h>
57 #endif
58 
59 // for GetCurrentProcessId on windows
60 #ifdef RUDIMENTS_HAVE_PROCESS_H
61 	#include <process.h>
62 #endif
63 
64 // for waitpid...
65 #if defined(RUDIMENTS_HAVE_SYS_WAIT_H)
66 	#include <sys/wait.h>
67 #endif
68 
69 signalhandler	process::_deadchildhandler;
70 signalhandler	process::_shutdownhandler;
71 signalhandler	process::_crashhandler;
72 
73 void		(*process::_shutdownfunc)(int32_t);
74 void		(*process::_crashfunc)(int32_t);
75 
76 bool		process::_retry=true;
77 
getProcessId()78 pid_t process::getProcessId() {
79 	#if defined(RUDIMENTS_HAVE_GETCURRENTPROCESSID)
80 		return GetCurrentProcessId();
81 	#elif defined(RUDIMENTS_HAVE_GETPID)
82 		return getpid();
83 	#else
84 		#error no getpid or anything like it
85 	#endif
86 }
87 
getParentProcessId()88 pid_t process::getParentProcessId() {
89 	#if defined(RUDIMENTS_HAVE_GETPPID)
90 		return getppid();
91 	#elif defined(RUDIMENTS_HAVE_PROCESS32FIRST) && _WIN32_WINNT>=0x0500
92 		HANDLE	snap=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
93 		if (snap==INVALID_HANDLE_VALUE) {
94 			return -1;
95 		}
96 		PROCESSENTRY32	pe;
97 		pe.dwSize=sizeof(pe);
98 		pid_t	mypid=getProcessId();
99 		pid_t	ppid=-1;
100 		if (Process32First(snap,&pe)) {
101 			do {
102 				if (pe.th32ProcessID==mypid) {
103 					ppid=pe.th32ParentProcessID;
104 					break;
105 				}
106 			} while (Process32Next(snap,&pe));
107 		}
108 		CloseHandle(snap);
109 		return ppid;
110 	#else
111 		RUDIMENTS_SET_ENOSYS
112 		return 0;
113 	#endif
114 }
115 
getProcessGroupId()116 pid_t process::getProcessGroupId() {
117 	return getProcessGroupId(0);
118 }
119 
getProcessGroupId(pid_t pid)120 pid_t process::getProcessGroupId(pid_t pid) {
121 	#if defined(RUDIMENTS_HAVE_GETPGID)
122 		return getpgid(pid);
123 	#else
124 		// minix doesn't have the notion of process groups
125 		// windows does, but they don't appear to have ID's
126 		RUDIMENTS_SET_ENOSYS
127 		return -1;
128 	#endif
129 }
130 
setProcessGroupId()131 bool process::setProcessGroupId() {
132 	return setProcessGroupId(0);
133 }
134 
setProcessGroupId(pid_t pgid)135 bool process::setProcessGroupId(pid_t pgid) {
136 	return setProcessGroupId(0,pgid);
137 }
138 
setProcessGroupId(pid_t pid,pid_t pgid)139 bool process::setProcessGroupId(pid_t pid, pid_t pgid) {
140 	#if defined(RUDIMENTS_HAVE_SETPGID)
141 		return !setpgid(pid,pgid);
142 	#else
143 		// minix doesn't have the notion of process groups
144 		// windows does, but they don't appear to have ID's
145 		RUDIMENTS_SET_ENOSYS
146 		return false;
147 	#endif
148 }
149 
getSessionId()150 pid_t process::getSessionId() {
151 	return getSessionId(0);
152 }
153 
getSessionId(pid_t pid)154 pid_t process::getSessionId(pid_t pid) {
155 	#if defined(RUDIMENTS_HAVE_GETSID)
156 		return getsid(pid);
157 	#else
158 		// windows doesn't have the notion of sessions
159 		RUDIMENTS_SET_ENOSYS
160 		return -1;
161 	#endif
162 }
163 
newSession()164 pid_t process::newSession() {
165 	#ifdef RUDIMENTS_HAVE_SETSID
166 		return setsid();
167 	#else
168 		// windows doesn't have the notion of sessions
169 		RUDIMENTS_SET_ENOSYS
170 		return -1;
171 	#endif
172 }
173 
getUserId()174 uid_t process::getUserId() {
175 	#if defined(RUDIMENTS_HAVE_GETUID)
176 		return getuid();
177 	#elif defined(RUDIMENTS_HAVE_GETUSERNAME)
178 		DWORD	size=0;
179 		GetUserName(NULL,&size);
180 		if (size<1) {
181 			return (uid_t)-1;
182 		}
183 		CHAR	*buffer=new CHAR[size];
184 		if (GetUserName(buffer,&size)==FALSE) {
185 			delete[] buffer;
186 			return (uid_t)-1;
187 		}
188 		uid_t	uid=userentry::getUserId(buffer);
189 		delete[] buffer;
190 		return uid;
191 	#else
192 		#error no getuid or anything like it
193 	#endif
194 }
195 
getEffectiveUserId()196 uid_t process::getEffectiveUserId() {
197 	#if defined(RUDIMENTS_HAVE_GETEUID)
198 		return geteuid();
199 	#else
200 		// windows doesn't have the notion of effective vs. actual
201 		// user id's, so we'll return the actual user id
202 		return getUserId();
203 	#endif
204 }
205 
setUserId(uid_t uid)206 bool process::setUserId(uid_t uid) {
207 	#if defined(RUDIMENTS_HAVE_SETUID)
208 		#if defined(RUDIMENTS_HAVE_SETGROUPS)
209 			// If we're changing from root to another user, be sure
210 			// to drop all group permissions first.  This will fail
211 			// if we're not root, so there's no need to check the
212 			// result.
213 			setgroups(0,NULL);
214 		#endif
215 		return !setuid(uid);
216 	#else
217 		RUDIMENTS_SET_ENOSYS
218 		return false;
219 	#endif
220 }
221 
setUser(const char * username)222 bool process::setUser(const char *username) {
223 	uid_t	userid=userentry::getUserId(username);
224 	return (userid!=(uid_t)-1)?setUserId(userid):true;
225 }
226 
227 #ifdef RUDIMENTS_HAVE_SETEUID_BUT_NOT_DEFINED
228 extern "C" int seteuid(uid_t euid);
229 #endif
230 
setEffectiveUserId(uid_t uid)231 bool process::setEffectiveUserId(uid_t uid) {
232 	#if defined(RUDIMENTS_HAVE_SETEUID)
233 		return !seteuid(uid);
234 	#elif defined(RUDIMENTS_HAVE_SYSCALL_SETEUID)
235 		return !syscall(SYS_seteuid,uid);
236 	#else
237 		// windows doesn't have the notion of effective user id's
238 		RUDIMENTS_SET_ENOSYS
239 		return false;
240 	#endif
241 }
242 
setEffectiveUser(const char * username)243 bool process::setEffectiveUser(const char *username) {
244 	uid_t	userid=userentry::getUserId(username);
245 	return (userid!=(uid_t)-1)?setEffectiveUserId(userid):true;
246 }
247 
setRealAndEffectiveUserId(uid_t uid,uid_t euid)248 bool process::setRealAndEffectiveUserId(uid_t uid, uid_t euid) {
249 	#if defined(RUDIMENTS_HAVE_SETREUID)
250 		return !setreuid(uid,euid);
251 	#else
252 		return setUserId(uid) && setEffectiveUserId(euid);
253 	#endif
254 }
255 
getGroupId()256 gid_t process::getGroupId() {
257 	#if defined(RUDIMENTS_HAVE_GETUID)
258 		return getgid();
259 	#elif defined(RUDIMENTS_HAVE_GETUSERNAME)
260 		// windows doesn't have the notion of group-thread association
261 		// but we can return the primary group of the user associated
262 		// with the thread
263 		userentry	uent;
264 		uent.initialize(getUserId());
265 		return uent.getPrimaryGroupId();
266 	#else
267 		#error no getgid or anything like it
268 	#endif
269 }
270 
getEffectiveGroupId()271 gid_t process::getEffectiveGroupId() {
272 	#if defined(RUDIMENTS_HAVE_GETEGID)
273 		return getegid();
274 	#else
275 		// windows doesn't have the notion of effective vs. actual
276 		// group id's, so we'll return the actual group id
277 		return getGroupId();
278 	#endif
279 }
280 
setGroupId(gid_t gid)281 bool process::setGroupId(gid_t gid) {
282 	#if defined(RUDIMENTS_HAVE_SETUID)
283 		return !setgid(gid);
284 	#else
285 		RUDIMENTS_SET_ENOSYS
286 		return false;
287 	#endif
288 }
289 
setGroup(const char * groupname)290 bool process::setGroup(const char *groupname) {
291 	gid_t	groupid=groupentry::getGroupId(groupname);
292 	return (groupid!=(gid_t)-1)?setGroupId(groupid):true;
293 }
294 
295 #ifdef RUDIMENTS_HAVE_SETEGID_BUT_NOT_DEFINED
296 extern "C" int setegid(gid_t egid);
297 #endif
298 
setEffectiveGroupId(gid_t gid)299 bool process::setEffectiveGroupId(gid_t gid) {
300 	#if defined(RUDIMENTS_HAVE_SETEGID)
301 		return !setegid(gid);
302 	#else
303 		// windows doesn't have the notion of effective group id's
304 		RUDIMENTS_SET_ENOSYS
305 		return false;
306 	#endif
307 }
308 
setEffectiveGroup(const char * groupname)309 bool process::setEffectiveGroup(const char *groupname) {
310 	gid_t	groupid=groupentry::getGroupId(groupname);
311 	return (groupid!=(gid_t)-1)?setEffectiveGroupId(groupid):true;
312 }
313 
setRealAndEffectiveGroupId(gid_t gid,gid_t egid)314 bool process::setRealAndEffectiveGroupId(gid_t gid, gid_t egid) {
315 	#if defined(RUDIMENTS_HAVE_SETREUID)
316 		return !setregid(gid,egid);
317 	#else
318 		return setGroupId(gid) && setEffectiveGroupId(egid);
319 	#endif
320 }
321 
setFileCreationMask(mode_t mask)322 mode_t process::setFileCreationMask(mode_t mask) {
323 	#if defined(RUDIMENTS_HAVE_UMASK)
324 		return ::umask(mask);
325 	#else
326 		RUDIMENTS_SET_ENOSYS
327 		return 0;
328 	#endif
329 }
330 
fork()331 pid_t process::fork() {
332 	#if defined(RUDIMENTS_HAVE_FORK)
333 		pid_t	result;
334 		error::clearError();
335 		do {
336 			result=::fork();
337 			if (result==-1 &&
338 				error::getErrorNumber()==EAGAIN && _retry) {
339 				snooze::macrosnooze(1);
340 				continue;
341 			}
342 		} while (result==-1 && error::getErrorNumber()==EINTR);
343 		return result;
344 	#else
345 		RUDIMENTS_SET_ENOSYS
346 		return -1;
347 	#endif
348 }
349 
supportsFork()350 bool process::supportsFork() {
351 	#if defined(RUDIMENTS_HAVE_FORK)
352 		return true;
353 	#else
354 		return false;
355 	#endif
356 }
357 
exec(const char * command,const char * const * args)358 bool process::exec(const char *command, const char * const *args) {
359 	#if defined(RUDIMENTS_HAVE_EXECVP)
360 		return execvp(command,(char * const *)args)!=-1;
361 	#elif defined(RUDIMENTS_HAVE_CREATE_PROCESS)
362 		if (spawn(command,args,false)) {
363 			exit(0);
364 		}
365 		return false;
366 	#else
367 		RUDIMENTS_SET_ENOSYS
368 		return false;
369 	#endif
370 }
371 
372 #if defined(RUDIMENTS_HAVE_CREATE_PROCESS)
quoteArg(const char * arg)373 static char *quoteArg(const char *arg) {
374 
375 	// put quotes around args that contain spaces...
376 	if (!charstring::contains(arg," ")) {
377 		return charstring::duplicate(arg);
378 	}
379 
380 	size_t	quotedarglen=charstring::length(arg);
381 	char	*quotedarg=new char[charstring::length(arg)+4];
382 
383 	charstring::copy(quotedarg,"\"");
384 	charstring::append(quotedarg,arg);
385 
386 	// if the last character is a backslash, then escape it using another
387 	// backslash, otherwise windows will think that the trailing \"
388 	// means "include a literal quote"
389 	if (arg[quotedarglen-1]=='\\') {
390 		charstring::append(quotedarg,"\\");
391 	}
392 
393 	charstring::append(quotedarg,"\"");
394 
395 	return quotedarg;
396 }
397 #endif
398 
spawn(const char * command,const char * const * args,bool detached)399 pid_t process::spawn(const char *command,
400 				const char * const *args,
401 				bool detached) {
402 	#if defined(RUDIMENTS_HAVE_FORK) && defined(RUDIMENTS_HAVE_EXECVP)
403 		pid_t	child=fork();
404 		if (child==-1 || child>0) {
405 			return child;
406 		}
407 		return exec(command,args);
408 	#elif defined(RUDIMENTS_HAVE_CREATE_PROCESS)
409 
410 		// get the fully qualified (and then shortened)
411 		// version of the command
412 		char	*shortcommand=fullyQualifiedCommand(command);
413 
414 		// are we trying to run a batch file?
415 		size_t	shortcommandlen=charstring::length(shortcommand);
416 		bool	batchfile=
417 			(shortcommandlen>=4 &&
418 				!charstring::compareIgnoringCase(
419 					shortcommand+shortcommandlen-4,".bat"));
420 
421 		// Create the command line from the args...
422 		// CreateProcess must be able to modify the command line (for
423 		// some reason, and there's no indication as to whether it could
424 		// try to use more bytes than originally passed in) and will
425 		// only accept a command line of 32768 chars or less.
426 		stringbuffer	cmdl;
427 		size_t		spaceleft=32768;
428 
429 		// If we're trying to run a batch file then we need to use
430 		// cmd.exe as our command and use /c batchfilename [args]
431 		// as the args, so append /c and the batch file name first.
432 		if (batchfile) {
433 			cmdl.append("/c ");
434 			spaceleft-=3;
435 			if (spaceleft>shortcommandlen) {
436 				cmdl.append(shortcommand);
437 				spaceleft-=shortcommandlen;
438 			}
439 		}
440 
441 		// append the args
442 		if (args) {
443 			bool	first=true;
444 			for (const char * const *arg=args; *arg; arg++) {
445 				if (!first || batchfile) {
446 					if (spaceleft>1) {
447 						cmdl.append(" ");
448 						spaceleft--;
449 					} else {
450 						break;
451 					}
452 				}
453 				if (first) {
454 					first=false;
455 				}
456 				char	*qarg=quoteArg(*arg);
457 				size_t	size=charstring::length(qarg);
458 				if (spaceleft>size) {
459 					cmdl.append(qarg);
460 					delete[] qarg;
461 					spaceleft-=size;
462 				} else {
463 					delete[] qarg;
464 					break;
465 				}
466 			}
467 		}
468 		char	*commandline=cmdl.detachString();
469 
470 		// replace the command with (fully qualified and shortened)
471 		// cmd.exe if we're trying to run a batch file
472 		if (batchfile) {
473 			char	*shortcmd=fullyQualifiedCommand("cmd.exe");
474 			delete[] shortcommand;
475 			shortcommand=shortcmd;
476 		}
477 
478 		// create the new process and return it's pid on success
479 		STARTUPINFO		si;
480 		PROCESS_INFORMATION	pi;
481 		bytestring::zero(&si,sizeof(si));
482 		bytestring::zero(&pi,sizeof(pi));
483 		bool	success=(CreateProcess(shortcommand,commandline,
484 					NULL,NULL,TRUE,
485 					(detached)?CREATE_NEW_PROCESS_GROUP:0,
486 					NULL,NULL,&si,&pi)==TRUE);
487 		delete[] shortcommand;
488 		delete[] commandline;
489 		return (success)?pi.dwProcessId:-1;
490 	#else
491 		RUDIMENTS_SET_ENOSYS
492 		return false;
493 	#endif
494 }
495 
fullyQualifiedCommand(const char * command)496 char *process::fullyQualifiedCommand(const char *command) {
497 
498 	#if defined(RUDIMENTS_HAVE_CREATE_PROCESS)
499 		// if the command doesn't include a backslash then search
500 		// the path for it
501 		char	*fqcommand=NULL;
502 		if (charstring::contains(command,"\\")) {
503 			fqcommand=charstring::duplicate(command);
504 		} else {
505 
506 			// split the PATH on ;'s
507 			const char	*path=environment::getValue("PATH");
508 			char		**dirs=NULL;
509 			uint64_t	dircount=0;
510 			charstring::split(path,";",true,&dirs,&dircount);
511 
512 			// search each directory in the PATH
513 			// (actually, try the current directory first, it's not
514 			// in the PATH, but should be searched first)
515 			size_t	cmdlen=charstring::length(command);
516 			for (uint64_t i=0; i<=dircount; i++) {
517 
518 				char	*dir=NULL;
519 				if (!i) {
520 					dir=directory::
521 						getCurrentWorkingDirectory();
522 				} else {
523 					dir=dirs[i-1];
524 				}
525 
526 				fqcommand=new char[
527 						charstring::length(dir)+1+
528 						cmdlen+1];
529 
530 				charstring::copy(fqcommand,dir);
531 				charstring::append(fqcommand,"\\");
532 				charstring::append(fqcommand,command);
533 
534 				delete[] dir;
535 
536 				if (file::exists(fqcommand)) {
537 					// if we found the command in the
538 					// current directory, then don't
539 					// prepend the directory to it,
540 					// just use it as-is
541 					if (!i) {
542 						delete[] fqcommand;
543 						fqcommand=charstring::
544 							duplicate(command);
545 					}
546 					break;
547 				}
548 
549 				delete[] fqcommand;
550 				fqcommand=NULL;
551 			}
552 
553 			// clean up
554 			delete[] dirs;
555 		}
556 		if (!fqcommand) {
557 			return NULL;
558 		}
559 
560 		// get the short form of the fully qualified command
561 		// (this will work on older versions of windows)
562 		size_t	shortcommandsize=charstring::length(fqcommand)+1;
563 		char	*shortcommand=new char[shortcommandsize];
564 		GetShortPathName(fqcommand,shortcommand,shortcommandsize);
565 		delete[] fqcommand;
566 
567 		return shortcommand;
568 	#else
569 		return NULL;
570 	#endif
571 }
572 
detach()573 bool process::detach() {
574 
575 	// fork off a child process
576 	pid_t	result=fork();
577 	if (result==-1) {
578 		return false;
579 	}
580 
581 	// let the parent process exit
582 	if (result) {
583 		// cygwin needs a sleep or both processes will exit
584 		#ifdef __CYGWIN__
585 			snooze::macrosnooze(1);
586 		#endif
587 		exitImmediately(0);
588 	}
589 
590 	// create a new session with no controlling terminal
591 	newSession();
592 
593 	// change directory to root to avoid keeping any directories in use
594 	directory::changeDirectory("/");
595 
596 	// Set umask such that files are created 666 and directories 777.  This
597 	// way we can change them to whatever we like using chmod().  We want to
598 	// avoid inheriting a umask which wouldn't give us write permissions to
599 	// files we create.
600 	setFileCreationMask(0);
601 
602 	return true;
603 }
604 
exit(int32_t status)605 void process::exit(int32_t status) {
606 	::exit(status);
607 }
608 
exitImmediately(int32_t status)609 void process::exitImmediately(int32_t status) {
610 	_exit(status);
611 }
612 
sendSignal(pid_t processid,int32_t signum)613 bool process::sendSignal(pid_t processid, int32_t signum) {
614 	#ifdef RUDIMENTS_HAVE_KILL
615 		int32_t	result;
616 		error::clearError();
617 		do {
618 			result=kill(processid,signum);
619 		} while (result==-1 && error::getErrorNumber()==EINTR);
620 		return !result;
621 	#elif defined(RUDIMENTS_HAVE_GENERATECONSOLECTRLEVENT)
622 
623 		// decide what access rights we need
624 		DWORD	accessrights=PROCESS_TERMINATE;
625 		if (signum!=SIGKILL) {
626 			accessrights=PROCESS_CREATE_THREAD|
627 					PROCESS_QUERY_INFORMATION|
628 					PROCESS_VM_OPERATION|
629 					PROCESS_VM_WRITE|
630 					PROCESS_VM_READ;
631 		}
632 
633 		// open the target process
634 		HANDLE	targetprocess=OpenProcess(accessrights,FALSE,processid);
635 		if (!targetprocess) {
636 			return false;
637 		}
638 
639 		// for SIGKILL we just need to call TerminateProcess
640 		if (signum==SIGKILL) {
641 			bool	result=(TerminateProcess(targetprocess,1)!=0);
642 			CloseHandle(targetprocess);
643 			return result;
644 		}
645 
646 		// For SIGABRT, SIGFPE, SIGILL and SIGSEGV we can trigger the
647 		// target process' unhandled exception filter by creating a
648 		// thread aimed at NULL.
649 		if (signum==SIGABRT || signum==SIGFPE ||
650 				signum==SIGILL || signum==SIGSEGV) {
651 			HANDLE	otherthread=
652 				CreateRemoteThread(targetprocess,
653 						NULL,0,
654 						(LPTHREAD_START_ROUTINE)NULL,
655 						NULL,0,NULL);
656 			if (otherthread) {
657 				CloseHandle(otherthread);
658 			}
659 			CloseHandle(targetprocess);
660 			return otherthread!=NULL;
661 		}
662 
663 		// For SIGINT/SIGTERM, it gets a lot crazier...
664 
665 		// Yes, the ridiculousness below is the only "reasonable"
666 		// way to do this...
667 
668 		// First... SIGINT is really CTRL-C, but processes created with
669 		// the CREATE_NEW_PROCESS_GROUP flag don't respond to CTRL-C.
670 		// All processes respond to CTRL-BREAK though, so we need to
671 		// use that instead.
672 
673 		// Ideally for SIGINT/SIGTERM we'd just run
674 		// GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,processid) but that
675 		// only works if the calling process is in the same process
676 		// group as processid (ie. a parent or child of processid).
677 		//
678 		// So, we need to somehow coerce a process or thread in the
679 		// target process group to run it for us.  We can create a new
680 		// thread in the target process using CreateRemoteThread.
681 		//
682 		// Ideally we'd just tell it to run
683 		// GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0) but
684 		// CreateRemoteThread only allows you to pass one argument
685 		// to the function that it runs and we need to pass two.
686 		//
687 		// The only "obvious" way to do this is to do define a chunk
688 		// of memory containing the machine code for a function that
689 		// runs GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,0) and copy it
690 		// over to the target process.
691  		//
692 		// Then we can create a thread over there and aim the thread at
693 		// our function.
694 
695 		// this only works on x86 and x64, so bail right away if
696 		// this isn't one of those platforms
697 		char	*arch=sys::getOperatingSystemArchitecture();
698 		if (!charstring::compare(arch,"Unknown")) {
699 			return false;
700 		}
701 
702 		// Get the address of GenerateConsoleCtrlEvent in kernel32.dll.
703 		// kernel32.dll is loaded at the same address for all programs,
704 		// so the address of this function ought to be the same in
705 		// the target process as it is here.
706 		HMODULE	kernel32=GetModuleHandle("Kernel32");
707 		if (!kernel32) {
708 			return false;
709 		}
710 		FARPROC	funcaddr=GetProcAddress(kernel32,
711 						"GenerateConsoleCtrlEvent");
712 		if (!funcaddr) {
713 			return false;
714 		}
715 
716 		// Define a chunk of memory containing the machine code for
717 		// a function that runs GenerateConsoleCtrlEvent with two
718 		// parameters (with values of 0).  Eventually this code will
719 		// be run in the target process...
720 		//
721 		// helpful site:
722 		// https://defuse.ca/online-x86-assembler.htm
723 
724 		const unsigned char	*updatedmachinecode=NULL;
725 		size_t			machinecodesize=0;
726 
727 		// FIXME: use better method of detecting x86 vs. x64
728 		#ifdef _USE_32BIT_TIME_T
729 
730 			// for x86:
731 			const unsigned char	machinecode32[]={
732 				// load second parameter (0)
733 				// (we'll overwrite this in a minute)
734 				0x68,			// push (word)
735 				0x0,0x0,0x0,0x0,	// 0
736 				// load first parameter (1)
737 				0x6A,			// push (byte)
738 				0x1,			// 1
739 				// load the absolute address of the function to
740 				// call (for now use 0, we'll overwrite this in
741 				// a minute)
742 				0xB8,			// mov eax
743 				0x0,0x0,0x0,0x0,	// 0
744 				// call the function
745 				0xFF,0xD0,		// call eax
746 				// return 1
747 				0xB8,			// mov eax
748 				0x1,0x0,0x0,0x0,	// 1
749 				// return
750 				0xC3			// ret
751 			};
752 			size_t		machinecode32size=sizeof(machinecode32);
753 
754 			// copy the code into a buffer and
755 			// replace the second parameter and call address
756 			unsigned char		*updatedmachinecode32=
757 				(unsigned char *)bytestring::duplicate(
758 							machinecode32,
759 							machinecode32size);
760 
761 			uint32_t	*addr=
762 				(uint32_t *)(updatedmachinecode32+1);
763 			*addr=(uint32_t)processid;
764 
765 			addr=(uint32_t *)(updatedmachinecode32+8);
766 			*addr=(uint32_t)funcaddr;
767 
768 			updatedmachinecode=updatedmachinecode32;
769 			machinecodesize=machinecode32size;
770 
771 		#else
772 
773 			// for x64:
774 			const unsigned char	machinecode64[]={
775 				// allocate shadow space of 32 bytes on the
776 				// stack and align it to 16 bytes
777 				0x48,0x83,0xEC,		// sub rsp
778 				0x28,			// 0x28
779 				// load second parameter (0)
780 				// (we'll overwrite this in a minute)
781 				0x48,0xC7,0xC2,		// mov rdx
782 				0x00,0x00,0x00,0x00,	// 0
783 				// load first parameter (0)
784 				0x48,0xC7,0xC1,		// mov rcx
785 				0x01,0x00,0x00,0x00,	// 1
786 				// load the absolute address of the function to
787 				// call (for now use 0, we'll overwrite this in
788 				// a minute)
789 				0x49,0xBA,		// movabs r10
790 				0x00,0x00,0x00,0x00,	// 0
791 				0x00,0x00,0x00,0x00,	// 0 (64-bit)
792 				// call the function
793 				0x41,0xFF,0xD2,		// call r10
794 				// return 1
795 				0x48,0xC7,0xC0,		// mov rax
796 				0x01,0x00,0x00,0x00,	// 1
797 				// deallocate the shadow space
798 				// and align the stack to 16 bytes
799 				0x48,0x83,0xC4,		// add rsp
800 				0x28,			// 0x28
801 				// return
802 				0xC3			// retq
803 			};
804 			size_t		machinecode64size=sizeof(machinecode64);
805 
806 			// copy the code into a buffer and
807 			// replace the second parameter and call address
808 			unsigned char		*updatedmachinecode64=
809 				(unsigned char *)bytestring::duplicate(
810 							machinecode64,
811 							machinecode64size);
812 
813 			uint32_t	*addr32=
814 				(uint32_t *)(updatedmachinecode64+7);
815 			*addr32=(uint32_t)processid;
816 
817 			uint64_t	*addr64=
818 				(uint64_t *)(updatedmachinecode64+20);
819 			*addr64=(uint64_t)funcaddr;
820 
821 			updatedmachinecode=updatedmachinecode64;
822 			machinecodesize=machinecode64size;
823 		#endif
824 
825 		// allocate memory in the target process to copy the
826 		// machine code into
827 		void	*codetorun=VirtualAllocEx(targetprocess,
828 						NULL,machinecodesize,
829 						MEM_COMMIT,
830 						PAGE_EXECUTE_READWRITE);
831 		if (!codetorun) {
832 			CloseHandle(targetprocess);
833 			return false;
834 		}
835 
836 		// copy the machine code over to the target process
837 		if (!WriteProcessMemory(targetprocess,
838 						codetorun,
839 						updatedmachinecode,
840 						machinecodesize,
841 						NULL)) {
842 			CloseHandle(targetprocess);
843 			return false;
844 		}
845 
846 		// create a thread in the target process and aim it at
847 		// the machine code we passed over there
848 		HANDLE	otherthread=
849 			CreateRemoteThread(targetprocess,
850 					NULL,0,
851 					(LPTHREAD_START_ROUTINE)codetorun,
852 					NULL,0,NULL);
853 		if (!otherthread) {
854 			CloseHandle(targetprocess);
855 			return false;
856 		}
857 
858 		// wait for the thread to finish running
859 		WaitForSingleObject(otherthread,INFINITE);
860 
861 		// clean up
862 		VirtualFreeEx(targetprocess,codetorun,0,MEM_RELEASE);
863 		CloseHandle(otherthread);
864 		CloseHandle(targetprocess);
865 
866 		return true;
867 	#else
868 		RUDIMENTS_SET_ENOSYS
869 		return false;
870 	#endif
871 }
872 
raiseSignal(int32_t signum)873 bool process::raiseSignal(int32_t signum) {
874 	#if defined(RUDIMENTS_HAVE_GENERATECONSOLECTRLEVENT)
875 		switch (signum) {
876 			case SIGINT:
877 			case SIGTERM:
878 				// SIGINT is really CTRL-C, but processes
879 				// created with the CREATE_NEW_PROCESS_GROUP
880 				// flag don't respond to CTRL-C.  All processes
881 				// respond to CTRL-BREAK though, so we need to
882 				// use that instead.
883 				if (GenerateConsoleCtrlEvent(
884 						CTRL_BREAK_EVENT,0)) {
885 					return true;
886 				}
887 			case SIGKILL:
888 				if (TerminateProcess(
889 						INVALID_HANDLE_VALUE,1)) {
890 					return true;
891 				}
892 			case SIGFPE:
893 				{
894 					// crash on purpose
895 					uint16_t	a=1;
896 					uint16_t	b=0;
897 					uint16_t	c=a/b;
898 				}
899 			case SIGABRT:
900 			case SIGILL:
901 			case SIGSEGV:
902 				{
903 					// crash on purpose
904 					void (*f)(void)=NULL;
905 					f();
906 				}
907 		}
908 		return false;
909 	#elif defined(RUDIMENTS_HAVE_RAISE)
910 		int32_t	result;
911 		error::clearError();
912 		do {
913 			result=raise(signum);
914 		} while (result==-1 && error::getErrorNumber()==EINTR);
915 		return !result;
916 	#else
917 		RUDIMENTS_SET_ENOSYS
918 		return false;
919 	#endif
920 }
921 
atExit(void (* function)(void))922 bool process::atExit(void (*function)(void)) {
923 	#ifdef RUDIMENTS_HAVE_ATEXIT
924 		return !atexit(function);
925 	#else
926 		return false;
927 	#endif
928 }
929 
createPidFile(const char * filename,mode_t permissions)930 bool process::createPidFile(const char *filename, mode_t permissions) {
931 	char	*pid=charstring::parseNumber((uint64_t)process::getProcessId());
932 	file	pidfile;
933 	bool	retval=(pidfile.create(filename,permissions) &&
934 			pidfile.write(pid)==(ssize_t)charstring::length(pid));
935 	delete[] pid;
936 	return retval;
937 }
938 
checkForPidFile(const char * filename)939 int64_t process::checkForPidFile(const char *filename) {
940 	char	*pidstring=file::getContents(filename);
941 	int64_t	retval=(pidstring && pidstring[0])?
942 				charstring::toInteger(pidstring):-1;
943 	delete[] pidstring;
944 	return retval;
945 }
946 
exitOnCrashOrShutDown()947 void process::exitOnCrashOrShutDown() {
948 	exitOnShutDown();
949 	exitOnCrash();
950 }
951 
exitOnShutDown()952 void process::exitOnShutDown() {
953 	_shutdownhandler.setHandler(defaultShutDown);
954 	_shutdownhandler.handleSignal(SIGINT);
955 	_shutdownhandler.handleSignal(SIGTERM);
956 	#ifdef SIGQUIT
957 	_shutdownhandler.handleSignal(SIGQUIT);
958 	#endif
959 	#ifdef SIGHUP
960 	_shutdownhandler.handleSignal(SIGHUP);
961 	#endif
962 }
963 
handleShutDown(void (* shutdownfunction)(int32_t))964 void process::handleShutDown(void (*shutdownfunction)(int32_t)) {
965 	_shutdownfunc=shutdownfunction;
966 	_shutdownhandler.setHandler(shutDown);
967 	_shutdownhandler.handleSignal(SIGINT);
968 	_shutdownhandler.handleSignal(SIGTERM);
969 	#ifdef SIGQUIT
970 	_shutdownhandler.handleSignal(SIGQUIT);
971 	#endif
972 	#ifdef SIGHUP
973 	_shutdownhandler.handleSignal(SIGHUP);
974 	#endif
975 }
976 
exitOnCrash()977 void process::exitOnCrash() {
978 	_crashhandler.setHandler(defaultCrash);
979 	_crashhandler.handleSignal(SIGABRT);
980 	_crashhandler.handleSignal(SIGFPE);
981 	_crashhandler.handleSignal(SIGILL);
982 	_crashhandler.handleSignal(SIGSEGV);
983 	#ifdef SIGBUS
984 	_crashhandler.handleSignal(SIGBUS);
985 	#endif
986 	#ifdef SIGIOT
987 	_crashhandler.handleSignal(SIGIOT);
988 	#endif
989 	#ifdef SIGEMT
990 	_crashhandler.handleSignal(SIGEMT);
991 	#endif
992 	#ifdef SIGSYS
993 	_crashhandler.handleSignal(SIGSYS);
994 	#endif
995 }
996 
handleCrash(void (* crashfunction)(int32_t))997 void process::handleCrash(void (*crashfunction)(int32_t)) {
998 	_crashfunc=crashfunction;
999 	_crashhandler.setHandler(crash);
1000 	_crashhandler.handleSignal(SIGABRT);
1001 	_crashhandler.handleSignal(SIGFPE);
1002 	_crashhandler.handleSignal(SIGILL);
1003 	_crashhandler.handleSignal(SIGSEGV);
1004 	#ifdef SIGBUS
1005 	_crashhandler.handleSignal(SIGBUS);
1006 	#endif
1007 	#ifdef SIGIOT
1008 	_crashhandler.handleSignal(SIGIOT);
1009 	#endif
1010 	#ifdef SIGEMT
1011 	_crashhandler.handleSignal(SIGEMT);
1012 	#endif
1013 	#ifdef SIGSYS
1014 	_crashhandler.handleSignal(SIGSYS);
1015 	#endif
1016 }
1017 
waitForChildren()1018 void process::waitForChildren() {
1019 	#ifdef SIGCHLD
1020 		_deadchildhandler.setHandler(waitForChildrenToExit);
1021 		_deadchildhandler.addFlag(SA_NOCLDSTOP);
1022 		_deadchildhandler.handleSignal(SIGCHLD);
1023 	#endif
1024 }
1025 
dontWaitForChildren()1026 void process::dontWaitForChildren() {
1027 	#ifdef SIGCHLD
1028 		_deadchildhandler.setHandler((void (*)(int32_t))SIG_DFL);
1029 		_deadchildhandler.removeAllFlags();
1030 		_deadchildhandler.handleSignal(SIGCHLD);
1031 	#endif
1032 }
1033 
shutDown(int32_t signum)1034 void process::shutDown(int32_t signum) {
1035 	(*_shutdownfunc)(signum);
1036 }
1037 
crash(int32_t signum)1038 void process::crash(int32_t signum) {
1039 	(*_crashfunc)(signum);
1040 }
1041 
defaultShutDown(int32_t signum)1042 void process::defaultShutDown(int32_t signum) {
1043 	process::exit(0);
1044 }
1045 
defaultCrash(int32_t signum)1046 void process::defaultCrash(int32_t signum) {
1047 	process::exit(1);
1048 }
1049 
waitForChildrenToExit(int32_t signum)1050 void process::waitForChildrenToExit(int32_t signum) {
1051 
1052 	// Some systems generate a single SIGCHLD even if more than 1 child
1053 	// has entered it's exit state, so we need to loop here and catch
1054 	// all of them.
1055 
1056 	// If getChildStateChange returns 0 then there were no more
1057 	// processes in their exit state, the loop should exit.
1058 	// If it returns > 0 then it successfully waited on a process and it
1059 	// should loop back to wait on another one.
1060 	// If it returns -1 then there was some error and the loop should exit.
1061 	do {} while (getChildStateChange(-1,false,true,true,
1062 						NULL,NULL,NULL,NULL)>0);
1063 
1064 	// FIXME: What if a SIGCHLD gets generated after waitpid() has returned
1065 	// but before the signal handler exits?   Will that SIGCHLD be lost?
1066 
1067 	// Since we didn't use the SA_ONESHOT flag when we set up this signal
1068 	// handler, we don't need to reinstall the signal handler here, it will
1069 	// be done automatically.
1070 }
1071 
wait(pid_t pid)1072 bool process::wait(pid_t pid) {
1073 	return wait(pid,NULL);
1074 }
1075 
wait(pid_t pid,int32_t * exitstatus)1076 bool process::wait(pid_t pid, int32_t *exitstatus) {
1077 #ifdef _WIN32
1078 	HANDLE	h=OpenProcess(SYNCHRONIZE,TRUE,pid);
1079 	if (!h) {
1080 		return false;
1081 	}
1082 
1083 	bool	retval=(WaitForSingleObject(h,INFINITE)==WAIT_OBJECT_0);
1084 
1085 	if (retval && exitstatus) {
1086 		DWORD	status;
1087 		if (GetExitCodeProcess(h,&status)) {
1088 			*exitstatus=status;
1089 		} else {
1090 			retval=false;
1091 		}
1092 	}
1093 
1094 	CloseHandle(h);
1095 
1096 	return retval;
1097 #else
1098 	return (getChildStateChange(pid,true,true,true,
1099 					NULL,exitstatus,NULL,NULL)==pid);
1100 #endif
1101 }
1102 
getChildStateChange(pid_t pid,bool wait,bool ignorestop,bool ignorecontinue,childstatechange * newstate,int32_t * exitstatus,int32_t * signum,bool * coredump)1103 pid_t process::getChildStateChange(pid_t pid,
1104 					bool wait,
1105 					bool ignorestop,
1106 					bool ignorecontinue,
1107 					childstatechange *newstate,
1108 					int32_t	*exitstatus,
1109 					int32_t *signum,
1110 					bool *coredump) {
1111 #ifdef _WIN32
1112 	RUDIMENTS_SET_ENOSYS
1113 	return -1;
1114 #else
1115 
1116 	// build options
1117 	int32_t	options=0;
1118 	if (!wait) {
1119 		options|=WNOHANG;
1120 	}
1121 	if (!ignorestop) {
1122 		options|=WUNTRACED;
1123 	}
1124 	if (!ignorecontinue) {
1125 		#ifdef WCONTINUED
1126 		options|=WCONTINUED;
1127 		#endif
1128 	}
1129 
1130 	// init status
1131 	int32_t	status=0;
1132 
1133 	// wait
1134 	int32_t	childpid=-1;
1135 	error::clearError();
1136 	do {
1137 		// Minix 3.1.8 needs the int * cast
1138 		childpid=waitpid(pid,(int *)&status,options);
1139 	} while (childpid==-1 && error::getErrorNumber()==EINTR);
1140 
1141 	// set return values
1142 	if (childpid>0 && newstate) {
1143 		if (WIFEXITED(status)) {
1144 			*newstate=EXIT_CHILDSTATECHANGE;
1145 			if (exitstatus) {
1146 				*exitstatus=WEXITSTATUS(status);
1147 			}
1148 		} else if (WIFSIGNALED(status)) {
1149 			*newstate=TERMINATED_CHILDSTATECHANGE;
1150 			if (signum) {
1151 				*signum=WTERMSIG(status);
1152 			}
1153 			#ifdef WCOREDUMP
1154 			if (coredump) {
1155 				*coredump=WCOREDUMP(status);
1156 			}
1157 			#endif
1158 		} else if (WIFSTOPPED(status)) {
1159 			*newstate=STOPPED_CHILDSTATECHANGE;
1160 			if (signum) {
1161 				*signum=WSTOPSIG(status);
1162 			}
1163 		#ifdef WIFCONTINUED
1164 		} else if (WIFCONTINUED(status)) {
1165 			*newstate=CONTINUED_CHILDSTATECHANGE;
1166 		#endif
1167 		}
1168 	}
1169 
1170 	return childpid;
1171 #endif
1172 }
1173 
supportsGetChildStateChange()1174 bool process::supportsGetChildStateChange() {
1175 	#ifdef _WIN32
1176 		return false;
1177 	#else
1178 		return true;
1179 	#endif
1180 }
1181 
retryFailedFork()1182 void process::retryFailedFork() {
1183 	_retry=true;
1184 }
1185 
dontRetryFailedFork()1186 void process::dontRetryFailedFork() {
1187 	_retry=false;
1188 }
1189 
getRetryFailedFork()1190 bool process::getRetryFailedFork() {
1191 	return _retry;
1192 }
1193 
backtrace(output * out,uint32_t maxframes)1194 void process::backtrace(output *out, uint32_t maxframes) {
1195 	#if defined(RUDIMENTS_HAVE_BACKTRACE)
1196 		unsigned char	**btarray=new unsigned char *[maxframes];
1197 		size_t	btsize=::backtrace((void **)btarray,(int)maxframes);
1198 		char	**btstrings=backtrace_symbols((void **)btarray,btsize);
1199 		for (size_t i=0; i<btsize; i++) {
1200 			out->write(btstrings[i]);
1201 			out->write('\n');
1202 		}
1203 		delete[] btstrings;
1204 		delete[] btarray;
1205 	#elif defined(RUDIMENTS_HAVE_CAPTURESTACKBACKTRACE) && \
1206 						_WIN32_WINVER >= 0x0600
1207 		// CaptureStackBackTrace not supported prior to Vista
1208 		HANDLE	process=GetCurrentProcess();
1209 		if (!SymInitialize(process,NULL,TRUE)) {
1210 			return;
1211 		}
1212 		void	**btarray=(void **)malloc(maxframes*sizeof(void *));
1213 		WORD btsize=CaptureStackBackTrace(0,128,btarray,NULL);
1214 		SYMBOL_INFO	*symbolinfo=(SYMBOL_INFO *)
1215 					malloc(sizeof(SYMBOL_INFO)+
1216 						(1024*sizeof(TCHAR)));
1217 		symbolinfo->MaxNameLen=1023;
1218 		symbolinfo->SizeOfStruct=sizeof(SYMBOL_INFO);
1219 		IMAGEHLP_LINE64	*line=(IMAGEHLP_LINE64 *)
1220 					malloc(sizeof(IMAGEHLP_LINE64));
1221 		line->SizeOfStruct=sizeof(IMAGEHLP_LINE64);
1222 		DWORD	displacement;
1223 		for (WORD i=0; i<btsize; i++) {
1224 			if (SymFromAddr(process,(DWORD64)btarray[i],
1225 							NULL,symbolinfo)) {
1226 				output->write("\?\?\?(");
1227 				output->write(symbolinfo->Name);
1228 				output->write(")[0x");
1229 				output->write(symbolinfo->Address);
1230 				output->write("]\n");
1231 			}
1232 		}
1233 		free(line);
1234 		free(symbolinfo);
1235 		free(btarray);
1236 	#endif
1237 }
1238 
backtrace(output * out)1239 void process::backtrace(output *out) {
1240 	backtrace(out,128);
1241 }
1242 
backtrace(const char * filename)1243 void process::backtrace(const char *filename) {
1244 	backtrace(filename,permissions::evalPermString("rw-------"),128);
1245 }
1246 
backtrace(const char * filename,mode_t perms,uint32_t maxframes)1247 void process::backtrace(const char *filename,
1248 				mode_t perms,
1249 				uint32_t maxframes) {
1250 	file	f;
1251 	if (f.open(filename,O_WRONLY|O_APPEND|O_CREAT,perms)) {
1252 		backtrace(&f,maxframes);
1253 	}
1254 }
1255