chiark / gitweb /
unit: introduce ConditionFileIsExecutable= and use it where we check for a binary...
[elogind.git] / src / load-fragment.c
index 3440d9158f1c91df0b94c7eb4cec9305426fa06a..5c1dff60b8aba1f029755b17579b4fc951842c65 100644 (file)
@@ -188,6 +188,72 @@ static int config_parse_string_printf(
         return 0;
 }
 
+static int config_parse_strv_printf(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char *k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(u);
+
+        k = unit_full_printf(u, rvalue);
+        if (!k)
+                return -ENOMEM;
+
+        r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
+        free(k);
+
+        return r;
+}
+
+static int config_parse_path_printf(
+                const char *filename,
+                unsigned line,
+                const char *section,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        Unit *u = userdata;
+        char **s = data;
+        char *k;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(s);
+        assert(u);
+
+        if (!(k = unit_full_printf(u, rvalue)))
+                return -ENOMEM;
+
+        if (!path_is_absolute(k)) {
+                log_error("[%s:%u] Not an absolute path: %s", filename, line, k);
+                free(k);
+                return -EINVAL;
+        }
+
+        path_kill_slashes(k);
+
+        free(*s);
+        *s = k;
+
+        return 0;
+}
+
 static int config_parse_listen(
                 const char *filename,
                 unsigned line,
@@ -198,7 +264,7 @@ static int config_parse_listen(
                 void *data,
                 void *userdata) {
 
-        SocketPort *p;
+        SocketPort *p, *tail;
         Socket *s;
 
         assert(filename);
@@ -214,25 +280,59 @@ static int config_parse_listen(
         if (streq(lvalue, "ListenFIFO")) {
                 p->type = SOCKET_FIFO;
 
-                if (!(p->path = strdup(rvalue))) {
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(p->path);
+
+        } else if (streq(lvalue, "ListenSpecial")) {
+                p->type = SOCKET_SPECIAL;
+
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
+                        free(p);
+                        return -ENOMEM;
+                }
+
+                path_kill_slashes(p->path);
+
+        } else if (streq(lvalue, "ListenMessageQueue")) {
+
+                p->type = SOCKET_MQUEUE;
+
+                if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
                         free(p);
                         return -ENOMEM;
                 }
 
                 path_kill_slashes(p->path);
+
         } else if (streq(lvalue, "ListenNetlink")) {
+                char  *k;
+                int r;
+
                 p->type = SOCKET_SOCKET;
+                k = unit_full_printf(UNIT(s), rvalue);
+                r = socket_address_parse_netlink(&p->address, k);
+                free(k);
 
-                if (socket_address_parse_netlink(&p->address, rvalue) < 0) {
+                if (r < 0) {
                         log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
                         free(p);
                         return 0;
                 }
 
         } else {
+                char *k;
+                int r;
+
                 p->type = SOCKET_SOCKET;
+                k = unit_full_printf(UNIT(s), rvalue);
+                r = socket_address_parse(&p->address, k);
+                free(k);
 
-                if (socket_address_parse(&p->address, rvalue) < 0) {
+                if (r < 0) {
                         log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
                         free(p);
                         return 0;
@@ -255,7 +355,12 @@ static int config_parse_listen(
         }
 
         p->fd = -1;
-        LIST_PREPEND(SocketPort, port, s->ports, p);
+
+        if (s->ports) {
+                LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
+                LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
+        } else
+                LIST_PREPEND(SocketPort, port, s->ports, p);
 
         return 0;
 }
@@ -1007,10 +1112,23 @@ static int config_parse_cgroup(
         char *state;
 
         FOREACH_WORD_QUOTED(w, l, rvalue, state) {
-                char *t;
+                char *t, *k;
                 int r;
 
-                if (!(t = cunescape_length(w, l)))
+                t = strndup(w, l);
+                if (!t)
+                        return -ENOMEM;
+
+                k = unit_full_printf(u, t);
+                free(t);
+
+                if (!k)
+                        return -ENOMEM;
+
+                t = cunescape(k);
+                free(k);
+
+                if (!t)
                         return -ENOMEM;
 
                 r = unit_add_cgroup_from_text(u, t);
@@ -1407,18 +1525,27 @@ static int config_parse_env_file(
                 void *userdata) {
 
         char ***env = data, **k;
+        Unit *u = userdata;
+        char *s;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
-        if (!path_is_absolute(rvalue[0] == '-' ? rvalue + 1 : rvalue)) {
-                log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, rvalue);
+        s = unit_full_printf(u, rvalue);
+        if (!s)
+                return -ENOMEM;
+
+        if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
+                log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
+                free(s);
                 return 0;
         }
 
-        if (!(k = strv_append(*env, rvalue)))
+        k = strv_append(*env, s);
+        free(s);
+        if (!k)
                 return -ENOMEM;
 
         strv_free(*env);
@@ -1597,13 +1724,16 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
                  * unit name. */
                 name = file_name_from_path(*filename);
 
-                if (unit_name_is_valid(name, false)) {
-                        if (!(id = set_get(names, name))) {
+                if (unit_name_is_valid(name, true)) {
 
-                                if (!(id = strdup(name)))
+                        id = set_get(names, name);
+                        if (!id) {
+                                id = strdup(name);
+                                if (!id)
                                         return -ENOMEM;
 
-                                if ((r = set_put(names, id)) < 0) {
+                                r = set_put(names, id);
+                                if (r < 0) {
                                         free(id);
                                         return r;
                                 }
@@ -1692,6 +1822,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
                 { config_parse_bool,             "BOOLEAN" },
                 { config_parse_string,           "STRING" },
                 { config_parse_path,             "PATH" },
+                { config_parse_path_printf,      "PATH" },
                 { config_parse_strv,             "STRING [...]" },
                 { config_parse_nice,             "NICE" },
                 { config_parse_oom_score_adjust, "OOMSCOREADJUST" },
@@ -1785,8 +1916,8 @@ static int load_from_path(Unit *u, const char *path) {
         };
 
 #define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
-                { "WorkingDirectory",       config_parse_path,            0, &(context).working_directory,                    section   }, \
-                { "RootDirectory",          config_parse_path,            0, &(context).root_directory,                       section   }, \
+                { "WorkingDirectory",       config_parse_path_printf,     0, &(context).working_directory,                    section   }, \
+                { "RootDirectory",          config_parse_path_printf,     0, &(context).root_directory,                       section   }, \
                 { "User",                   config_parse_string_printf,   0, &(context).user,                                 section   }, \
                 { "Group",                  config_parse_string_printf,   0, &(context).group,                                section   }, \
                 { "SupplementaryGroups",    config_parse_strv,            0, &(context).supplementary_groups,                 section   }, \
@@ -1799,12 +1930,15 @@ static int load_from_path(Unit *u, const char *path) {
                 { "CPUSchedulingResetOnFork", config_parse_bool,          0, &(context).cpu_sched_reset_on_fork,              section   }, \
                 { "CPUAffinity",            config_parse_cpu_affinity,    0, &(context),                                      section   }, \
                 { "UMask",                  config_parse_mode,            0, &(context).umask,                                section   }, \
-                { "Environment",            config_parse_strv,            0, &(context).environment,                          section   }, \
+                { "Environment",            config_parse_strv_printf,     0, &(context).environment,                          section   }, \
                 { "EnvironmentFile",        config_parse_env_file,        0, &(context).environment_files,                    section   }, \
                 { "StandardInput",          config_parse_input,           0, &(context).std_input,                            section   }, \
                 { "StandardOutput",         config_parse_output,          0, &(context).std_output,                           section   }, \
                 { "StandardError",          config_parse_output,          0, &(context).std_error,                            section   }, \
-                { "TTYPath",                config_parse_path,            0, &(context).tty_path,                             section   }, \
+                { "TTYPath",                config_parse_path_printf,     0, &(context).tty_path,                             section   }, \
+                { "TTYReset",               config_parse_bool,            0, &(context).tty_reset,                            section   }, \
+                { "TTYVHangup",             config_parse_bool,            0, &(context).tty_vhangup,                          section   }, \
+                { "TTYVTDisallocate",       config_parse_bool,            0, &(context).tty_vt_disallocate,                   section   }, \
                 { "SyslogIdentifier",       config_parse_string_printf,   0, &(context).syslog_identifier,                    section   }, \
                 { "SyslogFacility",         config_parse_facility,        0, &(context).syslog_priority,                      section   }, \
                 { "SyslogLevel",            config_parse_level,           0, &(context).syslog_priority,                      section   }, \
@@ -1840,7 +1974,8 @@ static int load_from_path(Unit *u, const char *path) {
                 { "KillMode",               config_parse_kill_mode,       0, &(context).kill_mode,                            section   }, \
                 { "KillSignal",             config_parse_kill_signal,     0, &(context).kill_signal,                          section   }, \
                 { "SendSIGKILL",            config_parse_bool,            0, &(context).send_sigkill,                         section   }, \
-                { "UtmpIdentifier",         config_parse_string_printf,   0, &(context).utmp_id,                              section   }
+                { "UtmpIdentifier",         config_parse_string_printf,   0, &(context).utmp_id,                              section   }, \
+                { "ControlGroupModify",     config_parse_bool,            0, &(context).control_group_modify,                 section   }
 
         const ConfigItem items[] = {
                 { "Names",                  config_parse_names,           0, u,                                               "Unit"    },
@@ -1861,16 +1996,20 @@ static int load_from_path(Unit *u, const char *path) {
                 { "AllowIsolate",           config_parse_bool,            0, &u->meta.allow_isolate,                          "Unit"    },
                 { "DefaultDependencies",    config_parse_bool,            0, &u->meta.default_dependencies,                   "Unit"    },
                 { "OnFailureIsolate",       config_parse_bool,            0, &u->meta.on_failure_isolate,                     "Unit"    },
+                { "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"    },
+                { "ConditionFileIsExecutable",  config_parse_condition_path,   CONDITION_FILE_IS_EXECUTABLE,  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,            0, &u->service.pid_file,                            "Service" },
+                { "PIDFile",                config_parse_path_printf,     0, &u->service.pid_file,                            "Service" },
                 { "ExecStartPre",           config_parse_exec,            0, u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
                 { "ExecStart",              config_parse_exec,            0, u->service.exec_command+SERVICE_EXEC_START,      "Service" },
                 { "ExecStartPost",          config_parse_exec,            0, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
@@ -1902,6 +2041,8 @@ static int load_from_path(Unit *u, const char *path) {
                 { "ListenSequentialPacket", config_parse_listen,          0, &u->socket,                                      "Socket"  },
                 { "ListenFIFO",             config_parse_listen,          0, &u->socket,                                      "Socket"  },
                 { "ListenNetlink",          config_parse_listen,          0, &u->socket,                                      "Socket"  },
+                { "ListenSpecial",          config_parse_listen,          0, &u->socket,                                      "Socket"  },
+                { "ListenMessageQueue",     config_parse_listen,          0, &u->socket,                                      "Socket"  },
                 { "BindIPv6Only",           config_parse_socket_bind,     0, &u->socket,                                      "Socket"  },
                 { "Backlog",                config_parse_unsigned,        0, &u->socket.backlog,                              "Socket"  },
                 { "BindToDevice",           config_parse_bindtodevice,    0, &u->socket,                                      "Socket"  },
@@ -1923,7 +2064,11 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Mark",                   config_parse_int,             0, &u->socket.mark,                                 "Socket"  },
                 { "PipeSize",               config_parse_size,            0, &u->socket.pipe_size,                            "Socket"  },
                 { "FreeBind",               config_parse_bool,            0, &u->socket.free_bind,                            "Socket"  },
+                { "Transparent",            config_parse_bool,            0, &u->socket.transparent,                          "Socket"  },
+                { "Broadcast",              config_parse_bool,            0, &u->socket.broadcast,                            "Socket"  },
                 { "TCPCongestion",          config_parse_string,          0, &u->socket.tcp_congestion,                       "Socket"  },
+                { "MessageQueueMaxMessages", config_parse_long,           0, &u->socket.mq_maxmsg,                            "Socket"  },
+                { "MessageQueueMessageSize", config_parse_long,           0, &u->socket.mq_msgsize,                           "Socket"  },
                 { "Service",                config_parse_socket_service,  0, &u->socket,                                      "Socket"  },
                 EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
 
@@ -1951,6 +2096,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"    },