{ "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
#endif
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_FRUGALWARE) || defined(TARGET_ANGSTROM)
+#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
/* Debian style rcS.d */
{ "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
#endif
/* LSB defined facilities */
"local_fs", SPECIAL_LOCAL_FS_TARGET,
#ifndef TARGET_MANDRIVA
- /* Due to unfortunate name selection in Mandriva,
- * $network is provided by network-up which is ordered
- * after network which actually starts interfaces.
- * To break the loop, just ignore it */
+ /* Due to unfortunate name selection in Mandriva,
+ * $network is provided by network-up which is ordered
+ * after network which actually starts interfaces.
+ * To break the loop, just ignore it */
"network", SPECIAL_NETWORK_TARGET,
#endif
"named", SPECIAL_NSS_LOOKUP_TARGET,
/* For each pair of services where at least one lacks a LSB
* header, we use the start priority value to order things. */
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *t;
UnitDependency d;
bool special_s, special_t;
LSB_DESCRIPTION
} state = NORMAL;
char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
+ struct stat st;
assert(s);
assert(path);
goto finish;
}
+ zero(st);
+ if (fstat(fileno(f), &st) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
free(s->sysv_path);
if (!(s->sysv_path = strdup(path))) {
r = -ENOMEM;
goto finish;
}
+ s->sysv_mtime = timespec_load(&st.st_mtim);
+
+ if (null_or_empty(&st)) {
+ u->meta.load_state = UNIT_MASKED;
+ r = 0;
+ goto finish;
+ }
+
while (!feof(f)) {
char l[LINE_MAX], *t;
char *d = NULL;
if (chkconfig_description)
- asprintf(&d, "%s %s", chkconfig_description, j);
+ d = join(chkconfig_description, " ", j, NULL);
else
d = strdup(j);
free(short_description);
short_description = d;
- } else if (startswith_no_case(t, "X-Interactive:")) {
- int b;
-
- if ((b = parse_boolean(strstrip(t+14))) < 0) {
- log_warning("[%s:%u] Couldn't parse interactive flag. Ignoring.", path, line);
- continue;
- }
-
- if (b)
- s->exec_context.std_input = EXEC_INPUT_TTY;
- else
- s->exec_context.std_input = EXEC_INPUT_NULL;
-
} else if (state == LSB_DESCRIPTION) {
if (startswith(l, "#\t") || startswith(l, "# ")) {
char *d = NULL;
if (long_description)
- asprintf(&d, "%s %s", long_description, t);
+ d = join(long_description, " ", t, NULL);
else
d = strdup(j);
/* Special setting for all SysV services */
s->type = SERVICE_FORKING;
- s->remain_after_exit = true;
+ s->remain_after_exit = !s->pid_file;
s->restart = SERVICE_RESTART_NO;
s->exec_context.std_output =
(s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY)
char *path;
int r;
- if (asprintf(&path, "%s/%s", *p, name) < 0)
+ path = join(*p, "/", name, NULL);
+ if (!path)
return -ENOMEM;
assert(endswith(path, ".service"));
if (r >= 0 && s->meta.load_state == UNIT_STUB) {
/* Try SUSE style boot.* init scripts */
- if (asprintf(&path, "%s/boot.%s", *p, name) < 0)
+ path = join(*p, "/boot.", name, NULL);
+ if (!path)
return -ENOMEM;
/* Drop .service suffix */
if (r >= 0 && s->meta.load_state == UNIT_STUB) {
/* Try Frugalware style rc.* init scripts */
- if (asprintf(&path, "%s/rc.%s", *p, name) < 0)
+ path = join(*p, "/rc.", name, NULL);
+ if (!path)
return -ENOMEM;
/* Drop .service suffix */
/* For each pair of services where both have an fsck priority
* we order things based on it. */
- LIST_FOREACH(units_per_type, other, s->meta.manager->units_per_type[UNIT_SERVICE]) {
+ LIST_FOREACH(units_by_type, other, s->meta.manager->units_by_type[UNIT_SERVICE]) {
Service *t;
UnitDependency d;
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
- if (state == SERVICE_EXITED && s->meta.manager->n_deserializing <= 0)
+ if (state == SERVICE_EXITED && s->meta.manager->n_reloading <= 0)
cgroup_bonding_trim_list(s->meta.cgroup_bondings, true);
if (old_state != state)
apply_tty_stdin,
s->meta.manager->confirm_spawn,
s->meta.cgroup_bondings,
+ s->meta.cgroup_attributes,
&pid);
if (r < 0)
}
#ifdef HAVE_SYSV_COMPAT
+
+#ifdef TARGET_SUSE
+static void sysv_facility_in_insserv_conf(Manager *mgr) {
+ FILE *f=NULL;
+ int r;
+
+ if (!(f = fopen("/etc/insserv.conf", "re"))) {
+ r = errno == ENOENT ? 0 : -errno;
+ goto finish;
+ }
+
+ while (!feof(f)) {
+ char l[LINE_MAX], *t;
+ char **parsed = NULL;
+
+ if (!fgets(l, sizeof(l), f)) {
+ if (feof(f))
+ break;
+
+ r = -errno;
+ log_error("Failed to read configuration file '/etc/insserv.conf': %s", strerror(-r));
+ goto finish;
+ }
+
+ t = strstrip(l);
+ if (*t != '$' && *t != '<')
+ continue;
+
+ parsed = strv_split(t,WHITESPACE);
+ /* we ignore <interactive>, not used, equivalent to X-Interactive */
+ if (parsed && !startswith_no_case (parsed[0], "<interactive>")) {
+ char *facility;
+ Unit *u;
+ if (sysv_translate_facility(parsed[0], NULL, &facility) < 0)
+ continue;
+ if ((u = manager_get_unit(mgr, facility)) && (u->meta.type == UNIT_TARGET)) {
+ UnitDependency e;
+ char *dep = NULL, *name, **j;
+
+ STRV_FOREACH (j, parsed+1) {
+ if (*j[0]=='+') {
+ e = UNIT_WANTS;
+ name = *j+1;
+ }
+ else {
+ e = UNIT_REQUIRES;
+ name = *j;
+ }
+ if (sysv_translate_facility(name, NULL, &dep) < 0)
+ continue;
+
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, e, dep, NULL, true);
+ free(dep);
+ }
+ }
+ free(facility);
+ }
+ strv_free(parsed);
+ }
+finish:
+ if (f)
+ fclose(f);
+
+}
+#endif
+
static int service_enumerate(Manager *m) {
char **p;
unsigned i;
assert(m);
+ if (m->running_as != MANAGER_SYSTEM)
+ return 0;
+
zero(runlevel_services);
STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)
struct dirent *de;
free(path);
- path = NULL;
- if (asprintf(&path, "%s/%s", *p, rcnd_table[i].path) < 0) {
+ path = join(*p, "/", rcnd_table[i].path, NULL);
+ if (!path) {
r = -ENOMEM;
goto finish;
}
continue;
free(fpath);
- fpath = NULL;
- if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i].path, de->d_name) < 0) {
+ fpath = join(path, "/", de->d_name, NULL);
+ if (!path) {
r = -ENOMEM;
goto finish;
}
r = 0;
+#ifdef TARGET_SUSE
+ sysv_facility_in_insserv_conf (m);
+#endif
+
finish:
free(path);
free(fpath);
s->failure = false;
}
+static bool service_need_daemon_reload(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+#ifdef HAVE_SYSV_COMPAT
+ if (s->sysv_path) {
+ struct stat st;
+
+ zero(st);
+ if (stat(s->sysv_path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
+
+ if (s->sysv_mtime > 0 &&
+ timespec_load(&st.st_mtim) != s->sysv_mtime)
+ return true;
+ }
+#endif
+
+ return false;
+}
+
static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *error) {
Service *s = SERVICE(u);
int r = 0;
if (s->main_pid <= 0 && who == KILL_MAIN) {
dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
- return -EINVAL;
+ return -ESRCH;
}
if (s->control_pid <= 0 && who == KILL_CONTROL) {
dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ENOENT;
+ return -ESRCH;
}
- if (s->control_pid > 0)
- if (kill(s->control_pid, signo) < 0)
- r = -errno;
+ if (who == KILL_CONTROL || who == KILL_ALL)
+ if (s->control_pid > 0)
+ if (kill(s->control_pid, signo) < 0)
+ r = -errno;
- if (s->main_pid > 0)
- if (kill(s->main_pid, signo) < 0)
- r = -errno;
+ if (who == KILL_MAIN || who == KILL_ALL)
+ if (s->main_pid > 0)
+ if (kill(s->main_pid, signo) < 0)
+ r = -errno;
- if (mode == KILL_CONTROL_GROUP) {
+ if (who == KILL_ALL && mode == KILL_CONTROL_GROUP) {
int q;
if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func)))
}
if ((q = cgroup_bonding_kill_list(s->meta.cgroup_bondings, signo, false, pid_set)) < 0)
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
+ if (q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
}
const UnitVTable service_vtable = {
.suffix = ".service",
+ .sections =
+ "Unit\0"
+ "Service\0"
+ "Install\0",
.show_status = true,
.init = service_init,
.reset_failed = service_reset_failed,
+ .need_daemon_reload = service_need_daemon_reload,
+
.cgroup_notify_empty = service_cgroup_notify_event,
.notify_message = service_notify_message,