1 // SoftEther VPN Source Code - Developer Edition Master Branch
2 // Mayaqua Kernel
3 
4 
5 // Unix.c
6 // UNIX dependent code
7 
8 #ifdef	OS_UNIX
9 
10 #include "Unix.h"
11 
12 #include "Cfg.h"
13 #include "FileIO.h"
14 #include "GlobalConst.h"
15 #include "Internat.h"
16 #include "Kernel.h"
17 #include "Mayaqua.h"
18 #include "Memory.h"
19 #include "Network.h"
20 #include "Object.h"
21 #include "Str.h"
22 #include "Table.h"
23 #include "Tick64.h"
24 
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include <dirent.h>
31 #include <fcntl.h>
32 #include <poll.h>
33 #include <pthread.h>
34 #include <signal.h>
35 
36 #include <sys/mount.h>
37 #include <sys/param.h>
38 #include <sys/resource.h>
39 #include <sys/stat.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/utsname.h>
43 #include <sys/wait.h>
44 
45 #ifdef UNIX_LINUX
46 #include <sys/statfs.h>
47 #endif
48 
49 #ifdef	UNIX_MACOS
50 #ifdef	NO_VLAN
51 // Struct statfs for MacOS X
52 typedef struct fsid { int32_t val[2]; } fsid_t;
53 struct statfs {
54         short   f_otype;                /* TEMPORARY SHADOW COPY OF f_type */
55         short   f_oflags;               /* TEMPORARY SHADOW COPY OF f_flags */
56         long    f_bsize;                /* fundamental file system block size */
57         long    f_iosize;               /* optimal transfer block size */
58         long    f_blocks;               /* total data blocks in file system */
59         long    f_bfree;                /* free blocks in fs */
60         long    f_bavail;               /* free blocks avail to non-superuser */
61         long    f_files;                /* total file nodes in file system */
62         long    f_ffree;                /* free file nodes in fs */
63         fsid_t  f_fsid;                 /* file system id */
64         uid_t   f_owner;                /* user that mounted the filesystem */
65         short   f_reserved1;    /* spare for later */
66         short   f_type;                 /* type of filesystem */
67     long        f_flags;                /* copy of mount exported flags */
68         long    f_reserved2[2]; /* reserved for future use */
69         char    f_fstypename[15]; /* fs type name */
70         char    f_mntonname[90];  /* directory on which mounted */
71         char    f_mntfromname[90];/* mounted filesystem */
72 };
73 #else	// NO_VLAN
74 #include <sys/mount.h>
75 #endif	// NO_VLAN
76 #endif	// UNIX_MACOS
77 
78 // Scandir() function for Solaris
79 #ifdef	UNIX_SOLARIS
80 #define scandir local_scandir
81 #define	alphasort local_alphasort
82 
local_scandir(const char * dir,struct dirent *** namelist,int (* select)(const struct dirent *),int (* compar)(const struct dirent **,const struct dirent **))83 int local_scandir(const char *dir, struct dirent ***namelist,
84             int (*select)(const struct dirent *),
85             int (*compar)(const struct dirent **, const struct dirent **))
86 {
87   DIR *d;
88   struct dirent *entry;
89   register int i=0;
90   size_t entrysize;
91 
92   if ((d=opendir(dir)) == NULL)
93      return(-1);
94 
95   *namelist=NULL;
96   while ((entry=readdir(d)) != NULL)
97   {
98     if (select == NULL || (*select)(entry))
99     {
100       *namelist=(struct dirent **)realloc((void *)(*namelist),
101                  (size_t)((i+1)*sizeof(struct dirent *)));
102 	if (*namelist == NULL) return(-1);
103 	entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
104 	(*namelist)[i]=(struct dirent *)malloc(entrysize);
105 	if ((*namelist)[i] == NULL) return(-1);
106 	memcpy((*namelist)[i], entry, entrysize);
107 	i++;
108     }
109   }
110   if (closedir(d)) return(-1);
111   if (i == 0) return(-1);
112   if (compar != NULL)
113     qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
114 
115   return(i);
116 }
117 
local_alphasort(const struct dirent ** a,const struct dirent ** b)118 int local_alphasort(const struct dirent **a, const struct dirent **b)
119 {
120   return(strcmp((*a)->d_name, (*b)->d_name));
121 }
122 
123 
124 #endif	// UNIX_SOLARIS
125 
126 // Thread data for UNIX
127 typedef struct UNIXTHREAD
128 {
129 	pthread_t thread;
130 	bool finished;
131 } UNIXTHREAD;
132 
133 // Thread startup information for UNIX
134 typedef struct UNIXTHREADSTARTUPINFO
135 {
136 	THREAD_PROC *thread_proc;
137 	void *param;
138 	THREAD *thread;
139 } UNIXTHREADSTARTUPINFO;
140 
141 // Thread function prototype for UNIX
142 void *UnixDefaultThreadProc(void *param);
143 
144 // Current process ID
145 static pid_t current_process_id = 0;
146 
147 // File I/O data for UNIX
148 typedef struct UNIXIO
149 {
150 	int fd;
151 	bool write_mode;
152 } UNIXIO;
153 
154 // Lock file data for UNIX
155 typedef struct UNIXLOCKFILE
156 {
157 	char FileName[MAX_SIZE];
158 	int fd;
159 } UNIXLOCKFILE;
160 
161 // Event data for UNIX
162 typedef struct UNIXEVENT
163 {
164 	pthread_mutex_t mutex;
165 	pthread_cond_t cond;
166 	bool signal;
167 } UNIXEVENT;
168 
169 static pthread_mutex_t get_time_lock;
170 static pthread_mutex_t malloc_lock;
171 static bool high_process = false;
172 
173 static bool unix_svc_terminate = false;
174 static int solaris_sleep_p1 = -1, solaris_sleep_p2 = -1;
175 
176 // Create a dispatch table
UnixGetDispatchTable()177 OS_DISPATCH_TABLE *UnixGetDispatchTable()
178 {
179 	static OS_DISPATCH_TABLE t =
180 	{
181 		UnixInit,
182 		UnixFree,
183 		UnixMemoryAlloc,
184 		UnixMemoryReAlloc,
185 		UnixMemoryFree,
186 		UnixGetTick,
187 		UnixGetSystemTime,
188 		UnixInc32,
189 		UnixDec32,
190 		UnixSleep,
191 		UnixNewLock,
192 		UnixLock,
193 		UnixUnlock,
194 		UnixDeleteLock,
195 		UnixInitEvent,
196 		UnixSetEvent,
197 		UnixResetEvent,
198 		UnixWaitEvent,
199 		UnixFreeEvent,
200 		UnixWaitThread,
201 		UnixFreeThread,
202 		UnixInitThread,
203 		UnixThreadId,
204 		UnixFileOpen,
205 		UnixFileOpenW,
206 		UnixFileCreate,
207 		UnixFileCreateW,
208 		UnixFileWrite,
209 		UnixFileRead,
210 		UnixFileClose,
211 		UnixFileFlush,
212 		UnixFileSize,
213 		UnixFileSeek,
214 		UnixFileDelete,
215 		UnixFileDeleteW,
216 		UnixMakeDir,
217 		UnixMakeDirW,
218 		UnixDeleteDir,
219 		UnixDeleteDirW,
220 		UnixGetCallStack,
221 		UnixGetCallStackSymbolInfo,
222 		UnixFileRename,
223 		UnixFileRenameW,
224 		UnixRun,
225 		UnixRunW,
226 		UnixIsSupportedOs,
227 		UnixGetOsInfo,
228 		UnixAlert,
229 		UnixAlertW,
230 		UnixGetProductId,
231 		UnixSetHighPriority,
232 		UnixRestorePriority,
233 		UnixNewSingleInstance,
234 		UnixFreeSingleInstance,
235 		UnixGetMemInfo,
236 		UnixYield,
237 	};
238 
239 	return &t;
240 }
241 
signal_received_for_ignore(int sig,siginfo_t * info,void * ucontext)242 static void *signal_received_for_ignore(int sig, siginfo_t *info, void *ucontext)
243 {
244 	return NULL;
245 }
246 
247 // Ignore the signal flew to the thread
UnixIgnoreSignalForThread(int sig)248 void UnixIgnoreSignalForThread(int sig)
249 {
250 	struct sigaction sa;
251 
252 	Zero(&sa, sizeof(sa));
253 	sa.sa_handler = NULL;
254 	sa.sa_sigaction = signal_received_for_ignore;
255 	sa.sa_flags = SA_SIGINFO;
256 
257 	sigemptyset(&sa.sa_mask);
258 
259 	sigaction(SIGUSR1, &sa, NULL);
260 }
261 
262 // Disable the off-loading function of the specific Ethernet device
UnixDisableInterfaceOffload(char * name)263 void UnixDisableInterfaceOffload(char *name)
264 {
265 #ifdef	UNIX_LINUX
266 	char tmp[MAX_SIZE];
267 	TOKEN_LIST *t;
268 	char *names = "rx tx sg tso ufo gso gro lro rxvlan txvlan ntuple rxhash";
269 	// Validate arguments
270 	if (name == NULL)
271 	{
272 		return;
273 	}
274 
275 	t = ParseToken(names, " ");
276 
277 	if (t != NULL)
278 	{
279 		UINT i;
280 		for (i = 0;i < t->NumTokens;i++)
281 		{
282 			char *a = t->Token[i];
283 
284 			Format(tmp, sizeof(tmp), "ethtool -K %s %s off 2>/dev/null", name, a);
285 			FreeToken(UnixExec(tmp));
286 		}
287 	}
288 
289 	FreeToken(t);
290 #endif	// UNIX_LINUX
291 }
292 
293 // Validate whether the UNIX is running in a VM
UnixIsInVmMain()294 bool UnixIsInVmMain()
295 {
296 	TOKEN_LIST *t = NULL;
297 	bool ret = false;
298 	char *vm_str_list = "Hypervisor detected,VMware Virtual Platform,VMware Virtual USB,qemu,xen,paravirtualized,virtual hd,virtualhd,virtual pc,virtualpc,kvm,oracle vm,oraclevm,parallels,xvm,bochs";
299 
300 #ifdef	UNIX_LINUX
301 	t = UnixExec("/bin/dmesg");
302 
303 	if (t != NULL)
304 	{
305 		BUF *b = NewBuf();
306 		UINT i;
307 
308 		for (i = 0;i < t->NumTokens;i++)
309 		{
310 			char *line = t->Token[i];
311 
312 			AddBufStr(b, line);
313 			AddBufStr(b, " ");
314 		}
315 
316 		WriteBufInt(b, 0);
317 
318 //		printf("%s\n", b->Buf);
319 
320 		ret = InStrList(b->Buf, vm_str_list, ",", false);
321 
322 		FreeBuf(b);
323 		FreeToken(t);
324 	}
325 #endif	// UNIX_LINUX
326 
327 	return ret;
328 }
UnixIsInVm()329 bool UnixIsInVm()
330 {
331 	static bool is_in_vm_flag = false;
332 	static bool is_in_vm_ret = false;
333 
334 	if (is_in_vm_flag == false)
335 	{
336 		is_in_vm_ret = UnixIsInVmMain();
337 		is_in_vm_flag = true;
338 	}
339 
340 	return is_in_vm_ret;
341 }
342 
343 // Run quietly in the UNIX
UnixExecSilent(char * cmd)344 void UnixExecSilent(char *cmd)
345 {
346 	char tmp[MAX_SIZE];
347 	// Validate arguments
348 	if (cmd == NULL)
349 	{
350 		return;
351 	}
352 
353 	Format(tmp, sizeof(tmp), "%s 2>/dev/null", cmd);
354 
355 	FreeToken(UnixExec(tmp));
356 }
357 
358 // Enable / disable the ESP processing in the kernel
UnixSetEnableKernelEspProcessing(bool b)359 void UnixSetEnableKernelEspProcessing(bool b)
360 {
361 	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
362 	{
363 		// Mac OS X
364 		if (b)
365 		{
366 			UnixExecSilent("/usr/sbin/sysctl -w net.inet.ipsec.esp_port=4500");
367 		}
368 		else
369 		{
370 			UnixExecSilent("/usr/sbin/sysctl -w net.inet.ipsec.esp_port=4501");
371 		}
372 	}
373 }
374 
375 // Run a command and return its result
UnixExec(char * cmd)376 TOKEN_LIST *UnixExec(char *cmd)
377 {
378 	FILE *fp;
379 	char tmp[MAX_SIZE];
380 	char *ptr;
381 	LIST *o;
382 	UINT i;
383 	TOKEN_LIST *ret;
384 	// Validate arguments
385 	if (cmd == NULL)
386 	{
387 		return NULL;
388 	}
389 
390 	fp = popen(cmd, "r");
391 	if (fp == NULL)
392 	{
393 		return NULL;
394 	}
395 
396 	o = NewList(NULL);
397 
398 	while (true)
399 	{
400 		fgets(tmp, sizeof(tmp), fp);
401 		if (feof(fp))
402 		{
403 			break;
404 		}
405 
406 		ptr = strchr(tmp, '\n');
407 		if (ptr != NULL)
408 		{
409 			*ptr = 0;
410 		}
411 
412 		ptr = strchr(tmp, '\r');
413 		if (ptr != NULL)
414 		{
415 			*ptr = 0;
416 		}
417 
418 		Add(o, CopyStr(tmp));
419 	}
420 
421 	pclose(fp);
422 
423 	ret = ListToTokenList(o);
424 
425 	FreeStrList(o);
426 
427 	return ret;
428 }
429 
430 // Initialize the Sleep for Solaris
UnixInitSolarisSleep()431 void UnixInitSolarisSleep()
432 {
433 	char tmp[MAX_SIZE];
434 
435 	UnixNewPipe(&solaris_sleep_p1, &solaris_sleep_p2);
436 	(void)read(solaris_sleep_p1, tmp, sizeof(tmp));
437 }
438 
439 // Release the Sleep for Solaris
UnixFreeSolarisSleep()440 void UnixFreeSolarisSleep()
441 {
442 	UnixDeletePipe(solaris_sleep_p1, solaris_sleep_p2);
443 	solaris_sleep_p1 = -1;
444 	solaris_sleep_p2 = -1;
445 }
446 
447 // Sleep for Solaris
UnixSolarisSleep(UINT msec)448 void UnixSolarisSleep(UINT msec)
449 {
450 	struct pollfd p;
451 
452 	memset(&p, 0, sizeof(p));
453 	p.fd = solaris_sleep_p1;
454 	p.events = POLLIN;
455 
456 	(void)poll(&p, 1, msec == INFINITE ? -1 : (int)msec);
457 }
458 
459 // Get the free space of the disk
UnixGetDiskFree(char * path,UINT64 * free_size,UINT64 * used_size,UINT64 * total_size)460 bool UnixGetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
461 {
462 	char tmp[MAX_PATH];
463 	bool ret = false;
464 	// Validate arguments
465 	if (path == NULL)
466 	{
467 		return false;
468 	}
469 
470 	NormalizePath(tmp, sizeof(tmp), path);
471 
472 	while ((ret = UnixGetDiskFreeMain(tmp, free_size, used_size, total_size)) == false)
473 	{
474 		if (StrCmpi(tmp, "/") == 0)
475 		{
476 			break;
477 		}
478 
479 		GetDirNameFromFilePath(tmp, sizeof(tmp), tmp);
480 	}
481 
482 	return ret;
483 }
UnixGetDiskFreeMain(char * path,UINT64 * free_size,UINT64 * used_size,UINT64 * total_size)484 bool UnixGetDiskFreeMain(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
485 {
486 #ifndef	USE_STATVFS
487 	struct statfs st;
488 	char tmp[MAX_PATH];
489 	UINT64 v1 = 0, v2 = 0;
490 	bool ret = false;
491 	// Validate arguments
492 	if (path == NULL)
493 	{
494 		return false;
495 	}
496 
497 	NormalizePath(tmp, sizeof(tmp), path);
498 
499 	Zero(&st, sizeof(st));
500 	if (statfs(tmp, &st) == 0)
501 	{
502 		v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;
503 		v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;
504 		ret = true;
505 	}
506 
507 	if (free_size != NULL)
508 	{
509 		*free_size = v1;
510 	}
511 
512 	if (total_size != NULL)
513 	{
514 		*total_size = v2;
515 	}
516 
517 	if (used_size != NULL)
518 	{
519 		*used_size = v2 - v1;
520 	}
521 
522 	return ret;
523 #else	// USE_STATVFS
524 	struct statvfs st;
525 	char tmp[MAX_PATH];
526 	UINT64 v1 = 0, v2 = 0;
527 	bool ret = false;
528 	// Validate arguments
529 	if (path == NULL)
530 	{
531 		return false;
532 	}
533 
534 	NormalizePath(tmp, sizeof(tmp), path);
535 
536 	Zero(&st, sizeof(st));
537 
538 	if (statvfs(tmp, &st) == 0)
539 	{
540 		v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;
541 		v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;
542 		ret = true;
543 	}
544 
545 	if (free_size != NULL)
546 	{
547 		*free_size = v1;
548 	}
549 
550 	if (total_size != NULL)
551 	{
552 		*total_size = v2;
553 	}
554 
555 	if (used_size != NULL)
556 	{
557 		*used_size = v2 - v1;
558 	}
559 
560 	return ret;
561 #endif	// USE_STATVFS
562 }
563 
564 // Directory enumeration
UnixEnumDirEx(char * dirname,COMPARE * compare)565 DIRLIST *UnixEnumDirEx(char *dirname, COMPARE *compare)
566 {
567 	char tmp[MAX_PATH];
568 	DIRLIST *d;
569 	int n;
570 	struct dirent **e;
571 	LIST *o;
572 	// Validate arguments
573 	if (dirname == NULL)
574 	{
575 		return NULL;
576 	}
577 
578 	o = NewListFast(compare);
579 
580 	NormalizePath(tmp, sizeof(tmp), dirname);
581 
582 	if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] != '/')
583 	{
584 		StrCat(tmp, sizeof(tmp), "/");
585 	}
586 
587 	e = NULL;
588 	n = scandir(tmp, &e, 0, alphasort);
589 
590 	if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] == '/')
591 	{
592 		tmp[StrLen(tmp) - 1] = 0;
593 	}
594 
595 	if (n >= 0 && e != NULL)
596 	{
597 		UINT i;
598 
599 		for (i = 0;i < (UINT)n;i++)
600 		{
601 			char *filename = e[i]->d_name;
602 
603 			if (filename != NULL)
604 			{
605 				if (StrCmpi(filename, "..") != 0 && StrCmpi(filename, ".") != 0)
606 				{
607 					char fullpath[MAX_PATH];
608 					struct stat st;
609 					Format(fullpath, sizeof(fullpath), "%s/%s", tmp, filename);
610 
611 					Zero(&st, sizeof(st));
612 
613 					if (stat(fullpath, &st) == 0)
614 					{
615 						DIRENT *f = ZeroMalloc(sizeof(DIRENT));
616 						SYSTEMTIME t;
617 
618 						f->Folder = S_ISDIR(st.st_mode) ? true : false;
619 						f->FileName = CopyStr(filename);
620 						f->FileNameW = CopyUtfToUni(f->FileName);
621 
622 						Zero(&t, sizeof(t));
623 						TimeToSystem(&t, st.st_ctime);
624 						f->CreateDate = SystemToUINT64(&t);
625 
626 						Zero(&t, sizeof(t));
627 						TimeToSystem(&t, st.st_mtime);
628 						f->UpdateDate = SystemToUINT64(&t);
629 
630 						if (f->Folder == false)
631 						{
632 							f->FileSize = st.st_size;
633 						}
634 
635 						Add(o, f);
636 					}
637 				}
638 			}
639 
640 			free(e[i]);
641 		}
642 
643 		free(e);
644 	}
645 
646 	Sort(o);
647 
648 	d = ZeroMalloc(sizeof(DIRLIST));
649 	d->NumFiles = LIST_NUM(o);
650 	d->File = ToArray(o);
651 
652 	ReleaseList(o);
653 
654 	return d;
655 }
UnixEnumDirExW(wchar_t * dirname,COMPARE * compare)656 DIRLIST *UnixEnumDirExW(wchar_t *dirname, COMPARE *compare)
657 {
658 	char *dirname_a = CopyUniToUtf(dirname);
659 	DIRLIST *ret;
660 
661 	ret = UnixEnumDirEx(dirname_a, compare);
662 
663 	Free(dirname_a);
664 
665 	return ret;
666 }
667 
668 // Check the execute permissions of the specified file
UnixCheckExecAccess(char * name)669 bool UnixCheckExecAccess(char *name)
670 {
671 	// Validate arguments
672 	if (name == NULL)
673 	{
674 		return false;
675 	}
676 
677 	if (access(name, X_OK) == 0)
678 	{
679 		return true;
680 	}
681 
682 	return false;
683 }
UnixCheckExecAccessW(wchar_t * name)684 bool UnixCheckExecAccessW(wchar_t *name)
685 {
686 	char *name_a;
687 	bool ret;
688 	// Validate arguments
689 	if (name == NULL)
690 	{
691 		return false;
692 	}
693 
694 	name_a = CopyUniToUtf(name);
695 
696 	ret = UnixCheckExecAccess(name_a);
697 
698 	Free(name_a);
699 
700 	return ret;
701 }
702 
703 // Raise the priority of the thread to highest
UnixSetThreadPriorityRealtime()704 void UnixSetThreadPriorityRealtime()
705 {
706 	struct sched_param p;
707 	Zero(&p, sizeof(p));
708 	p.sched_priority = 255;
709 	pthread_setschedparam(pthread_self(), SCHED_RR, &p);
710 }
711 
712 // Get the current directory
UnixGetCurrentDir(char * dir,UINT size)713 void UnixGetCurrentDir(char *dir, UINT size)
714 {
715 	// Validate arguments
716 	if (dir == NULL)
717 	{
718 		return;
719 	}
720 
721 	getcwd(dir, size);
722 }
UnixGetCurrentDirW(wchar_t * dir,UINT size)723 void UnixGetCurrentDirW(wchar_t *dir, UINT size)
724 {
725 	char dir_a[MAX_PATH];
726 
727 	UnixGetCurrentDir(dir_a, sizeof(dir_a));
728 
729 	UtfToUni(dir, size, dir_a);
730 }
731 
732 // Yield
UnixYield()733 void UnixYield()
734 {
735 #ifdef UNIX_SOLARIS
736 	UnixSolarisSleep(1);
737 #else
738 	usleep(1000);
739 #endif
740 }
741 
742 // Get the memory information
UnixGetMemInfo(MEMINFO * info)743 void UnixGetMemInfo(MEMINFO *info)
744 {
745 	// Validate arguments
746 	if (info == NULL)
747 	{
748 		return;
749 	}
750 
751 	// I don't know!!
752 	Zero(info, sizeof(MEMINFO));
753 }
754 
755 // Release of the single instance
UnixFreeSingleInstance(void * data)756 void UnixFreeSingleInstance(void *data)
757 {
758 	UNIXLOCKFILE *o;
759 	struct flock lock;
760 	// Validate arguments
761 	if (data == NULL)
762 	{
763 		return;
764 	}
765 
766 	o = (UNIXLOCKFILE *)data;
767 
768 	Zero(&lock, sizeof(lock));
769 	lock.l_type = F_UNLCK;
770 	lock.l_whence = SEEK_SET;
771 
772 	(void)fcntl(o->fd, F_SETLK, &lock);
773 	close(o->fd);
774 
775 	(void)remove(o->FileName);
776 
777 	Free(data);
778 }
779 
780 // Creating a single instance
UnixNewSingleInstance(char * instance_name)781 void *UnixNewSingleInstance(char *instance_name)
782 {
783 	UNIXLOCKFILE *ret;
784 	char tmp[MAX_SIZE];
785 	char name[MAX_SIZE];
786 	char dir[MAX_PATH];
787 	int fd;
788 	struct flock lock;
789 	int mode = S_IRUSR | S_IWUSR;
790 	// Validate arguments
791 	if (instance_name == NULL)
792 	{
793 		GetExeName(tmp, sizeof(tmp));
794 		HashInstanceName(tmp, sizeof(tmp), tmp);
795 	}
796 	else
797 	{
798 		StrCpy(tmp, sizeof(tmp), instance_name);
799 	}
800 
801 	GetPidDir(dir, sizeof(dir));
802 
803 	// File name generation
804 	Format(name, sizeof(name), "%s/.%s", dir, tmp);
805 
806 	fd = open(name, O_WRONLY);
807 	if (fd == -1)
808 	{
809 		fd = creat(name, mode);
810 	}
811 	if (fd == -1)
812 	{
813 		Format(tmp, sizeof(tmp), "Unable to create %s.", name);
814 		Alert(tmp, NULL);
815 		exit(0);
816 		return NULL;
817 	}
818 
819 	fchmod(fd, mode);
820 	(void)chmod(name, mode);
821 
822 	Zero(&lock, sizeof(lock));
823 	lock.l_type = F_WRLCK;
824 	lock.l_whence = SEEK_SET;
825 
826 	if (fcntl(fd, F_SETLK, &lock) == -1)
827 	{
828 		close(fd);
829 		return NULL;
830 	}
831 	else
832 	{
833 		ret = ZeroMalloc(sizeof(UNIXLOCKFILE));
834 		ret->fd = fd;
835 		StrCpy(ret->FileName, sizeof(ret->FileName), name);
836 		return (void *)ret;
837 	}
838 }
839 
840 // Set the high oom score
UnixSetHighOomScore()841 void UnixSetHighOomScore()
842 {
843 	IO *o;
844 	char tmp[256];
845 
846 	sprintf(tmp, "/proc/%u/oom_score_adj", getpid());
847 
848 	o = UnixFileCreate(tmp);
849 	if (o != NULL)
850 	{
851 		char tmp[128];
852 		sprintf(tmp, "%u\n", 800);
853 		UnixFileWrite(o, tmp, strlen(tmp));
854 		UnixFileClose(o, false);
855 	}
856 }
857 
858 // Raise the priority of the process
UnixSetHighPriority()859 void UnixSetHighPriority()
860 {
861 	if (high_process == false)
862 	{
863 		UINT pid = getpid();
864 		UINT pgid = getpgid(pid);
865 
866 		high_process = true;
867 		nice(-20);
868 
869 		setpriority(PRIO_PROCESS, pid, -20);
870 		setpriority(PRIO_PGRP, pgid, -20);
871 	}
872 }
873 
874 // Restore the priority of the process
UnixRestorePriority()875 void UnixRestorePriority()
876 {
877 	if (high_process != false)
878 	{
879 		high_process = false;
880 		nice(20);
881 	}
882 }
883 
UnixGetNumberOfCpuInner()884 UINT UnixGetNumberOfCpuInner()
885 {
886 	BUF *b;
887 	UINT ret = 0;
888 
889 	b = ReadDump("/proc/cpuinfo");
890 	if (b != NULL)
891 	{
892 		while (true)
893 		{
894 			char *line = CfgReadNextLine(b);
895 
896 			if (line == NULL)
897 			{
898 				break;
899 			}
900 
901 			if (IsEmptyStr(line) == false)
902 			{
903 				TOKEN_LIST *t = ParseToken(line, ":");
904 				if (t != NULL)
905 				{
906 					if (t->NumTokens >= 2)
907 					{
908 						char *key = t->Token[0];
909 						char *value = t->Token[1];
910 
911 						Trim(key);
912 						Trim(value);
913 
914 						if (StrCmpi(key, "processor") == 0)
915 						{
916 							if (IsNum(value))
917 							{
918 								UINT i = ToInt(value) + 1;
919 
920 								if (i >= 1 && i <= 128)
921 								{
922 									ret = MAX(ret, i);
923 								}
924 							}
925 						}
926 					}
927 
928 					FreeToken(t);
929 				}
930 			}
931 
932 			Free(line);
933 		}
934 
935 		FreeBuf(b);
936 	}
937 
938 	return ret;
939 }
940 
941 // Get the product ID
UnixGetProductId()942 char *UnixGetProductId()
943 {
944 	return CopyStr("--");
945 }
946 
947 // Display an alert
UnixAlertW(wchar_t * msg,wchar_t * caption)948 void UnixAlertW(wchar_t *msg, wchar_t *caption)
949 {
950 	char *msg8 = CopyUniToUtf(msg);
951 	char *caption8 = CopyUniToUtf(caption);
952 
953 	UnixAlert(msg8, caption8);
954 
955 	Free(msg8);
956 	Free(caption8);
957 }
UnixAlert(char * msg,char * caption)958 void UnixAlert(char *msg, char *caption)
959 {
960 	char *tag =
961 		"-- Alert: %s --\n%s\n";
962 	// Validate arguments
963 	if (msg == NULL)
964 	{
965 		msg = "Alert";
966 	}
967 	if (caption == NULL)
968 	{
969 		caption = CEDAR_PRODUCT_STR " VPN Kernel";
970 	}
971 
972 	printf(tag, caption, msg);
973 }
974 
975 // Get the information of the current OS
UnixGetOsInfo(OS_INFO * info)976 void UnixGetOsInfo(OS_INFO *info)
977 {
978 	struct utsname unix_info;
979 
980 	// Validate arguments
981 	if (info == NULL)
982 	{
983 		return;
984 	}
985 
986 	Zero(info, sizeof(OS_INFO));
987 
988 #ifdef	UNIX_SOLARIS
989 	info->OsType = OSTYPE_SOLARIS;
990 #elif	UNIX_CYGWIN
991 	info->OsType = OSTYPE_CYGWIN;
992 #elif	UNIX_MACOS
993 	info->OsType = OSTYPE_MACOS_X;
994 #elif	UNIX_BSD
995 	info->OsType = OSTYPE_BSD;
996 #elif	UNIX_LINUX
997 	info->OsType = OSTYPE_LINUX;
998 #else
999 	info->OsType = OSTYPE_UNIX_UNKNOWN;
1000 #endif
1001 
1002 	info->OsSystemName = CopyStr(OsTypeToStr(info->OsType));
1003 	info->KernelName = CopyStr("UNIX");
1004 
1005 	if (uname(&unix_info) > -1)
1006 	{
1007 		info->OsProductName = CopyStr(unix_info.sysname);
1008 		info->OsVersion = CopyStr(unix_info.release);
1009 		info->KernelVersion = CopyStr(unix_info.version);
1010 	}
1011 	else
1012 	{
1013 		Debug("UnixGetOsInfo(): uname() failed with error: %s\n", strerror(errno));
1014 
1015 		info->OsProductName = CopyStr(OsTypeToStr(info->OsType));
1016 		info->OsVersion = CopyStr("Unknown");
1017 		info->KernelVersion = CopyStr("Unknown");
1018 	}
1019 #ifdef	UNIX_LINUX
1020 	{
1021 		BUF *buffer = ReadDump("/etc/os-release");
1022 		if (buffer == NULL)
1023 		{
1024 			buffer = ReadDump("/usr/lib/os-release");
1025 		}
1026 
1027 		if (buffer != NULL)
1028 		{
1029 			LIST *values = NewEntryList(buffer->Buf, "\n", "=");
1030 
1031 			FreeBuf(buffer);
1032 
1033 			if (EntryListHasKey(values, "NAME"))
1034 			{
1035 				char *str = EntryListStrValue(values, "NAME");
1036 				TrimQuotes(str);
1037 				Free(info->OsProductName);
1038 				info->OsProductName = CopyStr(str);
1039 			}
1040 
1041 			if (EntryListHasKey(values, "HOME_URL"))
1042 			{
1043 				char *str = EntryListStrValue(values, "HOME_URL");
1044 				TrimQuotes(str);
1045 				info->OsVendorName = CopyStr(str);
1046 			}
1047 
1048 			if (EntryListHasKey(values, "VERSION"))
1049 			{
1050 				char *str = EntryListStrValue(values, "VERSION");
1051 				TrimQuotes(str);
1052 				Free(info->OsVersion);
1053 				info->OsVersion = CopyStr(str);
1054 			}
1055 			else
1056 			{
1057 				// Debian testing/sid doesn't provide the version in /etc/os-release
1058 				buffer = ReadDump("/etc/debian_version");
1059 				if (buffer != NULL)
1060 				{
1061 					Free(info->OsVersion);
1062 					info->OsVersion = CfgReadNextLine(buffer);
1063 					FreeBuf(buffer);
1064 				}
1065 			}
1066 
1067 			FreeEntryList(values);
1068 		}
1069 	}
1070 #endif
1071 }
1072 
1073 // Examine whether the current OS is supported by the PacketiX VPN Kernel
UnixIsSupportedOs()1074 bool UnixIsSupportedOs()
1075 {
1076 	// Support all UNIX OS which can run PacketiX VPN
1077 	return true;
1078 }
1079 
1080 // Run a specified command
UnixRunW(wchar_t * filename,wchar_t * arg,bool hide,bool wait)1081 bool UnixRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
1082 {
1083 	char *filename8 = CopyUniToUtf(filename);
1084 	char *arg8 = CopyUniToUtf(arg);
1085 	bool ret = UnixRun(filename8, arg8, hide, wait);
1086 
1087 	Free(filename8);
1088 	Free(arg8);
1089 
1090 	return ret;
1091 }
UnixRun(char * filename,char * arg,bool hide,bool wait)1092 bool UnixRun(char *filename, char *arg, bool hide, bool wait)
1093 {
1094 	TOKEN_LIST *t;
1095 	char **args;
1096 	UINT ret;
1097 
1098 	// Validate arguments
1099 	if (filename == NULL)
1100 	{
1101 		return false;
1102 	}
1103 	if (arg == NULL)
1104 	{
1105 		arg = "";
1106 	}
1107 
1108 	Print("", filename, arg);
1109 	t = ParseToken(arg, " ");
1110 	if (t == NULL)
1111 	{
1112 		return false;
1113 	}
1114 	else
1115 	{
1116 		UINT num_args;
1117 		UINT i;
1118 		num_args = t->NumTokens + 2;
1119 		args = ZeroMalloc(sizeof(char *) * num_args);
1120 		args[0] = filename;
1121 		for (i = 1;i < num_args - 1;i++)
1122 		{
1123 			args[i] = t->Token[i - 1];
1124 		}
1125 	}
1126 
1127 	// Create a child process
1128 	ret = fork();
1129 	if (ret == -1)
1130 	{
1131 		// Child process creation failure
1132 		return false;
1133 	}
1134 
1135 	if (ret == 0)
1136 	{
1137 		// Child process
1138 		if (hide)
1139 		{
1140 			// Close the standard I/O
1141 			UnixCloseIO();
1142 		}
1143 		execvp(filename, args);
1144 		AbortExit();
1145 	}
1146 	else
1147 	{
1148 		// Parent process
1149 		pid_t pid = (pid_t)ret;
1150 		Free(args);
1151 		FreeToken(t);
1152 
1153 		if (wait)
1154 		{
1155 			int status = 0;
1156 			// Wait for the termination of the child process
1157 			if (waitpid(pid, &status, 0) == -1)
1158 			{
1159 				return false;
1160 			}
1161 
1162 			if (WEXITSTATUS(status) == 0)
1163 			{
1164 				return true;
1165 			}
1166 			else
1167 			{
1168 				return false;
1169 			}
1170 		}
1171 
1172 		return true;
1173 	}
1174 }
1175 
1176 // Close the standard I/O
UnixCloseIO()1177 void UnixCloseIO()
1178 {
1179 	static bool close_io_first = false;
1180 
1181 	// Execute only once
1182 	if (close_io_first)
1183 	{
1184 		return;
1185 	}
1186 	else
1187 	{
1188 		close(0);
1189 		close(1);
1190 		close(2);
1191 		(void)open("/dev/null", O_RDWR);
1192 		dup2(0, 1);
1193 		dup2(0, 2);
1194 		close_io_first = false;
1195 	}
1196 }
1197 
1198 // Change the file name
UnixFileRenameW(wchar_t * old_name,wchar_t * new_name)1199 bool UnixFileRenameW(wchar_t *old_name, wchar_t *new_name)
1200 {
1201 	char *old_name8 = CopyUniToUtf(old_name);
1202 	char *new_name8 = CopyUniToUtf(new_name);
1203 	bool ret = UnixFileRename(old_name8, new_name8);
1204 
1205 	Free(old_name8);
1206 	Free(new_name8);
1207 
1208 	return ret;
1209 }
UnixFileRename(char * old_name,char * new_name)1210 bool UnixFileRename(char *old_name, char *new_name)
1211 {
1212 	// Validate arguments
1213 	if (old_name == NULL || new_name == NULL)
1214 	{
1215 		return false;
1216 	}
1217 
1218 	if (rename(old_name, new_name) != 0)
1219 	{
1220 		return false;
1221 	}
1222 
1223 	return true;
1224 }
1225 
1226 // Get the call stack
UnixGetCallStack()1227 CALLSTACK_DATA *UnixGetCallStack()
1228 {
1229 	// This is not supported on non-Win32
1230 	return NULL;
1231 }
1232 
1233 // Get the symbol information from the call stack
UnixGetCallStackSymbolInfo(CALLSTACK_DATA * s)1234 bool UnixGetCallStackSymbolInfo(CALLSTACK_DATA *s)
1235 {
1236 	// This is not supported on non-Win32
1237 	return false;
1238 }
1239 
1240 // Delete the directory
UnixDeleteDirW(wchar_t * name)1241 bool UnixDeleteDirW(wchar_t *name)
1242 {
1243 	char *name8 = CopyUniToUtf(name);
1244 	bool ret = UnixDeleteDir(name8);
1245 
1246 	Free(name8);
1247 
1248 	return ret;
1249 }
UnixDeleteDir(char * name)1250 bool UnixDeleteDir(char *name)
1251 {
1252 	// Validate arguments
1253 	if (name == NULL)
1254 	{
1255 		return false;
1256 	}
1257 
1258 	if (rmdir(name) != 0)
1259 	{
1260 		return false;
1261 	}
1262 
1263 	return true;
1264 }
1265 
1266 // Create a directory
UnixMakeDirW(wchar_t * name)1267 bool UnixMakeDirW(wchar_t *name)
1268 {
1269 	char *name8 = CopyUniToUtf(name);
1270 	bool ret = UnixMakeDir(name8);
1271 
1272 	Free(name8);
1273 
1274 	return ret;
1275 }
UnixMakeDir(char * name)1276 bool UnixMakeDir(char *name)
1277 {
1278 	// Validate arguments
1279 	if (name == NULL)
1280 	{
1281 		return false;
1282 	}
1283 
1284 	if (mkdir(name, 0700) != 0)
1285 	{
1286 		return false;
1287 	}
1288 
1289 	return true;
1290 }
1291 
1292 // Delete the file
UnixFileDeleteW(wchar_t * name)1293 bool UnixFileDeleteW(wchar_t *name)
1294 {
1295 	bool ret;
1296 	char *name8 = CopyUniToUtf(name);
1297 
1298 	ret = UnixFileDelete(name8);
1299 
1300 	Free(name8);
1301 
1302 	return ret;
1303 }
UnixFileDelete(char * name)1304 bool UnixFileDelete(char *name)
1305 {
1306 	// Validate arguments
1307 	if (name == NULL)
1308 	{
1309 		return false;
1310 	}
1311 
1312 	if (remove(name) != 0)
1313 	{
1314 		return false;
1315 	}
1316 
1317 	return true;
1318 }
1319 
1320 // Seek the file
UnixFileSeek(void * pData,UINT mode,int offset)1321 bool UnixFileSeek(void *pData, UINT mode, int offset)
1322 {
1323 	UNIXIO *p;
1324 	UINT ret;
1325 	// Validate arguments
1326 	if (pData == NULL)
1327 	{
1328 		return 0;
1329 	}
1330 	if (mode != FILE_BEGIN && mode != FILE_END && mode != FILE_CURRENT)
1331 	{
1332 		return false;
1333 	}
1334 
1335 	p = (UNIXIO *)pData;
1336 
1337 	ret = lseek(p->fd, offset, mode);
1338 
1339 	if (ret == -1)
1340 	{
1341 		return false;
1342 	}
1343 
1344 	return true;
1345 }
1346 
1347 // Get the file size
UnixFileSize(void * pData)1348 UINT64 UnixFileSize(void *pData)
1349 {
1350 	struct stat st;
1351 	UNIXIO *p;
1352 	int r;
1353 	// Validate arguments
1354 	if (pData == NULL)
1355 	{
1356 		return 0;
1357 	}
1358 
1359 	p = (UNIXIO *)pData;
1360 
1361 	Zero(&st, sizeof(st));
1362 	r = fstat(p->fd, &st);
1363 	if (r != 0)
1364 	{
1365 		return 0;
1366 	}
1367 
1368 	return (UINT64)st.st_size;
1369 }
1370 
1371 // Write to the file
UnixFileWrite(void * pData,void * buf,UINT size)1372 bool UnixFileWrite(void *pData, void *buf, UINT size)
1373 {
1374 	UNIXIO *p;
1375 	UINT ret;
1376 	// Validate arguments
1377 	if (pData == NULL || buf == NULL || size == 0)
1378 	{
1379 		return false;
1380 	}
1381 
1382 	p = (UNIXIO *)pData;
1383 
1384 	ret = write(p->fd, buf, size);
1385 	if (ret != size)
1386 	{
1387 		return false;
1388 	}
1389 
1390 	return true;
1391 }
1392 
1393 // Read from the file
UnixFileRead(void * pData,void * buf,UINT size)1394 bool UnixFileRead(void *pData, void *buf, UINT size)
1395 {
1396 	UNIXIO *p;
1397 	UINT ret;
1398 	// Validate arguments
1399 	if (pData == NULL || buf == NULL || size == 0)
1400 	{
1401 		return false;
1402 	}
1403 
1404 	p = (UNIXIO *)pData;
1405 
1406 	ret = read(p->fd, buf, size);
1407 	if (ret != size)
1408 	{
1409 		return false;
1410 	}
1411 
1412 	return true;
1413 }
1414 
1415 // Flush to the file
UnixFileFlush(void * pData)1416 void UnixFileFlush(void *pData)
1417 {
1418 	UNIXIO *p;
1419 	bool write_mode;
1420 	// Validate arguments
1421 	if (pData == NULL)
1422 	{
1423 		return;
1424 	}
1425 
1426 	p = (UNIXIO *)pData;
1427 
1428 	write_mode = p->write_mode;
1429 
1430 	if (write_mode)
1431 	{
1432 		fsync(p->fd);
1433 	}
1434 }
1435 
1436 // Close the file
UnixFileClose(void * pData,bool no_flush)1437 void UnixFileClose(void *pData, bool no_flush)
1438 {
1439 	UNIXIO *p;
1440 	bool write_mode;
1441 	// Validate arguments
1442 	if (pData == NULL)
1443 	{
1444 		return;
1445 	}
1446 
1447 	p = (UNIXIO *)pData;
1448 
1449 	write_mode = p->write_mode;
1450 
1451 	if (write_mode && no_flush == false)
1452 	{
1453 		fsync(p->fd);
1454 	}
1455 
1456 	close(p->fd);
1457 
1458 	UnixMemoryFree(p);
1459 
1460 	if (write_mode)
1461 	{
1462 		//sync();
1463 	}
1464 }
1465 
1466 // Create a file
UnixFileCreateW(wchar_t * name)1467 void *UnixFileCreateW(wchar_t *name)
1468 {
1469 	void *ret;
1470 	char *name8 = CopyUniToUtf(name);
1471 
1472 	ret = UnixFileCreate(name8);
1473 
1474 	Free(name8);
1475 
1476 	return ret;
1477 }
UnixFileCreate(char * name)1478 void *UnixFileCreate(char *name)
1479 {
1480 	UNIXIO *p;
1481 	int fd;
1482 	// Validate arguments
1483 	if (name == NULL)
1484 	{
1485 		return NULL;
1486 	}
1487 
1488 	fd = creat(name, 0600);
1489 	if (fd == -1)
1490 	{
1491 		return NULL;
1492 	}
1493 
1494 	// Memory allocation
1495 	p = UnixMemoryAlloc(sizeof(UNIXIO));
1496 	p->fd = fd;
1497 	p->write_mode = true;
1498 
1499 	return (void *)p;
1500 }
1501 
1502 // Open the file
UnixFileOpenW(wchar_t * name,bool write_mode,bool read_lock)1503 void *UnixFileOpenW(wchar_t *name, bool write_mode, bool read_lock)
1504 {
1505 	char *name8 = CopyUniToUtf(name);
1506 	void *ret;
1507 
1508 	ret = UnixFileOpen(name8, write_mode, read_lock);
1509 
1510 	Free(name8);
1511 
1512 	return ret;
1513 }
UnixFileOpen(char * name,bool write_mode,bool read_lock)1514 void *UnixFileOpen(char *name, bool write_mode, bool read_lock)
1515 {
1516 	UNIXIO *p;
1517 	int fd;
1518 	int mode;
1519 	// Validate arguments
1520 	if (name == NULL)
1521 	{
1522 		return NULL;
1523 	}
1524 
1525 	if (write_mode == false)
1526 	{
1527 		mode = O_RDONLY;
1528 	}
1529 	else
1530 	{
1531 		mode = O_RDWR;
1532 	}
1533 
1534 	// Open the file
1535 	fd = open(name, mode);
1536 	if (fd == -1)
1537 	{
1538 		return NULL;
1539 	}
1540 
1541 	// Memory allocation
1542 	p = UnixMemoryAlloc(sizeof(UNIXIO));
1543 	p->fd = fd;
1544 	p->write_mode = write_mode;
1545 
1546 	return (void *)p;
1547 }
1548 
1549 // Get UNIXIO object for stdout
GetUnixio4Stdout()1550 void* GetUnixio4Stdout()
1551 {
1552 	static UNIXIO unixio =
1553 	{
1554 		.fd = -1,
1555 		.write_mode = true
1556 	};
1557 
1558 	if (g_foreground)
1559 	{
1560 		unixio.fd = STDOUT_FILENO;
1561 		return &unixio;
1562 	}
1563 	return NULL;
1564 }
1565 
1566 // Return the current thread ID
UnixThreadId()1567 UINT UnixThreadId()
1568 {
1569 	UINT ret;
1570 
1571 	ret = (UINT)pthread_self();
1572 
1573 	return ret;
1574 }
1575 
1576 // Thread function
UnixDefaultThreadProc(void * param)1577 void *UnixDefaultThreadProc(void *param)
1578 {
1579 	UNIXTHREAD *ut;
1580 	UNIXTHREADSTARTUPINFO *info = (UNIXTHREADSTARTUPINFO *)param;
1581 	if (info == NULL)
1582 	{
1583 		return 0;
1584 	}
1585 
1586 	ut = (UNIXTHREAD *)info->thread->pData;
1587 
1588 	// Call the thread function
1589 	info->thread_proc(info->thread, info->param);
1590 
1591 	// Set a termination flag
1592 	ut->finished = true;
1593 
1594 	// Release of reference
1595 	ReleaseThread(info->thread);
1596 
1597 	UnixMemoryFree(info);
1598 
1599 	FreeOpenSSLThreadState();
1600 
1601 	return 0;
1602 }
1603 
1604 // Release of thread
UnixFreeThread(THREAD * t)1605 void UnixFreeThread(THREAD *t)
1606 {
1607 	// Validate arguments
1608 	if (t == NULL)
1609 	{
1610 		return;
1611 	}
1612 
1613 	// Free memory
1614 	UnixMemoryFree(t->pData);
1615 }
1616 
1617 // Wait for the termination of the thread
UnixWaitThread(THREAD * t)1618 bool UnixWaitThread(THREAD *t)
1619 {
1620 	UNIXTHREAD *ut;
1621 	void *retcode = NULL;
1622 	// Validate arguments
1623 	if (t == NULL)
1624 	{
1625 		return false;
1626 	}
1627 	ut = (UNIXTHREAD *)t->pData;
1628 	if (ut == NULL)
1629 	{
1630 		return false;
1631 	}
1632 
1633 	pthread_join(ut->thread, &retcode);
1634 
1635 	return true;
1636 }
1637 
1638 // Thread initialization
UnixInitThread(THREAD * t)1639 bool UnixInitThread(THREAD *t)
1640 {
1641 	UNIXTHREAD *ut;
1642 	UNIXTHREADSTARTUPINFO *info;
1643 	pthread_attr_t attr;
1644 	// Validate arguments
1645 	if (t == NULL || t->thread_proc == NULL)
1646 	{
1647 		return false;
1648 	}
1649 
1650 	// Thread data creation
1651 	ut = UnixMemoryAlloc(sizeof(UNIXTHREAD));
1652 	Zero(ut, sizeof(UNIXTHREAD));
1653 
1654 	// Creating the startup information
1655 	info = UnixMemoryAlloc(sizeof(UNIXTHREADSTARTUPINFO));
1656 	Zero(info, sizeof(UNIXTHREADSTARTUPINFO));
1657 	info->param = t->param;
1658 	info->thread_proc = t->thread_proc;
1659 	info->thread = t;
1660 	AddRef(t->ref);
1661 
1662 	// Thread creation
1663 	pthread_attr_init(&attr);
1664 	pthread_attr_setstacksize(&attr, UNIX_THREAD_STACK_SIZE);
1665 
1666 	t->pData = (void *)ut;
1667 
1668 	if (pthread_create(&ut->thread, &attr, UnixDefaultThreadProc, info) != 0)
1669 	{
1670 		// An error has occured
1671 		t->pData = NULL;
1672 		(void)Release(t->ref);
1673 		UnixMemoryFree(ut);
1674 		UnixMemoryFree(info);
1675 		pthread_attr_destroy(&attr);
1676 		return false;
1677 	}
1678 
1679 	pthread_attr_destroy(&attr);
1680 
1681 	return true;
1682 }
1683 
1684 // Release the event
UnixFreeEvent(EVENT * event)1685 void UnixFreeEvent(EVENT *event)
1686 {
1687 	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
1688 	if (ue == NULL)
1689 	{
1690 		return;
1691 	}
1692 
1693 	pthread_cond_destroy(&ue->cond);
1694 	pthread_mutex_destroy(&ue->mutex);
1695 
1696 	UnixMemoryFree(ue);
1697 }
1698 
1699 // Wait for a event
UnixWaitEvent(EVENT * event,UINT timeout)1700 bool UnixWaitEvent(EVENT *event, UINT timeout)
1701 {
1702 	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
1703 	struct timeval now;
1704 	struct timespec to;
1705 	bool ret;
1706 	if (ue == NULL)
1707 	{
1708 		return false;
1709 	}
1710 
1711 	pthread_mutex_lock(&ue->mutex);
1712 	gettimeofday(&now, NULL);
1713 	to.tv_sec = now.tv_sec + timeout / 1000;
1714 	to.tv_nsec = now.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000;
1715 	if ((to.tv_nsec / 1000000000) >= 1)
1716 	{
1717 		to.tv_sec += to.tv_nsec / 1000000000;
1718 		to.tv_nsec = to.tv_nsec % 1000000000;
1719 	}
1720 
1721 	ret = true;
1722 
1723 	while (ue->signal == false)
1724 	{
1725 		if (timeout != INFINITE)
1726 		{
1727 			if (pthread_cond_timedwait(&ue->cond, &ue->mutex, &to))
1728 			{
1729 				ret = false;
1730 				break;
1731 			}
1732 		}
1733 		else
1734 		{
1735 			pthread_cond_wait(&ue->cond, &ue->mutex);
1736 		}
1737 	}
1738 	ue->signal = false;
1739 
1740 	pthread_mutex_unlock(&ue->mutex);
1741 
1742 	return ret;
1743 }
1744 
1745 // Reset the event
UnixResetEvent(EVENT * event)1746 void UnixResetEvent(EVENT *event)
1747 {
1748 	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
1749 	if (ue == NULL)
1750 	{
1751 		return;
1752 	}
1753 
1754 	pthread_mutex_lock(&ue->mutex);
1755 	ue->signal = false;
1756 	pthread_cond_signal(&ue->cond);
1757 	pthread_mutex_unlock(&ue->mutex);
1758 }
1759 
1760 // Set the event
UnixSetEvent(EVENT * event)1761 void UnixSetEvent(EVENT *event)
1762 {
1763 	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
1764 	if (ue == NULL)
1765 	{
1766 		return;
1767 	}
1768 
1769 	pthread_mutex_lock(&ue->mutex);
1770 	ue->signal = true;
1771 	pthread_cond_signal(&ue->cond);
1772 	pthread_mutex_unlock(&ue->mutex);
1773 }
1774 
1775 // Initialize the event
UnixInitEvent(EVENT * event)1776 void UnixInitEvent(EVENT *event)
1777 {
1778 	UNIXEVENT *ue = UnixMemoryAlloc(sizeof(UNIXEVENT));
1779 
1780 	Zero(ue, sizeof(UNIXEVENT));
1781 
1782 	pthread_cond_init(&ue->cond, NULL);
1783 	pthread_mutex_init(&ue->mutex, NULL);
1784 	ue->signal = false;
1785 
1786 	event->pData = (void *)ue;
1787 }
1788 
1789 // Delete the lock
UnixDeleteLock(LOCK * lock)1790 void UnixDeleteLock(LOCK *lock)
1791 {
1792 	pthread_mutex_t *mutex;
1793 	// Reset Ready flag safely
1794 	UnixLock(lock);
1795 	lock->Ready = false;
1796 	UnixUnlockEx(lock, true);
1797 
1798 	// Delete the mutex
1799 	mutex = (pthread_mutex_t *)lock->pData;
1800 	pthread_mutex_destroy(mutex);
1801 
1802 	// Memory release
1803 	UnixMemoryFree(mutex);
1804 	UnixMemoryFree(lock);
1805 }
1806 
1807 // Unlock
UnixUnlock(LOCK * lock)1808 void UnixUnlock(LOCK *lock)
1809 {
1810 	UnixUnlockEx(lock, false);
1811 }
UnixUnlockEx(LOCK * lock,bool inner)1812 void UnixUnlockEx(LOCK *lock, bool inner)
1813 {
1814 	pthread_mutex_t *mutex;
1815 	if (lock->Ready == false && inner == false)
1816 	{
1817 		// State is invalid
1818 		return;
1819 	}
1820 	mutex = (pthread_mutex_t *)lock->pData;
1821 
1822 	if ((--lock->locked_count) > 0)
1823 	{
1824 		return;
1825 	}
1826 
1827 	lock->thread_id = INFINITE;
1828 
1829 	pthread_mutex_unlock(mutex);
1830 
1831 	return;
1832 }
1833 
1834 // Lock
UnixLock(LOCK * lock)1835 bool UnixLock(LOCK *lock)
1836 {
1837 	pthread_mutex_t *mutex;
1838 	UINT thread_id = UnixThreadId();
1839 	if (lock->Ready == false)
1840 	{
1841 		// State is invalid
1842 		return false;
1843 	}
1844 
1845 	if (lock->thread_id == thread_id)
1846 	{
1847 		lock->locked_count++;
1848 		return true;
1849 	}
1850 
1851 	mutex = (pthread_mutex_t *)lock->pData;
1852 
1853 	pthread_mutex_lock(mutex);
1854 
1855 	lock->thread_id = thread_id;
1856 	lock->locked_count++;
1857 
1858 	return true;
1859 }
1860 
1861 // Creating a new lock
UnixNewLock()1862 LOCK *UnixNewLock()
1863 {
1864 	pthread_mutex_t *mutex;
1865 	// Memory allocation
1866 	LOCK *lock = UnixMemoryAlloc(sizeof(LOCK));
1867 
1868 	// Create a mutex
1869 	mutex = UnixMemoryAlloc(sizeof(pthread_mutex_t));
1870 	if (mutex == NULL)
1871 	{
1872 		return NULL;
1873 	}
1874 
1875 	// Initialization of the mutex
1876 	pthread_mutex_init(mutex, NULL);
1877 
1878 	lock->pData = (void *)mutex;
1879 	lock->Ready = true;
1880 
1881 	lock->thread_id = INFINITE;
1882 	lock->locked_count = 0;
1883 
1884 	return lock;
1885 }
1886 
1887 // Sleep
UnixSleep(UINT time)1888 void UnixSleep(UINT time)
1889 {
1890 	UINT sec = 0, millisec = 0;
1891 	// Validate arguments
1892 	if (time == 0)
1893 	{
1894 		return;
1895 	}
1896 
1897 	if (time == INFINITE)
1898 	{
1899 		// Wait forever
1900 		while (true)
1901 		{
1902 #ifdef UNIX_SOLARIS
1903 			UnixSolarisSleep(time);
1904 #else
1905 			sleep(1000000);
1906 #endif
1907 		}
1908 	}
1909 
1910 #ifdef UNIX_SOLARIS
1911 	UnixSolarisSleep(time);
1912 #else
1913 
1914 	// Prevent overflow
1915 	sec = time / 1000;
1916 	millisec = time % 1000;
1917 
1918 	if (sec != 0)
1919 	{
1920 		sleep(sec);
1921 	}
1922 	if (millisec != 0)
1923 	{
1924 		usleep(millisec * 1000);
1925 	}
1926 #endif
1927 }
1928 
1929 // Decrement
UnixDec32(UINT * value)1930 void UnixDec32(UINT *value)
1931 {
1932 	if (value != NULL)
1933 	{
1934 		(*value)--;
1935 	}
1936 }
1937 
1938 // Increment
UnixInc32(UINT * value)1939 void UnixInc32(UINT *value)
1940 {
1941 	if (value != NULL)
1942 	{
1943 		(*value)++;
1944 	}
1945 }
1946 
1947 // Get the System Time
UnixGetSystemTime(SYSTEMTIME * system_time)1948 void UnixGetSystemTime(SYSTEMTIME *system_time)
1949 {
1950 	time_t now = 0;
1951 	time_64t now2 = 0;
1952 	struct tm tm;
1953 	struct timeval tv;
1954 	struct timezone tz;
1955 	// Validate arguments
1956 	if (system_time == NULL)
1957 	{
1958 		return;
1959 	}
1960 
1961 	pthread_mutex_lock(&get_time_lock);
1962 
1963 	Zero(system_time, sizeof(SYSTEMTIME));
1964 	Zero(&tv, sizeof(tv));
1965 	Zero(&tz, sizeof(tz));
1966 
1967 	time(&now);
1968 
1969 	if (sizeof(time_t) == 4)
1970 	{
1971 		now2 = (time_64t)((UINT64)((UINT)now));
1972 	}
1973 	else
1974 	{
1975 		now2 = now;
1976 	}
1977 
1978 	c_gmtime_r(&now2, &tm);
1979 
1980 	TmToSystem(system_time, &tm);
1981 
1982 	gettimeofday(&tv, &tz);
1983 
1984 	system_time->wMilliseconds = tv.tv_usec / 1000;
1985 
1986 	pthread_mutex_unlock(&get_time_lock);
1987 }
1988 
1989 // Get the system timer (64bit)
UnixGetTick64()1990 UINT64 UnixGetTick64()
1991 {
1992 #if	defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)
1993 
1994 	struct timespec t;
1995 	UINT64 ret;
1996 
1997 	Zero(&t, sizeof(t));
1998 
1999 	// Function to get the boot time of the system
2000 	// Be careful. The Implementation is depend on the system.
2001 #ifdef	CLOCK_HIGHRES
2002 	clock_gettime(CLOCK_HIGHRES, &t);
2003 #elif	CLOCK_MONOTONIC
2004 	clock_gettime(CLOCK_MONOTONIC, &t);
2005 #else
2006 	clock_gettime(CLOCK_REALTIME, &t);
2007 #endif
2008 
2009 	ret = ((UINT64)((UINT)t.tv_sec)) * 1000LL + (UINT64)t.tv_nsec / 1000000LL;
2010 
2011 	if (ret == 0)
2012 	{
2013 		ret = TickRealtimeManual();
2014 	}
2015 
2016 	return ret;
2017 #else
2018 	return TickRealtimeManual();
2019 #endif
2020 }
2021 
2022 // Get the system timer
UnixGetTick()2023 UINT UnixGetTick()
2024 {
2025 	return (UINT)UnixGetTick64();
2026 }
2027 
2028 // Memory allocation
UnixMemoryAlloc(UINT size)2029 void *UnixMemoryAlloc(UINT size)
2030 {
2031 	void *r;
2032 	pthread_mutex_lock(&malloc_lock);
2033 	r = malloc(size);
2034 	pthread_mutex_unlock(&malloc_lock);
2035 	return r;
2036 }
2037 
2038 // Reallocation of the memory
UnixMemoryReAlloc(void * addr,UINT size)2039 void *UnixMemoryReAlloc(void *addr, UINT size)
2040 {
2041 	void *r;
2042 	pthread_mutex_lock(&malloc_lock);
2043 	r = realloc(addr, size);
2044 	pthread_mutex_unlock(&malloc_lock);
2045 	return r;
2046 }
2047 
2048 // Free the memory
UnixMemoryFree(void * addr)2049 void UnixMemoryFree(void *addr)
2050 {
2051 	pthread_mutex_lock(&malloc_lock);
2052 	free(addr);
2053 	pthread_mutex_unlock(&malloc_lock);
2054 }
2055 
2056 // SIGCHLD handler
UnixSigChldHandler(int sig)2057 void UnixSigChldHandler(int sig)
2058 {
2059 	// Recall the zombie processes
2060 	while (waitpid(-1, NULL, WNOHANG) > 0);
2061 	signal(SIGCHLD, UnixSigChldHandler);
2062 }
2063 
2064 // Disable core dump
UnixDisableCoreDump()2065 void UnixDisableCoreDump()
2066 {
2067 #ifdef	RLIMIT_CORE
2068 	UnixSetResourceLimit(RLIMIT_CORE, 0);
2069 #endif	// RLIMIT_CORE
2070 }
2071 
2072 // Initialize the library for UNIX
UnixInit()2073 void UnixInit()
2074 {
2075 	UNIXIO *o;
2076 	UINT64 max_memory = UNIX_MAX_MEMORY;
2077 
2078 	if (UnixIs64BitRlimSupported())
2079 	{
2080 		max_memory = UNIX_MAX_MEMORY_64;
2081 	}
2082 
2083 	UnixInitSolarisSleep();
2084 
2085 	// Global lock
2086 	pthread_mutex_init(&get_time_lock, NULL);
2087 	pthread_mutex_init(&malloc_lock, NULL);
2088 
2089 	// Get the Process ID
2090 	current_process_id = getpid();
2091 
2092 #ifdef	RLIMIT_CORE
2093 	UnixSetResourceLimit(RLIMIT_CORE, max_memory);
2094 #endif	// RLIMIT_CORE
2095 
2096 #ifdef	RLIMIT_DATA
2097 	UnixSetResourceLimit(RLIMIT_DATA, max_memory);
2098 #endif	// RLIMIT_DATA
2099 
2100 #ifdef	RLIMIT_NOFILE
2101 #ifndef	UNIX_MACOS
2102 	UnixSetResourceLimit(RLIMIT_NOFILE, UNIX_MAX_FD);
2103 #else	// UNIX_MACOS
2104 	UnixSetResourceLimit(RLIMIT_NOFILE, UNIX_MAX_FD_MACOS);
2105 #endif	// UNIX_MACOS
2106 #endif	// RLIMIT_NOFILE
2107 
2108 #ifdef	RLIMIT_STACK
2109 //	UnixSetResourceLimit(RLIMIT_STACK, max_memory);
2110 #endif	// RLIMIT_STACK
2111 
2112 #ifdef	RLIMIT_RSS
2113 	UnixSetResourceLimit(RLIMIT_RSS, max_memory);
2114 #endif	// RLIMIT_RSS
2115 
2116 #ifdef	RLIMIT_LOCKS
2117 	UnixSetResourceLimit(RLIMIT_LOCKS, UNIX_MAX_LOCKS);
2118 #endif	// RLIMIT_LOCKS
2119 
2120 #ifdef	RLIMIT_MEMLOCK
2121 	UnixSetResourceLimit(RLIMIT_MEMLOCK, max_memory);
2122 #endif	// RLIMIT_MEMLOCK
2123 
2124 #ifdef	RLIMIT_NPROC
2125 	UnixSetResourceLimit(RLIMIT_NPROC, UNIX_MAX_CHILD_PROCESSES);
2126 #endif	// RLIMIT_NPROC
2127 
2128 	// Write a value to the threads-max of the proc file system
2129 	o = UnixFileCreate("/proc/sys/kernel/threads-max");
2130 	if (o != NULL)
2131 	{
2132 		char tmp[128];
2133 		sprintf(tmp, "%u\n", UNIX_LINUX_MAX_THREADS);
2134 		UnixFileWrite(o, tmp, strlen(tmp));
2135 		UnixFileClose(o, false);
2136 	}
2137 
2138 	// Set the signals that is to be ignored
2139 	signal(SIGPIPE, SIG_IGN);
2140 	signal(SIGALRM, SIG_IGN);
2141 
2142 #ifdef	UNIX_BSD
2143 	signal(64, SIG_IGN);
2144 #endif	// UNIX_BSD
2145 
2146 #ifdef	SIGXFSZ
2147 	signal(SIGXFSZ, SIG_IGN);
2148 #endif	// SIGXFSZ
2149 
2150 	// Set a signal handler to salvage the child processes
2151 	signal(SIGCHLD, UnixSigChldHandler);
2152 }
2153 
2154 // Release the library for UNIX
UnixFree()2155 void UnixFree()
2156 {
2157 	UnixFreeSolarisSleep();
2158 
2159 	current_process_id = 0;
2160 
2161 	pthread_mutex_destroy(&get_time_lock);
2162 }
2163 
2164 // Adjust the upper limit of resources that may be occupied
UnixSetResourceLimit(UINT id,UINT64 value)2165 void UnixSetResourceLimit(UINT id, UINT64 value)
2166 {
2167 	struct rlimit t;
2168 	UINT64 hard_limit;
2169 
2170 	if (UnixIs64BitRlimSupported() == false)
2171 	{
2172 		if (value > (UINT64)4294967295ULL)
2173 		{
2174 			value = (UINT64)4294967295ULL;
2175 		}
2176 	}
2177 
2178 	Zero(&t, sizeof(t));
2179 	getrlimit(id, &t);
2180 
2181 	hard_limit = (UINT64)t.rlim_max;
2182 
2183 	Zero(&t, sizeof(t));
2184 	t.rlim_cur = (rlim_t)MIN(value, hard_limit);
2185 	t.rlim_max = (rlim_t)hard_limit;
2186 	setrlimit(id, &t);
2187 
2188 	Zero(&t, sizeof(t));
2189 	t.rlim_cur = (rlim_t)value;
2190 	t.rlim_max = (rlim_t)value;
2191 	setrlimit(id, &t);
2192 }
2193 
2194 // Is the rlim_t type 64-bit?
UnixIs64BitRlimSupported()2195 bool UnixIs64BitRlimSupported()
2196 {
2197 	if (sizeof(rlim_t) >= 8)
2198 	{
2199 		return true;
2200 	}
2201 
2202 	return false;
2203 }
2204 
2205 // Generate the PID file name
UnixGenPidFileName(char * name,UINT size)2206 void UnixGenPidFileName(char *name, UINT size)
2207 {
2208 	char exe_name[MAX_PATH];
2209 	UCHAR hash[MD5_SIZE];
2210 	char tmp1[64];
2211 	char dir[MAX_PATH];
2212 	// Validate arguments
2213 	if (name == NULL)
2214 	{
2215 		return;
2216 	}
2217 
2218 	GetPidDir(dir, sizeof(dir));
2219 
2220 	GetExeName(exe_name, sizeof(exe_name));
2221 	StrCat(exe_name, sizeof(exe_name), ":pid_hash");
2222 	StrUpper(exe_name);
2223 
2224 	Md5(hash, exe_name, StrLen(exe_name));
2225 	BinToStr(tmp1, sizeof(tmp1), hash, sizeof(hash));
2226 
2227 	Format(name, size, "%s/.pid_%s", dir, tmp1);
2228 }
2229 
2230 // Delete the PID file
UnixDeletePidFile()2231 void UnixDeletePidFile()
2232 {
2233 	char tmp[MAX_PATH];
2234 
2235 	UnixGenPidFileName(tmp, sizeof(tmp));
2236 
2237 	UnixFileDelete(tmp);
2238 }
2239 
2240 // Delete the CTL file
UnixDeleteCtlFile()2241 void UnixDeleteCtlFile()
2242 {
2243 	char tmp[MAX_PATH];
2244 
2245 	UnixGenCtlFileName(tmp, sizeof(tmp));
2246 
2247 	UnixFileDelete(tmp);
2248 }
2249 
2250 // Generate the CTL file name
UnixGenCtlFileName(char * name,UINT size)2251 void UnixGenCtlFileName(char *name, UINT size)
2252 {
2253 	char exe_name[MAX_PATH];
2254 	UCHAR hash[MD5_SIZE];
2255 	char tmp1[64];
2256 	char dir[MAX_PATH];
2257 	// Validate arguments
2258 	if (name == NULL)
2259 	{
2260 		return;
2261 	}
2262 
2263 	GetPidDir(dir, sizeof(dir));
2264 
2265 	GetExeName(exe_name, sizeof(exe_name));
2266 	StrCat(exe_name, sizeof(exe_name), ":pid_hash");
2267 	StrUpper(exe_name);
2268 
2269 	Md5(hash, exe_name, StrLen(exe_name));
2270 	BinToStr(tmp1, sizeof(tmp1), hash, sizeof(hash));
2271 
2272 	Format(name, size, "%s/.ctl_%s", dir, tmp1);
2273 }
2274 
2275 // Write the CTL file
UnixWriteCtlFile(UINT i)2276 void UnixWriteCtlFile(UINT i)
2277 {
2278 	char tmp[MAX_PATH];
2279 	char tmp2[64];
2280 	IO *o;
2281 
2282 	UnixGenCtlFileName(tmp, sizeof(tmp));
2283 	Format(tmp2, sizeof(tmp2), "%u\n", i);
2284 
2285 	o = FileCreate(tmp);
2286 	if (o != NULL)
2287 	{
2288 		FileWrite(o, tmp2, StrLen(tmp2));
2289 		FileClose(o);
2290 	}
2291 }
2292 
2293 // Write to the PID file
UnixWritePidFile(UINT pid)2294 void UnixWritePidFile(UINT pid)
2295 {
2296 	char tmp[MAX_PATH];
2297 	char tmp2[64];
2298 	IO *o;
2299 
2300 	UnixGenPidFileName(tmp, sizeof(tmp));
2301 	Format(tmp2, sizeof(tmp2), "%u\n", pid);
2302 
2303 	o = FileCreate(tmp);
2304 	if (o != NULL)
2305 	{
2306 		FileWrite(o, tmp2, StrLen(tmp2));
2307 		FileClose(o);
2308 	}
2309 }
2310 
2311 // Read the PID file
UnixReadPidFile()2312 UINT UnixReadPidFile()
2313 {
2314 	char tmp[MAX_PATH];
2315 	BUF *buf;
2316 
2317 	UnixGenPidFileName(tmp, sizeof(tmp));
2318 
2319 	buf = ReadDump(tmp);
2320 	if (buf == NULL)
2321 	{
2322 		return 0;
2323 	}
2324 
2325 	Zero(tmp, sizeof(tmp));
2326 	Copy(tmp, buf->Buf, MIN(buf->Size, sizeof(tmp)));
2327 	FreeBuf(buf);
2328 
2329 	return ToInt(tmp);
2330 }
2331 
2332 // Read the CTL file
UnixReadCtlFile()2333 UINT UnixReadCtlFile()
2334 {
2335 	char tmp[MAX_PATH];
2336 	BUF *buf;
2337 
2338 	UnixGenCtlFileName(tmp, sizeof(tmp));
2339 
2340 	buf = ReadDump(tmp);
2341 	if (buf == NULL)
2342 	{
2343 		return 0;
2344 	}
2345 
2346 	Zero(tmp, sizeof(tmp));
2347 	Copy(tmp, buf->Buf, MIN(buf->Size, sizeof(tmp)));
2348 	FreeBuf(buf);
2349 
2350 	return ToInt(tmp);
2351 }
2352 
2353 // Get the UID
UnixGetUID()2354 UINT UnixGetUID()
2355 {
2356 	return (UINT)getuid();
2357 }
2358 
2359 // Start the service
UnixStartService(char * name)2360 void UnixStartService(char *name)
2361 {
2362 	char *svc_name, *svc_title;
2363 	char tmp[128];
2364 	INSTANCE *inst;
2365 	char exe[MAX_PATH];
2366 	// Validate arguments
2367 	if (name == NULL)
2368 	{
2369 		return;
2370 	}
2371 
2372 	GetExeName(exe, sizeof(exe));
2373 
2374 	Format(tmp, sizeof(tmp), SVC_NAME, name);
2375 	svc_name = _SS(tmp);
2376 	Format(tmp, sizeof(tmp), SVC_TITLE, name);
2377 	svc_title = _SS(tmp);
2378 
2379 	// Examine whether the service has not been started already
2380 	inst = NewSingleInstance(NULL);
2381 	if (inst == NULL)
2382 	{
2383 		// Service is already running
2384 		UniPrint(_UU("UNIX_SVC_ALREADY_START"), svc_title, svc_name);
2385 	}
2386 	else
2387 	{
2388 		int pid;
2389 		// Begin to start the service
2390 		UniPrint(_UU("UNIX_SVC_STARTED"), svc_title);
2391 
2392 		if (UnixGetUID() != 0)
2393 		{
2394 			// Non-root warning
2395 			UniPrint(_UU("UNIX_SVC_NONROOT"));
2396 		}
2397 
2398 		FreeSingleInstance(inst);
2399 
2400 		// Create a child process
2401 		pid = fork();
2402 		if (pid == -1)
2403 		{
2404 			UniPrint(_UU("UNIX_SVC_ERROR_FORK"), svc_title);
2405 		}
2406 		else
2407 		{
2408 			if (pid == 0)
2409 			{
2410 				// Child process
2411 				char *param = UNIX_SVC_ARG_EXEC_SVC;
2412 				char **args;
2413 
2414 				// Daemonize
2415 				setsid();
2416 				UnixCloseIO();
2417 				signal(SIGHUP, SIG_IGN);
2418 
2419 				// Prepare arguments
2420 				args = ZeroMalloc(sizeof(char *) * 3);
2421 				args[0] = exe;
2422 				args[1] = param;
2423 				args[2] = NULL;
2424 
2425 				execvp(exe, args);
2426 				AbortExit();
2427 			}
2428 			else
2429 			{
2430 				// Don't write the child process number to the file
2431 //				UnixWritePidFile(pid);
2432 			}
2433 		}
2434 	}
2435 }
2436 
2437 // Stop the Service
UnixStopService(char * name)2438 void UnixStopService(char *name)
2439 {
2440 	char *svc_name, *svc_title;
2441 	char tmp[128];
2442 	INSTANCE *inst;
2443 	char exe[MAX_PATH];
2444 	UINT pid;
2445 	// Validate arguments
2446 	if (name == NULL)
2447 	{
2448 		return;
2449 	}
2450 
2451 	GetExeName(exe, sizeof(exe));
2452 
2453 	Format(tmp, sizeof(tmp), SVC_NAME, name);
2454 	svc_name = _SS(tmp);
2455 	Format(tmp, sizeof(tmp), SVC_TITLE, name);
2456 	svc_title = _SS(tmp);
2457 
2458 	inst = NewSingleInstance(NULL);
2459 	pid = UnixReadPidFile();
2460 	if (inst != NULL || pid == 0)
2461 	{
2462 		// Service is not running yet
2463 		UniPrint(_UU("UNIX_SVC_NOT_STARTED"), svc_title, svc_name);
2464 	}
2465 	else
2466 	{
2467 		// Stop the service
2468 		UniPrint(_UU("UNIX_SVC_STOPPING"), svc_title);
2469 
2470 		// Terminate the process
2471 		kill(pid, SIGTERM);
2472 #ifdef	UNIX_BSD
2473 		UnixWriteCtlFile(Rand32());
2474 #endif	// UNIX_BSD
2475 		if (UnixWaitProcessEx(pid, UNIX_SERVICE_STOP_TIMEOUT_2))
2476 		{
2477 			UniPrint(_UU("UNIX_SVC_STOPPED"), svc_title);
2478 		}
2479 		else
2480 		{
2481 			// SIGKILL
2482 			char tmp[256];
2483 
2484 			Format(tmp, sizeof(tmp), "killall -KILL %s", name);
2485 
2486 			UniPrint(_UU("UNIX_SVC_STOP_FAILED"), svc_title);
2487 			system(tmp);
2488 		}
2489 	}
2490 
2491 	FreeSingleInstance(inst);
2492 }
2493 
2494 // Handler of the stop signal to the process
UnixSigTermHandler(int signum)2495 void UnixSigTermHandler(int signum)
2496 {
2497 	if (signum == SIGTERM)
2498 	{
2499 		unix_svc_terminate = true;
2500 	}
2501 }
2502 
2503 // The thread for stop service
UnixStopThread(THREAD * t,void * param)2504 void UnixStopThread(THREAD *t, void *param)
2505 {
2506 	SERVICE_FUNCTION *stop = (SERVICE_FUNCTION *)param;
2507 	// Validate arguments
2508 	if (t == NULL || param == NULL)
2509 	{
2510 		return;
2511 	}
2512 
2513 	stop();
2514 }
2515 
2516 // Execute the main body of the service
UnixExecService(char * name,SERVICE_FUNCTION * start,SERVICE_FUNCTION * stop)2517 void UnixExecService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
2518 {
2519 	char *svc_name, *svc_title;
2520 	char tmp[128];
2521 	INSTANCE *inst;
2522 	UINT yobi_size = 1024 * 128;
2523 	void *yobi1, *yobi2;
2524 	UINT saved_ctl;
2525 	// Validate arguments
2526 	if (start == NULL || stop == NULL || name == NULL)
2527 	{
2528 		return;
2529 	}
2530 
2531 	Format(tmp, sizeof(tmp), SVC_NAME, name);
2532 	svc_name = _SS(tmp);
2533 	Format(tmp, sizeof(tmp), SVC_TITLE, name);
2534 	svc_title = _SS(tmp);
2535 
2536 	UnixWriteCtlFile(Rand32());
2537 	saved_ctl = UnixReadCtlFile();
2538 
2539 	inst = NewSingleInstance(NULL);
2540 	if (inst != NULL)
2541 	{
2542 		THREAD *t;
2543 
2544 		yobi1 = ZeroMalloc(yobi_size);
2545 		yobi2 = ZeroMalloc(yobi_size);
2546 
2547 		// Start
2548 		UnixWritePidFile(getpid());
2549 
2550 		start();
2551 
2552 		// Starting complete. wait for arriving SIGTERM from another process
2553 		signal(SIGTERM, &UnixSigTermHandler);
2554 		while (unix_svc_terminate == false)
2555 		{
2556 #if	!(defined(UNIX_BSD) || defined(UNIX_MACOS))
2557 			pause();
2558 #else	// defined(UNIX_BSD) || defined(UNIX_MACOS)
2559 			if (UnixReadCtlFile() != saved_ctl)
2560 			{
2561 				break;
2562 			}
2563 
2564 			SleepThread(1394);
2565 #endif	// defined(UNIX_BSD) || defined(UNIX_MACOS)
2566 		}
2567 
2568 		// Stop
2569 		Free(yobi1);
2570 		t = NewThread(UnixStopThread, stop);
2571 		if (t == NULL || (WaitThread(t, UNIX_SERVICE_STOP_TIMEOUT_1) == false))
2572 		{
2573 			// Terminate forcibly if creation of a halting thread have
2574 			// failed or timed out
2575 			Free(yobi2);
2576 			FreeSingleInstance(inst);
2577 			UnixDeletePidFile();
2578 			_exit(0);
2579 		}
2580 		ReleaseThread(t);
2581 
2582 		// Delete the PID file
2583 		UnixDeletePidFile();
2584 
2585 		// Delete the CTL file
2586 		UnixDeleteCtlFile();
2587 
2588 		FreeSingleInstance(inst);
2589 
2590 		Free(yobi2);
2591 	}
2592 }
2593 
2594 // Get whether the process with the specified pid exists
UnixIsProcess(UINT pid)2595 bool UnixIsProcess(UINT pid)
2596 {
2597 	if (getsid((pid_t)pid) == -1)
2598 	{
2599 		return false;
2600 	}
2601 
2602 	return true;
2603 }
2604 
2605 // Wait for the termination of the specified process
UnixWaitProcessEx(UINT pid,UINT timeout)2606 bool UnixWaitProcessEx(UINT pid,  UINT timeout)
2607 {
2608 	UINT64 start_tick = Tick64();
2609 	UINT64 end_tick = start_tick + (UINT64)timeout;
2610 	if (timeout == INFINITE)
2611 	{
2612 		end_tick = 0;
2613 	}
2614 	while (UnixIsProcess(pid))
2615 	{
2616 		if (end_tick != 0)
2617 		{
2618 			if (end_tick < Tick64())
2619 			{
2620 				return false;
2621 			}
2622 		}
2623 		SleepThread(100);
2624 	}
2625 	return true;
2626 }
2627 
2628 // Description of how to start
UnixUsage(char * name)2629 void UnixUsage(char *name)
2630 {
2631 	char *svc_name, *svc_title;
2632 	char tmp[128];
2633 	// Validate arguments
2634 	if (name == NULL)
2635 	{
2636 		return;
2637 	}
2638 
2639 	Format(tmp, sizeof(tmp), SVC_NAME, name);
2640 	svc_name = _SS(tmp);
2641 	Format(tmp, sizeof(tmp), SVC_TITLE, name);
2642 	svc_title = _SS(tmp);
2643 
2644 	UniPrint(_UU("UNIX_SVC_HELP"), svc_title, svc_name, svc_name, svc_title, svc_name, svc_title);
2645 }
2646 
2647 // Main function of the UNIX service
UnixService(int argc,char * argv[],char * name,SERVICE_FUNCTION * start,SERVICE_FUNCTION * stop)2648 UINT UnixService(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
2649 {
2650 	// Validate arguments
2651 	if (name == NULL || start == NULL || stop == NULL)
2652 	{
2653 		return 0;
2654 	}
2655 
2656 	if (argc >= 2 && StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)
2657 	{
2658 		UINT pid;
2659 		// Start a child process
2660 		// Restart if the child process didn't exit properly
2661 
2662 RESTART_PROCESS:
2663 		pid = fork();
2664 		if ((int)pid != -1)
2665 		{
2666 			if (pid == 0)
2667 			{
2668 				// Run the main process
2669 				UnixServiceMain(argc, argv, name, start, stop);
2670 			}
2671 			else
2672 			{
2673 				int status = 0, ret;
2674 
2675 				// Wait for the termination of the child process
2676 				ret = waitpid(pid, &status, 0);
2677 
2678 				if (WIFEXITED(status) == 0)
2679 				{
2680 					// Aborted
2681 					UnixSleep(100);
2682 					goto RESTART_PROCESS;
2683 				}
2684 			}
2685 		}
2686 	}
2687 	else if (argc >= 3 && StrCmpi(argv[1], UNIX_SVC_ARG_START) == 0 && StrCmpi(argv[2], UNIX_SVC_ARG_FOREGROUND) == 0)
2688 	{
2689 #ifdef DEBUG
2690 		// If set memcheck = true, the program will be vitally slow since it will log all malloc() / realloc() / free() calls to find the cause of memory leak.
2691 		// For normal debug we set memcheck = false.
2692 		// Please set memcheck = true if you want to test the cause of memory leaks.
2693 		InitMayaqua(false, true, argc, argv);
2694 #else
2695 		InitMayaqua(false, false, argc, argv);
2696 #endif
2697 		UnixExecService(name, start, stop);
2698 		FreeMayaqua();
2699 	}
2700 	else
2701 	{
2702 		// Start normally
2703 		UnixServiceMain(argc, argv, name, start, stop);
2704 	}
2705 
2706 	return 0;
2707 }
UnixServiceMain(int argc,char * argv[],char * name,SERVICE_FUNCTION * start,SERVICE_FUNCTION * stop)2708 void UnixServiceMain(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
2709 {
2710 	UINT mode = 0;
2711 	// Start of the Mayaqua
2712 #ifdef DEBUG
2713 	// If set memcheck = true, the program will be vitally slow since it will log all malloc() / realloc() / free() calls to find the cause of memory leak.
2714 	// For normal debug we set memcheck = false.
2715 	// Please set memcheck = true if you want to test the cause of memory leaks.
2716 	InitMayaqua(false, true, argc, argv);
2717 #else
2718 	InitMayaqua(false, false, argc, argv);
2719 #endif
2720 
2721 	if (argc >= 2)
2722 	{
2723 		if (StrCmpi(argv[1], UNIX_SVC_ARG_START) == 0)
2724 		{
2725 			mode = UNIX_SVC_MODE_START;
2726 		}
2727 		if (StrCmpi(argv[1], UNIX_SVC_ARG_STOP) == 0)
2728 		{
2729 			mode = UNIX_SVC_MODE_STOP;
2730 		}
2731 		if (StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)
2732 		{
2733 			mode = UNIX_SVC_MODE_EXEC_SVC;
2734 		}
2735 		if (StrCmpi(argv[1], UNIX_ARG_EXIT) == 0)
2736 		{
2737 			mode = UNIX_SVC_MODE_EXIT;
2738 		}
2739 	}
2740 
2741 	switch (mode)
2742 	{
2743 	case UNIX_SVC_MODE_EXIT:
2744 		break;
2745 
2746 	case UNIX_SVC_MODE_START:
2747 		UnixStartService(name);
2748 		break;
2749 
2750 	case UNIX_SVC_MODE_STOP:
2751 		UnixStopService(name);
2752 		break;
2753 
2754 	case UNIX_SVC_MODE_EXEC_SVC:
2755 		UnixExecService(name, start, stop);
2756 		break;
2757 
2758 	default:
2759 		UnixUsage(name);
2760 		break;
2761 	}
2762 
2763 	// End of the Mayaqua
2764 	FreeMayaqua();
2765 
2766 	return;
2767 }
2768 
2769 #endif	// UNIX
2770