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?
<variablelist>
<varlistentry>
<term><varname>PathExists=</varname></term>
+ <term><varname>PathExistsGlob=</varname></term>
<term><varname>PathChanged=</varname></term>
<term><varname>DirectoryNotEmpty=</varname></term>
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
<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>.
<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>
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
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
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;
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;
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",
typedef enum ConditionType {
CONDITION_PATH_EXISTS,
+ CONDITION_PATH_EXISTS_GLOB,
CONDITION_PATH_IS_DIRECTORY,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_KERNEL_COMMAND_LINE,
{ "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" },
{ "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" },
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
};
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;
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)
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"
};
typedef enum PathType {
PATH_EXISTS,
+ PATH_EXISTS_GLOB,
PATH_DIRECTORY_NOT_EMPTY,
PATH_CHANGED,
_PATH_TYPE_MAX,
#include <sys/capability.h>
#include <sys/time.h>
#include <linux/rtc.h>
+#include <glob.h>
#include "macro.h"
#include "util.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",
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)