2009-11-20 01:13:20 +03:00
/*-*- Mode: C; c-basic-offset: 8 -*-*/
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/>.
* * */
2010-01-26 23:39:06 +03:00
# include <linux/oom.h>
2009-11-20 01:13:20 +03:00
# include <assert.h>
# include <errno.h>
# include <string.h>
2010-01-26 23:39:06 +03:00
# include <unistd.h>
# include <fcntl.h>
2010-01-30 03:55:42 +03:00
# include <sched.h>
# include <sys/prctl.h>
2009-11-20 01:13:20 +03:00
2010-01-26 23:39:06 +03:00
# include "unit.h"
2009-11-20 01:13:20 +03:00
# include "strv.h"
# include "conf-parser.h"
# include "load-fragment.h"
2010-01-20 21:19:53 +03:00
# include "log.h"
2010-01-29 22:46:22 +03:00
# include "ioprio.h"
2010-01-30 03:55:42 +03:00
# include "securebits.h"
# include "missing.h"
2010-04-15 05:11:11 +04:00
# include "unit-name.h"
2009-11-20 01:13:20 +03:00
2010-04-13 04:22:41 +04:00
# define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
static int function ( \
const char * filename , \
unsigned line , \
const char * section , \
const char * lvalue , \
const char * rvalue , \
void * data , \
void * userdata ) { \
\
type * i = data , x ; \
\
assert ( filename ) ; \
assert ( lvalue ) ; \
assert ( rvalue ) ; \
assert ( data ) ; \
\
if ( ( x = name # # _from_string ( rvalue ) ) < 0 ) { \
log_error ( " [%s:%u] " msg " : %s " , filename , line , rvalue ) ; \
return - EBADMSG ; \
} \
\
* i = x ; \
\
return 0 ; \
}
2010-01-19 04:56:37 +03:00
static int config_parse_deps (
2009-11-20 01:13:20 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-26 23:39:06 +03:00
UnitDependency d = PTR_TO_UINT ( data ) ;
Unit * u = userdata ;
2009-11-20 01:13:20 +03:00
char * w ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
2010-02-14 03:07:36 +03:00
FOREACH_WORD ( w , l , rvalue , state ) {
2010-04-15 05:11:11 +04:00
char * t , * k ;
2009-11-20 01:13:20 +03:00
int r ;
if ( ! ( t = strndup ( w , l ) ) )
return - ENOMEM ;
2010-04-15 05:11:11 +04:00
k = unit_name_printf ( u , t ) ;
2009-11-20 01:13:20 +03:00
free ( t ) ;
2010-04-15 05:11:11 +04:00
if ( ! k )
return - ENOMEM ;
r = unit_add_dependency_by_name ( u , d , k , NULL ) ;
free ( k ) ;
2009-11-20 01:13:20 +03:00
if ( r < 0 )
return r ;
}
return 0 ;
}
2010-01-19 04:56:37 +03:00
static int config_parse_names (
2010-01-19 01:50:13 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-26 23:39:06 +03:00
Unit * u = userdata ;
2010-01-19 01:50:13 +03:00
char * w ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-02-14 03:07:36 +03:00
FOREACH_WORD ( w , l , rvalue , state ) {
2010-04-15 05:11:11 +04:00
char * t , * k ;
2010-01-19 01:50:13 +03:00
int r ;
if ( ! ( t = strndup ( w , l ) ) )
return - ENOMEM ;
2010-04-15 05:11:11 +04:00
k = unit_name_printf ( u , t ) ;
2010-01-19 01:50:13 +03:00
free ( t ) ;
2010-04-06 04:43:58 +04:00
2010-04-15 05:11:11 +04:00
if ( ! k )
return - ENOMEM ;
r = unit_merge_by_name ( u , k ) ;
free ( k ) ;
2010-04-06 04:43:58 +04:00
if ( r < 0 )
return r ;
2010-01-19 01:50:13 +03:00
}
return 0 ;
}
2010-01-19 04:56:37 +03:00
static int config_parse_listen (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-20 21:19:53 +03:00
int r ;
2010-01-23 05:35:54 +03:00
SocketPort * p ;
Socket * s ;
2010-01-20 21:19:53 +03:00
2010-01-19 04:56:37 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-01-23 05:35:54 +03:00
s = ( Socket * ) data ;
if ( ! ( p = new0 ( SocketPort , 1 ) ) )
return - ENOMEM ;
if ( streq ( lvalue , " ListenFIFO " ) ) {
p - > type = SOCKET_FIFO ;
if ( ! ( p - > path = strdup ( rvalue ) ) ) {
free ( p ) ;
return - ENOMEM ;
}
} else {
p - > type = SOCKET_SOCKET ;
if ( ( r = socket_address_parse ( & p - > address , rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse address value: %s " , filename , line , rvalue ) ;
free ( p ) ;
return r ;
}
if ( streq ( lvalue , " ListenStream " ) )
p - > address . type = SOCK_STREAM ;
else if ( streq ( lvalue , " ListenDatagram " ) )
p - > address . type = SOCK_DGRAM ;
else {
assert ( streq ( lvalue , " ListenSequentialPacket " ) ) ;
p - > address . type = SOCK_SEQPACKET ;
}
if ( socket_address_family ( & p - > address ) ! = AF_LOCAL & & p - > address . type = = SOCK_SEQPACKET ) {
free ( p ) ;
return - EPROTONOSUPPORT ;
}
2010-01-20 21:19:53 +03:00
}
2010-01-23 05:35:54 +03:00
p - > fd = - 1 ;
2010-01-26 06:18:44 +03:00
LIST_PREPEND ( SocketPort , port , s - > ports , p ) ;
2010-01-23 05:35:54 +03:00
2010-01-20 21:19:53 +03:00
return 0 ;
2010-01-19 04:56:37 +03:00
}
2010-01-26 06:18:44 +03:00
static int config_parse_socket_bind (
2010-01-19 04:56:37 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-23 05:35:54 +03:00
int r ;
Socket * s ;
2010-01-19 04:56:37 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-01-23 05:35:54 +03:00
s = ( Socket * ) data ;
if ( ( r = parse_boolean ( rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse bind IPv6 only value: %s " , filename , line , rvalue ) ;
return r ;
2010-01-20 21:19:53 +03:00
}
2010-01-19 04:56:37 +03:00
2010-01-23 05:35:54 +03:00
s - > bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH ;
2010-01-19 04:56:37 +03:00
return 0 ;
}
2010-01-26 06:18:44 +03:00
static int config_parse_nice (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-28 04:53:56 +03:00
ExecContext * c = data ;
int priority , r ;
2010-01-26 06:18:44 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atoi ( rvalue , & priority ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse nice priority: %s " , filename , line , rvalue ) ;
return r ;
}
if ( priority < PRIO_MIN | | priority > = PRIO_MAX ) {
log_error ( " [%s:%u] Nice priority out of range: %s " , filename , line , rvalue ) ;
return - ERANGE ;
}
2010-01-28 04:53:56 +03:00
c - > nice = priority ;
c - > nice_set = false ;
2010-01-26 06:18:44 +03:00
return 0 ;
}
static int config_parse_oom_adjust (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-28 04:53:56 +03:00
ExecContext * c = data ;
int oa , r ;
2010-01-26 06:18:44 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atoi ( rvalue , & oa ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse OOM adjust value: %s " , filename , line , rvalue ) ;
return r ;
}
if ( oa < OOM_DISABLE | | oa > OOM_ADJUST_MAX ) {
log_error ( " [%s:%u] OOM adjust value out of range: %s " , filename , line , rvalue ) ;
return - ERANGE ;
}
2010-01-28 04:53:56 +03:00
c - > oom_adjust = oa ;
c - > oom_adjust_set = true ;
2010-01-26 06:18:44 +03:00
return 0 ;
}
2010-02-12 04:02:14 +03:00
static int config_parse_mode (
2010-01-26 06:18:44 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
mode_t * m = data ;
long l ;
char * x = NULL ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
errno = 0 ;
l = strtol ( rvalue , & x , 8 ) ;
if ( ! x | | * x | | errno ) {
2010-02-12 04:02:14 +03:00
log_error ( " [%s:%u] Failed to parse mode value: %s " , filename , line , rvalue ) ;
2010-01-26 06:18:44 +03:00
return errno ? - errno : - EINVAL ;
}
2010-02-12 04:02:14 +03:00
if ( l < 0000 | | l > 07777 ) {
log_error ( " [%s:%u] mode value out of range: %s " , filename , line , rvalue ) ;
2010-01-26 06:18:44 +03:00
return - ERANGE ;
}
* m = ( mode_t ) l ;
return 0 ;
}
static int config_parse_exec (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-02-14 03:05:55 +03:00
ExecCommand * * e = data , * nce = NULL ;
2010-01-26 06:18:44 +03:00
char * * n ;
char * w ;
unsigned k ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
k = 0 ;
FOREACH_WORD_QUOTED ( w , l , rvalue , state )
k + + ;
if ( ! ( n = new ( char * , k + 1 ) ) )
return - ENOMEM ;
2010-01-26 09:02:51 +03:00
k = 0 ;
2010-01-26 06:18:44 +03:00
FOREACH_WORD_QUOTED ( w , l , rvalue , state )
if ( ! ( n [ k + + ] = strndup ( w , l ) ) )
goto fail ;
n [ k ] = NULL ;
2010-01-27 02:15:56 +03:00
if ( ! n [ 0 ] | | ! path_is_absolute ( n [ 0 ] ) ) {
2010-01-26 06:18:44 +03:00
log_error ( " [%s:%u] Invalid executable path in command line: %s " , filename , line , rvalue ) ;
strv_free ( n ) ;
return - EINVAL ;
}
if ( ! ( nce = new0 ( ExecCommand , 1 ) ) )
goto fail ;
nce - > argv = n ;
if ( ! ( nce - > path = strdup ( n [ 0 ] ) ) )
goto fail ;
2010-02-14 03:05:55 +03:00
exec_command_append_list ( e , nce ) ;
2010-01-26 06:18:44 +03:00
return 0 ;
fail :
for ( ; k > 0 ; k - - )
free ( n [ k - 1 ] ) ;
free ( n ) ;
free ( nce ) ;
return - ENOMEM ;
}
static int config_parse_usec (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
usec_t * usec = data ;
unsigned long long u ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atollu ( rvalue , & u ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse time value: %s " , filename , line , rvalue ) ;
return r ;
}
/* We actually assume the user configures seconds. Later on we
* might choose to support suffixes for time values , to
* configure bigger or smaller units */
* usec = u * USEC_PER_SEC ;
return 0 ;
}
2010-04-13 04:22:41 +04:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_service_type , service_type , ServiceType , " Failed to parse service type " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_service_restart , service_restart , ServiceRestart , " Failed to parse service restart specifier " ) ;
2010-01-26 06:18:44 +03:00
2010-02-03 16:21:48 +03:00
static int config_parse_bindtodevice (
2010-01-27 06:31:52 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
Socket * s = data ;
char * n ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( rvalue [ 0 ] & & ! streq ( rvalue , " * " ) ) {
if ( ! ( n = strdup ( rvalue ) ) )
return - ENOMEM ;
} else
n = NULL ;
free ( s - > bind_to_device ) ;
s - > bind_to_device = n ;
return 0 ;
}
2010-04-13 04:22:41 +04:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_output , exec_output , ExecOutput , " Failed to parse output specifier " ) ;
DEFINE_CONFIG_PARSE_ENUM ( config_parse_input , exec_input , ExecInput , " Failed to parse input specifier " ) ;
2010-01-26 23:39:06 +03:00
2010-02-03 16:21:48 +03:00
static int config_parse_facility (
2010-01-28 04:06:20 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 03:55:42 +03:00
int * o = data , x ;
2010-01-28 04:06:20 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-04-13 04:22:41 +04:00
if ( ( x = log_facility_from_string ( rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse log facility: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
2010-01-30 03:55:42 +03:00
* o = LOG_MAKEPRI ( x , LOG_PRI ( * o ) ) ;
2010-01-28 04:06:20 +03:00
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_level (
2010-01-28 04:06:20 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 03:55:42 +03:00
int * o = data , x ;
2010-01-28 04:06:20 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-04-13 04:22:41 +04:00
if ( ( x = log_level_from_string ( rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse log level: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
2010-01-28 04:06:20 +03:00
2010-01-30 03:55:42 +03:00
* o = LOG_MAKEPRI ( LOG_FAC ( * o ) , x ) ;
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_io_class (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
int x ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-04-13 04:22:41 +04:00
if ( ( x = ioprio_class_from_string ( rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse IO scheduling class: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
2010-01-30 03:55:42 +03:00
c - > ioprio = IOPRIO_PRIO_VALUE ( x , IOPRIO_PRIO_DATA ( c - > ioprio ) ) ;
c - > ioprio_set = true ;
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_io_priority (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
int i ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( safe_atoi ( rvalue , & i ) < 0 | | i < 0 | | i > = IOPRIO_BE_NR ) {
log_error ( " [%s:%u] Failed to parse io priority: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
2010-01-28 04:06:20 +03:00
}
2010-01-30 03:55:42 +03:00
c - > ioprio = IOPRIO_PRIO_VALUE ( IOPRIO_PRIO_CLASS ( c - > ioprio ) , i ) ;
c - > ioprio_set = true ;
2010-01-28 04:06:20 +03:00
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_cpu_sched_policy (
2010-01-29 22:46:22 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-30 03:55:42 +03:00
ExecContext * c = data ;
int x ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-04-13 04:22:41 +04:00
if ( ( x = sched_policy_from_string ( rvalue ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse CPU scheduling policy: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
2010-01-30 03:55:42 +03:00
c - > cpu_sched_policy = x ;
c - > cpu_sched_set = true ;
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_cpu_sched_prio (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
2010-01-29 22:46:22 +03:00
ExecContext * c = data ;
int i ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-01-30 03:55:42 +03:00
/* On Linux RR/FIFO have the same range */
if ( safe_atoi ( rvalue , & i ) < 0 | | i < sched_get_priority_min ( SCHED_RR ) | | i > sched_get_priority_max ( SCHED_RR ) ) {
log_error ( " [%s:%u] Failed to parse CPU scheduling priority: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
2010-01-29 22:46:22 +03:00
2010-01-30 03:55:42 +03:00
c - > cpu_sched_priority = i ;
c - > cpu_sched_set = true ;
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_cpu_affinity (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
char * w ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-02-14 03:07:36 +03:00
FOREACH_WORD ( w , l , rvalue , state ) {
2010-01-30 03:55:42 +03:00
char * t ;
int r ;
unsigned cpu ;
if ( ! ( t = strndup ( w , l ) ) )
return - ENOMEM ;
r = safe_atou ( t , & cpu ) ;
free ( t ) ;
if ( r < 0 | | cpu > = CPU_SETSIZE ) {
log_error ( " [%s:%u] Failed to parse CPU affinity: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
2010-01-29 22:46:22 +03:00
}
2010-01-30 03:55:42 +03:00
CPU_SET ( cpu , & c - > cpu_affinity ) ;
2010-01-29 22:46:22 +03:00
}
2010-01-30 03:55:42 +03:00
c - > cpu_affinity_set = true ;
2010-01-29 22:46:22 +03:00
2010-01-30 03:55:42 +03:00
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_capabilities (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
cap_t cap ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ! ( cap = cap_from_text ( rvalue ) ) ) {
if ( errno = = ENOMEM )
return - ENOMEM ;
log_error ( " [%s:%u] Failed to parse capabilities: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
if ( c - > capabilities )
cap_free ( c - > capabilities ) ;
c - > capabilities = cap ;
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_secure_bits (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
char * w ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-02-14 03:07:36 +03:00
FOREACH_WORD ( w , l , rvalue , state ) {
2010-01-30 03:55:42 +03:00
if ( first_word ( w , " keep-caps " ) )
c - > secure_bits | = SECURE_KEEP_CAPS ;
else if ( first_word ( w , " keep-caps-locked " ) )
c - > secure_bits | = SECURE_KEEP_CAPS_LOCKED ;
else if ( first_word ( w , " no-setuid-fixup " ) )
c - > secure_bits | = SECURE_NO_SETUID_FIXUP ;
else if ( first_word ( w , " no-setuid-fixup-locked " ) )
c - > secure_bits | = SECURE_NO_SETUID_FIXUP_LOCKED ;
else if ( first_word ( w , " noroot " ) )
c - > secure_bits | = SECURE_NOROOT ;
else if ( first_word ( w , " noroot-locked " ) )
c - > secure_bits | = SECURE_NOROOT_LOCKED ;
2010-01-29 22:46:22 +03:00
else {
2010-01-30 03:55:42 +03:00
log_error ( " [%s:%u] Failed to parse secure bits: %s " , filename , line , rvalue ) ;
2010-01-29 22:46:22 +03:00
return - EBADMSG ;
}
}
2010-01-30 03:55:42 +03:00
return 0 ;
}
2010-02-03 16:21:48 +03:00
static int config_parse_bounding_set (
2010-01-30 03:55:42 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
char * w ;
size_t l ;
char * state ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-02-14 03:07:36 +03:00
FOREACH_WORD ( w , l , rvalue , state ) {
2010-01-30 03:55:42 +03:00
char * t ;
int r ;
cap_value_t cap ;
if ( ! ( t = strndup ( w , l ) ) )
return - ENOMEM ;
r = cap_from_name ( t , & cap ) ;
free ( t ) ;
if ( r < 0 ) {
log_error ( " [%s:%u] Failed to parse capability bounding set: %s " , filename , line , rvalue ) ;
return - EBADMSG ;
}
c - > capability_bounding_set_drop | = 1 < < cap ;
}
2010-01-29 22:46:22 +03:00
return 0 ;
}
2010-01-30 03:55:42 +03:00
static int config_parse_timer_slack_ns (
2010-01-29 22:46:22 +03:00
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
ExecContext * c = data ;
2010-01-30 03:55:42 +03:00
unsigned long u ;
int r ;
2010-01-29 22:46:22 +03:00
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
2010-01-30 03:55:42 +03:00
if ( ( r = safe_atolu ( rvalue , & u ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse time slack value: %s " , filename , line , rvalue ) ;
return r ;
2010-01-29 22:46:22 +03:00
}
2010-01-30 03:55:42 +03:00
c - > timer_slack_ns = u ;
return 0 ;
}
static int config_parse_limit (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
struct rlimit * * rl = data ;
unsigned long long u ;
int r ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atollu ( rvalue , & u ) ) < 0 ) {
log_error ( " [%s:%u] Failed to parse resource value: %s " , filename , line , rvalue ) ;
return r ;
}
if ( ! * rl )
if ( ! ( * rl = new ( struct rlimit , 1 ) ) )
return - ENOMEM ;
2010-01-29 22:46:22 +03:00
2010-01-30 03:55:42 +03:00
( * rl ) - > rlim_cur = ( * rl ) - > rlim_max = ( rlim_t ) u ;
2010-01-29 22:46:22 +03:00
return 0 ;
}
2010-03-31 18:29:55 +04:00
static int config_parse_cgroup (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
Unit * u = userdata ;
char * w ;
size_t l ;
char * state ;
FOREACH_WORD ( w , l , rvalue , state ) {
char * t ;
int r ;
if ( ! ( t = strndup ( w , l ) ) )
return - ENOMEM ;
r = unit_add_cgroup_from_text ( u , t ) ;
free ( t ) ;
if ( r < 0 )
return r ;
}
return 0 ;
}
2010-04-06 04:40:10 +04:00
static int config_parse_sysv_priority (
const char * filename ,
unsigned line ,
const char * section ,
const char * lvalue ,
const char * rvalue ,
void * data ,
void * userdata ) {
int * priority = data ;
int r , i ;
assert ( filename ) ;
assert ( lvalue ) ;
assert ( rvalue ) ;
assert ( data ) ;
if ( ( r = safe_atoi ( rvalue , & i ) ) < 0 | | i < 0 ) {
log_error ( " [%s:%u] Failed to parse SysV start priority: %s " , filename , line , rvalue ) ;
return r ;
}
* priority = ( int ) i ;
return 0 ;
}
2010-04-13 04:22:41 +04:00
DEFINE_CONFIG_PARSE_ENUM ( config_parse_kill_mode , kill_mode , KillMode , " Failed to parse kill mode " ) ;
2010-04-08 02:52:14 +04:00
2010-01-28 04:06:20 +03:00
# define FOLLOW_MAX 8
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
static int open_follow ( char * * filename , FILE * * _f , Set * names , char * * _final ) {
2010-01-27 02:15:56 +03:00
unsigned c = 0 ;
2010-01-26 23:39:06 +03:00
int fd , r ;
FILE * f ;
2010-01-27 02:15:56 +03:00
char * id = NULL ;
2010-01-26 23:39:06 +03:00
assert ( filename ) ;
assert ( * filename ) ;
assert ( _f ) ;
assert ( names ) ;
2010-01-27 02:15:56 +03:00
/* This will update the filename pointer if the loaded file is
* reached by a symlink . The old string will be freed . */
2010-01-26 23:39:06 +03:00
2010-01-27 02:15:56 +03:00
for ( ; ; ) {
2010-01-26 23:39:06 +03:00
char * target , * k , * name ;
2010-01-27 02:15:56 +03:00
if ( c + + > = FOLLOW_MAX )
return - ELOOP ;
2010-01-29 04:07:41 +03:00
path_kill_slashes ( * filename ) ;
2010-01-26 23:39:06 +03:00
/* Add the file name we are currently looking at to
* the names of this unit */
2010-01-27 02:15:56 +03:00
name = file_name_from_path ( * filename ) ;
if ( ! ( id = set_get ( names , name ) ) ) {
2010-01-26 23:39:06 +03:00
2010-01-27 02:15:56 +03:00
if ( ! ( id = strdup ( name ) ) )
return - ENOMEM ;
2010-01-26 23:39:06 +03:00
2010-01-27 02:15:56 +03:00
if ( ( r = set_put ( names , id ) ) < 0 ) {
free ( id ) ;
return r ;
2010-01-26 23:39:06 +03:00
}
}
2010-01-27 02:15:56 +03:00
/* Try to open the file name, but don't if its a symlink */
if ( ( fd = open ( * filename , O_RDONLY | O_CLOEXEC | O_NOCTTY | O_NOFOLLOW ) ) > = 0 )
2010-01-26 23:39:06 +03:00
break ;
2010-01-27 02:15:56 +03:00
if ( errno ! = ELOOP )
return - errno ;
2010-01-26 23:39:06 +03:00
/* Hmm, so this is a symlink. Let's read the name, and follow it manually */
2010-01-27 02:15:56 +03:00
if ( ( r = readlink_malloc ( * filename , & target ) ) < 0 )
return r ;
2010-01-26 23:39:06 +03:00
2010-01-28 00:39:10 +03:00
k = file_in_same_dir ( * filename , target ) ;
2010-01-26 23:39:06 +03:00
free ( target ) ;
2010-01-27 02:15:56 +03:00
if ( ! k )
return - ENOMEM ;
2010-01-26 23:39:06 +03:00
2010-01-27 02:15:56 +03:00
free ( * filename ) ;
* filename = k ;
2010-01-26 23:39:06 +03:00
}
if ( ! ( f = fdopen ( fd , " r " ) ) ) {
r = - errno ;
2010-04-15 05:11:11 +04:00
close_nointr_nofail ( fd ) ;
2010-01-27 02:15:56 +03:00
return r ;
2010-01-26 23:39:06 +03:00
}
* _f = f ;
2010-04-15 05:11:11 +04:00
* _final = id ;
2010-01-27 02:15:56 +03:00
return 0 ;
2010-01-26 23:39:06 +03:00
}
2010-04-06 04:43:58 +04:00
static int merge_by_names ( Unit * * u , Set * names , const char * id ) {
char * k ;
int r ;
assert ( u ) ;
assert ( * u ) ;
assert ( names ) ;
/* Let's try to add in all symlink names we found */
while ( ( k = set_steal_first ( names ) ) ) {
/* First try to merge in the other name into our
* unit */
if ( ( r = unit_merge_by_name ( * u , k ) ) < 0 ) {
Unit * other ;
/* Hmm, we couldn't merge the other unit into
* ours ? Then let ' s try it the other way
* round */
other = manager_get_unit ( ( * u ) - > meta . manager , k ) ;
free ( k ) ;
if ( other )
if ( ( r = unit_merge ( other , * u ) ) > = 0 ) {
* u = other ;
return merge_by_names ( u , names , NULL ) ;
}
return r ;
}
if ( id = = k )
unit_choose_id ( * u , id ) ;
free ( k ) ;
}
return 0 ;
}
2010-04-10 19:53:17 +04:00
static void dump_items ( FILE * f , const ConfigItem * items ) {
const ConfigItem * i ;
const char * prev_section = NULL ;
bool not_first = false ;
struct {
ConfigParserCallback callback ;
const char * rvalue ;
} table [ ] = {
{ config_parse_int , " INTEGER " } ,
{ config_parse_unsigned , " UNSIGNED " } ,
{ config_parse_size , " SIZE " } ,
{ config_parse_bool , " BOOLEAN " } ,
{ config_parse_string , " STRING " } ,
{ config_parse_path , " PATH " } ,
{ config_parse_strv , " STRING [...] " } ,
{ config_parse_nice , " NICE " } ,
{ config_parse_oom_adjust , " OOMADJUST " } ,
{ config_parse_io_class , " IOCLASS " } ,
{ config_parse_io_priority , " IOPRIORITY " } ,
{ config_parse_cpu_sched_policy , " CPUSCHEDPOLICY " } ,
{ config_parse_cpu_sched_prio , " CPUSCHEDPRIO " } ,
{ config_parse_cpu_affinity , " CPUAFFINITY " } ,
{ config_parse_mode , " MODE " } ,
{ config_parse_output , " OUTPUT " } ,
{ config_parse_input , " INPUT " } ,
{ config_parse_facility , " FACILITY " } ,
{ config_parse_level , " LEVEL " } ,
{ config_parse_capabilities , " CAPABILITIES " } ,
{ config_parse_secure_bits , " SECUREBITS " } ,
{ config_parse_bounding_set , " BOUNDINGSET " } ,
{ config_parse_timer_slack_ns , " TIMERSLACK " } ,
{ config_parse_limit , " LIMIT " } ,
{ config_parse_cgroup , " CGROUP [...] " } ,
{ config_parse_deps , " UNIT [...] " } ,
{ config_parse_names , " UNIT [...] " } ,
{ config_parse_exec , " PATH [ARGUMENT [...]] " } ,
{ config_parse_service_type , " SERVICETYPE " } ,
{ config_parse_service_restart , " SERVICERESTART " } ,
{ config_parse_sysv_priority , " SYSVPRIORITY " } ,
{ config_parse_kill_mode , " KILLMODE " } ,
{ config_parse_listen , " SOCKET [...] " } ,
{ config_parse_socket_bind , " SOCKETBIND " } ,
{ config_parse_bindtodevice , " NETWORKINTERFACE " }
} ;
assert ( f ) ;
assert ( items ) ;
for ( i = items ; i - > lvalue ; i + + ) {
unsigned j ;
const char * rvalue = " OTHER " ;
if ( ! streq_ptr ( i - > section , prev_section ) ) {
if ( ! not_first )
not_first = true ;
else
fputc ( ' \n ' , f ) ;
fprintf ( f , " [%s] \n " , i - > section ) ;
prev_section = i - > section ;
}
for ( j = 0 ; j < ELEMENTSOF ( table ) ; j + + )
if ( i - > parse = = table [ j ] . callback ) {
rvalue = table [ j ] . rvalue ;
break ;
}
fprintf ( f , " %s=%s \n " , i - > lvalue , rvalue ) ;
}
}
static int load_from_path ( Unit * u , const char * path ) {
2010-01-26 23:39:06 +03:00
static const char * const section_table [ _UNIT_TYPE_MAX ] = {
[ UNIT_SERVICE ] = " Service " ,
[ UNIT_TIMER ] = " Timer " ,
[ UNIT_SOCKET ] = " Socket " ,
[ UNIT_TARGET ] = " Target " ,
[ UNIT_DEVICE ] = " Device " ,
[ UNIT_MOUNT ] = " Mount " ,
[ UNIT_AUTOMOUNT ] = " Automount " ,
[ UNIT_SNAPSHOT ] = " Snapshot "
2010-01-19 04:56:37 +03:00
} ;
2010-01-26 06:18:44 +03:00
# define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
2010-01-29 22:46:22 +03:00
{ " WorkingDirectory " , config_parse_path , & ( context ) . working_directory , section } , \
{ " RootDirectory " , config_parse_path , & ( context ) . root_directory , section } , \
2010-01-27 04:16:11 +03:00
{ " User " , config_parse_string , & ( context ) . user , section } , \
{ " Group " , config_parse_string , & ( context ) . group , section } , \
{ " SupplementaryGroups " , config_parse_strv , & ( context ) . supplementary_groups , section } , \
2010-01-28 04:53:56 +03:00
{ " Nice " , config_parse_nice , & ( context ) , section } , \
{ " OOMAdjust " , config_parse_oom_adjust , & ( context ) , section } , \
2010-01-29 22:46:22 +03:00
{ " IOSchedulingClass " , config_parse_io_class , & ( context ) , section } , \
2010-01-30 03:55:42 +03:00
{ " IOSchedulingPriority " , config_parse_io_priority , & ( context ) , section } , \
{ " CPUSchedulingPolicy " , config_parse_cpu_sched_policy , & ( context ) , section } , \
{ " CPUSchedulingPriority " , config_parse_cpu_sched_prio , & ( context ) , section } , \
2010-02-02 14:50:04 +03:00
{ " CPUSchedulingResetOnFork " , config_parse_bool , & ( context ) . cpu_sched_reset_on_fork , section } , \
2010-01-30 03:55:42 +03:00
{ " CPUAffinity " , config_parse_cpu_affinity , & ( context ) , section } , \
2010-02-12 04:02:14 +03:00
{ " UMask " , config_parse_mode , & ( context ) . umask , section } , \
2010-01-28 04:06:20 +03:00
{ " Environment " , config_parse_strv , & ( context ) . environment , section } , \
2010-04-13 04:06:27 +04:00
{ " StandardInput " , config_parse_input , & ( context ) . std_input , section } , \
{ " StandardOutput " , config_parse_output , & ( context ) . std_output , section } , \
{ " StandardError " , config_parse_output , & ( context ) . std_output , section } , \
{ " TTYPath " , config_parse_path , & ( context ) . tty_path , section } , \
2010-01-28 04:06:20 +03:00
{ " SyslogIdentifier " , config_parse_string , & ( context ) . syslog_identifier , section } , \
{ " SyslogFacility " , config_parse_facility , & ( context ) . syslog_priority , section } , \
2010-01-30 03:55:42 +03:00
{ " SyslogLevel " , config_parse_level , & ( context ) . syslog_priority , section } , \
{ " Capabilities " , config_parse_capabilities , & ( context ) , section } , \
{ " SecureBits " , config_parse_secure_bits , & ( context ) , section } , \
{ " CapabilityBoundingSetDrop " , config_parse_bounding_set , & ( context ) , section } , \
{ " TimerSlackNS " , config_parse_timer_slack_ns , & ( context ) , section } , \
{ " LimitCPU " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_CPU ] , section } , \
{ " LimitFSIZE " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_FSIZE ] , section } , \
{ " LimitDATA " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_DATA ] , section } , \
{ " LimitSTACK " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_STACK ] , section } , \
{ " LimitCORE " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_CORE ] , section } , \
{ " LimitRSS " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_RSS ] , section } , \
{ " LimitNOFILE " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_NOFILE ] , section } , \
{ " LimitAS " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_AS ] , section } , \
{ " LimitNPROC " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_NPROC ] , section } , \
{ " LimitMEMLOCK " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_MEMLOCK ] , section } , \
{ " LimitLOCKS " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_LOCKS ] , section } , \
{ " LimitSIGPENDING " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_SIGPENDING ] , section } , \
{ " LimitMSGQUEUE " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_MSGQUEUE ] , section } , \
{ " LimitNICE " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_NICE ] , section } , \
{ " LimitRTPRIO " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_RTPRIO ] , section } , \
2010-02-12 04:00:18 +03:00
{ " LimitRTTIME " , config_parse_limit , & ( context ) . rlimit [ RLIMIT_RTTIME ] , section } , \
2010-04-13 04:06:27 +04:00
{ " ControlGroup " , config_parse_cgroup , u , section }
2010-01-26 06:18:44 +03:00
2009-11-20 01:13:20 +03:00
const ConfigItem items [ ] = {
2010-01-27 04:16:11 +03:00
{ " Names " , config_parse_names , u , " Meta " } ,
{ " Description " , config_parse_string , & u - > meta . description , " Meta " } ,
{ " Requires " , config_parse_deps , UINT_TO_PTR ( UNIT_REQUIRES ) , " Meta " } ,
2010-04-15 05:11:11 +04:00
{ " RequiresOverridable " , config_parse_deps , UINT_TO_PTR ( UNIT_REQUIRES_OVERRIDABLE ) , " Meta " } ,
2010-01-27 04:16:11 +03:00
{ " Requisite " , config_parse_deps , UINT_TO_PTR ( UNIT_REQUISITE ) , " Meta " } ,
2010-04-15 05:11:11 +04:00
{ " RequisiteOverridable " , config_parse_deps , UINT_TO_PTR ( UNIT_REQUISITE_OVERRIDABLE ) , " Meta " } ,
{ " Wants " , config_parse_deps , UINT_TO_PTR ( UNIT_WANTS ) , " Meta " } ,
2010-01-27 04:16:11 +03:00
{ " Conflicts " , config_parse_deps , UINT_TO_PTR ( UNIT_CONFLICTS ) , " Meta " } ,
{ " Before " , config_parse_deps , UINT_TO_PTR ( UNIT_BEFORE ) , " Meta " } ,
{ " After " , config_parse_deps , UINT_TO_PTR ( UNIT_AFTER ) , " Meta " } ,
2010-01-29 22:47:09 +03:00
{ " RecursiveStop " , config_parse_bool , & u - > meta . recursive_stop , " Meta " } ,
{ " StopWhenUnneeded " , config_parse_bool , & u - > meta . stop_when_unneeded , " Meta " } ,
2010-01-27 04:16:11 +03:00
{ " PIDFile " , config_parse_path , & u - > service . pid_file , " Service " } ,
{ " ExecStartPre " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_START_PRE , " Service " } ,
{ " ExecStart " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_START , " Service " } ,
{ " ExecStartPost " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_START_POST , " Service " } ,
{ " ExecReload " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_RELOAD , " Service " } ,
{ " ExecStop " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_STOP , " Service " } ,
{ " ExecStopPost " , config_parse_exec , u - > service . exec_command + SERVICE_EXEC_STOP_POST , " Service " } ,
{ " RestartSec " , config_parse_usec , & u - > service . restart_usec , " Service " } ,
{ " TimeoutSec " , config_parse_usec , & u - > service . timeout_usec , " Service " } ,
2010-04-13 04:22:41 +04:00
{ " Type " , config_parse_service_type , & u - > service . type , " Service " } ,
{ " Restart " , config_parse_service_restart , & u - > service . restart , " Service " } ,
2010-02-15 00:43:08 +03:00
{ " PermissionsStartOnly " , config_parse_bool , & u - > service . permissions_start_only , " Service " } ,
{ " RootDirectoryStartOnly " , config_parse_bool , & u - > service . root_directory_start_only , " Service " } ,
2010-03-31 18:29:55 +04:00
{ " ValidNoProcess " , config_parse_bool , & u - > service . valid_no_process , " Service " } ,
2010-04-06 04:40:10 +04:00
{ " SysVStartPriority " , config_parse_sysv_priority , & u - > service . sysv_start_priority , " Service " } ,
2010-04-08 02:52:14 +04:00
{ " KillMode " , config_parse_kill_mode , & u - > service . kill_mode , " Service " } ,
2010-04-10 19:48:41 +04:00
{ " NonBlocking " , config_parse_bool , & u - > service . exec_context . non_blocking , " Service " } ,
2010-01-26 23:39:06 +03:00
EXEC_CONTEXT_CONFIG_ITEMS ( u - > service . exec_context , " Service " ) ,
2010-01-27 04:16:11 +03:00
{ " ListenStream " , config_parse_listen , & u - > socket , " Socket " } ,
{ " ListenDatagram " , config_parse_listen , & u - > socket , " Socket " } ,
{ " ListenSequentialPacket " , config_parse_listen , & u - > socket , " Socket " } ,
{ " ListenFIFO " , config_parse_listen , & u - > socket , " Socket " } ,
{ " BindIPv6Only " , config_parse_socket_bind , & u - > socket , " Socket " } ,
{ " Backlog " , config_parse_unsigned , & u - > socket . backlog , " Socket " } ,
2010-01-27 06:31:52 +03:00
{ " BindToDevice " , config_parse_bindtodevice , & u - > socket , " Socket " } ,
2010-01-27 04:16:11 +03:00
{ " ExecStartPre " , config_parse_exec , u - > socket . exec_command + SOCKET_EXEC_START_PRE , " Socket " } ,
{ " ExecStartPost " , config_parse_exec , u - > socket . exec_command + SOCKET_EXEC_START_POST , " Socket " } ,
{ " ExecStopPre " , config_parse_exec , u - > socket . exec_command + SOCKET_EXEC_STOP_PRE , " Socket " } ,
{ " ExecStopPost " , config_parse_exec , u - > socket . exec_command + SOCKET_EXEC_STOP_POST , " Socket " } ,
2010-04-10 19:50:54 +04:00
{ " TimeoutSec " , config_parse_usec , & u - > socket . timeout_usec , " Socket " } ,
2010-02-12 04:02:14 +03:00
{ " DirectoryMode " , config_parse_mode , & u - > socket . directory_mode , " Socket " } ,
{ " SocketMode " , config_parse_mode , & u - > socket . socket_mode , " Socket " } ,
2010-04-08 02:52:14 +04:00
{ " KillMode " , config_parse_kill_mode , & u - > socket . kill_mode , " Socket " } ,
2010-01-26 23:39:06 +03:00
EXEC_CONTEXT_CONFIG_ITEMS ( u - > socket . exec_context , " Socket " ) ,
2010-04-10 19:53:17 +04:00
{ " What " , config_parse_string , & u - > mount . parameters_fragment . what , " Mount " } ,
{ " Where " , config_parse_path , & u - > mount . where , " Mount " } ,
{ " Options " , config_parse_string , & u - > mount . parameters_fragment . options , " Mount " } ,
{ " Type " , config_parse_string , & u - > mount . parameters_fragment . fstype , " Mount " } ,
{ " TimeoutSec " , config_parse_usec , & u - > mount . timeout_usec , " Mount " } ,
{ " KillMode " , config_parse_kill_mode , & u - > mount . kill_mode , " Mount " } ,
EXEC_CONTEXT_CONFIG_ITEMS ( u - > mount . exec_context , " Mount " ) ,
2010-01-26 06:18:44 +03:00
2009-11-20 01:13:20 +03:00
{ NULL , NULL , NULL , NULL }
} ;
2010-01-26 06:18:44 +03:00
# undef EXEC_CONTEXT_CONFIG_ITEMS
2010-01-19 04:56:37 +03:00
const char * sections [ 3 ] ;
2010-01-27 02:15:56 +03:00
char * k ;
int r ;
2010-01-26 23:39:06 +03:00
Set * symlink_names ;
2010-04-06 04:43:58 +04:00
FILE * f = NULL ;
char * filename = NULL , * id = NULL ;
Unit * merged ;
2010-04-10 19:53:17 +04:00
if ( ! u ) {
/* Dirty dirty hack. */
dump_items ( ( FILE * ) path , items ) ;
return 0 ;
}
2010-04-06 04:43:58 +04:00
assert ( u ) ;
2010-04-10 19:53:17 +04:00
assert ( path ) ;
2009-11-20 01:13:20 +03:00
2010-01-19 04:56:37 +03:00
sections [ 0 ] = " Meta " ;
2010-01-26 23:39:06 +03:00
sections [ 1 ] = section_table [ u - > meta . type ] ;
2010-01-19 04:56:37 +03:00
sections [ 2 ] = NULL ;
2010-01-26 23:39:06 +03:00
if ( ! ( symlink_names = set_new ( string_hash_func , string_compare_func ) ) )
return - ENOMEM ;
2009-11-20 01:13:20 +03:00
2010-02-13 03:07:02 +03:00
if ( path_is_absolute ( path ) ) {
if ( ! ( filename = strdup ( path ) ) ) {
r = - ENOMEM ;
goto finish ;
}
if ( ( r = open_follow ( & filename , & f , symlink_names , & id ) ) < 0 ) {
free ( filename ) ;
filename = NULL ;
if ( r ! = - ENOENT )
goto finish ;
}
} else {
char * * p ;
STRV_FOREACH ( p , u - > meta . manager - > unit_path ) {
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit
* name set while doing so */
if ( ! ( filename = path_make_absolute ( path , * p ) ) ) {
r = - ENOMEM ;
goto finish ;
}
if ( ( r = open_follow ( & filename , & f , symlink_names , & id ) ) < 0 ) {
char * sn ;
free ( filename ) ;
filename = NULL ;
if ( r ! = - ENOENT )
goto finish ;
/* Empty the symlink names for the next run */
while ( ( sn = set_steal_first ( symlink_names ) ) )
free ( sn ) ;
2009-11-20 01:13:20 +03:00
2010-02-13 03:07:02 +03:00
continue ;
}
break ;
}
}
2010-01-26 06:18:44 +03:00
2010-02-13 03:07:02 +03:00
if ( ! filename ) {
2010-04-06 04:43:58 +04:00
r = 0 ;
2010-01-27 02:15:56 +03:00
goto finish ;
}
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
merged = u ;
if ( ( r = merge_by_names ( & merged , symlink_names , id ) ) < 0 )
2010-01-27 02:15:56 +03:00
goto finish ;
2010-01-26 23:39:06 +03:00
2010-04-06 04:43:58 +04:00
if ( merged ! = u ) {
2010-04-10 19:53:17 +04:00
u - > meta . load_state = UNIT_MERGED ;
2010-04-06 04:43:58 +04:00
r = 0 ;
goto finish ;
2010-01-26 06:18:44 +03:00
}
2010-04-06 04:43:58 +04:00
/* Now, parse the file contents */
if ( ( r = config_parse ( filename , f , sections , items , u ) ) < 0 )
goto finish ;
2010-01-29 04:07:41 +03:00
2010-02-14 03:01:10 +03:00
free ( u - > meta . fragment_path ) ;
u - > meta . fragment_path = filename ;
2010-01-27 02:15:56 +03:00
filename = NULL ;
2010-01-26 23:39:06 +03:00
2010-04-10 19:53:17 +04:00
u - > meta . load_state = UNIT_LOADED ;
2010-04-06 04:43:58 +04:00
r = 0 ;
2010-01-26 23:39:06 +03:00
finish :
while ( ( k = set_steal_first ( symlink_names ) ) )
free ( k ) ;
2010-04-06 04:43:58 +04:00
2010-01-26 23:39:06 +03:00
set_free ( symlink_names ) ;
2010-01-27 02:15:56 +03:00
free ( filename ) ;
2010-04-06 04:43:58 +04:00
if ( f )
fclose ( f ) ;
2010-01-27 02:15:56 +03:00
return r ;
}
2010-04-10 19:53:17 +04:00
int unit_load_fragment ( Unit * u ) {
2010-04-06 04:43:58 +04:00
int r ;
2010-01-27 02:15:56 +03:00
assert ( u ) ;
2010-04-06 04:43:58 +04:00
if ( u - > meta . fragment_path ) {
2010-04-10 19:53:17 +04:00
if ( ( r = load_from_path ( u , u - > meta . fragment_path ) ) < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-01-27 02:15:56 +03:00
2010-04-06 04:43:58 +04:00
} else {
2010-01-27 02:15:56 +03:00
Iterator i ;
2010-02-14 03:08:20 +03:00
const char * t ;
2010-01-27 02:15:56 +03:00
2010-02-14 03:08:20 +03:00
/* Try to find the unit under its id */
2010-04-15 05:11:11 +04:00
if ( ( r = load_from_path ( u , u - > meta . id ) ) < 0 )
return r ;
2010-02-14 03:08:20 +03:00
/* Try to find an alias we can load this with */
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state = = UNIT_STUB )
2010-04-06 04:43:58 +04:00
SET_FOREACH ( t , u - > meta . names , i ) {
2010-01-26 23:39:06 +03:00
2010-04-15 05:11:11 +04:00
if ( t = = u - > meta . id )
2010-04-06 04:43:58 +04:00
continue ;
2010-01-28 04:06:20 +03:00
2010-04-10 19:53:17 +04:00
if ( ( r = load_from_path ( u , t ) ) < 0 )
2010-04-06 04:43:58 +04:00
return r ;
2010-02-14 03:08:20 +03:00
2010-04-10 19:53:17 +04:00
if ( u - > meta . load_state ! = UNIT_STUB )
2010-04-06 04:43:58 +04:00
break ;
}
2010-04-15 05:11:11 +04:00
/* Now, follow the same logic, but look for a template */
if ( u - > meta . load_state = = UNIT_STUB & & u - > meta . instance ) {
char * k ;
if ( ! ( k = unit_name_template ( u - > meta . id ) ) )
return - ENOMEM ;
r = load_from_path ( u , k ) ;
free ( k ) ;
if ( r < 0 )
return r ;
if ( u - > meta . load_state = = UNIT_STUB )
SET_FOREACH ( t , u - > meta . names , i ) {
if ( t = = u - > meta . id )
continue ;
if ( ! ( k = unit_name_template ( t ) ) )
return - ENOMEM ;
r = load_from_path ( u , k ) ;
free ( k ) ;
if ( r < 0 )
return r ;
if ( u - > meta . load_state ! = UNIT_STUB )
break ;
}
}
2010-01-28 04:06:20 +03:00
}
2010-04-06 04:43:58 +04:00
return 0 ;
2009-11-20 01:13:20 +03:00
}
2010-04-10 19:53:17 +04:00
void unit_dump_config_items ( FILE * f ) {
/* OK, this wins a prize for extreme ugliness. */
load_from_path ( NULL , ( const void * ) f ) ;
}