]> err.no Git - systemd/commitdiff
core: add minimal templating system
authorLennart Poettering <lennart@poettering.net>
Thu, 15 Apr 2010 01:11:11 +0000 (03:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 15 Apr 2010 01:11:15 +0000 (03:11 +0200)
26 files changed:
Makefile.am
dbus-job.c
dbus-manager.c
dbus-unit.c
device.c
execute.c
execute.h
job.c
job.h
load-dropin.c
load-fragment.c
main.c
manager.c
manager.h
mount.c
service.c
socket.c
specifier.c [new file with mode: 0644]
specifier.h [new file with mode: 0644]
target.c
test-engine.c
unit-name.c [new file with mode: 0644]
unit-name.h [new file with mode: 0644]
unit.c
unit.h
util.c

index 361786983d9e49ab90a1233b941804af31169697..8cad1420e0f239ef17b328c808d11b558aafc70f 100644 (file)
@@ -135,7 +135,11 @@ COMMON_SOURCES= \
        hostname-setup.c \
        hostname-setup.h \
        utmp-wtmp.c \
-       utmp-wtmp.h
+       utmp-wtmp.h \
+       specifier.c \
+       specifier.h \
+       unit-name.c \
+       unit-name.h
 
 systemd_SOURCES = \
        $(COMMON_SOURCES) \
index 9c6a798075600cd0a910219e45b7edf43ed24aa4..b0f575b11be921b1c183775624ffdd2a0e06bb24 100644 (file)
@@ -46,7 +46,6 @@ static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *prope
         Job *j = data;
         DBusMessageIter sub;
         char *p;
-        const char *id;
 
         assert(m);
         assert(i);
@@ -59,9 +58,7 @@ static int bus_job_append_unit(Manager *m, DBusMessageIter *i, const char *prope
         if (!(p = unit_dbus_path(j->unit)))
                 return -ENOMEM;
 
-        id = unit_id(j->unit);
-
-        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &id) ||
+        if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->meta.id) ||
             !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
                 free(p);
                 return -ENOMEM;
index 5f3d9647776e6a10050eac95bf384084f1bb0e3a..8deb451795ca8bf847b8da24c1e8e97f2c3a7da8 100644 (file)
@@ -175,7 +175,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
                                     DBUS_TYPE_INVALID))
                         return bus_send_error_reply(m, message, &error, -EINVAL);
 
-                if ((r = manager_load_unit(m, name, &u)) < 0)
+                if ((r = manager_load_unit(m, name, NULL, &u)) < 0)
                         return bus_send_error_reply(m, message, NULL, r);
 
                 if (!(reply = dbus_message_new_method_return(message)))
@@ -239,12 +239,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
 
                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
                         char *u_path, *j_path;
-                        const char *id, *description, *load_state, *active_state, *sub_state, *job_type;
+                        const char *description, *load_state, *active_state, *sub_state, *job_type;
                         DBusMessageIter sub2;
                         uint32_t job_id;
 
-                        id = unit_id(u);
-                        if (k != id)
+                        if (k != u->meta.id)
                                 continue;
 
                         if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
@@ -273,7 +272,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
                                 job_type = "";
                         }
 
-                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &id) ||
+                        if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
@@ -314,7 +313,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
 
                 HASHMAP_FOREACH(j, m->jobs, i) {
                         char *u_path, *j_path;
-                        const char *unit, *state, *type;
+                        const char *state, *type;
                         uint32_t id;
                         DBusMessageIter sub2;
 
@@ -322,7 +321,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
                                 goto oom;
 
                         id = (uint32_t) j->id;
-                        unit = unit_id(j->unit);
                         state = job_state_to_string(j->state);
                         type = job_type_to_string(j->type);
 
@@ -335,7 +333,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
                         }
 
                         if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
-                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &unit) ||
+                            !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->meta.id) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
                             !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
@@ -434,7 +432,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection  *connection
                 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
                         char *p;
 
