--- insserv.c +++ insserv.c 2010-06-10 15:18:32.218925119 +0000 @@ -389,8 +389,8 @@ static void reversereq(service_t *restri /* * Check required services for name */ -static boolean chkrequired(service_t *restrict serv) attribute((nonnull(1))); -static boolean chkrequired(service_t *restrict serv) +static boolean chkrequired(service_t *restrict serv, const boolean recursive) attribute((nonnull(1))); +static boolean chkrequired(service_t *restrict serv, const boolean recursive) { boolean ret = true; list_t * pos; @@ -409,12 +409,23 @@ static boolean chkrequired(service_t *re must = getorig(must); if ((must->attr.flags & (SERV_CMDLINE|SERV_ENABLED)) == 0) { - warn("Service %s has to be enabled to start service %s\n", - req->serv->name, serv->name); + if (recursive) { + must->attr.flags |= SERV_ENFORCE; + continue; /* Enabled this later even if not on command line */ + } + if ((must->attr.flags & SERV_WARNED) == 0) { + warn("FATAL: service %s has to be enabled to use service %s\n", + req->serv->name, serv->name); + must->attr.flags |= SERV_WARNED; + } ret = false; } } #if 0 + /* + * Once we may use REQ_MUST for X-Start-Before and/or + * X-Stop-After we may enable this, see reversereq() + */ if (serv->attr.flags & (SERV_CMDLINE|SERV_ENABLED)) goto out; np_list_for_each(pos, &serv->sort.rev) { @@ -425,9 +436,8 @@ static boolean chkrequired(service_t *re continue; must = rev->serv; must = getorig(must); - if (must->attr.flags & (SERV_CMDLINE|SERV_ENABLED)) { - warn("Service %s has to be enabled to stop service %s\n", + warn("FATAL: service %s has to be enabled to use service %s\n", serv->name, rev->serv->name); ret = false; } @@ -476,7 +486,7 @@ static boolean chkdependencies(service_t if ((cur->attr.flags & SERV_CMDLINE) && (flags & SERV_CMDLINE)) continue; - warn("Service %s has to be enabled to start service %s\n", + warn("FATAL: service %s has to be enabled to use service %s\n", name, cur->name); ret = false; } @@ -1378,10 +1388,10 @@ static uchar scan_lsb_headers(const int description = empty; } - if (!interactive && regexecutor(®.interact, COMMON_ARGS) == true) { - if (val->rm_so < val->rm_eo) { - *(pbuf+val->rm_eo) = '\0'; - interactive = xstrdup(pbuf+val->rm_so); + if (!interactive && regexecutor(®.interact, COMMON_SHD_ARGS) == true) { + if (shl->rm_so < shl->rm_eo) { + *(pbuf+shl->rm_eo) = '\0'; + interactive = xstrdup(pbuf+shl->rm_so); } else interactive = empty; } @@ -1416,7 +1426,7 @@ static uchar scan_lsb_headers(const int char *name = basename(path); if (*name == 'S' || *name == 'K') name += 3; - warn("Script %s is broken: missing end of LSB comment.\n", name); + warn("%sscript %s is broken: missing end of LSB comment.\n", ignore ? "" : "FATAL: ", name); if (!ignore) error("exiting now!\n"); } @@ -1432,7 +1442,7 @@ static uchar scan_lsb_headers(const int char *name = basename(path); if (*name == 'S' || *name == 'K') name += 3; - warn("Script %s is broken: incomplete LSB comment.\n", name); + warn("script %s is broken: incomplete LSB comment.\n", name); if (!provides) warn("missing `Provides:' entry: please add.\n"); if (provides == empty) @@ -2338,17 +2348,18 @@ out: static struct option long_options[] = { - {"verbose", 0, (int*)0, 'v'}, - {"config", 1, (int*)0, 'c'}, - {"dryrun", 0, (int*)0, 'n'}, - {"default", 0, (int*)0, 'd'}, - {"remove", 0, (int*)0, 'r'}, - {"force", 0, (int*)0, 'f'}, - {"path", 1, (int*)0, 'p'}, - {"override",1, (int*)0, 'o'}, - {"upstart-job",1, (int*)0, 'u'}, - {"help", 0, (int*)0, 'h'}, - { 0, 0, (int*)0, 0 }, + {"verbose", 0, (int*)0, 'v'}, + {"config", 1, (int*)0, 'c'}, + {"dryrun", 0, (int*)0, 'n'}, + {"default", 0, (int*)0, 'd'}, + {"remove", 0, (int*)0, 'r'}, + {"force", 0, (int*)0, 'f'}, + {"path", 1, (int*)0, 'p'}, + {"override", 1, (int*)0, 'o'}, + {"upstart-job", 1, (int*)0, 'u'}, + {"recursive", 0, (int*)0, 'e'}, + {"help", 0, (int*)0, 'h'}, + { 0, 0, (int*)0, 0 }, }; static void help(const char *restrict const name) attribute((nonnull(1))); @@ -2364,6 +2375,8 @@ static void help(const char *restrict co printf(" -o , --override Path to replace " OVERRIDEDIR ".\n"); printf(" -c , --config Path to config file.\n"); printf(" -n, --dryrun Do not change the system, only talk about it.\n"); + printf(" -u , --upstart-job Path to replace existing upstart job path.\n"); + printf(" -e, --recursive Expand and enable all required services.\n"); printf(" -d, --default Use default runlevels a defined in the scripts\n"); } @@ -2386,6 +2399,8 @@ int main (int argc, char *argv[]) boolean defaults = false; boolean ignore = false; boolean loadarg = false; + boolean recursive = false; + boolean waserr = false; myname = basename(*argv); @@ -2400,7 +2415,7 @@ int main (int argc, char *argv[]) for (c = 0; c < argc; c++) argr[c] = (char*)0; - while ((c = getopt_long(argc, argv, "c:dfrhvno:p:u:", long_options, (int *)0)) != -1) { + while ((c = getopt_long(argc, argv, "c:dfrhvno:p:u:e", long_options, (int *)0)) != -1) { size_t l; switch (c) { case 'c': @@ -2445,6 +2460,9 @@ int main (int argc, char *argv[]) goto err; upstartjob_path = optarg; break; + case 'e': + recursive = true; + break; case '?': err: error("For help use: %s -h\n", myname); @@ -3000,8 +3018,10 @@ int main (int argc, char *argv[]) if (!del || (del && !isarg)) warn("script %s: service %s already provided!\n", d->d_name, token); - if (!del && !ignore && isarg) - error("exiting now!\n"); + if (!del && !ignore && isarg) { + waserr = true; + continue; + } if (!del || (del && !ignore && !isarg)) continue; @@ -3064,9 +3084,9 @@ int main (int argc, char *argv[]) if (del) ok = chkdependencies(service); else - ok = chkrequired(service); + ok = chkrequired(service, recursive); if (!ok && !ignore) - error("exiting now!\n"); + waserr = true; } if (script_inf.default_start && script_inf.default_start != empty) { @@ -3357,6 +3377,42 @@ int main (int argc, char *argv[]) active_script(); /* + * Check for recursive mode the existence of the required services + */ + if (recursive && !del && !ignore) { + c = argc; + while (c--) { + service_t * cur; + list_t * ptr; + cur = findservice(argv[c]); + cur = getorig(cur); + if (list_empty(&cur->sort.req)) + continue; + np_list_for_each(ptr, &cur->sort.req) { + req_t *req = getreq(ptr); + service_t * must; + + if ((req->flags & REQ_MUST) == 0) + continue; + must = req->serv; + must = getorig(must); + + if (must->attr.flags & SERV_ENABLED) + continue; + + if ((must->attr.flags & (SERV_ENFORCE|SERV_KNOWN)) == SERV_ENFORCE) { + warn("FATAL: service %s has to exists for service %s\n", + req->serv->name, cur->name); + waserr = true; + } + } + } + } + + if (waserr) + error("exiting now!\n"); + + /* * Sorry but we support only [KS][0-9][0-9] */ if (maxstart > MAX_DEEP || maxstop > MAX_DEEP) @@ -3435,13 +3491,16 @@ int main (int argc, char *argv[]) script = (char*)0; while ((serv = listscripts(&script, 'X', lvl))) { - const boolean this = chkfor(script, argv, argc); + boolean this = chkfor(script, argv, argc); boolean found, slink; char * clink; if (*script == '$') /* Do not link in virtual dependencies */ continue; + if ((serv->attr.flags & (SERV_ENFORCE|SERV_ENABLED)) == SERV_ENFORCE) + this = true; + slink = false; if ((serv->start->lvl & lvl) == 0) goto stop; @@ -3616,7 +3675,7 @@ int main (int argc, char *argv[]) script = (char*)0; while ((serv = listscripts(&script, 'X', seek))) { - const boolean this = chkfor(script, argv, argc); + boolean this = chkfor(script, argv, argc); boolean found; char * clink; char mode; @@ -3624,6 +3683,9 @@ int main (int argc, char *argv[]) if (*script == '$') /* Do not link in virtual dependencies */ continue; + if ((serv->attr.flags & (SERV_ENFORCE|SERV_ENABLED)) == SERV_ENFORCE) + this = true; + sprintf(olink, "../init.d/%s", script); if (serv->stopp->lvl & lvl) { # ifndef USE_KILL_IN_BOOT --- listing.c +++ listing.c 2010-06-15 12:20:38.314924987 +0000 @@ -534,13 +534,11 @@ out: * Sort linked list of provides into start or stop order * during this set new start or stop order of the serives. */ -#undef SORT_REQUESTS +#define getdep(req) ((dir_t*)(req)->serv->dir) void lsort(const char type) { list_t sort = { &sort, &sort }; -#ifdef SORT_REQUESTS - list_t * this; -#endif /* SORT_REQUESTS */ + list_t * ptr, * safe, * this; int order; switch (type) { @@ -554,24 +552,51 @@ void lsort(const char type) } } join(&sort, d_start); -#ifdef SORT_REQUESTS list_for_each(this, s_start) { service_t * serv = getservice(this); if (serv->attr.flags & SERV_DUPLET) continue; initial(&sort); - for (order = 0; order <= maxstop; order++) { - list_t * ptr, * safe; + for (order = maxstop; order >= 0; order--) { list_for_each_safe(ptr, safe, &serv->sort.rev) { req_t * rev = getreq(ptr); - dir_t * dir = (dir_t*)rev->serv->dir; - if (dir->stopp.deep == order) - move_tail(ptr, &sort); + dir_t * dir = getdep(rev); + if (dir->stopp.deep == order) { + service_t *const orig = getorig(rev->serv); + list_t * chk; + boolean found = false; + + list_for_each_prev(chk, &sort) { /* check if service was already resorted */ + req_t * this = getreq(chk); + if (getdep(this)->stopp.deep != order) + break; /* added on tail always with same order */ + if (getdep(this) == orig->dir) { + found = true; + } + } + + if (!found) { + if (rev->serv != orig) { /* replace alias with its original */ + req_t *restrict this; + if (posix_memalign((void*)&this, sizeof(void*), alignof(req_t)) != 0) + error("%s", strerror(errno)); + memset(this, 0, alignof(req_t)); + this->flags = rev->flags; + this->serv = orig; + replace(ptr, &this->list); + ptr = &this->list; + free(rev); + } + move_tail(ptr, &sort); + } else { /* already included */ + delete(ptr); + free(rev); + } + } } } join(&sort, &serv->sort.rev); } -#endif /* SORT_REQUESTS */ break; default: for (order = 0; order <= maxstart; order++) { @@ -583,24 +608,52 @@ void lsort(const char type) } } join(&sort, d_start); -#ifdef SORT_REQUESTS list_for_each(this, s_start) { service_t * serv = getservice(this); if (serv->attr.flags & SERV_DUPLET) continue; initial(&sort); - for (order = 0; order <= maxstart; order++) { - list_t * ptr, * safe; + for (order = maxstart; order >= 0; order--) { list_for_each_safe(ptr, safe, &serv->sort.req) { req_t * req = getreq(ptr); - dir_t * dir = (dir_t*)req->serv->dir; - if (dir->start.deep == order) - move_tail(ptr, &sort); + dir_t * dir = getdep(req); + if (dir->start.deep == order) { + service_t * orig = getorig(req->serv); + list_t * chk; + boolean found = false; + + list_for_each_prev(chk, &sort) { /* check if service was already resorted */ + req_t * this = getreq(chk); + if (getdep(this)->start.deep != order) + break; /* added on tail always with same order */ + if (getdep(this) == orig->dir) { + found = true; + break; + } + } + + if (!found) { + if (req->serv != orig) { /* replace alias with its original */ + req_t *restrict this; + if (posix_memalign((void*)&this, sizeof(void*), alignof(req_t)) != 0) + error("%s", strerror(errno)); + memset(this, 0, alignof(req_t)); + this->flags = req->flags; + this->serv = orig; + replace(ptr, &this->list); + ptr = &this->list; + free(req); + } + move_tail(ptr, &sort); + } else { /* already included */ + delete(ptr); + free(req); + } + } } } join(&sort, &serv->sort.req); } -#endif /* SORT_REQUESTS */ break; } --- listing.h +++ listing.h 2010-06-15 10:52:04.446925086 +0000 @@ -158,6 +158,18 @@ static inline void delete(list_t *restri initial(entry); } +/* + * Replace an entry by a new one. + */ +static inline void replace(list_t *restrict old, list_t *restrict new) attribute((always_inline,nonnull(1,2))); +static inline void replace(list_t *restrict old, list_t *restrict new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + static inline void join(list_t *restrict list, list_t *restrict head) attribute((always_inline,nonnull(1,2))); static inline void join(list_t *restrict list, list_t *restrict head) { @@ -181,6 +193,24 @@ static inline boolean list_empty(list_t return head->next == head; } +static inline void move_head(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2))); +static inline void move_head(list_t *restrict entry, list_t *restrict head) +{ + list_t * prev = entry->prev; + list_t * next = entry->next; + + next->prev = prev; /* remove enty from old list */ + prev->next = next; + + prev = head; + next = head->next; + + next->prev = entry; /* and add it at head of new list */ + entry->next = next; + entry->prev = prev; + prev->next = entry; +} + static inline void move_tail(list_t *restrict entry, list_t *restrict head) attribute((always_inline,nonnull(1,2))); static inline void move_tail(list_t *restrict entry, list_t *restrict head) { @@ -379,6 +409,8 @@ static inline char * xstrdup(const char #define SERV_NOSTOP 0x0100 #define SERV_CMDLINE 0x0200 #define SERV_FIRST 0x0400 +#define SERV_ENFORCE 0x0800 +#define SERV_WARNED 0x1000 /* * Bits of the runlevels