-/*-*- Mode: C; c-basic-offset: 8 -*-*/
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
if (unit_name_to_type(m) == UNIT_SERVICE)
r = unit_add_name(u, m);
- else if (s->sysv_start_priority >= 0)
+ else if (s->sysv_enabled)
r = unit_add_two_dependencies_by_name_inverse(u, UNIT_AFTER, UNIT_WANTS, m, NULL, true);
else
r = unit_add_dependency_by_name_inverse(u, UNIT_AFTER, m, NULL, true);
s->type = SERVICE_FORKING;
s->valid_no_process = true;
s->restart = SERVICE_ONCE;
- s->exec_context.std_output = EXEC_OUTPUT_TTY;
+ s->exec_context.std_output = s->meta.manager->sysv_console ? EXEC_OUTPUT_TTY : EXEC_OUTPUT_NULL;
s->exec_context.kill_mode = KILL_PROCESS_GROUP;
u->meta.load_state = UNIT_LOADED;
if (t == s->meta.id)
continue;
- if ((r == service_load_sysv_name(s, t)) < 0)
+ if ((r = service_load_sysv_name(s, t)) < 0)
return r;
if (s->meta.load_state != UNIT_STUB)
return -EINVAL;
}
- if (s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_error("%s has more than one ExecStart setting. Refusing.", s->meta.id);
+ if (s->type != SERVICE_ONESHOT &&
+ s->exec_command[SERVICE_EXEC_START]->command_next) {
+ log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", s->meta.id);
return -EINVAL;
}
}
/* Second, activate normal shutdown */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTED_BY, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
static int service_load(Unit *u) {
if (s->sysv_start_priority >= 0)
fprintf(f,
- "%sSysVStartPriority: %i\n",
- prefix, s->sysv_start_priority);
+ "%sSysVStartPriority: %i\n"
+ "%sSysVEnabled: %s\n",
+ prefix, s->sysv_start_priority,
+ prefix, yes_no(s->sysv_enabled));
if (s->sysv_runlevels)
fprintf(f, "%sSysVRunLevels: %s\n",
if ((s->deserialized_state == SERVICE_START &&
(s->type == SERVICE_FORKING ||
s->type == SERVICE_DBUS ||
- s->type == SERVICE_FINISH ||
+ s->type == SERVICE_ONESHOT ||
s->type == SERVICE_NOTIFY)) ||
s->deserialized_state == SERVICE_START_POST ||
s->deserialized_state == SERVICE_RUNNING ||
s->failure = true;
if (allow_restart &&
- s->allow_restart &&
+ !s->forbid_restart &&
(s->restart == SERVICE_RESTART_ALWAYS ||
(s->restart == SERVICE_RESTART_ON_SUCCESS && !s->failure))) {
} else
service_set_state(s, s->failure ? SERVICE_MAINTENANCE : SERVICE_DEAD);
+ s->forbid_restart = false;
+
return;
fail:
assert(s);
assert(s->exec_command[SERVICE_EXEC_START]);
- assert(!s->exec_command[SERVICE_EXEC_START]->command_next);
+ assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
if (s->type == SERVICE_FORKING)
service_unwatch_control_pid(s);
else
service_unwatch_main_pid(s);
+ s->control_command_id = SERVICE_EXEC_START;
+ s->control_command = s->exec_command[SERVICE_EXEC_START];
+
if ((r = service_spawn(s,
- s->exec_command[SERVICE_EXEC_START],
+ s->control_command,
s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
true,
true,
/* For forking services we wait until the start
* process exited. */
- s->control_command_id = SERVICE_EXEC_START;
- s->control_command = s->exec_command[SERVICE_EXEC_START];
-
s->control_pid = pid;
service_set_state(s, SERVICE_START);
- } else if (s->type == SERVICE_FINISH ||
+ } else if (s->type == SERVICE_ONESHOT ||
s->type == SERVICE_DBUS ||
s->type == SERVICE_NOTIFY) {
- /* For finishing services we wait until the start
+ /* For oneshot services we wait until the start
* process exited, too, but it is our main process. */
/* For D-Bus services we know the main pid right away,
service_enter_stop(s, false);
}
-static void service_run_next(Service *s, bool success) {
+static void service_run_next_control(Service *s, bool success) {
int r;
assert(s);
if (!success)
s->failure = true;
- s->control_command = s->control_command->command_next;
+ assert(s->control_command_id != SERVICE_EXEC_START);
+ s->control_command = s->control_command->command_next;
service_unwatch_control_pid(s);
if ((r = service_spawn(s,
return;
fail:
- log_warning("%s failed to run next task: %s", s->meta.id, strerror(-r));
+ log_warning("%s failed to run next control task: %s", s->meta.id, strerror(-r));
if (s->state == SERVICE_START_PRE)
service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
service_enter_stop(s, false);
}
+static void service_run_next_main(Service *s, bool success) {
+ pid_t pid;
+ int r;
+
+ assert(s);
+ assert(s->control_command);
+ assert(s->control_command->command_next);
+
+ if (!success)
+ s->failure = true;
+
+ assert(s->control_command_id == SERVICE_EXEC_START);
+ assert(s->type == SERVICE_ONESHOT);
+
+ s->control_command = s->control_command->command_next;
+ service_unwatch_main_pid(s);
+
+ if ((r = service_spawn(s,
+ s->control_command,
+ false,
+ true,
+ true,
+ true,
+ true,
+ s->notify_access != NOTIFY_NONE,
+ &pid)) < 0)
+ goto fail;
+
+ service_set_main_pid(s, pid);
+
+ return;
+
+fail:
+ log_warning("%s failed to run next main task: %s", s->meta.id, strerror(-r));
+ service_enter_stop(s, false);
+}
+
static int service_start(Unit *u) {
Service *s = SERVICE(u);
s->failure = false;
s->main_pid_known = false;
- s->allow_restart = true;
+ s->forbid_restart = false;
service_enter_start_pre(s);
return 0;
/* This is a user request, so don't do restarts on this
* shutdown. */
- s->allow_restart = false;
+ s->forbid_restart = true;
/* Already on it */
if (s->state == SERVICE_STOP ||
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);
} else if (streq(key, "control-pid")) {
pid_t pid;
- if ((r = parse_pid(value, &pid)) < 0)
+ if (parse_pid(value, &pid) < 0)
log_debug("Failed to parse control-pid value %s", value);
else
s->control_pid = pid;
} else if (streq(key, "main-pid")) {
pid_t pid;
- if ((r = parse_pid(value, &pid)) < 0)
+ if (parse_pid(value, &pid) < 0)
log_debug("Failed to parse main-pid value %s", value);
else
service_set_main_pid(s, (pid_t) pid);
} else if (streq(key, "main-exec-status-pid")) {
pid_t pid;
- if ((r = parse_pid(value, &pid)) < 0)
+ if (parse_pid(value, &pid) < 0)
log_debug("Failed to parse main-exec-status-pid value %s", value);
else
s->main_exec_status.pid = pid;
} else if (streq(key, "main-exec-status-code")) {
int i;
- if ((r = safe_atoi(value, &i)) < 0)
+ if (safe_atoi(value, &i) < 0)
log_debug("Failed to parse main-exec-status-code value %s", value);
else
s->main_exec_status.code = i;
} else if (streq(key, "main-exec-status-status")) {
int i;
- if ((r = safe_atoi(value, &i)) < 0)
+ if (safe_atoi(value, &i) < 0)
log_debug("Failed to parse main-exec-status-status value %s", value);
else
s->main_exec_status.status = i;
} else if (streq(key, "main-exec-status-start-realtime")) {
uint64_t k;
- if ((r = safe_atou64(value, &k)) < 0)
+ if (safe_atou64(value, &k) < 0)
log_debug("Failed to parse main-exec-status-start-realtime value %s", value);
else
s->main_exec_status.start_timestamp.realtime = (usec_t) k;
} else if (streq(key, "main-exec-status-start-monotonic")) {
uint64_t k;
- if ((r = safe_atou64(value, &k)) < 0)
+ if (safe_atou64(value, &k) < 0)
log_debug("Failed to parse main-exec-status-start-monotonic value %s", value);
else
s->main_exec_status.start_timestamp.monotonic = (usec_t) k;
} else if (streq(key, "main-exec-status-exit-realtime")) {
uint64_t k;
- if ((r = safe_atou64(value, &k)) < 0)
+ if (safe_atou64(value, &k) < 0)
log_debug("Failed to parse main-exec-status-exit-realtime value %s", value);
else
s->main_exec_status.exit_timestamp.realtime = (usec_t) k;
} else if (streq(key, "main-exec-status-exit-monotonic")) {
uint64_t k;
- if ((r = safe_atou64(value, &k)) < 0)
+ if (safe_atou64(value, &k) < 0)
log_debug("Failed to parse main-exec-status-exit-monotonic value %s", value);
else
s->main_exec_status.exit_timestamp.monotonic = (usec_t) k;
if (s->main_pid == pid) {
- exec_status_exit(&s->main_exec_status, pid, code, status);
s->main_pid = 0;
+ exec_status_exit(&s->main_exec_status, pid, code, status);
- if (s->type != SERVICE_FORKING) {
- assert(s->exec_command[SERVICE_EXEC_START]);
- s->exec_command[SERVICE_EXEC_START]->exec_status = s->main_exec_status;
+ if (s->type != SERVICE_FORKING && s->control_command) {
+ s->control_command->exec_status = s->main_exec_status;
- if (s->exec_command[SERVICE_EXEC_START]->ignore)
+ if (s->control_command->ignore)
success = true;
}
"%s: main process exited, code=%s, status=%i", u->meta.id, sigchld_code_to_string(code), status);
s->failure = s->failure || !success;
- /* The service exited, so the service is officially
- * gone. */
+ if (s->control_command &&
+ s->control_command->command_next &&
+ success) {
- switch (s->state) {
+ /* There is another command to *
+ * execute, so let's do that. */
- case SERVICE_START_POST:
- case SERVICE_RELOAD:
- case SERVICE_STOP:
- /* Need to wait until the operation is
- * done */
- break;
+ log_debug("%s running next main command for state %s", u->meta.id, service_state_to_string(s->state));
+ service_run_next_main(s, success);
- case SERVICE_START:
- if (s->type == SERVICE_FINISH) {
- /* This was our main goal, so let's go on */
- if (success)
- service_enter_start_post(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+ } else {
+
+ /* The service exited, so the service is officially
+ * gone. */
+
+ s->control_command = NULL;
+ s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
+
+ switch (s->state) {
+
+ case SERVICE_START_POST:
+ case SERVICE_RELOAD:
+ case SERVICE_STOP:
+ /* Need to wait until the operation is
+ * done */
break;
- } else {
- assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
- /* Fall through */
- }
+ case SERVICE_START:
+ if (s->type == SERVICE_ONESHOT) {
+ /* This was our main goal, so let's go on */
+ if (success)
+ service_enter_start_post(s);
+ else
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+ break;
+ } else {
+ assert(s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY);
- case SERVICE_RUNNING:
- service_enter_running(s, success);
- break;
+ /* Fall through */
+ }
+
+ case SERVICE_RUNNING:
+ service_enter_running(s, success);
+ break;
- case SERVICE_STOP_SIGTERM:
- case SERVICE_STOP_SIGKILL:
+ case SERVICE_STOP_SIGTERM:
+ case SERVICE_STOP_SIGKILL:
- if (!control_pid_good(s))
- service_enter_stop_post(s, success);
+ if (!control_pid_good(s))
+ service_enter_stop_post(s, success);
- /* If there is still a control process, wait for that first */
- break;
+ /* If there is still a control process, wait for that first */
+ break;
- default:
- assert_not_reached("Uh, main process died at wrong time.");
+ default:
+ assert_not_reached("Uh, main process died at wrong time.");
+ }
}
} else if (s->control_pid == pid) {
+ s->control_pid = 0;
+
if (s->control_command) {
exec_status_exit(&s->control_command->exec_status, pid, code, status);
success = true;
}
- s->control_pid = 0;
-
- log_full(success ? LOG_DEBUG : LOG_NOTICE,
+ log_full(success ? LOG_DEBUG : LOG_NOTICE,
"%s: control process exited, code=%s status=%i", u->meta.id, sigchld_code_to_string(code), status);
s->failure = s->failure || !success;
- /* If we are shutting things down anyway we
- * don't care about failing commands. */
-
- if (s->control_command && 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. */
- log_debug("%s running next command for state %s", u->meta.id, service_state_to_string(s->state));
- service_run_next(s, success);
+ log_debug("%s running next control command for state %s", u->meta.id, service_state_to_string(s->state));
+ service_run_next_control(s, success);
} else {
/* No further commands for this step, so let's
}
if (de->d_name[0] == 'S' &&
- (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT))
+ (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
SERVICE(service)->sysv_start_priority =
MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
+ SERVICE(service)->sysv_enabled = true;
+ }
manager_dispatch_load_queue(m);
service = unit_follow_merge(service);
static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
[SERVICE_SIMPLE] = "simple",
[SERVICE_FORKING] = "forking",
- [SERVICE_FINISH] = "finish",
+ [SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
[SERVICE_NOTIFY] = "notify"
};