-                        if (k != unit_id(u))
+                        if (k != u->meta.id)
                                 continue;
 
                         if (!(p = bus_path_escape(k))) {
index 7897b857b67585b8e01b595be590ddafe3d90cd3..6bccec14a71fef7eee247b60cf3e81a388fe099d 100644 (file)
@@ -61,23 +61,6 @@ static const char introspection[] =
         BUS_INTROSPECTABLE_INTERFACE
         "</node>";
 
-static int bus_unit_append_id(Manager *m, DBusMessageIter *i, const char *property, void *data) {
-        Unit *u = data;
-        const char *id;
-
-        assert(m);
-        assert(i);
-        assert(property);
-        assert(u);
-
-        id = unit_id(u);
-
-        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
-                return -ENOMEM;
-
-        return 0;
-}
-
 static int bus_unit_append_description(Manager *m, DBusMessageIter *i, const char *property, void *data) {
         Unit *u = data;
         const char *d;
@@ -216,7 +199,7 @@ static int bus_unit_append_job(Manager *m, DBusMessageIter *i, const char *prope
 static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message) {
 
         const BusProperty properties[] = {
-                { "org.freedesktop.systemd1.Unit", "Id",                   bus_unit_append_id,           "s",    u                               },
+                { "org.freedesktop.systemd1.Unit", "Id",                   bus_property_append_string,   "s",    u->meta.id                      },
                 { "org.freedesktop.systemd1.Unit", "Description",          bus_unit_append_description,  "s",    u                               },
                 { "org.freedesktop.systemd1.Unit", "LoadState",            bus_unit_append_load_state,   "s",    &u->meta.load_state             },
                 { "org.freedesktop.systemd1.Unit", "ActiveState",          bus_unit_append_active_state, "s",    u                               },
@@ -353,15 +336,13 @@ void bus_unit_send_change_signal(Unit *u) {
                 if (!(m = dbus_message_new_signal(p, "org.freedesktop.systemd1.Unit", "Changed")))
                         goto oom;
         } else {
-                const char *id;
                 /* Send a new signal */
 
                 if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1", "UnitNew")))
                         goto oom;
 
-                id = unit_id(u);
                 if (!dbus_message_append_args(m,
-                                              DBUS_TYPE_STRING, &id,
+                                              DBUS_TYPE_STRING, &u->meta.id,
                                               DBUS_TYPE_OBJECT_PATH, &p,
                                               DBUS_TYPE_INVALID))
                         goto oom;
@@ -389,7 +370,6 @@ oom:
 void bus_unit_send_removed_signal(Unit *u) {
         char *p = NULL;
         DBusMessage *m = NULL;
-        const char *id;
 
         assert(u);
 
@@ -402,9 +382,8 @@ void bus_unit_send_removed_signal(Unit *u) {
         if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1", "UnitRemoved")))
                 goto oom;
 
-        id = unit_id(u);
         if (!dbus_message_append_args(m,
-                                      DBUS_TYPE_STRING, &id,
+                                      DBUS_TYPE_STRING, &u->meta.id,
                                       DBUS_TYPE_OBJECT_PATH, &p,
                                       DBUS_TYPE_INVALID))
                 goto oom;
index b00a0f987f6fb227b7192241e9a2d57f30866dc9..1c4c32931c0caea39f71d628494d76317579a346 100644 (file)
--- a/device.c
+++ b/device.c
@@ -27,6 +27,7 @@
 #include "device.h"
 #include "strv.h"
 #include "log.h"
+#include "unit-name.h"
 
 static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
         [DEVICE_DEAD] = UNIT_INACTIVE,
@@ -64,7 +65,7 @@ static void device_set_state(Device *d, DeviceState state) {
         d->state = state;
 
         if (state != old_state)
-                log_debug("%s changed %s → %s", unit_id(UNIT(d)), state_string_table[old_state], state_string_table[state]);
+                log_debug("%s changed %s → %s", UNIT(d)->meta.id, state_string_table[old_state], state_string_table[state]);
 
         unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state]);
 }
@@ -113,7 +114,7 @@ static int device_add_escaped_name(Unit *u, const char *dn, bool make_id) {
         assert(dn);
         assert(dn[0] == '/');
 
-        if (!(e = unit_name_escape_path(dn+1, ".device")))
+        if (!(e = unit_name_build_escape(dn+1, NULL, ".device")))
                 return -ENOMEM;
 
         r = unit_add_name(u, e);
@@ -138,7 +139,7 @@ static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
         assert(dn[0] == '/');
         assert(_u);
 
-        if (!(e = unit_name_escape_path(dn+1, ".device")))
+        if (!(e = unit_name_build_escape(dn+1, NULL, ".device")))
                 return -ENOMEM;
 
         u = manager_get_unit(m, e);
@@ -303,7 +304,7 @@ static int device_process_new_device(Manager *m, struct udev_device *dev, bool u
                                 goto fail;
                         }
 
-                        r = unit_add_dependency_by_name(u, UNIT_WANTS, e);
+                        r = unit_add_dependency_by_name(u, UNIT_WANTS, NULL, e);
                         free(e);
 
                         if (r < 0)
@@ -356,7 +357,7 @@ static int device_process_removed_device(Manager *m, struct udev_device *dev) {
                 return -ENOMEM;
 
         assert(sysfs[0] == '/');
-        if (!(e = unit_name_escape_path(sysfs+1, ".device")))
+        if (!(e = unit_name_build_escape(sysfs+1, NULL, ".device")))
                 return -ENOMEM;
 
         u = manager_get_unit(m, e);
@@ -414,21 +415,21 @@ static int device_enumerate(Manager *m) {
         if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
                 return -errno;
 
-        if (!(e = udev_enumerate_new(m->udev))) {
-                r = -ENOMEM;
-                goto fail;
-        }
+        /* if (!(e = udev_enumerate_new(m->udev))) { */
+        /*         r = -ENOMEM; */
+        /*         goto fail; */
+        /* } */
 
-        if (udev_enumerate_scan_devices(e) < 0) {
-                r = -EIO;
-                goto fail;
-        }
+        /* if (udev_enumerate_scan_devices(e) < 0) { */
+        /*         r = -EIO; */
+        /*         goto fail; */
+        /* } */
 
-        first = udev_enumerate_get_list_entry(e);
-        udev_list_entry_foreach(item, first)
-                device_process_path(m, udev_list_entry_get_name(item), false);
+        /* first = udev_enumerate_get_list_entry(e); */
+        /* udev_list_entry_foreach(item, first) */
+        /*         device_process_path(m, udev_list_entry_get_name(item), false); */
 
-        udev_enumerate_unref(e);
+        /* udev_enumerate_unref(e); */
         return 0;
 
 fail:
@@ -476,6 +477,9 @@ fail:
 const UnitVTable device_vtable = {
         .suffix = ".device",
 
+        .no_requires = true,
+        .no_instances = true,
+
         .init = device_init,
         .load = unit_load_fragment_and_dropin_optional,
         .done = device_done,
index 73d82d5a76218ac50d839ec80466b8d6fe5e80e1..9b407258ff20f00307af6c2a00832aa0c7a1e688 100644 (file)
--- a/execute.c
+++ b/execute.c
@@ -665,6 +665,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
 }
 
 int exec_spawn(ExecCommand *command,
+               char **argv,
                const ExecContext *context,
                int fds[], unsigned n_fds,
                bool apply_permissions,
@@ -682,7 +683,10 @@ int exec_spawn(ExecCommand *command,
         assert(ret);
         assert(fds || n_fds <= 0);
 
-        if (!(line = exec_command_line(command)))
+        if (!argv)
+                argv = command->argv;
+
+        if (!(line = exec_command_line(argv)))
                 return -ENOMEM;
 
         log_debug("About to execute: %s", line);
@@ -732,7 +736,7 @@ int exec_spawn(ExecCommand *command,
                                 goto fail;
 
                         /* Now ask the question. */
-                        if (!(line = exec_command_line(command))) {
+                        if (!(line = exec_command_line(argv))) {
                                 r = EXIT_MEMORY;
                                 goto fail;
                         }
@@ -950,7 +954,7 @@ int exec_spawn(ExecCommand *command,
                         goto fail;
                 }
 
-                execve(command->path, command->argv, final_env);
+                execve(command->path, argv, final_env);
                 r = EXIT_EXEC;
 
         fail:
@@ -1270,23 +1274,22 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
                         prefix, s->status);
 }
 
-char *exec_command_line(ExecCommand *c) {
+char *exec_command_line(char **argv) {
         size_t k;
         char *n, *p, **a;
         bool first = true;
 
-        assert(c);
-        assert(c->argv);
+        assert(argv);
 
         k = 1;
-        STRV_FOREACH(a, c->argv)
+        STRV_FOREACH(a, argv)
                 k += strlen(*a)+3;
 
         if (!(n = new(char, k)))
                 return NULL;
 
         p = n;
-        STRV_FOREACH(a, c->argv) {
+        STRV_FOREACH(a, argv) {
 
                 if (!first)
                         *(p++) = ' ';
@@ -1324,7 +1327,7 @@ void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
         p2 = strappend(prefix, "\t");
         prefix2 = p2 ? p2 : prefix;
 
-        cmd = exec_command_line(c);
+        cmd = exec_command_line(c->argv);
 
         fprintf(f,
                 "%sCommand Line: %s\n",
index 0ed3ecd7809e379abe1818526535e02e3e8348c8..6d877ff7b7edd9b57790076fc3387f762ae16aaa 100644 (file)
--- a/execute.h
+++ b/execute.h
@@ -163,6 +163,7 @@ typedef enum ExitStatus {
 } ExitStatus;
 
 int exec_spawn(ExecCommand *command,
+               char **argv,
                const ExecContext *context,
                int fds[], unsigned n_fds,
                bool apply_permissions,
@@ -177,7 +178,8 @@ void exec_command_done_array(ExecCommand *c, unsigned n);
 void exec_command_free_list(ExecCommand *c);
 void exec_command_free_array(ExecCommand **c, unsigned n);
 
-char *exec_command_line(ExecCommand *c);
+char *exec_command_line(char **argv);
+
 void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix);
 void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
 void exec_command_append_list(ExecCommand **l, ExecCommand *e);
diff --git a/job.c b/job.c
index 5e250d58f0ca0b9caca6c1aaaf7b3de8c07394ec..0e03fcdc77b4a943f9eec90259f75f3e99ea11c8 100644 (file)
--- a/job.c
+++ b/job.c
@@ -152,9 +152,9 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
                 "%s\tState: %s\n"
                 "%s\tForced: %s\n",
                 prefix, j->id,
-                prefix, unit_id(j->unit), job_type_to_string(j->type),
+                prefix, j->unit->meta.id, job_type_to_string(j->type),
                 prefix, job_state_to_string(j->state),
-                prefix, yes_no(j->forced));
+                prefix, yes_no(j->override));
 }
 
 bool job_is_anchor(Job *j) {
@@ -455,15 +455,15 @@ int job_finish_and_invalidate(Job *j, bool success) {
         assert(j);
         assert(j->installed);
 
-        log_debug("Job %s/%s finished, success=%s", unit_id(j->unit), job_type_to_string(j->type), yes_no(success));
+        log_debug("Job %s/%s finished, success=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(success));
         job_add_to_dbus_queue(j);
 
         /* Patch restart jobs so that they become normal start jobs */
         if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
 
                 log_debug("Converting job %s/%s → %s/%s",
-                          unit_id(j->unit), job_type_to_string(j->type),
-                          unit_id(j->unit), job_type_to_string(JOB_START));
+                          j->unit->meta.id, job_type_to_string(j->type),
+                          j->unit->meta.id, job_type_to_string(JOB_START));
 
                 j->state = JOB_RUNNING;
                 j->type = JOB_START;
@@ -490,9 +490,9 @@ int job_finish_and_invalidate(Job *j, bool success) {
                                      other->meta.job->type == JOB_RELOAD_OR_START))
                                         job_finish_and_invalidate(other->meta.job, false);
 
-                        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRED_BY], i)
+                        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
                                 if (other->meta.job &&
-                                    !other->meta.job->forced &&
+                                    !other->meta.job->override &&
                                     (other->meta.job->type == JOB_START ||
                                      other->meta.job->type == JOB_VERIFY_ACTIVE ||
                                      other->meta.job->type == JOB_RELOAD_OR_START))
diff --git a/job.h b/job.h
index 5bea2948c7b1b922afc0627595b17a56dc775beb..d04ca9d5b4ebd59ea55ae1b9357ec46a69e17586 100644 (file)
--- a/job.h
+++ b/job.h
@@ -93,7 +93,7 @@ struct Job {
         bool installed:1;
         bool in_run_queue:1;
         bool matters_to_anchor:1;
-        bool forced:1;
+        bool override:1;
         bool in_dbus_queue:1;
         bool sent_dbus_new_signal:1;
 
index a3c9d3c77dde42b5eb859494eff1bd7880220ad6..89e142f9a8f11d77f15c0288e34afd2a7df37d28 100644 (file)
 #include "load-dropin.h"
 #include "log.h"
 #include "strv.h"
+#include "unit-name.h"
+
+static int iterate_dir(Unit *u, const char *path) {
+        DIR *d;
+        struct dirent *de;
+        int r;
+
+        if (!(d = opendir(path))) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                return -errno;
+        }
+
+        while ((de = readdir(d))) {
+                char *f;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                if (asprintf(&f, "%s/%s", path, de->d_name) < 0) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
+
+                r = unit_add_dependency_by_name(u, UNIT_WANTS, de->d_name, f);
+                free(f);
+
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = 0;
+
+finish:
+        closedir(d);
+        return r;
+}
 
 int unit_load_dropin(Unit *u) {
         Iterator i;
@@ -38,8 +77,6 @@ int unit_load_dropin(Unit *u) {
 
         SET_FOREACH(t, u->meta.names, i) {
                 char *path;
-                DIR *d;
-                struct dirent *de;
                 char **p;
 
                 STRV_FOREACH(p, u->meta.manager->unit_path) {
@@ -47,44 +84,32 @@ int unit_load_dropin(Unit *u) {
                         if (asprintf(&path, "%s/%s.wants", *p, t) < 0)
                                 return -ENOMEM;
 
-                        if (!(d = opendir(path))) {
-                                r = -errno;
-                                free(path);
-
-                                if (r == -ENOENT)
-                                        continue;
+                        r = iterate_dir(u, path);
+                        free(path);
 
+                        if (r < 0)
                                 return r;
-                        }
 
-                        free(path);
+                        if (u->meta.instance) {
+                                char *template;
+                                /* Also try the template dir */
 
-                        while ((de = readdir(d))) {
+                                if (!(template = unit_name_template(t)))
+                                        return -ENOMEM;
 
-                                if (ignore_file(de->d_name))
-                                        continue;
+                                r = asprintf(&path, "%s/%s.wants", *p, template);
+                                free(template);
 
-                                if (asprintf(&path, "%s/%s.wants/%s", *p, t, de->d_name) < 0) {
-                                        closedir(d);
+                                if (r < 0)
                                         return -ENOMEM;
-                                }
-
-                                if (!unit_name_is_valid(de->d_name)) {
-                                        log_info("Name of %s is not a valid unit name. Ignoring.", path);
-                                        free(path);
-                                        continue;
-                                }
 
-                                r = unit_add_dependency_by_name(u, UNIT_WANTS, path);
+                                r = iterate_dir(u, path);
                                 free(path);
 
-                                if (r < 0) {
-                                        closedir(d);
+                                if (r < 0)
                                         return r;
-                                }
                         }
 
-                        closedir(d);
                 }
         }
 
index 47cfcd676c45a391fce4b1c678bebe44b2541ffc..5093c6dea96859000a21cede1527ec98e3326fa0 100644 (file)
@@ -36,6 +36,7 @@
 #include "ioprio.h"
 #include "securebits.h"
 #include "missing.h"
+#include "unit-name.h"
 
 #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg)                \
         static int function(                                            \
@@ -83,25 +84,22 @@ static int config_parse_deps(
         assert(lvalue);
         assert(rvalue);
 
-        if (UNIT_VTABLE(u)->refuse_requires &&
-            (d == UNIT_REQUIRES ||
-             d == UNIT_SOFT_REQUIRES ||
-             d == UNIT_REQUISITE ||
-             d == UNIT_SOFT_REQUISITE)) {
-                    log_error("[%s:%u] Dependency of type %s not acceptable for this unit type.", filename, line, lvalue);
-                    return -EBADMSG;
-            }
-
         FOREACH_WORD(w, l, rvalue, state) {
-                char *t;
+                char *t, *k;
                 int r;
 
                 if (!(t = strndup(w, l)))
                         return -ENOMEM;
 
-                r = unit_add_dependency_by_name(u, d, t);
+                k = unit_name_printf(u, t);
                 free(t);
 
+                if (!k)
+                        return -ENOMEM;
+
+                r = unit_add_dependency_by_name(u, d, k, NULL);
+                free(k);
+
                 if (r < 0)
                         return r;
         }
@@ -129,15 +127,21 @@ static int config_parse_names(
         assert(data);
 
         FOREACH_WORD(w, l, rvalue, state) {
-                char *t;
+                char *t, *k;
                 int r;
 
                 if (!(t = strndup(w, l)))
                         return -ENOMEM;
 
-                r = unit_merge_by_name(u, t);
+                k = unit_name_printf(u, t);
                 free(t);
 
+                if (!k)
+                        return -ENOMEM;
+
+                r = unit_merge_by_name(u, k);
+                free(k);
+
                 if (r < 0)
                         return r;
         }
@@ -907,7 +911,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to
 
 #define FOLLOW_MAX 8
 
-static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
+static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
         unsigned c = 0;
         int fd, r;
         FILE *f;
@@ -966,12 +970,12 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_id) {
 
         if (!(f = fdopen(fd, "r"))) {
                 r = -errno;
-                assert(close_nointr(fd) == 0);
+                close_nointr_nofail(fd);
                 return r;
         }
 
         *_f = f;
-        *_id = id;
+        *_final = id;
         return 0;
 }
 
@@ -1151,10 +1155,10 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Names",                  config_parse_names,           u,                                               "Meta"    },
                 { "Description",            config_parse_string,          &u->meta.description,                            "Meta"    },
                 { "Requires",               config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES),                      "Meta"    },
-                { "SoftRequires",           config_parse_deps,            UINT_TO_PTR(UNIT_SOFT_REQUIRES),                 "Meta"    },
-                { "Wants",                  config_parse_deps,            UINT_TO_PTR(UNIT_WANTS),                         "Meta"    },
+                { "RequiresOverridable",    config_parse_deps,            UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE),          "Meta"    },
                 { "Requisite",              config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE),                     "Meta"    },
-                { "SoftRequisite",          config_parse_deps,            UINT_TO_PTR(UNIT_SOFT_REQUISITE),                "Meta"    },
+                { "RequisiteOverridable",   config_parse_deps,            UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE),         "Meta"    },
+                { "Wants",                  config_parse_deps,            UINT_TO_PTR(UNIT_WANTS),                         "Meta"    },
                 { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Meta"    },
                 { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Meta"    },
                 { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Meta"    },
@@ -1336,15 +1340,14 @@ int unit_load_fragment(Unit *u) {
                 const char *t;
 
                 /* Try to find the unit under its id */
-                if ((t = unit_id(u)))
-                        if ((r = load_from_path(u, t)) < 0)
-                                return r;
+                if ((r = load_from_path(u, u->meta.id)) < 0)
+                        return r;
 
                 /* Try to find an alias we can load this with */
                 if (u->meta.load_state == UNIT_STUB)
                         SET_FOREACH(t, u->meta.names, i) {
 
-                                if (unit_id(u) == t)
+                                if (t == u->meta.id)
                                         continue;
 
                                 if ((r = load_from_path(u, t)) < 0)
@@ -1353,6 +1356,39 @@ int unit_load_fragment(Unit *u) {
                                 if (u->meta.load_state != UNIT_STUB)
                                         break;
                         }
+
+                /* Now, follow the same logic, but look for a template */
+                if (u->meta.load_state == UNIT_STUB && u->meta.instance) {
+                        char *k;
+
+                        if (!(k = unit_name_template(u->meta.id)))
+                                return -ENOMEM;
+
+                        r = load_from_path(u, k);
+                        free(k);
+
+                        if (r < 0)
+                                return r;
+
+                        if (u->meta.load_state == UNIT_STUB)
+                                SET_FOREACH(t, u->meta.names, i) {
+
+                                        if (t == u->meta.id)
+                                                continue;
+
+                                        if (!(k = unit_name_template(t)))
+                                                return -ENOMEM;
+
+                                        r = load_from_path(u, k);
+                                        free(k);
+
+                                        if (r < 0)
+                                                return r;
+
+                                        if (u->meta.load_state != UNIT_STUB)
+                                                break;
+                                }
+                }
         }
 
         return 0;
diff --git a/main.c b/main.c
index c1a15008adcbc20083d090d453cd3bfea7f8d8a8..c473ced2b41c04e0e2bd01e1424423ddd0e6c582 100644 (file)
--- a/main.c
+++ b/main.c
@@ -555,11 +555,11 @@ int main(int argc, char *argv[]) {
 
         log_debug("Activating default unit: %s", default_unit);
 
-        if ((r = manager_load_unit(m, default_unit, &target)) < 0) {
+        if ((r = manager_load_unit(m, default_unit, NULL, &target)) < 0) {
                 log_error("Failed to load default target: %s", strerror(-r));
 
                 log_info("Trying to load rescue target...");
-                if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, &target)) < 0) {
+                if ((r = manager_load_unit(m, SPECIAL_RESCUE_TARGET, NULL, &target)) < 0) {
                         log_error("Failed to load rescue target: %s", strerror(-r));
                         goto finish;
                 }
index 82dc9a676bb344273aeb2b9c9f9adc0cbf715bf5..07b2d4ac9a5eb85e00447550bf329b2a34ec858d 100644 (file)
--- a/manager.c
+++ b/manager.c
@@ -46,6 +46,7 @@
 #include "cgroup.h"
 #include "mount-setup.h"
 #include "utmp-wtmp.h"
+#include "unit-name.h"
 
 static int enable_special_signals(Manager *m) {
         char fd;
@@ -448,7 +449,7 @@ int manager_coldplug(Manager *m) {
         HASHMAP_FOREACH_KEY(u, k, m->units, i) {
 
                 /* ignore aliases */
-                if (unit_id(u) != k)
+                if (u->meta.id != k)
                         continue;
 
                 if (UNIT_VTABLE(u)->coldplug)
@@ -563,7 +564,7 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job
 
         j->type = t;
         j->state = JOB_WAITING;
-        j->forced = j->forced || other->forced;
+        j->override = j->override || other->override;
 
         j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
 
@@ -635,7 +636,7 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) {
                                 return -ENOEXEC;
 
                         /* Ok, we can drop one, so let's do so. */
-                        log_debug("Trying to fix job merging by deleting job %s/%s", unit_id(d->unit), job_type_to_string(d->type));
+                        log_debug("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type));
                         transaction_delete_job(m, d, true);
                         return 0;
                 }
@@ -735,7 +736,7 @@ static void transaction_drop_redundant(Manager *m) {
                         if (changes_something)
                                 continue;
 
-                        log_debug("Found redundant job %s/%s, dropping.", unit_id(j->unit), job_type_to_string(j->type));
+                        log_debug("Found redundant job %s/%s, dropping.", j->unit->meta.id, job_type_to_string(j->type));
                         transaction_delete_job(m, j, false);
                         again = true;
                         break;
@@ -781,17 +782,17 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned
                  * since smart how we are we stored our way back in
                  * there. */
 
-                log_debug("Found ordering cycle on %s/%s", unit_id(j->unit), job_type_to_string(j->type));
+                log_debug("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
 
                 for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
 
-                        log_debug("Walked on cycle path to %s/%s", unit_id(k->unit), job_type_to_string(k->type));
+                        log_debug("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
 
                         if (!k->installed &&
                             !unit_matters_to_anchor(k->unit, k)) {
                                 /* Ok, we can drop this one, so let's
                                  * do so. */
-                                log_debug("Breaking order cycle by deleting job %s/%s", unit_id(k->unit), job_type_to_string(k->type));
+                                log_debug("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type));
                                 transaction_delete_unit(m, k->unit);
                                 return -EAGAIN;
                         }
@@ -872,7 +873,7 @@ static void transaction_collect_garbage(Manager *m) {
                         if (j->object_list)
                                 continue;
 
-                        log_debug("Garbage collecting job %s/%s", unit_id(j->unit), job_type_to_string(j->type));
+                        log_debug("Garbage collecting job %s/%s", j->unit->meta.id, job_type_to_string(j->type));
                         transaction_delete_job(m, j, true);
                         again = true;
                         break;
@@ -940,13 +941,13 @@ static void transaction_minimize_impact(Manager *m) {
                                         continue;
 
                                 if (stops_running_service)
-                                        log_debug("%s/%s would stop a running service.", unit_id(j->unit), job_type_to_string(j->type));
+                                        log_debug("%s/%s would stop a running service.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 if (changes_existing_job)
-                                        log_debug("%s/%s would change existing job.", unit_id(j->unit), job_type_to_string(j->type));
+                                        log_debug("%s/%s would change existing job.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 /* Ok, let's get rid of this */
-                                log_debug("Deleting %s/%s to minimize impact.", unit_id(j->unit), job_type_to_string(j->type));
+                                log_debug("Deleting %s/%s to minimize impact.", j->unit->meta.id, job_type_to_string(j->type));
 
                                 transaction_delete_job(m, j, true);
                                 again = true;
@@ -1101,7 +1102,7 @@ rollback:
         return r;
 }
 
-static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool force, bool *is_new) {
+static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool override, bool *is_new) {
         Job *j, *f;
         int r;
 
@@ -1132,7 +1133,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool f
         j->generation = 0;
         j->marker = NULL;
         j->matters_to_anchor = false;
-        j->forced = force;
+        j->override = override;
 
         LIST_PREPEND(Job, transaction, f, j);
 
@@ -1144,7 +1145,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool f
         if (is_new)
                 *is_new = true;
 
-        log_debug("Added job %s/%s to transaction.", unit_id(unit), job_type_to_string(type));
+        log_debug("Added job %s/%s to transaction.", unit->meta.id, job_type_to_string(type));
 
         return j;
 }
@@ -1175,14 +1176,21 @@ void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies
 
                 if (other && delete_dependencies) {
                         log_debug("Deleting job %s/%s as dependency of job %s/%s",
-                                  unit_id(other->unit), job_type_to_string(other->type),
-                                  unit_id(j->unit), job_type_to_string(j->type));
+                                  other->unit->meta.id, job_type_to_string(other->type),
+                                  j->unit->meta.id, job_type_to_string(j->type));
                         transaction_delete_job(m, other, delete_dependencies);
                 }
         }
 }
 
-static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit *unit, Job *by, bool matters, bool force, Job **_ret) {
+static int transaction_add_job_and_dependencies(
+                Manager *m,
+                JobType type,
+                Unit *unit,
+                Job *by,
+                bool matters,
+                bool override,
+                Job **_ret) {
         Job *ret;
         Iterator i;
         Unit *dep;
@@ -1200,7 +1208,7 @@ static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit *
                 return -EBADR;
 
         /* First add the job. */
-        if (!(ret = transaction_add_one_job(m, type, unit, force, &is_new)))
+        if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
                 return -ENOMEM;
 
         /* Then, add a link to the job. */
@@ -1211,28 +1219,33 @@ static int transaction_add_job_and_dependencies(Manager *m, JobType type, Unit *
                 /* Finally, recursively add in all dependencies. */
                 if (type == JOB_START || type == JOB_RELOAD_OR_START) {
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUIRES], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
                                         goto fail;
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, force, NULL)) < 0)
-                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", unit_id(dep), strerror(-r));
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, NULL)) < 0)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
-                                        goto fail;
-                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_SOFT_REQUISITE], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !force, force, NULL)) < 0 && r != -EBADR)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
                                         goto fail;
+
+                        SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, NULL)) < 0 && r != -EBADR)
+                                        log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, strerror(-r));
+
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
-                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
+                                if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
                                         goto fail;
 
                 } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
 
                         SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
-                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, force, NULL)) < 0 && r != -EBADR)
+                                if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, NULL)) < 0 && r != -EBADR)
                                         goto fail;
                 }
 
@@ -1248,7 +1261,7 @@ fail:
         return r;
 }
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret) {
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, Job **_ret) {
         int r;
         Job *ret;
 
@@ -1257,9 +1270,9 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for
         assert(unit);
         assert(mode < _JOB_MODE_MAX);
 
-        log_debug("Trying to enqueue job %s/%s", unit_id(unit), job_type_to_string(type));
+        log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type));
 
-        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, force, &ret)) < 0) {
+        if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, &ret)) < 0) {
                 transaction_abort(m);
                 return r;
         }
