2010-08-14 21:59:25 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2009-11-18 02:42:52 +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
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 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
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2009-11-18 02:42:52 +03:00
# include <assert.h>
2010-01-21 02:51:37 +03:00
# include <errno.h>
2010-07-17 06:09:28 +04:00
# include <sys/timerfd.h>
# include <sys/epoll.h>
2009-11-18 02:42:52 +03:00
2010-01-30 03:55:42 +03:00
# include "set.h"
# include "unit.h"
2009-11-18 02:42:52 +03:00
# include "macro.h"
2010-01-30 03:55:42 +03:00
# include "strv.h"
# include "load-fragment.h"
# include "load-dropin.h"
2010-01-29 05:18:09 +03:00
# include "log.h"
2010-04-18 05:08:16 +04:00
# include "dbus-job.h"
2009-11-18 02:42:52 +03:00
2010-01-26 23:39:06 +03:00
Job * job_new ( Manager * m , JobType type , Unit * unit ) {
2009-11-18 02:42:52 +03:00
Job * j ;
assert ( m ) ;
assert ( type < _JOB_TYPE_MAX ) ;
2010-01-26 23:39:06 +03:00
assert ( unit ) ;
2009-11-18 02:42:52 +03:00
if ( ! ( j = new0 ( Job , 1 ) ) )
return NULL ;
j - > manager = m ;
j - > id = m - > current_job_id + + ;
j - > type = type ;
2010-01-26 23:39:06 +03:00
j - > unit = unit ;
2009-11-18 02:42:52 +03:00
2010-07-17 06:09:28 +04:00
j - > timer_watch . type = WATCH_INVALID ;
2010-01-20 04:12:51 +03:00
/* We don't link it here, that's what job_dependency() is for */
2009-11-18 02:42:52 +03:00
return j ;
}
void job_free ( Job * j ) {
assert ( j ) ;
/* Detach from next 'bigger' objects */
2010-01-26 21:25:02 +03:00
if ( j - > installed ) {
2011-02-24 04:36:34 +03:00
bus_job_send_removed_signal ( j ) ;
2010-02-05 02:38:41 +03:00
2012-01-15 15:04:08 +04:00
if ( j - > unit - > job = = j ) {
j - > unit - > job = NULL ;
2010-04-21 08:01:13 +04:00
unit_add_to_gc_queue ( j - > unit ) ;
}
2009-11-18 02:42:52 +03:00
hashmap_remove ( j - > manager - > jobs , UINT32_TO_PTR ( j - > id ) ) ;
2010-01-26 21:25:02 +03:00
j - > installed = false ;
2009-11-18 02:42:52 +03:00
}
2010-01-23 03:52:57 +03:00
/* Detach from next 'smaller' objects */
2010-04-06 04:43:58 +04:00
manager_transaction_unlink_job ( j - > manager , j , true ) ;
2009-11-18 02:42:52 +03:00
2010-02-05 02:38:41 +03:00
if ( j - > in_run_queue )
LIST_REMOVE ( Job , run_queue , j - > manager - > run_queue , j ) ;
if ( j - > in_dbus_queue )
LIST_REMOVE ( Job , dbus_queue , j - > manager - > dbus_job_queue , j ) ;
2010-07-17 06:09:28 +04:00
if ( j - > timer_watch . type ! = WATCH_INVALID ) {
assert ( j - > timer_watch . type = = WATCH_JOB_TIMER ) ;
assert ( j - > timer_watch . data . job = = j ) ;
assert ( j - > timer_watch . fd > = 0 ) ;
assert_se ( epoll_ctl ( j - > manager - > epoll_fd , EPOLL_CTL_DEL , j - > timer_watch . fd , NULL ) > = 0 ) ;
close_nointr_nofail ( j - > timer_watch . fd ) ;
}
2010-07-05 02:58:07 +04:00
free ( j - > bus_client ) ;
2009-11-18 02:42:52 +03:00
free ( j ) ;
}
2010-01-19 02:22:34 +03:00
2010-08-10 00:32:30 +04:00
JobDependency * job_dependency_new ( Job * subject , Job * object , bool matters , bool conflicts ) {
2010-01-20 04:12:51 +03:00
JobDependency * l ;
assert ( object ) ;
/* Adds a new job link, which encodes that the 'subject' job
* needs the ' object ' job in some way . If ' subject ' is NULL
* this means the ' anchor ' job ( i . e . the one the user
2011-02-21 17:32:17 +03:00
* explicitly asked for ) is the requester . */
2010-01-20 04:12:51 +03:00
2010-01-20 04:35:46 +03:00
if ( ! ( l = new0 ( JobDependency , 1 ) ) )
2010-01-20 04:12:51 +03:00
return NULL ;
l - > subject = subject ;
l - > object = object ;
l - > matters = matters ;
2010-08-10 00:32:30 +04:00
l - > conflicts = conflicts ;
2010-01-20 04:12:51 +03:00
2010-01-26 09:02:51 +03:00
if ( subject )
LIST_PREPEND ( JobDependency , subject , subject - > subject_list , l ) ;
else
LIST_PREPEND ( JobDependency , subject , object - > manager - > transaction_anchor , l ) ;
2010-01-20 04:12:51 +03:00
2010-01-26 09:02:51 +03:00
LIST_PREPEND ( JobDependency , object , object - > object_list , l ) ;
2010-01-20 04:12:51 +03:00
return l ;
}
void job_dependency_free ( JobDependency * l ) {
assert ( l ) ;
2010-01-26 09:02:51 +03:00
if ( l - > subject )
LIST_REMOVE ( JobDependency , subject , l - > subject - > subject_list , l ) ;
2010-01-20 04:12:51 +03:00
else
2010-01-26 09:02:51 +03:00
LIST_REMOVE ( JobDependency , subject , l - > object - > manager - > transaction_anchor , l ) ;
2010-01-20 04:12:51 +03:00
2010-01-26 09:02:51 +03:00
LIST_REMOVE ( JobDependency , object , l - > object - > object_list , l ) ;
2010-01-20 04:12:51 +03:00
free ( l ) ;
}
2010-01-21 02:51:37 +03:00
void job_dump ( Job * j , FILE * f , const char * prefix ) {
2010-01-19 02:22:34 +03:00
assert ( j ) ;
assert ( f ) ;
2010-05-20 03:14:09 +04:00
if ( ! prefix )
prefix = " " ;
2010-01-20 04:35:46 +03:00
fprintf ( f ,
2010-04-23 22:25:55 +04:00
" %s-> Job %u: \n "
" %s \t Action: %s -> %s \n "
2010-01-23 03:52:57 +03:00
" %s \t State: %s \n "
" %s \t Forced: %s \n " ,
2010-01-20 04:35:46 +03:00
prefix , j - > id ,
2012-01-15 15:04:08 +04:00
prefix , j - > unit - > id , job_type_to_string ( j - > type ) ,
2010-01-30 03:55:42 +03:00
prefix , job_state_to_string ( j - > state ) ,
2010-04-15 05:11:11 +04:00
prefix , yes_no ( j - > override ) ) ;
2010-01-19 02:22:34 +03:00
}
2010-01-20 04:12:51 +03:00
bool job_is_anchor ( Job * j ) {
JobDependency * l ;
assert ( j ) ;
2010-01-26 09:02:51 +03:00
LIST_FOREACH ( object , l , j - > object_list )
2010-01-20 04:12:51 +03:00
if ( ! l - > subject )
return true ;
return false ;
}
2010-01-21 02:51:37 +03:00
static bool types_match ( JobType a , JobType b , JobType c , JobType d ) {
return
( a = = c & & b = = d ) | |
( a = = d & & b = = c ) ;
}
int job_type_merge ( JobType * a , JobType b ) {
if ( * a = = b )
return 0 ;
/* Merging is associative! a merged with b merged with c is
* the same as a merged with c merged with b . */
/* Mergeability is transitive! if a can be merged with b and b
* with c then a also with c */
/* Also, if a merged with b cannot be merged with c, then
* either a or b cannot be merged with c either */
2010-01-23 03:52:57 +03:00
if ( types_match ( * a , b , JOB_START , JOB_VERIFY_ACTIVE ) )
2010-01-21 02:51:37 +03:00
* a = JOB_START ;
else if ( types_match ( * a , b , JOB_START , JOB_RELOAD ) | |
types_match ( * a , b , JOB_START , JOB_RELOAD_OR_START ) | |
2010-01-23 03:52:57 +03:00
types_match ( * a , b , JOB_VERIFY_ACTIVE , JOB_RELOAD_OR_START ) | |
2010-01-21 02:51:37 +03:00
types_match ( * a , b , JOB_RELOAD , JOB_RELOAD_OR_START ) )
* a = JOB_RELOAD_OR_START ;
else if ( types_match ( * a , b , JOB_START , JOB_RESTART ) | |
types_match ( * a , b , JOB_START , JOB_TRY_RESTART ) | |
2010-01-23 03:52:57 +03:00
types_match ( * a , b , JOB_VERIFY_ACTIVE , JOB_RESTART ) | |
2010-01-21 02:51:37 +03:00
types_match ( * a , b , JOB_RELOAD , JOB_RESTART ) | |
types_match ( * a , b , JOB_RELOAD_OR_START , JOB_RESTART ) | |
types_match ( * a , b , JOB_RELOAD_OR_START , JOB_TRY_RESTART ) | |
types_match ( * a , b , JOB_RESTART , JOB_TRY_RESTART ) )
* a = JOB_RESTART ;
2010-01-23 03:52:57 +03:00
else if ( types_match ( * a , b , JOB_VERIFY_ACTIVE , JOB_RELOAD ) )
2010-01-21 02:51:37 +03:00
* a = JOB_RELOAD ;
2010-01-23 03:52:57 +03:00
else if ( types_match ( * a , b , JOB_VERIFY_ACTIVE , JOB_TRY_RESTART ) | |
2010-01-21 02:51:37 +03:00
types_match ( * a , b , JOB_RELOAD , JOB_TRY_RESTART ) )
* a = JOB_TRY_RESTART ;
else
return - EEXIST ;
return 0 ;
}
2010-01-23 03:52:57 +03:00
bool job_type_is_mergeable ( JobType a , JobType b ) {
2010-01-21 02:51:37 +03:00
return job_type_merge ( & a , b ) > = 0 ;
}
bool job_type_is_superset ( JobType a , JobType b ) {
2010-01-23 03:52:57 +03:00
/* Checks whether operation a is a "superset" of b in its
* actions */
2010-01-21 02:51:37 +03:00
if ( a = = b )
return true ;
switch ( a ) {
case JOB_START :
2010-01-23 03:52:57 +03:00
return b = = JOB_VERIFY_ACTIVE ;
2010-01-21 02:51:37 +03:00
case JOB_RELOAD :
2010-01-23 03:52:57 +03:00
return
b = = JOB_VERIFY_ACTIVE ;
2010-01-21 02:51:37 +03:00
case JOB_RELOAD_OR_START :
return
b = = JOB_RELOAD | |
2010-01-23 03:52:57 +03:00
b = = JOB_START | |
b = = JOB_VERIFY_ACTIVE ;
2010-01-21 02:51:37 +03:00
case JOB_RESTART :
return
b = = JOB_START | |
2010-01-23 03:52:57 +03:00
b = = JOB_VERIFY_ACTIVE | |
2010-01-21 02:51:37 +03:00
b = = JOB_RELOAD | |
b = = JOB_RELOAD_OR_START | |
b = = JOB_TRY_RESTART ;
case JOB_TRY_RESTART :
return
2010-01-23 03:52:57 +03:00
b = = JOB_VERIFY_ACTIVE | |
2010-01-21 02:51:37 +03:00
b = = JOB_RELOAD ;
default :
return false ;
}
}
2010-01-21 04:59:12 +03:00
bool job_type_is_conflicting ( JobType a , JobType b ) {
2010-01-21 05:26:34 +03:00
assert ( a > = 0 & & a < _JOB_TYPE_MAX ) ;
assert ( b > = 0 & & b < _JOB_TYPE_MAX ) ;
2010-01-21 04:59:12 +03:00
2010-01-23 03:52:57 +03:00
return ( a = = JOB_STOP ) ! = ( b = = JOB_STOP ) ;
2010-01-21 04:59:12 +03:00
}
2010-01-21 05:26:34 +03:00
2010-04-06 04:39:16 +04:00
bool job_type_is_redundant ( JobType a , UnitActiveState b ) {
switch ( a ) {
case JOB_START :
return
b = = UNIT_ACTIVE | |
2010-07-01 05:34:15 +04:00
b = = UNIT_RELOADING ;
2010-04-06 04:39:16 +04:00
case JOB_STOP :
return
2010-07-01 02:31:53 +04:00
b = = UNIT_INACTIVE | |
2010-08-31 02:23:34 +04:00
b = = UNIT_FAILED ;
2010-04-06 04:39:16 +04:00
case JOB_VERIFY_ACTIVE :
return
b = = UNIT_ACTIVE | |
2010-07-01 05:34:15 +04:00
b = = UNIT_RELOADING ;
2010-04-06 04:39:16 +04:00
case JOB_RELOAD :
return
2010-07-01 05:34:15 +04:00
b = = UNIT_RELOADING ;
2010-04-06 04:39:16 +04:00
case JOB_RELOAD_OR_START :
return
b = = UNIT_ACTIVATING | |
2010-07-01 05:34:15 +04:00
b = = UNIT_RELOADING ;
2010-04-06 04:39:16 +04:00
case JOB_RESTART :
return
b = = UNIT_ACTIVATING ;
case JOB_TRY_RESTART :
return
b = = UNIT_ACTIVATING ;
default :
assert_not_reached ( " Invalid job type " ) ;
}
}
2010-01-23 03:52:57 +03:00
bool job_is_runnable ( Job * j ) {
2010-01-26 06:18:44 +03:00
Iterator i ;
2010-01-26 23:39:06 +03:00
Unit * other ;
2010-01-23 03:52:57 +03:00
assert ( j ) ;
2010-01-26 21:25:02 +03:00
assert ( j - > installed ) ;
2010-01-23 03:52:57 +03:00
2010-01-26 23:39:06 +03:00
/* Checks whether there is any job running for the units this
2010-01-23 03:52:57 +03:00
* job needs to be running after ( in the case of a ' positive '
2011-02-16 23:59:31 +03:00
* job type ) or before ( in the case of a ' negative ' job
* type . */
/* First check if there is an override */
2011-04-06 21:09:33 +04:00
if ( j - > ignore_order )
2011-02-16 23:59:31 +03:00
return true ;
2010-01-23 03:52:57 +03:00
if ( j - > type = = JOB_START | |
j - > type = = JOB_VERIFY_ACTIVE | |
j - > type = = JOB_RELOAD | |
j - > type = = JOB_RELOAD_OR_START ) {
/* Immediate result is that the job is or might be
* started . In this case lets wait for the
* dependencies , regardless whether they are
* starting or stopping something . */
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , j - > unit - > dependencies [ UNIT_AFTER ] , i )
if ( other - > job )
2010-01-23 03:52:57 +03:00
return false ;
}
/* Also, if something else is being stopped and we should
* change state after it , then lets wait . */
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , j - > unit - > dependencies [ UNIT_BEFORE ] , i )
if ( other - > job & &
( other - > job - > type = = JOB_STOP | |
other - > job - > type = = JOB_RESTART | |
other - > job - > type = = JOB_TRY_RESTART ) )
2010-01-23 03:52:57 +03:00
return false ;
/* This means that for a service a and a service b where b
* shall be started after a :
*
* start a + start b → 1 st step start a , 2 nd step start b
* start a + stop b → 1 st step stop b , 2 nd step start a
* stop a + start b → 1 st step stop a , 2 nd step start b
* stop a + stop b → 1 st step stop b , 2 nd step stop a
*
* This has the side effect that restarts are properly
* synchronized too . */
return true ;
}
int job_run_and_invalidate ( Job * j ) {
int r ;
2010-08-13 21:29:21 +04:00
uint32_t id ;
Manager * m ;
2010-01-26 21:25:02 +03:00
2010-01-23 03:52:57 +03:00
assert ( j ) ;
2010-01-26 21:25:02 +03:00
assert ( j - > installed ) ;
2010-01-23 03:52:57 +03:00
2010-01-26 06:18:44 +03:00
if ( j - > in_run_queue ) {
LIST_REMOVE ( Job , run_queue , j - > manager - > run_queue , j ) ;
j - > in_run_queue = false ;
}
2010-01-23 03:52:57 +03:00
if ( j - > state ! = JOB_WAITING )
return 0 ;
2010-01-26 06:18:44 +03:00
if ( ! job_is_runnable ( j ) )
return - EAGAIN ;
2010-01-24 00:56:47 +03:00
j - > state = JOB_RUNNING ;
2010-02-05 02:38:41 +03:00
job_add_to_dbus_queue ( j ) ;
2010-01-24 00:56:47 +03:00
2010-08-13 21:29:21 +04:00
/* While we execute this operation the job might go away (for
* example : because it is replaced by a new , conflicting
* job . ) To make sure we don ' t access a freed job later on we
* store the id here , so that we can verify the job is still
* valid . */
id = j - > id ;
m = j - > manager ;
2010-01-23 03:52:57 +03:00
switch ( j - > type ) {
case JOB_START :
2010-01-26 23:39:06 +03:00
r = unit_start ( j - > unit ) ;
2010-11-14 23:57:10 +03:00
/* If this unit cannot be started, then simply
* wait */
2010-01-23 03:52:57 +03:00
if ( r = = - EBADR )
r = 0 ;
2011-02-23 20:46:57 +03:00
2010-01-23 03:52:57 +03:00
break ;
case JOB_VERIFY_ACTIVE : {
2010-01-26 23:39:06 +03:00
UnitActiveState t = unit_active_state ( j - > unit ) ;
if ( UNIT_IS_ACTIVE_OR_RELOADING ( t ) )
2010-01-23 03:52:57 +03:00
r = - EALREADY ;
2010-01-26 23:39:06 +03:00
else if ( t = = UNIT_ACTIVATING )
2010-01-23 03:52:57 +03:00
r = - EAGAIN ;
else
r = - ENOEXEC ;
break ;
}
case JOB_STOP :
2010-01-26 23:39:06 +03:00
r = unit_stop ( j - > unit ) ;
2010-11-14 23:57:10 +03:00
/* If this unit cannot stopped, then simply
* wait . */
if ( r = = - EBADR )
r = 0 ;
2010-01-23 03:52:57 +03:00
break ;
case JOB_RELOAD :
2010-01-26 23:39:06 +03:00
r = unit_reload ( j - > unit ) ;
2010-01-23 03:52:57 +03:00
break ;
case JOB_RELOAD_OR_START :
2011-03-08 03:43:41 +03:00
if ( unit_active_state ( j - > unit ) = = UNIT_ACTIVE ) {
j - > type = JOB_RELOAD ;
2010-01-26 23:39:06 +03:00
r = unit_reload ( j - > unit ) ;
2011-03-08 03:43:41 +03:00
} else {
j - > type = JOB_START ;
2010-01-26 23:39:06 +03:00
r = unit_start ( j - > unit ) ;
2011-03-08 03:43:41 +03:00
if ( r = = - EBADR )
r = 0 ;
}
2010-01-23 03:52:57 +03:00
break ;
case JOB_RESTART : {
2010-01-26 23:39:06 +03:00
UnitActiveState t = unit_active_state ( j - > unit ) ;
2010-08-31 02:23:34 +04:00
if ( t = = UNIT_INACTIVE | | t = = UNIT_FAILED | | t = = UNIT_ACTIVATING ) {
2010-01-23 03:52:57 +03:00
j - > type = JOB_START ;
2010-01-26 23:39:06 +03:00
r = unit_start ( j - > unit ) ;
2010-01-23 03:52:57 +03:00
} else
2010-01-26 23:39:06 +03:00
r = unit_stop ( j - > unit ) ;
2010-01-23 03:52:57 +03:00
break ;
}
case JOB_TRY_RESTART : {
2010-01-26 23:39:06 +03:00
UnitActiveState t = unit_active_state ( j - > unit ) ;
2010-08-31 02:23:34 +04:00
if ( t = = UNIT_INACTIVE | | t = = UNIT_FAILED | | t = = UNIT_DEACTIVATING )
2010-01-23 03:52:57 +03:00
r = - ENOEXEC ;
2010-01-26 23:39:06 +03:00
else if ( t = = UNIT_ACTIVATING ) {
2010-01-23 03:52:57 +03:00
j - > type = JOB_START ;
2010-01-26 23:39:06 +03:00
r = unit_start ( j - > unit ) ;
2011-03-08 03:43:41 +03:00
} else {
j - > type = JOB_RESTART ;
2010-01-26 23:39:06 +03:00
r = unit_stop ( j - > unit ) ;
2011-03-08 03:43:41 +03:00
}
2010-01-23 03:52:57 +03:00
break ;
}
default :
2010-01-26 09:02:51 +03:00
assert_not_reached ( " Unknown job type " ) ;
2010-01-23 03:52:57 +03:00
}
2010-08-13 21:29:21 +04:00
if ( ( j = manager_get_job ( m , id ) ) ) {
if ( r = = - EALREADY )
2011-02-24 04:36:34 +03:00
r = job_finish_and_invalidate ( j , JOB_DONE ) ;
2011-03-08 03:44:19 +03:00
else if ( r = = - ENOEXEC )
r = job_finish_and_invalidate ( j , JOB_SKIPPED ) ;
2010-08-13 21:29:21 +04:00
else if ( r = = - EAGAIN )
j - > state = JOB_WAITING ;
else if ( r < 0 )
2011-02-24 04:36:34 +03:00
r = job_finish_and_invalidate ( j , JOB_FAILED ) ;
2010-08-13 21:29:21 +04:00
}
2010-01-23 03:52:57 +03:00
return r ;
}
2011-04-16 05:07:38 +04:00
static void job_print_status_message ( Unit * u , JobType t , JobResult result ) {
assert ( u ) ;
if ( t = = JOB_START ) {
switch ( result ) {
case JOB_DONE :
2011-11-10 15:53:39 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF , " Started %s " , unit_description ( u ) ) ;
2011-04-16 05:07:38 +04:00
break ;
case JOB_FAILED :
2012-01-14 00:56:09 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_RED_ON " FAILED " ANSI_HIGHLIGHT_OFF , " Failed to start %s " , unit_description ( u ) ) ;
2012-01-15 15:04:08 +04:00
unit_status_printf ( u , NULL , " See 'systemctl status %s' for details. " , u - > id ) ;
2011-04-16 05:07:38 +04:00
break ;
case JOB_DEPENDENCY :
2012-01-14 00:56:09 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_RED_ON " ABORT " ANSI_HIGHLIGHT_OFF , " Dependency failed. Aborted start of %s " , unit_description ( u ) ) ;
2011-04-16 05:07:38 +04:00
break ;
case JOB_TIMEOUT :
2012-01-14 00:56:09 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF , " Timed out starting %s " , unit_description ( u ) ) ;
2011-04-16 05:07:38 +04:00
break ;
default :
;
}
} else if ( t = = JOB_STOP ) {
switch ( result ) {
case JOB_TIMEOUT :
2012-01-14 00:56:09 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF , " Timed out stopping %s " , unit_description ( u ) ) ;
2011-04-16 05:07:38 +04:00
break ;
case JOB_DONE :
case JOB_FAILED :
2011-11-10 15:53:39 +04:00
unit_status_printf ( u , ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF , " Stopped %s " , unit_description ( u ) ) ;
2011-04-16 05:07:38 +04:00
break ;
default :
;
}
}
}
2011-02-24 04:36:34 +03:00
int job_finish_and_invalidate ( Job * j , JobResult result ) {
2010-01-26 23:39:06 +03:00
Unit * u ;
Unit * other ;
2010-03-31 22:08:05 +04:00
JobType t ;
2010-01-26 06:18:44 +03:00
Iterator i ;
2011-10-17 13:12:12 +04:00
bool recursed = false ;
2010-01-23 03:52:57 +03:00
assert ( j ) ;
2010-01-26 21:25:02 +03:00
assert ( j - > installed ) ;
2010-01-23 03:52:57 +03:00
2010-02-05 02:38:41 +03:00
job_add_to_dbus_queue ( j ) ;
2010-01-29 05:18:09 +03:00
2010-01-26 06:18:44 +03:00
/* Patch restart jobs so that they become normal start jobs */
2011-02-24 04:36:34 +03:00
if ( result = = JOB_DONE & & ( j - > type = = JOB_RESTART | | j - > type = = JOB_TRY_RESTART ) ) {
2010-01-29 05:18:09 +03:00
2010-04-23 22:25:55 +04:00
log_debug ( " Converting job %s/%s -> %s/%s " ,
2012-01-15 15:04:08 +04:00
j - > unit - > id , job_type_to_string ( j - > type ) ,
j - > unit - > id , job_type_to_string ( JOB_START ) ) ;
2010-01-29 05:18:09 +03:00
2010-07-08 02:28:04 +04:00
j - > state = JOB_WAITING ;
2010-01-23 03:52:57 +03:00
j - > type = JOB_START ;
2010-07-21 07:16:31 +04:00
job_add_to_run_queue ( j ) ;
2011-09-21 21:56:15 +04:00
u = j - > unit ;
goto finish ;
2010-01-23 03:52:57 +03:00
}
2011-02-24 04:36:34 +03:00
j - > result = result ;
2010-09-23 17:38:42 +04:00
2012-01-15 15:04:08 +04:00
log_debug ( " Job %s/%s finished, result=%s " , j - > unit - > id , job_type_to_string ( j - > type ) , job_result_to_string ( result ) ) ;
2010-07-08 02:28:04 +04:00
2011-02-24 04:36:34 +03:00
if ( result = = JOB_FAILED )
2010-09-23 17:38:42 +04:00
j - > manager - > n_failed_jobs + + ;
2010-01-26 23:39:06 +03:00
u = j - > unit ;
2010-01-23 03:52:57 +03:00
t = j - > type ;
job_free ( j ) ;
2011-04-16 05:07:38 +04:00
job_print_status_message ( u , t , result ) ;
2010-07-07 02:00:59 +04:00
2010-01-23 03:52:57 +03:00
/* Fail depending jobs on failure */
2011-02-24 04:36:34 +03:00
if ( result ! = JOB_DONE ) {
2010-01-23 03:52:57 +03:00
if ( t = = JOB_START | |
t = = JOB_VERIFY_ACTIVE | |
t = = JOB_RELOAD_OR_START ) {
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , u - > dependencies [ UNIT_REQUIRED_BY ] , i )
if ( other - > job & &
( other - > job - > type = = JOB_START | |
other - > job - > type = = JOB_VERIFY_ACTIVE | |
other - > job - > type = = JOB_RELOAD_OR_START ) ) {
job_finish_and_invalidate ( other - > job , JOB_DEPENDENCY ) ;
2011-10-17 13:12:12 +04:00
recursed = true ;
}
2010-01-23 03:52:57 +03:00
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , u - > dependencies [ UNIT_BOUND_BY ] , i )
if ( other - > job & &
( other - > job - > type = = JOB_START | |
other - > job - > type = = JOB_VERIFY_ACTIVE | |
other - > job - > type = = JOB_RELOAD_OR_START ) ) {
job_finish_and_invalidate ( other - > job , JOB_DEPENDENCY ) ;
2011-10-17 13:12:12 +04:00
recursed = true ;
}
2010-10-29 08:04:42 +04:00
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , u - > dependencies [ UNIT_REQUIRED_BY_OVERRIDABLE ] , i )
if ( other - > job & &
! other - > job - > override & &
( other - > job - > type = = JOB_START | |
other - > job - > type = = JOB_VERIFY_ACTIVE | |
other - > job - > type = = JOB_RELOAD_OR_START ) ) {
job_finish_and_invalidate ( other - > job , JOB_DEPENDENCY ) ;
2011-10-17 13:12:12 +04:00
recursed = true ;
}
2010-01-23 03:52:57 +03:00
} else if ( t = = JOB_STOP ) {
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , u - > dependencies [ UNIT_CONFLICTED_BY ] , i )
if ( other - > job & &
( other - > job - > type = = JOB_START | |
other - > job - > type = = JOB_VERIFY_ACTIVE | |
other - > job - > type = = JOB_RELOAD_OR_START ) ) {
job_finish_and_invalidate ( other - > job , JOB_DEPENDENCY ) ;
2011-10-17 13:12:12 +04:00
recursed = true ;
}
2010-01-23 03:52:57 +03:00
}
}
2011-02-24 05:24:23 +03:00
/* Trigger OnFailure dependencies that are not generated by
* the unit itself . We don ' t tread JOB_CANCELED as failure in
* this context . And JOB_FAILURE is already handled by the
* unit itself . */
2011-04-07 06:11:31 +04:00
if ( result = = JOB_TIMEOUT | | result = = JOB_DEPENDENCY ) {
log_notice ( " Job %s/%s failed with result '%s'. " ,
2012-01-15 15:04:08 +04:00
u - > id ,
2011-04-07 06:11:31 +04:00
job_type_to_string ( t ) ,
job_result_to_string ( result ) ) ;
2011-02-24 05:24:23 +03:00
unit_trigger_on_failure ( u ) ;
2011-04-07 06:11:31 +04:00
}
2011-02-24 05:24:23 +03:00
2011-09-21 21:56:15 +04:00
finish :
2010-01-23 03:52:57 +03:00
/* Try to start the next jobs that can be started */
2012-01-15 15:04:08 +04:00
SET_FOREACH ( other , u - > dependencies [ UNIT_AFTER ] , i )
if ( other - > job )
job_add_to_run_queue ( other - > job ) ;
SET_FOREACH ( other , u - > dependencies [ UNIT_BEFORE ] , i )
if ( other - > job )
job_add_to_run_queue ( other - > job ) ;
2010-01-23 03:52:57 +03:00
2012-01-15 15:04:08 +04:00
manager_check_finished ( u - > manager ) ;
2010-09-21 06:14:38 +04:00
2011-10-17 13:12:12 +04:00
return recursed ;
2010-01-23 03:52:57 +03:00
}
2010-01-26 06:18:44 +03:00
2010-07-17 06:09:28 +04:00
int job_start_timer ( Job * j ) {
struct itimerspec its ;
struct epoll_event ev ;
int fd , r ;
assert ( j ) ;
2012-01-15 15:04:08 +04:00
if ( j - > unit - > job_timeout < = 0 | |
2010-07-17 06:09:28 +04:00
j - > timer_watch . type = = WATCH_JOB_TIMER )
return 0 ;
assert ( j - > timer_watch . type = = WATCH_INVALID ) ;
if ( ( fd = timerfd_create ( CLOCK_MONOTONIC , TFD_NONBLOCK | TFD_CLOEXEC ) ) < 0 ) {
r = - errno ;
goto fail ;
}
zero ( its ) ;
2012-01-15 15:04:08 +04:00
timespec_store ( & its . it_value , j - > unit - > job_timeout ) ;
2010-07-17 06:09:28 +04:00
if ( timerfd_settime ( fd , 0 , & its , NULL ) < 0 ) {
r = - errno ;
goto fail ;
}
zero ( ev ) ;
ev . data . ptr = & j - > timer_watch ;
ev . events = EPOLLIN ;
if ( epoll_ctl ( j - > manager - > epoll_fd , EPOLL_CTL_ADD , fd , & ev ) < 0 ) {
r = - errno ;
goto fail ;
}
j - > timer_watch . type = WATCH_JOB_TIMER ;
j - > timer_watch . fd = fd ;
j - > timer_watch . data . job = j ;
return 0 ;
fail :
if ( fd > = 0 )
close_nointr_nofail ( fd ) ;
return r ;
}
2010-02-05 02:38:41 +03:00
void job_add_to_run_queue ( Job * j ) {
2010-01-26 06:18:44 +03:00
assert ( j ) ;
2010-01-26 21:25:02 +03:00
assert ( j - > installed ) ;
2010-01-26 06:18:44 +03:00
if ( j - > in_run_queue )
return ;
LIST_PREPEND ( Job , run_queue , j - > manager - > run_queue , j ) ;
j - > in_run_queue = true ;
}
2010-01-30 03:55:42 +03:00
2010-02-05 02:38:41 +03:00
void job_add_to_dbus_queue ( Job * j ) {
assert ( j ) ;
assert ( j - > installed ) ;
if ( j - > in_dbus_queue )
return ;
2010-07-05 02:58:07 +04:00
/* We don't check if anybody is subscribed here, since this
* job might just have been created and not yet assigned to a
* connection / client . */
2010-05-16 05:57:07 +04:00
2010-02-05 02:38:41 +03:00
LIST_PREPEND ( Job , dbus_queue , j - > manager - > dbus_job_queue , j ) ;
j - > in_dbus_queue = true ;
}
2010-02-01 05:33:24 +03:00
char * job_dbus_path ( Job * j ) {
char * p ;
assert ( j ) ;
if ( asprintf ( & p , " /org/freedesktop/systemd1/job/%lu " , ( unsigned long ) j - > id ) < 0 )
return NULL ;
return p ;
}
2010-07-17 06:09:28 +04:00
void job_timer_event ( Job * j , uint64_t n_elapsed , Watch * w ) {
assert ( j ) ;
assert ( w = = & j - > timer_watch ) ;
2012-01-15 15:04:08 +04:00
log_warning ( " Job %s/%s timed out. " , j - > unit - > id , job_type_to_string ( j - > type ) ) ;
2011-02-24 04:36:34 +03:00
job_finish_and_invalidate ( j , JOB_TIMEOUT ) ;
2010-07-17 06:09:28 +04:00
}
2010-01-30 03:55:42 +03:00
static const char * const job_state_table [ _JOB_STATE_MAX ] = {
[ JOB_WAITING ] = " waiting " ,
[ JOB_RUNNING ] = " running "
} ;
DEFINE_STRING_TABLE_LOOKUP ( job_state , JobState ) ;
static const char * const job_type_table [ _JOB_TYPE_MAX ] = {
[ JOB_START ] = " start " ,
[ JOB_VERIFY_ACTIVE ] = " verify-active " ,
[ JOB_STOP ] = " stop " ,
[ JOB_RELOAD ] = " reload " ,
[ JOB_RELOAD_OR_START ] = " reload-or-start " ,
[ JOB_RESTART ] = " restart " ,
[ JOB_TRY_RESTART ] = " try-restart " ,
} ;
DEFINE_STRING_TABLE_LOOKUP ( job_type , JobType ) ;
2010-02-03 14:37:42 +03:00
static const char * const job_mode_table [ _JOB_MODE_MAX ] = {
[ JOB_FAIL ] = " fail " ,
2010-04-22 04:42:59 +04:00
[ JOB_REPLACE ] = " replace " ,
2011-02-16 23:59:31 +03:00
[ JOB_ISOLATE ] = " isolate " ,
2011-04-06 21:09:33 +04:00
[ JOB_IGNORE_DEPENDENCIES ] = " ignore-dependencies " ,
[ JOB_IGNORE_REQUIREMENTS ] = " ignore-requirements "
2010-02-03 14:37:42 +03:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( job_mode , JobMode ) ;
2011-02-24 04:36:34 +03:00
static const char * const job_result_table [ _JOB_RESULT_MAX ] = {
[ JOB_DONE ] = " done " ,
[ JOB_CANCELED ] = " canceled " ,
[ JOB_TIMEOUT ] = " timeout " ,
[ JOB_FAILED ] = " failed " ,
2011-03-08 03:44:19 +03:00
[ JOB_DEPENDENCY ] = " dependency " ,
[ JOB_SKIPPED ] = " skipped "
2011-02-24 04:36:34 +03:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( job_result , JobResult ) ;