2013-07-02 05:47:23 +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/>.
* * */
# include <errno.h>
# include <pwd.h>
# include <fcntl.h>
# include <string.h>
# include <unistd.h>
# include <sys/epoll.h>
2013-10-30 05:06:55 +04:00
# include "sd-daemon.h"
2013-07-02 05:47:23 +04:00
# include "strv.h"
# include "conf-parser.h"
2013-10-30 05:06:55 +04:00
# include "cgroup-util.h"
2013-07-02 05:47:23 +04:00
# include "mkdir.h"
2013-10-30 05:06:55 +04:00
# include "bus-util.h"
# include "bus-error.h"
2014-10-23 21:58:45 +04:00
# include "label.h"
2014-12-28 04:44:37 +03:00
# include "machine-image.h"
2014-12-19 22:43:18 +03:00
# include "machined.h"
2013-07-02 05:47:23 +04:00
Manager * manager_new ( void ) {
Manager * m ;
2013-10-30 05:06:55 +04:00
int r ;
2013-07-02 05:47:23 +04:00
m = new0 ( Manager , 1 ) ;
if ( ! m )
return NULL ;
2014-08-13 03:00:18 +04:00
m - > machines = hashmap_new ( & string_hash_ops ) ;
m - > machine_units = hashmap_new ( & string_hash_ops ) ;
m - > machine_leaders = hashmap_new ( NULL ) ;
2013-07-02 05:47:23 +04:00
2013-11-06 05:03:04 +04:00
if ( ! m - > machines | | ! m - > machine_units | | ! m - > machine_leaders ) {
2013-10-30 05:06:55 +04:00
manager_free ( m ) ;
return NULL ;
}
2013-11-11 22:34:13 +04:00
r = sd_event_default ( & m - > event ) ;
2013-11-05 03:52:46 +04:00
if ( r < 0 ) {
2013-07-02 05:47:23 +04:00
manager_free ( m ) ;
return NULL ;
}
2013-12-11 21:14:52 +04:00
sd_event_set_watchdog ( m - > event , true ) ;
2013-07-02 05:47:23 +04:00
return m ;
}
void manager_free ( Manager * m ) {
Machine * machine ;
2014-12-28 04:44:37 +03:00
Image * i ;
2013-07-02 05:47:23 +04:00
assert ( m ) ;
while ( ( machine = hashmap_first ( m - > machines ) ) )
machine_free ( machine ) ;
hashmap_free ( m - > machines ) ;
hashmap_free ( m - > machine_units ) ;
2013-11-06 05:03:04 +04:00
hashmap_free ( m - > machine_leaders ) ;
2013-07-02 05:47:23 +04:00
2014-12-28 04:44:37 +03:00
while ( ( i = hashmap_steal_first ( m - > image_cache ) ) )
image_unref ( i ) ;
hashmap_free ( m - > image_cache ) ;
sd_event_source_unref ( m - > image_cache_defer_event ) ;
2014-12-23 23:28:22 +03:00
bus_verify_polkit_async_registry_free ( m - > polkit_registry ) ;
2013-10-30 05:06:55 +04:00
sd_bus_unref ( m - > bus ) ;
sd_event_unref ( m - > event ) ;
free ( m ) ;
}
2013-07-02 05:47:23 +04:00
int manager_enumerate_machines ( Manager * m ) {
_cleanup_closedir_ DIR * d = NULL ;
struct dirent * de ;
int r = 0 ;
assert ( m ) ;
/* Read in machine data stored on disk */
d = opendir ( " /run/systemd/machines " ) ;
if ( ! d ) {
if ( errno = = ENOENT )
return 0 ;
2014-11-28 21:29:59 +03:00
log_error_errno ( errno , " Failed to open /run/systemd/machines: %m " ) ;
2013-07-02 05:47:23 +04:00
return - errno ;
}
FOREACH_DIRENT ( de , d , return - errno ) {
struct Machine * machine ;
int k ;
if ( ! dirent_is_file ( de ) )
continue ;
2014-02-12 00:06:51 +04:00
/* Ignore symlinks that map the unit name to the machine */
if ( startswith ( de - > d_name , " unit: " ) )
continue ;
2013-07-02 05:47:23 +04:00
k = manager_add_machine ( m , de - > d_name , & machine ) ;
if ( k < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( k , " Failed to add machine by file name %s: %m " , de - > d_name ) ;
2013-07-02 05:47:23 +04:00
r = k ;
continue ;
}
machine_add_to_gc_queue ( machine ) ;
k = machine_load ( machine ) ;
if ( k < 0 )
r = k ;
}
return r ;
}
static int manager_connect_bus ( Manager * m ) {
2013-10-30 05:06:55 +04:00
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL ;
2013-07-02 05:47:23 +04:00
int r ;
assert ( m ) ;
assert ( ! m - > bus ) ;
2013-11-12 01:00:48 +04:00
r = sd_bus_default_system ( & m - > bus ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to connect to system bus: %m " ) ;
2013-07-02 05:47:23 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_object_vtable ( m - > bus , NULL , " /org/freedesktop/machine1 " , " org.freedesktop.machine1.Manager " , manager_vtable , m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add manager object vtable: %m " ) ;
2013-07-02 05:47:23 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_fallback_vtable ( m - > bus , NULL , " /org/freedesktop/machine1/machine " , " org.freedesktop.machine1.Machine " , machine_vtable , machine_object_find , m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add machine object vtable: %m " ) ;
2013-10-30 05:06:55 +04:00
2014-05-15 03:15:30 +04:00
r = sd_bus_add_node_enumerator ( m - > bus , NULL , " /org/freedesktop/machine1/machine " , machine_node_enumerator , m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add machine enumerator: %m " ) ;
2013-07-02 05:47:23 +04:00
2014-12-19 22:43:18 +03:00
r = sd_bus_add_fallback_vtable ( m - > bus , NULL , " /org/freedesktop/machine1/image " , " org.freedesktop.machine1.Image " , image_vtable , image_object_find , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add image object vtable: %m " ) ;
r = sd_bus_add_node_enumerator ( m - > bus , NULL , " /org/freedesktop/machine1/image " , image_node_enumerator , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add image enumerator: %m " ) ;
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-10-30 05:06:55 +04:00
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='JobRemoved', "
" path='/org/freedesktop/systemd1' " ,
match_job_removed ,
m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add match for JobRemoved: %m " ) ;
2013-07-02 05:47:23 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-10-30 05:06:55 +04:00
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='UnitRemoved', "
" path='/org/freedesktop/systemd1' " ,
match_unit_removed ,
m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add match for UnitRemoved: %m " ) ;
2013-07-03 17:12:58 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-10-30 05:06:55 +04:00
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.DBus.Properties', "
" member='PropertiesChanged' " ,
match_properties_changed ,
m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add match for PropertiesChanged: %m " ) ;
2013-07-02 05:47:23 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
2014-05-15 03:15:30 +04:00
NULL ,
2013-10-30 05:06:55 +04:00
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='Reloading', "
" path='/org/freedesktop/systemd1' " ,
match_reloading ,
m ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to add match for Reloading: %m " ) ;
2013-07-11 01:31:40 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_call_method (
2013-07-02 05:47:23 +04:00
m - > bus ,
" org.freedesktop.systemd1 " ,
" /org/freedesktop/systemd1 " ,
" org.freedesktop.systemd1.Manager " ,
" Subscribe " ,
& error ,
2013-10-30 05:06:55 +04:00
NULL , NULL ) ;
2013-07-02 05:47:23 +04:00
if ( r < 0 ) {
2013-10-30 05:06:55 +04:00
log_error ( " Failed to enable subscription: %s " , bus_error_message ( & error , r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-12-12 23:26:48 +04:00
r = sd_bus_request_name ( m - > bus , " org.freedesktop.machine1 " , 0 ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to register name: %m " ) ;
2013-07-02 05:47:23 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_attach_event ( m - > bus , m - > event , 0 ) ;
2014-11-28 20:50:43 +03:00
if ( r < 0 )
return log_error_errno ( r , " Failed to attach bus to event loop: %m " ) ;
2013-07-02 05:47:23 +04:00
return 0 ;
}
void manager_gc ( Manager * m , bool drop_not_started ) {
Machine * machine ;
assert ( m ) ;
while ( ( machine = m - > machine_gc_queue ) ) {
2013-10-14 08:10:14 +04:00
LIST_REMOVE ( gc_queue , m - > machine_gc_queue , machine ) ;
2013-07-02 05:47:23 +04:00
machine - > in_gc_queue = false ;
2013-11-05 03:52:46 +04:00
if ( ! machine_check_gc ( machine , drop_not_started ) ) {
2013-07-02 05:47:23 +04:00
machine_stop ( machine ) ;
machine_free ( machine ) ;
}
}
}
int manager_startup ( Manager * m ) {
Machine * machine ;
Iterator i ;
2013-10-30 05:06:55 +04:00
int r ;
2013-07-02 05:47:23 +04:00
assert ( m ) ;
/* Connect to the bus */
r = manager_connect_bus ( m ) ;
if ( r < 0 )
return r ;
/* Deserialize state */
manager_enumerate_machines ( m ) ;
/* Remove stale objects before we start them */
manager_gc ( m , false ) ;
/* And start everything */
HASHMAP_FOREACH ( machine , m - > machines , i )
2013-10-30 05:06:55 +04:00
machine_start ( machine , NULL , NULL ) ;
2013-07-02 05:47:23 +04:00
return 0 ;
}
2013-12-20 00:15:08 +04:00
static bool check_idle ( void * userdata ) {
Manager * m = userdata ;
2013-07-02 05:47:23 +04:00
2013-12-20 00:15:08 +04:00
manager_gc ( m , true ) ;
2013-07-02 05:47:23 +04:00
2013-12-20 00:15:08 +04:00
return hashmap_isempty ( m - > machines ) ;
}
2013-07-02 05:47:23 +04:00
2013-12-20 00:15:08 +04:00
int manager_run ( Manager * m ) {
assert ( m ) ;
2013-07-02 05:47:23 +04:00
2013-12-20 00:15:08 +04:00
return bus_event_loop_with_idle (
m - > event ,
m - > bus ,
" org.freedesktop.machine1 " ,
DEFAULT_EXIT_USEC ,
check_idle , m ) ;
2013-07-02 05:47:23 +04:00
}
int main ( int argc , char * argv [ ] ) {
Manager * m = NULL ;
int r ;
log_set_target ( LOG_TARGET_AUTO ) ;
log_set_facility ( LOG_AUTH ) ;
log_parse_environment ( ) ;
log_open ( ) ;
umask ( 0022 ) ;
if ( argc ! = 1 ) {
log_error ( " This program takes no arguments. " ) ;
r = - EINVAL ;
goto finish ;
}
/* Always create the directories people can create inotify
* watches in . Note that some applications might check for the
2013-10-30 05:06:55 +04:00
* existence of / run / systemd / machines / to determine whether
* machined is available , so please always make sure this
* check stays in . */
2013-07-02 05:47:23 +04:00
mkdir_label ( " /run/systemd/machines " , 0755 ) ;
m = manager_new ( ) ;
if ( ! m ) {
r = log_oom ( ) ;
goto finish ;
}
r = manager_startup ( m ) ;
if ( r < 0 ) {
2014-11-28 15:19:16 +03:00
log_error_errno ( r , " Failed to fully start up daemon: %m " ) ;
2013-07-02 05:47:23 +04:00
goto finish ;
}
2014-04-25 15:45:15 +04:00
log_debug ( " systemd-machined running as pid " PID_FMT , getpid ( ) ) ;
2013-07-02 05:47:23 +04:00
sd_notify ( false ,
" READY=1 \n "
" STATUS=Processing requests... " ) ;
r = manager_run ( m ) ;
2014-04-25 15:45:15 +04:00
log_debug ( " systemd-machined stopped as pid " PID_FMT , getpid ( ) ) ;
2013-07-02 05:47:23 +04:00
finish :
if ( m )
manager_free ( m ) ;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
}