2017-10-19 05:48:23 +03:00
// SoftEther VPN Source Code - Developer Edition Master Branch
2014-01-04 17:00:08 +04:00
// Mayaqua Kernel
// Unix.c
// UNIX dependent code
2021-04-05 05:48:25 +03:00
# ifdef OS_UNIX
2014-01-04 17:00:08 +04:00
2021-04-05 05:48:25 +03:00
# include "Unix.h"
2014-01-04 17:00:08 +04:00
2021-04-05 05:48:25 +03:00
# include "Cfg.h"
# include "FileIO.h"
# include "GlobalConst.h"
# include "Internat.h"
# include "Kernel.h"
# include "Mayaqua.h"
# include "Memory.h"
# include "Network.h"
# include "Object.h"
# include "Str.h"
# include "Table.h"
# include "Tick64.h"
# include <errno.h>
2014-01-04 17:00:08 +04:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2021-04-05 05:48:25 +03:00
# include <dirent.h>
# include <fcntl.h>
# include <poll.h>
# include <pthread.h>
# include <signal.h>
# include <sys/mount.h>
# include <sys/param.h>
# include <sys/resource.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <sys/types.h>
2018-10-07 02:38:02 +03:00
# include <sys/utsname.h>
2021-04-05 05:48:25 +03:00
# include <sys/wait.h>
# ifdef UNIX_LINUX
# include <sys/statfs.h>
# endif
2014-01-04 17:00:08 +04:00
2022-01-07 00:09:27 +03:00
# ifdef UNIX_SOLARIS
# define USE_STATVFS
# include <sys/statvfs.h>'
# endif
2014-01-04 17:00:08 +04:00
# ifdef UNIX_MACOS
2014-01-14 18:19:37 +04:00
# ifdef NO_VLAN
2014-03-12 03:06:21 +04:00
// Struct statfs for MacOS X
2014-01-04 17:00:08 +04:00
typedef struct fsid { int32_t val [ 2 ] ; } fsid_t ;
struct statfs {
short f_otype ; /* TEMPORARY SHADOW COPY OF f_type */
short f_oflags ; /* TEMPORARY SHADOW COPY OF f_flags */
long f_bsize ; /* fundamental file system block size */
long f_iosize ; /* optimal transfer block size */
long f_blocks ; /* total data blocks in file system */
long f_bfree ; /* free blocks in fs */
long f_bavail ; /* free blocks avail to non-superuser */
long f_files ; /* total file nodes in file system */
long f_ffree ; /* free file nodes in fs */
fsid_t f_fsid ; /* file system id */
uid_t f_owner ; /* user that mounted the filesystem */
short f_reserved1 ; /* spare for later */
short f_type ; /* type of filesystem */
long f_flags ; /* copy of mount exported flags */
long f_reserved2 [ 2 ] ; /* reserved for future use */
char f_fstypename [ 15 ] ; /* fs type name */
char f_mntonname [ 90 ] ; /* directory on which mounted */
char f_mntfromname [ 90 ] ; /* mounted filesystem */
} ;
2014-02-05 20:36:42 +04:00
# else // NO_VLAN
2014-01-14 18:19:37 +04:00
# include <sys/mount.h>
2014-02-05 20:36:42 +04:00
# endif // NO_VLAN
2014-01-04 17:00:08 +04:00
# endif // UNIX_MACOS
// Scandir() function for Solaris
# ifdef UNIX_SOLARIS
# define scandir local_scandir
# define alphasort local_alphasort
int local_scandir ( const char * dir , struct dirent * * * namelist ,
int ( * select ) ( const struct dirent * ) ,
int ( * compar ) ( const struct dirent * * , const struct dirent * * ) )
{
DIR * d ;
struct dirent * entry ;
register int i = 0 ;
size_t entrysize ;
if ( ( d = opendir ( dir ) ) = = NULL )
return ( - 1 ) ;
* namelist = NULL ;
while ( ( entry = readdir ( d ) ) ! = NULL )
{
2018-08-21 09:05:31 +03:00
if ( select = = NULL | | ( * select ) ( entry ) )
2014-01-04 17:00:08 +04:00
{
* namelist = ( struct dirent * * ) realloc ( ( void * ) ( * namelist ) ,
( size_t ) ( ( i + 1 ) * sizeof ( struct dirent * ) ) ) ;
if ( * namelist = = NULL ) return ( - 1 ) ;
entrysize = sizeof ( struct dirent ) - sizeof ( entry - > d_name ) + strlen ( entry - > d_name ) + 1 ;
( * namelist ) [ i ] = ( struct dirent * ) malloc ( entrysize ) ;
if ( ( * namelist ) [ i ] = = NULL ) return ( - 1 ) ;
memcpy ( ( * namelist ) [ i ] , entry , entrysize ) ;
i + + ;
}
}
if ( closedir ( d ) ) return ( - 1 ) ;
if ( i = = 0 ) return ( - 1 ) ;
if ( compar ! = NULL )
qsort ( ( void * ) ( * namelist ) , ( size_t ) i , sizeof ( struct dirent * ) , compar ) ;
return ( i ) ;
}
int local_alphasort ( const struct dirent * * a , const struct dirent * * b )
{
return ( strcmp ( ( * a ) - > d_name , ( * b ) - > d_name ) ) ;
}
# endif // UNIX_SOLARIS
// Thread data for UNIX
typedef struct UNIXTHREAD
{
pthread_t thread ;
bool finished ;
} UNIXTHREAD ;
// Thread startup information for UNIX
typedef struct UNIXTHREADSTARTUPINFO
{
THREAD_PROC * thread_proc ;
void * param ;
THREAD * thread ;
} UNIXTHREADSTARTUPINFO ;
// Thread function prototype for UNIX
void * UnixDefaultThreadProc ( void * param ) ;
// Current process ID
static pid_t current_process_id = 0 ;
// File I/O data for UNIX
typedef struct UNIXIO
{
int fd ;
bool write_mode ;
} UNIXIO ;
// Lock file data for UNIX
typedef struct UNIXLOCKFILE
{
char FileName [ MAX_SIZE ] ;
int fd ;
} UNIXLOCKFILE ;
// Event data for UNIX
typedef struct UNIXEVENT
{
pthread_mutex_t mutex ;
pthread_cond_t cond ;
bool signal ;
} UNIXEVENT ;
static pthread_mutex_t get_time_lock ;
static pthread_mutex_t malloc_lock ;
static bool high_process = false ;
static bool unix_svc_terminate = false ;
static int solaris_sleep_p1 = - 1 , solaris_sleep_p2 = - 1 ;
// Create a dispatch table
OS_DISPATCH_TABLE * UnixGetDispatchTable ( )
{
static OS_DISPATCH_TABLE t =
{
UnixInit ,
UnixFree ,
UnixMemoryAlloc ,
UnixMemoryReAlloc ,
UnixMemoryFree ,
UnixGetTick ,
UnixGetSystemTime ,
UnixInc32 ,
UnixDec32 ,
UnixSleep ,
UnixNewLock ,
UnixLock ,
UnixUnlock ,
UnixDeleteLock ,
UnixInitEvent ,
UnixSetEvent ,
UnixResetEvent ,
UnixWaitEvent ,
UnixFreeEvent ,
UnixWaitThread ,
UnixFreeThread ,
UnixInitThread ,
UnixThreadId ,
UnixFileOpen ,
UnixFileOpenW ,
UnixFileCreate ,
UnixFileCreateW ,
UnixFileWrite ,
UnixFileRead ,
UnixFileClose ,
UnixFileFlush ,
UnixFileSize ,
UnixFileSeek ,
UnixFileDelete ,
UnixFileDeleteW ,
UnixMakeDir ,
UnixMakeDirW ,
UnixDeleteDir ,
UnixDeleteDirW ,
UnixGetCallStack ,
UnixGetCallStackSymbolInfo ,
UnixFileRename ,
UnixFileRenameW ,
UnixRun ,
UnixRunW ,
UnixIsSupportedOs ,
UnixGetOsInfo ,
UnixAlert ,
UnixAlertW ,
UnixGetProductId ,
UnixSetHighPriority ,
UnixRestorePriority ,
UnixNewSingleInstance ,
UnixFreeSingleInstance ,
UnixGetMemInfo ,
UnixYield ,
} ;
return & t ;
}
static void * signal_received_for_ignore ( int sig , siginfo_t * info , void * ucontext )
{
return NULL ;
}
// Ignore the signal flew to the thread
void UnixIgnoreSignalForThread ( int sig )
{
struct sigaction sa ;
Zero ( & sa , sizeof ( sa ) ) ;
sa . sa_handler = NULL ;
sa . sa_sigaction = signal_received_for_ignore ;
sa . sa_flags = SA_SIGINFO ;
sigemptyset ( & sa . sa_mask ) ;
sigaction ( SIGUSR1 , & sa , NULL ) ;
}
// Disable the off-loading function of the specific Ethernet device
void UnixDisableInterfaceOffload ( char * name )
{
# ifdef UNIX_LINUX
char tmp [ MAX_SIZE ] ;
TOKEN_LIST * t ;
char * names = " rx tx sg tso ufo gso gro lro rxvlan txvlan ntuple rxhash " ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
t = ParseToken ( names , " " ) ;
if ( t ! = NULL )
{
UINT i ;
for ( i = 0 ; i < t - > NumTokens ; i + + )
{
char * a = t - > Token [ i ] ;
2018-07-30 07:35:02 +03:00
Format ( tmp , sizeof ( tmp ) , " ethtool -K %s %s off 2>/dev/null " , name , a ) ;
2014-01-04 17:00:08 +04:00
FreeToken ( UnixExec ( tmp ) ) ;
}
}
FreeToken ( t ) ;
# endif // UNIX_LINUX
}
// Validate whether the UNIX is running in a VM
bool UnixIsInVmMain ( )
{
TOKEN_LIST * t = NULL ;
bool ret = false ;
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 " ;
# ifdef UNIX_LINUX
t = UnixExec ( " /bin/dmesg " ) ;
if ( t ! = NULL )
{
BUF * b = NewBuf ( ) ;
UINT i ;
for ( i = 0 ; i < t - > NumTokens ; i + + )
{
char * line = t - > Token [ i ] ;
AddBufStr ( b , line ) ;
AddBufStr ( b , " " ) ;
}
WriteBufInt ( b , 0 ) ;
// printf("%s\n", b->Buf);
ret = InStrList ( b - > Buf , vm_str_list , " , " , false ) ;
FreeBuf ( b ) ;
FreeToken ( t ) ;
}
# endif // UNIX_LINUX
return ret ;
}
bool UnixIsInVm ( )
{
static bool is_in_vm_flag = false ;
static bool is_in_vm_ret = false ;
if ( is_in_vm_flag = = false )
{
is_in_vm_ret = UnixIsInVmMain ( ) ;
is_in_vm_flag = true ;
}
return is_in_vm_ret ;
}
// Run quietly in the UNIX
void UnixExecSilent ( char * cmd )
{
char tmp [ MAX_SIZE ] ;
// Validate arguments
if ( cmd = = NULL )
{
return ;
}
Format ( tmp , sizeof ( tmp ) , " %s 2>/dev/null " , cmd ) ;
FreeToken ( UnixExec ( tmp ) ) ;
}
// Enable / disable the ESP processing in the kernel
void UnixSetEnableKernelEspProcessing ( bool b )
{
if ( GetOsInfo ( ) - > OsType = = OSTYPE_MACOS_X )
{
// Mac OS X
if ( b )
{
UnixExecSilent ( " /usr/sbin/sysctl -w net.inet.ipsec.esp_port=4500 " ) ;
}
else
{
UnixExecSilent ( " /usr/sbin/sysctl -w net.inet.ipsec.esp_port=4501 " ) ;
}
}
}
// Run a command and return its result
TOKEN_LIST * UnixExec ( char * cmd )
{
FILE * fp ;
char tmp [ MAX_SIZE ] ;
char * ptr ;
LIST * o ;
UINT i ;
TOKEN_LIST * ret ;
// Validate arguments
if ( cmd = = NULL )
{
return NULL ;
}
fp = popen ( cmd , " r " ) ;
if ( fp = = NULL )
{
return NULL ;
}
o = NewList ( NULL ) ;
while ( true )
{
fgets ( tmp , sizeof ( tmp ) , fp ) ;
if ( feof ( fp ) )
{
break ;
}
ptr = strchr ( tmp , ' \n ' ) ;
if ( ptr ! = NULL )
{
* ptr = 0 ;
}
ptr = strchr ( tmp , ' \r ' ) ;
if ( ptr ! = NULL )
{
* ptr = 0 ;
}
Add ( o , CopyStr ( tmp ) ) ;
}
pclose ( fp ) ;
ret = ListToTokenList ( o ) ;
FreeStrList ( o ) ;
return ret ;
}
// Initialize the Sleep for Solaris
void UnixInitSolarisSleep ( )
{
char tmp [ MAX_SIZE ] ;
UnixNewPipe ( & solaris_sleep_p1 , & solaris_sleep_p2 ) ;
2018-08-21 09:05:31 +03:00
( void ) read ( solaris_sleep_p1 , tmp , sizeof ( tmp ) ) ;
2014-01-04 17:00:08 +04:00
}
// Release the Sleep for Solaris
void UnixFreeSolarisSleep ( )
{
UnixDeletePipe ( solaris_sleep_p1 , solaris_sleep_p2 ) ;
solaris_sleep_p1 = - 1 ;
solaris_sleep_p2 = - 1 ;
}
// Sleep for Solaris
void UnixSolarisSleep ( UINT msec )
{
struct pollfd p ;
memset ( & p , 0 , sizeof ( p ) ) ;
p . fd = solaris_sleep_p1 ;
p . events = POLLIN ;
2018-08-22 08:40:13 +03:00
( void ) poll ( & p , 1 , msec = = INFINITE ? - 1 : ( int ) msec ) ;
2014-01-04 17:00:08 +04:00
}
// Get the free space of the disk
bool UnixGetDiskFree ( char * path , UINT64 * free_size , UINT64 * used_size , UINT64 * total_size )
{
char tmp [ MAX_PATH ] ;
bool ret = false ;
// Validate arguments
if ( path = = NULL )
{
return false ;
}
NormalizePath ( tmp , sizeof ( tmp ) , path ) ;
while ( ( ret = UnixGetDiskFreeMain ( tmp , free_size , used_size , total_size ) ) = = false )
{
if ( StrCmpi ( tmp , " / " ) = = 0 )
{
break ;
}
GetDirNameFromFilePath ( tmp , sizeof ( tmp ) , tmp ) ;
}
return ret ;
}
bool UnixGetDiskFreeMain ( char * path , UINT64 * free_size , UINT64 * used_size , UINT64 * total_size )
{
# ifndef USE_STATVFS
struct statfs st ;
char tmp [ MAX_PATH ] ;
UINT64 v1 = 0 , v2 = 0 ;
bool ret = false ;
// Validate arguments
if ( path = = NULL )
{
return false ;
}
NormalizePath ( tmp , sizeof ( tmp ) , path ) ;
Zero ( & st , sizeof ( st ) ) ;
if ( statfs ( tmp , & st ) = = 0 )
{
v1 = ( UINT64 ) st . f_bsize * ( UINT64 ) st . f_bavail ;
v2 = ( UINT64 ) st . f_bsize * ( UINT64 ) st . f_blocks ;
ret = true ;
}
if ( free_size ! = NULL )
{
* free_size = v1 ;
}
if ( total_size ! = NULL )
{
* total_size = v2 ;
}
if ( used_size ! = NULL )
{
* used_size = v2 - v1 ;
}
return ret ;
# else // USE_STATVFS
struct statvfs st ;
char tmp [ MAX_PATH ] ;
UINT64 v1 = 0 , v2 = 0 ;
bool ret = false ;
// Validate arguments
if ( path = = NULL )
{
return false ;
}
NormalizePath ( tmp , sizeof ( tmp ) , path ) ;
Zero ( & st , sizeof ( st ) ) ;
if ( statvfs ( tmp , & st ) = = 0 )
{
v1 = ( UINT64 ) st . f_bsize * ( UINT64 ) st . f_bavail ;
v2 = ( UINT64 ) st . f_bsize * ( UINT64 ) st . f_blocks ;
ret = true ;
}
if ( free_size ! = NULL )
{
* free_size = v1 ;
}
if ( total_size ! = NULL )
{
* total_size = v2 ;
}
if ( used_size ! = NULL )
{
* used_size = v2 - v1 ;
}
return ret ;
# endif // USE_STATVFS
}
// Directory enumeration
DIRLIST * UnixEnumDirEx ( char * dirname , COMPARE * compare )
{
char tmp [ MAX_PATH ] ;
DIRLIST * d ;
int n ;
struct dirent * * e ;
LIST * o ;
// Validate arguments
if ( dirname = = NULL )
{
return NULL ;
}
o = NewListFast ( compare ) ;
NormalizePath ( tmp , sizeof ( tmp ) , dirname ) ;
if ( StrLen ( tmp ) > = 1 & & tmp [ StrLen ( tmp ) - 1 ] ! = ' / ' )
{
StrCat ( tmp , sizeof ( tmp ) , " / " ) ;
}
e = NULL ;
n = scandir ( tmp , & e , 0 , alphasort ) ;
if ( StrLen ( tmp ) > = 1 & & tmp [ StrLen ( tmp ) - 1 ] = = ' / ' )
{
tmp [ StrLen ( tmp ) - 1 ] = 0 ;
}
if ( n > = 0 & & e ! = NULL )
{
UINT i ;
for ( i = 0 ; i < ( UINT ) n ; i + + )
{
char * filename = e [ i ] - > d_name ;
if ( filename ! = NULL )
{
if ( StrCmpi ( filename , " .. " ) ! = 0 & & StrCmpi ( filename , " . " ) ! = 0 )
{
char fullpath [ MAX_PATH ] ;
struct stat st ;
Format ( fullpath , sizeof ( fullpath ) , " %s/%s " , tmp , filename ) ;
Zero ( & st , sizeof ( st ) ) ;
if ( stat ( fullpath , & st ) = = 0 )
{
DIRENT * f = ZeroMalloc ( sizeof ( DIRENT ) ) ;
SYSTEMTIME t ;
f - > Folder = S_ISDIR ( st . st_mode ) ? true : false ;
f - > FileName = CopyStr ( filename ) ;
f - > FileNameW = CopyUtfToUni ( f - > FileName ) ;
Zero ( & t , sizeof ( t ) ) ;
TimeToSystem ( & t , st . st_ctime ) ;
f - > CreateDate = SystemToUINT64 ( & t ) ;
Zero ( & t , sizeof ( t ) ) ;
TimeToSystem ( & t , st . st_mtime ) ;
f - > UpdateDate = SystemToUINT64 ( & t ) ;
if ( f - > Folder = = false )
{
f - > FileSize = st . st_size ;
}
Add ( o , f ) ;
}
}
}
free ( e [ i ] ) ;
}
free ( e ) ;
}
Sort ( o ) ;
d = ZeroMalloc ( sizeof ( DIRLIST ) ) ;
d - > NumFiles = LIST_NUM ( o ) ;
d - > File = ToArray ( o ) ;
ReleaseList ( o ) ;
return d ;
}
DIRLIST * UnixEnumDirExW ( wchar_t * dirname , COMPARE * compare )
{
char * dirname_a = CopyUniToUtf ( dirname ) ;
DIRLIST * ret ;
ret = UnixEnumDirEx ( dirname_a , compare ) ;
Free ( dirname_a ) ;
return ret ;
}
// Check the execute permissions of the specified file
bool UnixCheckExecAccess ( char * name )
{
// Validate arguments
if ( name = = NULL )
{
return false ;
}
if ( access ( name , X_OK ) = = 0 )
{
return true ;
}
return false ;
}
bool UnixCheckExecAccessW ( wchar_t * name )
{
char * name_a ;
bool ret ;
// Validate arguments
if ( name = = NULL )
{
return false ;
}
name_a = CopyUniToUtf ( name ) ;
ret = UnixCheckExecAccess ( name_a ) ;
Free ( name_a ) ;
return ret ;
}
// Raise the priority of the thread to highest
void UnixSetThreadPriorityRealtime ( )
{
struct sched_param p ;
Zero ( & p , sizeof ( p ) ) ;
p . sched_priority = 255 ;
pthread_setschedparam ( pthread_self ( ) , SCHED_RR , & p ) ;
}
// Get the current directory
void UnixGetCurrentDir ( char * dir , UINT size )
{
// Validate arguments
if ( dir = = NULL )
{
return ;
}
getcwd ( dir , size ) ;
}
void UnixGetCurrentDirW ( wchar_t * dir , UINT size )
{
char dir_a [ MAX_PATH ] ;
UnixGetCurrentDir ( dir_a , sizeof ( dir_a ) ) ;
UtfToUni ( dir , size , dir_a ) ;
}
// Yield
void UnixYield ( )
{
# ifdef UNIX_SOLARIS
UnixSolarisSleep ( 1 ) ;
# else
usleep ( 1000 ) ;
# endif
}
// Get the memory information
void UnixGetMemInfo ( MEMINFO * info )
{
// Validate arguments
if ( info = = NULL )
{
return ;
}
// I don't know!!
Zero ( info , sizeof ( MEMINFO ) ) ;
}
// Release of the single instance
void UnixFreeSingleInstance ( void * data )
{
UNIXLOCKFILE * o ;
struct flock lock ;
// Validate arguments
if ( data = = NULL )
{
return ;
}
o = ( UNIXLOCKFILE * ) data ;
Zero ( & lock , sizeof ( lock ) ) ;
lock . l_type = F_UNLCK ;
lock . l_whence = SEEK_SET ;
2018-08-21 09:05:31 +03:00
( void ) fcntl ( o - > fd , F_SETLK , & lock ) ;
2014-01-04 17:00:08 +04:00
close ( o - > fd ) ;
2018-08-22 08:40:13 +03:00
( void ) remove ( o - > FileName ) ;
2014-01-04 17:00:08 +04:00
Free ( data ) ;
}
// Creating a single instance
void * UnixNewSingleInstance ( char * instance_name )
{
UNIXLOCKFILE * ret ;
char tmp [ MAX_SIZE ] ;
char name [ MAX_SIZE ] ;
char dir [ MAX_PATH ] ;
int fd ;
struct flock lock ;
int mode = S_IRUSR | S_IWUSR ;
// Validate arguments
if ( instance_name = = NULL )
{
GetExeName ( tmp , sizeof ( tmp ) ) ;
HashInstanceName ( tmp , sizeof ( tmp ) , tmp ) ;
}
else
{
StrCpy ( tmp , sizeof ( tmp ) , instance_name ) ;
}
2019-11-29 16:58:57 +03:00
GetPidDir ( dir , sizeof ( dir ) ) ;
2014-01-04 17:00:08 +04:00
// File name generation
Format ( name , sizeof ( name ) , " %s/.%s " , dir , tmp ) ;
fd = open ( name , O_WRONLY ) ;
if ( fd = = - 1 )
{
fd = creat ( name , mode ) ;
}
if ( fd = = - 1 )
{
Format ( tmp , sizeof ( tmp ) , " Unable to create %s. " , name ) ;
Alert ( tmp , NULL ) ;
exit ( 0 ) ;
return NULL ;
}
fchmod ( fd , mode ) ;
2018-08-21 09:05:31 +03:00
( void ) chmod ( name , mode ) ;
2014-01-04 17:00:08 +04:00
Zero ( & lock , sizeof ( lock ) ) ;
lock . l_type = F_WRLCK ;
lock . l_whence = SEEK_SET ;
if ( fcntl ( fd , F_SETLK , & lock ) = = - 1 )
{
2018-09-28 16:39:38 +03:00
close ( fd ) ;
2014-01-04 17:00:08 +04:00
return NULL ;
}
else
{
ret = ZeroMalloc ( sizeof ( UNIXLOCKFILE ) ) ;
ret - > fd = fd ;
StrCpy ( ret - > FileName , sizeof ( ret - > FileName ) , name ) ;
return ( void * ) ret ;
}
}
2014-10-03 19:09:23 +04:00
// Set the high oom score
void UnixSetHighOomScore ( )
{
IO * o ;
char tmp [ 256 ] ;
sprintf ( tmp , " /proc/%u/oom_score_adj " , getpid ( ) ) ;
o = UnixFileCreate ( tmp ) ;
if ( o ! = NULL )
{
char tmp [ 128 ] ;
sprintf ( tmp , " %u \n " , 800 ) ;
UnixFileWrite ( o , tmp , strlen ( tmp ) ) ;
UnixFileClose ( o , false ) ;
}
}
2014-01-04 17:00:08 +04:00
// Raise the priority of the process
void UnixSetHighPriority ( )
{
if ( high_process = = false )
{
UINT pid = getpid ( ) ;
UINT pgid = getpgid ( pid ) ;
high_process = true ;
nice ( - 20 ) ;
setpriority ( PRIO_PROCESS , pid , - 20 ) ;
setpriority ( PRIO_PGRP , pgid , - 20 ) ;
}
}
// Restore the priority of the process
void UnixRestorePriority ( )
{
if ( high_process ! = false )
{
high_process = false ;
nice ( 20 ) ;
}
}
2017-10-18 12:24:21 +03:00
UINT UnixGetNumberOfCpuInner ( )
{
BUF * b ;
UINT ret = 0 ;
b = ReadDump ( " /proc/cpuinfo " ) ;
if ( b ! = NULL )
{
while ( true )
{
char * line = CfgReadNextLine ( b ) ;
if ( line = = NULL )
{
break ;
}
if ( IsEmptyStr ( line ) = = false )
{
TOKEN_LIST * t = ParseToken ( line , " : " ) ;
if ( t ! = NULL )
{
if ( t - > NumTokens > = 2 )
{
char * key = t - > Token [ 0 ] ;
char * value = t - > Token [ 1 ] ;
Trim ( key ) ;
Trim ( value ) ;
if ( StrCmpi ( key , " processor " ) = = 0 )
{
if ( IsNum ( value ) )
{
UINT i = ToInt ( value ) + 1 ;
if ( i > = 1 & & i < = 128 )
{
ret = MAX ( ret , i ) ;
}
}
}
}
FreeToken ( t ) ;
}
}
Free ( line ) ;
}
FreeBuf ( b ) ;
}
return ret ;
}
2014-01-04 17:00:08 +04:00
// Get the product ID
char * UnixGetProductId ( )
{
return CopyStr ( " -- " ) ;
}
// Display an alert
void UnixAlertW ( wchar_t * msg , wchar_t * caption )
{
char * msg8 = CopyUniToUtf ( msg ) ;
char * caption8 = CopyUniToUtf ( caption ) ;
UnixAlert ( msg8 , caption8 ) ;
Free ( msg8 ) ;
Free ( caption8 ) ;
}
void UnixAlert ( char * msg , char * caption )
{
char * tag =
" -- Alert: %s -- \n %s \n " ;
// Validate arguments
if ( msg = = NULL )
{
msg = " Alert " ;
}
if ( caption = = NULL )
{
caption = CEDAR_PRODUCT_STR " VPN Kernel " ;
}
printf ( tag , caption , msg ) ;
}
// Get the information of the current OS
void UnixGetOsInfo ( OS_INFO * info )
{
2018-10-07 02:38:02 +03:00
struct utsname unix_info ;
2014-01-04 17:00:08 +04:00
// Validate arguments
if ( info = = NULL )
{
return ;
}
Zero ( info , sizeof ( OS_INFO ) ) ;
# ifdef UNIX_SOLARIS
info - > OsType = OSTYPE_SOLARIS ;
2018-08-05 10:08:56 +03:00
# elif UNIX_CYGWIN
2014-01-04 17:00:08 +04:00
info - > OsType = OSTYPE_CYGWIN ;
2018-08-05 10:08:56 +03:00
# elif UNIX_MACOS
2014-01-04 17:00:08 +04:00
info - > OsType = OSTYPE_MACOS_X ;
2018-08-05 10:08:56 +03:00
# elif UNIX_BSD
2014-01-04 17:00:08 +04:00
info - > OsType = OSTYPE_BSD ;
2018-08-05 10:08:56 +03:00
# elif UNIX_LINUX
2014-01-04 17:00:08 +04:00
info - > OsType = OSTYPE_LINUX ;
2018-08-05 10:08:56 +03:00
# else
info - > OsType = OSTYPE_UNIX_UNKNOWN ;
# endif
2014-01-04 17:00:08 +04:00
2018-10-07 02:38:02 +03:00
info - > OsSystemName = CopyStr ( OsTypeToStr ( info - > OsType ) ) ;
info - > KernelName = CopyStr ( " UNIX " ) ;
2014-01-04 17:00:08 +04:00
2018-10-07 02:38:02 +03:00
if ( uname ( & unix_info ) > - 1 )
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
info - > OsProductName = CopyStr ( unix_info . sysname ) ;
info - > OsVersion = CopyStr ( unix_info . release ) ;
info - > KernelVersion = CopyStr ( unix_info . version ) ;
2014-01-04 17:00:08 +04:00
}
else
{
2018-10-07 02:38:02 +03:00
Debug ( " UnixGetOsInfo(): uname() failed with error: %s \n " , strerror ( errno ) ) ;
2014-01-04 17:00:08 +04:00
2018-10-07 02:38:02 +03:00
info - > OsProductName = CopyStr ( OsTypeToStr ( info - > OsType ) ) ;
info - > OsVersion = CopyStr ( " Unknown " ) ;
info - > KernelVersion = CopyStr ( " Unknown " ) ;
}
# ifdef UNIX_LINUX
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
BUF * buffer = ReadDump ( " /etc/os-release " ) ;
if ( buffer = = NULL )
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
buffer = ReadDump ( " /usr/lib/os-release " ) ;
2014-01-04 17:00:08 +04:00
}
2018-10-07 02:38:02 +03:00
if ( buffer ! = NULL )
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
LIST * values = NewEntryList ( buffer - > Buf , " \n " , " = " ) ;
FreeBuf ( buffer ) ;
if ( EntryListHasKey ( values , " NAME " ) )
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
char * str = EntryListStrValue ( values , " NAME " ) ;
TrimQuotes ( str ) ;
Free ( info - > OsProductName ) ;
info - > OsProductName = CopyStr ( str ) ;
2014-01-04 17:00:08 +04:00
}
2018-10-07 02:38:02 +03:00
if ( EntryListHasKey ( values , " HOME_URL " ) )
2014-01-04 17:00:08 +04:00
{
2018-10-07 02:38:02 +03:00
char * str = EntryListStrValue ( values , " HOME_URL " ) ;
TrimQuotes ( str ) ;
info - > OsVendorName = CopyStr ( str ) ;
2014-01-04 17:00:08 +04:00
}
2018-10-07 02:38:02 +03:00
if ( EntryListHasKey ( values , " VERSION " ) )
{
char * str = EntryListStrValue ( values , " VERSION " ) ;
TrimQuotes ( str ) ;
Free ( info - > OsVersion ) ;
info - > OsVersion = CopyStr ( str ) ;
}
else
{
// Debian testing/sid doesn't provide the version in /etc/os-release
buffer = ReadDump ( " /etc/debian_version " ) ;
if ( buffer ! = NULL )
{
Free ( info - > OsVersion ) ;
info - > OsVersion = CfgReadNextLine ( buffer ) ;
FreeBuf ( buffer ) ;
}
}
2014-01-04 17:00:08 +04:00
2018-10-07 02:38:02 +03:00
FreeEntryList ( values ) ;
2014-01-04 17:00:08 +04:00
}
}
2018-10-07 02:38:02 +03:00
# endif
2014-01-04 17:00:08 +04:00
}
// Examine whether the current OS is supported by the PacketiX VPN Kernel
bool UnixIsSupportedOs ( )
{
// Support all UNIX OS which can run PacketiX VPN
return true ;
}
// Run a specified command
bool UnixRunW ( wchar_t * filename , wchar_t * arg , bool hide , bool wait )
{
char * filename8 = CopyUniToUtf ( filename ) ;
char * arg8 = CopyUniToUtf ( arg ) ;
bool ret = UnixRun ( filename8 , arg8 , hide , wait ) ;
Free ( filename8 ) ;
Free ( arg8 ) ;
return ret ;
}
bool UnixRun ( char * filename , char * arg , bool hide , bool wait )
{
TOKEN_LIST * t ;
2016-10-09 09:23:25 +03:00
char * * args ;
2014-01-04 17:00:08 +04:00
UINT ret ;
2016-10-09 09:23:25 +03:00
2014-01-04 17:00:08 +04:00
// Validate arguments
if ( filename = = NULL )
{
return false ;
}
if ( arg = = NULL )
{
arg = " " ;
}
2016-10-09 09:23:25 +03:00
Print ( " " , filename , arg ) ;
t = ParseToken ( arg , " " ) ;
if ( t = = NULL )
{
return false ;
}
else
{
UINT num_args ;
UINT i ;
num_args = t - > NumTokens + 2 ;
args = ZeroMalloc ( sizeof ( char * ) * num_args ) ;
args [ 0 ] = filename ;
for ( i = 1 ; i < num_args - 1 ; i + + )
{
args [ i ] = t - > Token [ i - 1 ] ;
}
}
2014-01-04 17:00:08 +04:00
// Create a child process
ret = fork ( ) ;
if ( ret = = - 1 )
{
// Child process creation failure
return false ;
}
if ( ret = = 0 )
{
// Child process
if ( hide )
{
// Close the standard I/O
UnixCloseIO ( ) ;
}
2016-10-09 09:23:25 +03:00
execvp ( filename , args ) ;
AbortExit ( ) ;
2014-01-04 17:00:08 +04:00
}
else
{
// Parent process
pid_t pid = ( pid_t ) ret ;
2016-10-09 09:23:25 +03:00
Free ( args ) ;
FreeToken ( t ) ;
2014-01-04 17:00:08 +04:00
if ( wait )
{
int status = 0 ;
// Wait for the termination of the child process
if ( waitpid ( pid , & status , 0 ) = = - 1 )
{
return false ;
}
if ( WEXITSTATUS ( status ) = = 0 )
{
return true ;
}
else
{
return false ;
}
}
return true ;
}
}
// Close the standard I/O
void UnixCloseIO ( )
{
static bool close_io_first = false ;
// Execute only once
if ( close_io_first )
{
return ;
}
else
{
close ( 0 ) ;
close ( 1 ) ;
close ( 2 ) ;
2018-08-22 08:40:13 +03:00
( void ) open ( " /dev/null " , O_RDWR ) ;
2014-01-04 17:00:08 +04:00
dup2 ( 0 , 1 ) ;
dup2 ( 0 , 2 ) ;
close_io_first = false ;
}
}
// Change the file name
bool UnixFileRenameW ( wchar_t * old_name , wchar_t * new_name )
{
char * old_name8 = CopyUniToUtf ( old_name ) ;
char * new_name8 = CopyUniToUtf ( new_name ) ;
bool ret = UnixFileRename ( old_name8 , new_name8 ) ;
Free ( old_name8 ) ;
Free ( new_name8 ) ;
return ret ;
}
bool UnixFileRename ( char * old_name , char * new_name )
{
// Validate arguments
if ( old_name = = NULL | | new_name = = NULL )
{
return false ;
}
if ( rename ( old_name , new_name ) ! = 0 )
{
return false ;
}
return true ;
}
// Get the call stack
CALLSTACK_DATA * UnixGetCallStack ( )
{
// This is not supported on non-Win32
return NULL ;
}
// Get the symbol information from the call stack
bool UnixGetCallStackSymbolInfo ( CALLSTACK_DATA * s )
{
// This is not supported on non-Win32
return false ;
}
// Delete the directory
bool UnixDeleteDirW ( wchar_t * name )
{
char * name8 = CopyUniToUtf ( name ) ;
bool ret = UnixDeleteDir ( name8 ) ;
Free ( name8 ) ;
return ret ;
}
bool UnixDeleteDir ( char * name )
{
// Validate arguments
if ( name = = NULL )
{
return false ;
}
if ( rmdir ( name ) ! = 0 )
{
return false ;
}
return true ;
}
// Create a directory
bool UnixMakeDirW ( wchar_t * name )
{
char * name8 = CopyUniToUtf ( name ) ;
bool ret = UnixMakeDir ( name8 ) ;
Free ( name8 ) ;
return ret ;
}
bool UnixMakeDir ( char * name )
{
// Validate arguments
if ( name = = NULL )
{
return false ;
}
if ( mkdir ( name , 0700 ) ! = 0 )
{
return false ;
}
return true ;
}
// Delete the file
bool UnixFileDeleteW ( wchar_t * name )
{
bool ret ;
char * name8 = CopyUniToUtf ( name ) ;
ret = UnixFileDelete ( name8 ) ;
Free ( name8 ) ;
return ret ;
}
bool UnixFileDelete ( char * name )
{
// Validate arguments
if ( name = = NULL )
{
return false ;
}
if ( remove ( name ) ! = 0 )
{
return false ;
}
return true ;
}
// Seek the file
bool UnixFileSeek ( void * pData , UINT mode , int offset )
{
UNIXIO * p ;
UINT ret ;
// Validate arguments
if ( pData = = NULL )
{
return 0 ;
}
if ( mode ! = FILE_BEGIN & & mode ! = FILE_END & & mode ! = FILE_CURRENT )
{
return false ;
}
p = ( UNIXIO * ) pData ;
ret = lseek ( p - > fd , offset , mode ) ;
if ( ret = = - 1 )
{
return false ;
}
return true ;
}
// Get the file size
UINT64 UnixFileSize ( void * pData )
{
struct stat st ;
UNIXIO * p ;
int r ;
// Validate arguments
if ( pData = = NULL )
{
return 0 ;
}
p = ( UNIXIO * ) pData ;
Zero ( & st , sizeof ( st ) ) ;
r = fstat ( p - > fd , & st ) ;
if ( r ! = 0 )
{
return 0 ;
}
return ( UINT64 ) st . st_size ;
}
// Write to the file
bool UnixFileWrite ( void * pData , void * buf , UINT size )
{
UNIXIO * p ;
UINT ret ;
// Validate arguments
if ( pData = = NULL | | buf = = NULL | | size = = 0 )
{
return false ;
}
p = ( UNIXIO * ) pData ;
ret = write ( p - > fd , buf , size ) ;
if ( ret ! = size )
{
return false ;
}
return true ;
}
// Read from the file
bool UnixFileRead ( void * pData , void * buf , UINT size )
{
UNIXIO * p ;
UINT ret ;
// Validate arguments
if ( pData = = NULL | | buf = = NULL | | size = = 0 )
{
return false ;
}
p = ( UNIXIO * ) pData ;
ret = read ( p - > fd , buf , size ) ;
if ( ret ! = size )
{
return false ;
}
return true ;
}
// Flush to the file
void UnixFileFlush ( void * pData )
{
UNIXIO * p ;
bool write_mode ;
// Validate arguments
if ( pData = = NULL )
{
return ;
}
p = ( UNIXIO * ) pData ;
write_mode = p - > write_mode ;
if ( write_mode )
{
fsync ( p - > fd ) ;
}
}
// Close the file
void UnixFileClose ( void * pData , bool no_flush )
{
UNIXIO * p ;
bool write_mode ;
// Validate arguments
if ( pData = = NULL )
{
return ;
}
p = ( UNIXIO * ) pData ;
write_mode = p - > write_mode ;
if ( write_mode & & no_flush = = false )
{
fsync ( p - > fd ) ;
}
close ( p - > fd ) ;
UnixMemoryFree ( p ) ;
if ( write_mode )
{
//sync();
}
}
// Create a file
void * UnixFileCreateW ( wchar_t * name )
{
void * ret ;
char * name8 = CopyUniToUtf ( name ) ;
ret = UnixFileCreate ( name8 ) ;
Free ( name8 ) ;
return ret ;
}
void * UnixFileCreate ( char * name )
{
UNIXIO * p ;
int fd ;
// Validate arguments
if ( name = = NULL )
{
return NULL ;
}
fd = creat ( name , 0600 ) ;
if ( fd = = - 1 )
{
return NULL ;
}
// Memory allocation
p = UnixMemoryAlloc ( sizeof ( UNIXIO ) ) ;
p - > fd = fd ;
p - > write_mode = true ;
return ( void * ) p ;
}
// Open the file
void * UnixFileOpenW ( wchar_t * name , bool write_mode , bool read_lock )
{
char * name8 = CopyUniToUtf ( name ) ;
void * ret ;
ret = UnixFileOpen ( name8 , write_mode , read_lock ) ;
Free ( name8 ) ;
return ret ;
}
void * UnixFileOpen ( char * name , bool write_mode , bool read_lock )
{
UNIXIO * p ;
int fd ;
int mode ;
// Validate arguments
if ( name = = NULL )
{
return NULL ;
}
if ( write_mode = = false )
{
mode = O_RDONLY ;
}
else
{
mode = O_RDWR ;
}
// Open the file
fd = open ( name , mode ) ;
if ( fd = = - 1 )
{
return NULL ;
}
// Memory allocation
p = UnixMemoryAlloc ( sizeof ( UNIXIO ) ) ;
p - > fd = fd ;
p - > write_mode = write_mode ;
return ( void * ) p ;
}
2017-06-28 16:22:53 +03:00
// Get UNIXIO object for stdout
void * GetUnixio4Stdout ( )
{
static UNIXIO unixio =
{
. fd = - 1 ,
. write_mode = true
} ;
if ( g_foreground )
{
unixio . fd = STDOUT_FILENO ;
return & unixio ;
}
return NULL ;
}
2014-01-04 17:00:08 +04:00
// Return the current thread ID
UINT UnixThreadId ( )
{
UINT ret ;
ret = ( UINT ) pthread_self ( ) ;
return ret ;
}
// Thread function
void * UnixDefaultThreadProc ( void * param )
{
UNIXTHREAD * ut ;
UNIXTHREADSTARTUPINFO * info = ( UNIXTHREADSTARTUPINFO * ) param ;
if ( info = = NULL )
{
return 0 ;
}
ut = ( UNIXTHREAD * ) info - > thread - > pData ;
// Call the thread function
info - > thread_proc ( info - > thread , info - > param ) ;
// Set a termination flag
ut - > finished = true ;
// Release of reference
ReleaseThread ( info - > thread ) ;
UnixMemoryFree ( info ) ;
FreeOpenSSLThreadState ( ) ;
return 0 ;
}
// Release of thread
void UnixFreeThread ( THREAD * t )
{
// Validate arguments
if ( t = = NULL )
{
return ;
}
// Free memory
UnixMemoryFree ( t - > pData ) ;
}
// Wait for the termination of the thread
bool UnixWaitThread ( THREAD * t )
{
UNIXTHREAD * ut ;
void * retcode = NULL ;
// Validate arguments
if ( t = = NULL )
{
return false ;
}
ut = ( UNIXTHREAD * ) t - > pData ;
if ( ut = = NULL )
{
return false ;
}
pthread_join ( ut - > thread , & retcode ) ;
return true ;
}
// Thread initialization
bool UnixInitThread ( THREAD * t )
{
UNIXTHREAD * ut ;
UNIXTHREADSTARTUPINFO * info ;
pthread_attr_t attr ;
// Validate arguments
if ( t = = NULL | | t - > thread_proc = = NULL )
{
return false ;
}
// Thread data creation
ut = UnixMemoryAlloc ( sizeof ( UNIXTHREAD ) ) ;
Zero ( ut , sizeof ( UNIXTHREAD ) ) ;
// Creating the startup information
info = UnixMemoryAlloc ( sizeof ( UNIXTHREADSTARTUPINFO ) ) ;
Zero ( info , sizeof ( UNIXTHREADSTARTUPINFO ) ) ;
info - > param = t - > param ;
info - > thread_proc = t - > thread_proc ;
info - > thread = t ;
AddRef ( t - > ref ) ;
// Thread creation
pthread_attr_init ( & attr ) ;
pthread_attr_setstacksize ( & attr , UNIX_THREAD_STACK_SIZE ) ;
t - > pData = ( void * ) ut ;
if ( pthread_create ( & ut - > thread , & attr , UnixDefaultThreadProc , info ) ! = 0 )
{
// An error has occured
t - > pData = NULL ;
2018-08-21 09:05:31 +03:00
( void ) Release ( t - > ref ) ;
2014-01-04 17:00:08 +04:00
UnixMemoryFree ( ut ) ;
UnixMemoryFree ( info ) ;
pthread_attr_destroy ( & attr ) ;
return false ;
}
pthread_attr_destroy ( & attr ) ;
return true ;
}
// Release the event
void UnixFreeEvent ( EVENT * event )
{
UNIXEVENT * ue = ( UNIXEVENT * ) event - > pData ;
if ( ue = = NULL )
{
return ;
}
pthread_cond_destroy ( & ue - > cond ) ;
pthread_mutex_destroy ( & ue - > mutex ) ;
UnixMemoryFree ( ue ) ;
}
// Wait for a event
bool UnixWaitEvent ( EVENT * event , UINT timeout )
{
UNIXEVENT * ue = ( UNIXEVENT * ) event - > pData ;
struct timeval now ;
struct timespec to ;
bool ret ;
if ( ue = = NULL )
{
return false ;
}
pthread_mutex_lock ( & ue - > mutex ) ;
gettimeofday ( & now , NULL ) ;
to . tv_sec = now . tv_sec + timeout / 1000 ;
to . tv_nsec = now . tv_usec * 1000 + ( timeout % 1000 ) * 1000 * 1000 ;
if ( ( to . tv_nsec / 1000000000 ) > = 1 )
{
to . tv_sec + = to . tv_nsec / 1000000000 ;
to . tv_nsec = to . tv_nsec % 1000000000 ;
}
ret = true ;
while ( ue - > signal = = false )
{
if ( timeout ! = INFINITE )
{
if ( pthread_cond_timedwait ( & ue - > cond , & ue - > mutex , & to ) )
{
ret = false ;
break ;
}
}
else
{
pthread_cond_wait ( & ue - > cond , & ue - > mutex ) ;
}
}
ue - > signal = false ;
pthread_mutex_unlock ( & ue - > mutex ) ;
return ret ;
}
// Reset the event
void UnixResetEvent ( EVENT * event )
{
UNIXEVENT * ue = ( UNIXEVENT * ) event - > pData ;
if ( ue = = NULL )
{
return ;
}
pthread_mutex_lock ( & ue - > mutex ) ;
ue - > signal = false ;
pthread_cond_signal ( & ue - > cond ) ;
pthread_mutex_unlock ( & ue - > mutex ) ;
}
// Set the event
void UnixSetEvent ( EVENT * event )
{
UNIXEVENT * ue = ( UNIXEVENT * ) event - > pData ;
if ( ue = = NULL )
{
return ;
}
pthread_mutex_lock ( & ue - > mutex ) ;
ue - > signal = true ;
pthread_cond_signal ( & ue - > cond ) ;
pthread_mutex_unlock ( & ue - > mutex ) ;
}
// Initialize the event
void UnixInitEvent ( EVENT * event )
{
UNIXEVENT * ue = UnixMemoryAlloc ( sizeof ( UNIXEVENT ) ) ;
Zero ( ue , sizeof ( UNIXEVENT ) ) ;
pthread_cond_init ( & ue - > cond , NULL ) ;
pthread_mutex_init ( & ue - > mutex , NULL ) ;
ue - > signal = false ;
event - > pData = ( void * ) ue ;
}
// Delete the lock
void UnixDeleteLock ( LOCK * lock )
{
pthread_mutex_t * mutex ;
// Reset Ready flag safely
UnixLock ( lock ) ;
lock - > Ready = false ;
UnixUnlockEx ( lock , true ) ;
// Delete the mutex
mutex = ( pthread_mutex_t * ) lock - > pData ;
pthread_mutex_destroy ( mutex ) ;
// Memory release
UnixMemoryFree ( mutex ) ;
UnixMemoryFree ( lock ) ;
}
// Unlock
void UnixUnlock ( LOCK * lock )
{
UnixUnlockEx ( lock , false ) ;
}
void UnixUnlockEx ( LOCK * lock , bool inner )
{
pthread_mutex_t * mutex ;
if ( lock - > Ready = = false & & inner = = false )
{
// State is invalid
return ;
}
mutex = ( pthread_mutex_t * ) lock - > pData ;
if ( ( - - lock - > locked_count ) > 0 )
{
return ;
}
lock - > thread_id = INFINITE ;
pthread_mutex_unlock ( mutex ) ;
return ;
}
// Lock
bool UnixLock ( LOCK * lock )
{
pthread_mutex_t * mutex ;
UINT thread_id = UnixThreadId ( ) ;
if ( lock - > Ready = = false )
{
// State is invalid
return false ;
}
if ( lock - > thread_id = = thread_id )
{
lock - > locked_count + + ;
return true ;
}
mutex = ( pthread_mutex_t * ) lock - > pData ;
pthread_mutex_lock ( mutex ) ;
lock - > thread_id = thread_id ;
lock - > locked_count + + ;
return true ;
}
// Creating a new lock
LOCK * UnixNewLock ( )
{
pthread_mutex_t * mutex ;
// Memory allocation
LOCK * lock = UnixMemoryAlloc ( sizeof ( LOCK ) ) ;
// Create a mutex
mutex = UnixMemoryAlloc ( sizeof ( pthread_mutex_t ) ) ;
fix null pointer dereference found by ErrorSanitizer
(gdb) bt
0 0x00007f43857a5e14 in __GI___pthread_mutex_init (mutex=0x0, mutexattr=0x0) at pthread_mutex_init.c:89
1 0x00007f4385eaaf1b in UnixNewLock () at SoftEtherVPN/src/Mayaqua/Unix.c:1845
2 0x00007f4385e92331 in NewLockMain () at SoftEtherVPN/src/Mayaqua/Object.c:89
3 0x00007f4385e92359 in NewLock () at SoftEtherVPN/src/Mayaqua/Object.c:101
4 0x00007f4385e92765 in NewCounter () at SoftEtherVPN/src/Mayaqua/Object.c:171
5 0x00007f4385e92e76 in NewRef () at SoftEtherVPN/src/Mayaqua/Object.c:339
6 0x00007f4385e76939 in NewSkEx (no_compact=0) at SoftEtherVPN/src/Mayaqua/Memory.c:863
7 0x00007f4385e68c95 in NormalizePathW (
dst=0x7ffe65932940 L"\xd6ff2ffb\xfbf14ce5\xad8669ca\x41998a9c\x5107d62d\x8d2ab3f2\x37ceaad2\xffc947ec\xad8ed8d8\x33e9f2f7\xc05723a9\x843263e3\x5516beb3\x12571e2a\xd81405f3\xf92194fe\xd807aa98\x12835b01\x243185be\x550c7dc3\xfd74170d\x12835b01\x553185be\x550c7dc3\x72be5d74\x80deb1fe\x9bdc06a7\xc19bf1f4\x72be5d74\x80deb1fe\x9bdc06a7\xc19bf174\x894d4018\xc54302b8\x145dc92\x143b3917\x62aa4fb8\x915764b1\xd5e11bef\x9d5fbc5\xb956c25b\x59f111f1\x923f82a4\xab1c5ed5\x3956c25b\x59f111f1\x923f82a4\xab1c5ed5\xbaeb40", size=2048, src=<optimized out>)
at SoftEtherVPN/src/Mayaqua/FileIO.c:1960
8 0x00007f4385e69188 in ConbinePathW (
dst=0x7ffe65932940 L"\xd6ff2ffb\xfbf14ce5\xad8669ca\x41998a9c\x5107d62d\x8d2ab3f2\x37ceaad2\xffc947ec\xad8ed8d8\x33e9f2f7\xc05723a9\x843263e3\x5516beb3\x12571e2a\xd81405f3\xf92194fe\xd807aa98\x12835b01\x243185be\x550c7dc3\xfd74170d\x12835b01\x553185be\x550c7dc3\x72be5d74\x80deb1fe\x9bdc06a7\xc19bf1f4\x72be5d74\x80deb1fe\x9bdc06a7\xc19bf174\x894d4018\xc54302b8\x145dc92\x143b3917\x62aa4fb8\x915764b1\xd5e11bef\x9d5fbc5\xb956c25b\x59f111f1\x923f82a4\xab1c5ed5\x3956c25b\x59f111f1\x923f82a4\xab1c5ed5\xbaeb40", size=2048,
dirname=0xbace10 L"/root/.local/bin", filename=0x7ffe65932100 L"SoftEtherVPN/build/vpntest") at SoftEtherVPN/src/Mayaqua/FileIO.c:1686
9 0x00007f4385e6af48 in UnixGetExeNameW (name=0x7f4385ede820 <exe_file_name_w> L"/tmp/a.out", size=2048, arg=0xbb5050 L"./vpntest") at SoftEtherVPN/src/Mayaqua/FileIO.c:1401
10 0x00007f4385e6b04b in InitGetExeName (arg=<optimized out>) at SoftEtherVPN/src/Mayaqua/FileIO.c:1367
11 0x00007f4385e7470a in InitMayaqua (memcheck=memcheck@entry=0, debug=debug@entry=1, argc=argc@entry=3, argv=argv@entry=0x7ffe659340e8)
at SoftEtherVPN/src/Mayaqua/Mayaqua.c:456
12 0x0000000000401282 in main (argc=3, argv=0x7ffe659340e8) at SoftEtherVPN/src/vpntest/vpntest.c:259
2021-02-21 14:13:36 +03:00
if ( mutex = = NULL )
{
return NULL ;
}
2014-01-04 17:00:08 +04:00
// Initialization of the mutex
pthread_mutex_init ( mutex , NULL ) ;
lock - > pData = ( void * ) mutex ;
lock - > Ready = true ;
lock - > thread_id = INFINITE ;
lock - > locked_count = 0 ;
return lock ;
}
// Sleep
void UnixSleep ( UINT time )
{
UINT sec = 0 , millisec = 0 ;
// Validate arguments
if ( time = = 0 )
{
return ;
}
if ( time = = INFINITE )
{
// Wait forever
while ( true )
{
# ifdef UNIX_SOLARIS
UnixSolarisSleep ( time ) ;
# else
sleep ( 1000000 ) ;
# endif
}
}
# ifdef UNIX_SOLARIS
UnixSolarisSleep ( time ) ;
# else
// Prevent overflow
sec = time / 1000 ;
millisec = time % 1000 ;
if ( sec ! = 0 )
{
sleep ( sec ) ;
}
if ( millisec ! = 0 )
{
usleep ( millisec * 1000 ) ;
}
# endif
}
// Decrement
void UnixDec32 ( UINT * value )
{
if ( value ! = NULL )
{
( * value ) - - ;
}
}
// Increment
void UnixInc32 ( UINT * value )
{
if ( value ! = NULL )
{
( * value ) + + ;
}
}
// Get the System Time
void UnixGetSystemTime ( SYSTEMTIME * system_time )
{
time_t now = 0 ;
2016-11-27 11:43:14 +03:00
time_64t now2 = 0 ;
2014-01-04 17:00:08 +04:00
struct tm tm ;
struct timeval tv ;
struct timezone tz ;
// Validate arguments
if ( system_time = = NULL )
{
return ;
}
pthread_mutex_lock ( & get_time_lock ) ;
Zero ( system_time , sizeof ( SYSTEMTIME ) ) ;
Zero ( & tv , sizeof ( tv ) ) ;
Zero ( & tz , sizeof ( tz ) ) ;
time ( & now ) ;
2016-11-27 11:43:14 +03:00
if ( sizeof ( time_t ) = = 4 )
{
2020-08-15 09:31:45 +03:00
now2 = ( time_64t ) ( ( UINT64 ) ( ( UINT ) now ) ) ;
2016-11-27 11:43:14 +03:00
}
else
{
now2 = now ;
}
c_gmtime_r ( & now2 , & tm ) ;
2014-01-04 17:00:08 +04:00
TmToSystem ( system_time , & tm ) ;
gettimeofday ( & tv , & tz ) ;
system_time - > wMilliseconds = tv . tv_usec / 1000 ;
pthread_mutex_unlock ( & get_time_lock ) ;
}
// Get the system timer (64bit)
UINT64 UnixGetTick64 ( )
{
# if defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)
struct timespec t ;
UINT64 ret ;
Zero ( & t , sizeof ( t ) ) ;
// Function to get the boot time of the system
// Be careful. The Implementation is depend on the system.
# ifdef CLOCK_HIGHRES
clock_gettime ( CLOCK_HIGHRES , & t ) ;
2018-08-28 08:21:36 +03:00
# elif CLOCK_MONOTONIC
2014-01-04 17:00:08 +04:00
clock_gettime ( CLOCK_MONOTONIC , & t ) ;
2018-08-28 08:21:36 +03:00
# else
2014-01-04 17:00:08 +04:00
clock_gettime ( CLOCK_REALTIME , & t ) ;
2018-08-28 08:21:36 +03:00
# endif
2014-01-04 17:00:08 +04:00
2020-08-15 09:31:45 +03:00
ret = ( ( UINT64 ) ( ( UINT ) t . tv_sec ) ) * 1000LL + ( UINT64 ) t . tv_nsec / 1000000LL ;
2014-01-04 17:00:08 +04:00
2018-08-28 08:21:36 +03:00
if ( ret = = 0 )
2014-01-04 17:00:08 +04:00
{
ret = TickRealtimeManual ( ) ;
}
return ret ;
2014-03-12 03:06:21 +04:00
# else
2014-01-04 17:00:08 +04:00
return TickRealtimeManual ( ) ;
2014-03-12 03:06:21 +04:00
# endif
2014-01-04 17:00:08 +04:00
}
// Get the system timer
UINT UnixGetTick ( )
{
return ( UINT ) UnixGetTick64 ( ) ;
}
// Memory allocation
void * UnixMemoryAlloc ( UINT size )
{
void * r ;
pthread_mutex_lock ( & malloc_lock ) ;
r = malloc ( size ) ;
pthread_mutex_unlock ( & malloc_lock ) ;
return r ;
}
// Reallocation of the memory
void * UnixMemoryReAlloc ( void * addr , UINT size )
{
void * r ;
pthread_mutex_lock ( & malloc_lock ) ;
r = realloc ( addr , size ) ;
pthread_mutex_unlock ( & malloc_lock ) ;
return r ;
}
// Free the memory
void UnixMemoryFree ( void * addr )
{
pthread_mutex_lock ( & malloc_lock ) ;
free ( addr ) ;
pthread_mutex_unlock ( & malloc_lock ) ;
}
// SIGCHLD handler
void UnixSigChldHandler ( int sig )
{
// Recall the zombie processes
while ( waitpid ( - 1 , NULL , WNOHANG ) > 0 ) ;
signal ( SIGCHLD , UnixSigChldHandler ) ;
}
2014-10-03 19:09:23 +04:00
// Disable core dump
void UnixDisableCoreDump ( )
{
# ifdef RLIMIT_CORE
UnixSetResourceLimit ( RLIMIT_CORE , 0 ) ;
# endif // RLIMIT_CORE
}
2014-01-04 17:00:08 +04:00
// Initialize the library for UNIX
void UnixInit ( )
{
UNIXIO * o ;
2014-10-03 19:09:23 +04:00
UINT64 max_memory = UNIX_MAX_MEMORY ;
if ( UnixIs64BitRlimSupported ( ) )
{
max_memory = UNIX_MAX_MEMORY_64 ;
}
2014-01-04 17:00:08 +04:00
UnixInitSolarisSleep ( ) ;
// Global lock
pthread_mutex_init ( & get_time_lock , NULL ) ;
pthread_mutex_init ( & malloc_lock , NULL ) ;
// Get the Process ID
current_process_id = getpid ( ) ;
# ifdef RLIMIT_CORE
2014-10-03 19:09:23 +04:00
UnixSetResourceLimit ( RLIMIT_CORE , max_memory ) ;
2014-01-04 17:00:08 +04:00
# endif // RLIMIT_CORE
# ifdef RLIMIT_DATA
2014-10-03 19:09:23 +04:00
UnixSetResourceLimit ( RLIMIT_DATA , max_memory ) ;
2014-01-04 17:00:08 +04:00
# endif // RLIMIT_DATA
# ifdef RLIMIT_NOFILE
# ifndef UNIX_MACOS
UnixSetResourceLimit ( RLIMIT_NOFILE , UNIX_MAX_FD ) ;
# else // UNIX_MACOS
UnixSetResourceLimit ( RLIMIT_NOFILE , UNIX_MAX_FD_MACOS ) ;
# endif // UNIX_MACOS
# endif // RLIMIT_NOFILE
# ifdef RLIMIT_STACK
2014-10-03 19:09:23 +04:00
// UnixSetResourceLimit(RLIMIT_STACK, max_memory);
2014-01-04 17:00:08 +04:00
# endif // RLIMIT_STACK
# ifdef RLIMIT_RSS
2014-10-03 19:09:23 +04:00
UnixSetResourceLimit ( RLIMIT_RSS , max_memory ) ;
2014-01-04 17:00:08 +04:00
# endif // RLIMIT_RSS
# ifdef RLIMIT_LOCKS
UnixSetResourceLimit ( RLIMIT_LOCKS , UNIX_MAX_LOCKS ) ;
# endif // RLIMIT_LOCKS
# ifdef RLIMIT_MEMLOCK
2014-10-03 19:09:23 +04:00
UnixSetResourceLimit ( RLIMIT_MEMLOCK , max_memory ) ;
2014-01-04 17:00:08 +04:00
# endif // RLIMIT_MEMLOCK
# ifdef RLIMIT_NPROC
UnixSetResourceLimit ( RLIMIT_NPROC , UNIX_MAX_CHILD_PROCESSES ) ;
# endif // RLIMIT_NPROC
// Write a value to the threads-max of the proc file system
o = UnixFileCreate ( " /proc/sys/kernel/threads-max " ) ;
if ( o ! = NULL )
{
char tmp [ 128 ] ;
sprintf ( tmp , " %u \n " , UNIX_LINUX_MAX_THREADS ) ;
UnixFileWrite ( o , tmp , strlen ( tmp ) ) ;
UnixFileClose ( o , false ) ;
}
// Set the signals that is to be ignored
signal ( SIGPIPE , SIG_IGN ) ;
signal ( SIGALRM , SIG_IGN ) ;
# ifdef UNIX_BSD
signal ( 64 , SIG_IGN ) ;
# endif // UNIX_BSD
# ifdef SIGXFSZ
signal ( SIGXFSZ , SIG_IGN ) ;
# endif // SIGXFSZ
// Set a signal handler to salvage the child processes
signal ( SIGCHLD , UnixSigChldHandler ) ;
}
// Release the library for UNIX
void UnixFree ( )
{
UnixFreeSolarisSleep ( ) ;
current_process_id = 0 ;
pthread_mutex_destroy ( & get_time_lock ) ;
}
// Adjust the upper limit of resources that may be occupied
2014-10-03 19:09:23 +04:00
void UnixSetResourceLimit ( UINT id , UINT64 value )
2014-01-04 17:00:08 +04:00
{
struct rlimit t ;
2014-10-03 19:09:23 +04:00
UINT64 hard_limit ;
if ( UnixIs64BitRlimSupported ( ) = = false )
{
if ( value > ( UINT64 ) 4294967295ULL )
{
value = ( UINT64 ) 4294967295ULL ;
}
}
2014-01-04 17:00:08 +04:00
Zero ( & t , sizeof ( t ) ) ;
getrlimit ( id , & t ) ;
2014-10-03 19:09:23 +04:00
hard_limit = ( UINT64 ) t . rlim_max ;
2014-01-04 17:00:08 +04:00
Zero ( & t , sizeof ( t ) ) ;
2014-10-03 19:09:23 +04:00
t . rlim_cur = ( rlim_t ) MIN ( value , hard_limit ) ;
t . rlim_max = ( rlim_t ) hard_limit ;
2014-01-04 17:00:08 +04:00
setrlimit ( id , & t ) ;
Zero ( & t , sizeof ( t ) ) ;
2014-10-03 19:09:23 +04:00
t . rlim_cur = ( rlim_t ) value ;
t . rlim_max = ( rlim_t ) value ;
2014-01-04 17:00:08 +04:00
setrlimit ( id , & t ) ;
}
2014-10-03 19:09:23 +04:00
// Is the rlim_t type 64-bit?
bool UnixIs64BitRlimSupported ( )
{
if ( sizeof ( rlim_t ) > = 8 )
{
return true ;
}
return false ;
}
2014-01-04 17:00:08 +04:00
// Generate the PID file name
void UnixGenPidFileName ( char * name , UINT size )
{
char exe_name [ MAX_PATH ] ;
UCHAR hash [ MD5_SIZE ] ;
char tmp1 [ 64 ] ;
char dir [ MAX_PATH ] ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
2019-11-29 16:58:57 +03:00
GetPidDir ( dir , sizeof ( dir ) ) ;
2014-01-04 17:00:08 +04:00
GetExeName ( exe_name , sizeof ( exe_name ) ) ;
StrCat ( exe_name , sizeof ( exe_name ) , " :pid_hash " ) ;
StrUpper ( exe_name ) ;
2018-09-22 07:35:30 +03:00
Md5 ( hash , exe_name , StrLen ( exe_name ) ) ;
2014-01-04 17:00:08 +04:00
BinToStr ( tmp1 , sizeof ( tmp1 ) , hash , sizeof ( hash ) ) ;
Format ( name , size , " %s/.pid_%s " , dir , tmp1 ) ;
}
// Delete the PID file
void UnixDeletePidFile ( )
{
char tmp [ MAX_PATH ] ;
UnixGenPidFileName ( tmp , sizeof ( tmp ) ) ;
UnixFileDelete ( tmp ) ;
}
// Delete the CTL file
void UnixDeleteCtlFile ( )
{
char tmp [ MAX_PATH ] ;
UnixGenCtlFileName ( tmp , sizeof ( tmp ) ) ;
UnixFileDelete ( tmp ) ;
}
// Generate the CTL file name
void UnixGenCtlFileName ( char * name , UINT size )
{
char exe_name [ MAX_PATH ] ;
UCHAR hash [ MD5_SIZE ] ;
char tmp1 [ 64 ] ;
char dir [ MAX_PATH ] ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
2019-11-29 16:58:57 +03:00
GetPidDir ( dir , sizeof ( dir ) ) ;
2014-01-04 17:00:08 +04:00
GetExeName ( exe_name , sizeof ( exe_name ) ) ;
StrCat ( exe_name , sizeof ( exe_name ) , " :pid_hash " ) ;
StrUpper ( exe_name ) ;
2018-09-22 07:35:30 +03:00
Md5 ( hash , exe_name , StrLen ( exe_name ) ) ;
2014-01-04 17:00:08 +04:00
BinToStr ( tmp1 , sizeof ( tmp1 ) , hash , sizeof ( hash ) ) ;
Format ( name , size , " %s/.ctl_%s " , dir , tmp1 ) ;
}
// Write the CTL file
void UnixWriteCtlFile ( UINT i )
{
char tmp [ MAX_PATH ] ;
char tmp2 [ 64 ] ;
IO * o ;
UnixGenCtlFileName ( tmp , sizeof ( tmp ) ) ;
Format ( tmp2 , sizeof ( tmp2 ) , " %u \n " , i ) ;
o = FileCreate ( tmp ) ;
if ( o ! = NULL )
{
FileWrite ( o , tmp2 , StrLen ( tmp2 ) ) ;
FileClose ( o ) ;
}
}
// Write to the PID file
void UnixWritePidFile ( UINT pid )
{
char tmp [ MAX_PATH ] ;
char tmp2 [ 64 ] ;
IO * o ;
UnixGenPidFileName ( tmp , sizeof ( tmp ) ) ;
Format ( tmp2 , sizeof ( tmp2 ) , " %u \n " , pid ) ;
o = FileCreate ( tmp ) ;
if ( o ! = NULL )
{
FileWrite ( o , tmp2 , StrLen ( tmp2 ) ) ;
FileClose ( o ) ;
}
}
// Read the PID file
UINT UnixReadPidFile ( )
{
char tmp [ MAX_PATH ] ;
BUF * buf ;
UnixGenPidFileName ( tmp , sizeof ( tmp ) ) ;
buf = ReadDump ( tmp ) ;
if ( buf = = NULL )
{
return 0 ;
}
Zero ( tmp , sizeof ( tmp ) ) ;
Copy ( tmp , buf - > Buf , MIN ( buf - > Size , sizeof ( tmp ) ) ) ;
FreeBuf ( buf ) ;
return ToInt ( tmp ) ;
}
// Read the CTL file
UINT UnixReadCtlFile ( )
{
char tmp [ MAX_PATH ] ;
BUF * buf ;
UnixGenCtlFileName ( tmp , sizeof ( tmp ) ) ;
buf = ReadDump ( tmp ) ;
if ( buf = = NULL )
{
return 0 ;
}
Zero ( tmp , sizeof ( tmp ) ) ;
Copy ( tmp , buf - > Buf , MIN ( buf - > Size , sizeof ( tmp ) ) ) ;
FreeBuf ( buf ) ;
return ToInt ( tmp ) ;
}
// Get the UID
UINT UnixGetUID ( )
{
return ( UINT ) getuid ( ) ;
}
// Start the service
void UnixStartService ( char * name )
{
char * svc_name , * svc_title ;
char tmp [ 128 ] ;
INSTANCE * inst ;
char exe [ MAX_PATH ] ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
GetExeName ( exe , sizeof ( exe ) ) ;
Format ( tmp , sizeof ( tmp ) , SVC_NAME , name ) ;
svc_name = _SS ( tmp ) ;
Format ( tmp , sizeof ( tmp ) , SVC_TITLE , name ) ;
svc_title = _SS ( tmp ) ;
// Examine whether the service has not been started already
inst = NewSingleInstance ( NULL ) ;
if ( inst = = NULL )
{
// Service is already running
UniPrint ( _UU ( " UNIX_SVC_ALREADY_START " ) , svc_title , svc_name ) ;
}
else
{
int pid ;
// Begin to start the service
UniPrint ( _UU ( " UNIX_SVC_STARTED " ) , svc_title ) ;
2014-07-11 21:06:20 +04:00
if ( UnixGetUID ( ) ! = 0 )
{
// Non-root warning
UniPrint ( _UU ( " UNIX_SVC_NONROOT " ) ) ;
}
2014-01-04 17:00:08 +04:00
FreeSingleInstance ( inst ) ;
// Create a child process
pid = fork ( ) ;
if ( pid = = - 1 )
{
UniPrint ( _UU ( " UNIX_SVC_ERROR_FORK " ) , svc_title ) ;
}
else
{
if ( pid = = 0 )
{
// Child process
char * param = UNIX_SVC_ARG_EXEC_SVC ;
char * * args ;
// Daemonize
setsid ( ) ;
UnixCloseIO ( ) ;
signal ( SIGHUP , SIG_IGN ) ;
// Prepare arguments
args = ZeroMalloc ( sizeof ( char * ) * 3 ) ;
args [ 0 ] = exe ;
args [ 1 ] = param ;
args [ 2 ] = NULL ;
execvp ( exe , args ) ;
AbortExit ( ) ;
}
else
{
// Don't write the child process number to the file
// UnixWritePidFile(pid);
}
}
}
}
// Stop the Service
void UnixStopService ( char * name )
{
char * svc_name , * svc_title ;
char tmp [ 128 ] ;
INSTANCE * inst ;
char exe [ MAX_PATH ] ;
UINT pid ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
GetExeName ( exe , sizeof ( exe ) ) ;
Format ( tmp , sizeof ( tmp ) , SVC_NAME , name ) ;
svc_name = _SS ( tmp ) ;
Format ( tmp , sizeof ( tmp ) , SVC_TITLE , name ) ;
svc_title = _SS ( tmp ) ;
inst = NewSingleInstance ( NULL ) ;
pid = UnixReadPidFile ( ) ;
if ( inst ! = NULL | | pid = = 0 )
{
// Service is not running yet
UniPrint ( _UU ( " UNIX_SVC_NOT_STARTED " ) , svc_title , svc_name ) ;
}
else
{
// Stop the service
UniPrint ( _UU ( " UNIX_SVC_STOPPING " ) , svc_title ) ;
// Terminate the process
kill ( pid , SIGTERM ) ;
# ifdef UNIX_BSD
UnixWriteCtlFile ( Rand32 ( ) ) ;
# endif // UNIX_BSD
if ( UnixWaitProcessEx ( pid , UNIX_SERVICE_STOP_TIMEOUT_2 ) )
{
UniPrint ( _UU ( " UNIX_SVC_STOPPED " ) , svc_title ) ;
}
else
{
2014-03-20 00:45:05 +04:00
// SIGKILL
char tmp [ 256 ] ;
Format ( tmp , sizeof ( tmp ) , " killall -KILL %s " , name ) ;
2014-01-04 17:00:08 +04:00
UniPrint ( _UU ( " UNIX_SVC_STOP_FAILED " ) , svc_title ) ;
2014-03-20 00:45:05 +04:00
system ( tmp ) ;
2014-01-04 17:00:08 +04:00
}
}
FreeSingleInstance ( inst ) ;
}
// Handler of the stop signal to the process
void UnixSigTermHandler ( int signum )
{
if ( signum = = SIGTERM )
{
unix_svc_terminate = true ;
}
}
// The thread for stop service
void UnixStopThread ( THREAD * t , void * param )
{
SERVICE_FUNCTION * stop = ( SERVICE_FUNCTION * ) param ;
// Validate arguments
if ( t = = NULL | | param = = NULL )
{
return ;
}
stop ( ) ;
}
// Execute the main body of the service
void UnixExecService ( char * name , SERVICE_FUNCTION * start , SERVICE_FUNCTION * stop )
{
char * svc_name , * svc_title ;
char tmp [ 128 ] ;
INSTANCE * inst ;
UINT yobi_size = 1024 * 128 ;
void * yobi1 , * yobi2 ;
UINT saved_ctl ;
// Validate arguments
if ( start = = NULL | | stop = = NULL | | name = = NULL )
{
return ;
}
Format ( tmp , sizeof ( tmp ) , SVC_NAME , name ) ;
svc_name = _SS ( tmp ) ;
Format ( tmp , sizeof ( tmp ) , SVC_TITLE , name ) ;
svc_title = _SS ( tmp ) ;
UnixWriteCtlFile ( Rand32 ( ) ) ;
saved_ctl = UnixReadCtlFile ( ) ;
inst = NewSingleInstance ( NULL ) ;
if ( inst ! = NULL )
{
THREAD * t ;
yobi1 = ZeroMalloc ( yobi_size ) ;
yobi2 = ZeroMalloc ( yobi_size ) ;
// Start
UnixWritePidFile ( getpid ( ) ) ;
start ( ) ;
// Starting complete. wait for arriving SIGTERM from another process
signal ( SIGTERM , & UnixSigTermHandler ) ;
while ( unix_svc_terminate = = false )
{
2014-03-12 03:06:21 +04:00
# if !(defined(UNIX_BSD) || defined(UNIX_MACOS))
2014-01-04 17:00:08 +04:00
pause ( ) ;
2014-03-12 03:06:21 +04:00
# else // defined(UNIX_BSD) || defined(UNIX_MACOS)
2014-01-04 17:00:08 +04:00
if ( UnixReadCtlFile ( ) ! = saved_ctl )
{
break ;
}
SleepThread ( 1394 ) ;
2014-03-12 03:06:21 +04:00
# endif // defined(UNIX_BSD) || defined(UNIX_MACOS)
2014-01-04 17:00:08 +04:00
}
// Stop
Free ( yobi1 ) ;
t = NewThread ( UnixStopThread , stop ) ;
if ( t = = NULL | | ( WaitThread ( t , UNIX_SERVICE_STOP_TIMEOUT_1 ) = = false ) )
{
// Terminate forcibly if creation of a halting thread have
// failed or timed out
Free ( yobi2 ) ;
FreeSingleInstance ( inst ) ;
UnixDeletePidFile ( ) ;
_exit ( 0 ) ;
}
ReleaseThread ( t ) ;
// Delete the PID file
UnixDeletePidFile ( ) ;
// Delete the CTL file
UnixDeleteCtlFile ( ) ;
FreeSingleInstance ( inst ) ;
Free ( yobi2 ) ;
}
}
// Get whether the process with the specified pid exists
bool UnixIsProcess ( UINT pid )
{
if ( getsid ( ( pid_t ) pid ) = = - 1 )
{
return false ;
}
return true ;
}
// Wait for the termination of the specified process
bool UnixWaitProcessEx ( UINT pid , UINT timeout )
{
UINT64 start_tick = Tick64 ( ) ;
UINT64 end_tick = start_tick + ( UINT64 ) timeout ;
if ( timeout = = INFINITE )
{
end_tick = 0 ;
}
while ( UnixIsProcess ( pid ) )
{
if ( end_tick ! = 0 )
{
if ( end_tick < Tick64 ( ) )
{
return false ;
}
}
SleepThread ( 100 ) ;
}
return true ;
}
// Description of how to start
void UnixUsage ( char * name )
{
char * svc_name , * svc_title ;
char tmp [ 128 ] ;
// Validate arguments
if ( name = = NULL )
{
return ;
}
Format ( tmp , sizeof ( tmp ) , SVC_NAME , name ) ;
svc_name = _SS ( tmp ) ;
Format ( tmp , sizeof ( tmp ) , SVC_TITLE , name ) ;
svc_title = _SS ( tmp ) ;
UniPrint ( _UU ( " UNIX_SVC_HELP " ) , svc_title , svc_name , svc_name , svc_title , svc_name , svc_title ) ;
}
// Main function of the UNIX service
UINT UnixService ( int argc , char * argv [ ] , char * name , SERVICE_FUNCTION * start , SERVICE_FUNCTION * stop )
{
// Validate arguments
if ( name = = NULL | | start = = NULL | | stop = = NULL )
{
return 0 ;
}
if ( argc > = 2 & & StrCmpi ( argv [ 1 ] , UNIX_SVC_ARG_EXEC_SVC ) = = 0 )
{
UINT pid ;
// Start a child process
// Restart if the child process didn't exit properly
RESTART_PROCESS :
pid = fork ( ) ;
if ( ( int ) pid ! = - 1 )
{
if ( pid = = 0 )
{
// Run the main process
UnixServiceMain ( argc , argv , name , start , stop ) ;
}
else
{
int status = 0 , ret ;
// Wait for the termination of the child process
ret = waitpid ( pid , & status , 0 ) ;
if ( WIFEXITED ( status ) = = 0 )
{
// Aborted
UnixSleep ( 100 ) ;
goto RESTART_PROCESS ;
}
}
}
}
2017-06-22 18:41:47 +03:00
else if ( argc > = 3 & & StrCmpi ( argv [ 1 ] , UNIX_SVC_ARG_START ) = = 0 & & StrCmpi ( argv [ 2 ] , UNIX_SVC_ARG_FOREGROUND ) = = 0 )
{
2018-09-15 20:12:21 +03:00
# ifdef DEBUG
2018-10-08 05:03:58 +03:00
// 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.
// For normal debug we set memcheck = false.
// Please set memcheck = true if you want to test the cause of memory leaks.
InitMayaqua ( false , true , argc , argv ) ;
2018-09-15 20:12:21 +03:00
# else
2017-06-22 18:41:47 +03:00
InitMayaqua ( false , false , argc , argv ) ;
2018-09-15 20:12:21 +03:00
# endif
2017-06-22 18:41:47 +03:00
UnixExecService ( name , start , stop ) ;
FreeMayaqua ( ) ;
}
2014-01-04 17:00:08 +04:00
else
{
// Start normally
UnixServiceMain ( argc , argv , name , start , stop ) ;
}
return 0 ;
}
void UnixServiceMain ( int argc , char * argv [ ] , char * name , SERVICE_FUNCTION * start , SERVICE_FUNCTION * stop )
{
UINT mode = 0 ;
// Start of the Mayaqua
2018-09-15 20:12:21 +03:00
# ifdef DEBUG
2018-10-08 05:03:58 +03:00
// 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.
// For normal debug we set memcheck = false.
// Please set memcheck = true if you want to test the cause of memory leaks.
InitMayaqua ( false , true , argc , argv ) ;
2018-09-15 20:12:21 +03:00
# else
2014-01-04 17:00:08 +04:00
InitMayaqua ( false , false , argc , argv ) ;
2018-09-15 20:12:21 +03:00
# endif
2014-01-04 17:00:08 +04:00
if ( argc > = 2 )
{
if ( StrCmpi ( argv [ 1 ] , UNIX_SVC_ARG_START ) = = 0 )
{
mode = UNIX_SVC_MODE_START ;
}
if ( StrCmpi ( argv [ 1 ] , UNIX_SVC_ARG_STOP ) = = 0 )
{
mode = UNIX_SVC_MODE_STOP ;
}
if ( StrCmpi ( argv [ 1 ] , UNIX_SVC_ARG_EXEC_SVC ) = = 0 )
{
mode = UNIX_SVC_MODE_EXEC_SVC ;
}
if ( StrCmpi ( argv [ 1 ] , UNIX_ARG_EXIT ) = = 0 )
{
mode = UNIX_SVC_MODE_EXIT ;
}
}
switch ( mode )
{
case UNIX_SVC_MODE_EXIT :
break ;
case UNIX_SVC_MODE_START :
UnixStartService ( name ) ;
break ;
case UNIX_SVC_MODE_STOP :
UnixStopService ( name ) ;
break ;
case UNIX_SVC_MODE_EXEC_SVC :
UnixExecService ( name , start , stop ) ;
break ;
default :
UnixUsage ( name ) ;
break ;
}
// End of the Mayaqua
FreeMayaqua ( ) ;
return ;
}
# endif // UNIX