#include <signal.h>
#include <dirent.h>
#include <unistd.h>
+#include <sys/reboot.h>
+#include "manager.h"
#include "unit.h"
#include "service.h"
#include "load-fragment.h"
exec_context_init(&s->exec_context);
- RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
+ RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
}
s->remain_after_exit = !s->pid_file;
s->guess_main_pid = false;
s->restart = SERVICE_RESTART_NO;
+ s->exec_context.ignore_sigpipe = false;
if (UNIT(s)->manager->sysv_console)
s->exec_context.std_output = EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
s->notify_access = NOTIFY_MAIN;
+ if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
+ s->notify_access = NOTIFY_MAIN;
+
if (s->type == SERVICE_DBUS || s->bus_name)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
return r;
goto fail;
}
+ if (s->watchdog_usec > 0)
+ if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
+
if (!(final_env = strv_env_merge(2,
UNIT(s)->manager->environment,
our_env,
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
+static int service_start_limit_test(Service *s) {
+ assert(s);
+
+ if (ratelimit_test(&s->start_limit))
+ return 0;
+
+ switch (s->start_limit_action) {
+
+ case SERVICE_START_LIMIT_NONE:
+ log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
+ break;
+
+ case SERVICE_START_LIMIT_REBOOT: {
+ DBusError error;
+ int r;
+
+ dbus_error_init(&error);
+
+ log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
+
+ r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
+ if (r < 0) {
+ log_error("Failed to reboot: %s.", bus_error(&error, r));
+ dbus_error_free(&error);
+ }
+
+ break;
+ }
+
+ case SERVICE_START_LIMIT_REBOOT_FORCE:
+ log_warning("%s start request repeated too quickly, force rebooting.", UNIT(s)->id);
+ UNIT(s)->manager->exit_code = MANAGER_REBOOT;
+ break;
+
+ case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
+ log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
+ reboot(RB_AUTOBOOT);
+ break;
+
+ default:
+ log_error("start limit action=%i", s->start_limit_action);
+ assert_not_reached("Unknown StartLimitAction.");
+ }
+
+ return -ECANCELED;
+}
+
static int service_start(Unit *u) {
Service *s = SERVICE(u);
+ int r;
assert(s);
assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART);
/* 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.", u->id);
- return -ECANCELED;
- }
+ r = service_start_limit_test(s);
+ if (r < 0)
+ return r;
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
+static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
+ [SERVICE_START_LIMIT_NONE] = "none",
+ [SERVICE_START_LIMIT_REBOOT] = "reboot",
+ [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force",
+ [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate"
+};
+DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
+
const UnitVTable service_vtable = {
.suffix = ".service",
.object_size = sizeof(Service),