2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2010-02-01 05:33:24 +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-02-01 05:33:24 +03:00
# include <sys/epoll.h>
# include <sys/timerfd.h>
# include <errno.h>
# include <unistd.h>
2010-04-18 05:08:16 +04:00
# include <dbus/dbus.h>
2010-02-01 05:33:24 +03:00
# include "dbus.h"
# include "log.h"
# include "strv.h"
2010-03-31 18:29:55 +04:00
# include "cgroup.h"
2010-04-18 05:08:16 +04:00
# include "dbus-unit.h"
# include "dbus-job.h"
# include "dbus-manager.h"
2010-05-23 05:45:33 +04:00
# include "dbus-service.h"
# include "dbus-socket.h"
# include "dbus-target.h"
# include "dbus-device.h"
# include "dbus-mount.h"
# include "dbus-automount.h"
# include "dbus-snapshot.h"
# include "dbus-swap.h"
2010-05-24 03:45:54 +04:00
# include "dbus-timer.h"
2010-05-24 07:25:33 +04:00
# include "dbus-path.h"
2010-07-08 04:43:18 +04:00
# include "bus-errors.h"
2010-09-01 05:30:59 +04:00
# include "special.h"
2011-04-16 03:54:49 +04:00
# include "dbus-common.h"
2010-05-23 05:45:33 +04:00
2010-06-19 05:04:04 +04:00
# define CONNECTIONS_MAX 52
2010-05-23 05:45:33 +04:00
static const char bus_properties_interface [ ] = BUS_PROPERTIES_INTERFACE ;
static const char bus_introspectable_interface [ ] = BUS_INTROSPECTABLE_INTERFACE ;
const char * const bus_interface_table [ ] = {
" org.freedesktop.DBus.Properties " , bus_properties_interface ,
" org.freedesktop.DBus.Introspectable " , bus_introspectable_interface ,
" org.freedesktop.systemd1.Manager " , bus_manager_interface ,
" org.freedesktop.systemd1.Job " , bus_job_interface ,
" org.freedesktop.systemd1.Unit " , bus_unit_interface ,
" org.freedesktop.systemd1.Service " , bus_service_interface ,
" org.freedesktop.systemd1.Socket " , bus_socket_interface ,
" org.freedesktop.systemd1.Target " , bus_target_interface ,
" org.freedesktop.systemd1.Device " , bus_device_interface ,
" org.freedesktop.systemd1.Mount " , bus_mount_interface ,
" org.freedesktop.systemd1.Automount " , bus_automount_interface ,
" org.freedesktop.systemd1.Snapshot " , bus_snapshot_interface ,
" org.freedesktop.systemd1.Swap " , bus_swap_interface ,
2010-05-24 03:45:54 +04:00
" org.freedesktop.systemd1.Timer " , bus_timer_interface ,
2010-05-24 07:25:33 +04:00
" org.freedesktop.systemd1.Path " , bus_path_interface ,
2010-05-23 05:45:33 +04:00
NULL
} ;
2010-02-01 05:33:24 +03:00
2010-06-19 05:04:04 +04:00
static void bus_done_api ( Manager * m ) ;
static void bus_done_system ( Manager * m ) ;
static void bus_done_private ( Manager * m ) ;
2010-07-08 00:28:02 +04:00
static void shutdown_connection ( Manager * m , DBusConnection * c ) ;
2010-06-02 06:24:16 +04:00
2010-06-19 05:04:04 +04:00
static void bus_dispatch_status ( DBusConnection * bus , DBusDispatchStatus status , void * data ) {
2010-03-31 18:29:55 +04:00
Manager * m = data ;
assert ( bus ) ;
assert ( m ) ;
2010-04-08 06:58:30 +04:00
2010-06-19 05:04:04 +04:00
/* We maintain two sets, one for those connections where we
* requested a dispatch , and another where we didn ' t . And then ,
* we move the connections between the two sets . */
2010-03-31 18:29:55 +04:00
2010-06-19 05:04:04 +04:00
if ( status = = DBUS_DISPATCH_COMPLETE )
set_move_one ( m - > bus_connections , m - > bus_connections_for_dispatch , bus ) ;
else
set_move_one ( m - > bus_connections_for_dispatch , m - > bus_connections , bus ) ;
2010-03-31 18:29:55 +04:00
}
2010-02-01 05:33:24 +03:00
static uint32_t bus_flags_to_events ( DBusWatch * bus_watch ) {
unsigned flags ;
uint32_t events = 0 ;
assert ( bus_watch ) ;
/* no watch flags for disabled watches */
if ( ! dbus_watch_get_enabled ( bus_watch ) )
return 0 ;
flags = dbus_watch_get_flags ( bus_watch ) ;
if ( flags & DBUS_WATCH_READABLE )
events | = EPOLLIN ;
if ( flags & DBUS_WATCH_WRITABLE )
events | = EPOLLOUT ;
return events | EPOLLHUP | EPOLLERR ;
}
static unsigned events_to_bus_flags ( uint32_t events ) {
unsigned flags = 0 ;
if ( events & EPOLLIN )
flags | = DBUS_WATCH_READABLE ;
if ( events & EPOLLOUT )
flags | = DBUS_WATCH_WRITABLE ;
if ( events & EPOLLHUP )
flags | = DBUS_WATCH_HANGUP ;
if ( events & EPOLLERR )
flags | = DBUS_WATCH_ERROR ;
return flags ;
}
void bus_watch_event ( Manager * m , Watch * w , int events ) {
assert ( m ) ;
assert ( w ) ;
/* This is called by the event loop whenever there is
* something happening on D - Bus ' file handles . */
2010-03-31 18:29:55 +04:00
if ( ! dbus_watch_get_enabled ( w - > data . bus_watch ) )
2010-02-01 05:33:24 +03:00
return ;
dbus_watch_handle ( w - > data . bus_watch , events_to_bus_flags ( events ) ) ;
}
static dbus_bool_t bus_add_watch ( DBusWatch * bus_watch , void * data ) {
Manager * m = data ;
Watch * w ;
struct epoll_event ev ;
assert ( bus_watch ) ;
assert ( m ) ;
if ( ! ( w = new0 ( Watch , 1 ) ) )
return FALSE ;
w - > fd = dbus_watch_get_unix_fd ( bus_watch ) ;
w - > type = WATCH_DBUS_WATCH ;
w - > data . bus_watch = bus_watch ;
zero ( ev ) ;
ev . events = bus_flags_to_events ( bus_watch ) ;
ev . data . ptr = w ;
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , w - > fd , & ev ) < 0 ) {
if ( errno ! = EEXIST ) {
free ( w ) ;
return FALSE ;
}
/* Hmm, bloody D-Bus creates multiple watches on the
* same fd . epoll ( ) does not like that . As a dirty
* hack we simply dup ( ) the fd and hence get a second
* one we can safely add to the epoll ( ) . */
if ( ( w - > fd = dup ( w - > fd ) ) < 0 ) {
free ( w ) ;
return FALSE ;
}
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , w - > fd , & ev ) < 0 ) {
close_nointr_nofail ( w - > fd ) ;
2011-03-31 17:35:40 +04:00
free ( w ) ;
2010-02-01 05:33:24 +03:00
return FALSE ;
}
w - > fd_is_dupped = true ;
}
dbus_watch_set_data ( bus_watch , w , NULL ) ;
return TRUE ;
}
static void bus_remove_watch ( DBusWatch * bus_watch , void * data ) {
Manager * m = data ;
Watch * w ;
assert ( bus_watch ) ;
assert ( m ) ;
if ( ! ( w = dbus_watch_get_data ( bus_watch ) ) )
return ;
assert ( w - > type = = WATCH_DBUS_WATCH ) ;
assert_se ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_DEL , w - > fd , NULL ) > = 0 ) ;
if ( w - > fd_is_dupped )
close_nointr_nofail ( w - > fd ) ;
free ( w ) ;
}
static void bus_toggle_watch ( DBusWatch * bus_watch , void * data ) {
Manager * m = data ;
Watch * w ;
struct epoll_event ev ;
assert ( bus_watch ) ;
assert ( m ) ;
assert_se ( w = dbus_watch_get_data ( bus_watch ) ) ;
assert ( w - > type = = WATCH_DBUS_WATCH ) ;
zero ( ev ) ;
ev . events = bus_flags_to_events ( bus_watch ) ;
ev . data . ptr = w ;
assert_se ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_MOD , w - > fd , & ev ) = = 0 ) ;
}
static int bus_timeout_arm ( Manager * m , Watch * w ) {
struct itimerspec its ;
assert ( m ) ;
assert ( w ) ;
zero ( its ) ;
if ( dbus_timeout_get_enabled ( w - > data . bus_timeout ) ) {
timespec_store ( & its . it_value , dbus_timeout_get_interval ( w - > data . bus_timeout ) * USEC_PER_MSEC ) ;
2011-03-31 17:35:40 +04:00
its . it_interval = its . it_value ;
2010-02-01 05:33:24 +03:00
}
if ( timerfd_settime ( w - > fd , 0 , & its , NULL ) < 0 )
return - errno ;
return 0 ;
}
void bus_timeout_event ( Manager * m , Watch * w , int events ) {
assert ( m ) ;
assert ( w ) ;
/* This is called by the event loop whenever there is
* something happening on D - Bus ' file handles . */
if ( ! ( dbus_timeout_get_enabled ( w - > data . bus_timeout ) ) )
return ;
dbus_timeout_handle ( w - > data . bus_timeout ) ;
}
static dbus_bool_t bus_add_timeout ( DBusTimeout * timeout , void * data ) {
Manager * m = data ;
Watch * w ;
struct epoll_event ev ;
assert ( timeout ) ;
assert ( m ) ;
if ( ! ( w = new0 ( Watch , 1 ) ) )
return FALSE ;
2011-03-31 17:35:40 +04:00
if ( ( w - > fd = timerfd_create ( CLOCK_MONOTONIC , TFD_NONBLOCK | TFD_CLOEXEC ) ) < 0 )
2010-02-01 05:33:24 +03:00
goto fail ;
w - > type = WATCH_DBUS_TIMEOUT ;
w - > data . bus_timeout = timeout ;
if ( bus_timeout_arm ( m , w ) < 0 )
goto fail ;
zero ( ev ) ;
ev . events = EPOLLIN ;
ev . data . ptr = w ;
if ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_ADD , w - > fd , & ev ) < 0 )
goto fail ;
dbus_timeout_set_data ( timeout , w , NULL ) ;
return TRUE ;
fail :
if ( w - > fd > = 0 )
close_nointr_nofail ( w - > fd ) ;
free ( w ) ;
return FALSE ;
}
static void bus_remove_timeout ( DBusTimeout * timeout , void * data ) {
Manager * m = data ;
Watch * w ;
assert ( timeout ) ;
assert ( m ) ;
if ( ! ( w = dbus_timeout_get_data ( timeout ) ) )
return ;
assert ( w - > type = = WATCH_DBUS_TIMEOUT ) ;
assert_se ( epoll_ctl ( m - > epoll_fd , EPOLL_CTL_DEL , w - > fd , NULL ) > = 0 ) ;
close_nointr_nofail ( w - > fd ) ;
free ( w ) ;
}
static void bus_toggle_timeout ( DBusTimeout * timeout , void * data ) {
Manager * m = data ;
Watch * w ;
int r ;
assert ( timeout ) ;
assert ( m ) ;
assert_se ( w = dbus_timeout_get_data ( timeout ) ) ;
assert ( w - > type = = WATCH_DBUS_TIMEOUT ) ;
if ( ( r = bus_timeout_arm ( m , w ) ) < 0 )
log_error ( " Failed to rearm timer: %s " , strerror ( - r ) ) ;
}
2010-06-15 04:46:07 +04:00
static DBusHandlerResult api_bus_message_filter ( DBusConnection * connection , DBusMessage * message , void * data ) {
2010-02-05 02:38:41 +03:00
Manager * m = data ;
DBusError error ;
2010-06-02 06:24:16 +04:00
DBusMessage * reply = NULL ;
2010-02-05 02:38:41 +03:00
assert ( connection ) ;
assert ( message ) ;
assert ( m ) ;
dbus_error_init ( & error ) ;
2010-07-10 06:50:19 +04:00
if ( dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_METHOD_CALL | |
dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_SIGNAL )
log_debug ( " Got D-Bus request: %s.%s() on %s " ,
dbus_message_get_interface ( message ) ,
dbus_message_get_member ( message ) ,
dbus_message_get_path ( message ) ) ;
2010-02-05 02:38:41 +03:00
if ( dbus_message_is_signal ( message , DBUS_INTERFACE_LOCAL , " Disconnected " ) ) {
2010-08-18 00:14:43 +04:00
log_debug ( " API D-Bus connection terminated. " ) ;
2010-04-06 18:32:07 +04:00
bus_done_api ( m ) ;
2010-02-05 02:38:41 +03:00
} else if ( dbus_message_is_signal ( message , DBUS_INTERFACE_DBUS , " NameOwnerChanged " ) ) {
2010-04-16 01:16:16 +04:00
const char * name , * old_owner , * new_owner ;
2010-02-05 02:38:41 +03:00
if ( ! dbus_message_get_args ( message , & error ,
DBUS_TYPE_STRING , & name ,
2010-04-16 01:16:16 +04:00
DBUS_TYPE_STRING , & old_owner ,
DBUS_TYPE_STRING , & new_owner ,
2010-02-05 02:38:41 +03:00
DBUS_TYPE_INVALID ) )
log_error ( " Failed to parse NameOwnerChanged message: %s " , error . message ) ;
else {
2010-07-05 02:58:07 +04:00
if ( set_remove ( BUS_CONNECTION_SUBSCRIBED ( m , connection ) , ( char * ) name ) )
log_debug ( " Subscription client vanished: %s (left: %u) " , name , set_size ( BUS_CONNECTION_SUBSCRIBED ( m , connection ) ) ) ;
2010-04-16 01:16:16 +04:00
if ( old_owner [ 0 ] = = 0 )
old_owner = NULL ;
if ( new_owner [ 0 ] = = 0 )
new_owner = NULL ;
manager_dispatch_bus_name_owner_changed ( m , name , old_owner , new_owner ) ;
2010-02-05 02:38:41 +03:00
}
2010-06-02 06:24:16 +04:00
} else if ( dbus_message_is_signal ( message , " org.freedesktop.systemd1.Activator " , " ActivationRequest " ) ) {
const char * name ;
if ( ! dbus_message_get_args ( message , & error ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_INVALID ) )
log_error ( " Failed to parse ActivationRequest message: %s " , error . message ) ;
else {
int r ;
Unit * u ;
2010-06-05 00:35:31 +04:00
log_debug ( " Got D-Bus activation request for %s " , name ) ;
2010-09-01 05:30:59 +04:00
if ( manager_unit_pending_inactive ( m , SPECIAL_DBUS_SERVICE ) | |
manager_unit_pending_inactive ( m , SPECIAL_DBUS_SOCKET ) ) {
r = - EADDRNOTAVAIL ;
dbus_set_error ( & error , BUS_ERROR_SHUTTING_DOWN , " Refusing activation, D-Bus is shutting down. " ) ;
} else {
r = manager_load_unit ( m , name , NULL , & error , & u ) ;
2010-06-02 06:24:16 +04:00
2010-09-01 05:30:59 +04:00
if ( r > = 0 & & u - > meta . refuse_manual_start )
r = - EPERM ;
2010-06-02 06:24:16 +04:00
2010-09-01 05:30:59 +04:00
if ( r > = 0 )
r = manager_add_job ( m , JOB_START , u , JOB_REPLACE , true , & error , NULL ) ;
}
2010-06-02 06:24:16 +04:00
if ( r < 0 ) {
const char * id , * text ;
2010-09-06 04:42:42 +04:00
log_debug ( " D-Bus activation failed for %s: %s " , name , strerror ( - r ) ) ;
2010-06-07 06:15:37 +04:00
2010-06-02 06:24:16 +04:00
if ( ! ( reply = dbus_message_new_signal ( " /org/freedesktop/systemd1 " , " org.freedesktop.systemd1.Activator " , " ActivationFailure " ) ) )
goto oom ;
2011-04-16 03:54:49 +04:00
id = error . name ? error . name : bus_errno_to_dbus ( r ) ;
2010-07-08 04:43:18 +04:00
text = bus_error ( & error , r ) ;
2010-06-02 06:24:16 +04:00
if ( ! dbus_message_set_destination ( reply , DBUS_SERVICE_DBUS ) | |
! dbus_message_append_args ( reply ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_STRING , & id ,
DBUS_TYPE_STRING , & text ,
DBUS_TYPE_INVALID ) )
goto oom ;
}
2011-02-21 17:32:17 +03:00
/* On success we don't do anything, the service will be spawned now */
2010-06-02 06:24:16 +04:00
}
2010-02-05 02:38:41 +03:00
}
dbus_error_free ( & error ) ;
2010-06-02 06:24:16 +04:00
if ( reply ) {
if ( ! dbus_connection_send ( connection , reply , NULL ) )
goto oom ;
dbus_message_unref ( reply ) ;
}
2010-02-05 02:38:41 +03:00
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
2010-06-02 06:24:16 +04:00
oom :
if ( reply )
dbus_message_unref ( reply ) ;
dbus_error_free ( & error ) ;
return DBUS_HANDLER_RESULT_NEED_MEMORY ;
2010-02-05 02:38:41 +03:00
}
2010-06-15 04:46:07 +04:00
static DBusHandlerResult system_bus_message_filter ( DBusConnection * connection , DBusMessage * message , void * data ) {
2010-03-31 18:29:55 +04:00
Manager * m = data ;
DBusError error ;
assert ( connection ) ;
assert ( message ) ;
assert ( m ) ;
dbus_error_init ( & error ) ;
2010-07-10 06:50:19 +04:00
if ( m - > api_bus ! = m - > system_bus & &
( dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_METHOD_CALL | |
dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_SIGNAL ) )
log_debug ( " Got D-Bus request on system bus: %s.%s() on %s " ,
dbus_message_get_interface ( message ) ,
dbus_message_get_member ( message ) ,
dbus_message_get_path ( message ) ) ;
2010-03-31 18:29:55 +04:00
if ( dbus_message_is_signal ( message , DBUS_INTERFACE_LOCAL , " Disconnected " ) ) {
2010-08-12 03:02:19 +04:00
log_debug ( " System D-Bus connection terminated. " ) ;
2010-04-06 18:32:07 +04:00
bus_done_system ( m ) ;
2010-03-31 18:29:55 +04:00
2010-09-03 03:45:14 +04:00
} else if ( m - > running_as ! = MANAGER_SYSTEM & &
dbus_message_is_signal ( message , " org.freedesktop.systemd1.Agent " , " Released " ) ) {
2010-03-31 18:29:55 +04:00
const char * cgroup ;
if ( ! dbus_message_get_args ( message , & error ,
DBUS_TYPE_STRING , & cgroup ,
DBUS_TYPE_INVALID ) )
log_error ( " Failed to parse Released message: %s " , error . message ) ;
else
cgroup_notify_empty ( m , cgroup ) ;
}
dbus_error_free ( & error ) ;
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
}
2010-06-19 05:04:04 +04:00
static DBusHandlerResult private_bus_message_filter ( DBusConnection * connection , DBusMessage * message , void * data ) {
Manager * m = data ;
2010-08-06 05:21:50 +04:00
DBusError error ;
2010-06-19 05:04:04 +04:00
assert ( connection ) ;
assert ( message ) ;
assert ( m ) ;
2010-08-06 05:21:50 +04:00
dbus_error_init ( & error ) ;
2010-07-10 06:50:19 +04:00
if ( dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_METHOD_CALL | |
dbus_message_get_type ( message ) = = DBUS_MESSAGE_TYPE_SIGNAL )
log_debug ( " Got D-Bus request: %s.%s() on %s " ,
dbus_message_get_interface ( message ) ,
dbus_message_get_member ( message ) ,
dbus_message_get_path ( message ) ) ;
2010-06-19 05:04:04 +04:00
2010-07-08 00:28:02 +04:00
if ( dbus_message_is_signal ( message , DBUS_INTERFACE_LOCAL , " Disconnected " ) )
shutdown_connection ( m , connection ) ;
2010-09-03 03:45:14 +04:00
else if ( m - > running_as = = MANAGER_SYSTEM & &
dbus_message_is_signal ( message , " org.freedesktop.systemd1.Agent " , " Released " ) ) {
2010-08-06 05:21:50 +04:00
const char * cgroup ;
if ( ! dbus_message_get_args ( message , & error ,
DBUS_TYPE_STRING , & cgroup ,
DBUS_TYPE_INVALID ) )
log_error ( " Failed to parse Released message: %s " , error . message ) ;
else
cgroup_notify_empty ( m , cgroup ) ;
2010-09-03 03:45:14 +04:00
/* Forward the message to the system bus, so that user
* instances are notified as well */
if ( m - > system_bus )
dbus_connection_send ( m - > system_bus , message , NULL ) ;
2010-08-06 05:21:50 +04:00
}
dbus_error_free ( & error ) ;
2010-06-19 05:04:04 +04:00
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED ;
}
2010-02-05 02:38:41 +03:00
unsigned bus_dispatch ( Manager * m ) {
2010-06-19 05:04:04 +04:00
DBusConnection * c ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2010-04-21 05:27:44 +04:00
if ( m - > queued_message ) {
/* If we cannot get rid of this message we won't
* dispatch any D - Bus messages , so that we won ' t end
* up wanting to queue another message . */
2010-07-07 04:21:16 +04:00
if ( m - > queued_message_connection )
if ( ! dbus_connection_send ( m - > queued_message_connection , m - > queued_message , NULL ) )
2010-06-19 05:04:04 +04:00
return 0 ;
2010-04-21 05:27:44 +04:00
dbus_message_unref ( m - > queued_message ) ;
m - > queued_message = NULL ;
2010-07-07 04:21:16 +04:00
m - > queued_message_connection = NULL ;
2010-04-21 05:27:44 +04:00
}
2010-06-19 05:04:04 +04:00
if ( ( c = set_first ( m - > bus_connections_for_dispatch ) ) ) {
if ( dbus_connection_dispatch ( c ) = = DBUS_DISPATCH_COMPLETE )
set_move_one ( m - > bus_connections , m - > bus_connections_for_dispatch , c ) ;
2010-04-08 02:52:50 +04:00
return 1 ;
}
2010-02-05 02:38:41 +03:00
2010-03-31 18:29:55 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2010-04-16 01:16:16 +04:00
static void request_name_pending_cb ( DBusPendingCall * pending , void * userdata ) {
2010-04-05 00:48:47 +04:00
DBusMessage * reply ;
DBusError error ;
dbus_error_init ( & error ) ;
assert_se ( reply = dbus_pending_call_steal_reply ( pending ) ) ;
switch ( dbus_message_get_type ( reply ) ) {
case DBUS_MESSAGE_TYPE_ERROR :
assert_se ( dbus_set_error_from_message ( & error , reply ) ) ;
log_warning ( " RequestName() failed: %s " , error . message ) ;
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN : {
uint32_t r ;
if ( ! dbus_message_get_args ( reply ,
& error ,
DBUS_TYPE_UINT32 , & r ,
DBUS_TYPE_INVALID ) ) {
log_error ( " Failed to parse RequestName() reply: %s " , error . message ) ;
break ;
}
if ( r = = 1 )
log_debug ( " Successfully acquired name. " ) ;
else
log_error ( " Name already owned. " ) ;
break ;
}
default :
assert_not_reached ( " Invalid reply message " ) ;
}
dbus_message_unref ( reply ) ;
dbus_error_free ( & error ) ;
}
2010-02-01 05:33:24 +03:00
static int request_name ( Manager * m ) {
const char * name = " org.freedesktop.systemd1 " ;
uint32_t flags = 0 ;
2010-04-16 01:16:16 +04:00
DBusMessage * message = NULL ;
DBusPendingCall * pending = NULL ;
2010-02-01 05:33:24 +03:00
if ( ! ( message = dbus_message_new_method_call (
DBUS_SERVICE_DBUS ,
DBUS_PATH_DBUS ,
DBUS_INTERFACE_DBUS ,
" RequestName " ) ) )
2010-04-16 01:16:16 +04:00
goto oom ;
2010-02-01 05:33:24 +03:00
if ( ! dbus_message_append_args (
message ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_UINT32 , & flags ,
2010-04-16 01:16:16 +04:00
DBUS_TYPE_INVALID ) )
goto oom ;
2010-02-01 05:33:24 +03:00
2010-04-16 01:16:16 +04:00
if ( ! dbus_connection_send_with_reply ( m - > api_bus , message , & pending , - 1 ) )
goto oom ;
2010-02-01 05:33:24 +03:00
2010-04-16 01:16:16 +04:00
if ( ! dbus_pending_call_set_notify ( pending , request_name_pending_cb , m , NULL ) )
goto oom ;
2010-02-01 05:33:24 +03:00
dbus_message_unref ( message ) ;
2010-04-05 00:48:47 +04:00
dbus_pending_call_unref ( pending ) ;
/* We simple ask for the name and don't wait for it. Sooner or
* later we ' ll have it . */
2010-02-01 05:33:24 +03:00
return 0 ;
2010-04-16 01:16:16 +04:00
oom :
if ( pending ) {
dbus_pending_call_cancel ( pending ) ;
dbus_pending_call_unref ( pending ) ;
}
if ( message )
dbus_message_unref ( message ) ;
return - ENOMEM ;
2010-02-01 05:33:24 +03:00
}
2010-06-05 00:03:22 +04:00
static void query_name_list_pending_cb ( DBusPendingCall * pending , void * userdata ) {
DBusMessage * reply ;
DBusError error ;
Manager * m = userdata ;
assert ( m ) ;
dbus_error_init ( & error ) ;
assert_se ( reply = dbus_pending_call_steal_reply ( pending ) ) ;
switch ( dbus_message_get_type ( reply ) ) {
case DBUS_MESSAGE_TYPE_ERROR :
assert_se ( dbus_set_error_from_message ( & error , reply ) ) ;
log_warning ( " ListNames() failed: %s " , error . message ) ;
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN : {
int r ;
char * * l ;
if ( ( r = bus_parse_strv ( reply , & l ) ) < 0 )
log_warning ( " Failed to parse ListNames() reply: %s " , strerror ( - r ) ) ;
else {
char * * t ;
STRV_FOREACH ( t , l )
/* This is a bit hacky, we say the
* owner of the name is the name
* itself , because we don ' t want the
* extra traffic to figure out the
* real owner . */
manager_dispatch_bus_name_owner_changed ( m , * t , NULL , * t ) ;
strv_free ( l ) ;
}
break ;
}
default :
assert_not_reached ( " Invalid reply message " ) ;
}
dbus_message_unref ( reply ) ;
dbus_error_free ( & error ) ;
}
static int query_name_list ( Manager * m ) {
DBusMessage * message = NULL ;
DBusPendingCall * pending = NULL ;
/* Asks for the currently installed bus names */
if ( ! ( message = dbus_message_new_method_call (
DBUS_SERVICE_DBUS ,
DBUS_PATH_DBUS ,
DBUS_INTERFACE_DBUS ,
" ListNames " ) ) )
goto oom ;
if ( ! dbus_connection_send_with_reply ( m - > api_bus , message , & pending , - 1 ) )
goto oom ;
if ( ! dbus_pending_call_set_notify ( pending , query_name_list_pending_cb , m , NULL ) )
goto oom ;
dbus_message_unref ( message ) ;
dbus_pending_call_unref ( pending ) ;
/* We simple ask for the list and don't wait for it. Sooner or
* later we ' ll get it . */
return 0 ;
oom :
if ( pending ) {
dbus_pending_call_cancel ( pending ) ;
dbus_pending_call_unref ( pending ) ;
}
if ( message )
dbus_message_unref ( message ) ;
return - ENOMEM ;
}
2010-03-31 18:29:55 +04:00
static int bus_setup_loop ( Manager * m , DBusConnection * bus ) {
assert ( m ) ;
assert ( bus ) ;
dbus_connection_set_exit_on_disconnect ( bus , FALSE ) ;
2010-04-08 02:52:50 +04:00
2010-03-31 18:29:55 +04:00
if ( ! dbus_connection_set_watch_functions ( bus , bus_add_watch , bus_remove_watch , bus_toggle_watch , m , NULL ) | |
2010-06-19 05:04:04 +04:00
! dbus_connection_set_timeout_functions ( bus , bus_add_timeout , bus_remove_timeout , bus_toggle_timeout , m , NULL ) ) {
log_error ( " Not enough memory " ) ;
2010-03-31 18:29:55 +04:00
return - ENOMEM ;
2010-06-19 05:04:04 +04:00
}
2010-03-31 18:29:55 +04:00
2010-06-19 05:04:04 +04:00
if ( set_put ( m - > bus_connections_for_dispatch , bus ) < 0 ) {
log_error ( " Not enough memory " ) ;
return - ENOMEM ;
}
dbus_connection_set_dispatch_status_function ( bus , bus_dispatch_status , m , NULL ) ;
2010-03-31 18:29:55 +04:00
return 0 ;
}
2010-06-19 05:04:04 +04:00
static dbus_bool_t allow_only_root ( DBusConnection * connection , unsigned long uid , void * data ) {
return uid = = 0 ;
}
static void bus_new_connection (
DBusServer * server ,
DBusConnection * new_connection ,
void * data ) {
Manager * m = data ;
assert ( m ) ;
if ( set_size ( m - > bus_connections ) > = CONNECTIONS_MAX ) {
log_error ( " Too many concurrent connections. " ) ;
return ;
}
dbus_connection_set_unix_user_function ( new_connection , allow_only_root , NULL , NULL ) ;
if ( bus_setup_loop ( m , new_connection ) < 0 )
return ;
if ( ! dbus_connection_register_object_path ( new_connection , " /org/freedesktop/systemd1 " , & bus_manager_vtable , m ) | |
! dbus_connection_register_fallback ( new_connection , " /org/freedesktop/systemd1/unit " , & bus_unit_vtable , m ) | |
! dbus_connection_register_fallback ( new_connection , " /org/freedesktop/systemd1/job " , & bus_job_vtable , m ) | |
! dbus_connection_add_filter ( new_connection , private_bus_message_filter , m , NULL ) ) {
log_error ( " Not enough memory. " ) ;
return ;
}
log_debug ( " Accepted connection on private bus. " ) ;
dbus_connection_ref ( new_connection ) ;
}
static int bus_init_system ( Manager * m ) {
2010-02-01 05:33:24 +03:00
DBusError error ;
int r ;
assert ( m ) ;
dbus_error_init ( & error ) ;
2010-04-06 18:32:07 +04:00
if ( m - > system_bus )
return 0 ;
2010-03-31 18:29:55 +04:00
2010-06-19 05:15:59 +04:00
if ( m - > running_as = = MANAGER_SYSTEM & & m - > api_bus )
2010-04-06 18:32:07 +04:00
m - > system_bus = m - > api_bus ;
else {
2010-03-31 18:29:55 +04:00
if ( ! ( m - > system_bus = dbus_bus_get_private ( DBUS_BUS_SYSTEM , & error ) ) ) {
2010-04-07 05:16:50 +04:00
log_debug ( " Failed to get system D-Bus connection, retrying later: %s " , error . message ) ;
2010-06-19 05:04:04 +04:00
r = 0 ;
goto fail ;
2010-03-31 18:29:55 +04:00
}
2010-06-19 05:04:04 +04:00
if ( ( r = bus_setup_loop ( m , m - > system_bus ) ) < 0 )
goto fail ;
2010-04-06 18:32:07 +04:00
}
if ( ! dbus_connection_add_filter ( m - > system_bus , system_bus_message_filter , m , NULL ) ) {
2010-06-19 05:04:04 +04:00
log_error ( " Not enough memory " ) ;
r = - EIO ;
goto fail ;
2010-02-05 02:38:41 +03:00
}
2010-09-03 03:45:14 +04:00
if ( m - > running_as ! = MANAGER_SYSTEM ) {
dbus_bus_add_match ( m - > system_bus ,
" type='signal', "
" interface='org.freedesktop.systemd1.Agent', "
" member='Released', "
" path='/org/freedesktop/systemd1/agent' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to register match: %s " , error . message ) ;
r = - EIO ;
goto fail ;
}
2010-02-01 05:33:24 +03:00
}
2010-07-11 02:51:28 +04:00
if ( m - > api_bus ! = m - > system_bus ) {
char * id ;
2010-08-12 03:02:19 +04:00
log_debug ( " Successfully connected to system D-Bus bus %s as %s " ,
2010-07-11 02:51:28 +04:00
strnull ( ( id = dbus_connection_get_server_id ( m - > system_bus ) ) ) ,
strnull ( dbus_bus_get_unique_name ( m - > system_bus ) ) ) ;
dbus_free ( id ) ;
}
2010-04-06 18:32:07 +04:00
return 0 ;
2010-06-19 05:04:04 +04:00
fail :
bus_done_system ( m ) ;
dbus_error_free ( & error ) ;
return r ;
2010-04-06 18:32:07 +04:00
}
2010-06-19 05:04:04 +04:00
static int bus_init_api ( Manager * m ) {
2010-04-06 18:32:07 +04:00
DBusError error ;
int r ;
assert ( m ) ;
dbus_error_init ( & error ) ;
if ( m - > api_bus )
return 0 ;
2010-06-19 05:15:59 +04:00
if ( m - > running_as = = MANAGER_SYSTEM & & m - > system_bus )
2010-04-06 18:32:07 +04:00
m - > api_bus = m - > system_bus ;
else {
2010-11-16 00:12:41 +03:00
if ( ! ( m - > api_bus = dbus_bus_get_private ( m - > running_as = = MANAGER_USER ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM , & error ) ) ) {
2010-04-07 05:16:50 +04:00
log_debug ( " Failed to get API D-Bus connection, retrying later: %s " , error . message ) ;
2010-06-19 05:04:04 +04:00
r = 0 ;
goto fail ;
2010-04-06 18:32:07 +04:00
}
2010-06-19 05:04:04 +04:00
if ( ( r = bus_setup_loop ( m , m - > api_bus ) ) < 0 )
goto fail ;
2010-02-01 05:33:24 +03:00
}
2010-04-06 18:32:07 +04:00
if ( ! dbus_connection_register_object_path ( m - > api_bus , " /org/freedesktop/systemd1 " , & bus_manager_vtable , m ) | |
! dbus_connection_register_fallback ( m - > api_bus , " /org/freedesktop/systemd1/unit " , & bus_unit_vtable , m ) | |
! dbus_connection_register_fallback ( m - > api_bus , " /org/freedesktop/systemd1/job " , & bus_job_vtable , m ) | |
! dbus_connection_add_filter ( m - > api_bus , api_bus_message_filter , m , NULL ) ) {
2010-06-19 05:04:04 +04:00
log_error ( " Not enough memory " ) ;
r = - ENOMEM ;
goto fail ;
2010-04-06 18:32:07 +04:00
}
2010-06-02 06:24:16 +04:00
/* Get NameOwnerChange messages */
2010-04-06 18:32:07 +04:00
dbus_bus_add_match ( m - > api_bus ,
2010-03-31 18:29:55 +04:00
" type='signal', "
2010-04-06 18:32:07 +04:00
" sender=' " DBUS_SERVICE_DBUS " ', "
" interface=' " DBUS_INTERFACE_DBUS " ', "
2010-06-15 06:24:16 +04:00
" member='NameOwnerChanged', "
2010-04-06 18:32:07 +04:00
" path=' " DBUS_PATH_DBUS " ' " ,
2010-03-31 18:29:55 +04:00
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to register match: %s " , error . message ) ;
2010-06-19 05:04:04 +04:00
r = - EIO ;
goto fail ;
2010-03-31 18:29:55 +04:00
}
2010-06-02 06:24:16 +04:00
/* Get activation requests */
dbus_bus_add_match ( m - > api_bus ,
" type='signal', "
" sender=' " DBUS_SERVICE_DBUS " ', "
" interface='org.freedesktop.systemd1.Activator', "
2010-06-15 04:46:07 +04:00
" member='ActivationRequest', "
2010-06-02 06:24:16 +04:00
" path=' " DBUS_PATH_DBUS " ' " ,
& error ) ;
if ( dbus_error_is_set ( & error ) ) {
log_error ( " Failed to register match: %s " , error . message ) ;
2010-06-19 05:04:04 +04:00
r = - EIO ;
goto fail ;
2010-06-02 06:24:16 +04:00
}
2010-06-19 05:04:04 +04:00
if ( ( r = request_name ( m ) ) < 0 )
goto fail ;
2010-02-01 05:33:24 +03:00
2010-06-19 05:04:04 +04:00
if ( ( r = query_name_list ( m ) ) < 0 )
goto fail ;
2010-06-05 00:03:22 +04:00
2010-07-11 02:51:28 +04:00
if ( m - > api_bus ! = m - > system_bus ) {
char * id ;
2010-08-12 03:02:19 +04:00
log_debug ( " Successfully connected to API D-Bus bus %s as %s " ,
2010-07-11 02:51:28 +04:00
strnull ( ( id = dbus_connection_get_server_id ( m - > api_bus ) ) ) ,
strnull ( dbus_bus_get_unique_name ( m - > api_bus ) ) ) ;
dbus_free ( id ) ;
}
2010-03-31 18:29:55 +04:00
2010-06-19 05:04:04 +04:00
return 0 ;
fail :
bus_done_api ( m ) ;
dbus_error_free ( & error ) ;
return r ;
}
static int bus_init_private ( Manager * m ) {
DBusError error ;
int r ;
const char * const external_only [ ] = {
" EXTERNAL " ,
NULL
} ;
assert ( m ) ;
dbus_error_init ( & error ) ;
if ( m - > private_bus )
return 0 ;
/* We want the private bus only when running as init */
2010-07-10 01:18:50 +04:00
if ( getpid ( ) ! = 1 )
2010-06-19 05:04:04 +04:00
return 0 ;
2011-03-25 07:07:20 +03:00
unlink ( " /run/systemd/private " ) ;
if ( ! ( m - > private_bus = dbus_server_listen ( " unix:path=/run/systemd/private " , & error ) ) ) {
2010-06-19 05:04:04 +04:00
log_error ( " Failed to create private D-Bus server: %s " , error . message ) ;
r = - EIO ;
goto fail ;
}
if ( ! dbus_server_set_auth_mechanisms ( m - > private_bus , ( const char * * ) external_only ) | |
! dbus_server_set_watch_functions ( m - > private_bus , bus_add_watch , bus_remove_watch , bus_toggle_watch , m , NULL ) | |
! dbus_server_set_timeout_functions ( m - > private_bus , bus_add_timeout , bus_remove_timeout , bus_toggle_timeout , m , NULL ) ) {
log_error ( " Not enough memory " ) ;
r = - ENOMEM ;
goto fail ;
}
dbus_server_set_new_connection_function ( m - > private_bus , bus_new_connection , m , NULL ) ;
2010-07-07 19:57:54 +04:00
log_debug ( " Successfully created private D-Bus server. " ) ;
2010-06-19 05:04:04 +04:00
return 0 ;
fail :
bus_done_private ( m ) ;
dbus_error_free ( & error ) ;
return r ;
}
2011-01-20 21:43:38 +03:00
int bus_init ( Manager * m , bool try_bus_connect ) {
2010-06-19 05:04:04 +04:00
int r ;
if ( set_ensure_allocated ( & m - > bus_connections , trivial_hash_func , trivial_compare_func ) < 0 | |
set_ensure_allocated ( & m - > bus_connections_for_dispatch , trivial_hash_func , trivial_compare_func ) < 0 ) {
log_error ( " Not enough memory " ) ;
return - ENOMEM ;
}
if ( m - > name_data_slot < 0 )
if ( ! dbus_pending_call_allocate_data_slot ( & m - > name_data_slot ) ) {
log_error ( " Not enough memory " ) ;
2010-04-06 18:32:07 +04:00
return - ENOMEM ;
2010-06-19 05:04:04 +04:00
}
2010-07-05 02:58:07 +04:00
if ( m - > subscribed_data_slot < 0 )
2010-11-25 03:37:21 +03:00
if ( ! dbus_connection_allocate_data_slot ( & m - > subscribed_data_slot ) ) {
2010-07-05 02:58:07 +04:00
log_error ( " Not enough memory " ) ;
return - ENOMEM ;
}
2011-01-20 21:43:38 +03:00
if ( try_bus_connect ) {
if ( ( r = bus_init_system ( m ) ) < 0 | |
( r = bus_init_api ( m ) ) < 0 )
return r ;
}
if ( ( r = bus_init_private ( m ) ) < 0 )
2010-06-19 05:04:04 +04:00
return r ;
2010-04-06 18:32:07 +04:00
2010-02-01 05:33:24 +03:00
return 0 ;
}
2010-07-04 23:17:40 +04:00
static void shutdown_connection ( Manager * m , DBusConnection * c ) {
2010-07-05 02:58:07 +04:00
Set * s ;
Job * j ;
Iterator i ;
HASHMAP_FOREACH ( j , m - > jobs , i )
if ( j - > bus = = c ) {
free ( j - > bus_client ) ;
j - > bus_client = NULL ;
j - > bus = NULL ;
}
2010-07-04 23:17:40 +04:00
set_remove ( m - > bus_connections , c ) ;
set_remove ( m - > bus_connections_for_dispatch , c ) ;
2010-07-05 02:58:07 +04:00
if ( ( s = BUS_CONNECTION_SUBSCRIBED ( m , c ) ) ) {
char * t ;
while ( ( t = set_steal_first ( s ) ) )
free ( t ) ;
set_free ( s ) ;
}
2010-07-07 04:21:16 +04:00
if ( m - > queued_message_connection = = c ) {
m - > queued_message_connection = NULL ;
if ( m - > queued_message ) {
dbus_message_unref ( m - > queued_message ) ;
m - > queued_message = NULL ;
}
}
2010-06-19 05:04:04 +04:00
dbus_connection_set_dispatch_status_function ( c , NULL , NULL , NULL ) ;
dbus_connection_flush ( c ) ;
dbus_connection_close ( c ) ;
dbus_connection_unref ( c ) ;
}
static void bus_done_api ( Manager * m ) {
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2010-04-06 18:32:07 +04:00
if ( m - > api_bus ) {
if ( m - > system_bus = = m - > api_bus )
m - > system_bus = NULL ;
2010-07-04 23:17:40 +04:00
shutdown_connection ( m , m - > api_bus ) ;
2010-04-06 18:32:07 +04:00
m - > api_bus = NULL ;
2010-02-01 05:33:24 +03:00
}
2010-02-05 02:38:41 +03:00
2010-04-16 01:16:16 +04:00
2010-04-21 05:27:44 +04:00
if ( m - > queued_message ) {
dbus_message_unref ( m - > queued_message ) ;
m - > queued_message = NULL ;
}
2010-02-01 05:33:24 +03:00
}
2010-06-19 05:04:04 +04:00
static void bus_done_system ( Manager * m ) {
2010-04-06 18:32:07 +04:00
assert ( m ) ;
if ( m - > system_bus = = m - > api_bus )
bus_done_api ( m ) ;
if ( m - > system_bus ) {
2010-07-04 23:17:40 +04:00
shutdown_connection ( m , m - > system_bus ) ;
2010-04-06 18:32:07 +04:00
m - > system_bus = NULL ;
}
}
2010-06-19 05:04:04 +04:00
static void bus_done_private ( Manager * m ) {
if ( m - > private_bus ) {
dbus_server_disconnect ( m - > private_bus ) ;
dbus_server_unref ( m - > private_bus ) ;
m - > private_bus = NULL ;
}
}
void bus_done ( Manager * m ) {
DBusConnection * c ;
bus_done_api ( m ) ;
bus_done_system ( m ) ;
bus_done_private ( m ) ;
while ( ( c = set_steal_first ( m - > bus_connections ) ) )
2010-07-04 23:17:40 +04:00
shutdown_connection ( m , c ) ;
2010-06-19 05:04:04 +04:00
while ( ( c = set_steal_first ( m - > bus_connections_for_dispatch ) ) )
2010-07-04 23:17:40 +04:00
shutdown_connection ( m , c ) ;
2010-06-19 05:04:04 +04:00
set_free ( m - > bus_connections ) ;
set_free ( m - > bus_connections_for_dispatch ) ;
if ( m - > name_data_slot > = 0 )
dbus_pending_call_free_data_slot ( & m - > name_data_slot ) ;
2010-07-05 02:58:07 +04:00
if ( m - > subscribed_data_slot > = 0 )
2010-11-25 03:37:21 +03:00
dbus_connection_free_data_slot ( & m - > subscribed_data_slot ) ;
2010-06-19 05:04:04 +04:00
}
2010-04-16 01:16:16 +04:00
static void query_pid_pending_cb ( DBusPendingCall * pending , void * userdata ) {
Manager * m = userdata ;
DBusMessage * reply ;
DBusError error ;
const char * name ;
dbus_error_init ( & error ) ;
2010-07-05 02:58:07 +04:00
assert_se ( name = BUS_PENDING_CALL_NAME ( m , pending ) ) ;
2010-04-16 01:16:16 +04:00
assert_se ( reply = dbus_pending_call_steal_reply ( pending ) ) ;
switch ( dbus_message_get_type ( reply ) ) {
case DBUS_MESSAGE_TYPE_ERROR :
assert_se ( dbus_set_error_from_message ( & error , reply ) ) ;
log_warning ( " GetConnectionUnixProcessID() failed: %s " , error . message ) ;
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN : {
uint32_t r ;
if ( ! dbus_message_get_args ( reply ,
& error ,
DBUS_TYPE_UINT32 , & r ,
DBUS_TYPE_INVALID ) ) {
log_error ( " Failed to parse GetConnectionUnixProcessID() reply: %s " , error . message ) ;
break ;
}
manager_dispatch_bus_query_pid_done ( m , name , ( pid_t ) r ) ;
break ;
}
default :
assert_not_reached ( " Invalid reply message " ) ;
}
dbus_message_unref ( reply ) ;
dbus_error_free ( & error ) ;
}
int bus_query_pid ( Manager * m , const char * name ) {
DBusMessage * message = NULL ;
DBusPendingCall * pending = NULL ;
char * n = NULL ;
assert ( m ) ;
assert ( name ) ;
if ( ! ( message = dbus_message_new_method_call (
DBUS_SERVICE_DBUS ,
DBUS_PATH_DBUS ,
DBUS_INTERFACE_DBUS ,
" GetConnectionUnixProcessID " ) ) )
goto oom ;
if ( ! ( dbus_message_append_args (
message ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_INVALID ) ) )
goto oom ;
if ( ! dbus_connection_send_with_reply ( m - > api_bus , message , & pending , - 1 ) )
goto oom ;
if ( ! ( n = strdup ( name ) ) )
goto oom ;
if ( ! dbus_pending_call_set_data ( pending , m - > name_data_slot , n , free ) )
goto oom ;
n = NULL ;
if ( ! dbus_pending_call_set_notify ( pending , query_pid_pending_cb , m , NULL ) )
goto oom ;
dbus_message_unref ( message ) ;
dbus_pending_call_unref ( pending ) ;
return 0 ;
oom :
free ( n ) ;
if ( pending ) {
dbus_pending_call_cancel ( pending ) ;
dbus_pending_call_unref ( pending ) ;
}
if ( message )
dbus_message_unref ( message ) ;
return - ENOMEM ;
}
2010-06-19 05:04:04 +04:00
int bus_broadcast ( Manager * m , DBusMessage * message ) {
bool oom = false ;
Iterator i ;
DBusConnection * c ;
assert ( m ) ;
assert ( message ) ;
SET_FOREACH ( c , m - > bus_connections_for_dispatch , i )
2010-06-19 05:15:59 +04:00
if ( c ! = m - > system_bus | | m - > running_as = = MANAGER_SYSTEM )
2010-06-19 05:04:04 +04:00
oom = ! dbus_connection_send ( c , message , NULL ) ;
SET_FOREACH ( c , m - > bus_connections , i )
2010-06-19 05:15:59 +04:00
if ( c ! = m - > system_bus | | m - > running_as = = MANAGER_SYSTEM )
2010-06-19 05:04:04 +04:00
oom = ! dbus_connection_send ( c , message , NULL ) ;
return oom ? - ENOMEM : 0 ;
}
2010-05-10 01:53:52 +04:00
int bus_parse_strv ( DBusMessage * m , char * * * _l ) {
DBusMessageIter iter , sub ;
unsigned n = 0 , i = 0 ;
char * * l ;
assert ( m ) ;
assert ( _l ) ;
if ( ! dbus_message_iter_init ( m , & iter ) | |
dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_ARRAY | |
dbus_message_iter_get_element_type ( & iter ) ! = DBUS_TYPE_STRING )
return - EINVAL ;
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
n + + ;
dbus_message_iter_next ( & sub ) ;
}
if ( ! ( l = new ( char * , n + 1 ) ) )
return - ENOMEM ;
assert_se ( dbus_message_iter_init ( m , & iter ) ) ;
dbus_message_iter_recurse ( & iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) ! = DBUS_TYPE_INVALID ) {
const char * s ;
assert_se ( dbus_message_iter_get_arg_type ( & sub ) = = DBUS_TYPE_STRING ) ;
dbus_message_iter_get_basic ( & sub , & s ) ;
if ( ! ( l [ i + + ] = strdup ( s ) ) ) {
strv_free ( l ) ;
return - ENOMEM ;
}
dbus_message_iter_next ( & sub ) ;
}
assert ( i = = n ) ;
l [ i ] = NULL ;
if ( _l )
* _l = l ;
return 0 ;
}
2010-07-05 02:58:07 +04:00
bool bus_has_subscriber ( Manager * m ) {
Iterator i ;
DBusConnection * c ;
assert ( m ) ;
SET_FOREACH ( c , m - > bus_connections_for_dispatch , i )
if ( bus_connection_has_subscriber ( m , c ) )
return true ;
SET_FOREACH ( c , m - > bus_connections , i )
if ( bus_connection_has_subscriber ( m , c ) )
return true ;
return false ;
}
bool bus_connection_has_subscriber ( Manager * m , DBusConnection * c ) {
assert ( m ) ;
assert ( c ) ;
return ! set_isempty ( BUS_CONNECTION_SUBSCRIBED ( m , c ) ) ;
}