#include "log.h"
#include "strv.h"
#include "unit-name.h"
+#include "dbus-service.h"
#define COMMENTS "#;\n"
#define NEWLINES "\n\r"
#define LINE_MAX 4096
-static const char * const rcnd_table[] = {
- "/rc0.d", SPECIAL_RUNLEVEL0_TARGET,
- "/rc1.d", SPECIAL_RUNLEVEL1_TARGET,
- "/rc2.d", SPECIAL_RUNLEVEL2_TARGET,
- "/rc3.d", SPECIAL_RUNLEVEL3_TARGET,
- "/rc4.d", SPECIAL_RUNLEVEL4_TARGET,
- "/rc5.d", SPECIAL_RUNLEVEL5_TARGET,
- "/rc6.d", SPECIAL_RUNLEVEL6_TARGET,
- "/boot.d", SPECIAL_BASIC_TARGET
+typedef enum RunlevelType {
+ RUNLEVEL_UP,
+ RUNLEVEL_DOWN,
+ RUNLEVEL_BASIC
+} RunlevelType;
+
+static const struct {
+ const char *path;
+ const char *target;
+ const RunlevelType type;
+} rcnd_table[] = {
+ /* Standard SysV runlevels */
+ { "rc0.d", SPECIAL_RUNLEVEL0_TARGET, RUNLEVEL_DOWN },
+ { "rc1.d", SPECIAL_RUNLEVEL1_TARGET, RUNLEVEL_UP },
+ { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
+ { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
+ { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
+ { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
+ { "rc6.d", SPECIAL_RUNLEVEL6_TARGET, RUNLEVEL_DOWN },
+
+ /* SuSE style boot.d */
+ { "boot.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
+
+ /* Debian style rcS.d */
+ { "rcS.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
};
+#define RUNLEVELS_UP "12345"
+/* #define RUNLEVELS_DOWN "06" */
+/* #define RUNLEVELS_BOOT "bBsS" */
+
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
[SERVICE_START_PRE] = UNIT_ACTIVATING,
[SERVICE_AUTO_RESTART] = UNIT_ACTIVATING,
};
+static void service_init(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(u);
+ assert(u->meta.load_state == UNIT_STUB);
+
+ s->timeout_usec = DEFAULT_TIMEOUT_USEC;
+ s->restart_usec = DEFAULT_RESTART_USEC;
+ s->timer_watch.type = WATCH_INVALID;
+ s->sysv_start_priority = -1;
+ s->socket_fd = -1;
+
+ exec_context_init(&s->exec_context);
+
+ RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
+
+ s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+}
+
static void service_unwatch_control_pid(Service *s) {
assert(s);
/* FIXME: Maybe we should compare the name here lexicographically? */
- if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t))) < 0)
+ if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
return r;
}
return 0;
}
-static int priority_from_rcd(Service *s, const char *init_script) {
- char **p;
- unsigned i;
-
- STRV_FOREACH(p, UNIT(s)->meta.manager->sysvrcnd_path)
- for (i = 0; i < ELEMENTSOF(rcnd_table); i += 2) {
- char *path;
- DIR *d;
- struct dirent *de;
-
- if (asprintf(&path, "%s/%s", *p, rcnd_table[i]) < 0)
- return -ENOMEM;
-
- d = opendir(path);
- free(path);
-
- if (!d) {
- if (errno != ENOENT)
- log_warning("opendir() failed on %s: %s", path, strerror(errno));
-
- continue;
- }
-
- while ((de = readdir(d))) {
- int a, b;
-
- if (ignore_file(de->d_name))
- continue;
-
- if (de->d_name[0] != 'S')
- continue;
-
- if (strlen(de->d_name) < 4)
- continue;
-
- if (!streq(de->d_name + 3, init_script))
- continue;
-
- /* Yay, we found it! Now decode the priority */
-
- a = undecchar(de->d_name[1]);
- b = undecchar(de->d_name[2]);
-
- if (a < 0 || b < 0)
- continue;
-
- s->sysv_start_priority = a*10 + b;
-
- log_debug("Determined priority %i from link farm for %s", s->sysv_start_priority, UNIT(s)->meta.id);
-
- closedir(d);
- return 0;
- }
-
- closedir(d);
- }
-
- return 0;
-}
-
static int service_load_sysv_path(Service *s, const char *path) {
FILE *f;
Unit *u;
continue;
}
+ /* A start priority gathered from the
+ * symlink farms is preferred over the
+ * data from the LSB header. */
if (start_priority < 0 || start_priority > 99)
log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
- else
+ else if (s->sysv_start_priority < 0)
s->sysv_start_priority = start_priority;
char_array_0(runlevels);
s->sysv_runlevels = d;
}
-
} else if (startswith(t, "description:")) {
size_t k = strlen(t);
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, NULL)) >= 0)
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL);
+ if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m, NULL, true)) >= 0)
+ r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true);
}
free(m);
if (r == 0)
continue;
- r = unit_add_dependency_by_name(u, UNIT_AFTER, m, NULL);
+ r = unit_add_dependency_by_name(u, UNIT_AFTER, m, NULL, true);
free(m);
if (r < 0)
}
}
- /* If init scripts have no LSB header, then we enforce the
- * ordering via the chkconfig priorities. We try to determine
- * a priority for *all* init scripts here, since they are
- * 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.", 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!", u->meta.id);
- }
-
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
- if (!s->sysv_runlevels || chars_intersect("12345", s->sysv_runlevels)) {
+ if (!s->sysv_runlevels || chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
/* If there a runlevels configured for this service
* but none of the standard ones, then we assume this
* is some special kind of service (which might be
* 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, NULL)) < 0 ||
- (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL)) < 0)
+ if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0 ||
+ (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
goto finish;
- }
+
+ } else
+ /* Don't timeout special services during boot (like fsck) */
+ s->timeout_usec = 0;
/* Special setting for all SysV services */
s->valid_no_process = true;
-
- /* Don't timeout special services during boot (like fsck) */
- if (s->sysv_runlevels && !chars_intersect("12345", s->sysv_runlevels))
- s->timeout_usec = -1;
+ s->kill_mode = KILL_PROCESS_GROUP;
u->meta.load_state = UNIT_LOADED;
r = 0;
path[strlen(path)-8] = 0;
r = service_load_sysv_path(s, path);
+
+ if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+ /* Try Debian style .sh source'able init scripts */
+ strcat(path, ".sh");
+ r = service_load_sysv_path(s, path);
+ }
+
free(path);
+ if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+ /* Try Suse style boot.xxxx init scripts */
+
+ if (asprintf(&path, "%s/boot.%s", *p, name) < 0)
+ return -ENOMEM;
+
+ path[strlen(path)-8] = 0;
+ r = service_load_sysv_path(s, path);
+ free(path);
+ }
+
if (r < 0)
return r;
return r;
}
-static void service_init(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
- assert(u->meta.load_state == UNIT_STUB);
-
- s->type = 0;
- s->restart = 0;
-
- s->timeout_usec = DEFAULT_TIMEOUT_USEC;
- s->restart_usec = DEFAULT_RESTART_USEC;
-
- exec_context_init(&s->exec_context);
-
- s->timer_watch.type = WATCH_INVALID;
-
- s->state = SERVICE_DEAD;
-
- s->sysv_start_priority = -1;
- s->permissions_start_only = false;
- s->root_directory_start_only = false;
- s->valid_no_process = false;
- s->kill_mode = 0;
- s->sysv_has_lsb = false;
- s->main_pid = s->control_pid = 0;
- s->main_pid_known = false;
- s->failure = false;
-
- s->socket_fd = -1;
- s->bus_name_good = false;
-
- RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
-}
-
static int service_verify(Service *s) {
assert(s);
if (!s->exec_command[c])
continue;
- fprintf(f, "%s→ %s:\n",
+ fprintf(f, "%s-> %s:\n",
prefix, service_exec_command_to_string(c));
exec_command_dump_list(s->exec_command[c], f, prefix2);
p = manager_get_unit(UNIT(s)->meta.manager, k);
free(k);
- if (!p) continue;
+ if (!p)
+ continue;
if ((r = set_put(set, p)) < 0)
goto fail;
state != SERVICE_FINAL_SIGKILL) {
service_unwatch_control_pid(s);
s->control_command = NULL;
+ s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
}
if (state == SERVICE_DEAD ||
service_close_socket_fd(s);
if (old_state != state)
- log_debug("%s changed %s → %s", UNIT(s)->meta.id, 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]);
}
+static int service_coldplug(Unit *u) {
+ Service *s = SERVICE(u);
+ int r;
+
+ assert(s);
+ assert(s->state == SERVICE_DEAD);
+
+ if (s->deserialized_state != s->state) {
+
+ if (s->deserialized_state == SERVICE_START_PRE ||
+ s->deserialized_state == SERVICE_START ||
+ s->deserialized_state == SERVICE_START_POST ||
+ s->deserialized_state == SERVICE_RELOAD ||
+ s->deserialized_state == SERVICE_STOP ||
+ s->deserialized_state == SERVICE_STOP_SIGTERM ||
+ s->deserialized_state == SERVICE_STOP_SIGKILL ||
+ s->deserialized_state == SERVICE_STOP_POST ||
+ s->deserialized_state == SERVICE_FINAL_SIGTERM ||
+ s->deserialized_state == SERVICE_FINAL_SIGKILL ||
+ s->deserialized_state == SERVICE_AUTO_RESTART) {
+
+ if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_usec > 0) {
+ usec_t k;
+
+ k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_usec;
+
+ if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0)
+ return r;
+ }
+ }
+
+ if ((s->deserialized_state == SERVICE_START &&
+ (s->type == SERVICE_FORKING ||
+ s->type == SERVICE_DBUS)) ||
+ s->deserialized_state == SERVICE_START_POST ||
+ s->deserialized_state == SERVICE_RUNNING ||
+ s->deserialized_state == SERVICE_RELOAD ||
+ s->deserialized_state == SERVICE_STOP ||
+ s->deserialized_state == SERVICE_STOP_SIGTERM ||
+ s->deserialized_state == SERVICE_STOP_SIGKILL)
+ if (s->main_pid > 0)
+ if ((r = unit_watch_pid(UNIT(s), s->main_pid)) < 0)
+ return r;
+
+ if (s->deserialized_state == SERVICE_START_PRE ||
+ s->deserialized_state == SERVICE_START ||
+ s->deserialized_state == SERVICE_START_POST ||
+ s->deserialized_state == SERVICE_RELOAD ||
+ s->deserialized_state == SERVICE_STOP ||
+ s->deserialized_state == SERVICE_STOP_SIGTERM ||
+ s->deserialized_state == SERVICE_STOP_SIGKILL ||
+ s->deserialized_state == SERVICE_STOP_POST ||
+ s->deserialized_state == SERVICE_FINAL_SIGTERM ||
+ s->deserialized_state == SERVICE_FINAL_SIGKILL)
+ if (s->control_pid > 0)
+ if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
+ return r;
+
+ service_set_state(s, s->deserialized_state);
+ }
+
+ return 0;
+}
+
static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
Iterator i;
int r;
goto fail;
}
- if (timeout) {
+ if (timeout && s->timeout_usec) {
if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
goto fail;
} else
argv,
&s->exec_context,
fds, n_fds,
+ s->meta.manager->environment,
apply_permissions,
apply_chroot,
UNIT(s)->meta.manager->confirm_spawn,
s->failure = true;
if (allow_restart &&
+ s->allow_restart &&
(s->restart == SERVICE_RESTART_ALWAYS ||
(s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure))) {
service_unwatch_control_pid(s);
+ s->control_command_id = SERVICE_EXEC_STOP_POST;
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
if ((r = service_spawn(s,
s->control_command,
}
}
- if (sent) {
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
- goto fail;
+ if (sent && (s->main_pid > 0 || s->control_pid > 0)) {
+ if (s->timeout_usec > 0)
+ if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
+ goto fail;
service_set_state(s, state);
} else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
service_unwatch_control_pid(s);
+ s->control_command_id = SERVICE_EXEC_STOP;
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
if ((r = service_spawn(s,
s->control_command,
service_unwatch_control_pid(s);
+ s->control_command_id = SERVICE_EXEC_START_POST;
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
if ((r = service_spawn(s,
s->control_command,
s->control_pid = pid;
+ s->control_command_id = SERVICE_EXEC_START;
s->control_command = s->exec_command[SERVICE_EXEC_START];
service_set_state(s, SERVICE_START);
service_unwatch_control_pid(s);
+ s->control_command_id = SERVICE_EXEC_START_PRE;
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
if ((r = service_spawn(s,
s->control_command,
service_unwatch_control_pid(s);
+ s->control_command_id = SERVICE_EXEC_RELOAD;
if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
if ((r = service_spawn(s,
s->control_command,
s->failure = false;
s->main_pid_known = false;
+ s->allow_restart = true;
service_enter_start_pre(s);
return 0;
assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
+ /* This is a user request, so don't do restarts on this
+ * shutdown. */
+ s->allow_restart = false;
+
service_enter_stop(s, true);
return 0;
}
return !!s->exec_command[SERVICE_EXEC_RELOAD];
}
+static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
+ Service *s = SERVICE(u);
+
+ assert(u);
+ assert(f);
+ assert(fds);
+
+ unit_serialize_item(u, f, "state", service_state_to_string(s->state));
+ unit_serialize_item(u, f, "failure", yes_no(s->failure));
+
+ if (s->control_pid > 0)
+ unit_serialize_item_format(u, f, "control-pid", "%u", (unsigned) (s->control_pid));
+
+ if (s->main_pid > 0)
+ unit_serialize_item_format(u, f, "main-pid", "%u", (unsigned) (s->main_pid));
+
+ unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
+
+ /* There's a minor uncleanliness here: if there are multiple
+ * commands attached here, we will start from the first one
+ * again */
+ if (s->control_command_id >= 0)
+ unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
+
+ if (s->socket_fd >= 0) {
+ int copy;
+
+ if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0)
+ return copy;
+
+ unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
+ }
+
+ return 0;
+}
+
+static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
+ Service *s = SERVICE(u);
+ int r;
+
+ assert(u);
+ assert(key);
+ assert(value);
+ assert(fds);
+
+ if (streq(key, "state")) {
+ ServiceState state;
+
+ if ((state = service_state_from_string(value)) < 0)
+ log_debug("Failed to parse state value %s", value);
+ else
+ s->deserialized_state = state;
+ } else if (streq(key, "failure")) {
+ int b;
+
+ if ((b = parse_boolean(value)) < 0)
+ log_debug("Failed to parse failure value %s", value);
+ else
+ s->failure = b || s->failure;
+ } else if (streq(key, "control-pid")) {
+ unsigned pid;
+
+ if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+ log_debug("Failed to parse control-pid value %s", value);
+ else
+ s->control_pid = (pid_t) pid;
+ } else if (streq(key, "main-pid")) {
+ unsigned pid;
+
+ if ((r = safe_atou(value, &pid)) < 0 || pid <= 0)
+ log_debug("Failed to parse main-pid value %s", value);
+ else
+ s->main_pid = (pid_t) pid;
+ } else if (streq(key, "main-pid-known")) {
+ int b;
+
+ if ((b = parse_boolean(value)) < 0)
+ log_debug("Failed to parse main-pid-known value %s", value);
+ else
+ s->main_pid_known = b;
+ } else if (streq(key, "control-command")) {
+ ServiceExecCommand id;
+
+ if ((id = service_exec_command_from_string(value)) < 0)
+ log_debug("Failed to parse exec-command value %s", value);
+ else {
+ s->control_command_id = id;
+ s->control_command = s->exec_command[id];
+ }
+ } else if (streq(key, "socket-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse socket-fd value %s", value);
+ else {
+
+ if (s->socket_fd >= 0)
+ close_nointr_nofail(s->socket_fd);
+ s->socket_fd = fdset_remove(fds, fd);
+ }
+ } else
+ log_debug("Unknown serialization key '%s'", key);
+
+ return 0;
+}
+
static UnitActiveState service_active_state(Unit *u) {
assert(u);
return service_state_to_string(SERVICE(u)->state);
}
+static bool service_check_gc(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+ return !!s->sysv_path;
+}
+
+static bool service_check_snapshot(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+ return !s->got_socket_fd;
+}
+
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
Service *s = SERVICE(u);
bool success;
}
} else if (s->control_pid == pid) {
- assert(s->control_command);
- exec_status_fill(&s->control_command->exec_status, pid, code, status);
+ if (s->control_command)
+ 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", u->meta.id, sigchld_code_to_string(code), status);
/* If we are shutting things down anyway we
* don't care about failing commands. */
- if (s->control_command->command_next && success) {
+ if (s->control_command && s->control_command->command_next && success) {
/* There is another command to *
* execute, so let's do that. */
/* No further commands for this step, so let's
* figure out what to do next */
+ s->control_command = NULL;
+ s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+
log_debug("%s got final SIGCHLD for state %s", u->meta.id, service_state_to_string(s->state));
switch (s->state) {
assert(m);
STRV_FOREACH(p, m->sysvrcnd_path)
- for (i = 0; i < ELEMENTSOF(rcnd_table); i += 2) {
+ for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
struct dirent *de;
free(path);
path = NULL;
- if (asprintf(&path, "%s/%s", *p, rcnd_table[i]) < 0) {
+ if (asprintf(&path, "%s/%s", *p, rcnd_table[i].path) < 0) {
r = -ENOMEM;
goto finish;
}
}
while ((de = readdir(d))) {
- Unit *runlevel, *service;
+ Unit *service;
+ int a, b;
if (ignore_file(de->d_name))
continue;
if (strlen(de->d_name) < 4)
continue;
+ a = undecchar(de->d_name[1]);
+ b = undecchar(de->d_name[2]);
+
+ if (a < 0 || b < 0)
+ continue;
+
free(fpath);
fpath = NULL;
- if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i], de->d_name) < 0) {
+ if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i].path, de->d_name) < 0) {
r = -ENOMEM;
goto finish;
}
}
free(name);
- name = NULL;
- if (asprintf(&name, "%s.service", de->d_name+3) < 0) {
+ if (!(name = new(char, strlen(de->d_name) - 3 + 8 + 1))) {
r = -ENOMEM;
goto finish;
}
- if ((r = manager_load_unit(m, name, NULL, &service)) < 0)
- goto finish;
+ if (startswith(de->d_name+3, "boot."))
+ /* Drop SuSE-style boot. prefix */
+ strcpy(stpcpy(name, de->d_name + 3 + 5), ".service");
+ else if (endswith(de->d_name+3, ".sh"))
+ /* Drop Debian-style .sh suffix */
+ strcpy(stpcpy(name, de->d_name + 3) - 3, ".service");
+ else
+ /* Normal init scripts */
+ strcpy(stpcpy(name, de->d_name + 3), ".service");
- if ((r = manager_load_unit(m, rcnd_table[i+1], NULL, &runlevel)) < 0)
- goto finish;
+ if ((r = manager_load_unit_prepare(m, name, NULL, &service)) < 0) {
+ log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
+ continue;
+ }
+
+ if (de->d_name[0] == 'S' &&
+ (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_BASIC))
+ SERVICE(service)->sysv_start_priority =
+ MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
+
+ manager_dispatch_load_queue(m);
+ service = unit_follow_merge(service);
if (de->d_name[0] == 'S') {
- if ((r = unit_add_dependency(runlevel, UNIT_WANTS, service)) < 0)
+ Unit *runlevel_target;
+
+ if ((r = manager_load_unit(m, rcnd_table[i].target, NULL, &runlevel_target)) < 0)
+ goto finish;
+
+ if ((r = unit_add_dependency(runlevel_target, UNIT_WANTS, service, true)) < 0)
goto finish;
- if ((r = unit_add_dependency(runlevel, UNIT_AFTER, service)) < 0)
+ if ((r = unit_add_dependency(service, UNIT_BEFORE, runlevel_target, true)) < 0)
goto finish;
- } else if (de->d_name[0] == 'K' &&
- (streq(rcnd_table[i+1], SPECIAL_RUNLEVEL0_TARGET) ||
- streq(rcnd_table[i+1], SPECIAL_RUNLEVEL6_TARGET))) {
+ } else if (de->d_name[0] == 'K' && rcnd_table[i].type == RUNLEVEL_DOWN) {
+ Unit *shutdown_target;
/* We honour K links only for
* halt/reboot. For the normal
* runlevels we assume the
* stop jobs will be
* implicitly added by the
- * core logic. */
+ * core logic. Also, we don't
+ * really distuingish here
+ * between the runlevels 0 and
+ * 6 and just add them to the
+ * special shutdown target. */
- if ((r = unit_add_dependency(runlevel, UNIT_CONFLICTS, service)) < 0)
+ if ((r = manager_load_unit(m, SPECIAL_SHUTDOWN_TARGET, NULL, &shutdown_target)) < 0)
goto finish;
- if ((r = unit_add_dependency(runlevel, UNIT_BEFORE, service)) < 0)
+ if ((r = unit_add_dependency(service, UNIT_CONFLICTS, shutdown_target, true)) < 0)
+ goto finish;
+
+ if ((r = unit_add_dependency(service, UNIT_BEFORE, shutdown_target, true)) < 0)
goto finish;
}
}
free(path);
free(fpath);
free(name);
- closedir(d);
+
+ if (d)
+ closedir(d);
return r;
}
return -EAGAIN;
s->socket_fd = fd;
+ s->got_socket_fd = true;
return 0;
}
.suffix = ".service",
.init = service_init,
- .load = service_load,
.done = service_done,
+ .load = service_load,
+
+ .coldplug = service_coldplug,
.dump = service_dump,
.can_reload = service_can_reload,
+ .serialize = service_serialize,
+ .deserialize_item = service_deserialize_item,
+
.active_state = service_active_state,
.sub_state_to_string = service_sub_state_to_string,
+ .check_gc = service_check_gc,
+ .check_snapshot = service_check_snapshot,
+
.sigchld_event = service_sigchld_event,
.timer_event = service_timer_event,
.bus_name_owner_change = service_bus_name_owner_change,
.bus_query_pid_done = service_bus_query_pid_done,
+ .bus_message_handler = bus_service_message_handler,
+
.enumerate = service_enumerate
};