mirror of
https://github.com/systemd/systemd.git
synced 2025-03-28 02:50:16 +03:00
path,unit: support globbing in conditions and path units
This commit is contained in:
parent
31a5f880cf
commit
8092a428d4
4
TODO
4
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?
|
||||
|
||||
|
@ -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>.
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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" },
|
||||
|
@ -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"
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ typedef enum PathState {
|
||||
|
||||
typedef enum PathType {
|
||||
PATH_EXISTS,
|
||||
PATH_EXISTS_GLOB,
|
||||
PATH_DIRECTORY_NOT_EMPTY,
|
||||
PATH_CHANGED,
|
||||
_PATH_TYPE_MAX,
|
||||
|
25
src/util.c
25
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",
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user