On Fri, May 07, 2010 at 05:41:58PM +0200, Petter Reinholdtsen wrote:
> [Werner Fink]
> > Please try out the attached patch
> 
> Thank you.  Kel proposed a very similar patch earlier today, which
> worked for me.  Sorry I have been to busy to pass it on before now.
> 
> Description: Fix regular expression match for X-Interactive keyword, it was
>  off-by-one match group and thus always returned 'X-'.
> From: Kel Modderman <k...@otaku42.de>
> ---
> --- a/insserv.c
> +++ b/insserv.c
> @@ -1378,10 +1378,10 @@ static uchar scan_lsb_headers(const int
>               description = empty;
>       }
>  
> -     if (!interactive    && regexecutor(&reg.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(&reg.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;
>       }

Hi Petter,

you may try out the attached patch as this not only includes the patch
above but also implements a new option `--recursive' to enable all
required services for the specified service.  Beside this a small bug
has been fixed. Now also alias provides of a script will be placed
within the makefiles .depend.*

        Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr
--- 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(&reg.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(&reg.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 <path>, --override <path> Path to replace " OVERRIDEDIR ".\n");
     printf("  -c <config>, --config <config>  Path to config file.\n");
     printf("  -n, --dryrun     Do not change the system, only talk about it.\n");
+    printf("  -u <path>, --upstart-job <path> 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]<name>
      */
     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

Reply via email to