if (r == 0)
continue;
- r = unit_add_name(u, m);
+ if (unit_name_to_type(m) == UNIT_SERVICE)
+ r = unit_add_name(u, m);
+ else {
+ if ((r = unit_add_dependency_by_name_inverse(u, UNIT_REQUIRES, m)) >= 0)
+ r = unit_add_dependency_by_name(u, UNIT_BEFORE, m);
+ }
+
free(m);
if (r < 0)
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
+ if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_SYSINIT_SERVICE)) < 0 ||
+ (r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_SYSINIT_SERVICE)) < 0)
+ goto finish;
+
r = 1;
finish:
r = service_load_sysv_path(s, path);
free(path);
- if (r >= 0)
+ if (r != 0)
return r;
}
return r;
}
- /* Load a classic init script as a fallback, if we couldn*t find anything */
+ /* Load a classic init script as a fallback, if we couldn't find anything */
if (r == 0)
if ((r = service_load_sysv(s)) <= 0) {
service_done(u);
return r;
}
+ /* Add default cgroup */
+ if ((r = unit_add_default_cgroup(u)) < 0) {
+ service_done(u);
+ return r;
+ }
+
return 0;
}
fprintf(f,
"%sService State: %s\n"
"%sPermissionsStartOnly: %s\n"
- "%sRootDirectoryStartOnly: %s\n",
+ "%sRootDirectoryStartOnly: %s\n"
+ "%sValidNoProcess: %s\n"
+ "%sType: %s\n",
prefix, service_state_to_string(s->state),
prefix, yes_no(s->permissions_start_only),
- prefix, yes_no(s->root_directory_start_only));
+ prefix, yes_no(s->root_directory_start_only),
+ prefix, yes_no(s->valid_no_process),
+ prefix, service_type_to_string(s->type));
if (s->pid_file)
fprintf(f,
fds, n_fds,
apply_permissions,
apply_chroot,
+ UNIT(s)->meta.cgroup_bondings,
&pid)) < 0)
goto fail;
return s->main_pid > 0;
/* We don't know the pid */
- return -1;
+ return -EAGAIN;
}
static bool control_pid_good(Service *s) {
return s->control_pid > 0;
}
+static int cgroup_good(Service *s) {
+ assert(s);
+
+ if (s->valid_no_process)
+ return -EAGAIN;
+
+ return cgroup_bonding_is_empty_list(UNIT(s)->meta.cgroup_bondings);
+}
+
static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
Service *s = SERVICE(u);
bool success;
* don't care about failing commands. */
if (s->control_command->command_next &&
- (success || (s->state == SERVICE_EXEC_STOP || s->state == SERVICE_EXEC_STOP_POST)))
+ (success || (s->state == SERVICE_STOP || s->state == SERVICE_STOP_POST)))
/* There is another command to *
* execute, so let's do that. */
case SERVICE_RELOAD:
if (success) {
- if (main_pid_good(s) != 0)
+ if (main_pid_good(s) != 0 && cgroup_good(s) != 0)
service_set_state(s, SERVICE_RUNNING);
else
service_enter_stop(s, true);
}
}
+static void service_cgroup_notify_event(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(u);
+
+ log_debug("%s: cgroup is empty", unit_id(u));
+
+ switch (s->state) {
+
+ /* Waiting for SIGCHLD is usually more interesting,
+ * because it includes return codes/signals. Which is
+ * why we ignore the cgroup events for most cases,
+ * except when we don't know pid which to expect the
+ * SIGCHLD for. */
+
+ case SERVICE_RUNNING:
+
+ if (!s->valid_no_process && main_pid_good(s) <= 0)
+ service_enter_stop(s, true);
+
+ break;
+
+ default:
+ ;
+ }
+}
+
static int service_enumerate(Manager *m) {
static const char * const rcnd[] = {
if ((r = manager_load_unit(m, name, &service)) < 0)
goto finish;
- /* Don't allow that non-SysV services
- * are started via rcN.d/ links. */
- if (!SERVICE(service)->sysv_path)
- continue;
-
if ((r = manager_load_unit(m, rcnd[i+1], &runlevel)) < 0)
goto finish;
.sigchld_event = service_sigchld_event,
.timer_event = service_timer_event,
+ .cgroup_notify_empty = service_cgroup_notify_event,
+
.enumerate = service_enumerate
};