Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
steam
systemd
Commits
52661efd
Commit
52661efd
authored
Oct 13, 2010
by
Lennart Poettering
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
unit: add minimal condition checker for unit startup
parent
e04aad61
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
341 additions
and
7 deletions
+341
-7
Makefile.am
Makefile.am
+2
-1
TODO
TODO
+2
-2
man/systemd.unit.xml
man/systemd.unit.xml
+42
-0
src/condition.c
src/condition.c
+158
-0
src/condition.h
src/condition.h
+57
-0
src/execute.c
src/execute.c
+0
-1
src/load-fragment.c
src/load-fragment.c
+65
-0
src/main.c
src/main.c
+1
-3
src/unit.c
src/unit.c
+10
-0
src/unit.h
src/unit.h
+4
-0
No files found.
Makefile.am
View file @
52661efd
...
...
@@ -402,7 +402,8 @@ libsystemd_core_la_SOURCES = \
src/fdset.c
\
src/namespace.c
\
src/tcpwrap.c
\
src/cgroup-util.c
src/cgroup-util.c
\
src/condition.c
libsystemd_core_la_CFLAGS
=
\
$(AM_CFLAGS)
\
...
...
TODO
View file @
52661efd
...
...
@@ -42,8 +42,6 @@
* systemctl list-jobs - show dependencies
* ConditionFileExists=, ConditionKernelCommandLine=, ConditionEnvironment= with !
* accountsservice is borked
* auditd service files
...
...
@@ -84,6 +82,8 @@
* fix plymouth socket, when plymouth started to use a clean one
* parse early boot time env var from dracut
External:
* patch kernel to add /proc/swaps change notifications
...
...
man/systemd.unit.xml
View file @
52661efd
...
...
@@ -585,6 +585,48 @@
change.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>
ConditionPathExists=
</varname></term>
<term><varname>
ConditionKernelCommandLine=
</varname></term>
<listitem><para>
Before starting a unit
verify that the specified condition is
true. With
<varname>
ConditionPathExists=
</varname>
a file existance condition can be
checked before a unit is started. If
the specified absolute path name does
not exist startup of a unit will not
actually happen, however the unit is
still useful for ordering purposes in
this case. The condition is checked at
the time the queued start job is to be
executed. If the absolute path name
passed to
<varname>
ConditionPathExists=
</varname>
is prefixed with an exclamation mark
(!), the test is negated, and the unit
only started if the path does not
exist. Similarly
<varname>
ConditionKernelCommandLine=
</varname>
may be used to check whether a
specific kernel command line option is
set (or if prefixed with the
exclamation mark unset). The argument
must either be a single word, or an
assignment (i.e. two words, seperated
by the equality sign). In the former
case the kernel command line is search
for the word appearing as is, or as
left hand side of an assignment. In
the latter case the exact assignment
is looked for with right and left hand
side matching. If multiple conditions
are specified the unit will be
executed iff at least one of them
apply (i.e. a logical OR is
applied).
</para></listitem>
</varlistentry>
</variablelist>
<para>
Unit file may include a [Install] section, which
...
...
src/condition.c
0 → 100644
View file @
52661efd
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 ProFUSION embedded systems
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/>.
***/
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "util.h"
#include "condition.h"
Condition
*
condition_new
(
ConditionType
type
,
const
char
*
parameter
,
bool
negate
)
{
Condition
*
c
;
c
=
new0
(
Condition
,
1
);
c
->
type
=
type
;
c
->
negate
=
negate
;
if
(
!
(
c
->
parameter
=
strdup
(
parameter
)))
{
free
(
c
);
return
NULL
;
}
return
c
;
}
void
condition_free
(
Condition
*
c
)
{
assert
(
c
);
free
(
c
->
parameter
);
free
(
c
);
}
void
condition_free_list
(
Condition
*
first
)
{
Condition
*
c
,
*
n
;
LIST_FOREACH_SAFE
(
conditions
,
c
,
n
,
first
)
condition_free
(
c
);
}
static
bool
test_kernel_command_line
(
const
char
*
parameter
)
{
char
*
line
,
*
w
,
*
state
,
*
word
=
NULL
;
bool
equal
;
int
r
;
size_t
l
,
pl
;
bool
found
=
false
;
if
((
r
=
read_one_line_file
(
"/proc/cmdline"
,
&
line
))
<
0
)
{
log_warning
(
"Failed to read /proc/cmdline, ignoring: %s"
,
strerror
(
-
r
));
return
false
;
}
equal
=
!!
strchr
(
parameter
,
'='
);
pl
=
strlen
(
parameter
);
FOREACH_WORD_QUOTED
(
w
,
l
,
line
,
state
)
{
free
(
word
);
if
(
!
(
word
=
strndup
(
w
,
l
)))
break
;
if
(
equal
)
{
if
(
streq
(
word
,
parameter
))
{
found
=
true
;
break
;
}
}
else
{
if
(
startswith
(
word
,
parameter
)
&&
(
word
[
pl
]
==
'='
||
word
[
pl
]
==
0
))
{
found
=
true
;
break
;
}
}
}
free
(
word
);
free
(
line
);
return
found
;
}
bool
condition_test
(
Condition
*
c
)
{
assert
(
c
);
switch
(
c
->
type
)
{
case
CONDITION_PATH_EXISTS
:
return
(
access
(
c
->
parameter
,
F_OK
)
>=
0
)
==
!
c
->
negate
;
case
CONDITION_KERNEL_COMMAND_LINE
:
return
!!
test_kernel_command_line
(
c
->
parameter
)
==
!
c
->
negate
;
default:
assert_not_reached
(
"Invalid condition type."
);
}
}
bool
condition_test_list
(
Condition
*
first
)
{
Condition
*
c
;
/* If the condition list is empty, then it is true */
if
(
!
first
)
return
true
;
/* Otherwise, if any of the conditions apply we return true */
LIST_FOREACH
(
conditions
,
c
,
first
)
if
(
condition_test
(
c
))
return
true
;
return
false
;
}
void
condition_dump
(
Condition
*
c
,
FILE
*
f
,
const
char
*
prefix
)
{
assert
(
c
);
assert
(
f
);
if
(
!
prefix
)
prefix
=
""
;
fprintf
(
f
,
"%s%s: %s%s
\n
"
,
prefix
,
condition_type_to_string
(
c
->
type
),
c
->
negate
?
"!"
:
""
,
c
->
parameter
);
}
void
condition_dump_list
(
Condition
*
first
,
FILE
*
f
,
const
char
*
prefix
)
{
Condition
*
c
;
LIST_FOREACH
(
conditions
,
c
,
first
)
condition_dump
(
c
,
f
,
prefix
);
}
static
const
char
*
const
condition_type_table
[
_CONDITION_TYPE_MAX
]
=
{
[
CONDITION_KERNEL_COMMAND_LINE
]
=
"ConditionKernelCommandLine"
,
[
CONDITION_PATH_EXISTS
]
=
"ConditionPathExists"
};
DEFINE_STRING_TABLE_LOOKUP
(
condition_type
,
ConditionType
);
src/condition.h
0 → 100644
View file @
52661efd
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
#ifndef fooconditionhfoo
#define fooconditionhfoo
/***
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/>.
***/
#include <stdbool.h>
#include "list.h"
typedef
enum
ConditionType
{
CONDITION_PATH_EXISTS
,
CONDITION_KERNEL_COMMAND_LINE
,
_CONDITION_TYPE_MAX
,
_CONDITION_TYPE_INVALID
=
-
1
}
ConditionType
;
typedef
struct
Condition
{
ConditionType
type
;
char
*
parameter
;
bool
negate
;
LIST_FIELDS
(
struct
Condition
,
conditions
);
}
Condition
;
Condition
*
condition_new
(
ConditionType
type
,
const
char
*
parameter
,
bool
negate
);
void
condition_free
(
Condition
*
c
);
void
condition_free_list
(
Condition
*
c
);
bool
condition_test
(
Condition
*
c
);
bool
condition_test_list
(
Condition
*
c
);
void
condition_dump
(
Condition
*
c
,
FILE
*
f
,
const
char
*
prefix
);
void
condition_dump_list
(
Condition
*
c
,
FILE
*
f
,
const
char
*
prefix
);
const
char
*
condition_type_to_string
(
ConditionType
t
);
int
condition_type_from_string
(
const
char
*
s
);
#endif
src/execute.c
View file @
52661efd
...
...
@@ -1613,7 +1613,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf
(
f
,
"%sUtmpIdentifier: %s
\n
"
,
prefix
,
c
->
utmp_id
);
}
void
exec_status_start
(
ExecStatus
*
s
,
pid_t
pid
)
{
...
...
src/load-fragment.c
View file @
52661efd
...
...
@@ -1400,6 +1400,67 @@ static int config_parse_ip_tos(
return
0
;
}
static
int
config_parse_condition_path
(
const
char
*
filename
,
unsigned
line
,
const
char
*
section
,
const
char
*
lvalue
,
const
char
*
rvalue
,
void
*
data
,
void
*
userdata
)
{
Unit
*
u
=
data
;
bool
negate
;
Condition
*
c
;
assert
(
filename
);
assert
(
lvalue
);
assert
(
rvalue
);
assert
(
data
);
if
((
negate
=
rvalue
[
0
]
==
'!'
))
rvalue
++
;
if
(
!
path_is_absolute
(
rvalue
))
{
log_error
(
"[%s:%u] Path in condition not absolute: %s"
,
filename
,
line
,
rvalue
);
return
0
;
}
if
(
!
(
c
=
condition_new
(
CONDITION_PATH_EXISTS
,
rvalue
,
negate
)))
return
-
ENOMEM
;
LIST_PREPEND
(
Condition
,
conditions
,
u
->
meta
.
conditions
,
c
);
return
0
;
}
static
int
config_parse_condition_kernel
(
const
char
*
filename
,
unsigned
line
,
const
char
*
section
,
const
char
*
lvalue
,
const
char
*
rvalue
,
void
*
data
,
void
*
userdata
)
{
Unit
*
u
=
data
;
bool
negate
;
Condition
*
c
;
assert
(
filename
);
assert
(
lvalue
);
assert
(
rvalue
);
assert
(
data
);
if
((
negate
=
rvalue
[
0
]
==
'!'
))
rvalue
++
;
if
(
!
(
c
=
condition_new
(
CONDITION_KERNEL_COMMAND_LINE
,
rvalue
,
negate
)))
return
-
ENOMEM
;
LIST_PREPEND
(
Condition
,
conditions
,
u
->
meta
.
conditions
,
c
);
return
0
;
}
static
DEFINE_CONFIG_PARSE_ENUM
(
config_parse_notify_access
,
notify_access
,
NotifyAccess
,
"Failed to parse notify access specifier"
);
#define FOLLOW_MAX 8
...
...
@@ -1571,6 +1632,8 @@ static void dump_items(FILE *f, const ConfigItem *items) {
{
config_parse_path_unit
,
"UNIT"
},
{
config_parse_notify_access
,
"ACCESS"
},
{
config_parse_ip_tos
,
"TOS"
},
{
config_parse_condition_path
,
"CONDITION"
},
{
config_parse_condition_kernel
,
"CONDITION"
},
};
assert
(
f
);
...
...
@@ -1692,6 +1755,8 @@ static int load_from_path(Unit *u, const char *path) {
{
"DefaultDependencies"
,
config_parse_bool
,
&
u
->
meta
.
default_dependencies
,
"Unit"
},
{
"IgnoreDependencyFailure"
,
config_parse_bool
,
&
u
->
meta
.
ignore_dependency_failure
,
"Unit"
},
{
"JobTimeoutSec"
,
config_parse_usec
,
&
u
->
meta
.
job_timeout
,
"Unit"
},
{
"ConditionPathExists"
,
config_parse_condition_path
,
u
,
"Unit"
},
{
"ConditionKernelCommandLine"
,
config_parse_condition_kernel
,
u
,
"Unit"
},
{
"PIDFile"
,
config_parse_path
,
&
u
->
service
.
pid_file
,
"Service"
},
{
"ExecStartPre"
,
config_parse_exec
,
u
->
service
.
exec_command
+
SERVICE_EXEC_START_PRE
,
"Service"
},
...
...
src/main.c
View file @
52661efd
...
...
@@ -545,11 +545,9 @@ static int parse_config_file(void) {
}
static
int
parse_proc_cmdline
(
void
)
{
char
*
line
;
char
*
line
,
*
w
,
*
state
;
int
r
;
char
*
w
;
size_t
l
;
char
*
state
;
if
((
r
=
read_one_line_file
(
"/proc/cmdline"
,
&
line
))
<
0
)
{
log_warning
(
"Failed to read /proc/cmdline, ignoring: %s"
,
strerror
(
-
r
));
...
...
src/unit.c
View file @
52661efd
...
...
@@ -375,6 +375,8 @@ void unit_free(Unit *u) {
set_free_free
(
u
->
meta
.
names
);
condition_free_list
(
u
->
meta
.
conditions
);
free
(
u
->
meta
.
instance
);
free
(
u
);
}
...
...
@@ -639,6 +641,8 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
if
(
u
->
meta
.
job_timeout
>
0
)
fprintf
(
f
,
"%s
\t
Job Timeout: %s
\n
"
,
prefix
,
format_timespan
(
timespan
,
sizeof
(
timespan
),
u
->
meta
.
job_timeout
));
condition_dump_list
(
u
->
meta
.
conditions
,
f
,
prefix
);
for
(
d
=
0
;
d
<
_UNIT_DEPENDENCY_MAX
;
d
++
)
{
Unit
*
other
;
...
...
@@ -840,6 +844,12 @@ int unit_start(Unit *u) {
if
(
!
UNIT_VTABLE
(
u
)
->
start
)
return
-
EBADR
;
/* If the conditions failed, don't do anything at all */
if
(
!
condition_test_list
(
u
->
meta
.
conditions
))
{
log_debug
(
"Starting of %s requested but condition failed. Ignoring."
,
u
->
meta
.
id
);
return
-
EALREADY
;
}
/* We don't suppress calls to ->start() here when we are
* already starting, to allow this request to be used as a
* "hurry up" call, for example when the unit is in some "auto
...
...
src/unit.h
View file @
52661efd
...
...
@@ -38,6 +38,7 @@ typedef enum UnitDependency UnitDependency;
#include "list.h"
#include "socket-util.h"
#include "execute.h"
#include "condition.h"
#define DEFAULT_TIMEOUT_USEC (60*USEC_PER_SEC)
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
...
...
@@ -154,6 +155,9 @@ struct Meta {
usec_t
job_timeout
;
/* Conditions to check */
LIST_HEAD
(
Condition
,
conditions
);
dual_timestamp
inactive_exit_timestamp
;
dual_timestamp
active_enter_timestamp
;
dual_timestamp
active_exit_timestamp
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment