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