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) \
Job *j = data;
DBusMessageIter sub;
char *p;
- const char *id;
assert(m);
assert(i);
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;
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)))
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))
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) ||
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;
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);
}
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) ||
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))) {
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;
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 },
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;
void bus_unit_send_removed_signal(Unit *u) {
char *p = NULL;
DBusMessage *m = NULL;
- const char *id;
assert(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;
#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,
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]);
}
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);
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);
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)
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);
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:
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,
}
int exec_spawn(ExecCommand *command,
+ char **argv,
const ExecContext *context,
int fds[], unsigned n_fds,
bool apply_permissions,
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);
goto fail;
/* Now ask the question. */
- if (!(line = exec_command_line(command))) {
+ if (!(line = exec_command_line(argv))) {
r = EXIT_MEMORY;
goto fail;
}
goto fail;
}
- execve(command->path, command->argv, final_env);
+ execve(command->path, argv, final_env);
r = EXIT_EXEC;
fail:
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++) = ' ';
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",
} ExitStatus;
int exec_spawn(ExecCommand *command,
+ char **argv,
const ExecContext *context,
int fds[], unsigned n_fds,
bool apply_permissions,
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);
"%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) {
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;
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))
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;
#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;
SET_FOREACH(t, u->meta.names, i) {
char *path;
- DIR *d;
- struct dirent *de;
char **p;
STRV_FOREACH(p, u->meta.manager->unit_path) {
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);
}
}
#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( \
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;
}
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;
}
#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;
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;
}
{ "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" },
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)
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;
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;
}
#include "cgroup.h"
#include "mount-setup.h"
#include "utmp-wtmp.h"
+#include "unit-name.h"
static int enable_special_signals(Manager *m) {
char fd;
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)
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;
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;
}
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;
* 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;
}
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;
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;
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;
j->generation = 0;
j->marker = NULL;
j->matters_to_anchor = false;
- j->forced = force;
+ j->override = override;
LIST_PREPEND(Job, transaction, f, j);
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;
}
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;
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. */
/* 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;
}
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;
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;
}
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;
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;
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) {
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;
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);
manager_dispatch_load_queue(m);
- *_ret = unit_follow_merge(ret);
+ if (_ret)
+ *_ret = unit_follow_merge(ret);
+
return 0;
}
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);
}
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);
}
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);
#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,
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)
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)
}
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]);
}
goto fail;
if ((r = exec_spawn(c,
+ NULL,
&m->exec_context,
NULL, 0,
true,
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);
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);
}
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);
}
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
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);
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;
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;
}
.suffix = ".mount",
.no_alias = true,
+ .no_instances = true,
.init = mount_init,
.load = mount_load,
#include "load-dropin.h"
#include "log.h"
#include "strv.h"
+#include "unit-name.h"
#define COMMENTS "#;\n"
#define NEWLINES "\n\r"
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;
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);
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)
* 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)
* 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;
}
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)
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;
}
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]);
}
int r;
int *fds = NULL;
unsigned n_fds = 0;
+ char **argv;
assert(s);
assert(c);
} 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)
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
/* 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;
}
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. */
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. */
/* 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) {
* 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 */
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;
* 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;
assert(u);
- log_debug("%s: cgroup is empty", unit_id(u));
+ log_debug("%s: cgroup is empty", u->meta.id);
switch (s->state) {
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') {
#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,
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]);
}
static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
+ char **argv;
assert(s);
assert(c);
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)
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);
}
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);
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);
}
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;
}
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;
}
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;
}
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);
}
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);
}
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);
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);
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) {
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;
/* 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);
}
}
--- /dev/null
+/*-*- 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));
+}
--- /dev/null
+/*-*- 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
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]);
}
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");
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");
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");
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");
--- /dev/null
+/*-*- 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;
+
+}
--- /dev/null
+/*-*- 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
#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,
[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;
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;
}
free(t);
set_free(u->meta.names);
+ free(u->meta.instance);
+
free(u);
}
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 &&
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) {
/* 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) {
char timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX];
assert(u);
+ assert(u->meta.type >= 0);
if (!prefix)
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)),
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) {
} 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);
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;
}
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;
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);
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);
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)
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);
}
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,
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;
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) {
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) {
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;
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",
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",
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,
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];
/* 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
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);
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);
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);
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;