X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=service.c;h=bf91561901f03d3fb8c23769049148962fdaeefa;hp=ec466181ee0cec35c8c84d5dfd1831ecd35a3238;hb=1b00a255225bd65bcc3f6257bd4b1e2089f231b4;hpb=db06e3b6a5254ec247de5bc1a1b6a8670c2f4b2b diff --git a/service.c b/service.c index ec466181e..bf9156190 100644 --- a/service.c +++ b/service.c @@ -37,17 +37,37 @@ #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, @@ -278,7 +298,6 @@ static int service_load_sysv_path(Service *s, const char *path) { Unit *u; unsigned line = 0; int r; - bool normal_service; enum { NORMAL, DESCRIPTION, @@ -355,6 +374,9 @@ static int service_load_sysv_path(Service *s, const char *path) { 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) @@ -569,20 +591,10 @@ static int service_load_sysv_path(Service *s, const char *path) { } } - /* 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 @@ -592,16 +604,15 @@ static int service_load_sysv_path(Service *s, const char *path) { 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; @@ -630,8 +641,26 @@ static int service_load_sysv_name(Service *s, const char *name) { 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; @@ -1177,6 +1206,7 @@ static int service_spawn( argv, &s->exec_context, fds, n_fds, + s->meta.manager->environment, apply_permissions, apply_chroot, UNIT(s)->meta.manager->confirm_spawn, @@ -1860,7 +1890,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { assert(s); assert(pid >= 0); - success = code == CLD_EXITED && status == 0; + success = is_clean_exit(code, status); s->failure = s->failure || !success; if (s->main_pid == pid) { @@ -2123,12 +2153,12 @@ static int service_enumerate(Manager *m) { 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; } @@ -2164,7 +2194,7 @@ static int service_enumerate(Manager *m) { 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; } @@ -2178,17 +2208,30 @@ static int service_enumerate(Manager *m) { } 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); @@ -2196,7 +2239,7 @@ static int service_enumerate(Manager *m) { 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) @@ -2205,10 +2248,7 @@ static int service_enumerate(Manager *m) { 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 @@ -2240,7 +2280,9 @@ finish: free(path); free(fpath); free(name); - closedir(d); + + if (d) + closedir(d); return r; }