2013-07-01 02:03:57 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2013 Lennart Poettering
systemd is free software ; you can redistribute it and / or modify it
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
( 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2015-02-18 19:40:57 +03:00
# include "selinux-access.h"
2013-11-20 00:12:59 +04:00
# include "unit.h"
# include "scope.h"
2014-08-06 13:45:36 +04:00
# include "dbus.h"
2013-11-20 00:12:59 +04:00
# include "bus-util.h"
2014-01-31 20:45:13 +04:00
# include "bus-internal.h"
2014-12-10 21:00:46 +03:00
# include "bus-common-errors.h"
2015-02-18 19:40:57 +03:00
# include "dbus-unit.h"
# include "dbus-cgroup.h"
# include "dbus-kill.h"
# include "dbus-scope.h"
2013-07-01 02:03:57 +04:00
2014-02-06 20:17:51 +04:00
static int bus_scope_abandon ( sd_bus * bus , sd_bus_message * message , void * userdata , sd_bus_error * error ) {
Scope * s = userdata ;
2014-02-07 20:59:27 +04:00
int r ;
2014-02-06 20:17:51 +04:00
assert ( bus ) ;
assert ( message ) ;
assert ( s ) ;
2015-02-18 19:40:57 +03:00
r = mac_selinux_unit_access_check ( UNIT ( s ) , message , " stop " , error ) ;
if ( r < 0 )
return r ;
r = bus_verify_manage_units_async ( UNIT ( s ) - > manager , message , error ) ;
2014-08-06 13:45:36 +04:00
if ( r < 0 )
return r ;
if ( r = = 0 )
return 1 ; /* No authorization for now, but the async polkit stuff will call us again when it has it */
2014-02-07 20:59:27 +04:00
r = scope_abandon ( s ) ;
if ( r = = - ESTALE )
return sd_bus_error_setf ( error , BUS_ERROR_SCOPE_NOT_RUNNING , " Scope %s is not running, cannot abandon. " , UNIT ( s ) - > id ) ;
2015-02-18 19:40:57 +03:00
if ( r < 0 )
return r ;
2014-02-07 20:59:27 +04:00
return sd_bus_reply_method_return ( message , NULL ) ;
2014-02-06 20:17:51 +04:00
}
2013-11-20 00:12:59 +04:00
static BUS_DEFINE_PROPERTY_GET_ENUM ( property_get_result , scope_result , ScopeResult ) ;
2013-07-01 02:03:57 +04:00
2013-11-20 00:12:59 +04:00
const sd_bus_vtable bus_scope_vtable [ ] = {
SD_BUS_VTABLE_START ( 0 ) ,
2014-01-31 20:45:13 +04:00
SD_BUS_PROPERTY ( " Controller " , " s " , NULL , offsetof ( Scope , controller ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-12-22 05:24:05 +04:00
SD_BUS_PROPERTY ( " TimeoutStopUSec " , " t " , bus_property_get_usec , offsetof ( Scope , timeout_stop_usec ) , SD_BUS_VTABLE_PROPERTY_CONST ) ,
2013-11-20 00:12:59 +04:00
SD_BUS_PROPERTY ( " Result " , " s " , property_get_result , offsetof ( Scope , result ) , SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE ) ,
2014-01-31 20:45:13 +04:00
SD_BUS_SIGNAL ( " RequestStop " , NULL , 0 ) ,
2015-02-18 19:40:57 +03:00
SD_BUS_METHOD ( " Abandon " , NULL , NULL , bus_scope_abandon , SD_BUS_VTABLE_UNPRIVILEGED ) ,
2013-11-20 00:12:59 +04:00
SD_BUS_VTABLE_END
} ;
2013-07-01 02:03:57 +04:00
2013-07-01 02:40:56 +04:00
static int bus_scope_set_transient_property (
2013-07-01 02:03:57 +04:00
Scope * s ,
const char * name ,
2013-11-20 00:12:59 +04:00
sd_bus_message * message ,
2013-07-01 02:03:57 +04:00
UnitSetPropertiesMode mode ,
2013-11-20 00:12:59 +04:00
sd_bus_error * error ) {
2013-07-01 02:03:57 +04:00
int r ;
assert ( s ) ;
2013-11-20 00:12:59 +04:00
assert ( name ) ;
assert ( message ) ;
2013-07-01 02:03:57 +04:00
if ( streq ( name , " PIDs " ) ) {
2013-07-02 18:44:02 +04:00
unsigned n = 0 ;
2013-11-20 00:12:59 +04:00
uint32_t pid ;
2013-07-01 02:03:57 +04:00
2013-11-20 00:12:59 +04:00
r = sd_bus_message_enter_container ( message , ' a ' , " u " ) ;
if ( r < 0 )
return r ;
2013-07-01 02:03:57 +04:00
2013-11-20 00:12:59 +04:00
while ( ( r = sd_bus_message_read ( message , " u " , & pid ) ) > 0 ) {
2013-07-01 02:03:57 +04:00
if ( pid < = 1 )
return - EINVAL ;
2013-07-01 04:47:11 +04:00
if ( mode ! = UNIT_CHECK ) {
2014-02-06 20:17:51 +04:00
r = unit_watch_pid ( UNIT ( s ) , pid ) ;
2013-07-01 04:47:11 +04:00
if ( r < 0 & & r ! = - EEXIST )
return r ;
}
2013-07-01 02:03:57 +04:00
2013-07-01 04:47:11 +04:00
n + + ;
2013-07-01 02:03:57 +04:00
}
2013-11-20 00:12:59 +04:00
if ( r < 0 )
return r ;
r = sd_bus_message_exit_container ( message ) ;
if ( r < 0 )
return r ;
2013-07-01 02:03:57 +04:00
2013-07-01 04:47:11 +04:00
if ( n < = 0 )
2013-07-01 02:03:57 +04:00
return - EINVAL ;
return 1 ;
2013-07-02 03:34:04 +04:00
2014-01-31 20:45:13 +04:00
} else if ( streq ( name , " Controller " ) ) {
const char * controller ;
char * c ;
r = sd_bus_message_read ( message , " s " , & controller ) ;
if ( r < 0 )
return r ;
if ( ! isempty ( controller ) & & ! service_name_is_valid ( controller ) )
return sd_bus_error_setf ( error , SD_BUS_ERROR_INVALID_ARGS , " Controller '%s' is not a valid bus name. " , controller ) ;
if ( mode ! = UNIT_CHECK ) {
if ( isempty ( controller ) )
c = NULL ;
else {
c = strdup ( controller ) ;
if ( ! c )
return - ENOMEM ;
}
free ( s - > controller ) ;
s - > controller = c ;
}
return 1 ;
2013-07-02 03:34:04 +04:00
} else if ( streq ( name , " TimeoutStopUSec " ) ) {
if ( mode ! = UNIT_CHECK ) {
2013-11-20 00:12:59 +04:00
r = sd_bus_message_read ( message , " t " , & s - > timeout_stop_usec ) ;
if ( r < 0 )
return r ;
2014-04-25 15:45:15 +04:00
unit_write_drop_in_format ( UNIT ( s ) , mode , name , " [Scope] \n TimeoutStopSec= " USEC_FMT " us \n " , s - > timeout_stop_usec ) ;
2013-11-20 00:12:59 +04:00
} else {
r = sd_bus_message_skip ( message , " t " ) ;
if ( r < 0 )
return r ;
2013-07-02 03:34:04 +04:00
}
return 1 ;
2013-07-01 02:03:57 +04:00
}
return 0 ;
}
int bus_scope_set_property (
Unit * u ,
const char * name ,
2013-11-20 00:12:59 +04:00
sd_bus_message * message ,
2013-07-01 02:03:57 +04:00
UnitSetPropertiesMode mode ,
2013-11-20 00:12:59 +04:00
sd_bus_error * error ) {
2013-07-01 02:03:57 +04:00
Scope * s = SCOPE ( u ) ;
int r ;
2013-11-20 00:12:59 +04:00
assert ( s ) ;
2013-07-01 02:03:57 +04:00
assert ( name ) ;
2013-11-20 00:12:59 +04:00
assert ( message ) ;
2013-07-01 02:03:57 +04:00
2013-11-20 00:12:59 +04:00
r = bus_cgroup_set_property ( u , & s - > cgroup_context , name , message , mode , error ) ;
2013-07-01 02:03:57 +04:00
if ( r ! = 0 )
return r ;
if ( u - > load_state = = UNIT_STUB ) {
/* While we are created we still accept PIDs */
2013-11-20 00:12:59 +04:00
r = bus_scope_set_transient_property ( s , name , message , mode , error ) ;
2013-07-01 02:03:57 +04:00
if ( r ! = 0 )
return r ;
2013-07-30 04:28:22 +04:00
2013-11-20 00:12:59 +04:00
r = bus_kill_context_set_transient_property ( u , & s - > kill_context , name , message , mode , error ) ;
2013-07-30 04:28:22 +04:00
if ( r ! = 0 )
return r ;
2013-07-01 02:03:57 +04:00
}
return 0 ;
}
int bus_scope_commit_properties ( Unit * u ) {
assert ( u ) ;
2014-02-14 22:11:07 +04:00
unit_update_cgroup_members_masks ( u ) ;
2013-07-01 02:03:57 +04:00
unit_realize_cgroup ( u ) ;
2014-02-14 22:11:07 +04:00
2013-07-01 02:03:57 +04:00
return 0 ;
}
2014-01-31 20:45:13 +04:00
int bus_scope_send_request_stop ( Scope * s ) {
_cleanup_bus_message_unref_ sd_bus_message * m = NULL ;
_cleanup_free_ char * p = NULL ;
int r ;
assert ( s ) ;
if ( ! s - > controller )
return 0 ;
p = unit_dbus_path ( UNIT ( s ) ) ;
if ( ! p )
return - ENOMEM ;
r = sd_bus_message_new_signal (
UNIT ( s ) - > manager - > api_bus ,
2014-02-20 02:54:58 +04:00
& m ,
2014-01-31 20:45:13 +04:00
p ,
" org.freedesktop.systemd1.Scope " ,
2014-02-20 02:54:58 +04:00
" RequestStop " ) ;
2014-01-31 20:45:13 +04:00
if ( r < 0 )
return r ;
return sd_bus_send_to ( UNIT ( s ) - > manager - > api_bus , m , /* s->controller */ NULL , NULL ) ;
}