#define NEWLINES "\n\r"
#define LINE_MAX 4096
-static const char * const rcnd_table[] = {
- "/rc0.d", SPECIAL_RUNLEVEL0_TARGET,
- "/rc1.d", SPECIAL_RUNLEVEL1_TARGET,
- "/rc2.d", SPECIAL_RUNLEVEL2_TARGET,
- "/rc3.d", SPECIAL_RUNLEVEL3_TARGET,
- "/rc4.d", SPECIAL_RUNLEVEL4_TARGET,
- "/rc5.d", SPECIAL_RUNLEVEL5_TARGET,
- "/rc6.d", SPECIAL_RUNLEVEL6_TARGET,
- "/boot.d", SPECIAL_BASIC_TARGET
+typedef enum RunlevelType {
+ RUNLEVEL_UP,
+ RUNLEVEL_DOWN,
+ RUNLEVEL_BASIC
+} RunlevelType;
+
+static const struct {
+ const char *path;
+ const char *target;
+ const RunlevelType type;
+} rcnd_table[] = {
+ /* Standard SysV runlevels */
+ { "rc0.d", SPECIAL_RUNLEVEL0_TARGET, RUNLEVEL_DOWN },
+ { "rc1.d", SPECIAL_RUNLEVEL1_TARGET, RUNLEVEL_UP },
+ { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
+ { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
+ { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
+ { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
+ { "rc6.d", SPECIAL_RUNLEVEL6_TARGET, RUNLEVEL_DOWN },
+
+ /* SuSE style boot.d */
+ { "boot.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
+
+ /* Debian style rcS.d */
+ { "rcS.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
};
+#define RUNLEVELS_UP "12345"
+/* #define RUNLEVELS_DOWN "06" */
+/* #define RUNLEVELS_BOOT "bBsS" */
+
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
[SERVICE_START_PRE] = UNIT_ACTIVATING,
Unit *u;
unsigned line = 0;
int r;
- bool normal_service;
enum {
NORMAL,
DESCRIPTION,
continue;
}
+ /* A start priority gathered from the
+ * symlink farms is preferred over the
+ * data from the LSB header. */
if (start_priority < 0 || start_priority > 99)
log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
else if (s->sysv_start_priority < 0)
}
}
- /* If init scripts have no LSB header, then we enforce the
- * ordering via the chkconfig priorities. We try to determine
- * a priority for *all* init scripts here, since they are
- * needed as soon as at least one non-LSB script is used. */
-
- if (s->sysv_start_priority < 0)
- log_warning("%s has neither a chkconfig header nor a directory link, cannot order unit!", u->meta.id);
-
if ((r = sysv_exec_commands(s)) < 0)
goto finish;
- normal_service = !s->sysv_runlevels || chars_intersect("12345", s->sysv_runlevels);
-
- if (normal_service) {
+ if (!s->sysv_runlevels || chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
/* If there a runlevels configured for this service
* but none of the standard ones, then we assume this
* is some special kind of service (which might be
if ((r = unit_add_dependency_by_name(u, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0 ||
(r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
goto finish;
- }
+
+ } else
+ /* Don't timeout special services during boot (like fsck) */
+ s->timeout_usec = 0;
/* Special setting for all SysV services */
s->valid_no_process = true;
s->kill_mode = KILL_PROCESS_GROUP;
- /* Don't timeout special services during boot (like fsck) */
- if (s->sysv_runlevels && !normal_service)
- s->timeout_usec = 0;
-
u->meta.load_state = UNIT_LOADED;
r = 0;
path[strlen(path)-8] = 0;
r = service_load_sysv_path(s, path);
+
+ if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+ /* Try Debian style .sh source'able init scripts */
+ strcat(path, ".sh");
+ r = service_load_sysv_path(s, path);
+ }
+
free(path);
+ if (r >= 0 && UNIT(s)->meta.load_state == UNIT_STUB) {
+ /* Try Suse style boot.xxxx init scripts */
+
+ if (asprintf(&path, "%s/boot.%s", *p, name) < 0)
+ return -ENOMEM;
+
+ path[strlen(path)-8] = 0;
+ r = service_load_sysv_path(s, path);
+ free(path);
+ }
+
if (r < 0)
return r;
argv,
&s->exec_context,
fds, n_fds,
+ s->meta.manager->environment,
apply_permissions,
apply_chroot,
UNIT(s)->meta.manager->confirm_spawn,
assert(m);
STRV_FOREACH(p, m->sysvrcnd_path)
- for (i = 0; i < ELEMENTSOF(rcnd_table); i += 2) {
+ for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
struct dirent *de;
free(path);
path = NULL;
- if (asprintf(&path, "%s/%s", *p, rcnd_table[i]) < 0) {
+ if (asprintf(&path, "%s/%s", *p, rcnd_table[i].path) < 0) {
r = -ENOMEM;
goto finish;
}
free(fpath);
fpath = NULL;
- if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i], de->d_name) < 0) {
+ if (asprintf(&fpath, "%s/%s/%s", *p, rcnd_table[i].path, de->d_name) < 0) {
r = -ENOMEM;
goto finish;
}
}
free(name);
- name = NULL;
- if (asprintf(&name, "%s.service", de->d_name+3) < 0) {
+ if (!(name = new(char, strlen(de->d_name) - 3 + 8 + 1))) {
r = -ENOMEM;
goto finish;
}
- if ((r = manager_load_unit_prepare(m, name, NULL, &service)) < 0)
- goto finish;
+ if (startswith(de->d_name+3, "boot."))
+ /* Drop SuSE-style boot. prefix */
+ strcpy(stpcpy(name, de->d_name + 3 + 5), ".service");
+ else if (endswith(de->d_name+3, ".sh"))
+ /* Drop Debian-style .sh suffix */
+ strcpy(stpcpy(name, de->d_name + 3) - 3, ".service");
+ else
+ /* Normal init scripts */
+ strcpy(stpcpy(name, de->d_name + 3), ".service");
+
+ if ((r = manager_load_unit_prepare(m, name, NULL, &service)) < 0) {
+ log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
+ continue;
+ }
- if (de->d_name[0] == 'S')
- SERVICE(service)->sysv_start_priority = a*10 + b;
+ if (de->d_name[0] == 'S' &&
+ (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_BASIC))
+ SERVICE(service)->sysv_start_priority =
+ MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
manager_dispatch_load_queue(m);
service = unit_follow_merge(service);
if (de->d_name[0] == 'S') {
Unit *runlevel_target;
- if ((r = manager_load_unit(m, rcnd_table[i+1], NULL, &runlevel_target)) < 0)
+ if ((r = manager_load_unit(m, rcnd_table[i].target, NULL, &runlevel_target)) < 0)
goto finish;
if ((r = unit_add_dependency(runlevel_target, UNIT_WANTS, service, true)) < 0)
if ((r = unit_add_dependency(service, UNIT_BEFORE, runlevel_target, true)) < 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))) {
-
+ } else if (de->d_name[0] == 'K' && rcnd_table[i].type == RUNLEVEL_DOWN) {
Unit *shutdown_target;
/* We honour K links only for
free(path);
free(fpath);
free(name);
- closedir(d);
+
+ if (d)
+ closedir(d);
return r;
}