summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-07-07 02:07:39 +0200
committerLennart Poettering <lennart@poettering.net>2011-07-07 02:07:39 +0200
commit8092a428d40ac682df9e80c36988043854579679 (patch)
tree789262689c0eddf1deabfc01294b36140bee65a6
parentupdate TODO (diff)
downloadsystemd-8092a428d40ac682df9e80c36988043854579679.tar.xz
systemd-8092a428d40ac682df9e80c36988043854579679.zip
path,unit: support globbing in conditions and path units
-rw-r--r--TODO4
-rw-r--r--man/systemd.path.xml16
-rw-r--r--man/systemd.unit.xml20
-rw-r--r--src/condition.c6
-rw-r--r--src/condition.h1
-rw-r--r--src/load-fragment.c12
-rw-r--r--src/path.c8
-rw-r--r--src/path.h1
-rw-r--r--src/util.c25
-rw-r--r--src/util.h2
10 files changed, 75 insertions, 20 deletions
diff --git a/TODO b/TODO
index 721e82724d..6ce4240188 100644
--- a/TODO
+++ b/TODO
@@ -20,9 +20,9 @@ F15 External:
Features:
-* support presets
+* add loginctl, i.e. a systemctl for logind introspection
-* wildcard support for .path units (think CUPS spool directory!)
+* support presets
* kernel: add /proc/sys file exposing CAP_LAST_CAP?
diff --git a/man/systemd.path.xml b/man/systemd.path.xml
index e816c3018c..f99931ab1e 100644
--- a/man/systemd.path.xml
+++ b/man/systemd.path.xml
@@ -111,6 +111,7 @@
<variablelist>
<varlistentry>
<term><varname>PathExists=</varname></term>
+ <term><varname>PathExistsGlob=</varname></term>
<term><varname>PathChanged=</varname></term>
<term><varname>DirectoryNotEmpty=</varname></term>
@@ -121,7 +122,11 @@
file or directory. If the file
specified exists the configured unit
is
- activated. <varname>PathChanged=</varname>
+ activated. <varname>PathExistsGlob=</varname>
+ works similar, but checks for the
+ existance of at least one file
+ matching the globbing pattern
+ specified. <varname>PathChanged=</varname>
may be used to watch a file or
directory and activate the configured
unit whenever it changes or is
@@ -140,12 +145,13 @@
<para>If a path is already existing
(in case of
- <varname>PathExists=</varname>) or a
- directory already is not empty (in
+ <varname>PathExists=</varname> and
+ <varname>PathExistsGlob=</varname>) or
+ a directory already is not empty (in
case of
<varname>DirectoryNotEmpty=</varname>)
- at the time the path unit is activated,
- then the configured unit is
+ at the time the path unit is
+ activated, then the configured unit is
immediately activated as
well. Something similar does not apply
to <varname>PathChanged=</varname>.
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index dd32e5505c..0ca18bd317 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -607,6 +607,7 @@
<varlistentry>
<term><varname>ConditionPathExists=</varname></term>
+ <term><varname>ConditionPathExistsGlob=</varname></term>
<term><varname>ConditionPathIsDirectory=</varname></term>
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
<term><varname>ConditionKernelCommandLine=</varname></term>
@@ -632,7 +633,12 @@
is prefixed with an exclamation mark
(!), the test is negated, and the unit
only started if the path does not
- exist. <varname>ConditionPathIsDirectory=</varname>
+ exist. <varname>ConditionPathExistsGlob=</varname>
+ work in a similar way, but checks for
+ the existance of at least one file or
+ directory matching the specified
+ globbing
+ pattern. <varname>ConditionPathIsDirectory=</varname>
is similar to
<varname>ConditionPathExists=</varname>
but verifies whether a certain path
@@ -677,12 +683,12 @@
test may be negated by prepending an
exclamation mark.
<varname>ConditionSecurity=</varname>
- may be used to check whether the given security
- module is enabled on the system.
- Currently the only recognized value is
- <varname>selinux</varname>.
- The test may be negated by prepending an
- exclamation mark. Finally,
+ may be used to check whether the given
+ security module is enabled on the
+ system. Currently the only recognized
+ value is <varname>selinux</varname>.
+ The test may be negated by prepending
+ an exclamation mark. Finally,
<varname>ConditionNull=</varname> may
be used to add a constant condition
check value to the unit. It takes a
diff --git a/src/condition.c b/src/condition.c
index a520e43436..76ee0370d2 100644
--- a/src/condition.c
+++ b/src/condition.c
@@ -34,6 +34,8 @@
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
Condition *c;
+ assert(type < _CONDITION_TYPE_MAX);
+
if (!(c = new0(Condition, 1)))
return NULL;
@@ -148,6 +150,9 @@ bool condition_test(Condition *c) {
case CONDITION_PATH_EXISTS:
return (access(c->parameter, F_OK) >= 0) == !c->negate;
+ case CONDITION_PATH_EXISTS_GLOB:
+ return (glob_exists(c->parameter) > 0) == !c->negate;
+
case CONDITION_PATH_IS_DIRECTORY: {
struct stat st;
@@ -231,6 +236,7 @@ void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_PATH_EXISTS] = "ConditionPathExists",
+ [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
[CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
[CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
diff --git a/src/condition.h b/src/condition.h
index 84028028c4..ff896a793a 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -28,6 +28,7 @@
typedef enum ConditionType {
CONDITION_PATH_EXISTS,
+ CONDITION_PATH_EXISTS_GLOB,
CONDITION_PATH_IS_DIRECTORY,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_KERNEL_COMMAND_LINE,
diff --git a/src/load-fragment.c b/src/load-fragment.c
index 8f39839986..05e60bf8fd 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1999,12 +1999,13 @@ static int load_from_path(Unit *u, const char *path) {
{ "IgnoreOnIsolate", config_parse_bool, 0, &u->meta.ignore_on_isolate, "Unit" },
{ "IgnoreOnSnapshot", config_parse_bool, 0, &u->meta.ignore_on_snapshot, "Unit" },
{ "JobTimeoutSec", config_parse_usec, 0, &u->meta.job_timeout, "Unit" },
- { "ConditionPathExists", config_parse_condition_path, CONDITION_PATH_EXISTS, u, "Unit" },
- { "ConditionPathIsDirectory", config_parse_condition_path, CONDITION_PATH_IS_DIRECTORY, u, "Unit" },
- { "ConditionDirectoryNotEmpty", config_parse_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, u, "Unit" },
+ { "ConditionPathExists", config_parse_condition_path, CONDITION_PATH_EXISTS, u, "Unit" },
+ { "ConditionPathExistsGlob", config_parse_condition_path, CONDITION_PATH_EXISTS_GLOB, u, "Unit" },
+ { "ConditionPathIsDirectory", config_parse_condition_path, CONDITION_PATH_IS_DIRECTORY, u, "Unit" },
+ { "ConditionDirectoryNotEmpty", config_parse_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, u, "Unit" },
{ "ConditionKernelCommandLine", config_parse_condition_string, CONDITION_KERNEL_COMMAND_LINE, u, "Unit" },
- { "ConditionVirtualization", config_parse_condition_string, CONDITION_VIRTUALIZATION, u, "Unit" },
- { "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" },
+ { "ConditionVirtualization", config_parse_condition_string, CONDITION_VIRTUALIZATION, u, "Unit" },
+ { "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" },
{ "ConditionNull", config_parse_condition_null, 0, u, "Unit" },
{ "PIDFile", config_parse_path_printf, 0, &u->service.pid_file, "Service" },
@@ -2094,6 +2095,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "Unit", config_parse_timer_unit, 0, &u->timer, "Timer" },
{ "PathExists", config_parse_path_spec, 0, &u->path, "Path" },
+ { "PathExistsGlob", config_parse_path_spec, 0, &u->path, "Path" },
{ "PathChanged", config_parse_path_spec, 0, &u->path, "Path" },
{ "DirectoryNotEmpty", config_parse_path_spec, 0, &u->path, "Path" },
{ "Unit", config_parse_path_unit, 0, &u->path, "Path" },
diff --git a/src/path.c b/src/path.c
index 1c20dcfed6..200fc2bdcb 100644
--- a/src/path.c
+++ b/src/path.c
@@ -197,6 +197,7 @@ static void path_dump(Unit *u, FILE *f, const char *prefix) {
static int path_watch_one(Path *p, PathSpec *s) {
static const int flags_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
+ [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
[PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
[PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
};
@@ -367,6 +368,10 @@ static bool path_check_good(Path *p, bool initial) {
good = access(s->path, F_OK) >= 0;
break;
+ case PATH_EXISTS_GLOB:
+ good = glob_exists(s->path) > 0;
+ break;
+
case PATH_DIRECTORY_NOT_EMPTY: {
int k;
@@ -438,7 +443,7 @@ static void path_mkdir(Path *p) {
LIST_FOREACH(spec, s, p->specs) {
int r;
- if (s->type == PATH_EXISTS)
+ if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
continue;
if ((r = mkdir_p(s->path, p->directory_mode)) < 0)
@@ -672,6 +677,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
static const char* const path_type_table[_PATH_TYPE_MAX] = {
[PATH_EXISTS] = "PathExists",
+ [PATH_EXISTS_GLOB] = "PathExistsGlob",
[PATH_CHANGED] = "PathChanged",
[PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
};
diff --git a/src/path.h b/src/path.h
index 8ba0ce6890..116fc63ff7 100644
--- a/src/path.h
+++ b/src/path.h
@@ -38,6 +38,7 @@ typedef enum PathState {
typedef enum PathType {
PATH_EXISTS,
+ PATH_EXISTS_GLOB,
PATH_DIRECTORY_NOT_EMPTY,
PATH_CHANGED,
_PATH_TYPE_MAX,
diff --git a/src/util.c b/src/util.c
index 344b869c8c..356b4f9de2 100644
--- a/src/util.c
+++ b/src/util.c
@@ -53,6 +53,7 @@
#include <sys/capability.h>
#include <sys/time.h>
#include <linux/rtc.h>
+#include <glob.h>
#include "macro.h"
#include "util.h"
@@ -5238,6 +5239,30 @@ int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **h
return 0;
}
+int glob_exists(const char *path) {
+ glob_t g;
+ int r, k;
+
+ assert(path);
+
+ zero(g);
+ errno = 0;
+ k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g);
+
+ if (k == GLOB_NOMATCH)
+ r = 0;
+ else if (k == GLOB_NOSPACE)
+ r = -ENOMEM;
+ else if (k == 0)
+ r = !strv_isempty(g.gl_pathv);
+ else
+ r = errno ? -errno : -EIO;
+
+ globfree(&g);
+
+ return r;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/util.h b/src/util.h
index 411efae933..b8bbd23e8c 100644
--- a/src/util.h
+++ b/src/util.h
@@ -447,6 +447,8 @@ int socket_from_display(const char *display, char **path);
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home);
+int glob_exists(const char *path);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)