2011-05-13 12:45:46 +04:00
/*
2012-02-28 22:35:04 +04:00
* Copyright ( C ) 2011 - 2012 Red Hat , Inc .
2011-05-13 12:45:46 +04:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2012-09-26 16:44:03 +04:00
# include "daemon-io.h"
2012-02-28 22:35:04 +04:00
# include "daemon-server.h"
2012-08-08 11:41:01 +04:00
# include "daemon-log.h"
2012-02-28 22:35:04 +04:00
2011-05-13 12:45:46 +04:00
# include <dlfcn.h>
# include <errno.h>
# include <pthread.h>
# include <sys/file.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/time.h>
# include <sys/resource.h>
2011-05-15 15:02:29 +04:00
# include <netinet/in.h>
# include <sys/un.h>
2011-05-13 12:45:46 +04:00
# include <unistd.h>
# include <signal.h>
2012-08-08 11:41:01 +04:00
# include <syslog.h> /* FIXME. For the global closelog(). */
2011-05-13 12:45:46 +04:00
2011-05-15 15:02:29 +04:00
#if 0
2011-05-13 12:45:46 +04:00
/* Create a device monitoring thread. */
static int _pthread_create ( pthread_t * t , void * ( * fun ) ( void * ) , void * arg , int stacksize )
{
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
/*
* We use a smaller stack since it gets preallocated in its entirety
*/
pthread_attr_setstacksize ( & attr , stacksize ) ;
return pthread_create ( t , & attr , fun , arg ) ;
}
2011-05-15 15:02:29 +04:00
# endif
2011-05-13 12:45:46 +04:00
static volatile sig_atomic_t _shutdown_requested = 0 ;
2012-02-28 17:05:21 +04:00
static int _systemd_activation = 0 ;
2011-05-13 12:45:46 +04:00
static void _exit_handler ( int sig __attribute__ ( ( unused ) ) )
{
_shutdown_requested = 1 ;
}
2013-04-15 11:43:30 +04:00
# define EXIT_ALREADYRUNNING 13
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2012-02-28 17:05:21 +04:00
# include <stddef.h>
/*
* Kernel version 2.6 .36 and higher has
* new OOM killer adjustment interface .
*/
# define OOM_ADJ_FILE_OLD " / proc / self / oom_adj"
# define OOM_ADJ_FILE " / proc / self / oom_score_adj"
2011-05-13 12:45:46 +04:00
/* From linux/oom.h */
2012-02-28 17:05:21 +04:00
/* Old interface */
2011-05-13 12:45:46 +04:00
# define OOM_DISABLE (-17)
# define OOM_ADJUST_MIN (-16)
2012-02-28 17:05:21 +04:00
/* New interface */
# define OOM_SCORE_ADJ_MIN (-1000)
/* Systemd on-demand activation support */
2012-03-14 19:51:51 +04:00
# define SD_ACTIVATION_ENV_VAR_NAME "SD_ACTIVATION"
2012-02-28 17:05:21 +04:00
# define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID"
# define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS"
# define SD_LISTEN_FDS_START 3
# define SD_FD_SOCKET_SERVER SD_LISTEN_FDS_START
# include <stdio.h>
2015-04-29 17:59:30 +03:00
static int _is_idle ( daemon_state s )
{
2015-05-12 10:37:19 +03:00
return s . idle & & s . idle - > is_idle & & ! s . threads - > next ;
2015-04-29 17:59:30 +03:00
}
static struct timeval * _get_timeout ( daemon_state s )
{
2015-05-12 10:37:19 +03:00
return s . idle ? s . idle - > ptimeout : NULL ;
2015-04-29 17:59:30 +03:00
}
static void _reset_timeout ( daemon_state s )
{
if ( s . idle ) {
s . idle - > ptimeout - > tv_sec = 1 ;
s . idle - > ptimeout - > tv_usec = 0 ;
}
}
static unsigned _get_max_timeouts ( daemon_state s )
{
return s . idle ? s . idle - > max_timeouts : 0 ;
}
2012-02-28 17:05:21 +04:00
static int _set_oom_adj ( const char * oom_adj_path , int val )
{
FILE * fp ;
if ( ! ( fp = fopen ( oom_adj_path , " w " ) ) ) {
perror ( " oom_adj: fopen failed " ) ;
return 0 ;
}
fprintf ( fp , " %i " , val ) ;
if ( dm_fclose ( fp ) )
perror ( " oom_adj: fclose failed " ) ;
return 1 ;
}
2011-05-13 12:45:46 +04:00
/*
* Protection against OOM killer if kernel supports it
*/
2012-02-28 17:05:21 +04:00
static int _protect_against_oom_killer ( void )
2011-05-13 12:45:46 +04:00
{
struct stat st ;
if ( stat ( OOM_ADJ_FILE , & st ) = = - 1 ) {
2012-02-28 17:05:21 +04:00
if ( errno ! = ENOENT )
2011-05-13 12:45:46 +04:00
perror ( OOM_ADJ_FILE " : stat failed " ) ;
2012-02-28 17:05:21 +04:00
/* Try old oom_adj interface as a fallback */
if ( stat ( OOM_ADJ_FILE_OLD , & st ) = = - 1 ) {
if ( errno = = ENOENT )
perror ( OOM_ADJ_FILE_OLD " not found " ) ;
else
perror ( OOM_ADJ_FILE_OLD " : stat failed " ) ;
return 1 ;
}
return _set_oom_adj ( OOM_ADJ_FILE_OLD , OOM_DISABLE ) | |
_set_oom_adj ( OOM_ADJ_FILE_OLD , OOM_ADJUST_MIN ) ;
2011-05-13 12:45:46 +04:00
}
2012-02-28 17:05:21 +04:00
return _set_oom_adj ( OOM_ADJ_FILE , OOM_SCORE_ADJ_MIN ) ;
}
union sockaddr_union {
struct sockaddr sa ;
struct sockaddr_un un ;
} ;
static int _handle_preloaded_socket ( int fd , const char * path )
{
struct stat st_fd ;
2012-06-21 23:19:28 +04:00
union sockaddr_union sockaddr = { . sa . sa_family = 0 } ;
2012-02-28 17:05:21 +04:00
int type = 0 ;
socklen_t len = sizeof ( type ) ;
size_t path_len = strlen ( path ) ;
if ( fd < 0 )
2011-05-13 12:45:46 +04:00
return 0 ;
2012-02-28 17:05:21 +04:00
if ( fstat ( fd , & st_fd ) < 0 | | ! S_ISSOCK ( st_fd . st_mode ) )
return 0 ;
if ( getsockopt ( fd , SOL_SOCKET , SO_TYPE , & type , & len ) < 0 | |
len ! = sizeof ( type ) | | type ! = SOCK_STREAM )
return 0 ;
len = sizeof ( sockaddr ) ;
if ( getsockname ( fd , & sockaddr . sa , & len ) < 0 | |
len < sizeof ( sa_family_t ) | |
sockaddr . sa . sa_family ! = PF_UNIX )
return 0 ;
if ( ! ( len > = offsetof ( struct sockaddr_un , sun_path ) + path_len + 1 & &
memcmp ( path , sockaddr . un . sun_path , path_len ) = = 0 ) )
return 0 ;
2011-05-13 12:45:46 +04:00
return 1 ;
}
2012-02-28 17:05:21 +04:00
static int _systemd_handover ( struct daemon_state * ds )
{
const char * e ;
char * p ;
unsigned long env_pid , env_listen_fds ;
int r = 0 ;
2012-03-14 19:51:51 +04:00
/* SD_ACTIVATION must be set! */
if ( ! ( e = getenv ( SD_ACTIVATION_ENV_VAR_NAME ) ) | | strcmp ( e , " 1 " ) )
goto out ;
2012-02-28 17:05:21 +04:00
/* LISTEN_PID must be equal to our PID! */
if ( ! ( e = getenv ( SD_LISTEN_PID_ENV_VAR_NAME ) ) )
goto out ;
errno = 0 ;
env_pid = strtoul ( e , & p , 10 ) ;
if ( errno | | ! p | | * p | | env_pid < = 0 | |
getpid ( ) ! = ( pid_t ) env_pid )
2012-03-17 01:30:53 +04:00
goto out ;
2012-02-28 17:05:21 +04:00
/* LISTEN_FDS must be 1 and the fd must be a socket! */
if ( ! ( e = getenv ( SD_LISTEN_FDS_ENV_VAR_NAME ) ) )
goto out ;
errno = 0 ;
env_listen_fds = strtoul ( e , & p , 10 ) ;
if ( errno | | ! p | | * p | | env_listen_fds ! = 1 )
goto out ;
/* Check and handle the socket passed in */
if ( ( r = _handle_preloaded_socket ( SD_FD_SOCKET_SERVER , ds - > socket_path ) ) )
ds - > socket_fd = SD_FD_SOCKET_SERVER ;
out :
2012-03-14 19:51:51 +04:00
unsetenv ( SD_ACTIVATION_ENV_VAR_NAME ) ;
2012-02-28 17:05:21 +04:00
unsetenv ( SD_LISTEN_PID_ENV_VAR_NAME ) ;
unsetenv ( SD_LISTEN_FDS_ENV_VAR_NAME ) ;
return r ;
}
2011-05-13 12:45:46 +04:00
# endif
2011-05-13 13:34:12 +04:00
static int _open_socket ( daemon_state s )
{
2014-08-19 16:19:11 +04:00
int fd ;
2013-11-30 00:56:29 +04:00
int file_created = 0 ;
2012-06-21 23:19:28 +04:00
struct sockaddr_un sockaddr = { . sun_family = AF_UNIX } ;
2013-11-30 00:56:29 +04:00
struct stat buf ;
2011-05-13 13:34:12 +04:00
mode_t old_mask ;
( void ) dm_prepare_selinux_context ( s . socket_path , S_IFSOCK ) ;
old_mask = umask ( 0077 ) ;
/* Open local socket */
fd = socket ( PF_UNIX , SOCK_STREAM , 0 ) ;
if ( fd < 0 ) {
2011-05-15 15:02:29 +04:00
perror ( " Can't create local socket. " ) ;
2011-05-13 13:34:12 +04:00
goto error ;
}
2015-01-30 17:15:24 +03:00
/* Set non-blocking */
2012-06-20 12:49:16 +04:00
if ( fcntl ( fd , F_SETFL , fcntl ( fd , F_GETFL , 0 ) | O_NONBLOCK ) )
fprintf ( stderr , " setting O_NONBLOCK on socket fd %d failed: %s \n " , fd , strerror ( errno ) ) ;
2011-05-13 13:34:12 +04:00
2011-06-27 17:46:45 +04:00
fprintf ( stderr , " [D] creating %s \n " , s . socket_path ) ;
2012-04-27 13:52:33 +04:00
if ( ! dm_strncpy ( sockaddr . sun_path , s . socket_path , sizeof ( sockaddr . sun_path ) ) ) {
fprintf ( stderr , " %s: daemon socket path too long. \n " , s . socket_path ) ;
goto error ;
}
2011-05-13 13:34:12 +04:00
if ( bind ( fd , ( struct sockaddr * ) & sockaddr , sizeof ( sockaddr ) ) ) {
2013-11-30 00:56:29 +04:00
if ( errno ! = EADDRINUSE ) {
perror ( " can't bind local socket " ) ;
goto error ;
}
/* Socket already exists. If it's stale, remove it. */
2015-05-13 15:42:09 +03:00
if ( lstat ( sockaddr . sun_path , & buf ) ) {
2013-11-30 00:56:29 +04:00
perror ( " stat failed " ) ;
goto error ;
}
2015-05-13 15:42:09 +03:00
if ( ! S_ISSOCK ( buf . st_mode ) ) {
2013-11-30 00:56:29 +04:00
fprintf ( stderr , " %s: not a socket \n " , sockaddr . sun_path ) ;
goto error ;
}
if ( buf . st_uid | | ( buf . st_mode & ( S_IRWXG | S_IRWXO ) ) ) {
fprintf ( stderr , " %s: unrecognised permissions \n " , sockaddr . sun_path ) ;
goto error ;
}
if ( ! connect ( fd , ( struct sockaddr * ) & sockaddr , sizeof ( sockaddr ) ) ) {
fprintf ( stderr , " Socket %s already in use \n " , sockaddr . sun_path ) ;
goto error ;
}
fprintf ( stderr , " removing stale socket %s \n " , sockaddr . sun_path ) ;
if ( unlink ( sockaddr . sun_path ) & & ( errno ! = ENOENT ) ) {
perror ( " unlink failed " ) ;
goto error ;
}
if ( bind ( fd , ( struct sockaddr * ) & sockaddr , sizeof ( sockaddr ) ) ) {
perror ( " local socket bind failed after unlink " ) ;
goto error ;
}
2011-05-13 13:34:12 +04:00
}
2013-11-30 00:56:29 +04:00
file_created = 1 ;
2011-05-13 13:34:12 +04:00
if ( listen ( fd , 1 ) ! = 0 ) {
2011-05-15 15:02:29 +04:00
perror ( " listen local " ) ;
2011-05-13 13:34:12 +04:00
goto error ;
}
out :
umask ( old_mask ) ;
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
return fd ;
error :
if ( fd > = 0 ) {
2012-01-26 01:30:27 +04:00
if ( close ( fd ) )
perror ( " close failed " ) ;
2013-11-30 00:56:29 +04:00
if ( file_created & & unlink ( s . socket_path ) )
2012-01-26 01:30:27 +04:00
perror ( " unlink failed " ) ;
2011-05-13 13:34:12 +04:00
fd = - 1 ;
}
goto out ;
}
2011-05-13 12:45:46 +04:00
static void remove_lockfile ( const char * file )
{
if ( unlink ( file ) )
2011-05-15 15:02:29 +04:00
perror ( " unlink failed " ) ;
2011-05-13 12:45:46 +04:00
}
2013-04-15 11:43:30 +04:00
static void _daemonise ( daemon_state s )
2011-05-13 12:45:46 +04:00
{
int child_status ;
int fd ;
pid_t pid ;
struct rlimit rlim ;
struct timeval tval ;
sigset_t my_sigset ;
sigemptyset ( & my_sigset ) ;
if ( sigprocmask ( SIG_SETMASK , & my_sigset , NULL ) < 0 ) {
fprintf ( stderr , " Unable to restore signals. \n " ) ;
exit ( EXIT_FAILURE ) ;
}
signal ( SIGTERM , & _exit_handler ) ;
switch ( pid = fork ( ) ) {
case - 1 :
perror ( " fork failed: " ) ;
exit ( EXIT_FAILURE ) ;
case 0 : /* Child */
break ;
default :
/* Wait for response from child */
2011-05-15 15:02:29 +04:00
while ( ! waitpid ( pid , & child_status , WNOHANG ) & & ! _shutdown_requested ) {
2011-05-13 12:45:46 +04:00
tval . tv_sec = 0 ;
tval . tv_usec = 250000 ; /* .25 sec */
select ( 0 , NULL , NULL , NULL , & tval ) ;
}
if ( _shutdown_requested ) /* Child has signaled it is ok - we can exit now */
exit ( 0 ) ;
2013-04-15 11:43:30 +04:00
switch ( WEXITSTATUS ( child_status ) ) {
case EXIT_ALREADYRUNNING :
fprintf ( stderr , " Failed to acquire lock on %s. Already running? \n " , s . pidfile ) ;
break ;
default :
/* Problem with child. Determine what it is by exit code */
fprintf ( stderr , " Child exited with code %d \n " , WEXITSTATUS ( child_status ) ) ;
}
2011-05-13 12:45:46 +04:00
exit ( WEXITSTATUS ( child_status ) ) ;
}
if ( chdir ( " / " ) )
exit ( 1 ) ;
if ( getrlimit ( RLIMIT_NOFILE , & rlim ) < 0 )
fd = 256 ; /* just have to guess */
else
fd = rlim . rlim_cur ;
2012-02-28 17:05:21 +04:00
for ( - - fd ; fd > = 0 ; fd - - ) {
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2012-02-28 17:05:21 +04:00
/* Do not close fds preloaded by systemd! */
if ( _systemd_activation & & fd = = SD_FD_SOCKET_SERVER )
continue ;
# endif
2012-03-02 01:12:37 +04:00
( void ) close ( fd ) ;
2012-02-28 17:05:21 +04:00
}
2011-05-13 12:45:46 +04:00
if ( ( open ( " /dev/null " , O_RDONLY ) < 0 ) | |
( open ( " /dev/null " , O_WRONLY ) < 0 ) | |
( open ( " /dev/null " , O_WRONLY ) < 0 ) )
exit ( 1 ) ;
setsid ( ) ;
}
2011-08-31 16:39:58 +04:00
response daemon_reply_simple ( const char * id , . . . )
2011-06-27 17:58:11 +04:00
{
va_list ap ;
2011-09-17 18:49:18 +04:00
response res = { . cft = NULL } ;
2011-06-27 17:58:11 +04:00
va_start ( ap , id ) ;
2012-10-11 16:17:17 +04:00
buffer_init ( & res . buffer ) ;
if ( ! buffer_append_f ( & res . buffer , " response = %s " , id , NULL ) ) {
2011-06-27 17:58:11 +04:00
res . error = ENOMEM ;
2012-08-11 12:33:53 +04:00
goto end ;
}
2012-10-11 16:17:17 +04:00
if ( ! buffer_append_vf ( & res . buffer , ap ) ) {
2012-08-11 12:33:53 +04:00
res . error = ENOMEM ;
goto end ;
}
2011-09-17 18:49:18 +04:00
2012-08-11 12:33:53 +04:00
end :
va_end ( ap ) ;
2011-06-27 17:58:11 +04:00
return res ;
}
2012-02-24 03:52:11 +04:00
static response builtin_handler ( daemon_state s , client_handle h , request r )
{
const char * rq = daemon_request_str ( r , " request " , " NONE " ) ;
2012-10-12 12:15:30 +04:00
response res = { . error = EPROTO } ;
2012-02-24 03:52:11 +04:00
if ( ! strcmp ( rq , " hello " ) ) {
return daemon_reply_simple ( " OK " , " protocol = %s " , s . protocol ? : " default " ,
2012-09-09 23:57:59 +04:00
" version = % " PRId64 , ( int64_t ) s . protocol_version , NULL ) ;
2012-02-24 03:52:11 +04:00
}
2012-10-11 16:17:17 +04:00
buffer_init ( & res . buffer ) ;
2012-02-24 03:52:11 +04:00
return res ;
}
2014-06-09 03:50:57 +04:00
static void * client_thread ( void * state )
2011-06-14 06:34:18 +04:00
{
2014-06-09 03:50:57 +04:00
thread_state * ts = state ;
2012-10-11 16:17:17 +04:00
request req ;
2011-09-17 18:49:18 +04:00
response res ;
2012-10-11 16:17:17 +04:00
buffer_init ( & req . buffer ) ;
2011-06-14 06:34:18 +04:00
while ( 1 ) {
2014-06-09 03:50:57 +04:00
if ( ! buffer_read ( ts - > client . socket_fd , & req . buffer ) )
2011-06-14 06:34:18 +04:00
goto fail ;
2012-10-11 16:17:17 +04:00
req . cft = dm_config_from_string ( req . buffer . mem ) ;
2012-08-23 13:01:00 +04:00
2011-07-18 18:46:54 +04:00
if ( ! req . cft )
2012-10-11 16:17:17 +04:00
fprintf ( stderr , " error parsing request: \n %s \n " , req . buffer . mem ) ;
2012-08-23 13:01:00 +04:00
else
2014-06-09 03:50:57 +04:00
daemon_log_cft ( ts - > s . log , DAEMON_LOG_WIRE , " <- " , req . cft - > root ) ;
2012-02-24 03:52:11 +04:00
2014-06-09 03:50:57 +04:00
res = builtin_handler ( ts - > s , ts - > client , req ) ;
2012-02-24 03:52:11 +04:00
if ( res . error = = EPROTO ) /* Not a builtin, delegate to the custom handler. */
2014-06-09 03:50:57 +04:00
res = ts - > s . handler ( ts - > s , ts - > client , req ) ;
2011-06-14 06:34:18 +04:00
2012-10-11 16:17:17 +04:00
if ( ! res . buffer . mem ) {
2012-12-15 00:36:27 +04:00
if ( ! dm_config_write_node ( res . cft - > root , buffer_line , & res . buffer ) )
goto fail ;
2012-10-11 16:17:17 +04:00
if ( ! buffer_append ( & res . buffer , " \n \n " ) )
2012-02-28 18:25:37 +04:00
goto fail ;
2011-08-31 15:31:57 +04:00
dm_config_destroy ( res . cft ) ;
2011-06-14 06:34:18 +04:00
}
2012-01-15 14:33:41 +04:00
if ( req . cft )
dm_config_destroy ( req . cft ) ;
2012-10-11 16:17:17 +04:00
buffer_destroy ( & req . buffer ) ;
2012-01-15 14:33:41 +04:00
2014-06-09 03:50:57 +04:00
daemon_log_multi ( ts - > s . log , DAEMON_LOG_WIRE , " -> " , res . buffer . mem ) ;
buffer_write ( ts - > client . socket_fd , & res . buffer ) ;
2011-06-14 06:34:18 +04:00
2012-10-11 16:17:17 +04:00
buffer_destroy ( & res . buffer ) ;
2011-06-14 06:34:18 +04:00
}
fail :
/* TODO what should we really do here? */
2014-06-09 03:50:57 +04:00
if ( close ( ts - > client . socket_fd ) )
2012-03-02 01:12:37 +04:00
perror ( " close " ) ;
2012-10-11 16:17:17 +04:00
buffer_destroy ( & req . buffer ) ;
2014-06-09 03:50:57 +04:00
ts - > active = 0 ;
2011-06-14 06:34:18 +04:00
return NULL ;
}
2011-08-31 16:18:40 +04:00
static int handle_connect ( daemon_state s )
2011-06-14 06:34:18 +04:00
{
2014-06-09 03:50:57 +04:00
thread_state * ts ;
2011-06-14 06:34:18 +04:00
struct sockaddr_un sockaddr ;
2011-09-17 18:49:18 +04:00
client_handle client = { . thread_id = 0 } ;
2011-06-14 06:34:18 +04:00
socklen_t sl = sizeof ( sockaddr ) ;
2011-09-17 18:49:18 +04:00
client . socket_fd = accept ( s . socket_fd , ( struct sockaddr * ) & sockaddr , & sl ) ;
if ( client . socket_fd < 0 )
2011-06-14 06:34:18 +04:00
return 0 ;
2014-11-12 11:50:59 +03:00
if ( fcntl ( client . socket_fd , F_SETFD , FD_CLOEXEC ) )
WARN ( & s , " setting CLOEXEC on client socket fd %d failed " , client . socket_fd ) ;
2014-06-09 03:50:57 +04:00
if ( ! ( ts = dm_malloc ( sizeof ( thread_state ) ) ) ) {
2012-12-15 00:31:22 +04:00
if ( close ( client . socket_fd ) )
perror ( " close " ) ;
2014-06-09 03:50:57 +04:00
ERROR ( & s , " Failed to allocate thread state " ) ;
2011-06-14 06:34:18 +04:00
return 0 ;
2012-12-15 00:31:22 +04:00
}
2011-06-14 06:34:18 +04:00
2014-06-09 03:50:57 +04:00
ts - > next = s . threads - > next ;
s . threads - > next = ts ;
2011-06-14 06:34:18 +04:00
2014-06-09 03:50:57 +04:00
ts - > active = 1 ;
ts - > s = s ;
ts - > client = client ;
2011-09-17 18:49:18 +04:00
2014-06-09 03:50:57 +04:00
if ( pthread_create ( & ts - > client . thread_id , NULL , client_thread , ts ) )
return 0 ;
2012-01-15 14:33:41 +04:00
2011-06-14 06:34:18 +04:00
return 1 ;
}
2014-06-19 13:33:11 +04:00
static void reap ( daemon_state s , int waiting )
2014-06-09 03:50:57 +04:00
{
thread_state * last = s . threads , * ts = last - > next ;
void * rv ;
while ( ts ) {
2014-06-19 13:33:11 +04:00
if ( waiting | | ! ts - > active ) {
2014-06-24 16:58:53 +04:00
if ( ( errno = pthread_join ( ts - > client . thread_id , & rv ) ) )
ERROR ( & s , " pthread_join failed: %s " , strerror ( errno ) ) ;
2014-06-09 03:50:57 +04:00
last - > next = ts - > next ;
dm_free ( ts ) ;
} else
last = ts ;
ts = last - > next ;
}
}
2011-05-15 15:02:29 +04:00
void daemon_start ( daemon_state s )
2011-05-13 12:45:46 +04:00
{
2011-05-13 13:34:12 +04:00
int failed = 0 ;
2012-10-12 12:15:30 +04:00
log_state _log = { { 0 } } ;
2014-06-09 03:50:57 +04:00
thread_state _threads = { . next = NULL } ;
2015-04-29 17:59:30 +03:00
unsigned timeout_count = 0 ;
2012-10-12 12:15:30 +04:00
2011-05-13 12:45:46 +04:00
/*
* Switch to C locale to avoid reading large locale - archive file used by
* some glibc ( on some distributions it takes over 100 MB ) . Some daemons
* need to use mlockall ( ) .
*/
2013-01-22 14:25:02 +04:00
if ( setenv ( " LC_ALL " , " C " , 1 ) )
perror ( " Cannot set LC_ALL to C " ) ;
2011-05-13 12:45:46 +04:00
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2012-02-28 17:05:21 +04:00
_systemd_activation = _systemd_handover ( & s ) ;
# endif
2011-05-13 12:45:46 +04:00
if ( ! s . foreground )
2013-04-15 11:43:30 +04:00
_daemonise ( s ) ;
2011-05-13 12:45:46 +04:00
2012-08-08 11:41:01 +04:00
s . log = & _log ;
s . log - > name = s . name ;
2014-06-09 03:50:57 +04:00
s . threads = & _threads ;
2012-08-08 11:41:01 +04:00
/* Log important things to syslog by default. */
daemon_log_enable ( s . log , DAEMON_LOG_OUTLET_SYSLOG , DAEMON_LOG_FATAL , 1 ) ;
daemon_log_enable ( s . log , DAEMON_LOG_OUTLET_SYSLOG , DAEMON_LOG_ERROR , 1 ) ;
2011-05-13 12:45:46 +04:00
2012-10-09 22:22:30 +04:00
if ( s . pidfile ) {
( void ) dm_prepare_selinux_context ( s . pidfile , S_IFREG ) ;
2011-05-13 12:45:46 +04:00
2012-10-09 22:22:30 +04:00
/*
* NB . Take care to not keep stale locks around . Best not exit ( . . . )
* after this point .
*/
if ( dm_create_lockfile ( s . pidfile ) = = 0 )
2013-04-15 11:43:30 +04:00
exit ( EXIT_ALREADYRUNNING ) ;
2011-05-13 12:45:46 +04:00
2012-10-09 22:22:30 +04:00
( void ) dm_prepare_selinux_context ( NULL , 0 ) ;
}
2011-05-13 12:45:46 +04:00
/* Set normal exit signals to request shutdown instead of dying. */
signal ( SIGINT , & _exit_handler ) ;
signal ( SIGHUP , & _exit_handler ) ;
signal ( SIGQUIT , & _exit_handler ) ;
2011-06-14 06:34:18 +04:00
signal ( SIGTERM , & _exit_handler ) ;
2011-08-30 19:42:56 +04:00
signal ( SIGALRM , & _exit_handler ) ;
2011-06-14 06:34:18 +04:00
signal ( SIGPIPE , SIG_IGN ) ;
2011-05-13 12:45:46 +04:00
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2012-02-28 17:05:21 +04:00
/* Systemd has adjusted oom killer for us already */
if ( s . avoid_oom & & ! _systemd_activation & & ! _protect_against_oom_killer ( ) )
2012-08-08 11:41:01 +04:00
ERROR ( & s , " Failed to protect against OOM killer " ) ;
2011-05-13 12:45:46 +04:00
# endif
2012-02-28 17:05:21 +04:00
if ( ! _systemd_activation & & s . socket_path ) {
2011-05-13 13:34:12 +04:00
s . socket_fd = _open_socket ( s ) ;
if ( s . socket_fd < 0 )
failed = 1 ;
}
2015-01-30 17:15:24 +03:00
/* Set Close-on-exec */
2015-05-13 15:42:09 +03:00
if ( ! failed & & fcntl ( s . socket_fd , F_SETFD , 1 ) )
2015-01-30 17:15:24 +03:00
fprintf ( stderr , " setting CLOEXEC on socket fd %d failed: %s \n " , s . socket_fd , strerror ( errno ) ) ;
2011-05-13 12:45:46 +04:00
/* Signal parent, letting them know we are ready to go. */
if ( ! s . foreground )
kill ( getppid ( ) , SIGTERM ) ;
2011-07-18 18:46:54 +04:00
if ( s . daemon_init )
2012-10-15 05:06:27 +04:00
if ( ! s . daemon_init ( & s ) )
failed = 1 ;
2011-07-18 18:46:54 +04:00
2011-05-13 13:34:12 +04:00
while ( ! _shutdown_requested & & ! failed ) {
2015-04-29 17:59:30 +03:00
_reset_timeout ( s ) ;
2011-06-14 06:34:18 +04:00
fd_set in ;
FD_ZERO ( & in ) ;
FD_SET ( s . socket_fd , & in ) ;
2015-04-29 17:59:30 +03:00
if ( select ( FD_SETSIZE , & in , NULL , NULL , _get_timeout ( s ) ) < 0 & & errno ! = EINTR )
2011-06-14 06:34:18 +04:00
perror ( " select error " ) ;
2015-04-29 17:59:30 +03:00
if ( FD_ISSET ( s . socket_fd , & in ) ) {
timeout_count = 0 ;
2012-07-19 18:45:08 +04:00
if ( ! _shutdown_requested & & ! handle_connect ( s ) )
2012-08-08 11:41:01 +04:00
ERROR ( & s , " Failed to handle a client connection. " ) ;
2015-04-29 17:59:30 +03:00
}
2014-06-09 03:50:57 +04:00
reap ( s , 0 ) ;
2015-04-29 17:59:30 +03:00
/* s.idle == NULL equals no shutdown on timeout */
if ( _is_idle ( s ) ) {
DEBUGLOG ( & s , " timeout occured " ) ;
if ( + + timeout_count > = _get_max_timeouts ( s ) ) {
INFO ( & s , " Inactive for %d seconds. Exiting. " , timeout_count ) ;
break ;
}
}
2011-05-13 12:45:46 +04:00
}
2014-06-09 03:50:57 +04:00
INFO ( & s , " %s waiting for client threads to finish " , s . name ) ;
reap ( s , 1 ) ;
2012-03-08 18:54:05 +04:00
/* If activated by systemd, do not unlink the socket - systemd takes care of that! */
if ( ! _systemd_activation & & s . socket_fd > = 0 )
2012-01-26 01:30:27 +04:00
if ( unlink ( s . socket_path ) )
perror ( " unlink error " ) ;
2011-06-14 06:34:18 +04:00
2011-07-18 18:46:54 +04:00
if ( s . daemon_fini )
2012-10-15 05:06:27 +04:00
if ( ! s . daemon_fini ( & s ) )
failed = 1 ;
2011-07-18 18:46:54 +04:00
2012-08-08 11:41:01 +04:00
INFO ( & s , " %s shutting down " , s . name ) ;
closelog ( ) ; /* FIXME */
2012-10-09 22:22:30 +04:00
if ( s . pidfile )
remove_lockfile ( s . pidfile ) ;
2011-05-13 13:34:12 +04:00
if ( failed )
exit ( 1 ) ;
2011-05-13 12:45:46 +04:00
}