2009-11-18 00:42:52 +01:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
# include <assert.h>
# include <errno.h>
2010-01-18 23:50:13 +01:00
# include <string.h>
2009-11-18 00:42:52 +01:00
# include "manager.h"
# include "hashmap.h"
# include "macro.h"
# include "strv.h"
2009-11-19 02:52:17 +01:00
# include "load-fragment.h"
2009-11-18 00:42:52 +01:00
Manager * manager_new ( void ) {
Manager * m ;
if ( ! ( m = new0 ( Manager , 1 ) ) )
return NULL ;
if ( ! ( m - > names = hashmap_new ( string_hash_func , string_compare_func ) ) )
goto fail ;
if ( ! ( m - > jobs = hashmap_new ( trivial_hash_func , trivial_compare_func ) ) )
goto fail ;
if ( ! ( m - > jobs_to_add = hashmap_new ( trivial_hash_func , trivial_compare_func ) ) )
goto fail ;
if ( ! ( m - > jobs_to_remove = set_new ( trivial_hash_func , trivial_compare_func ) ) )
goto fail ;
return m ;
fail :
manager_free ( m ) ;
return NULL ;
}
void manager_free ( Manager * m ) {
Name * n ;
assert ( m ) ;
while ( ( n = hashmap_first ( m - > names ) ) )
name_free ( n ) ;
hashmap_free ( m - > names ) ;
hashmap_free ( m - > jobs ) ;
/* FIXME: This is incomplete */
hashmap_free ( m - > jobs_to_add ) ;
set_free ( m - > jobs_to_remove ) ;
free ( m ) ;
}
int manager_add_job ( Manager * m , JobType type , Name * name , JobMode mode , Job * * _ret ) {
Job * ret , * other ;
void * state ;
Name * dep ;
int r ;
assert ( m ) ;
assert ( type < _JOB_TYPE_MAX ) ;
assert ( name ) ;
assert ( mode < _JOB_MODE_MAX ) ;
assert ( _ret ) ;
/* Check for conflicts, first against the jobs we shall
* create */
if ( ( other = hashmap_get ( m - > jobs_to_add , name ) ) ) {
if ( other - > type ! = type )
return - EEXIST ;
} else if ( name - > meta . job ) {
if ( name - > meta . job - > type ! = type ) {
if ( mode = = JOB_FAIL )
return - EEXIST ;
if ( ( r = set_put ( m - > jobs_to_remove , name - > meta . job ) ) < 0 )
return r ;
}
}
if ( ! ( ret = job_new ( m , type , name ) ) )
return - ENOMEM ;
if ( ( r = hashmap_put ( m - > jobs_to_add , name , ret ) ) < 0 )
goto fail ;
if ( type = = JOB_START | | type = = JOB_VERIFY_STARTED | | type = = JOB_RESTART_FINISH ) {
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_REQUIRES ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , type , dep , mode , NULL ) ) < 0 )
goto fail ;
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_SOFT_REQUIRES ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , type , dep , JOB_FAIL , NULL ) ) < 0 )
goto fail ;
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_WANTS ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , type , dep , JOB_FAIL , NULL ) ) < 0 )
goto fail ;
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_REQUISITE ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , JOB_VERIFY_STARTED , dep , mode , NULL ) ) < 0 )
goto fail ;
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_SOFT_REQUISITE ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , JOB_VERIFY_STARTED , dep , JOB_FAIL , NULL ) ) < 0 )
goto fail ;
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_CONFLICTS ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , type , dep , mode , NULL ) ) < 0 )
goto fail ;
} else if ( type = = JOB_STOP | | type = = JOB_RESTART | | type = = JOB_TRY_RESTART ) {
2010-01-18 23:50:13 +01:00
SET_FOREACH ( dep , ret - > name - > meta . dependencies [ NAME_REQUIRED_BY ] , state )
2009-11-18 00:42:52 +01:00
if ( ( r = manager_add_job ( m , type , dep , mode , NULL ) ) < 0 )
goto fail ;
}
if ( _ret )
* _ret = ret ;
return 0 ;
fail :
job_free ( ret ) ;
return r ;
}
Job * manager_get_job ( Manager * m , uint32_t id ) {
assert ( m ) ;
return hashmap_get ( m - > jobs , UINT32_TO_PTR ( id ) ) ;
}
Name * manager_get_name ( Manager * m , const char * name ) {
assert ( m ) ;
assert ( name ) ;
return hashmap_get ( m - > names , name ) ;
}
2010-01-18 23:50:13 +01:00
static int verify_type ( Name * name ) {
char * n ;
void * state ;
2009-11-18 00:42:52 +01:00
assert ( name ) ;
2010-01-18 23:50:13 +01:00
/* Checks that all aliases of this name have the same and valid type */
2009-11-18 00:42:52 +01:00
2010-01-18 23:50:13 +01:00
SET_FOREACH ( n , name - > meta . names , state ) {
2009-11-18 00:42:52 +01:00
NameType t ;
2010-01-18 23:50:13 +01:00
if ( ( t = name_type_from_string ( n ) ) = = _NAME_TYPE_INVALID )
2009-11-18 00:42:52 +01:00
return - EINVAL ;
if ( name - > meta . type = = _NAME_TYPE_INVALID ) {
name - > meta . type = t ;
continue ;
}
if ( name - > meta . type ! = t )
return - EINVAL ;
}
2010-01-18 23:50:13 +01:00
if ( name - > meta . type = = _NAME_TYPE_INVALID )
return - EINVAL ;
2009-11-18 00:42:52 +01:00
return 0 ;
}
2009-11-19 02:52:17 +01:00
static int service_load_sysv ( Service * s ) {
2009-11-18 00:42:52 +01:00
assert ( s ) ;
2009-11-19 02:52:17 +01:00
/* Load service data from SysV init scripts, preferably with
* LSB headers . . . */
2009-11-18 00:42:52 +01:00
return 0 ;
}
2009-11-19 02:52:17 +01:00
static int name_load_fstab ( Name * n ) {
2009-11-18 00:42:52 +01:00
assert ( n ) ;
assert ( n - > meta . type = = NAME_MOUNT | | n - > meta . type = = NAME_AUTOMOUNT ) ;
2009-11-19 02:52:17 +01:00
/* Load mount data from /etc/fstab */
2009-11-18 00:42:52 +01:00
return 0 ;
}
static int snapshot_load ( Snapshot * s ) {
assert ( s ) ;
2009-11-19 02:52:17 +01:00
/* Load snapshots from disk */
return 0 ;
}
static int name_load_dropin ( Name * n ) {
assert ( n ) ;
/* Load dependencies from drop-in directories */
2009-11-18 00:42:52 +01:00
return 0 ;
}
static int load ( Name * name ) {
int r ;
assert ( name ) ;
if ( name - > meta . state ! = NAME_STUB )
return 0 ;
2010-01-18 23:50:13 +01:00
if ( ( r = verify_type ( name ) ) < 0 )
2009-11-18 00:42:52 +01:00
return r ;
if ( name - > meta . type = = NAME_SERVICE ) {
/* Load a .service file */
2009-11-19 02:52:17 +01:00
if ( ( r = name_load_fragment ( name ) ) = = 0 )
2009-11-18 00:42:52 +01:00
goto finish ;
/* Load a classic init script */
if ( r = = - ENOENT )
2009-11-19 02:52:17 +01:00
if ( ( r = service_load_sysv ( SERVICE ( name ) ) ) = = 0 )
2009-11-18 00:42:52 +01:00
goto finish ;
} else if ( name - > meta . type = = NAME_MOUNT | |
name - > meta . type = = NAME_AUTOMOUNT ) {
2009-11-19 02:52:17 +01:00
if ( ( r = name_load_fstab ( name ) ) = = 0 )
2009-11-18 00:42:52 +01:00
goto finish ;
} else if ( name - > meta . type = = NAME_SNAPSHOT ) {
if ( ( r = snapshot_load ( SNAPSHOT ( name ) ) ) = = 0 )
goto finish ;
} else {
2009-11-19 02:52:17 +01:00
if ( ( r = name_load_fragment ( name ) ) = = 0 )
2009-11-18 00:42:52 +01:00
goto finish ;
}
name - > meta . state = NAME_FAILED ;
return r ;
finish :
2009-11-19 02:52:17 +01:00
if ( ( r = name_load_dropin ( name ) ) < 0 )
return r ;
2009-11-18 00:42:52 +01:00
name - > meta . state = NAME_LOADED ;
return 0 ;
}
static int dispatch_load_queue ( Manager * m ) {
Meta * meta ;
assert ( m ) ;
2009-11-19 02:52:17 +01:00
/* Make sure we are not run recursively */
if ( m - > dispatching_load_queue )
return 0 ;
m - > dispatching_load_queue = true ;
2009-11-18 00:42:52 +01:00
/* Dispatches the load queue. Takes a name from the queue and
* tries to load its data until the queue is empty */
while ( ( meta = m - > load_queue ) ) {
load ( NAME ( meta ) ) ;
LIST_REMOVE ( Meta , m - > load_queue , meta ) ;
}
2009-11-19 02:52:17 +01:00
m - > dispatching_load_queue = false ;
2009-11-18 00:42:52 +01:00
return 0 ;
}
int manager_load_name ( Manager * m , const char * name , Name * * _ret ) {
Name * ret ;
NameType t ;
int r ;
2010-01-18 23:50:13 +01:00
char * n ;
2009-11-18 00:42:52 +01:00
assert ( m ) ;
assert ( name ) ;
assert ( _ret ) ;
2009-11-19 02:52:17 +01:00
if ( ! name_is_valid ( name ) )
return - EINVAL ;
/* This will load the service information files, but not actually
* start any services or anything */
2009-11-18 00:42:52 +01:00
if ( ( ret = manager_get_name ( m , name ) ) )
goto finish ;
if ( ( t = name_type_from_string ( name ) ) = = _NAME_TYPE_INVALID )
return - EINVAL ;
if ( ! ( ret = name_new ( m ) ) )
return - ENOMEM ;
ret - > meta . type = t ;
2010-01-18 23:50:13 +01:00
if ( ! ( n = strdup ( name ) ) ) {
name_free ( ret ) ;
return - ENOMEM ;
}
if ( set_put ( ret - > meta . names , n ) < 0 ) {
2009-11-18 00:42:52 +01:00
name_free ( ret ) ;
2010-01-18 23:50:13 +01:00
free ( n ) ;
2009-11-18 00:42:52 +01:00
return - ENOMEM ;
}
if ( ( r = name_link ( ret ) ) < 0 ) {
name_free ( ret ) ;
return r ;
}
/* At this point the new entry is created and linked. However,
* not loaded . Now load this entry and all its dependencies
* recursively */
dispatch_load_queue ( m ) ;
finish :
* _ret = ret ;
return 0 ;
}
2010-01-19 00:22:34 +01:00
void manager_dump_jobs ( Manager * s , FILE * f ) {
void * state ;
Job * j ;
assert ( s ) ;
assert ( f ) ;
HASHMAP_FOREACH ( j , s - > jobs , state )
job_dump ( j , f ) ;
}
void manager_dump_names ( Manager * s , FILE * f ) {
void * state ;
Name * n ;
assert ( s ) ;
assert ( f ) ;
HASHMAP_FOREACH ( n , s - > names , state )
name_dump ( n , f ) ;
}