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
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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.
+ Lesser General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "bus-errors.h"
#include "exit-status.h"
#include "def.h"
+#include "path-util.h"
#include "util.h"
#include "utf8.h"
static void service_init(Unit *u) {
Service *s = SERVICE(u);
+ int i;
assert(u);
assert(u->load_state == UNIT_STUB);
s->timeout_usec = DEFAULT_TIMEOUT_USEC;
s->restart_usec = DEFAULT_RESTART_USEC;
+ s->type = _SERVICE_TYPE_INVALID;
s->watchdog_watch.type = WATCH_INVALID;
s->guess_main_pid = true;
exec_context_init(&s->exec_context);
+ for (i = 0; i < RLIMIT_NLIMITS; i++)
+ if (UNIT(s)->manager->rlimit[i])
+ s->exec_context.rlimit[i] = newdup(struct rlimit, UNIT(s)->manager->rlimit[i], 1);
RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
goto finish;
}
- r = sysv_translate_facility(n, file_name_from_path(path), &m);
+ r = sysv_translate_facility(n, path_get_file_name(path), &m);
free(n);
if (r < 0)
goto finish;
}
- r = sysv_translate_facility(n, file_name_from_path(path), &m);
+ r = sysv_translate_facility(n, path_get_file_name(path), &m);
if (r < 0) {
log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
return -EINVAL;
}
+ if (s->bus_name && s->type != SERVICE_DBUS)
+ log_warning("%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
+
if (s->exec_context.pam_name && s->exec_context.kill_mode != KILL_CONTROL_GROUP) {
log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
return -EINVAL;
/* This is a new unit? Then let's add in some extras */
if (u->load_state == UNIT_LOADED) {
+ if (s->type == _SERVICE_TYPE_INVALID)
+ s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
+
service_fix_output(s);
if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
bool apply_chroot,
bool apply_tty_stdin,
bool set_notify_socket,
+ bool is_control,
pid_t *_pid) {
pid_t pid;
UNIT(s)->manager->confirm_spawn,
UNIT(s)->cgroup_bondings,
UNIT(s)->cgroup_attributes,
+ is_control ? "control" : NULL,
+ s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
&pid);
if (r < 0)
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
s->control_command_id = SERVICE_EXEC_STOP_POST;
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ true,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
goto fail;
- if ((r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, pid_set)) < 0) {
+ r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
+ if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning("Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
s->control_command_id = SERVICE_EXEC_STOP;
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ false,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
service_set_state(s, SERVICE_STOP);
if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
s->control_command_id = SERVICE_EXEC_START_POST;
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ false,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
service_set_state(s, SERVICE_START_POST);
/* We want to ensure that nobody leaks processes from
* START_PRE here, so let's go on a killing spree, People
* should not spawn long running processes from START_PRE. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+ cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
if (s->type == SERVICE_FORKING) {
s->control_command_id = SERVICE_EXEC_START;
c = s->main_command = s->exec_command[SERVICE_EXEC_START];
}
- if ((r = service_spawn(s,
- c,
- s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
- true,
- true,
- true,
- true,
- s->notify_access != NOTIFY_NONE,
- &pid)) < 0)
+ r = service_spawn(s,
+ c,
+ s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY,
+ true,
+ true,
+ true,
+ true,
+ s->notify_access != NOTIFY_NONE,
+ false,
+ &pid);
+ if (r < 0)
goto fail;
- if (s->type == SERVICE_SIMPLE) {
+ if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
/* For simple services we immediately start
* the START_POST binaries. */
/* Before we start anything, let's clear up what might
* be left from previous runs. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, NULL);
+ cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
s->control_command_id = SERVICE_EXEC_START_PRE;
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ true,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
service_set_state(s, SERVICE_START_PRE);
if ((r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch)) < 0)
goto fail;
+
+ return;
}
/* Any units that are bound to this service must also be
if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
s->control_command_id = SERVICE_EXEC_RELOAD;
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ false,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
service_set_state(s, SERVICE_RELOAD);
s->control_command = s->control_command->command_next;
service_unwatch_control_pid(s);
- if ((r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- s->control_command_id == SERVICE_EXEC_START_PRE ||
- s->control_command_id == SERVICE_EXEC_STOP_POST,
- false,
- &s->control_pid)) < 0)
+ r = service_spawn(s,
+ s->control_command,
+ true,
+ false,
+ !s->permissions_start_only,
+ !s->root_directory_start_only,
+ s->control_command_id == SERVICE_EXEC_START_PRE ||
+ s->control_command_id == SERVICE_EXEC_STOP_POST,
+ false,
+ true,
+ &s->control_pid);
+ if (r < 0)
goto fail;
return;
s->main_command = s->main_command->command_next;
service_unwatch_main_pid(s);
- if ((r = service_spawn(s,
- s->main_command,
- false,
- true,
- true,
- true,
- true,
- s->notify_access != NOTIFY_NONE,
- &pid)) < 0)
+ r = service_spawn(s,
+ s->main_command,
+ false,
+ true,
+ true,
+ true,
+ true,
+ s->notify_access != NOTIFY_NONE,
+ false,
+ &pid);
+ if (r < 0)
goto fail;
service_set_main_pid(s, pid);
if (f != SERVICE_SUCCESS)
s->result = f;
+ /* Immediately get rid of the cgroup, so that the
+ * kernel doesn't delay the cgroup empty messages for
+ * the service cgroup any longer than necessary */
+ cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
+
if (s->control_command &&
s->control_command->command_next &&
f == SERVICE_SUCCESS) {
r = q;
goto finish;
}
-
- if ((q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, pid_set)) < 0)
+ q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
+ if (q < 0)
if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
}
[SERVICE_FORKING] = "forking",
[SERVICE_ONESHOT] = "oneshot",
[SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify"
+ [SERVICE_NOTIFY] = "notify",
+ [SERVICE_IDLE] = "idle"
};
DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
"Unit\0"
"Service\0"
"Install\0",
- .show_status = true,
.init = service_init,
.done = service_done,
.bus_invalidating_properties = bus_service_invalidating_properties,
#ifdef HAVE_SYSV_COMPAT
- .enumerate = service_enumerate
+ .enumerate = service_enumerate,
#endif
+ .status_message_formats = {
+ .starting_stopping = {
+ [0] = "Starting %s...",
+ [1] = "Stopping %s...",
+ },
+ .finished_start_job = {
+ [JOB_DONE] = "Started %s.",
+ [JOB_FAILED] = "Failed to start %s.",
+ [JOB_DEPENDENCY] = "Dependency failed for %s.",
+ [JOB_TIMEOUT] = "Timed out starting %s.",
+ },
+ .finished_stop_job = {
+ [JOB_DONE] = "Stopped %s.",
+ [JOB_FAILED] = "Stopped (with error) %s.",
+ [JOB_TIMEOUT] = "Timed out stopping %s.",
+ },
+ },
};