Commit 9e2f7c11 authored by Lennart Poettering's avatar Lennart Poettering
Browse files

core: add minimal templating system

parent 9fcc065a
......@@ -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) \
......
......@@ -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;
......
......@@ -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))) {
......
......@@ -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;
......
......@@ -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,
......
......@@ -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",
......
......@@ -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);
......
......@@ -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))
......
......@@ -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;
......
......@@ -26,6 +26,45 @@
#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);
}
}
......
......@@ -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) {