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