@@ -1267,7 +1280,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for
         if ((r = transaction_activate(m, mode)) < 0)
                 return r;
 
-        log_debug("Enqueued job %s/%s as %u", unit_id(unit), job_type_to_string(type), (unsigned) ret->id);
+        log_debug("Enqueued job %s/%s as %u", unit->meta.id, job_type_to_string(type), (unsigned) ret->id);
 
         if (_ret)
                 *_ret = ret;
@@ -1275,7 +1288,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool for
         return 0;
 }
 
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, Job **_ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, Job **_ret) {
         Unit *unit;
         int r;
 
@@ -1284,10 +1297,10 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
         assert(name);
         assert(mode < _JOB_MODE_MAX);
 
-        if ((r = manager_load_unit(m, name, &unit)) < 0)
+        if ((r = manager_load_unit(m, name, NULL, &unit)) < 0)
                 return r;
 
-        return manager_add_job(m, type, unit, mode, force, _ret);
+        return manager_add_job(m, type, unit, mode, override, _ret);
 }
 
 Job *manager_get_job(Manager *m, uint32_t id) {
@@ -1329,19 +1342,24 @@ unsigned manager_dispatch_load_queue(Manager *m) {
         return n;
 }
 
-int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
+int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret) {
         Unit *ret;
         int r;
-        const char *name;
 
         assert(m);
-        assert(path);
-        assert(_ret);
+        assert(name || path);
 
         /* This will load the service information files, but not actually
          * start any services or anything. */
 
-        name = file_name_from_path(path);
+        if (path && !is_path(path))
+                return -EINVAL;
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        if (!unit_name_is_valid(name))
+                return -EINVAL;
 
         if ((ret = manager_get_unit(m, name))) {
                 *_ret = ret;
@@ -1351,12 +1369,11 @@ int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
         if (!(ret = unit_new(m)))
                 return -ENOMEM;
 
-        if (is_path(path)) {
+        if (path)
                 if (!(ret->meta.fragment_path = strdup(path))) {
                         unit_free(ret);
                         return -ENOMEM;
                 }
-        }
 
         if ((r = unit_add_name(ret, name)) < 0) {
                 unit_free(ret);
@@ -1368,7 +1385,9 @@ int manager_load_unit(Manager *m, const char *path, Unit **_ret) {
 
         manager_dispatch_load_queue(m);
 
-        *_ret = unit_follow_merge(ret);
+        if (_ret)
+                *_ret = unit_follow_merge(ret);
+
         return 0;
 }
 
@@ -1392,7 +1411,7 @@ void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
         assert(f);
 
         HASHMAP_FOREACH_KEY(u, t, s->units, i)
-                if (unit_id(u) == t)
+                if (u->meta.id == t)
                         unit_dump(u, f, prefix);
 }
 
@@ -1512,7 +1531,7 @@ static int manager_dispatch_sigchld(Manager *m) {
                 if (!(u = hashmap_remove(m->watch_pids, UINT32_TO_PTR(si.si_pid))))
                         continue;
 
-                log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, unit_id(u));
+                log_debug("Child %llu belongs to %s", (long long unsigned) si.si_pid, u->meta.id);
 
                 UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
         }
index b6030a02374c018059c33647172786297958216f..a2b7b7ef8dcbf690f2894c68e21cf8d05715d81b 100644 (file)
--- a/manager.h
+++ b/manager.h
@@ -196,7 +196,7 @@ Unit *manager_get_unit(Manager *m, const char *name);
 int manager_get_unit_from_dbus_path(Manager *m, const char *s, Unit **_u);
 int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
 
-int manager_load_unit(Manager *m, const char *path_or_name, Unit **_ret);
+int manager_load_unit(Manager *m, const char *name, const char *path, Unit **_ret);
 
 int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, Job **_ret);
 int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, Job **_ret);
diff --git a/mount.c b/mount.c
index 2e3abcc6bc4a080db8f50b6ebe6a8eaa6594d15f..597df9e614fe289893a501247da57ad5cc6a3f8d 100644 (file)
--- a/mount.c
+++ b/mount.c
@@ -32,6 +32,7 @@
 #include "log.h"
 #include "strv.h"
 #include "mount-setup.h"
+#include "unit-name.h"
 
 static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
         [MOUNT_DEAD] = UNIT_INACTIVE,
@@ -156,10 +157,10 @@ static int mount_add_node_links(Mount *m) {
         if (!path_startswith(what, "/dev/"))
                 return 0;
 
-        if (!(e = unit_name_escape_path(what+1, ".device")))
+        if (!(e = unit_name_build_escape(what+1, NULL, ".device")))
                 return -ENOMEM;
 
-        r = manager_load_unit(UNIT(m)->meta.manager, e, &device);
+        r = manager_load_unit(UNIT(m)->meta.manager, e, NULL, &device);
         free(e);
 
         if (r < 0)
@@ -268,7 +269,7 @@ static int mount_add_target_links(Mount *m) {
         else
                 target = SPECIAL_LOCAL_FS_TARGET;
 
-        if ((r = manager_load_unit(UNIT(m)->meta.manager, target, &u)) < 0)
+        if ((r = manager_load_unit(UNIT(m)->meta.manager, target, NULL, &u)) < 0)
                 return r;
 
         if (handle)
@@ -337,7 +338,7 @@ static void mount_set_state(Mount *m, MountState state) {
         }
 
         if (state != old_state)
-                log_debug("%s changed %s → %s", unit_id(UNIT(m)), state_string_table[old_state], state_string_table[state]);
+                log_debug("%s changed %s → %s", UNIT(m)->meta.id, state_string_table[old_state], state_string_table[state]);
 
         unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state]);
 }
@@ -366,6 +367,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
                 goto fail;
 
         if ((r = exec_spawn(c,
+                            NULL,
                             &m->exec_context,
                             NULL, 0,
                             true,
@@ -492,7 +494,7 @@ static void mount_enter_signal(Mount *m, MountState state, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to kill processes: %s", unit_id(UNIT(m)), strerror(-r));
+        log_warning("%s failed to kill processes: %s", UNIT(m)->meta.id, strerror(-r));
 
         if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
                 mount_enter_mounted(m, false);
@@ -528,7 +530,7 @@ static void mount_enter_unmounting(Mount *m, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run umount exectuable: %s", unit_id(UNIT(m)), strerror(-r));
+        log_warning("%s failed to run umount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
         mount_enter_mounted(m, false);
 }
 
@@ -574,7 +576,7 @@ static void mount_enter_mounting(Mount *m, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run mount exectuable: %s", unit_id(UNIT(m)), strerror(-r));
+        log_warning("%s failed to run mount exectuable: %s", UNIT(m)->meta.id, strerror(-r));
         mount_enter_dead(m, false);
 }
 
@@ -745,7 +747,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         exec_status_fill(&m->control_command->exec_status, pid, code, status);
         m->control_pid = 0;
 
-        log_debug("%s control process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status);
+        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
 
         /* Note that mount(8) returning and the kernel sending us a
          * mount table change event might happen out-of-order. If an
@@ -800,39 +802,39 @@ static void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
 
         case MOUNT_MOUNTING:
         case MOUNT_MOUNTING_DONE:
-                log_warning("%s mounting timed out. Stopping.", unit_id(u));
+                log_warning("%s mounting timed out. Stopping.", u->meta.id);
                 mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, false);
                 break;
 
         case MOUNT_REMOUNTING:
-                log_warning("%s remounting timed out. Stopping.", unit_id(u));
+                log_warning("%s remounting timed out. Stopping.", u->meta.id);
                 mount_enter_signal(m, MOUNT_REMOUNTING_SIGTERM, false);
                 break;
 
         case MOUNT_UNMOUNTING:
-                log_warning("%s unmounting timed out. Stopping.", unit_id(u));
+                log_warning("%s unmounting timed out. Stopping.", u->meta.id);
                 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, false);
                 break;
 
         case MOUNT_MOUNTING_SIGTERM:
-                log_warning("%s mounting timed out. Killing.", unit_id(u));
+                log_warning("%s mounting timed out. Killing.", u->meta.id);
                 mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, false);
                 break;
 
         case MOUNT_REMOUNTING_SIGTERM:
-                log_warning("%s remounting timed out. Killing.", unit_id(u));
+                log_warning("%s remounting timed out. Killing.", u->meta.id);
                 mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, false);
                 break;
 
         case MOUNT_UNMOUNTING_SIGTERM:
-                log_warning("%s unmounting timed out. Killing.", unit_id(u));
+                log_warning("%s unmounting timed out. Killing.", u->meta.id);
                 mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, false);
                 break;
 
         case MOUNT_MOUNTING_SIGKILL:
         case MOUNT_REMOUNTING_SIGKILL:
         case MOUNT_UNMOUNTING_SIGKILL:
-                log_warning("%s mount process still around after SIGKILL. Ignoring.", unit_id(u));
+                log_warning("%s mount process still around after SIGKILL. Ignoring.", u->meta.id);
 
                 if (m->from_proc_self_mountinfo)
                         mount_enter_mounted(m, false);
@@ -879,7 +881,7 @@ static int mount_add_one(
         if (streq(where, "/"))
                 e = strdup("-.mount");
         else
-                e = unit_name_escape_path(where+1, ".mount");
+                e = unit_name_build_escape(where+1, NULL, ".mount");
 
         if (!e)
                 return -ENOMEM;
@@ -1245,7 +1247,7 @@ int mount_path_is_mounted(Manager *m, const char* path) {
                 char *e, *slash;
                 Unit *u;
 
-                if (!(e = unit_name_escape_path(t+1, ".mount"))) {
+                if (!(e = unit_name_build_escape(t+1, NULL, ".mount"))) {
                         r = -ENOMEM;
                         goto finish;
                 }
@@ -1281,6 +1283,7 @@ const UnitVTable mount_vtable = {
         .suffix = ".mount",
 
         .no_alias = true,
+        .no_instances = true,
 
         .init = mount_init,
         .load = mount_load,
index 74e8019bd194eddd804bd7aa143bf416c7e5bfec..9ab8ec1a430833cfa2232dc5d816244bbc815101 100644 (file)
--- a/service.c
+++ b/service.c
@@ -30,6 +30,7 @@
 #include "load-dropin.h"
 #include "log.h"
 #include "strv.h"
+#include "unit-name.h"
 
 #define COMMENTS "#;\n"
 #define NEWLINES "\n\r"
@@ -282,7 +283,7 @@ static int priority_from_rcd(Service *s, const char *init_script) {
 
                                 s->sysv_start_priority = a*10 + b;
 
-                                log_debug("Determined priority %i from link farm for %s", s->sysv_start_priority, unit_id(UNIT(s)));
+                                log_debug("Determined priority %i from link farm for %s", s->sysv_start_priority, UNIT(s)->meta.id);
 
                                 closedir(d);
                                 return 0;
@@ -485,8 +486,8 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         if (unit_name_to_type(m) == UNIT_SERVICE)
                                                 r = unit_add_name(u, m);
                                         else {
-                                                if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m)) >= 0)
-                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m);
+                                                if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m, NULL)) >= 0)
+                                                        r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL);
                                         }
 
                                         free(m);
@@ -519,7 +520,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
                                         if (r == 0)
                                                 continue;
 
-                                        r = unit_add_dependency_by_name(u, UNIT_AFTER, m);
+                                        r = unit_add_dependency_by_name(u, UNIT_AFTER, m, NULL);
                                         free(m);
 
                                         if (r < 0)
@@ -596,13 +597,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
          * needed as soon as at least one non-LSB script is used. */
 
         if (s->sysv_start_priority < 0) {
-                log_debug("%s has no chkconfig header, trying to determine SysV priority from link farm.", unit_id(u));
+                log_debug("%s has no chkconfig header, trying to determine SysV priority from link farm.", u->meta.id);
 
                 if ((r = priority_from_rcd(s, file_name_from_path(path))) < 0)
                         goto finish;
 
                 if (s->sysv_start_priority < 0)
-                        log_warning("%s has neither a chkconfig header nor a directory link, cannot order unit!", unit_id(u));
+                        log_warning("%s has neither a chkconfig header nor a directory link, cannot order unit!", u->meta.id);
         }
 
         if ((r = sysv_exec_commands(s)) < 0)
@@ -615,8 +616,8 @@ static int service_load_sysv_path(Service *s, const char *path) {
                  * needed for early boot) and don't create any links
                  * to it. */
 
-                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET)) < 0 ||
-                    (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET)) < 0)
+                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL)) < 0 ||
+                    (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL)) < 0)
                         goto finish;
         }
 
