2011-03-12 03:03:13 +03:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2010 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
2012-04-12 02:20:58 +04:00
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
2011-03-12 03:03:13 +03:00
( 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
2012-04-12 02:20:58 +04:00
Lesser General Public License for more details .
2011-03-12 03:03:13 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2011-03-12 03:03:13 +03:00
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <sys/socket.h>
# include <sys/un.h>
# include <sys/types.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <errno.h>
2013-04-01 05:28:42 +04:00
# include <sys/poll.h>
2011-03-12 03:03:13 +03:00
# include <stddef.h>
2013-11-15 21:05:27 +04:00
# include <getopt.h>
2011-03-12 03:03:13 +03:00
# include "log.h"
# include "util.h"
# include "socket-util.h"
2013-04-01 05:28:42 +04:00
# include "sd-daemon.h"
# include "sd-bus.h"
# include "bus-internal.h"
# include "bus-message.h"
2013-10-16 08:10:04 +04:00
# include "bus-util.h"
2013-11-15 21:05:27 +04:00
# include "build.h"
# define DEFAULT_BUS_PATH "unix:path= / run / dbus / system_bus_socket"
const char * arg_bus_path = DEFAULT_BUS_PATH ;
static int help ( void ) {
printf ( " %s [OPTIONS...] \n \n "
" STDIO or socket-activatable proxy to a given DBus endpoint. \n \n "
" -h --help Show this help \n "
" --version Show package version \n "
2013-11-30 10:55:30 +04:00
" -p --bus-path=PATH Path to the kernel bus (default: %s) \n " ,
2013-11-15 21:05:27 +04:00
program_invocation_short_name , DEFAULT_BUS_PATH ) ;
return 0 ;
}
static int parse_argv ( int argc , char * argv [ ] ) {
enum {
ARG_VERSION = 0x100 ,
} ;
static const struct option options [ ] = {
{ " help " , no_argument , NULL , ' h ' } ,
{ " bus-path " , required_argument , NULL , ' p ' } ,
{ NULL , 0 , NULL , 0 }
} ;
int c ;
assert ( argc > = 0 ) ;
assert ( argv ) ;
while ( ( c = getopt_long ( argc , argv , " hsup: " , options , NULL ) ) > = 0 ) {
switch ( c ) {
case ' h ' :
help ( ) ;
return 0 ;
case ARG_VERSION :
puts ( PACKAGE_STRING ) ;
puts ( SYSTEMD_FEATURES ) ;
return 0 ;
case ' ? ' :
return - EINVAL ;
case ' p ' :
arg_bus_path = optarg ;
break ;
default :
log_error ( " Unknown option code %c " , c ) ;
return - EINVAL ;
}
}
return 1 ;
}
2011-03-12 03:03:13 +03:00
int main ( int argc , char * argv [ ] ) {
2013-04-01 05:28:42 +04:00
_cleanup_bus_unref_ sd_bus * a = NULL , * b = NULL ;
sd_id128_t server_id ;
bool is_unix ;
2013-11-15 21:05:27 +04:00
int r , in_fd , out_fd ;
2011-03-12 03:03:13 +03:00
2012-01-12 08:09:06 +04:00
log_set_target ( LOG_TARGET_JOURNAL_OR_KMSG ) ;
2011-03-12 03:03:13 +03:00
log_parse_environment ( ) ;
log_open ( ) ;
2013-11-15 21:05:27 +04:00
r = parse_argv ( argc , argv ) ;
if ( r < = 0 )
goto finish ;
r = sd_listen_fds ( 0 ) ;
if ( r = = 0 ) {
in_fd = STDIN_FILENO ;
out_fd = STDOUT_FILENO ;
} else if ( r = = 1 ) {
in_fd = SD_LISTEN_FDS_START ;
out_fd = SD_LISTEN_FDS_START ;
} else {
log_error ( " Illegal number of file descriptors passed \n " ) ;
goto finish ;
}
2013-04-01 05:28:42 +04:00
is_unix =
2013-11-15 21:05:27 +04:00
sd_is_socket ( in_fd , AF_UNIX , 0 , 0 ) > 0 & &
sd_is_socket ( out_fd , AF_UNIX , 0 , 0 ) > 0 ;
2013-04-01 05:28:42 +04:00
r = sd_bus_new ( & a ) ;
if ( r < 0 ) {
log_error ( " Failed to allocate bus: %s " , strerror ( - r ) ) ;
2011-03-12 03:03:13 +03:00
goto finish ;
}
2013-11-15 21:05:27 +04:00
r = sd_bus_set_address ( a , arg_bus_path ) ;
2013-04-01 05:28:42 +04:00
if ( r < 0 ) {
log_error ( " Failed to set address to connect to: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-05-17 06:25:56 +04:00
r = sd_bus_negotiate_fds ( a , is_unix ) ;
2013-04-01 05:28:42 +04:00
if ( r < 0 ) {
log_error ( " Failed to set FD negotiation: %s " , strerror ( - r ) ) ;
2011-03-12 03:03:13 +03:00
goto finish ;
}
2013-04-01 05:28:42 +04:00
r = sd_bus_start ( a ) ;
if ( r < 0 ) {
log_error ( " Failed to start bus client: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_get_server_id ( a , & server_id ) ;
if ( r < 0 ) {
log_error ( " Failed to get server ID: %s " , strerror ( - r ) ) ;
2011-03-12 03:03:13 +03:00
goto finish ;
}
2013-04-01 05:28:42 +04:00
r = sd_bus_new ( & b ) ;
if ( r < 0 ) {
log_error ( " Failed to allocate bus: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-11-15 21:05:27 +04:00
r = sd_bus_set_fd ( b , in_fd , out_fd ) ;
2013-04-01 05:28:42 +04:00
if ( r < 0 ) {
log_error ( " Failed to set fds: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_set_server ( b , 1 , server_id ) ;
if ( r < 0 ) {
log_error ( " Failed to set server mode: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-05-17 06:25:56 +04:00
r = sd_bus_negotiate_fds ( b , is_unix ) ;
2013-04-01 05:28:42 +04:00
if ( r < 0 ) {
log_error ( " Failed to set FD negotiation: %s " , strerror ( - r ) ) ;
2011-03-12 03:03:13 +03:00
goto finish ;
}
2013-04-01 05:28:42 +04:00
r = sd_bus_set_anonymous ( b , true ) ;
if ( r < 0 ) {
log_error ( " Failed to set anonymous authentication: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_start ( b ) ;
if ( r < 0 ) {
log_error ( " Failed to start bus client: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
for ( ; ; ) {
_cleanup_bus_message_unref_ sd_bus_message * m = NULL ;
int events_a , events_b , fd ;
uint64_t timeout_a , timeout_b , t ;
struct timespec _ts , * ts ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_process ( a , & m ) ;
if ( r < 0 ) {
2013-11-15 21:05:27 +04:00
log_error ( " Failed to process bus a: %s " , strerror ( - r ) ) ;
2011-03-12 03:03:13 +03:00
goto finish ;
}
2013-04-01 05:28:42 +04:00
if ( m ) {
r = sd_bus_send ( b , m , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to send message: %s " , strerror ( - r ) ) ;
goto finish ;
}
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
if ( r > 0 )
continue ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_process ( b , & m ) ;
if ( r < 0 ) {
2013-11-15 21:05:27 +04:00
/* treat 'connection reset by peer' as clean exit condition */
if ( r = = - ECONNRESET )
r = 0 ;
2013-04-01 05:28:42 +04:00
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
if ( m ) {
r = sd_bus_send ( a , m , NULL ) ;
if ( r < 0 ) {
log_error ( " Failed to send message: %s " , strerror ( - r ) ) ;
goto finish ;
2011-03-12 03:03:13 +03:00
}
}
2013-04-01 05:28:42 +04:00
if ( r > 0 )
continue ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
fd = sd_bus_get_fd ( a ) ;
if ( fd < 0 ) {
log_error ( " Failed to get fd: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
events_a = sd_bus_get_events ( a ) ;
if ( events_a < 0 ) {
log_error ( " Failed to get events mask: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_get_timeout ( a , & timeout_a ) ;
if ( r < 0 ) {
log_error ( " Failed to get timeout: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
events_b = sd_bus_get_events ( b ) ;
if ( events_b < 0 ) {
log_error ( " Failed to get events mask: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = sd_bus_get_timeout ( b , & timeout_b ) ;
if ( r < 0 ) {
log_error ( " Failed to get timeout: %s " , strerror ( - r ) ) ;
goto finish ;
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
t = timeout_a ;
if ( t = = ( uint64_t ) - 1 | | ( timeout_b ! = ( uint64_t ) - 1 & & timeout_b < timeout_a ) )
t = timeout_b ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
if ( t = = ( uint64_t ) - 1 )
ts = NULL ;
else {
usec_t nw ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
nw = now ( CLOCK_MONOTONIC ) ;
if ( t > nw )
t - = nw ;
else
t = 0 ;
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
ts = timespec_store ( & _ts , t ) ;
2011-03-12 03:03:13 +03:00
}
2013-03-25 03:59:00 +04:00
{
struct pollfd p [ 3 ] = {
{ . fd = fd , . events = events_a , } ,
{ . fd = STDIN_FILENO , . events = events_b & POLLIN , } ,
{ . fd = STDOUT_FILENO , . events = events_b & POLLOUT , } } ;
2013-04-01 05:28:42 +04:00
2013-03-25 03:59:00 +04:00
r = ppoll ( p , ELEMENTSOF ( p ) , ts , NULL ) ;
}
2013-04-01 05:28:42 +04:00
if ( r < 0 ) {
log_error ( " ppoll() failed: %m " ) ;
goto finish ;
}
}
2011-03-12 03:03:13 +03:00
2013-04-01 05:28:42 +04:00
r = 0 ;
2011-03-12 03:03:13 +03:00
finish :
2013-04-01 05:28:42 +04:00
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
2011-03-12 03:03:13 +03:00
}