service.c revision cd25cce98f5cc930202212c3c9c13605c09698b4
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen This file is part of systemd.
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen Copyright 2010 Lennart Poettering
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen systemd is free software; you can redistribute it and/or modify it
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen under the terms of the GNU General Public License as published by
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen the Free Software Foundation; either version 2 of the License, or
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen (at your option) any later version.
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen systemd is distributed in the hope that it will be useful, but
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen General Public License for more details.
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen You should have received a copy of the GNU General Public License
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersenstatic const struct {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Standard SysV runlevels for start-up */
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* SUSE style boot.d */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek { "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_FRUGALWARE)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Debian style rcS.d */
12b42c76672a66c2d4ea7212c14f8f1b5a62b78dTom Gundersen { "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
57e27ec0ada6775d85a5201cd25e989d92d0a1afZbigniew Jędrzejewski-Szmek /* Standard SysV runlevels for shutdown */
57e27ec0ada6775d85a5201cd25e989d92d0a1afZbigniew Jędrzejewski-Szmek { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN },
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN }
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Note that the order here matters, as we read the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek directories in this order, and we want to make sure that
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek sysv_start_priority is known when we first load the
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit. And that value we only know from S links. Hence
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek UP/SYSINIT must be read before DOWN */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek/* #define RUNLEVELS_DOWN "06" */
102bd40e1ed71c7ab980a90435a1c23d4c786c63Lennart Poettering/* #define RUNLEVELS_BOOT "bBsS" */
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersenstatic const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_START_PRE] = UNIT_ACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_START] = UNIT_ACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_RUNNING] = UNIT_ACTIVE,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_RELOAD] = UNIT_RELOADING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_STOP] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek assert(u->meta.load_state == UNIT_STUB);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek s->timeout_usec = DEFAULT_TIMEOUT_USEC;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek s->restart_usec = DEFAULT_RESTART_USEC;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek exec_context_init(&s->exec_context);
5256e00e8b9015dd1a976d647fc71dc7efbd8cf8Tom Gundersen s->exec_context.std_output = u->meta.manager->default_std_output;
5256e00e8b9015dd1a976d647fc71dc7efbd8cf8Tom Gundersen s->exec_context.std_error = u->meta.manager->default_std_error;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void service_unwatch_control_pid(Service *s) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_pid(UNIT(s), s->control_pid);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void service_unwatch_main_pid(Service *s) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_pid(UNIT(s), s->main_pid);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int service_set_main_pid(Service *s, pid_t pid) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid())
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.",
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek s->meta.id, (unsigned long) pid);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek exec_status_start(&s->main_exec_status, pid);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void service_close_socket_fd(Service *s) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void service_connection_unref(Service *s) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek socket_connection_unref(s->accept_socket);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic void service_done(Unit *u) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek exec_context_done(&s->exec_context);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* This will leak a process, but at least no memory or any of
1c25683e0f40c6169676cc44fa1897082597feecTom Gundersen * our resources */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_bus_name(UNIT(u), s->bus_name);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek unit_unwatch_timer(u, &s->timer_watch);
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic char *sysv_translate_name(const char *name) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(r = new(char, strlen(name) + sizeof(".service"))))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Drop Debian-style .sh suffix */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strcpy(stpcpy(r, name) - 3, ".service");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Drop SuSE-style boot. prefix */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strcpy(stpcpy(r, name + 5), ".service");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Drop Frugalware-style rc. prefix */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek strcpy(stpcpy(r, name + 3), ".service");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Normal init scripts */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int sysv_translate_facility(const char *name, const char *filename, char **_r) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* We silently ignore the $ prefix here. According to the LSB
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * spec it simply indicates whether something is a
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * standardized name or a distribution-specific one. Since we
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * just follow what already exists and do not introduce new
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * uses or names we don't care who introduced a new name. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek static const char * const table[] = {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* LSB defined facilities */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "local_fs", SPECIAL_LOCAL_FS_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Due to unfortunate name selection in Mandriva,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * $network is provided by network-up which is ordered
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * after network which actually starts interfaces.
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * To break the loop, just ignore it */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "network", SPECIAL_NETWORK_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "named", SPECIAL_NSS_LOOKUP_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "portmap", SPECIAL_RPCBIND_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "remote_fs", SPECIAL_REMOTE_FS_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "syslog", SPECIAL_SYSLOG_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* common extensions */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "mail-transfer-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "x-display-manager", SPECIAL_DISPLAY_MANAGER_SERVICE,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "MTA", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "smtpdaemon", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "httpd", SPECIAL_HTTP_DAEMON_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek "smtp", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek n = *name == '$' ? name + 1 : name;
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek for (i = 0; i < ELEMENTSOF(table); i += 2) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* If we don't know this name, fallback heuristics to figure
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * out whether something is a target or a service alias. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Facilities starting with $ are most likely targets */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek r = unit_name_build(n, NULL, ".target");
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek } else if (filename && streq(name, filename))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Names equaling the file name of the services are redundant */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* Everything else we assume to be normal service names */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic int sysv_fix_order(Service *s) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* For each pair of services where at least one lacks a LSB
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek * header, we use the start priority value to order things. */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (t->meta.load_state != UNIT_LOADED)
6c1695be47b2830c79e128e4d05d760eb862184eLennart Poettering /* If both units have modern headers we don't care
1ff28eaee33d9d0cee46bd176b6d6f8805c95036Tom Gundersen * about the priorities */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if ((s->meta.fragment_path || s->sysv_has_lsb) &&
7abaad1ab099b077ebd6452b14ef351483831245poma special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels);
7abaad1ab099b077ebd6452b14ef351483831245poma special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels);
7abaad1ab099b077ebd6452b14ef351483831245poma else if (t->sysv_start_priority < s->sysv_start_priority)
7abaad1ab099b077ebd6452b14ef351483831245poma else if (t->sysv_start_priority > s->sysv_start_priority)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek /* FIXME: Maybe we should compare the name here lexicographically? */
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmekstatic ExecCommand *exec_command_new(const char *path, const char *arg1) {
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(c = new0(ExecCommand, 1)))
798d3a524ea57aaf40cb53858aaa45ec702f012dZbigniew Jędrzejewski-Szmek if (!(c->path = strdup(path))) {
free(c);
return NULL;
ExecCommand *c;
assert(s);
return -ENOMEM;
return -ENOMEM;
return -ENOMEM;
FILE *f;
Unit *u;
unsigned line = 0;
LSB,
char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
assert(s);
u = UNIT(s);
goto finish;
r = -ENOMEM;
goto finish;
while (!feof(f)) {
char l[LINE_MAX], *t;
if (!fgets(l, sizeof(l), f)) {
if (feof(f))
r = -errno;
goto finish;
line++;
t = strstrip(l);
s->sysv_has_lsb = true;
int start_priority;
else if (s->sysv_start_priority < 0)
if (!(d = strdup(k))) {
r = -ENOMEM;
goto finish;
s->sysv_runlevels = d;
if (!(d = strdup(j))) {
r = -ENOMEM;
goto finish;
d = NULL;
char *fn;
r = -ENOMEM;
goto finish;
if ((j = strstrip(t)) && *j) {
char *d = NULL;
d = strdup(j);
r = -ENOMEM;
goto finish;
size_t z;
if (!(n = strndup(w, z))) {
r = -ENOMEM;
goto finish;
free(n);
goto finish;
r = unit_add_name(u, m);
free(m);
size_t z;
if (!(n = strndup(w, z))) {
r = -ENOMEM;
goto finish;
log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
free(n);
free(n);
r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true);
free(m);
if (!(d = strdup(k))) {
r = -ENOMEM;
goto finish;
s->sysv_runlevels = d;
if (!(d = strdup(j))) {
r = -ENOMEM;
goto finish;
d = NULL;
long_description = d;
if (!(d = strdup(j))) {
r = -ENOMEM;
goto finish;
d = NULL;
short_description = d;
if ((j = strstrip(t)) && *j) {
char *d = NULL;
if (long_description)
d = strdup(j);
r = -ENOMEM;
goto finish;
long_description = d;
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
s->timeout_usec = 0;
s->remain_after_exit = true;
if (short_description)
else if (chkconfig_description)
else if (long_description)
if (description) {
r = -ENOMEM;
goto finish;
fclose(f);
assert(s);
return -ENOENT;
#ifdef TARGET_SUSE
return -ENOENT;
#ifdef TARGET_FRUGALWARE
return -ENOENT;
char *path;
return -ENOMEM;
#ifdef TARGET_SUSE
return -ENOMEM;
#ifdef TARGET_FRUGALWARE
return -ENOMEM;
Iterator i;
assert(s);
if ((r = service_load_sysv_name(s, t)) < 0)
if ((r = service_load_sysv_name(s, t)) < 0)
assert(s);
if (s->fsck_passno <= 0)
Service *t;
if (t->fsck_passno <= 0)
d = UNIT_AFTER;
d = UNIT_BEFORE;
assert(s);
return -EINVAL;
log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", s->meta.id);
return -EINVAL;
log_error("%s has an ExecReload setting, which is not allowed for Type=oneshot services. Refusing.", s->meta.id);
return -EINVAL;
log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", s->meta.id);
return -EINVAL;
return -EINVAL;
assert(s);
if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
assert(s);
if ((r = unit_load_fragment(u)) < 0)
#ifdef HAVE_SYSV_COMPAT
if ((r = service_load_sysv(s)) < 0)
return -ENOENT;
if ((r = unit_add_default_cgroups(u)) < 0)
#ifdef HAVE_SYSV_COMPAT
if ((r = sysv_fix_order(s)) < 0)
if ((r = fsck_fix_order(s)) < 0)
if (s->bus_name)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
if ((r = service_add_default_dependencies(s)) < 0)
return service_verify(s);
const char *prefix2;
char *p2;
assert(s);
fprintf(f,
if (s->control_pid > 0)
fprintf(f,
if (s->main_pid > 0)
fprintf(f,
if (s->pid_file)
fprintf(f,
if (s->bus_name)
fprintf(f,
for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
if (!s->exec_command[c])
#ifdef HAVE_SYSV_COMPAT
if (s->sysv_path)
fprintf(f,
if (s->sysv_start_priority >= 0)
fprintf(f,
if (s->sysv_runlevels)
if (s->fsck_passno > 0)
fprintf(f,
if (s->status_text)
assert(s);
if (!s->pid_file)
return -ENOENT;
free(k);
log_warning("PID %lu read from file %s does not exist. Your service or init script might be broken.",
return -ESRCH;
assert(s);
if (s->main_pid_known)
if (!s->guess_main_pid)
return -ENOENT;
Iterator i;
assert(s);
if (s->socket_fd >= 0)
return -ENOMEM;
Unit *p;
r = -ENOMEM;
goto fail;
free(k);
goto fail;
fail:
Iterator i;
assert(s);
if (s->socket_fd >= 0)
assert(s);
log_debug("%s changed %s -> %s", 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], !s->reload_failure);
s->reload_failure = false;
assert(s);
usec_t k;
if (s->main_pid > 0)
if (s->control_pid > 0)
Iterator i;
unsigned rn_fds = 0;
assert(s);
if (s->socket_fd >= 0)
int *cfds;
unsigned cn_fds;
goto fail;
if (!cfds)
if (!rfds) {
r = -ENOMEM;
goto fail;
rfds = t;
fail:
static int service_spawn(
Service *s,
ExecCommand *c,
bool timeout,
bool pass_fds,
bool apply_permissions,
bool apply_chroot,
bool apply_tty_stdin,
bool set_notify_socket,
assert(s);
assert(c);
if (pass_fds ||
if (s->socket_fd >= 0) {
goto fail;
goto fail;
r = -ENOMEM;
goto fail;
r = -ENOMEM;
goto fail;
if (set_notify_socket)
r = -ENOMEM;
goto fail;
if (s->main_pid > 0)
r = -ENOMEM;
goto fail;
NULL))) {
r = -ENOMEM;
goto fail;
r = exec_spawn(c,
argv,
&s->exec_context,
&pid);
goto fail;
goto fail;
fail:
if (timeout)
assert(s);
if (s->main_pid_known)
return s->main_pid > 0;
return -EAGAIN;
assert(s);
return s->control_pid > 0;
assert(s);
assert(s);
if (!success)
s->failure = true;
if (allow_restart &&
!s->forbid_restart &&
goto fail;
s->forbid_restart = false;
fail:
service_enter_dead(s, false, false);
assert(s);
if (!success)
s->failure = true;
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
fail:
bool wait_for_exit = false;
assert(s);
if (!success)
s->failure = true;
int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
if (s->main_pid > 0) {
wait_for_exit = true;
if (s->control_pid > 0) {
wait_for_exit = true;
r = -ENOMEM;
goto fail;
if (s->main_pid > 0)
goto fail;
if (s->control_pid > 0)
goto fail;
wait_for_exit = true;
if (wait_for_exit) {
if (s->timeout_usec > 0)
goto fail;
service_enter_stop_post(s, true);
service_enter_dead(s, true, true);
fail:
service_enter_stop_post(s, false);
service_enter_dead(s, false, true);
if (pid_set)
assert(s);
if (!success)
s->failure = true;
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
fail:
assert(s);
if (!success)
s->failure = true;
else if (s->remain_after_exit)
service_enter_stop(s, true);
assert(s);
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
service_enter_running(s, true);
fail:
service_enter_stop(s, false);
ExecCommand *c;
assert(s);
if ((r = service_spawn(s,
&pid)) < 0)
goto fail;
fail:
assert(s);
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
fail:
service_enter_dead(s, false, true);
assert(s);
goto fail;
service_enter_dead(s, true, false);
goto fail;
fail:
service_enter_dead(s, false, false);
assert(s);
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
service_enter_running(s, true);
fail:
s->reload_failure = true;
service_enter_running(s, true);
assert(s);
if (!success)
s->failure = true;
if ((r = service_spawn(s,
s->control_command,
&s->control_pid)) < 0)
goto fail;
fail:
service_enter_dead(s, false, true);
s->reload_failure = true;
service_enter_running(s, true);
service_enter_stop(s, false);
assert(s);
if (!success)
s->failure = true;
if ((r = service_spawn(s,
s->main_command,
&pid)) < 0)
goto fail;
fail:
service_enter_stop(s, false);
assert(s);
return -EAGAIN;
return -ECANCELED;
s->failure = false;
s->main_pid_known = false;
s->forbid_restart = false;
assert(s);
s->forbid_restart = true;
service_enter_stop(s, true);
assert(s);
assert(s);
assert(u);
assert(f);
if (s->control_pid > 0)
if (s->status_text)
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;
return copy;
unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) s->main_exec_status.pid);
assert(u);
s->main_pid_known = b;
s->status_text = t;
int fd;
if (s->socket_fd >= 0)
assert(u);
assert(u);
assert(s);
if (cgroup_good(s) > 0 ||
main_pid_good(s) > 0 ||
control_pid_good(s) > 0)
#ifdef HAVE_SYSV_COMPAT
if (s->sysv_path)
assert(s);
return !s->got_socket_fd;
bool success;
assert(s);
s->main_pid = 0;
if (s->main_command) {
success = true;
if (s->main_command &&
success) {
log_debug("%s running next main command for state %s", u->meta.id, service_state_to_string(s->state));
switch (s->state) {
case SERVICE_START_POST:
case SERVICE_RELOAD:
case SERVICE_STOP:
case SERVICE_START:
if (success)
case SERVICE_RUNNING:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
if (!control_pid_good(s))
s->control_pid = 0;
if (s->control_command) {
success = true;
if (s->control_command &&
success) {
log_debug("%s running next control command for state %s", u->meta.id, service_state_to_string(s->state));
switch (s->state) {
case SERVICE_START_PRE:
if (success)
case SERVICE_START:
if (success) {
case SERVICE_START_POST:
if ((r = service_load_pid_file(s)) < 0)
service_enter_running(s, true);
case SERVICE_RELOAD:
if (success) {
service_enter_running(s, true);
case SERVICE_STOP:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
if (main_pid_good(s) <= 0)
case SERVICE_STOP_POST:
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
assert(s);
switch (s->state) {
case SERVICE_START_PRE:
case SERVICE_START:
case SERVICE_START_POST:
service_enter_stop(s, false);
case SERVICE_RELOAD:
s->reload_failure = true;
service_enter_running(s, true);
case SERVICE_STOP:
case SERVICE_STOP_SIGTERM:
service_enter_stop_post(s, false);
case SERVICE_STOP_SIGKILL:
service_enter_stop_post(s, false);
case SERVICE_STOP_POST:
case SERVICE_FINAL_SIGTERM:
service_enter_dead(s, false, true);
case SERVICE_FINAL_SIGKILL:
service_enter_dead(s, false, true);
case SERVICE_AUTO_RESTART:
assert(u);
switch (s->state) {
case SERVICE_RUNNING:
service_enter_running(s, true);
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
service_enter_stop_post(s, true);
case SERVICE_FINAL_SIGTERM:
case SERVICE_FINAL_SIGKILL:
service_enter_dead(s, true, true);
assert(u);
s->status_text = t;
#ifdef HAVE_SYSV_COMPAT
Iterator j;
assert(m);
r = -ENOMEM;
goto finish;
closedir(d);
r = -ENOMEM;
goto finish;
r = -ENOMEM;
goto finish;
goto finish;
goto finish;
goto finish;
goto finish;
if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0)
goto finish;
if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
goto finish;
closedir(d);
static void service_bus_name_owner_change(
Unit *u,
const char *name,
const char *old_owner,
const char *new_owner) {
assert(s);
log_debug("%s's D-Bus name %s changed owner from %s to %s", u->meta.id, name, old_owner, new_owner);
else if (old_owner)
service_enter_running(s, true);
} else if (new_owner &&
s->main_pid <= 0 &&
static void service_bus_query_pid_done(
Unit *u,
const char *name,
assert(s);
if (s->main_pid <= 0 &&
assert(s);
return -EINVAL;
if (s->socket_fd >= 0)
return -EBUSY;
return -EAGAIN;
s->got_socket_fd = true;
assert(s);
s->failure = false;
assert(s);
return -EINVAL;
return -ENOENT;
if (s->control_pid > 0)
r = -errno;
if (s->main_pid > 0)
r = -errno;
return -ENOMEM;
if (s->control_pid > 0)
goto finish;
if (s->main_pid > 0)
goto finish;
if (pid_set)
.show_status = true,
#ifdef HAVE_SYSV_COMPAT