@@ -680,13 +681,13 @@ static int service_load_sysv(Service *s) {
         if (strv_isempty(UNIT(s)->meta.manager->sysvinit_path))
                 return 0;
 
-        if ((t = unit_id(UNIT(s))))
+        if ((t = UNIT(s)->meta.id))
                 if ((r = service_load_sysv_name(s, t)) < 0)
                         return r;
 
         if (UNIT(s)->meta.load_state == UNIT_STUB)
                 SET_FOREACH(t, UNIT(s)->meta.names, i) {
-                        if (t == unit_id(UNIT(s)))
+                        if (t == UNIT(s)->meta.id)
                                 continue;
 
                         if ((r == service_load_sysv_name(s, t)) < 0)
@@ -737,7 +738,7 @@ static int service_verify(Service *s) {
                 return 0;
 
         if (!s->exec_command[SERVICE_EXEC_START]) {
-                log_error("%s lacks ExecStart setting. Refusing.", unit_id(UNIT(s)));
+                log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->meta.id);
                 return -EINVAL;
         }
 
@@ -1020,7 +1021,7 @@ static void service_set_state(Service *s, ServiceState state) {
                 service_notify_sockets_dead(s);
 
         if (old_state != state)
-                log_debug("%s changed %s → %s", unit_id(UNIT(s)), service_state_to_string(old_state), service_state_to_string(state));
+                log_debug("%s changed %s → %s", UNIT(s)->meta.id, service_state_to_string(old_state), service_state_to_string(state));
 
         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
 }
@@ -1099,6 +1100,7 @@ static int service_spawn(
         int r;
         int *fds = NULL;
         unsigned n_fds = 0;
+        char **argv;
 
         assert(s);
         assert(c);
@@ -1114,14 +1116,23 @@ static int service_spawn(
         } else
                 unit_unwatch_timer(UNIT(s), &s->timer_watch);
 
-        if ((r = exec_spawn(c,
-                            &s->exec_context,
-                            fds, n_fds,
-                            apply_permissions,
-                            apply_chroot,
-                            UNIT(s)->meta.manager->confirm_spawn,
-                            UNIT(s)->meta.cgroup_bondings,
-                            &pid)) < 0)
+        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = exec_spawn(c,
+                       argv,
+                       &s->exec_context,
+                       fds, n_fds,
+                       apply_permissions,
+                       apply_chroot,
+                       UNIT(s)->meta.manager->confirm_spawn,
+                       UNIT(s)->meta.cgroup_bondings,
+                       &pid);
+
+        strv_free(argv);
+        if (r < 0)
                 goto fail;
 
         if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
@@ -1198,7 +1209,7 @@ static void service_enter_dead(Service *s, bool success, bool allow_restart) {
         return;
 
 fail:
-        log_warning("%s failed to run install restart timer: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run install restart timer: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_dead(s, false, false);
 }
 
@@ -1231,7 +1242,7 @@ static void service_enter_stop_post(Service *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run stop-post executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run stop-post executable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
 }
 
@@ -1291,7 +1302,7 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to kill processes: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to kill processes: %s", UNIT(s)->meta.id, strerror(-r));
 
         if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
                 service_enter_stop_post(s, false);
@@ -1325,7 +1336,7 @@ static void service_enter_stop(Service *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run stop executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run stop executable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
 }
 
@@ -1367,7 +1378,7 @@ static void service_enter_start_post(Service *s) {
         return;
 
 fail:
-        log_warning("%s failed to run start-post executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run start-post executable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_stop(s, false);
 }
 
@@ -1429,7 +1440,7 @@ static void service_enter_start(Service *s) {
         return;
 
 fail:
-        log_warning("%s failed to run start exectuable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run start exectuable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
 }
 
@@ -1457,7 +1468,7 @@ static void service_enter_start_pre(Service *s) {
         return;
 
 fail:
-        log_warning("%s failed to run start-pre executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run start-pre executable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_dead(s, false, true);
 }
 
@@ -1470,12 +1481,12 @@ static void service_enter_restart(Service *s) {
         if ((r = manager_add_job(UNIT(s)->meta.manager, JOB_START, UNIT(s), JOB_FAIL, false, NULL)) < 0)
                 goto fail;
 
-        log_debug("%s scheduled restart job.", unit_id(UNIT(s)));
+        log_debug("%s scheduled restart job.", UNIT(s)->meta.id);
         return;
 
 fail:
 
-        log_warning("%s failed to schedule restart job: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to schedule restart job: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_dead(s, false, false);
 }
 
@@ -1503,7 +1514,7 @@ static void service_enter_reload(Service *s) {
         return;
 
 fail:
-        log_warning("%s failed to run reload executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run reload executable: %s", UNIT(s)->meta.id, strerror(-r));
         service_enter_stop(s, false);
 }
 
@@ -1533,7 +1544,7 @@ static void service_run_next(Service *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run spawn next executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run spawn next executable: %s", UNIT(s)->meta.id, strerror(-r));
 
         if (s->state == SERVICE_START_PRE)
                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
@@ -1570,7 +1581,7 @@ static int service_start(Unit *u) {
 
         /* Make sure we don't enter a busy loop of some kind. */
         if (!ratelimit_test(&s->ratelimit)) {
-                log_warning("%s start request repeated too quickly, refusing to start.", unit_id(u));
+                log_warning("%s start request repeated too quickly, refusing to start.", u->meta.id);
                 return -EAGAIN;
         }
 
@@ -1664,7 +1675,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                         s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
                 }
 
-                log_debug("%s: main process exited, code=%s, status=%i", unit_id(u), sigchld_code_to_string(code), status);
+                log_debug("%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
 
                 /* The service exited, so the service is officially
                  * gone. */
@@ -1711,7 +1722,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                 exec_status_fill(&s->control_command->exec_status, pid, code, status);
                 s->control_pid = 0;
 
-                log_debug("%s: control process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status);
+                log_debug("%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
 
                 /* If we are shutting things down anyway we
                  * don't care about failing commands. */
@@ -1721,14 +1732,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                         /* There is another command to *
                          * execute, so let's do that. */
 
-                        log_debug("%s running next command for state %s", unit_id(u), service_state_to_string(s->state));
+                        log_debug("%s running next command for state %s", u->meta.id, service_state_to_string(s->state));
                         service_run_next(s, success);
 
                 } else {
                         /* No further commands for this step, so let's
                          * figure out what to do next */
 
-                        log_debug("%s got final SIGCHLD for state %s", unit_id(u), service_state_to_string(s->state));
+                        log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state));
 
                         switch (s->state) {
 
@@ -1769,7 +1780,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                          * executed. */
 
                                         if ((r = service_load_pid_file(s)) < 0)
-                                                log_warning("%s: failed to load PID file %s: %s", unit_id(UNIT(s)), s->pid_file, strerror(-r));
+                                                log_warning("%s: failed to load PID file %s: %s", UNIT(s)->meta.id, s->pid_file, strerror(-r));
                                 }
 
                                 /* Fall through */
@@ -1822,23 +1833,23 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
 
         case SERVICE_START_PRE:
         case SERVICE_START:
-                log_warning("%s operation timed out. Terminating.", unit_id(u));
+                log_warning("%s operation timed out. Terminating.", u->meta.id);
                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
                 break;
 
         case SERVICE_START_POST:
         case SERVICE_RELOAD:
-                log_warning("%s operation timed out. Stopping.", unit_id(u));
+                log_warning("%s operation timed out. Stopping.", u->meta.id);
                 service_enter_stop(s, false);
                 break;
 
         case SERVICE_STOP:
-                log_warning("%s stopping timed out. Terminating.", unit_id(u));
+                log_warning("%s stopping timed out. Terminating.", u->meta.id);
                 service_enter_signal(s, SERVICE_STOP_SIGTERM, false);
                 break;
 
         case SERVICE_STOP_SIGTERM:
-                log_warning("%s stopping timed out. Killing.", unit_id(u));
+                log_warning("%s stopping timed out. Killing.", u->meta.id);
                 service_enter_signal(s, SERVICE_STOP_SIGKILL, false);
                 break;
 
@@ -1847,27 +1858,27 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
                  * Must be something we cannot kill, so let's just be
                  * weirded out and continue */
 
-                log_warning("%s still around after SIGKILL. Ignoring.", unit_id(u));
+                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
                 service_enter_stop_post(s, false);
                 break;
 
         case SERVICE_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", unit_id(u));
+                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
                 break;
 
         case SERVICE_FINAL_SIGTERM:
-                log_warning("%s stopping timed out (2). Killing.", unit_id(u));
+                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
                 service_enter_signal(s, SERVICE_FINAL_SIGKILL, false);
                 break;
 
         case SERVICE_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", unit_id(u));
+                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
                 service_enter_dead(s, false, true);
                 break;
 
         case SERVICE_AUTO_RESTART:
-                log_debug("%s holdoff time over, scheduling restart.", unit_id(u));
+                log_debug("%s holdoff time over, scheduling restart.", u->meta.id);
                 service_enter_restart(s);
                 break;
 
@@ -1881,7 +1892,7 @@ static void service_cgroup_notify_event(Unit *u) {
 
         assert(u);
 
-        log_debug("%s: cgroup is empty", unit_id(u));
+        log_debug("%s: cgroup is empty", u->meta.id);
 
         switch (s->state) {
 
@@ -1964,10 +1975,10 @@ static int service_enumerate(Manager *m) {
                                         goto finish;
                                 }
 
-                                if ((r = manager_load_unit(m, name, &service)) < 0)
+                                if ((r = manager_load_unit(m, name, NULL, &service)) < 0)
                                         goto finish;
 
-                                if ((r = manager_load_unit(m, rcnd_table[i+1], &runlevel)) < 0)
+                                if ((r = manager_load_unit(m, rcnd_table[i+1], NULL, &runlevel)) < 0)
                                         goto finish;
 
                                 if (de->d_name[0] == 'S') {
index 4fdd88027a4b9628291743c75fdf11896fabf3a4..8e893d465748f19186a191ab30d06cdccba6029f 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -32,6 +32,7 @@
 #include "log.h"
 #include "load-dropin.h"
 #include "load-fragment.h"
+#include "strv.h"
 
 static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
         [SOCKET_DEAD] = UNIT_INACTIVE,
@@ -384,7 +385,7 @@ static void socket_set_state(Socket *s, SocketState state) {
                 socket_unwatch_fds(s);
 
         if (state != old_state)
-                log_debug("%s changed %s → %s", unit_id(UNIT(s)), state_string_table[old_state], state_string_table[state]);
+                log_debug("%s changed %s → %s", s->meta.id, state_string_table[old_state], state_string_table[state]);
 
         unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state]);
 }
@@ -392,6 +393,7 @@ static void socket_set_state(Socket *s, SocketState state) {
 static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
         pid_t pid;
         int r;
+        char **argv;
 
         assert(s);
         assert(c);
@@ -400,14 +402,23 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
         if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
                 goto fail;
 
-        if ((r = exec_spawn(c,
-                            &s->exec_context,
-                            NULL, 0,
-                            true,
-                            true,
-                            UNIT(s)->meta.manager->confirm_spawn,
-                            UNIT(s)->meta.cgroup_bondings,
-                            &pid)) < 0)
+        if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
+                r = -ENOMEM;
+                goto fail;
+        }
+
+        r = exec_spawn(c,
+                       argv,
+                       &s->exec_context,
+                       NULL, 0,
+                       true,
+                       true,
+                       UNIT(s)->meta.manager->confirm_spawn,
+                       UNIT(s)->meta.cgroup_bondings,
+                       &pid);
+
+        strv_free(argv);
+        if (r < 0)
                 goto fail;
 
         if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
@@ -455,7 +466,7 @@ static void socket_enter_stop_post(Socket *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run stop-post executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run stop-post executable: %s", s->meta.id, strerror(-r));
         socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
 }
 
@@ -500,7 +511,7 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to kill processes: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to kill processes: %s", s->meta.id, strerror(-r));
 
         if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
                 socket_enter_stop_post(s, false);
@@ -528,7 +539,7 @@ static void socket_enter_stop_pre(Socket *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run stop-pre executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run stop-pre executable: %s", s->meta.id, strerror(-r));
         socket_enter_stop_post(s, false);
 }
 
@@ -537,7 +548,7 @@ static void socket_enter_listening(Socket *s) {
         assert(s);
 
         if ((r = socket_watch_fds(s)) < 0) {
-                log_warning("%s failed to watch sockets: %s", unit_id(UNIT(s)), strerror(-r));
+                log_warning("%s failed to watch sockets: %s", s->meta.id, strerror(-r));
                 goto fail;
         }
 
@@ -553,7 +564,7 @@ static void socket_enter_start_post(Socket *s) {
         assert(s);
 
         if ((r = socket_open_fds(s)) < 0) {
-                log_warning("%s failed to listen on sockets: %s", unit_id(UNIT(s)), strerror(-r));
+                log_warning("%s failed to listen on sockets: %s", s->meta.id, strerror(-r));
                 goto fail;
         }
 
@@ -561,7 +572,7 @@ static void socket_enter_start_post(Socket *s) {
 
         if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) {
                 if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0) {
-                        log_warning("%s failed to run start-post executable: %s", unit_id(UNIT(s)), strerror(-r));
+                        log_warning("%s failed to run start-post executable: %s", s->meta.id, strerror(-r));
                         goto fail;
                 }
 
@@ -592,7 +603,7 @@ static void socket_enter_start_pre(Socket *s) {
         return;
 
 fail:
-        log_warning("%s failed to run start-pre exectuable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run start-pre exectuable: %s", s->meta.id, strerror(-r));
         socket_enter_dead(s, false);
 }
 
@@ -608,7 +619,7 @@ static void socket_enter_running(Socket *s) {
         return;
 
 fail:
-        log_warning("%s failed to queue socket startup job: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to queue socket startup job: %s", s->meta.id, strerror(-r));
         socket_enter_stop_pre(s, false);
 }
 
@@ -632,7 +643,7 @@ static void socket_run_next(Socket *s, bool success) {
         return;
 
 fail:
-        log_warning("%s failed to run spawn next executable: %s", unit_id(UNIT(s)), strerror(-r));
+        log_warning("%s failed to run spawn next executable: %s", s->meta.id, strerror(-r));
 
         if (s->state == SOCKET_START_POST)
                 socket_enter_stop_pre(s, false);
@@ -722,7 +733,7 @@ static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
 
         assert(s);
 
-        log_debug("Incoming traffic on %s", unit_id(u));
+        log_debug("Incoming traffic on %s", u->meta.id);
 
         if (events != EPOLLIN)
                 socket_enter_stop_pre(s, false);
@@ -746,16 +757,16 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         exec_status_fill(&s->control_command->exec_status, pid, code, status);
         s->control_pid = 0;
 
-        log_debug("%s control process exited, code=%s status=%i", unit_id(u), sigchld_code_to_string(code), status);
+        log_debug("%s control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
 
         if (s->control_command->command_next && success) {
-                log_debug("%s running next command for state %s", unit_id(u), state_string_table[s->state]);
+                log_debug("%s running next command for state %s", u->meta.id, state_string_table[s->state]);
                 socket_run_next(s, success);
         } else {
                 /* No further commands for this step, so let's figure
                  * out what to do next */
 
-                log_debug("%s got final SIGCHLD for state %s", unit_id(u), state_string_table[s->state]);
+                log_debug("%s got final SIGCHLD for state %s", u->meta.id, state_string_table[s->state]);
 
                 switch (s->state) {
 
@@ -801,41 +812,41 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
         switch (s->state) {
 
         case SOCKET_START_PRE:
-                log_warning("%s starting timed out. Terminating.", unit_id(u));
+                log_warning("%s starting timed out. Terminating.", u->meta.id);
                 socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
 
         case SOCKET_START_POST:
-                log_warning("%s starting timed out. Stopping.", unit_id(u));
+                log_warning("%s starting timed out. Stopping.", u->meta.id);
                 socket_enter_stop_pre(s, false);
                 break;
 
         case SOCKET_STOP_PRE:
-                log_warning("%s stopping timed out. Terminating.", unit_id(u));
+                log_warning("%s stopping timed out. Terminating.", u->meta.id);
                 socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, false);
                 break;
 
         case SOCKET_STOP_PRE_SIGTERM:
-                log_warning("%s stopping timed out. Killing.", unit_id(u));
+                log_warning("%s stopping timed out. Killing.", u->meta.id);
                 socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, false);
                 break;
 
         case SOCKET_STOP_PRE_SIGKILL:
-                log_warning("%s still around after SIGKILL. Ignoring.", unit_id(u));
+                log_warning("%s still around after SIGKILL. Ignoring.", u->meta.id);
                 socket_enter_stop_post(s, false);
                 break;
 
         case SOCKET_STOP_POST:
-                log_warning("%s stopping timed out (2). Terminating.", unit_id(u));
+                log_warning("%s stopping timed out (2). Terminating.", u->meta.id);
                 socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
                 break;
 
         case SOCKET_FINAL_SIGTERM:
-                log_warning("%s stopping timed out (2). Killing.", unit_id(u));
+                log_warning("%s stopping timed out (2). Killing.", u->meta.id);
                 socket_enter_signal(s, SOCKET_FINAL_SIGKILL, false);
                 break;
 
         case SOCKET_FINAL_SIGKILL:
-                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", unit_id(u));
+                log_warning("%s still around after SIGKILL (2). Entering maintainance mode.", u->meta.id);
                 socket_enter_dead(s, false);
                 break;
 
@@ -882,7 +893,7 @@ void socket_notify_service_dead(Socket *s) {
         /* The service is dead. Dang. */
 
         if (s->state == SOCKET_RUNNING) {
-                log_debug("%s got notified about service death.", unit_id(UNIT(s)));
+                log_debug("%s got notified about service death.", s->meta.id);
                 socket_enter_listening(s);
         }
 }
diff --git a/specifier.c b/specifier.c
new file mode 100644 (file)
index 0000000..a25f33a
--- /dev/null
@@ -0,0 +1,110 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <string.h>
+
+#include "macro.h"
+#include "util.h"
+#include "specifier.h"
+
+/*
+ * Generic infrastructure for replacing %x style specifiers in
+ * strings. Will call a callback for each replacement.
+ *
+ */
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata) {
+        char *r, *t;
+        const char *f;
+        bool percent = false;
+        size_t l;
+
+        assert(text);
+        assert(table);
+
+        l = strlen(text);
+        if (!(r = new(char, l+1)))
+                return NULL;
+
+        t = r;
+
+        for (f = text; *f; f++, l--) {
+
+                if (percent) {
+                        if (*f == '%')
+                                *(t++) = '%';
+                        else {
+                                const Specifier *i;
+
+                                for (i = table; i->specifier; i++)
+                                        if (i->specifier == *f)
+                                                break;
+
+                                if (i->lookup) {
+                                        char *n, *w;
+                                        size_t k, j;
+
+                                        if (!(w = i->lookup(i->specifier, i->data, userdata))) {
+                                                free(r);
+                                                return NULL;
+                                        }
+
+                                        j = t - r;
+                                        k = strlen(w);
+
+                                        if (!(n = new(char, j + k + (l - (f - text)) + 1))) {
+                                                free(r);
+                                                free(w);
+                                                return NULL;
+                                        }
+
+                                        memcpy(n, r, j);
+                                        memcpy(n + j, w, k);
+
+                                        free(r);
+                                        free(w);
+
+                                        r = n;
+                                        t = n + j + k;
+                                } else {
+                                        *(t++) = '%';
+                                        *(t++) = *f;
+                                }
+                        }
+
+                        percent = false;
+                } else if (*f == '%')
+                        percent = true;
+                else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+        return r;
+}
+
+/* Generic handler for simple string replacements */
+
+char* specifier_string(char specifier, void *data, void *userdata) {
+        assert(data);
+
+        return strdup(strempty(data));
+}
diff --git a/specifier.h b/specifier.h
new file mode 100644 (file)
index 0000000..4b3b94c
--- /dev/null
@@ -0,0 +1,37 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foospecifierhfoo
+#define foospecifierhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+typedef char* (*SpecifierCallback)(char specifier, void *data, void *userdata);
+
+typedef struct Specifier {
+        const char specifier;
+        const SpecifierCallback lookup;
+        void *data;
+} Specifier;
+
+char *specifier_printf(const char *text, const Specifier table[], void *userdata);
+
+char* specifier_string(char specifier, void *data, void *userdata);
+
+#endif
index 5b897c0bfbc4aef2425473e006448467bd153024..e6f26f1412ad19ad63117a8603140d1a72b58852 100644 (file)
--- a/target.c
+++ b/target.c
@@ -65,7 +65,7 @@ static void target_set_state(Target *t, TargetState state) {
         t->state = state;
 
         if (state != old_state)
-                log_debug("%s changed %s → %s", unit_id(UNIT(t)), state_string_table[old_state], state_string_table[state]);
+                log_debug("%s changed %s → %s", UNIT(t)->meta.id, state_string_table[old_state], state_string_table[state]);
 
         unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state]);
 }
index 1a2f8930d83687e0b91c0f07e39c811c3676834b..27e16f34848d54c476ef27d47448d41742be73e4 100644 (file)
@@ -36,9 +36,9 @@ int main(int argc, char *argv[]) {
         assert_se(manager_new(MANAGER_INIT, false, &m) >= 0);
 
         printf("Load1:\n");
-        assert_se(manager_load_unit(m, "a.service", &a) == 0);
-        assert_se(manager_load_unit(m, "b.service", &b) == 0);
-        assert_se(manager_load_unit(m, "c.service", &c) == 0);
+        assert_se(manager_load_unit(m, "a.service", NULL, &a) == 0);
+        assert_se(manager_load_unit(m, "b.service", NULL, &b) == 0);
+        assert_se(manager_load_unit(m, "c.service", NULL, &c) == 0);
         manager_dump_units(m, stdout, "\t");
 
         printf("Test1: (Trivial)\n");
@@ -47,8 +47,8 @@ int main(int argc, char *argv[]) {
 
         printf("Load2:\n");
         manager_clear_jobs(m);
-        assert_se(manager_load_unit(m, "d.service", &d) == 0);
-        assert_se(manager_load_unit(m, "e.service", &e) == 0);
+        assert_se(manager_load_unit(m, "d.service", NULL, &d) == 0);
+        assert_se(manager_load_unit(m, "e.service", NULL, &e) == 0);
         manager_dump_units(m, stdout, "\t");
 
         printf("Test2: (Cyclic Order, Unfixable)\n");
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load3:\n");
-        assert_se(manager_load_unit(m, "g.service", &g) == 0);
+        assert_se(manager_load_unit(m, "g.service", NULL, &g) == 0);
         manager_dump_units(m, stdout, "\t");
 
         printf("Test5: (Colliding transaction, fail)\n");
@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load4:\n");
-        assert_se(manager_load_unit(m, "h.service", &h) == 0);
+        assert_se(manager_load_unit(m, "h.service", NULL, &h) == 0);
         manager_dump_units(m, stdout, "\t");
 
         printf("Test10: (Unmeargable job type of auxiliary job, fail)\n");
diff --git a/unit-name.c b/unit-name.c
new file mode 100644 (file)
index 0000000..219997b
--- /dev/null
@@ -0,0 +1,373 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <string.h>
+
+#include "unit.h"
+#include "unit-name.h"
+
+#define VALID_CHARS                             \
+        "0123456789"                            \
+        "abcdefghijklmnopqrstuvwxyz"            \
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
+        "-_.\\"
+
+UnitType unit_name_to_type(const char *n) {
+        UnitType t;
+
+        assert(n);
+
+        for (t = 0; t < _UNIT_TYPE_MAX; t++)
+                if (endswith(n, unit_vtable[t]->suffix))
+                        return t;
+
+        return _UNIT_TYPE_INVALID;
+}
+
+bool unit_name_is_valid(const char *n) {
+        UnitType t;
+        const char *e, *i, *at;
+
+        /* Valid formats:
+         *
+         *         string@instance.suffix
+         *         string.suffix
+         */
+
+        assert(n);
+
+        if (strlen(n) >= UNIT_NAME_MAX)
+                return false;
+
+        t = unit_name_to_type(n);
+        if (t < 0 || t >= _UNIT_TYPE_MAX)
+                return false;
+
+        assert_se(e = strrchr(n, '.'));
+
+        if (e == n)
+                return false;
+
+        for (i = n, at = NULL; i < e; i++) {
+
+                if (*i == '@' && !at)
+                        at = i;
+
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+        }
+
+        if (at) {
+                if (at == n)
+                        return false;
+
+                if (at[1] == '.')
+                        return false;
+        }
+
+        return true;
+}
+
+bool unit_instance_is_valid(const char *i) {
+        assert(i);
+
+        /* The max length depends on the length of the string, so we
+         * don't really check this here. */
+
+        if (i[0] == 0)
+                return false;
+
+        /* We allow additional @ in the instance string, we do not
+         * allow them in the prefix! */
+
+        for (; *i; i++)
+                if (!strchr("@" VALID_CHARS, *i))
+                        return false;
+
+        return true;
+}
+
+bool unit_prefix_is_valid(const char *p) {
+
+        /* We don't allow additional @ in the instance string */
+
+        if (p[0] == 0)
+                return false;
+
+        for (; *p; p++)
+                if (!strchr(VALID_CHARS, *p))
+                        return false;
+
+        return true;
+}
+
+int unit_name_to_instance(const char *n, char **instance) {
+        const char *p, *d;
+        char *i;
+
+        assert(n);
+        assert(instance);
+
+        /* Everything past the first @ and before the last . is the instance */
+        if (!(p = strchr(n, '@'))) {
+                *instance = NULL;
+                return 0;
+        }
+
+        assert_se(d = strrchr(n, '.'));
+        assert(p < d);
+
+        if (!(i = strndup(p+1, d-p-1)))
+                return -ENOMEM;
+
+        *instance = i;
+        return 0;
+}
+
+char *unit_name_to_prefix_and_instance(const char *n) {
+        const char *d;
+
+        assert(n);
+
+        assert_se(d = strrchr(n, '.'));
+
+        return strndup(n, d - n);
+}
+
+char *unit_name_to_prefix(const char *n) {
+        const char *p;
+
+        if ((p = strchr(n, '@')))
+                return strndup(n, p - n);
+
+        return unit_name_to_prefix_and_instance(n);
+}
+
+char *unit_name_change_suffix(const char *n, const char *suffix) {
+        char *e, *r;
+        size_t a, b;
+
+        assert(n);
+        assert(unit_name_is_valid(n));
+        assert(suffix);
+
+        assert_se(e = strrchr(n, '.'));
+        a = e - n;
+        b = strlen(suffix);
+
+        if (!(r = new(char, a + b + 1)))
+                return NULL;
+
+        memcpy(r, n, a);
+        memcpy(r+a, suffix, b+1);
+
+        return r;
+}
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix) {
+        char *r;
+
+        assert(prefix);
+        assert(unit_prefix_is_valid(prefix));
+        assert(!instance || unit_instance_is_valid(instance));
+        assert(suffix);
+        assert(unit_name_to_type(suffix) >= 0);
+
+        if (!instance)
+                return strappend(prefix, suffix);
+
+        if (asprintf(&r, "%s@%s%s", prefix, instance, suffix) < 0)
+                return NULL;
+
+        return r;
+}
+
+static char* do_escape(const char *f, char *t) {
+        assert(f);
+        assert(t);
+
+        for (; *f; f++) {
+                if (*f == '/')
+                        *(t++) = '.';
+                else if (*f == '.' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
+                        *(t++) = '\\';
+                        *(t++) = 'x';
+                        *(t++) = hexchar(*f > 4);
+                        *(t++) = hexchar(*f);
+                } else
+                        *(t++) = *f;
+        }
+
+        return t;
+}
+
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix) {
+        char *r, *t;
+        size_t a, b, c;
+
+        assert(prefix);
+        assert(suffix);
+        assert(unit_name_to_type(suffix) >= 0);
+
+        /* Takes a arbitrary string for prefix and instance plus a
+         * suffix and makes a nice string suitable as unit name of it,
+         * escaping all weird chars on the way.
+         *
+         * / becomes ., and all chars not alloweed in a unit name get
+         * escaped as \xFF, including \ and ., of course. This
+         * escaping is hence reversible.
+         *
+         * This is primarily useful to make nice unit names from
+         * strings, but is actually useful for any kind of string.
+         */
+
+        a = strlen(prefix);
+        c = strlen(suffix);
+
+        if (instance) {
+                b = strlen(instance);
+
+                if (!(r = new(char, a*4 + 1 + b*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+                *(t++) = '@';
+                t = do_escape(instance, t);
+        } else {
+
+                if (!(r = new(char, a*4 + c + 1)))
+                        return NULL;
+
+                t = do_escape(prefix, r);
+        }
+
+        strcpy(t, suffix);
+        return r;
+}
+
+char *unit_name_escape(const char *f) {
+        char *r, *t;
+
+        if (!(r = new(char, strlen(f)*4+1)))
+                return NULL;
+
+        t = do_escape(f, r);
+        *t = 0;
+
+        return r;
+
+}
+
+char *unit_name_unescape(const char *f) {
+        char *r, *t;
+
+        assert(f);
+
+        if (!(r = strdup(f)))
+                return NULL;
+
+        for (t = r; *f; f++) {
+                if (*f == '.')
+                        *(t++) = '/';
+                else if (*f == '\\') {
+                        int a, b;
+
+                        if ((a = unhexchar(f[1])) < 0 ||
+                            (b = unhexchar(f[2])) < 0) {
+                                /* Invalid escape code, let's take it literal then */
+                                *(t++) = '\\';
+                        } else {
+                                *(t++) = (char) ((a << 4) | b);
+                                f += 2;
+                        }
+                } else
+                        *(t++) = *f;
+        }
+
+        *t = 0;
+
+        return r;
+}
+
+bool unit_name_is_template(const char *n) {
+        const char *p;
+
+        assert(n);
+
+        if (!(p = strchr(n, '@')))
+                return false;
+
+        return p[1] == '.';
+}
+
+char *unit_name_replace_instance(const char *f, const char *i) {
+        const char *p, *e;
+        char *r, *k;
+        size_t a;
+
+        assert(f);
+
+        p = strchr(f, '@');
+        assert_se(e = strrchr(f, '.'));
+
+        a = p - f;
+
+        if (p) {
+                size_t b;
+
+                b = strlen(i);
+
+                if (!(r = new(char, a + 1 + b + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a + 1);
+                k = mempcpy(k, i, b);
+        } else {
+
+                if (!(r = new(char, a + strlen(e) + 1)))
+                        return NULL;
+
+                k = mempcpy(r, f, a);
+        }
+
+        strcpy(k, e);
+        return r;
+}
+
+char *unit_name_template(const char *f) {
+        const char *p, *e;
+        char *r;
+        size_t a;
+
+        if (!(p = strchr(f, '@')))
+                return strdup(f);
+
+        assert_se(e = strrchr(f, '.'));
+        a = p - f + 1;
+
+        if (!(r = new(char, a + strlen(e) + 1)))
+                return NULL;
+
+        strcpy(mempcpy(r, f, a), e);
+        return r;
+
+}
diff --git a/unit-name.h b/unit-name.h
new file mode 100644 (file)
index 0000000..587741b
--- /dev/null
@@ -0,0 +1,51 @@
+/*-*- Mode: C; c-basic-offset: 8 -*-*/
+
+#ifndef foounitnamehfoo
+#define foounitnamehfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2010 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "unit.h"
+
+UnitType unit_name_to_type(const char *n);
+
+int unit_name_to_instance(const char *n, char **instance);
+char* unit_name_to_prefix(const char *n);
+char* unit_name_to_prefix_and_instance(const char *n);
+
+bool unit_name_is_valid(const char *n);
+bool unit_prefix_is_valid(const char *p);
+bool unit_instance_is_valid(const char *i);
+
+char *unit_name_change_suffix(const char *n, const char *suffix);
+
+char *unit_name_build(const char *prefix, const char *instance, const char *suffix);
+char *unit_name_build_escape(const char *prefix, const char *instance, const char *suffix);
+
+char *unit_name_escape(const char *f);
+char *unit_name_unescape(const char *f);
+
+bool unit_name_is_template(const char *n);
+
+char *unit_name_replace_instance(const char *f, const char *i);
+
+char *unit_name_template(const char *f);
+
+#endif
diff --git a/unit.c b/unit.c
index 3b30c8265f579d6330cd854faf1c01d6b6abfd1d..7f147537e30e418da1c2dc50e4fc1248f2d1af51 100644 (file)
--- a/unit.c
+++ b/unit.c
@@ -35,6 +35,8 @@
 #include "load-fragment.h"
 #include "load-dropin.h"
 #include "log.h"
+#include "unit-name.h"
+#include "specifier.h"
 
 const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = &service_vtable,
@@ -47,71 +49,6 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
         [UNIT_SNAPSHOT] = &snapshot_vtable
 };
 
-UnitType unit_name_to_type(const char *n) {
-        UnitType t;
-
-        assert(n);
-
-        for (t = 0; t < _UNIT_TYPE_MAX; t++)
-                if (endswith(n, unit_vtable[t]->suffix))
-                        return t;
-
-        return _UNIT_TYPE_INVALID;
-}
-
-#define VALID_CHARS                             \
-        "0123456789"                            \
-        "abcdefghijklmnopqrstuvwxyz"            \
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"            \
-        "-_.\\"
-
-bool unit_name_is_valid(const char *n) {
-        UnitType t;
-        const char *e, *i;
-
-        assert(n);
-
-        if (strlen(n) >= UNIT_NAME_MAX)
-                return false;
-
-        t = unit_name_to_type(n);
-        if (t < 0 || t >= _UNIT_TYPE_MAX)
-                return false;
-
-        if (!(e = strrchr(n, '.')))
-                return false;
-
-        if (e == n)
-                return false;
-
-        for (i = n; i < e; i++)
-                if (!strchr(VALID_CHARS, *i))
-                        return false;
-
-        return true;
-}
-
-char *unit_name_change_suffix(const char *n, const char *suffix) {
-        char *e, *r;
-        size_t a, b;
-
-        assert(n);
-        assert(unit_name_is_valid(n));
-        assert(suffix);
-
-        assert_se(e = strrchr(n, '.'));
-        a = e - n;
-        b = strlen(suffix);
-
-        if (!(r = new(char, a + b + 1)))
-                return NULL;
-
-        memcpy(r, n, a);
-        memcpy(r+a, suffix, b+1);
-
-        return r;
-}
-
 Unit *unit_new(Manager *m) {
         Unit *u;
 
@@ -140,74 +77,114 @@ bool unit_has_name(Unit *u, const char *name) {
 
 int unit_add_name(Unit *u, const char *text) {
         UnitType t;
-        char *s;
+        char *s = NULL, *i = NULL;
         int r;
 
         assert(u);
         assert(text);
 
-        if (!unit_name_is_valid(text))
-                return -EINVAL;
+        if (unit_name_is_template(text)) {
+                if (!u->meta.instance)
+                        return -EINVAL;
 
-        if ((t = unit_name_to_type(text)) == _UNIT_TYPE_INVALID)
-                return -EINVAL;
+                s = unit_name_replace_instance(text, u->meta.instance);
+        } else
+                s = strdup(text);
 
-        if (u->meta.type != _UNIT_TYPE_INVALID && t != u->meta.type)
-                return -EINVAL;
+        if (!s)
+                return -ENOMEM;
 
-        if (u->meta.type != _UNIT_TYPE_INVALID &&
-            UNIT_VTABLE(u)->no_alias &&
-            !set_isempty(u->meta.names))
-                return -EEXIST;
+        if (!unit_name_is_valid(s)) {
+                r = -EINVAL;
+                goto fail;
+        }
 
-        if (!(s = strdup(text)))
-                return -ENOMEM;
+        assert_se((t = unit_name_to_type(s)) >= 0);
 
-        if ((r = set_put(u->meta.names, s)) < 0) {
-                free(s);
+        if (u->meta.type != _UNIT_TYPE_INVALID && t != u->meta.type) {
+                r = -EINVAL;
+                goto fail;
+        }
 
-                if (r == -EEXIST)
-                        return 0;
+        if ((r = unit_name_to_instance(s, &i)) < 0)
+                goto fail;
 
-                return r;
+        if (i && unit_vtable[t]->no_instances)
+                goto fail;
+
+        if (u->meta.type != _UNIT_TYPE_INVALID && !streq_ptr(u->meta.instance, i)) {
+                r = -EINVAL;
+                goto fail;
+        }
+
+        if (unit_vtable[t]->no_alias &&
+            !set_isempty(u->meta.names) &&
+            !set_get(u->meta.names, s)) {
+                r = -EEXIST;
+                goto fail;
+        }
+
+        if ((r = set_put(u->meta.names, s)) < 0) {
+                if (r == -EEXIST)
+                        r = 0;
+                goto fail;
         }
 
         if ((r = hashmap_put(u->meta.manager->units, s, u)) < 0) {
                 set_remove(u->meta.names, s);
-                free(s);
-                return r;
+                goto fail;
         }
 
         if (u->meta.type == _UNIT_TYPE_INVALID) {
-                LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
 
                 u->meta.type = t;
+                u->meta.id = s;
+                u->meta.instance = i;
+
+                LIST_PREPEND(Meta, units_per_type, u->meta.manager->units_per_type[t], &u->meta);
 
                 if (UNIT_VTABLE(u)->init)
                         UNIT_VTABLE(u)->init(u);
-        }
-
-        if (!u->meta.id)
-                u->meta.id = s;
+        } else
+                free(i);
 
         unit_add_to_dbus_queue(u);
         return 0;
+
+fail:
+        free(s);
+        free(i);
+
+        return r;
 }
 
 int unit_choose_id(Unit *u, const char *name) {
-        char *s;
+        char *s, *t = NULL;
 
         assert(u);
         assert(name);
 
+        if (unit_name_is_template(name)) {
+
+                if (!u->meta.instance)
+                        return -EINVAL;
+
+                if (!(t = unit_name_replace_instance(name, u->meta.instance)))
+                        return -ENOMEM;
+
+                name = t;
+        }
+
         /* Selects one of the names of this unit as the id */
+        s = set_get(u->meta.names, (char*) name);
+        free(t);
 
-        if (!(s = set_get(u->meta.names, (char*) name)))
+        if (!s)
                 return -ENOENT;
 
         u->meta.id = s;
-
         unit_add_to_dbus_queue(u);
+
         return 0;
 }
 
@@ -322,6 +299,8 @@ void unit_free(Unit *u) {
                 free(t);
         set_free(u->meta.names);
 
+        free(u->meta.instance);
+
         free(u);
 }
 
@@ -409,13 +388,17 @@ int unit_merge(Unit *u, Unit *other) {
         assert(u);
         assert(other);
         assert(u->meta.manager == other->meta.manager);
+        assert(u->meta.type != _UNIT_TYPE_INVALID);
 
         other = unit_follow_merge(other);
 
         if (other == u)
                 return 0;
 
-        if (u->meta.type != u->meta.type)
+        if (u->meta.type != other->meta.type)
+                return -EINVAL;
+
+        if (!streq_ptr(u->meta.instance, other->meta.instance))
                 return -EINVAL;
 
         if (other->meta.load_state != UNIT_STUB &&
@@ -452,14 +435,29 @@ int unit_merge(Unit *u, Unit *other) {
 
 int unit_merge_by_name(Unit *u, const char *name) {
         Unit *other;
+        int r;
+        char *s = NULL;
 
         assert(u);
         assert(name);
 
+        if (unit_name_is_template(name)) {
+                if (!u->meta.instance)
+                        return -EINVAL;
+
+                if (!(s = unit_name_replace_instance(name, u->meta.instance)))
+                        return -ENOMEM;
+
+                name = s;
+        }
+
         if (!(other = manager_get_unit(u->meta.manager, name)))
-                return unit_add_name(u, name);
+                r = unit_add_name(u, name);
+        else
+                r = unit_merge(u, other);
 
-        return unit_merge(u, other);
+        free(s);
+        return r;
 }
 
 Unit* unit_follow_merge(Unit *u) {
@@ -483,32 +481,23 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
         /* If syslog or kernel logging is requested, make sure our own
          * logging daemon is run first. */
 
-        if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET)) < 0)
+        if ((r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_LOGGER_SOCKET, NULL)) < 0)
                 return r;
 
         if (u->meta.manager->running_as != MANAGER_SESSION)
-                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET)) < 0)
+                if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_LOGGER_SOCKET, NULL)) < 0)
                         return r;
 
         return 0;
 }
 
-const char* unit_id(Unit *u) {
-        assert(u);
-
-        if (u->meta.id)
-                return u->meta.id;
-
-        return set_first(u->meta.names);
-}
-
 const char *unit_description(Unit *u) {
         assert(u);
 
         if (u->meta.description)
                 return u->meta.description;
 
-        return unit_id(u);
+        return u->meta.id;
 }
 
 void unit_dump(Unit *u, FILE *f, const char *prefix) {
@@ -521,6 +510,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
         char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
 
         assert(u);
+        assert(u->meta.type >= 0);
 
         if (!prefix)
                 prefix = "";
@@ -530,12 +520,14 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
         fprintf(f,
                 "%s→ Unit %s:\n"
                 "%s\tDescription: %s\n"
+                "%s\tInstance: %s\n"
                 "%s\tUnit Load State: %s\n"
                 "%s\tUnit Active State: %s\n"
                 "%s\tActive Enter Timestamp: %s\n"
                 "%s\tActive Exit Timestamp: %s\n",
-                prefix, unit_id(u),
+                prefix, u->meta.id,
                 prefix, unit_description(u),
+                prefix, strna(u->meta.instance),
                 prefix, unit_load_state_to_string(u->meta.load_state),
                 prefix, unit_active_state_to_string(unit_active_state(u)),
                 prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.active_enter_timestamp)),
@@ -551,7 +543,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 Unit *other;
 
                 SET_FOREACH(other, u->meta.dependencies[d], i)
-                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), unit_id(other));
+                        fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->meta.id);
         }
 
         if (u->meta.load_state == UNIT_LOADED) {
@@ -571,7 +563,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
         } else if (u->meta.load_state == UNIT_MERGED)
                 fprintf(f,
                         "%s\tMerged into: %s\n",
-                        prefix, unit_id(u->meta.merged_into));
+                        prefix, u->meta.merged_into->meta.id);
 
         if (u->meta.job)
                 job_dump(u->meta.job, f, prefix2);
@@ -657,7 +649,7 @@ fail:
         u->meta.load_state = UNIT_FAILED;
         unit_add_to_dbus_queue(u);
 
-        log_error("Failed to load configuration for %s: %s", unit_id(u), strerror(-r));
+        log_error("Failed to load configuration for %s: %s", u->meta.id, strerror(-r));
 
         return r;
 }
@@ -776,7 +768,7 @@ static void unit_check_uneeded(Unit *u) {
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         return;
 
-        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRED_BY], i)
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         return;
 
@@ -784,7 +776,7 @@ static void unit_check_uneeded(Unit *u) {
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         return;
 
-        log_debug("Service %s is not needed anymore. Stopping.", unit_id(u));
+        log_debug("Service %s is not needed anymore. Stopping.", u->meta.id);
 
         /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
         manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL);
@@ -801,7 +793,7 @@ static void retroactively_start_dependencies(Unit *u) {
                 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
                         manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL);
 
-        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRES], i)
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
                 if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
                         manager_add_job(u->meta.manager, JOB_START, other, JOB_FAIL, false, NULL);
 
@@ -836,7 +828,7 @@ static void retroactively_stop_dependencies(Unit *u) {
         SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRES], i)
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_uneeded(other);
         SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
@@ -845,7 +837,7 @@ static void retroactively_stop_dependencies(Unit *u) {
         SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_uneeded(other);
-        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUISITE], i)
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                         unit_check_uneeded(other);
 }
@@ -1150,12 +1142,12 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) {
 
         static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
                 [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
-                [UNIT_SOFT_REQUIRES] = UNIT_SOFT_REQUIRED_BY,
+                [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
                 [UNIT_WANTS] = UNIT_WANTED_BY,
                 [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
-                [UNIT_SOFT_REQUISITE] = UNIT_SOFT_REQUIRED_BY,
+                [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
                 [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
-                [UNIT_SOFT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
+                [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
                 [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
                 [UNIT_CONFLICTS] = UNIT_CONFLICTS,
                 [UNIT_BEFORE] = UNIT_AFTER,
@@ -1173,6 +1165,14 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) {
         if (u == other)
                 return 0;
 
+        if (UNIT_VTABLE(u)->no_requires &&
+            (d == UNIT_REQUIRES ||
+             d == UNIT_REQUIRES_OVERRIDABLE ||
+             d == UNIT_REQUISITE ||
+             d == UNIT_REQUISITE_OVERRIDABLE)) {
+                    return -EINVAL;
+        }
+
         if ((r = set_ensure_allocated(&u->meta.dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
                 return r;
 
@@ -1191,30 +1191,79 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other) {
         return 0;
 }
 
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name) {
+static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
+        char *s;
+
+        assert(u);
+        assert(name || path);
+
+        if (!name)
+                name = file_name_from_path(path);
+
+        if (!unit_name_is_template(name)) {
+                *p = NULL;
+                return name;
+        }
+
+        if (u->meta.instance)
+                s = unit_name_replace_instance(name, u->meta.instance);
+        else {
+                char *i;
+
+                if (!(i = unit_name_to_prefix(u->meta.id)))
+                        return NULL;
+
+                s = unit_name_replace_instance(name, i);
+                free(i);
+        }
+
+        if (!s)
+                return NULL;
+
+        *p = s;
+        return s;
+}
+
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path) {
         Unit *other;
         int r;
+        char *s;
 
-        if ((r = manager_load_unit(u->meta.manager, name, &other)) < 0)
-                return r;
+        assert(u);
+        assert(name || path);
 
-        if ((r = unit_add_dependency(u, d, other)) < 0)
-                return r;
+        if (!(name = resolve_template(u, name, path, &s)))
+                return -ENOMEM;
 
-        return 0;
+        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(u, d, other);
+
+finish:
+        free(s);
+        return r;
 }
 
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name) {
+int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path) {
         Unit *other;
         int r;
+        char *s;
 
-        if ((r = manager_load_unit(u->meta.manager, name, &other)) < 0)
-                return r;
+        assert(u);
+        assert(name || path);
 
-        if ((r = unit_add_dependency(other, d, u)) < 0)
-                return r;
+        if (!(name = resolve_template(u, name, path, &s)))
+                return -ENOMEM;
 
-        return 0;
+        if ((r = manager_load_unit(u->meta.manager, name, path, &other)) < 0)
+                goto finish;
+
+        r = unit_add_dependency(other, d, u);
+
+finish:
+        free(s);
+        return r;
 }
 
 int set_unit_path(const char *p) {
@@ -1246,54 +1295,12 @@ int set_unit_path(const char *p) {
         return 0;
 }
 
-char *unit_name_escape_path(const char *path, const char *suffix) {
-        char *r, *t;
-        const char *f;
-        size_t a, b;
-
-        assert(path);
-
-        /* Takes a path and a suffix and prefix and makes a nice
-         * string suitable as unit name of it, escaping all weird
-         * chars on the way.
-         *
-         * / becomes ., and all chars not alloweed in a unit name get
-         * escaped as \xFF, including \ and ., of course. This
-         * escaping is hence reversible.
-         */
-
-        if (!suffix)
-                suffix = "";
-
-        a = strlen(path);
-        b = strlen(suffix);
-
-        if (!(r = new(char, a*4+b+1)))
-                return NULL;
-
-        for (f = path, t = r; *f; f++) {
-                if (*f == '/')
-                        *(t++) = '.';
-                else if (*f == '.' || *f == '\\' || !strchr(VALID_CHARS, *f)) {
-                        *(t++) = '\\';
-                        *(t++) = 'x';
-                        *(t++) = hexchar(*f > 4);
-                        *(t++) = hexchar(*f);
-                } else
-                        *(t++) = *f;
-        }
-
-        memcpy(t, suffix, b+1);
-
-        return r;
-}
-
 char *unit_dbus_path(Unit *u) {
         char *p, *e;
 
         assert(u);
 
-        if (!(e = bus_path_escape(unit_id(u))))
+        if (!(e = bus_path_escape(u->meta.id)))
                 return NULL;
 
         if (asprintf(&p, "/org/freedesktop/systemd1/unit/%s", e) < 0) {
@@ -1335,7 +1342,7 @@ static char *default_cgroup_path(Unit *u) {
 
         assert(u);
 
-        if (asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, unit_id(u)) < 0)
+        if (asprintf(&p, "%s/%s", u->meta.manager->cgroup_hierarchy, u->meta.id) < 0)
                 return NULL;
 
         return p;
@@ -1462,20 +1469,134 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
         assert(type);
         assert(_found);
 
-        if (!(t = unit_name_change_suffix(unit_id(u), type)))
+        if (!(t = unit_name_change_suffix(u->meta.id, type)))
                 return -ENOMEM;
 
         assert(!unit_has_name(u, t));
 
-        r = manager_load_unit(u->meta.manager, t, _found);
+        r = manager_load_unit(u->meta.manager, t, NULL, _found);
         free(t);
 
-        if (r >= 0)
-                assert(*_found != u);
+        assert(r < 0 || *_found != u);
 
         return r;
 }
 
+static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return unit_name_to_prefix_and_instance(u->meta.id);
+}
+
+static char *specifier_prefix(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        return unit_name_to_prefix(u->meta.id);
+}
+
+static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        char *p, *r;
+
+        assert(u);
+
+        if (!(p = unit_name_to_prefix(u->meta.id)))
+                return NULL;
+
+        r = unit_name_unescape(p);
+        free(p);
+
+        return r;
+}
+
+static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
+        Unit *u = userdata;
+        assert(u);
+
+        if (u->meta.instance)
+                return unit_name_unescape(u->meta.instance);
+
+        return strdup("");
+}
+
+char *unit_name_printf(Unit *u, const char* format) {
+
+        /*
+         * This will use the passed string as format string and
+         * replace the following specifiers:
+         *
+         * %n: the full id of the unit                 (foo@bar.waldo)
+         * %N: the id of the unit without the suffix   (foo@bar)
+         * %p: the prefix                              (foo)
+         * %i: the instance                            (bar)
+         */
+
+        const Specifier table[] = {
+                { 'n', specifier_string,              u->meta.id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'i', specifier_string,              u->meta.instance },
+                { 0, NULL, NULL }
+        };
+
+        assert(u);
+        assert(format);
+
+        return specifier_printf(format, table, u);
+}
+
+char *unit_full_printf(Unit *u, const char *format) {
+
+        /* This is similar to unit_name_printf() but also supports
+         * unescaping */
+
+        const Specifier table[] = {
+                { 'n', specifier_string,              u->meta.id },
+                { 'N', specifier_prefix_and_instance, NULL },
+                { 'p', specifier_prefix,              NULL },
+                { 'P', specifier_prefix_unescaped,    NULL },
+                { 'i', specifier_string,              u->meta.instance },
+                { 'I', specifier_instance_unescaped,  NULL },
+                { 0, NULL, NULL }
+        };
+
+        assert(u);
+        assert(format);
+
+        return specifier_printf(format, table, u);
+}
+
+char **unit_full_printf_strv(Unit *u, char **l) {
+        size_t n;
+        char **r, **i, **j;
+
+        /* Applies unit_full_printf to every entry in l */
+
+        assert(u);
+
+        n = strv_length(l);
+        if (!(r = new(char*, n+1)))
+                return NULL;
+
+        for (i = l, j = r; *i; i++, j++)
+                if (!(*j = unit_full_printf(u, *i)))
+                        goto fail;
+
+        *j = NULL;
+        return r;
+
+fail:
+        j--;
+        while (j >= r)
+                free(*j);
+
+        free(r);
+
+        return NULL;
+}
+
 static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
         [UNIT_SERVICE] = "service",
         [UNIT_TIMER] = "timer",
@@ -1509,12 +1630,12 @@ DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
 
 static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
         [UNIT_REQUIRES] = "Requires",
-        [UNIT_SOFT_REQUIRES] = "SoftRequires",
+        [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
         [UNIT_WANTS] = "Wants",
         [UNIT_REQUISITE] = "Requisite",
-        [UNIT_SOFT_REQUISITE] = "SoftRequisite",
+        [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
         [UNIT_REQUIRED_BY] = "RequiredBy",
-        [UNIT_SOFT_REQUIRED_BY] = "SoftRequiredBy",
+        [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
         [UNIT_WANTED_BY] = "WantedBy",
         [UNIT_CONFLICTS] = "Conflicts",
         [UNIT_BEFORE] = "Before",
diff --git a/unit.h b/unit.h
index 052cee01eab93b37473704152a95f8b6150cd360..c0423354d10336e1da0bc526b6008873ddc26731 100644 (file)
--- a/unit.h
+++ b/unit.h
@@ -99,21 +99,21 @@ static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
 enum UnitDependency {
         /* Positive dependencies */
         UNIT_REQUIRES,
-        UNIT_SOFT_REQUIRES,
-        UNIT_WANTS,
+        UNIT_REQUIRES_OVERRIDABLE,
         UNIT_REQUISITE,
-        UNIT_SOFT_REQUISITE,
+        UNIT_REQUISITE_OVERRIDABLE,
+        UNIT_WANTS,
 
         /* Inverse of the above */
-        UNIT_REQUIRED_BY,       /* inverse of 'requires' and 'requisite' is 'required_by' */
-        UNIT_SOFT_REQUIRED_BY,  /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
-        UNIT_WANTED_BY,         /* inverse of 'wants' */
+        UNIT_REQUIRED_BY,             /* inverse of 'requires' and 'requisite' is 'required_by' */
+        UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'soft_requires' and 'soft_requisite' is 'soft_required_by' */
+        UNIT_WANTED_BY,               /* inverse of 'wants' */
 
         /* Negative dependencies */
-        UNIT_CONFLICTS,         /* inverse of 'conflicts' is 'conflicts' */
+        UNIT_CONFLICTS,               /* inverse of 'conflicts' is 'conflicts' */
 
         /* Order */
-        UNIT_BEFORE,            /* inverse of before is after and vice versa */
+        UNIT_BEFORE,                  /* inverse of before is after and vice versa */
         UNIT_AFTER,
 
         _UNIT_DEPENDENCY_MAX,
@@ -132,6 +132,7 @@ struct Meta {
         Unit *merged_into;
 
         char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
+        char *instance;
 
         Set *names;
         Set *dependencies[_UNIT_DEPENDENCY_MAX];
@@ -203,7 +204,10 @@ struct UnitVTable {
         /* If true units of this types can never have "Requires"
          * dependencies, because state changes can only be observed,
          * not triggered */
-        bool refuse_requires:1;
+        bool no_requires:1;
+
+        /* Instances make no sense for this type */
+        bool no_instances:1;
 
         /* This should reset all type-specific variables. This should
          * not allocate memory, and is either called with 0
@@ -284,17 +288,14 @@ DEFINE_CAST(MOUNT, Mount);
 DEFINE_CAST(AUTOMOUNT, Automount);
 DEFINE_CAST(SNAPSHOT, Snapshot);
 
-UnitType unit_name_to_type(const char *n);
-bool unit_name_is_valid(const char *n);
-char *unit_name_change_suffix(const char *n, const char *suffix);
-
 Unit *unit_new(Manager *m);
 void unit_free(Unit *u);
 
 int unit_add_name(Unit *u, const char *name);
+
 int unit_add_dependency(Unit *u, UnitDependency d, Unit *other);
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name);
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name);
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename);
+int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename);
 
 int unit_add_exec_dependencies(Unit *u, ExecContext *c);
 
@@ -319,7 +320,6 @@ int unit_load_fragment_and_dropin(Unit *u);
 int unit_load_fragment_and_dropin_optional(Unit *u);
 int unit_load(Unit *unit);
 
-const char* unit_id(Unit *u);
 const char *unit_description(Unit *u);
 
 bool unit_has_name(Unit *u, const char *name);
@@ -352,12 +352,14 @@ bool unit_job_is_applicable(Unit *u, JobType j);
 
 int set_unit_path(const char *p);
 
-char *unit_name_escape_path(const char *path, const char *suffix);
-
 char *unit_dbus_path(Unit *u);
 
 int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
 
+char *unit_name_printf(Unit *u, const char* text);
+char *unit_full_printf(Unit *u, const char *text);
+char **unit_full_printf_strv(Unit *u, char **l);
+
 const char *unit_type_to_string(UnitType i);
 UnitType unit_type_from_string(const char *s);
 
diff --git a/util.c b/util.c
index 17ee09c1f7d23da9782c3db0b4432f505c7579d0..5f36819fa31f432181989130822d6f047c013da7 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1041,16 +1041,15 @@ char *bus_path_escape(const char *s) {
         return r;
 }
 
-char *bus_path_unescape(const char *s) {
+char *bus_path_unescape(const char *f) {
         char *r, *t;
-        const char *f;
 
-        assert(s);
+        assert(f);
 
-        if (!(r = new(char, strlen(s)+1)))
+        if (!(r = strdup(f)))
                 return NULL;
 
-        for (f = s, t = r; *f; f++) {
+        for (t = r; *f; f++) {
 
                 if (*f == '_') {
                         int a, b;