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 <errno.h>
# include <unistd.h>
2013-11-20 00:12:59 +04:00
# include "sd-bus.h"
2010-02-01 05:33:24 +03:00
# include "log.h"
# include "strv.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"
2013-11-20 00:12:59 +04:00
# include "dbus-execute.h"
# include "dbus-kill.h"
# include "dbus-cgroup.h"
2010-09-01 05:30:59 +04:00
# include "special.h"
2013-11-20 00:12:59 +04:00
# include "dbus.h"
# include "bus-util.h"
# include "bus-error.h"
2014-12-10 21:00:46 +03:00
# include "bus-common-errors.h"
2013-11-20 00:12:59 +04:00
# include "strxcpyx.h"
2013-11-22 02:36:51 +04:00
# include "bus-internal.h"
# include "selinux-access.h"
2010-05-23 05:45:33 +04:00
2013-05-03 18:32:41 +04:00
# define CONNECTIONS_MAX 512
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
static void destroy_bus ( Manager * m , sd_bus * * bus ) ;
int bus_send_queued_message ( Manager * m ) {
int r ;
2010-03-31 18:29:55 +04:00
assert ( m ) ;
2010-04-08 06:58:30 +04:00
2013-11-20 00:12:59 +04:00
if ( ! m - > queued_message )
return 0 ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
assert ( m - > queued_message_bus ) ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
/* 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-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
r = sd_bus_send ( m - > queued_message_bus , m - > queued_message , NULL ) ;
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to send queued message: %m " ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
m - > queued_message = sd_bus_message_unref ( m - > queued_message ) ;
m - > queued_message_bus = sd_bus_unref ( m - > queued_message_bus ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2013-11-21 22:34:37 +04:00
static int signal_agent_released ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
const char * cgroup ;
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( message ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
r = sd_bus_message_read ( message , " s " , & cgroup ) ;
if ( r < 0 ) {
bus_log_parse_error ( r ) ;
return 0 ;
}
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
manager_notify_cgroup_empty ( m , cgroup ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
if ( m - > running_as = = SYSTEMD_SYSTEM & & m - > system_bus ) {
/* If we are running as system manager, forward the
* message to the system bus */
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
r = sd_bus_send ( m - > system_bus , message , NULL ) ;
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to forward Released message: %m " ) ;
2013-11-20 00:12:59 +04:00
}
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-02-01 05:33:24 +03:00
2013-11-21 22:34:37 +04:00
static int signal_disconnected ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( message ) ;
assert ( m ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
if ( bus = = m - > api_bus )
destroy_bus ( m , & m - > api_bus ) ;
if ( bus = = m - > system_bus )
destroy_bus ( m , & m - > system_bus ) ;
if ( set_remove ( m - > private_buses , bus ) ) {
log_debug ( " Got disconnect on private connection. " ) ;
destroy_bus ( m , & bus ) ;
2010-02-01 05:33:24 +03:00
}
2013-11-20 00:12:59 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2013-11-21 22:34:37 +04:00
static int signal_name_owner_changed ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
const char * name , * old_owner , * new_owner ;
Manager * m = userdata ;
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( message ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
r = sd_bus_message_read ( message , " sss " , & name , & old_owner , & new_owner ) ;
if ( r < 0 ) {
bus_log_parse_error ( r ) ;
return 0 ;
}
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
manager_dispatch_bus_name_owner_changed (
m , name ,
isempty ( old_owner ) ? NULL : old_owner ,
isempty ( new_owner ) ? NULL : new_owner ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2013-11-21 22:34:37 +04:00
static int signal_activation_request ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * ret_error ) {
2013-11-20 00:12:59 +04:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
_cleanup_bus_message_unref_ sd_bus_message * reply = NULL ;
Manager * m = userdata ;
const char * name ;
Unit * u ;
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( message ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
r = sd_bus_message_read ( message , " s " , & name ) ;
if ( r < 0 ) {
bus_log_parse_error ( r ) ;
return 0 ;
}
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
if ( manager_unit_inactive_or_pending ( m , SPECIAL_DBUS_SERVICE ) | |
manager_unit_inactive_or_pending ( m , SPECIAL_DBUS_SOCKET ) ) {
r = sd_bus_error_setf ( & error , BUS_ERROR_SHUTTING_DOWN , " Refusing activation, D-Bus is shutting down. " ) ;
goto failed ;
}
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
r = manager_load_unit ( m , name , NULL , & error , & u ) ;
if ( r < 0 )
goto failed ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
if ( u - > refuse_manual_start ) {
2013-12-28 18:05:45 +04:00
r = sd_bus_error_setf ( & error , BUS_ERROR_ONLY_BY_DEPENDENCY , " Operation refused, %s may be requested by dependency only. " , u - > id ) ;
2013-11-20 00:12:59 +04:00
goto failed ;
2010-02-01 05:33:24 +03:00
}
2013-11-20 00:12:59 +04:00
r = manager_add_job ( m , JOB_START , u , JOB_REPLACE , true , & error , NULL ) ;
if ( r < 0 )
goto failed ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
/* Successfully queued, that's it for us */
2010-02-01 05:33:24 +03:00
return 0 ;
2013-11-20 00:12:59 +04:00
failed :
if ( ! sd_bus_error_is_set ( & error ) )
sd_bus_error_set_errno ( & error , r ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
log_debug ( " D-Bus activation failed for %s: %s " , name , bus_error_message ( & error , r ) ) ;
2010-02-01 05:33:24 +03:00
2014-02-20 02:54:58 +04:00
r = sd_bus_message_new_signal ( bus , & reply , " /org/freedesktop/systemd1 " , " org.freedesktop.systemd1.Activator " , " ActivationFailure " ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 ) {
bus_log_create_error ( r ) ;
return 0 ;
}
2013-11-21 05:14:05 +04:00
r = sd_bus_message_append ( reply , " sss " , name , error . name , error . message ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 ) {
bus_log_create_error ( r ) ;
return 0 ;
}
r = sd_bus_send_to ( bus , reply , " org.freedesktop.DBus " , NULL ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to respond with to bus activation request: %m " ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2013-12-12 18:58:31 +04:00
# ifdef HAVE_SELINUX
2014-10-24 16:15:25 +04:00
static int mac_selinux_filter ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * error ) {
2013-11-22 02:36:51 +04:00
Manager * m = userdata ;
const char * verb , * path ;
Unit * u = NULL ;
Job * j ;
int r ;
assert ( bus ) ;
assert ( message ) ;
/* Our own method calls are all protected individually with
* selinux checks , but the built - in interfaces need to be
* protected too . */
if ( sd_bus_message_is_method_call ( message , " org.freedesktop.DBus.Properties " , " Set " ) )
verb = " reload " ;
else if ( sd_bus_message_is_method_call ( message , " org.freedesktop.DBus.Introspectable " , NULL ) | |
sd_bus_message_is_method_call ( message , " org.freedesktop.DBus.Properties " , NULL ) | |
sd_bus_message_is_method_call ( message , " org.freedesktop.DBus.ObjectManager " , NULL ) | |
sd_bus_message_is_method_call ( message , " org.freedesktop.DBus.Peer " , NULL ) )
verb = " status " ;
else
return 0 ;
path = sd_bus_message_get_path ( message ) ;
if ( object_path_startswith ( " /org/freedesktop/systemd1 " , path ) ) {
2014-10-24 16:15:25 +04:00
r = mac_selinux_access_check ( message , verb , error ) ;
2013-11-22 02:36:51 +04:00
if ( r < 0 )
return r ;
return 0 ;
}
if ( streq_ptr ( path , " /org/freedesktop/systemd1/unit/self " ) ) {
2013-11-28 20:50:02 +04:00
_cleanup_bus_creds_unref_ sd_bus_creds * creds = NULL ;
2013-11-22 02:36:51 +04:00
pid_t pid ;
2013-11-28 20:50:02 +04:00
r = sd_bus_query_sender_creds ( message , SD_BUS_CREDS_PID , & creds ) ;
if ( r < 0 )
return 0 ;
r = sd_bus_creds_get_pid ( creds , & pid ) ;
2013-11-22 02:36:51 +04:00
if ( r < 0 )
return 0 ;
u = manager_get_unit_by_pid ( m , pid ) ;
} else {
r = manager_get_job_from_dbus_path ( m , path , & j ) ;
if ( r > = 0 )
u = j - > unit ;
else
manager_load_unit_from_dbus_path ( m , path , NULL , & u ) ;
}
if ( ! u )
return 0 ;
2014-10-24 16:15:25 +04:00
r = mac_selinux_unit_access_check ( u , message , verb , error ) ;
2013-11-22 02:36:51 +04:00
if ( r < 0 )
return r ;
return 0 ;
}
2013-12-12 18:58:31 +04:00
# endif
2013-11-22 02:36:51 +04:00
2013-11-22 04:14:57 +04:00
static int bus_job_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
Job * j ;
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
r = manager_get_job_from_dbus_path ( m , path , & j ) ;
if ( r < 0 )
return 0 ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
* found = j ;
return 1 ;
}
2010-02-01 05:33:24 +03:00
2013-11-22 04:14:57 +04:00
static int find_unit ( Manager * m , sd_bus * bus , const char * path , Unit * * unit , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Unit * u ;
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( m ) ;
assert ( bus ) ;
assert ( path ) ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
if ( streq_ptr ( path , " /org/freedesktop/systemd1/unit/self " ) ) {
2013-11-28 20:50:02 +04:00
_cleanup_bus_creds_unref_ sd_bus_creds * creds = NULL ;
2013-11-20 00:12:59 +04:00
sd_bus_message * message ;
pid_t pid ;
2010-02-01 05:33:24 +03:00
2014-05-15 03:15:30 +04:00
message = sd_bus_get_current_message ( bus ) ;
2013-11-20 00:12:59 +04:00
if ( ! message )
2013-11-22 04:14:57 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
2013-11-28 20:50:02 +04:00
r = sd_bus_query_sender_creds ( message , SD_BUS_CREDS_PID , & creds ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 )
2013-11-28 20:50:02 +04:00
return r ;
r = sd_bus_creds_get_pid ( creds , & pid ) ;
if ( r < 0 )
return r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
u = manager_get_unit_by_pid ( m , pid ) ;
} else {
2013-11-22 04:14:57 +04:00
r = manager_load_unit_from_dbus_path ( m , path , error , & u ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 )
2013-11-22 04:14:57 +04:00
return 0 ;
2013-11-20 00:12:59 +04:00
}
2010-02-01 05:33:24 +03:00
2013-11-22 04:14:57 +04:00
if ( ! u )
return 0 ;
* unit = u ;
return 1 ;
2010-02-01 05:33:24 +03:00
}
2013-11-22 04:14:57 +04:00
static int bus_unit_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-22 04:14:57 +04:00
return find_unit ( m , bus , path , ( Unit * * ) found , error ) ;
2010-02-01 05:33:24 +03:00
}
2013-11-22 04:14:57 +04:00
static int bus_unit_interface_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
Unit * u ;
2013-11-22 04:14:57 +04:00
int r ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-22 04:14:57 +04:00
r = find_unit ( m , bus , path , & u , error ) ;
if ( r < = 0 )
return r ;
2011-05-23 23:36:52 +04:00
2013-11-20 00:12:59 +04:00
if ( ! streq_ptr ( interface , UNIT_VTABLE ( u ) - > bus_interface ) )
return 0 ;
2010-02-01 05:33:24 +03:00
2013-11-20 00:12:59 +04:00
* found = u ;
return 1 ;
2010-02-01 05:33:24 +03:00
}
2013-11-22 04:14:57 +04:00
static int bus_unit_cgroup_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
Unit * u ;
2013-11-22 04:14:57 +04:00
int r ;
2010-02-05 02:38:41 +03:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
2010-02-05 02:38:41 +03:00
assert ( m ) ;
2013-11-22 04:14:57 +04:00
r = find_unit ( m , bus , path , & u , error ) ;
if ( r < = 0 )
return r ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
if ( ! streq_ptr ( interface , UNIT_VTABLE ( u ) - > bus_interface ) )
return 0 ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
if ( ! unit_get_cgroup_context ( u ) )
return 0 ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
* found = u ;
return 1 ;
}
2010-06-02 06:24:16 +04:00
2013-11-22 04:14:57 +04:00
static int bus_cgroup_context_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
CGroupContext * c ;
Unit * u ;
2013-11-22 04:14:57 +04:00
int r ;
2010-06-07 06:15:37 +04:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
assert ( m ) ;
2010-06-02 06:24:16 +04:00
2013-11-22 04:14:57 +04:00
r = find_unit ( m , bus , path , & u , error ) ;
if ( r < = 0 )
return r ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
if ( ! streq_ptr ( interface , UNIT_VTABLE ( u ) - > bus_interface ) )
return 0 ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
c = unit_get_cgroup_context ( u ) ;
if ( ! c )
return 0 ;
2010-02-05 02:38:41 +03:00
2013-11-20 00:12:59 +04:00
* found = c ;
return 1 ;
}
2010-06-02 06:24:16 +04:00
2013-11-22 04:14:57 +04:00
static int bus_exec_context_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
ExecContext * c ;
Unit * u ;
2013-11-22 04:14:57 +04:00
int r ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
assert ( m ) ;
2010-06-02 06:24:16 +04:00
2013-11-22 04:14:57 +04:00
r = find_unit ( m , bus , path , & u , error ) ;
if ( r < = 0 )
return r ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
if ( ! streq_ptr ( interface , UNIT_VTABLE ( u ) - > bus_interface ) )
return 0 ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
c = unit_get_exec_context ( u ) ;
if ( ! c )
return 0 ;
2010-06-02 06:24:16 +04:00
2013-11-20 00:12:59 +04:00
* found = c ;
return 1 ;
2010-02-05 02:38:41 +03:00
}
2013-11-22 04:14:57 +04:00
static int bus_kill_context_find ( sd_bus * bus , const char * path , const char * interface , void * userdata , void * * found , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
Manager * m = userdata ;
KillContext * c ;
Unit * u ;
2013-11-22 04:14:57 +04:00
int r ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
assert ( path ) ;
assert ( interface ) ;
assert ( found ) ;
2010-03-31 18:29:55 +04:00
assert ( m ) ;
2013-11-22 04:14:57 +04:00
r = find_unit ( m , bus , path , & u , error ) ;
if ( r < = 0 )
return r ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
if ( ! streq_ptr ( interface , UNIT_VTABLE ( u ) - > bus_interface ) )
return 0 ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
c = unit_get_kill_context ( u ) ;
if ( ! c )
return 0 ;
2010-09-03 03:45:14 +04:00
2013-11-20 00:12:59 +04:00
* found = c ;
return 1 ;
}
2010-03-31 18:29:55 +04:00
2013-11-22 04:14:57 +04:00
static int bus_job_enumerate ( sd_bus * bus , const char * path , void * userdata , char * * * nodes , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
_cleanup_free_ char * * l = NULL ;
Manager * m = userdata ;
unsigned k = 0 ;
Iterator i ;
Job * j ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
l = new0 ( char * , hashmap_size ( m - > jobs ) + 1 ) ;
if ( ! l )
return - ENOMEM ;
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
HASHMAP_FOREACH ( j , m - > jobs , i ) {
l [ k ] = job_dbus_path ( j ) ;
if ( ! l [ k ] )
return - ENOMEM ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
k + + ;
}
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
assert ( hashmap_size ( m - > jobs ) = = k ) ;
2010-08-06 05:21:50 +04:00
2013-11-20 00:12:59 +04:00
* nodes = l ;
l = NULL ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
return k ;
}
2010-09-03 03:45:14 +04:00
2013-11-22 04:14:57 +04:00
static int bus_unit_enumerate ( sd_bus * bus , const char * path , void * userdata , char * * * nodes , sd_bus_error * error ) {
2013-11-20 00:12:59 +04:00
_cleanup_free_ char * * l = NULL ;
Manager * m = userdata ;
unsigned k = 0 ;
Iterator i ;
Unit * u ;
2010-08-06 05:21:50 +04:00
2013-11-20 00:12:59 +04:00
l = new0 ( char * , hashmap_size ( m - > units ) + 1 ) ;
if ( ! l )
return - ENOMEM ;
2010-09-03 03:45:14 +04:00
2013-11-20 00:12:59 +04:00
HASHMAP_FOREACH ( u , m - > units , i ) {
l [ k ] = unit_dbus_path ( u ) ;
if ( ! l [ k ] )
return - ENOMEM ;
2010-09-03 03:45:14 +04:00
2013-11-20 00:12:59 +04:00
k + + ;
2010-08-06 05:21:50 +04:00
}
2013-11-20 00:12:59 +04:00
* nodes = l ;
l = NULL ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
return k ;
2010-06-19 05:04:04 +04:00
}
2013-11-20 00:12:59 +04:00
static int bus_setup_api_vtables ( Manager * m , sd_bus * bus ) {
UnitType t ;
int r ;
2010-06-19 05:04:04 +04:00
2010-02-01 05:33:24 +03:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
2010-02-01 05:33:24 +03:00
2013-12-12 18:58:31 +04:00
# ifdef HAVE_SELINUX
2014-10-24 16:15:25 +04:00
r = sd_bus_add_filter ( bus , NULL , mac_selinux_filter , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add SELinux access filter: %m " ) ;
2013-12-12 18:58:31 +04:00
# endif
2013-11-22 02:36:51 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_object_vtable ( bus , NULL , " /org/freedesktop/systemd1 " , " org.freedesktop.systemd1.Manager " , bus_manager_vtable , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register Manager vtable: %m " ) ;
2010-04-21 05:27:44 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/job " , " org.freedesktop.systemd1.Job " , bus_job_vtable , bus_job_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register Job vtable: %m " ) ;
2010-02-05 02:38:41 +03:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_node_enumerator ( bus , NULL , " /org/freedesktop/systemd1/job " , bus_job_enumerate , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add job enumerator: %m " ) ;
2010-04-05 00:48:47 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , " org.freedesktop.systemd1.Unit " , bus_unit_vtable , bus_unit_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register Unit vtable: %m " ) ;
2010-04-05 00:48:47 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_node_enumerator ( bus , NULL , " /org/freedesktop/systemd1/unit " , bus_unit_enumerate , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add job enumerator: %m " ) ;
2010-04-05 00:48:47 +04:00
2013-11-20 00:12:59 +04:00
for ( t = 0 ; t < _UNIT_TYPE_MAX ; t + + ) {
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , unit_vtable [ t ] - > bus_interface , unit_vtable [ t ] - > bus_vtable , bus_unit_interface_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register type specific vtable for %s: %m " , unit_vtable [ t ] - > bus_interface ) ;
2010-04-05 00:48:47 +04:00
2013-11-20 00:12:59 +04:00
if ( unit_vtable [ t ] - > cgroup_context_offset > 0 ) {
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , unit_vtable [ t ] - > bus_interface , bus_unit_cgroup_vtable , bus_unit_cgroup_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register control group unit vtable for %s: %m " , unit_vtable [ t ] - > bus_interface ) ;
2010-04-05 00:48:47 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , unit_vtable [ t ] - > bus_interface , bus_cgroup_vtable , bus_cgroup_context_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register control group vtable for %s: %m " , unit_vtable [ t ] - > bus_interface ) ;
2010-04-05 00:48:47 +04:00
}
2013-11-20 00:12:59 +04:00
if ( unit_vtable [ t ] - > exec_context_offset > 0 ) {
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , unit_vtable [ t ] - > bus_interface , bus_exec_vtable , bus_exec_context_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register execute vtable for %s: %m " , unit_vtable [ t ] - > bus_interface ) ;
2013-11-20 00:12:59 +04:00
}
2010-04-05 00:48:47 +04:00
2013-11-20 00:12:59 +04:00
if ( unit_vtable [ t ] - > kill_context_offset > 0 ) {
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( bus , NULL , " /org/freedesktop/systemd1/unit " , unit_vtable [ t ] - > bus_interface , bus_kill_vtable , bus_kill_context_find , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register kill vtable for %s: %m " , unit_vtable [ t ] - > bus_interface ) ;
2013-11-20 00:12:59 +04:00
}
2010-04-05 00:48:47 +04:00
}
2013-11-20 00:12:59 +04:00
return 0 ;
2010-04-05 00:48:47 +04:00
}
2013-11-20 00:12:59 +04:00
static int bus_setup_disconnected_match ( Manager * m , sd_bus * bus ) {
int r ;
2010-04-05 00:48:47 +04:00
2013-11-20 00:12:59 +04:00
assert ( m ) ;
assert ( bus ) ;
2010-04-05 00:48:47 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_add_match (
bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-12-21 05:40:40 +04:00
" sender='org.freedesktop.DBus.Local', "
2013-11-20 00:12:59 +04:00
" type='signal', "
" path='/org/freedesktop/DBus/Local', "
" interface='org.freedesktop.DBus.Local', "
" member='Disconnected' " ,
signal_disconnected , m ) ;
2010-04-16 01:16:16 +04:00
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register match for Disconnected message: %m " ) ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-02-01 05:33:24 +03:00
}
2013-11-20 00:12:59 +04:00
static int bus_on_connection ( sd_event_source * s , int fd , uint32_t revents , void * userdata ) {
_cleanup_bus_unref_ sd_bus * bus = NULL ;
_cleanup_close_ int nfd = - 1 ;
2010-06-05 00:03:22 +04:00
Manager * m = userdata ;
2013-11-20 00:12:59 +04:00
sd_id128_t id ;
int r ;
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
assert ( s ) ;
2010-06-05 00:03:22 +04:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
nfd = accept4 ( fd , NULL , NULL , SOCK_NONBLOCK | SOCK_CLOEXEC ) ;
if ( nfd < 0 ) {
2014-11-28 21:29:59 +03:00
log_warning_errno ( errno , " Failed to accept private connection, ignoring: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
if ( set_size ( m - > private_buses ) > = CONNECTIONS_MAX ) {
log_warning ( " Too many concurrent connections, refusing " ) ;
return 0 ;
}
2010-06-05 00:03:22 +04:00
2014-08-13 03:00:18 +04:00
r = set_ensure_allocated ( & m - > private_buses , NULL ) ;
2013-11-20 00:12:59 +04:00
if ( r < 0 ) {
log_oom ( ) ;
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_new ( & bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to allocate new private connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_set_fd ( bus , nfd , nfd ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to set fd on new connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
nfd = - 1 ;
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = bus_check_peercred ( bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Incoming private connection from unprivileged client, refusing: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
assert_se ( sd_id128_randomize ( & id ) > = 0 ) ;
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_set_server ( bus , 1 , id ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to enable server support for new connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_start ( bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to start new connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2010-06-05 00:03:22 +04:00
}
2013-11-20 00:12:59 +04:00
r = sd_bus_attach_event ( bus , m - > event , SD_EVENT_PRIORITY_NORMAL ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to attach new connection bus to event loop: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2010-06-05 00:03:22 +04:00
}
2013-11-20 00:12:59 +04:00
if ( m - > running_as = = SYSTEMD_SYSTEM ) {
/* When we run as system instance we get the Released
* signal via a direct connection */
r = sd_bus_add_match (
bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-11-20 00:12:59 +04:00
" type='signal', "
" interface='org.freedesktop.systemd1.Agent', "
" member='Released', "
" path='/org/freedesktop/systemd1/agent' " ,
signal_agent_released , m ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to register Released match on new connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = bus_setup_disconnected_match ( m , bus ) ;
if ( r < 0 )
return 0 ;
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = bus_setup_api_vtables ( m , bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to set up API vtables on new connection bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
}
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
r = set_put ( m - > private_buses , bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to add new conenction bus to set: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2010-06-05 00:03:22 +04:00
}
2013-11-20 00:12:59 +04:00
bus = NULL ;
2010-06-05 00:03:22 +04:00
2013-11-20 00:12:59 +04:00
log_debug ( " Accepted new private connection. " ) ;
2010-06-05 00:03:22 +04:00
2010-03-31 18:29:55 +04:00
return 0 ;
}
2013-11-20 00:12:59 +04:00
static int bus_list_names ( Manager * m , sd_bus * bus ) {
2013-12-03 21:58:18 +04:00
_cleanup_strv_free_ char * * names = NULL ;
char * * i ;
2013-11-20 00:12:59 +04:00
int r ;
2010-06-19 05:04:04 +04:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
assert ( bus ) ;
2010-06-19 05:04:04 +04:00
2013-12-03 21:58:18 +04:00
r = sd_bus_list_names ( bus , & names , NULL ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to get initial list of names: %m " ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
/* 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 . */
2013-12-03 21:58:18 +04:00
STRV_FOREACH ( i , names )
manager_dispatch_bus_name_owner_changed ( m , * i , NULL , * i ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-06-19 05:04:04 +04:00
}
2013-11-20 00:12:59 +04:00
static int bus_setup_api ( Manager * m , sd_bus * bus ) {
int r ;
2010-04-06 18:32:07 +04:00
2013-11-20 00:12:59 +04:00
assert ( m ) ;
assert ( bus ) ;
2010-02-05 02:38:41 +03:00
2014-11-26 20:57:37 +03:00
/* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
r = sd_bus_negotiate_creds ( bus , 1 ,
SD_BUS_CREDS_PID | SD_BUS_CREDS_UID |
SD_BUS_CREDS_EUID | SD_BUS_CREDS_EFFECTIVE_CAPS |
SD_BUS_CREDS_SELINUX_CONTEXT ) ;
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to enable credential passing, ignoring: %m " ) ;
2014-11-26 20:57:37 +03:00
2013-11-20 00:12:59 +04:00
r = bus_setup_api_vtables ( m , bus ) ;
if ( r < 0 )
return r ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_add_match (
bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-11-20 00:12:59 +04:00
" type='signal', "
" sender='org.freedesktop.DBus', "
" path='/org/freedesktop/DBus', "
" interface='org.freedesktop.DBus', "
" member='NameOwnerChanged' " ,
signal_name_owner_changed , m ) ;
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to subscribe to NameOwnerChanged signal: %m " ) ;
2013-11-20 00:12:59 +04:00
r = sd_bus_add_match (
bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-11-20 00:12:59 +04:00
" type='signal', "
" sender='org.freedesktop.DBus', "
" path='/org/freedesktop/DBus', "
" interface='org.freedesktop.systemd1.Activator', "
" member='ActivationRequest' " ,
signal_activation_request , m ) ;
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to subscribe to activation signal: %m " ) ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +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 */
2013-12-12 08:55:58 +04:00
r = sd_bus_request_name ( bus , " org.freedesktop.systemd1 " , SD_BUS_NAME_REPLACE_EXISTING | SD_BUS_NAME_ALLOW_REPLACEMENT ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register name: %m " ) ;
2010-09-03 03:45:14 +04:00
2013-11-20 00:12:59 +04:00
bus_list_names ( m , bus ) ;
2010-04-06 18:32:07 +04:00
2013-11-20 00:12:59 +04:00
log_debug ( " Successfully connected to API bus. " ) ;
2010-04-06 18:32:07 +04:00
return 0 ;
}
2013-11-20 00:12:59 +04:00
static int bus_init_api ( Manager * m ) {
_cleanup_bus_unref_ sd_bus * bus = NULL ;
2010-04-06 18:32:07 +04:00
int r ;
2013-11-20 00:12:59 +04:00
if ( m - > api_bus )
return 0 ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
/* The API and system bus is the same if we are running in system mode */
if ( m - > running_as = = SYSTEMD_SYSTEM & & m - > system_bus )
bus = sd_bus_ref ( m - > system_bus ) ;
else {
if ( m - > running_as = = SYSTEMD_SYSTEM )
r = sd_bus_open_system ( & bus ) ;
else
r = sd_bus_open_user ( & bus ) ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
if ( r < 0 ) {
log_debug ( " Failed to connect to API bus, retrying later... " ) ;
return 0 ;
2011-12-18 17:58:10 +04:00
}
2013-11-20 00:12:59 +04:00
r = sd_bus_attach_event ( bus , m - > event , SD_EVENT_PRIORITY_NORMAL ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to attach API bus to event loop: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2011-12-18 17:58:10 +04:00
}
2013-11-20 00:12:59 +04:00
r = bus_setup_disconnected_match ( m , bus ) ;
if ( r < 0 )
return 0 ;
2011-12-18 17:58:10 +04:00
}
2013-11-20 00:12:59 +04:00
r = bus_setup_api ( m , bus ) ;
2011-12-18 17:58:10 +04:00
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to set up API bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2011-12-18 17:58:10 +04:00
}
2013-11-20 00:12:59 +04:00
m - > api_bus = bus ;
bus = NULL ;
2011-12-18 17:58:10 +04:00
return 0 ;
}
2013-11-20 00:12:59 +04:00
static int bus_setup_system ( Manager * m , sd_bus * bus ) {
int r ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
assert ( m ) ;
assert ( bus ) ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
if ( m - > running_as = = SYSTEMD_SYSTEM )
return 0 ;
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
/* If we are a user instance we get the Released message via
* the system bus */
r = sd_bus_add_match (
bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-11-20 00:12:59 +04:00
" type='signal', "
" interface='org.freedesktop.systemd1.Agent', "
" member='Released', "
" path='/org/freedesktop/systemd1/agent' " ,
signal_agent_released , m ) ;
2013-03-30 09:38:36 +04:00
2013-11-20 00:12:59 +04:00
if ( r < 0 )
2014-11-28 15:19:16 +03:00
log_warning_errno ( r , " Failed to register Released match on system bus: %m " ) ;
2013-11-20 00:12:59 +04:00
log_debug ( " Successfully connected to system bus. " ) ;
return 0 ;
2011-12-18 17:58:10 +04:00
}
static int bus_init_system ( Manager * m ) {
2013-11-20 00:12:59 +04:00
_cleanup_bus_unref_ sd_bus * bus = NULL ;
2011-12-18 17:58:10 +04:00
int r ;
if ( m - > system_bus )
return 0 ;
2013-11-20 00:12:59 +04:00
/* The API and system bus is the same if we are running in system mode */
if ( m - > running_as = = SYSTEMD_SYSTEM & & m - > api_bus ) {
m - > system_bus = sd_bus_ref ( m - > api_bus ) ;
return 0 ;
2010-07-11 02:51:28 +04:00
}
2010-03-31 18:29:55 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_open_system ( & bus ) ;
if ( r < 0 ) {
log_debug ( " Failed to connect to system bus, retrying later... " ) ;
return 0 ;
}
2011-12-18 17:58:10 +04:00
2013-11-20 00:12:59 +04:00
r = bus_setup_disconnected_match ( m , bus ) ;
2011-12-18 17:58:10 +04:00
if ( r < 0 )
return 0 ;
2013-11-20 00:12:59 +04:00
r = sd_bus_attach_event ( bus , m - > event , SD_EVENT_PRIORITY_NORMAL ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to attach system bus to event loop: %m " ) ;
2011-12-18 17:58:10 +04:00
return 0 ;
}
2013-11-20 00:12:59 +04:00
r = bus_setup_system ( m , bus ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to set up system bus: %m " ) ;
2013-11-20 00:12:59 +04:00
return 0 ;
2011-12-18 17:58:10 +04:00
}
2013-11-20 00:12:59 +04:00
m - > system_bus = bus ;
bus = NULL ;
2011-12-18 17:58:10 +04:00
return 0 ;
2010-06-19 05:04:04 +04:00
}
static int bus_init_private ( Manager * m ) {
2013-11-20 00:12:59 +04:00
_cleanup_close_ int fd = - 1 ;
union sockaddr_union sa = {
. un . sun_family = AF_UNIX
2010-06-19 05:04:04 +04:00
} ;
2013-11-20 00:12:59 +04:00
sd_event_source * s ;
socklen_t salen ;
int r ;
2010-06-19 05:04:04 +04:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
if ( m - > private_listen_fd > = 0 )
2010-06-19 05:04:04 +04:00
return 0 ;
2013-12-03 22:55:51 +04:00
/* We don't need the private socket if we have kdbus */
if ( m - > kdbus_fd > = 0 )
return 0 ;
2012-09-18 19:11:12 +04:00
if ( m - > running_as = = SYSTEMD_SYSTEM ) {
2011-07-02 00:34:37 +04:00
/* We want the private bus only when running as init */
if ( getpid ( ) ! = 1 )
return 0 ;
2013-11-20 00:12:59 +04:00
strcpy ( sa . un . sun_path , " /run/systemd/private " ) ;
2014-03-15 22:40:07 +04:00
salen = offsetof ( union sockaddr_union , un . sun_path ) + strlen ( " /run/systemd/private " ) ;
2011-07-02 00:34:37 +04:00
} else {
2013-11-20 00:12:59 +04:00
size_t left = sizeof ( sa . un . sun_path ) ;
char * p = sa . un . sun_path ;
2011-07-02 00:34:37 +04:00
const char * e ;
2012-09-17 02:21:25 +04:00
e = secure_getenv ( " XDG_RUNTIME_DIR " ) ;
2013-11-20 00:12:59 +04:00
if ( ! e ) {
log_error ( " Failed to determine XDG_RUNTIME_DIR " ) ;
return - EHOSTDOWN ;
2011-07-02 00:34:37 +04:00
}
2013-11-20 00:12:59 +04:00
left = strpcpy ( & p , left , e ) ;
left = strpcpy ( & p , left , " /systemd/private " ) ;
2013-02-08 01:14:56 +04:00
2013-11-20 00:12:59 +04:00
salen = sizeof ( sa . un ) - left ;
2011-07-02 00:34:37 +04:00
}
2010-06-19 05:04:04 +04:00
2014-11-07 18:32:06 +03:00
( void ) mkdir_parents_label ( sa . un . sun_path , 0755 ) ;
( void ) unlink ( sa . un . sun_path ) ;
2013-11-20 00:12:59 +04:00
fd = socket ( AF_UNIX , SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK , 0 ) ;
2014-11-28 21:57:32 +03:00
if ( fd < 0 )
return log_error_errno ( errno , " Failed to allocate private socket: %m " ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
r = bind ( fd , & sa . sa , salen ) ;
2014-11-28 21:57:32 +03:00
if ( r < 0 )
return log_error_errno ( errno , " Failed to bind private socket: %m " ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
r = listen ( fd , SOMAXCONN ) ;
2014-11-28 21:57:32 +03:00
if ( r < 0 )
return log_error_errno ( errno , " Failed to make private socket listening: %m " ) ;
2010-06-19 05:04:04 +04:00
2014-02-20 02:54:58 +04:00
r = sd_event_add_io ( m - > event , & s , fd , EPOLLIN , bus_on_connection , m ) ;
2014-11-28 20:23:20 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to allocate event source: %m " ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
m - > private_listen_fd = fd ;
m - > private_listen_event_source = s ;
fd = - 1 ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
log_debug ( " Successfully created private D-Bus server. " ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
return 0 ;
2010-06-19 05:04:04 +04:00
}
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 ;
2011-01-20 21:43:38 +03:00
if ( try_bus_connect ) {
2013-11-20 00:12:59 +04:00
r = bus_init_system ( m ) ;
if ( r < 0 )
return r ;
r = bus_init_api ( m ) ;
if ( r < 0 )
2011-01-20 21:43:38 +03:00
return r ;
}
2013-07-10 21:24:03 +04:00
r = bus_init_private ( m ) ;
if ( r < 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 ;
}
2013-11-20 00:12:59 +04:00
static void destroy_bus ( Manager * m , sd_bus * * bus ) {
2010-07-05 02:58:07 +04:00
Iterator i ;
2013-11-20 00:12:59 +04:00
Job * j ;
2010-07-05 02:58:07 +04:00
2013-11-20 00:12:59 +04:00
assert ( m ) ;
assert ( bus ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
if ( ! * bus )
2011-12-18 17:58:10 +04:00
return ;
2010-04-06 18:32:07 +04:00
2013-11-20 00:12:59 +04:00
/* Get rid of tracked clients on this bus */
2014-03-03 04:33:45 +04:00
if ( m - > subscribed & & sd_bus_track_get_bus ( m - > subscribed ) = = * bus )
m - > subscribed = sd_bus_track_unref ( m - > subscribed ) ;
2013-11-20 00:12:59 +04:00
HASHMAP_FOREACH ( j , m - > jobs , i )
2014-08-06 13:53:00 +04:00
if ( j - > clients & & sd_bus_track_get_bus ( j - > clients ) = = * bus )
j - > clients = sd_bus_track_unref ( j - > clients ) ;
2010-02-05 02:38:41 +03:00
2013-11-20 00:12:59 +04:00
/* Get rid of queued message on this bus */
if ( m - > queued_message_bus = = * bus ) {
m - > queued_message_bus = sd_bus_unref ( m - > queued_message_bus ) ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
if ( m - > queued_message )
m - > queued_message = sd_bus_message_unref ( m - > queued_message ) ;
2011-12-18 17:58:10 +04:00
}
2010-04-06 18:32:07 +04:00
2013-11-20 00:12:59 +04:00
/* Possibly flush unwritten data, but only if we are
* unprivileged , since we don ' t want to sync here */
if ( m - > running_as ! = SYSTEMD_SYSTEM )
sd_bus_flush ( * bus ) ;
2010-06-19 05:04:04 +04:00
2013-11-20 00:12:59 +04:00
/* And destroy the object */
sd_bus_close ( * bus ) ;
* bus = sd_bus_unref ( * bus ) ;
2010-06-19 05:04:04 +04:00
}
void bus_done ( Manager * m ) {
2013-11-20 00:12:59 +04:00
sd_bus * b ;
2010-04-16 01:16:16 +04:00
assert ( m ) ;
2013-11-20 00:12:59 +04:00
if ( m - > api_bus )
destroy_bus ( m , & m - > api_bus ) ;
if ( m - > system_bus )
destroy_bus ( m , & m - > system_bus ) ;
while ( ( b = set_steal_first ( m - > private_buses ) ) )
destroy_bus ( m , & b ) ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
set_free ( m - > private_buses ) ;
2014-03-03 04:33:45 +04:00
m - > private_buses = NULL ;
m - > subscribed = sd_bus_track_unref ( m - > subscribed ) ;
strv_free ( m - > deserialized_subscribed ) ;
m - > deserialized_subscribed = NULL ;
2010-04-16 01:16:16 +04:00
2013-11-20 00:12:59 +04:00
if ( m - > private_listen_event_source )
m - > private_listen_event_source = sd_event_source_unref ( m - > private_listen_event_source ) ;
2010-04-16 01:16:16 +04:00
2014-03-18 22:22:43 +04:00
m - > private_listen_fd = safe_close ( m - > private_listen_fd ) ;
2014-08-06 13:45:36 +04:00
bus_verify_polkit_async_registry_free ( m - > polkit_registry ) ;
2010-07-05 02:58:07 +04:00
}
2011-04-29 00:07:01 +04:00
int bus_fdset_add_all ( Manager * m , FDSet * fds ) {
Iterator i ;
2013-11-20 00:12:59 +04:00
sd_bus * b ;
int fd ;
2011-04-29 00:07:01 +04:00
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
2013-11-20 00:12:59 +04:00
* be used there however , except thatt they are closed at the
2011-04-29 00:07:01 +04:00
* 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 */
2013-11-20 00:12:59 +04:00
if ( m - > api_bus ) {
fd = sd_bus_get_fd ( m - > api_bus ) ;
if ( fd > = 0 ) {
2011-04-29 00:07:01 +04:00
fd = fdset_put_dup ( fds , fd ) ;
if ( fd < 0 )
return fd ;
}
}
2013-11-20 00:12:59 +04:00
SET_FOREACH ( b , m - > private_buses , i ) {
fd = sd_bus_get_fd ( b ) ;
if ( fd > = 0 ) {
2011-04-29 00:07:01 +04:00
fd = fdset_put_dup ( fds , fd ) ;
if ( fd < 0 )
return fd ;
}
}
2013-11-20 00:12:59 +04:00
/* We don't offer any APIs on the system bus (well, unless it
* is the same as the API bus ) hence we don ' t bother with it
* here */
2013-07-10 21:24:03 +04:00
2013-11-20 00:12:59 +04:00
return 0 ;
2013-07-10 21:24:03 +04:00
}
2014-03-03 04:33:45 +04:00
int bus_foreach_bus (
Manager * m ,
sd_bus_track * subscribed2 ,
int ( * send_message ) ( sd_bus * bus , void * userdata ) ,
void * userdata ) {
Iterator i ;
sd_bus * b ;
int r , ret = 0 ;
/* Send to all direct busses, unconditionally */
SET_FOREACH ( b , m - > private_buses , i ) {
r = send_message ( b , userdata ) ;
if ( r < 0 )
ret = r ;
}
/* Send to API bus, but only if somebody is subscribed */
if ( sd_bus_track_count ( m - > subscribed ) > 0 | |
sd_bus_track_count ( subscribed2 ) > 0 ) {
r = send_message ( m - > api_bus , userdata ) ;
if ( r < 0 )
ret = r ;
}
return ret ;
}
void bus_track_serialize ( sd_bus_track * t , FILE * f ) {
const char * n ;
2013-07-10 21:24:03 +04:00
assert ( f ) ;
2014-03-03 04:33:45 +04:00
for ( n = sd_bus_track_first ( t ) ; n ; n = sd_bus_track_next ( t ) )
fprintf ( f , " subscribed=%s \n " , n ) ;
2013-07-10 21:24:03 +04:00
}
2014-03-03 04:33:45 +04:00
int bus_track_deserialize_item ( char * * * l , const char * line ) {
const char * e ;
2014-12-02 02:15:13 +03:00
int r ;
2014-03-03 04:33:45 +04:00
assert ( l ) ;
2013-07-10 21:24:03 +04:00
assert ( line ) ;
2014-03-03 04:33:45 +04:00
e = startswith ( line , " subscribed= " ) ;
if ( ! e )
2014-12-02 02:15:13 +03:00
return 0 ;
r = strv_extend ( l , e ) ;
if ( r < 0 )
return r ;
2014-03-03 04:33:45 +04:00
2014-12-02 02:15:13 +03:00
return 1 ;
2014-03-03 04:33:45 +04:00
}
int bus_track_coldplug ( Manager * m , sd_bus_track * * t , char * * * l ) {
int r = 0 ;
assert ( m ) ;
assert ( t ) ;
assert ( l ) ;
if ( ! strv_isempty ( * l ) & & m - > api_bus ) {
char * * i ;
if ( ! * t ) {
r = sd_bus_track_new ( m - > api_bus , t , NULL , NULL ) ;
if ( r < 0 )
return r ;
}
r = 0 ;
STRV_FOREACH ( i , * l ) {
int k ;
k = sd_bus_track_add_name ( * t , * i ) ;
if ( k < 0 )
r = k ;
}
}
strv_free ( * l ) ;
* l = NULL ;
return r ;
2013-07-10 21:24:03 +04:00
}
2014-08-06 13:45:36 +04:00
2015-02-18 19:40:57 +03:00
int bus_verify_manage_units_async ( Manager * m , sd_bus_message * call , sd_bus_error * error ) {
2015-02-18 14:55:25 +03:00
return bus_verify_polkit_async ( call , CAP_SYS_ADMIN , " org.freedesktop.systemd1.manage-units " , false , UID_INVALID , & m - > polkit_registry , error ) ;
2014-08-06 13:45:36 +04:00
}
/* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */
2015-02-18 19:40:57 +03:00
int bus_verify_manage_units_async_for_kill ( Manager * m , sd_bus_message * call , sd_bus_error * error ) {
2015-02-18 14:55:25 +03:00
return bus_verify_polkit_async ( call , CAP_KILL , " org.freedesktop.systemd1.manage-units " , false , UID_INVALID , & m - > polkit_registry , error ) ;
2014-08-06 13:45:36 +04:00
}
int bus_verify_manage_unit_files_async ( Manager * m , sd_bus_message * call , sd_bus_error * error ) {
2015-02-18 14:55:25 +03:00
return bus_verify_polkit_async ( call , CAP_SYS_ADMIN , " org.freedesktop.systemd1.manage-unit-files " , false , UID_INVALID , & m - > polkit_registry , error ) ;
2014-08-06 13:45:36 +04:00
}
int bus_verify_reload_daemon_async ( Manager * m , sd_bus_message * call , sd_bus_error * error ) {
2015-02-18 14:55:25 +03:00
return bus_verify_polkit_async ( call , CAP_SYS_ADMIN , " org.freedesktop.systemd1.reload-daemon " , false , UID_INVALID , & m - > polkit_registry , error ) ;
2014-08-06 13:45:36 +04:00
}
2015-02-18 19:40:57 +03:00
int bus_verify_set_environment_async ( Manager * m , sd_bus_message * call , sd_bus_error * error ) {
return bus_verify_polkit_async ( call , CAP_SYS_ADMIN , " org.freedesktop.systemd1.set-environment " , false , UID_INVALID , & m - > polkit_registry , error ) ;
}