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
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
2010-02-03 15:03:47 +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 .
2010-02-03 15:03:47 +03:00
2012-04-12 02:20:58 +04:00
You should have received a copy of the GNU Lesser General Public License
2010-02-03 15:03:47 +03:00
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"
2012-04-10 23:54:31 +04:00
# include "mkdir.h"
2012-09-17 02:21:25 +04:00
# include "missing.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
2011-12-18 17:58:10 +04:00
/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
# define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path= / var / run / dbus / system_bus_socket"
/* Only used as a fallback */
# define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
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
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 ;
2011-05-23 23:36:52 +04:00
dbus_watch_handle ( w - > data . bus_watch , bus_events_to_flags ( events ) ) ;
2010-02-01 05:33:24 +03:00
}
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 ) ;
2011-05-23 23:36:52 +04:00
w = dbus_watch_get_data ( bus_watch ) ;
if ( ! w )
2010-02-01 05:33:24 +03:00
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 ) ;
2011-05-23 23:36:52 +04:00
w = dbus_watch_get_data ( bus_watch ) ;
if ( ! w )
return ;
2010-02-01 05:33:24 +03:00
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 ) ;
2011-05-23 23:36:52 +04:00
w = dbus_timeout_get_data ( timeout ) ;
if ( ! w )
2010-02-01 05:33:24 +03:00
return ;
assert ( w - > type = = WATCH_DBUS_TIMEOUT ) ;
2011-05-23 23:36:52 +04:00
2010-02-01 05:33:24 +03:00
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 ) ;
2011-05-23 23:36:52 +04:00
w = dbus_timeout_get_data ( timeout ) ;
if ( ! w )
return ;
2010-02-01 05:33:24 +03:00
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 ) )
2011-06-28 01:15:30 +04:00
log_error ( " Failed to parse NameOwnerChanged message: %s " , bus_error_message ( & error ) ) ;
2010-02-05 02:38:41 +03:00
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 ) )
2011-06-28 01:15:30 +04:00
log_error ( " Failed to parse ActivationRequest message: %s " , bus_error_message ( & error ) ) ;
2010-06-02 06:24:16 +04:00
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
2012-01-15 15:04:08 +04:00
if ( r > = 0 & & u - > refuse_manual_start )
2010-09-01 05:30:59 +04:00
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 ) )
2011-06-24 22:40:00 +04:00
log_error ( " Failed to parse Released message: %s " , bus_error_message ( & error ) ) ;
2010-03-31 18:29:55 +04:00
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 ) )
2011-06-28 01:15:30 +04:00
log_error ( " Failed to parse Released message: %s " , bus_error_message ( & error ) ) ;
2010-08-06 05:21:50 +04:00
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 ) ) ;
2011-06-28 01:15:30 +04:00
log_warning ( " RequestName() failed: %s " , bus_error_message ( & error ) ) ;
2010-04-05 00:48:47 +04:00
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN : {
uint32_t r ;
if ( ! dbus_message_get_args ( reply ,
& error ,
DBUS_TYPE_UINT32 , & r ,
DBUS_TYPE_INVALID ) ) {
2011-06-28 01:15:30 +04:00
log_error ( " Failed to parse RequestName() reply: %s " , bus_error_message ( & error ) ) ;
2010-04-05 00:48:47 +04:00
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 " ;
2011-04-29 00:07:01 +04:00
/* Allow replacing of our name, to ease implementation of
* reexecution , where we keep the old connection open until
* after the new connection is set up and the name installed
* to allow clients to synchronously wait for reexecution to
* finish */
uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT | DBUS_NAME_FLAG_REPLACE_EXISTING ;
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 ) ) ;
2011-06-28 01:15:30 +04:00
log_warning ( " ListNames() failed: %s " , bus_error_message ( & error ) ) ;
2010-06-05 00:03:22 +04:00
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 ) | |
2012-07-26 01:55:59 +04:00
! dbus_connection_set_timeout_functions ( bus , bus_add_timeout , bus_remove_timeout , bus_toggle_timeout , m , NULL ) )
return log_oom ( ) ;
2010-03-31 18:29:55 +04:00
2012-07-26 01:55:59 +04:00
if ( set_put ( m - > bus_connections_for_dispatch , bus ) < 0 )
return log_oom ( ) ;
2010-06-19 05:04:04 +04:00
dbus_connection_set_dispatch_status_function ( bus , bus_dispatch_status , m , NULL ) ;
2010-03-31 18:29:55 +04:00
return 0 ;
}
2011-07-02 00:34:37 +04:00
static dbus_bool_t allow_only_same_user ( DBusConnection * connection , unsigned long uid , void * data ) {
return uid = = 0 | | uid = = geteuid ( ) ;
2010-06-19 05:04:04 +04:00
}
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 ;
}
2011-07-02 00:34:37 +04:00
dbus_connection_set_unix_user_function ( new_connection , allow_only_same_user , NULL , NULL ) ;
2010-06-19 05:04:04 +04:00
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 ) ) {
2012-07-26 01:55:59 +04:00
log_oom ( ) ;
2010-06-19 05:04:04 +04:00
return ;
}
log_debug ( " Accepted connection on private bus. " ) ;
dbus_connection_ref ( new_connection ) ;
}
2011-12-18 17:58:10 +04:00
static int init_registered_system_bus ( Manager * m ) {
char * id ;
2010-04-06 18:32:07 +04:00
2012-07-26 01:55:59 +04:00
if ( ! dbus_connection_add_filter ( m - > system_bus , system_bus_message_filter , m , NULL ) )
return log_oom ( ) ;
2010-02-05 02:38:41 +03:00
2010-09-03 03:45:14 +04:00
if ( m - > running_as ! = MANAGER_SYSTEM ) {
2011-12-18 17:58:10 +04:00
DBusError error ;
dbus_error_init ( & error ) ;
2010-09-03 03:45:14 +04:00
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 ) ) {
2011-06-28 01:15:30 +04:00
log_error ( " Failed to register match: %s " , bus_error_message ( & error ) ) ;
2011-12-18 17:58:10 +04:00
dbus_error_free ( & error ) ;
return - 1 ;
2010-09-03 03:45:14 +04:00
}
2010-02-01 05:33:24 +03:00
}
2011-12-18 17:58:10 +04:00
log_debug ( " Successfully connected to system D-Bus bus %s as %s " ,
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 ;
}
2011-12-18 17:58:10 +04:00
static int init_registered_api_bus ( Manager * m ) {
2010-04-06 18:32:07 +04:00
int r ;
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 ) | |
2012-07-26 01:55:59 +04:00
! dbus_connection_add_filter ( m - > api_bus , api_bus_message_filter , m , NULL ) )
return log_oom ( ) ;
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 " ' " ,
2011-12-18 17:58:10 +04:00
NULL ) ;
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 " ' " ,
2011-12-18 17:58:10 +04:00
NULL ) ;
2010-06-02 06:24:16 +04:00
2011-12-18 17:58:10 +04:00
r = request_name ( m ) ;
if ( r < 0 )
return r ;
2010-02-01 05:33:24 +03:00
2011-12-18 17:58:10 +04:00
r = query_name_list ( m ) ;
if ( r < 0 )
return r ;
2010-06-05 00:03:22 +04:00
2011-12-18 17:58:10 +04:00
if ( m - > running_as = = MANAGER_USER ) {
2010-07-11 02:51:28 +04:00
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 ) ;
2011-12-18 17:58:10 +04:00
} else
log_debug ( " Successfully initialized API on the system bus " ) ;
return 0 ;
}
static void bus_register_cb ( DBusPendingCall * pending , void * userdata ) {
Manager * m = userdata ;
DBusConnection * * conn ;
DBusMessage * reply ;
DBusError error ;
const char * name ;
int r = 0 ;
dbus_error_init ( & error ) ;
conn = dbus_pending_call_get_data ( pending , m - > conn_data_slot ) ;
assert ( conn = = & m - > system_bus | | conn = = & m - > api_bus ) ;
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 ( " Failed to register to bus: %s " , bus_error_message ( & error ) ) ;
r = - 1 ;
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN :
if ( ! dbus_message_get_args ( reply , & error ,
DBUS_TYPE_STRING , & name ,
DBUS_TYPE_INVALID ) ) {
log_error ( " Failed to parse Hello reply: %s " , bus_error_message ( & error ) ) ;
r = - 1 ;
break ;
}
log_debug ( " Received name %s in reply to Hello " , name ) ;
if ( ! dbus_bus_set_unique_name ( * conn , name ) ) {
log_error ( " Failed to set unique name " ) ;
r = - 1 ;
break ;
}
if ( conn = = & m - > system_bus ) {
r = init_registered_system_bus ( m ) ;
if ( r = = 0 & & m - > running_as = = MANAGER_SYSTEM )
r = init_registered_api_bus ( m ) ;
} else
r = init_registered_api_bus ( m ) ;
break ;
default :
assert_not_reached ( " Invalid reply message " ) ;
}
dbus_message_unref ( reply ) ;
dbus_error_free ( & error ) ;
if ( r < 0 ) {
if ( conn = = & m - > system_bus ) {
log_debug ( " Failed setting up the system bus " ) ;
bus_done_system ( m ) ;
} else {
log_debug ( " Failed setting up the API bus " ) ;
bus_done_api ( m ) ;
}
}
}
static int manager_bus_async_register ( Manager * m , DBusConnection * * conn ) {
DBusMessage * message = NULL ;
DBusPendingCall * pending = NULL ;
message = dbus_message_new_method_call ( DBUS_SERVICE_DBUS ,
DBUS_PATH_DBUS ,
DBUS_INTERFACE_DBUS ,
" Hello " ) ;
if ( ! message )
goto oom ;
if ( ! dbus_connection_send_with_reply ( * conn , message , & pending , - 1 ) )
goto oom ;
if ( ! dbus_pending_call_set_data ( pending , m - > conn_data_slot , conn , NULL ) )
goto oom ;
if ( ! dbus_pending_call_set_notify ( pending , bus_register_cb , m , NULL ) )
goto oom ;
dbus_message_unref ( message ) ;
dbus_pending_call_unref ( pending ) ;
return 0 ;
oom :
if ( pending ) {
dbus_pending_call_cancel ( pending ) ;
dbus_pending_call_unref ( pending ) ;
}
if ( message )
dbus_message_unref ( message ) ;
return - ENOMEM ;
}
static DBusConnection * manager_bus_connect_private ( Manager * m , DBusBusType type ) {
const char * address ;
DBusConnection * connection ;
DBusError error ;
switch ( type ) {
case DBUS_BUS_SYSTEM :
2012-09-17 02:21:25 +04:00
address = secure_getenv ( " DBUS_SYSTEM_BUS_ADDRESS " ) ;
2011-12-18 17:58:10 +04:00
if ( ! address | | ! address [ 0 ] )
address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS ;
break ;
case DBUS_BUS_SESSION :
2012-09-17 02:21:25 +04:00
address = secure_getenv ( " DBUS_SESSION_BUS_ADDRESS " ) ;
2011-12-18 17:58:10 +04:00
if ( ! address | | ! address [ 0 ] )
address = DBUS_SESSION_BUS_DEFAULT_ADDRESS ;
break ;
default :
assert_not_reached ( " Invalid bus type " ) ;
}
dbus_error_init ( & error ) ;
connection = dbus_connection_open_private ( address , & error ) ;
if ( ! connection ) {
log_warning ( " Failed to open private bus connection: %s " , bus_error_message ( & error ) ) ;
goto fail ;
}
return connection ;
fail :
if ( connection )
dbus_connection_close ( connection ) ;
dbus_error_free ( & error ) ;
return NULL ;
}
static int bus_init_system ( Manager * m ) {
int r ;
if ( m - > system_bus )
return 0 ;
m - > system_bus = manager_bus_connect_private ( m , DBUS_BUS_SYSTEM ) ;
if ( ! m - > system_bus ) {
log_debug ( " Failed to connect to system D-Bus, retrying later " ) ;
r = 0 ;
goto fail ;
2010-07-11 02:51:28 +04:00
}
2010-03-31 18:29:55 +04:00
2011-12-18 17:58:10 +04:00
r = bus_setup_loop ( m , m - > system_bus ) ;
if ( r < 0 )
goto fail ;
r = manager_bus_async_register ( m , & m - > system_bus ) ;
if ( r < 0 )
goto fail ;
2010-06-19 05:04:04 +04:00
return 0 ;
2011-12-18 17:58:10 +04:00
fail :
bus_done_system ( m ) ;
return r ;
}
static int bus_init_api ( Manager * m ) {
int r ;
if ( m - > api_bus )
return 0 ;
if ( m - > running_as = = MANAGER_SYSTEM ) {
m - > api_bus = m - > system_bus ;
/* In this mode there is no distinct connection to the API bus,
* the API is published on the system bus .
* bus_register_cb ( ) is aware of that and will init the API
* when the system bus gets registered .
* No need to setup anything here . */
return 0 ;
}
m - > api_bus = manager_bus_connect_private ( m , DBUS_BUS_SESSION ) ;
if ( ! m - > api_bus ) {
log_debug ( " Failed to connect to API D-Bus, retrying later " ) ;
r = 0 ;
goto fail ;
}
r = bus_setup_loop ( m , m - > api_bus ) ;
if ( r < 0 )
goto fail ;
2010-06-19 05:04:04 +04:00
2011-12-18 17:58:10 +04:00
r = manager_bus_async_register ( m , & m - > api_bus ) ;
if ( r < 0 )
goto fail ;
return 0 ;
2010-06-19 05:04:04 +04:00
fail :
bus_done_api ( m ) ;
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 ;
2011-07-02 00:34:37 +04:00
if ( m - > running_as = = MANAGER_SYSTEM ) {
/* We want the private bus only when running as init */
if ( getpid ( ) ! = 1 )
return 0 ;
unlink ( " /run/systemd/private " ) ;
m - > private_bus = dbus_server_listen ( " unix:path=/run/systemd/private " , & error ) ;
} else {
const char * e ;
char * p ;
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " XDG_RUNTIME_DIR " ) ;
2011-07-02 00:34:37 +04:00
if ( ! e )
return 0 ;
if ( asprintf ( & p , " unix:path=%s/systemd/private " , e ) < 0 ) {
2012-07-26 01:55:59 +04:00
r = log_oom ( ) ;
2011-07-02 00:34:37 +04:00
goto fail ;
}
2012-05-31 14:40:20 +04:00
mkdir_parents_label ( p + 10 , 0755 ) ;
2011-07-02 00:34:37 +04:00
unlink ( p + 10 ) ;
m - > private_bus = dbus_server_listen ( p , & error ) ;
free ( p ) ;
}
2010-06-19 05:04:04 +04:00
2011-07-02 00:34:37 +04:00
if ( ! m - > private_bus ) {
2011-06-28 01:15:30 +04:00
log_error ( " Failed to create private D-Bus server: %s " , bus_error_message ( & error ) ) ;
2010-06-19 05:04:04 +04:00
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 ) ) {
2012-07-26 01:55:59 +04:00
r = log_oom ( ) ;
2010-06-19 05:04:04 +04:00
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 | |
2011-12-18 17:58:10 +04:00
set_ensure_allocated ( & m - > bus_connections_for_dispatch , trivial_hash_func , trivial_compare_func ) < 0 )
goto oom ;
2010-06-19 05:04:04 +04:00
if ( m - > name_data_slot < 0 )
2011-12-18 17:58:10 +04:00
if ( ! dbus_pending_call_allocate_data_slot ( & m - > name_data_slot ) )
goto oom ;
if ( m - > conn_data_slot < 0 )
if ( ! dbus_pending_call_allocate_data_slot ( & m - > conn_data_slot ) )
goto oom ;
2010-06-19 05:04:04 +04:00
2010-07-05 02:58:07 +04:00
if ( m - > subscribed_data_slot < 0 )
2011-12-18 17:58:10 +04:00
if ( ! dbus_connection_allocate_data_slot ( & m - > subscribed_data_slot ) )
goto oom ;
2010-07-05 02:58:07 +04:00
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 ;
2011-12-18 17:58:10 +04:00
oom :
2012-07-26 01:55:59 +04:00
return log_oom ( ) ;
2010-02-01 05:33:24 +03:00
}
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 ;
2012-04-20 14:28:31 +04:00
HASHMAP_FOREACH ( j , m - > jobs , i ) {
JobBusClient * cl , * nextcl ;
LIST_FOREACH_SAFE ( client , cl , nextcl , j - > bus_client_list ) {
if ( cl - > bus = = c ) {
LIST_REMOVE ( JobBusClient , client , j - > bus_client_list , cl ) ;
free ( cl ) ;
}
2010-07-05 02:58:07 +04:00
}
2012-04-20 14:28:31 +04:00
}
2010-07-05 02:58:07 +04:00
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 ) ;
2011-12-19 21:32:10 +04:00
/* system manager cannot afford to block on DBus */
if ( m - > running_as ! = MANAGER_SYSTEM )
dbus_connection_flush ( c ) ;
2010-06-19 05:04:04 +04:00
dbus_connection_close ( c ) ;
dbus_connection_unref ( c ) ;
}
static void bus_done_api ( Manager * m ) {
2011-12-18 17:58:10 +04:00
if ( ! m - > api_bus )
return ;
2010-04-06 18:32:07 +04:00
2011-12-18 17:58:10 +04:00
if ( m - > running_as = = MANAGER_USER )
2010-07-04 23:17:40 +04:00
shutdown_connection ( m , m - > api_bus ) ;
2010-02-05 02:38:41 +03:00
2011-12-18 17:58:10 +04:00
m - > api_bus = NULL ;
2010-04-16 01:16:16 +04:00
2011-12-18 17:58:10 +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 ) {
2011-12-18 17:58:10 +04:00
if ( ! m - > system_bus )
return ;
2010-04-06 18:32:07 +04:00
2011-12-18 17:58:10 +04:00
if ( m - > running_as = = MANAGER_SYSTEM )
2010-04-06 18:32:07 +04:00
bus_done_api ( m ) ;
2011-12-18 17:58:10 +04:00
shutdown_connection ( m , m - > system_bus ) ;
m - > system_bus = NULL ;
2010-04-06 18:32:07 +04:00
}
2010-06-19 05:04:04 +04:00
static void bus_done_private ( Manager * m ) {
2011-12-18 17:58:10 +04:00
if ( ! m - > private_bus )
return ;
2010-06-19 05:04:04 +04:00
2011-12-18 17:58:10 +04:00
dbus_server_disconnect ( m - > private_bus ) ;
dbus_server_unref ( m - > private_bus ) ;
m - > private_bus = NULL ;
2010-06-19 05:04:04 +04:00
}
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
2011-12-18 17:58:10 +04:00
if ( m - > conn_data_slot > = 0 )
dbus_pending_call_free_data_slot ( & m - > conn_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 ) ) ;
2011-06-28 01:15:30 +04:00
log_warning ( " GetConnectionUnixProcessID() failed: %s " , bus_error_message ( & error ) ) ;
2010-04-16 01:16:16 +04:00
break ;
case DBUS_MESSAGE_TYPE_METHOD_RETURN : {
uint32_t r ;
if ( ! dbus_message_get_args ( reply ,
& error ,
DBUS_TYPE_UINT32 , & r ,
DBUS_TYPE_INVALID ) ) {
2011-06-28 01:15:30 +04:00
log_error ( " Failed to parse GetConnectionUnixProcessID() reply: %s " , bus_error_message ( & error ) ) ;
2010-04-16 01:16:16 +04:00
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-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 ) ) ;
}
2011-04-29 00:07:01 +04:00
int bus_fdset_add_all ( Manager * m , FDSet * fds ) {
Iterator i ;
DBusConnection * c ;
assert ( m ) ;
assert ( fds ) ;
/* When we are about to reexecute we add all D-Bus fds to the
* set to pass over to the newly executed systemd . They won ' t
* be used there however , except that they are closed at the
* very end of deserialization , those making it possible for
2011-04-29 01:51:24 +04:00
* clients to synchronously wait for systemd to reexec by
2011-04-29 00:07:01 +04:00
* simply waiting for disconnection */
SET_FOREACH ( c , m - > bus_connections_for_dispatch , i ) {
int fd ;
if ( dbus_connection_get_unix_fd ( c , & fd ) ) {
fd = fdset_put_dup ( fds , fd ) ;
if ( fd < 0 )
return fd ;
}
}
SET_FOREACH ( c , m - > bus_connections , i ) {
int fd ;
if ( dbus_connection_get_unix_fd ( c , & fd ) ) {
fd = fdset_put_dup ( fds , fd ) ;
if ( fd < 0 )
return fd ;
}
}
return 0 ;
}
2011-06-27 15:47:03 +04:00
void bus_broadcast_finished (
Manager * m ,
2012-09-13 20:54:32 +04:00
usec_t firmware_usec ,
usec_t loader_usec ,
2011-06-27 15:47:03 +04:00
usec_t kernel_usec ,
usec_t initrd_usec ,
usec_t userspace_usec ,
usec_t total_usec ) {
DBusMessage * message ;
assert ( m ) ;
message = dbus_message_new_signal ( " /org/freedesktop/systemd1 " , " org.freedesktop.systemd1.Manager " , " StartupFinished " ) ;
if ( ! message ) {
2012-07-26 01:55:59 +04:00
log_oom ( ) ;
2011-06-27 15:47:03 +04:00
return ;
}
assert_cc ( sizeof ( usec_t ) = = sizeof ( uint64_t ) ) ;
if ( ! dbus_message_append_args ( message ,
2012-09-13 20:54:32 +04:00
DBUS_TYPE_UINT64 , & firmware_usec ,
DBUS_TYPE_UINT64 , & loader_usec ,
2011-06-27 15:47:03 +04:00
DBUS_TYPE_UINT64 , & kernel_usec ,
DBUS_TYPE_UINT64 , & initrd_usec ,
DBUS_TYPE_UINT64 , & userspace_usec ,
DBUS_TYPE_UINT64 , & total_usec ,
DBUS_TYPE_INVALID ) ) {
2012-07-26 01:55:59 +04:00
log_oom ( ) ;
2011-06-27 15:47:03 +04:00
goto finish ;
}
if ( bus_broadcast ( m , message ) < 0 ) {
2012-07-26 01:55:59 +04:00
log_oom ( ) ;
2011-06-27 15:47:03 +04:00
goto finish ;
}
finish :
2011-06-28 14:49:52 +04:00
if ( message )
2011-06-27 15:47:03 +04:00
dbus_message_unref ( message ) ;
}