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"
# 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 ;
m - > machines = hashmap_new ( string_hash_func , string_compare_func ) ;
m - > machine_units = hashmap_new ( string_hash_func , string_compare_func ) ;
2013-11-06 05:03:04 +04:00
m - > machine_leaders = hashmap_new ( trivial_hash_func , trivial_compare_func ) ;
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-05 03:52:46 +04:00
r = sd_event_new ( & m - > event ) ;
if ( r < 0 ) {
2013-07-02 05:47:23 +04:00
manager_free ( m ) ;
return NULL ;
}
return m ;
}
void manager_free ( Manager * m ) {
Machine * machine ;
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
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 ;
log_error ( " Failed to open /run/systemd/machines: %m " ) ;
return - errno ;
}
FOREACH_DIRENT ( de , d , return - errno ) {
struct Machine * machine ;
int k ;
if ( ! dirent_is_file ( de ) )
continue ;
k = manager_add_machine ( m , de - > d_name , & machine ) ;
if ( k < 0 ) {
log_error ( " Failed to add machine by file name %s: %s " , de - > d_name , strerror ( - k ) ) ;
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-10-30 05:06:55 +04:00
r = sd_bus_open_system ( & m - > bus ) ;
if ( r < 0 ) {
log_error ( " Failed to connect to system bus: %s " , strerror ( - r ) ) ;
return r ;
}
2013-07-02 05:47:23 +04:00
2013-10-30 05:06:55 +04:00
r = sd_bus_add_object_vtable ( m - > bus , " /org/freedesktop/machine1 " , " org.freedesktop.machine1.Manager " , manager_vtable , m ) ;
if ( r < 0 ) {
log_error ( " Failed to add manager object vtable: %s " , strerror ( - r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-10-30 05:06:55 +04:00
r = sd_bus_add_fallback_vtable ( m - > bus , " /org/freedesktop/machine1/machine " , " org.freedesktop.machine1.Machine " , machine_vtable , machine_object_find , m ) ;
if ( r < 0 ) {
log_error ( " Failed to add machine object vtable: %s " , strerror ( - r ) ) ;
return r ;
}
r = sd_bus_add_node_enumerator ( m - > bus , " /org/freedesktop/machine1/machine " , machine_node_enumerator , m ) ;
if ( r < 0 ) {
log_error ( " Failed to add machine enumerator: %s " , strerror ( - r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='JobRemoved', "
" path='/org/freedesktop/systemd1' " ,
match_job_removed ,
m ) ;
if ( r < 0 ) {
log_error ( " Failed to add match for JobRemoved: %s " , strerror ( - r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='UnitRemoved', "
" path='/org/freedesktop/systemd1' " ,
match_unit_removed ,
m ) ;
if ( r < 0 ) {
log_error ( " Failed to add match for UnitRemoved: %s " , strerror ( - r ) ) ;
return r ;
2013-07-03 17:12:58 +04:00
}
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.DBus.Properties', "
" member='PropertiesChanged' " ,
match_properties_changed ,
m ) ;
if ( r < 0 ) {
log_error ( " Failed to add match for PropertiesChanged: %s " , strerror ( - r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-10-30 05:06:55 +04:00
r = sd_bus_add_match ( m - > bus ,
" type='signal', "
" sender='org.freedesktop.systemd1', "
" interface='org.freedesktop.systemd1.Manager', "
" member='Reloading', "
" path='/org/freedesktop/systemd1' " ,
match_reloading ,
m ) ;
if ( r < 0 ) {
log_error ( " Failed to add match for Reloading: %s " , strerror ( - r ) ) ;
return r ;
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-10-30 05:06:55 +04:00
r = sd_bus_request_name ( m - > bus , " org.freedesktop.machine1 " , SD_BUS_NAME_DO_NOT_QUEUE ) ;
if ( r < 0 ) {
log_error ( " Failed to register name: %s " , strerror ( - r ) ) ;
return r ;
2013-07-02 05:47:23 +04:00
}
2013-10-30 05:06:55 +04:00
if ( r ! = SD_BUS_NAME_PRIMARY_OWNER ) {
2013-07-02 05:47:23 +04:00
log_error ( " Failed to acquire name. " ) ;
2013-10-30 05:06:55 +04:00
return - EEXIST ;
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 ) ;
if ( r < 0 ) {
log_error ( " Failed to attach bus to event loop: %s " , strerror ( - r ) ) ;
return r ;
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 ;
}
int manager_run ( Manager * m ) {
2013-10-30 05:06:55 +04:00
int r ;
2013-07-02 05:47:23 +04:00
assert ( m ) ;
for ( ; ; ) {
2013-10-30 05:06:55 +04:00
r = sd_event_get_state ( m - > event ) ;
if ( r < 0 )
return r ;
if ( r = = SD_EVENT_FINISHED )
return 0 ;
2013-07-02 05:47:23 +04:00
manager_gc ( m , true ) ;
2013-10-30 05:06:55 +04:00
r = sd_event_run ( m - > event , ( uint64_t ) - 1 ) ;
if ( r < 0 )
return r ;
2013-07-02 05:47:23 +04:00
}
return 0 ;
}
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 ) {
log_error ( " Failed to fully start up daemon: %s " , strerror ( - r ) ) ;
goto finish ;
}
log_debug ( " systemd-machined running as pid %lu " , ( unsigned long ) getpid ( ) ) ;
sd_notify ( false ,
" READY=1 \n "
" STATUS=Processing requests... " ) ;
r = manager_run ( m ) ;
log_debug ( " systemd-machined stopped as pid %lu " , ( unsigned long ) getpid ( ) ) ;
finish :
sd_notify ( false ,
" STATUS=Shutting down... " ) ;
if ( m )
manager_free ( m ) ;
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS ;
}