diff options
author | Lennart Poettering <lennart@poettering.net> | 2011-07-07 02:07:39 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2011-07-07 02:07:39 +0200 |
commit | 8092a428d40ac682df9e80c36988043854579679 (patch) | |
tree | 789262689c0eddf1deabfc01294b36140bee65a6 | |
parent | 31a5f880cf7a742e63a81bacef681939ee4e6616 (diff) |
path,unit: support globbing in conditions and path units
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | man/systemd.path.xml | 16 | ||||
-rw-r--r-- | man/systemd.unit.xml | 20 | ||||
-rw-r--r-- | src/condition.c | 6 | ||||
-rw-r--r-- | src/condition.h | 1 | ||||
-rw-r--r-- | src/load-fragment.c | 12 | ||||
-rw-r--r-- | src/path.c | 8 | ||||
-rw-r--r-- | src/path.h | 1 | ||||
-rw-r--r-- | src/util.c | 25 | ||||
-rw-r--r-- | src/util.h | 2 |
10 files changed, 75 insertions, 20 deletions
@@ -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) |