+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:
+ service_enter_running(s, true);
+ break;
+
+ default:
+ ;
+ }
+}
+
+static int service_enumerate(Manager *m) {
+ char **p;
+ unsigned i;
+ DIR *d = NULL;
+ char *path = NULL, *fpath = NULL, *name = NULL;
+ int r;
+
+ assert(m);
+
+ STRV_FOREACH(p, m->sysvrcnd_path)
+ for (i = 0; i < ELEMENTSOF(rcnd_table); i += 2) {
+ struct dirent *de;
+
+ free(path);
+ path = NULL;
+ if (asprintf(&path, "%s/%s", *p, rcnd_table[i]) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (d)
+ closedir(d);
+
+ if (!(d = opendir(path))) {
+ if (errno != ENOENT)
+ log_warning("opendir() failed on %s: %s", path, strerror(errno));
+
+ continue;
+ }
+
+ while ((de = readdir(d))) {
+ Unit *runlevel, *service;
+
+ if (ignore_file(de->d_name))
+ continue;
+
+ if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
+ continue;
+
+ if (strlen(de->d_name) < 4)
+ continue;
+
+ free(fpath);
+ fpath = NULL;
+ if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i], de->d_name) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if (access(fpath, X_OK) < 0) {
+
+ if (errno != ENOENT)
+ log_warning("access() failed on %s: %s", fpath, strerror(errno));
+
+ continue;
+ }
+
+ free(name);
+ name = NULL;
+ if (asprintf(&name, "%s.service", de->d_name+3) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if ((r = manager_load_unit(m, name, &service)) < 0)
+ goto finish;
+
+ if ((r = manager_load_unit(m, rcnd_table[i+1], &runlevel)) < 0)
+ goto finish;
+
+ if (de->d_name[0] == 'S') {
+ if ((r = unit_add_dependency(runlevel, UNIT_WANTS, service)) < 0)
+ goto finish;
+
+ if ((r = unit_add_dependency(runlevel, UNIT_AFTER, service)) < 0)
+ goto finish;
+
+ } else if (de->d_name[0] == 'K' &&
+ (streq(rcnd_table[i+1], SPECIAL_RUNLEVEL0_TARGET) ||
+ streq(rcnd_table[i+1], SPECIAL_RUNLEVEL6_TARGET))) {
+
+ /* We honour K links only for
+ * halt/reboot. For the normal
+ * runlevels we assume the
+ * stop jobs will be
+ * implicitly added by the
+ * core logic. */
+
+ if ((r = unit_add_dependency(runlevel, UNIT_CONFLICTS, service)) < 0)
+ goto finish;
+
+ if ((r = unit_add_dependency(runlevel, UNIT_BEFORE, service)) < 0)
+ goto finish;
+ }
+ }
+ }
+
+ r = 0;
+
+finish:
+ free(path);
+ free(fpath);
+ free(name);
+ closedir(d);
+
+ return r;
+}
+
+static const char* const service_state_table[_SERVICE_STATE_MAX] = {
+ [SERVICE_DEAD] = "dead",
+ [SERVICE_START_PRE] = "start-pre",
+ [SERVICE_START] = "start",
+ [SERVICE_START_POST] = "start-post",
+ [SERVICE_RUNNING] = "running",
+ [SERVICE_EXITED] = "exited",
+ [SERVICE_RELOAD] = "reload",
+ [SERVICE_STOP] = "stop",
+ [SERVICE_STOP_SIGTERM] = "stop-sigterm",
+ [SERVICE_STOP_SIGKILL] = "stop-sigkill",
+ [SERVICE_STOP_POST] = "stop-post",
+ [SERVICE_FINAL_SIGTERM] = "final-sigterm",
+ [SERVICE_FINAL_SIGKILL] = "final-sigkill",
+ [SERVICE_MAINTAINANCE] = "maintainance",
+ [SERVICE_AUTO_RESTART] = "auto-restart",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
+
+static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
+ [SERVICE_ONCE] = "once",
+ [SERVICE_RESTART_ON_SUCCESS] = "restart-on-success",
+ [SERVICE_RESTART_ALWAYS] = "restart-always",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
+
+static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
+ [SERVICE_FORKING] = "forking",
+ [SERVICE_SIMPLE] = "simple",
+ [SERVICE_FINISH] = "finish"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
+
+static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
+ [SERVICE_EXEC_START_PRE] = "ExecStartPre",
+ [SERVICE_EXEC_START] = "ExecStart",
+ [SERVICE_EXEC_START_POST] = "ExecStartPost",
+ [SERVICE_EXEC_RELOAD] = "ExecReload",
+ [SERVICE_EXEC_STOP] = "ExecStop",
+ [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
+
+const UnitVTable service_vtable = {