2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-01-28 00:43:50 +03:00
2010-02-03 15:03:47 +03:00
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd is distributed in the hope that it will be useful , but
WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2010-01-28 00:43:50 +03:00
# include <sys/socket.h>
# include <sys/types.h>
# include <assert.h>
# include <time.h>
# include <string.h>
# include <stdio.h>
# include <errno.h>
# include <unistd.h>
# include <sys/poll.h>
# include <sys/epoll.h>
# include <sys/un.h>
2010-01-28 01:32:50 +03:00
# include <fcntl.h>
2010-01-28 00:43:50 +03:00
# include "util.h"
# include "log.h"
# include "list.h"
2010-05-16 03:45:52 +04:00
# include "sd-daemon.h"
2010-06-16 17:41:29 +04:00
# include "tcpwrap.h"
2010-01-28 00:43:50 +03:00
# define STREAMS_MAX 256
# define SERVER_FD_MAX 16
# define TIMEOUT ((int) (10*MSEC_PER_SEC))
typedef struct Stream Stream ;
typedef struct Server {
2010-01-28 01:32:50 +03:00
int syslog_fd ;
int kmsg_fd ;
2010-01-28 00:43:50 +03:00
int epoll_fd ;
unsigned n_server_fd ;
2010-09-10 19:11:11 +04:00
bool syslog_is_stream ;
2010-01-28 00:43:50 +03:00
LIST_HEAD ( Stream , streams ) ;
unsigned n_streams ;
} Server ;
2010-05-16 03:46:35 +04:00
typedef enum StreamTarget {
STREAM_SYSLOG ,
STREAM_KMSG
} StreamTarget ;
2010-01-28 00:43:50 +03:00
typedef enum StreamState {
2010-05-16 03:46:35 +04:00
STREAM_TARGET ,
2010-01-28 00:43:50 +03:00
STREAM_PRIORITY ,
STREAM_PROCESS ,
2010-05-16 03:46:35 +04:00
STREAM_PREFIX ,
2010-01-28 00:43:50 +03:00
STREAM_RUNNING
} StreamState ;
struct Stream {
Server * server ;
StreamState state ;
int fd ;
2010-01-28 01:32:50 +03:00
2010-05-19 05:42:24 +04:00
StreamTarget target ;
2010-01-28 00:43:50 +03:00
int priority ;
char * process ;
2010-01-28 01:32:50 +03:00
pid_t pid ;
uid_t uid ;
2010-08-21 03:51:16 +04:00
gid_t gid ;
2010-01-28 00:43:50 +03:00
2010-05-16 03:46:35 +04:00
bool prefix ;
2010-08-21 05:57:47 +04:00
char buffer [ LINE_MAX ] ;
2010-01-28 00:43:50 +03:00
size_t length ;
LIST_FIELDS ( Stream , stream ) ;
} ;
2010-05-24 03:45:54 +04:00
static int stream_log ( Stream * s , char * p , usec_t ts ) {
2010-01-28 00:43:50 +03:00
char header_priority [ 16 ] , header_time [ 64 ] , header_pid [ 16 ] ;
struct iovec iovec [ 5 ] ;
2010-05-16 03:46:35 +04:00
int priority ;
2010-01-28 00:43:50 +03:00
assert ( s ) ;
assert ( p ) ;
2010-05-16 03:46:35 +04:00
priority = s - > priority ;
if ( s - > prefix & &
p [ 0 ] = = ' < ' & &
p [ 1 ] > = ' 0 ' & & p [ 1 ] < = ' 7 ' & &
p [ 2 ] = = ' > ' ) {
/* Detected priority prefix */
priority = LOG_MAKEPRI ( LOG_FAC ( priority ) , ( p [ 1 ] - ' 0 ' ) ) ;
p + = 3 ;
}
2010-01-28 00:43:50 +03:00
if ( * p = = 0 )
return 0 ;
/*
2010-01-28 01:32:50 +03:00
* The format glibc uses to talk to the syslog daemon is :
*
* < priority > time process [ pid ] : msg
2010-01-28 00:43:50 +03:00
*
2010-01-28 01:32:50 +03:00
* The format the kernel uses is :
*
* < priority > msg \ n
*
* We extend the latter to include the process name and pid .
2010-01-28 00:43:50 +03:00
*/
2010-01-28 01:32:50 +03:00
snprintf ( header_priority , sizeof ( header_priority ) , " <%i> " ,
2010-05-16 03:46:35 +04:00
s - > target = = STREAM_SYSLOG ? priority : LOG_PRI ( priority ) ) ;
2010-01-28 00:43:50 +03:00
char_array_0 ( header_priority ) ;
2010-05-16 03:46:35 +04:00
if ( s - > target = = STREAM_SYSLOG ) {
2010-01-28 01:32:50 +03:00
time_t t ;
struct tm * tm ;
2010-01-28 00:43:50 +03:00
2010-05-24 03:45:54 +04:00
t = ( time_t ) ( ts / USEC_PER_SEC ) ;
2010-01-28 01:32:50 +03:00
if ( ! ( tm = localtime ( & t ) ) )
return - EINVAL ;
if ( strftime ( header_time , sizeof ( header_time ) , " %h %e %T " , tm ) < = 0 )
return - EINVAL ;
}
2010-01-28 00:43:50 +03:00
2010-06-19 06:35:52 +04:00
snprintf ( header_pid , sizeof ( header_pid ) , " [%lu]: " , ( unsigned long ) s - > pid ) ;
2010-01-28 00:43:50 +03:00
char_array_0 ( header_pid ) ;
zero ( iovec ) ;
IOVEC_SET_STRING ( iovec [ 0 ] , header_priority ) ;
2010-05-16 03:46:35 +04:00
if ( s - > target = = STREAM_SYSLOG ) {
2010-04-06 23:57:45 +04:00
struct msghdr msghdr ;
2010-08-21 03:51:16 +04:00
union {
struct cmsghdr cmsghdr ;
uint8_t buf [ CMSG_SPACE ( sizeof ( struct ucred ) ) ] ;
} control ;
struct ucred * ucred ;
zero ( control ) ;
control . cmsghdr . cmsg_level = SOL_SOCKET ;
control . cmsghdr . cmsg_type = SCM_CREDENTIALS ;
control . cmsghdr . cmsg_len = CMSG_LEN ( sizeof ( struct ucred ) ) ;
ucred = ( struct ucred * ) CMSG_DATA ( & control . cmsghdr ) ;
ucred - > pid = s - > pid ;
ucred - > uid = s - > uid ;
ucred - > gid = s - > gid ;
2010-04-06 23:57:45 +04:00
2010-01-28 01:32:50 +03:00
IOVEC_SET_STRING ( iovec [ 1 ] , header_time ) ;
IOVEC_SET_STRING ( iovec [ 2 ] , s - > process ) ;
IOVEC_SET_STRING ( iovec [ 3 ] , header_pid ) ;
IOVEC_SET_STRING ( iovec [ 4 ] , p ) ;
2010-01-28 00:43:50 +03:00
2010-09-10 19:11:11 +04:00
/* When using syslog via SOCK_STREAM seperate the messages by NUL chars */
if ( s - > server - > syslog_is_stream )
iovec [ 4 ] . iov_len + + ;
2010-01-28 01:32:50 +03:00
zero ( msghdr ) ;
msghdr . msg_iov = iovec ;
msghdr . msg_iovlen = ELEMENTSOF ( iovec ) ;
2010-08-21 03:51:16 +04:00
msghdr . msg_control = & control ;
msghdr . msg_controllen = control . cmsghdr . cmsg_len ;
2010-01-28 01:32:50 +03:00
2010-09-10 19:11:11 +04:00
for ( ; ; ) {
ssize_t n ;
if ( ( n = sendmsg ( s - > server - > syslog_fd , & msghdr , MSG_NOSIGNAL ) ) < 0 )
return - errno ;
if ( ! s - > server - > syslog_is_stream | |
( size_t ) n > = IOVEC_TOTAL_SIZE ( iovec , ELEMENTSOF ( iovec ) ) )
break ;
IOVEC_INCREMENT ( iovec , ELEMENTSOF ( iovec ) , n ) ;
}
2010-01-28 01:32:50 +03:00
2010-05-16 03:46:35 +04:00
} else if ( s - > target = = STREAM_KMSG ) {
2010-01-28 01:32:50 +03:00
IOVEC_SET_STRING ( iovec [ 1 ] , s - > process ) ;
IOVEC_SET_STRING ( iovec [ 2 ] , header_pid ) ;
IOVEC_SET_STRING ( iovec [ 3 ] , p ) ;
2010-02-03 16:21:48 +03:00
IOVEC_SET_STRING ( iovec [ 4 ] , ( char * ) " \n " ) ;
2010-01-28 01:32:50 +03:00
if ( writev ( s - > server - > kmsg_fd , iovec , ELEMENTSOF ( iovec ) ) < 0 )
return - errno ;
} else
assert_not_reached ( " Unknown log target " ) ;
2010-01-28 00:43:50 +03:00
return 0 ;
}
2010-05-24 03:45:54 +04:00
static int stream_line ( Stream * s , char * p , usec_t ts ) {
2010-01-28 00:43:50 +03:00
int r ;
assert ( s ) ;
assert ( p ) ;
p = strstrip ( p ) ;
switch ( s - > state ) {
2010-05-16 03:46:35 +04:00
case STREAM_TARGET :
2010-01-28 01:32:50 +03:00
if ( streq ( p , " syslog " ) )
2010-05-16 03:46:35 +04:00
s - > target = STREAM_SYSLOG ;
2010-01-28 01:32:50 +03:00
else if ( streq ( p , " kmsg " ) ) {
if ( s - > server - > kmsg_fd > = 0 & & s - > uid = = 0 )
2010-05-16 03:46:35 +04:00
s - > target = STREAM_KMSG ;
2010-01-28 01:32:50 +03:00
else {
log_warning ( " /dev/kmsg logging not available. " ) ;
return - EPERM ;
}
} else {
log_warning ( " Failed to parse log target line. " ) ;
return - EBADMSG ;
}
s - > state = STREAM_PRIORITY ;
return 0 ;
2010-01-28 00:43:50 +03:00
case STREAM_PRIORITY :
2010-01-28 01:32:50 +03:00
if ( ( r = safe_atoi ( p , & s - > priority ) ) < 0 ) {
2010-08-21 03:51:16 +04:00
log_warning ( " Failed to parse log priority line: %m " ) ;
2010-01-28 00:43:50 +03:00
return r ;
2010-01-28 01:32:50 +03:00
}
2010-01-28 00:43:50 +03:00
2010-01-28 01:32:50 +03:00
if ( s - > priority < 0 ) {
2010-08-21 03:51:16 +04:00
log_warning ( " Log priority negative: %m " ) ;
2010-01-28 00:43:50 +03:00
return - ERANGE ;
2010-01-28 01:32:50 +03:00
}
2010-01-28 00:43:50 +03:00
s - > state = STREAM_PROCESS ;
return 0 ;
case STREAM_PROCESS :
if ( ! ( s - > process = strdup ( p ) ) )
return - ENOMEM ;
2010-05-16 03:46:35 +04:00
s - > state = STREAM_PREFIX ;
return 0 ;
case STREAM_PREFIX :
if ( ( r = parse_boolean ( p ) ) < 0 )
return r ;
s - > prefix = r ;
2010-01-28 00:43:50 +03:00
s - > state = STREAM_RUNNING ;
return 0 ;
case STREAM_RUNNING :
2010-05-24 03:45:54 +04:00
return stream_log ( s , p , ts ) ;
2010-01-28 00:43:50 +03:00
}
assert_not_reached ( " Unknown stream state " ) ;
}
2010-05-24 03:45:54 +04:00
static int stream_scan ( Stream * s , usec_t ts ) {
2010-01-28 00:43:50 +03:00
char * p ;
size_t remaining ;
int r = 0 ;
assert ( s ) ;
p = s - > buffer ;
remaining = s - > length ;
for ( ; ; ) {
char * newline ;
if ( ! ( newline = memchr ( p , ' \n ' , remaining ) ) )
break ;
* newline = 0 ;
2010-05-24 03:45:54 +04:00
if ( ( r = stream_line ( s , p , ts ) ) > = 0 ) {
2010-01-28 00:43:50 +03:00
remaining - = newline - p + 1 ;
p = newline + 1 ;
}
}
if ( p > s - > buffer ) {
memmove ( s - > buffer , p , remaining ) ;
s - > length = remaining ;
}
return r ;
}
2010-05-24 03:45:54 +04:00
static int stream_process ( Stream * s , usec_t ts ) {
2010-01-28 00:43:50 +03:00
ssize_t l ;
int r ;
assert ( s ) ;
2010-08-21 05:57:47 +04:00
if ( ( l = read ( s - > fd , s - > buffer + s - > length , LINE_MAX - s - > length ) ) < 0 ) {
2010-01-28 00:43:50 +03:00
if ( errno = = EAGAIN )
return 0 ;
2010-08-21 03:51:16 +04:00
log_warning ( " Failed to read from stream: %m " ) ;
2010-01-28 00:43:50 +03:00
return - 1 ;
}
if ( l = = 0 )
return 0 ;
s - > length + = l ;
2010-05-24 03:45:54 +04:00
r = stream_scan ( s , ts ) ;
2010-01-28 00:43:50 +03:00
if ( r < 0 )
return r ;
return 1 ;
}
static void stream_free ( Stream * s ) {
assert ( s ) ;
if ( s - > server ) {
assert ( s - > server - > n_streams > 0 ) ;
s - > server - > n_streams - - ;
LIST_REMOVE ( Stream , stream , s - > server - > streams , s ) ;
}
if ( s - > fd > = 0 ) {
if ( s - > server )
epoll_ctl ( s - > server - > epoll_fd , EPOLL_CTL_DEL , s - > fd , NULL ) ;
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( s - > fd ) ;
2010-01-28 00:43:50 +03:00
}
free ( s - > process ) ;
free ( s ) ;
}
static int stream_new ( Server * s , int server_fd ) {
Stream * stream ;
int fd ;
struct ucred ucred ;
socklen_t len = sizeof ( ucred ) ;
struct epoll_event ev ;
int r ;
assert ( s ) ;
if ( ( fd = accept4 ( server_fd , NULL , NULL , SOCK_NONBLOCK | SOCK_CLOEXEC ) ) < 0 )
return - errno ;
if ( s - > n_streams > = STREAMS_MAX ) {
log_warning ( " Too many connections, refusing connection. " ) ;
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( fd ) ;
2010-01-28 00:43:50 +03:00
return 0 ;
}
2010-06-16 17:41:29 +04:00
if ( ! socket_tcpwrap ( fd , " systemd-logger " ) ) {
close_nointr_nofail ( fd ) ;
return 0 ;
}
2010-01-28 00:43:50 +03:00
if ( ! ( stream = new0 ( Stream , 1 ) ) ) {
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( fd ) ;
2010-01-28 00:43:50 +03:00
return - ENOMEM ;
}
stream - > fd = fd ;
if ( getsockopt ( stream - > fd , SOL_SOCKET , SO_PEERCRED , & ucred , & len ) < 0 ) {
r = - errno ;
goto fail ;
}
if ( shutdown ( fd , SHUT_WR ) < 0 ) {
r = - errno ;
goto fail ;
}
zero ( ev ) ;
ev . data . ptr = stream ;
2010-01-29 08:45:59 +03:00
ev . events = EPOLLIN ;
2010-01-28 00:43:50 +03:00
if ( epoll_ctl ( s - > epoll_fd , EPOLL_CTL_ADD , fd , & ev ) < 0 ) {
r = - errno ;
goto fail ;
}
stream - > pid = ucred . pid ;
2010-01-28 01:32:50 +03:00
stream - > uid = ucred . uid ;
2010-08-21 03:51:16 +04:00
stream - > gid = ucred . gid ;
2010-01-28 00:43:50 +03:00
stream - > server = s ;
LIST_PREPEND ( Stream , stream , s - > streams , stream ) ;
s - > n_streams + + ;
return 0 ;
fail :
stream_free ( stream ) ;
return r ;
}
static void server_done ( Server * s ) {
unsigned i ;
assert ( s ) ;
while ( s - > streams )
stream_free ( s - > streams ) ;
for ( i = 0 ; i < s - > n_server_fd ; i + + )
2010-05-16 03:45:52 +04:00
close_nointr_nofail ( SD_LISTEN_FDS_START + i ) ;
2010-01-28 00:43:50 +03:00
2010-01-28 01:32:50 +03:00
if ( s - > syslog_fd > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( s - > syslog_fd ) ;
2010-01-28 00:43:50 +03:00
if ( s - > epoll_fd > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( s - > epoll_fd ) ;
2010-01-28 01:32:50 +03:00
if ( s - > kmsg_fd > = 0 )
2010-04-21 05:27:44 +04:00
close_nointr_nofail ( s - > kmsg_fd ) ;
2010-01-28 00:43:50 +03:00
}
static int server_init ( Server * s , unsigned n_sockets ) {
int r ;
unsigned i ;
union {
struct sockaddr sa ;
struct sockaddr_un un ;
} sa ;
assert ( s ) ;
assert ( n_sockets > 0 ) ;
zero ( * s ) ;
s - > n_server_fd = n_sockets ;
2010-01-28 01:32:50 +03:00
s - > syslog_fd = - 1 ;
s - > kmsg_fd = - 1 ;
2010-01-28 00:43:50 +03:00
if ( ( s - > epoll_fd = epoll_create1 ( EPOLL_CLOEXEC ) ) < 0 ) {
r = - errno ;
2010-08-21 03:51:16 +04:00
log_error ( " Failed to create epoll object: %m " ) ;
2010-01-28 00:43:50 +03:00
goto fail ;
}
for ( i = 0 ; i < n_sockets ; i + + ) {
struct epoll_event ev ;
2010-05-20 03:13:43 +04:00
int fd ;
fd = SD_LISTEN_FDS_START + i ;
2010-05-21 19:06:40 +04:00
if ( ( r = sd_is_socket ( fd , AF_UNSPEC , SOCK_STREAM , 1 ) ) < 0 ) {
2010-05-20 03:13:43 +04:00
log_error ( " Failed to determine file descriptor type: %s " , strerror ( - r ) ) ;
goto fail ;
}
if ( ! r ) {
log_error ( " Wrong file descriptor type. " ) ;
r = - EINVAL ;
goto fail ;
}
2010-01-28 00:43:50 +03:00
2010-08-21 03:51:16 +04:00
/* We use ev.data.ptr instead of ev.data.fd here,
* since on 64 bit archs fd is 32 bit while a pointer is
* 64 bit . To make sure we can easily distuingish fd
* values and pointer values we want to make sure to
* write the full field unconditionally . */
2010-01-28 00:43:50 +03:00
zero ( ev ) ;
2010-01-29 08:45:59 +03:00
ev . events = EPOLLIN ;
2010-08-21 03:51:16 +04:00
ev . data . ptr = INT_TO_PTR ( fd ) ;
2010-05-20 03:13:43 +04:00
if ( epoll_ctl ( s - > epoll_fd , EPOLL_CTL_ADD , fd , & ev ) < 0 ) {
2010-01-28 00:43:50 +03:00
r = - errno ;
2010-08-21 03:51:16 +04:00
log_error ( " Failed to add server fd to epoll object: %m " ) ;
2010-01-28 00:43:50 +03:00
goto fail ;
}
}
zero ( sa ) ;
sa . un . sun_family = AF_UNIX ;
strncpy ( sa . un . sun_path , " /dev/log " , sizeof ( sa . un . sun_path ) ) ;
2010-09-10 19:11:11 +04:00
if ( ( s - > syslog_fd = socket ( AF_UNIX , SOCK_DGRAM | SOCK_CLOEXEC , 0 ) ) < 0 ) {
2010-01-28 00:43:50 +03:00
r = - errno ;
2010-09-10 19:11:11 +04:00
log_error ( " Failed to create log fd: %m " ) ;
2010-01-28 00:43:50 +03:00
goto fail ;
}
2010-09-10 19:11:11 +04:00
if ( connect ( s - > syslog_fd , & sa . sa , sizeof ( sa ) ) < 0 ) {
close_nointr_nofail ( s - > syslog_fd ) ;
if ( ( s - > syslog_fd = socket ( AF_UNIX , SOCK_STREAM | SOCK_CLOEXEC , 0 ) ) < 0 ) {
r = - errno ;
log_error ( " Failed to create log fd: %m " ) ;
goto fail ;
}
if ( connect ( s - > syslog_fd , & sa . sa , sizeof ( sa ) ) < 0 ) {
r = - errno ;
log_error ( " Failed to connect log socket to /dev/log: %m " ) ;
goto fail ;
}
s - > syslog_is_stream = true ;
} else
s - > syslog_is_stream = false ;
2010-01-28 01:32:50 +03:00
/* /dev/kmsg logging is strictly optional */
if ( ( s - > kmsg_fd = open ( " /dev/kmsg " , O_WRONLY | O_NOCTTY | O_CLOEXEC ) ) < 0 )
2010-08-21 03:51:16 +04:00
log_warning ( " Failed to open /dev/kmsg for logging, disabling kernel log buffer support: %m " ) ;
2010-01-28 01:32:50 +03:00
2010-01-28 00:43:50 +03:00
return 0 ;
fail :
server_done ( s ) ;
return r ;
}
static int process_event ( Server * s , struct epoll_event * ev ) {
int r ;
assert ( s ) ;
/* Yes, this is a bit ugly, we assume that that valid pointers
2010-05-16 03:45:52 +04:00
* are > SD_LISTEN_FDS_START + SERVER_FD_MAX . Which is certainly
2010-01-28 00:43:50 +03:00
* true on Linux ( and probably most other OSes , too , since the
2010-09-03 18:30:48 +04:00
* first 4 k usually are part of a separate null pointer
2010-01-28 00:43:50 +03:00
* dereference page . */
2010-08-21 03:51:16 +04:00
if ( PTR_TO_INT ( ev - > data . ptr ) > = SD_LISTEN_FDS_START & &
PTR_TO_INT ( ev - > data . ptr ) < SD_LISTEN_FDS_START + ( int ) s - > n_server_fd ) {
2010-01-28 00:43:50 +03:00
2010-01-29 08:45:59 +03:00
if ( ev - > events ! = EPOLLIN ) {
2010-01-28 00:43:50 +03:00
log_info ( " Got invalid event from epoll. (1) " ) ;
return - EIO ;
}
2010-08-21 03:51:16 +04:00
if ( ( r = stream_new ( s , PTR_TO_INT ( ev - > data . ptr ) ) ) < 0 ) {
2010-01-28 00:43:50 +03:00
log_info ( " Failed to accept new connection: %s " , strerror ( - r ) ) ;
return r ;
}
} else {
2010-05-24 03:45:54 +04:00
usec_t ts ;
2010-01-28 00:43:50 +03:00
Stream * stream = ev - > data . ptr ;
2010-05-24 03:45:54 +04:00
ts = now ( CLOCK_REALTIME ) ;
2010-01-28 00:43:50 +03:00
2010-01-29 08:45:59 +03:00
if ( ! ( ev - > events & EPOLLIN ) ) {
2010-05-16 03:45:52 +04:00
log_info ( " Got invalid event from epoll. (2) " ) ;
2010-01-28 00:43:50 +03:00
stream_free ( stream ) ;
return 0 ;
}
2010-05-24 03:45:54 +04:00
if ( ( r = stream_process ( stream , ts ) ) < = 0 ) {
2010-01-28 00:43:50 +03:00
if ( r < 0 )
log_info ( " Got error on stream: %s " , strerror ( - r ) ) ;
stream_free ( stream ) ;
return 0 ;
}
}
return 0 ;
}
int main ( int argc , char * argv [ ] ) {
Server server ;
2010-08-31 23:05:54 +04:00
int r = EXIT_FAILURE , n ;
2010-05-16 03:45:52 +04:00
2010-06-19 18:56:57 +04:00
if ( getppid ( ) ! = 1 ) {
log_error ( " This program should be invoked by init only. " ) ;
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-06-19 18:56:57 +04:00
}
if ( argc > 1 ) {
log_error ( " This program does not take arguments. " ) ;
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-06-19 18:56:57 +04:00
}
2010-05-16 03:45:52 +04:00
log_set_target ( LOG_TARGET_SYSLOG_OR_KMSG ) ;
log_parse_environment ( ) ;
2010-08-17 00:39:02 +04:00
log_open ( ) ;
2010-01-28 00:43:50 +03:00
2010-05-16 03:45:52 +04:00
if ( ( n = sd_listen_fds ( true ) ) < 0 ) {
log_error ( " Failed to read listening file descriptors from environment: %s " , strerror ( - r ) ) ;
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-05-16 03:45:52 +04:00
}
2010-01-28 00:43:50 +03:00
2010-05-16 03:45:52 +04:00
if ( n < = 0 | | n > SERVER_FD_MAX ) {
log_error ( " No or too many file descriptors passed. " ) ;
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-05-16 03:45:52 +04:00
}
if ( server_init ( & server , ( unsigned ) n ) < 0 )
2010-08-31 23:05:54 +04:00
return EXIT_FAILURE ;
2010-01-28 00:43:50 +03:00
2010-08-11 06:38:55 +04:00
log_debug ( " systemd-logger running as pid %lu " , ( unsigned long ) getpid ( ) ) ;
2010-06-16 07:10:31 +04:00
sd_notify ( false ,
" READY=1 \n "
" STATUS=Processing requests... " ) ;
2010-01-28 00:43:50 +03:00
for ( ; ; ) {
struct epoll_event event ;
2010-02-03 16:21:48 +03:00
int k ;
2010-01-28 00:43:50 +03:00
2010-02-03 16:21:48 +03:00
if ( ( k = epoll_wait ( server . epoll_fd ,
2010-01-28 00:43:50 +03:00
& event , 1 ,
server . n_streams < = 0 ? TIMEOUT : - 1 ) ) < 0 ) {
if ( errno = = EINTR )
continue ;
2010-08-21 03:51:16 +04:00
log_error ( " epoll_wait() failed: %m " ) ;
2010-01-28 00:43:50 +03:00
goto fail ;
}
2010-02-03 16:21:48 +03:00
if ( k < = 0 )
2010-01-28 00:43:50 +03:00
break ;
2010-08-12 00:04:22 +04:00
if ( process_event ( & server , & event ) < 0 )
2010-01-28 00:43:50 +03:00
goto fail ;
}
2010-08-11 06:38:55 +04:00
2010-08-31 23:05:54 +04:00
r = EXIT_SUCCESS ;
2010-01-28 00:43:50 +03:00
2010-08-21 05:57:47 +04:00
log_debug ( " systemd-logger stopped as pid %lu " , ( unsigned long ) getpid ( ) ) ;
2010-08-11 06:38:55 +04:00
2010-01-28 00:43:50 +03:00
fail :
2010-06-16 07:10:31 +04:00
sd_notify ( false ,
" STATUS=Shutting down... " ) ;
2010-01-28 00:43:50 +03:00
server_done ( & server ) ;
return r ;
}