[Initscripts-ng-commits] r1088 - in /trunk/src/insserv: CHANGES Makefile insserv.8.in insserv.c listing.c listing.h systemd.c systemd.h

pere at users.alioth.debian.org pere at users.alioth.debian.org
Sat Feb 8 21:29:44 UTC 2014


Author: pere
Date: Sat Feb  8 21:29:44 2014
New Revision: 1088

URL: http://svn.debian.org/wsvn/initscripts-ng/?sc=1&rev=1088
Log:
New upstream version 1.16.0.

Added:
    trunk/src/insserv/systemd.c
    trunk/src/insserv/systemd.h
Modified:
    trunk/src/insserv/CHANGES
    trunk/src/insserv/Makefile
    trunk/src/insserv/insserv.8.in
    trunk/src/insserv/insserv.c
    trunk/src/insserv/listing.c
    trunk/src/insserv/listing.h

Modified: trunk/src/insserv/CHANGES
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/CHANGES?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/CHANGES	(original)
+++ trunk/src/insserv/CHANGES	Sat Feb  8 21:29:44 2014
@@ -1,3 +1,94 @@
+-------------------------------------------------------------------
+Wed Nov 14 12:12:15 CET 2012 - werner at suse.de
+
+- Add systemd support
+  * Talk with systemd over dbus connection to get all services and
+    targets known by systemd
+  * Implement missing garbage collector for system facilities as
+    the systemd targets are used as system facilities
+  + Side efect is that we detect loops in the systemd units
+
+-------------------------------------------------------------------
+Fri Oct 26 11:14:05 UTC 2012 - werner at suse.de
+
+- Add showall patch from Debian developer Kel Modderman
+
+-------------------------------------------------------------------
+Mon Sep 24 14:05:44 UTC 2012 - werner at suse.de
+
+- Avoid warnings if there exsists LSB tags for a script in the
+  override locations (fate #314069) 
+
+-------------------------------------------------------------------
+Fri Nov 18 14:40:21 UTC 2011 - werner at suse.de
+
+- Do not enforce service reload in case of an other root files
+  system no in case of not having systemd running (bnc#728947)  
+
+-------------------------------------------------------------------
+Fri Aug 19 13:57:29 UTC 2011 - werner at suse.de
+
+- We should forward to systemctl when running under rpm (this is
+  supposed to be handled outside insserv) (from Frederic Crozat)
+- When insserv is called with full path of initscript
+  ("insserv /etc/init.d/acpid") , systemctl was called with a "null"
+  alternative root (from Frederic Crozat).
+ 
+-------------------------------------------------------------------
+Tue Aug  2 12:18:51 UTC 2011 - werner at suse.de
+
+- Enable insserv to support systemd services if shadowed by systemd
+
+-------------------------------------------------------------------
+Fri Feb 25 17:39:37 CET 2011 - werner at suse.de
+
+- Skip `FATAL' key word from messages currently nonfatal
+
+-------------------------------------------------------------------
+Thu Feb 10 12:49:14 CET 2011 - werner at suse.de
+
+- Linked lists: support prefetch of next pointer address for all
+  architectures
+
+-------------------------------------------------------------------
+Tue Nov 30 11:03:21 CET 2010 - werner at suse.de
+
+- Make temporary the new dependency checks nonfatal
+
+-------------------------------------------------------------------
+Fri Nov 26 15:50:35 CET 2010 - werner at suse.de
+
+- Warn if dependencies are not done in all runlevel
+- Ignore real boot scripts for runlevel services as those
+  are already enabled.
+
+-------------------------------------------------------------------
+Fri Jun 18 18:08:54 CEST 2010 - werner at suse.de
+
+- Remove redundant dependencies in the .depend.* makefiles
+
+-------------------------------------------------------------------
+Tue Jun 15 14:05:31 CEST 2010 - werner at suse.de
+
+- Do not forget the aliases in the makefiles
+
+-------------------------------------------------------------------
+Thu Jun 10 17:19:26 CEST 2010 - werner at suse.de
+
+- Sort dependency lists of the services that is the highest
+  dependencies first
+
+-------------------------------------------------------------------
+Fri May  7 17:15:02 CEST 2010 - werner at suse.de
+
+- Get the value instead the ``X-'' from interactive tag
+  this fix debian bug #580564
+
+-------------------------------------------------------------------
+Fri Apr 30 18:27:29 CEST 2010 - werner at suse.de
+
+- Add the option of recursive enabling all required services
+
 -------------------------------------------------------------------
 Wed Apr 28 15:29:23 CEST 2010 - werner at suse.de
 

Modified: trunk/src/insserv/Makefile
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/Makefile?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/Makefile	(original)
+++ trunk/src/insserv/Makefile	Sat Feb  8 21:29:44 2014
@@ -12,8 +12,9 @@
 DEBUG	 =
 ISSUSE	 =	-DSUSE
 DESTDIR	 =
-VERSION	 =	1.14.0
+VERSION	 =	1.16.0
 DATE	 =	$(shell date +'%d%b%y' | tr '[:lower:]' '[:upper:]')
+CFLDBUS	 =	$(shell pkg-config --cflags dbus-1)
 
 #
 # Architecture
@@ -38,6 +39,7 @@
 	LDFLAGS += -Wl,--as-needed
 	   LIBS += -lrpm
 endif
+	   LIBS += $(shell pkg-config --libs dbus-1)
 	     CC = gcc
 	     RM = rm -f
 	  MKDIR = mkdir -p
@@ -74,14 +76,17 @@
 
 all:		$(TODO)
 
-insserv:	insserv.o listing.o
+insserv:	insserv.o listing.o systemd.o
 	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 listing.o:	listing.c listing.h config.h .system
 	$(CC) $(CFLAGS) $(CLOOP) -c $<
 
-insserv.o:	insserv.c listing.h config.h .system
-	$(CC) $(CFLAGS) $(CLOOP) -c $<
+insserv.o:	insserv.c listing.h systemd.h config.h .system
+	$(CC) $(CFLAGS) $(CLOOP) $(CFLDBUS) -c $<
+
+systemd.o:	systemd.c listing.h systemd.h config.h .system
+	$(CC) $(CFLAGS) $(CLOOP) $(CFLDBUS) -c $<
 
 listing.h:	.system
 
@@ -161,6 +166,8 @@
 	  Makefile       \
 	  listing.c      \
 	  listing.h      \
+	  systemd.c      \
+	  systemd.h      \
 	  insserv.8.in   \
 	  insserv.c      \
 	  insserv.conf   \
@@ -172,6 +179,7 @@
 	  insserv-$(VERSION).lsm
 
 SVLOGIN=$(shell svn info | sed -rn '/Repository Root:/{ s|.*//(.*)\@.*|\1|p }')
+ifeq ($(MAKECMDGOALS),upload)
 override TMP:=$(shell mktemp -d $(PACKAGE)-$(VERSION).XXXXXXXX)
 override TARBALL:=$(TMP)/$(PACKAGE)-$(VERSION).tar.bz2
 override SFTPBATCH:=$(TMP)/$(VERSION)-sftpbatch
@@ -224,4 +232,4 @@
 	svn export . $@
 	@chmod -R a+r,u+w,og-w $@
 	@find $@ -type d | xargs -r chmod a+rx,u+w,og-w
-
+endif

Modified: trunk/src/insserv/insserv.8.in
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv.8.in?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/insserv.8.in	(original)
+++ trunk/src/insserv/insserv.8.in	Sat Feb  8 21:29:44 2014
@@ -269,6 +269,9 @@
 .TP
 .BR \-n ,\  \-\-dryrun
 Do not update symlinks.
+.TP
+.BR \-s ,\  \-\-showall
+Output runlevel and sequence information. Do not update symlinks.
 .TP
 .BR \-r ,\  \-\-remove
 Remove the listed scripts from all runlevels.

Modified: trunk/src/insserv/insserv.c
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/insserv.c?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/insserv.c	(original)
+++ trunk/src/insserv/insserv.c	Sat Feb  8 21:29:44 2014
@@ -23,9 +23,16 @@
  *
  */
 
+/*
+ * Systemd integration
+ */
+#define SYSTEMD_SERVICE_PATH	"/lib/systemd/system"
+#define SYSTEMD_BINARY_PATH	"/bin/systemd"
+
 #define MINIMAL_MAKE	1	/* Remove disabled scripts from .depend.boot,
 				 * .depend.start, .depend.halt, and .depend.stop */
 #define MINIMAL_RULES	1	/* ditto */
+#define MINIMAL_DEPEND	1	/* Remove redundant dependencies */
 
 #include <pwd.h>
 #include <string.h>
@@ -36,6 +43,7 @@
 #include <stdlib.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/statfs.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/syscall.h>
@@ -44,6 +52,12 @@
 #include <errno.h>
 #include <limits.h>
 #include <getopt.h>
+#if defined(__linux__)
+# include <linux/magic.h>
+#endif
+#if !defined(CGROUP_SUPER_MAGIC)
+# define CGROUP_SUPER_MAGIC	0x27e0eb
+#endif
 #if defined(USE_RPMLIB) && (USE_RPMLIB > 0)
 # include <rpm/rpmlib.h>
 # include <rpm/rpmmacro.h>
@@ -52,6 +66,7 @@
 # include <sys/mount.h>
 #endif /* SUSE */
 #include "listing.h"
+#include "systemd.h"
 
 #if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
 # ifndef POSIX_FADV_SEQUENTIAL
@@ -97,7 +112,11 @@
 # define INSCONF	"/etc/insserv.conf"
 #endif
 
-const char *upstartjob_path = "/lib/init/upstart-job";
+/* Upstart suport */
+static const char *upstartjob_path = "/lib/init/upstart-job";
+
+/* Systemd support */
+static DBusConnection *sbus;
 
 /*
  * For a description of regular expressions see regex(7).
@@ -151,6 +170,10 @@
 static boolean set_override = false;
 static boolean set_insconf = false;
 
+/* Wether systemd is active or not */
+static boolean systemd = false;
+static boolean is_overridden_by_systemd(const char *);
+
 /* Search results points here */
 typedef struct lsb_struct {
     char *provides;
@@ -242,13 +265,18 @@
  * Linked list of system facilities services and their replacment
  */
 typedef struct string {
-    int *restrict ref;
+    list_t     s_list;
+    int		  ref;
     char	*name;
 } __align string_t;
+#define getfstr(arg)	list_entry((arg), struct string, s_list)
 
 typedef struct repl {
     list_t     r_list;
-    string_t	 r[1];
+    struct {
+	string_t   *addr;
+	const char *name;
+    };
     ushort	flags;
 } __align repl_t;
 #define getrepl(arg)	list_entry((arg), struct repl, r_list)
@@ -260,6 +288,7 @@
 } __align faci_t;
 #define getfaci(arg)	list_entry((arg), struct faci, list)
 
+static list_t facistr = { &facistr, &facistr }, *facistr_start = &facistr;
 static list_t sysfaci = { &sysfaci, &sysfaci }, *sysfaci_start = &sysfaci;
 
 /*
@@ -337,7 +366,7 @@
 		if (!strcmp(token, getfaci(ptr)->name)) {
 		    list_t * lst;
 		    np_list_for_each(lst, &getfaci(ptr)->replace)
-			rememberreq(serv, bit, getrepl(lst)->r[0].name);
+			rememberreq(serv, bit, getrepl(lst)->name);
 		    break;
 		}
 	    }
@@ -377,7 +406,7 @@
 		if (!strcmp(token, getfaci(ptr)->name)) {
 		    list_t * lst;
 		    np_list_for_each(lst, &getfaci(ptr)->replace)
-			reversereq(serv, bit, getrepl(lst)->r[0].name);
+			reversereq(serv, bit, getrepl(lst)->name);
 		    break;
 		}
 	    }
@@ -389,8 +418,8 @@
 /*
  * 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 +438,23 @@
 	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 +465,8 @@
 	    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 +515,7 @@
 	    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;
 	}
@@ -738,7 +777,7 @@
     FILE *halt;
 #endif /* USE_KILL_IN_BOOT */
     const char *target;
-    service_t *serv;
+    const service_t *serv;
 
     if (dryrun) {
 #ifdef USE_KILL_IN_BOOT
@@ -818,6 +857,10 @@
 
     target = (char*)0;
     while ((serv = listscripts(&target, 'S', LVL_BOOT|LVL_ALL))) {
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	const service_t * lserv[100] = {0};
+	unsigned long lcnt = 0;
+#endif /* not MINIMAL_DEPEND */
 	boolean mark;
 	list_t * pos;
 
@@ -841,6 +884,10 @@
 	np_list_for_each(pos, &serv->sort.req) {
 	    req_t * req = getreq(pos);
 	    service_t * dep = req->serv;
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    boolean shadow = false;
+	    unsigned long n;
+#endif /* not MINIMAL_DEPEND */
 	    const char * name;
 
 	    if (!dep)
@@ -870,7 +917,36 @@
 		fprintf(out, "%s:", target);
 		mark = true;
 	    }
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    for (n = 0; n < lcnt && lserv[n] ; n++) {
+		list_t * red;
+		if (lserv[n]->attr.sorder <= dep->attr.sorder)
+		    break;
+		np_list_for_each(red, &(lserv[n])->sort.req) {
+		    req_t * other = getreq(red);
+		    if (other->serv->attr.flags & SERV_DUPLET)
+			continue;
+		    if (other->serv->attr.ref <= 0)
+			continue;
+		    if ((serv->start->lvl & other->serv->start->lvl) == 0)
+			continue;
+		    if (!other->serv->attr.script)
+			continue;
+		    if (other->serv != dep)
+			continue;
+		    shadow = true;
+		}
+	    }
+	    if (shadow)
+		continue;
+#endif /* not MINIMAL_DEPEND */
 	    fprintf(out, " %s", name);
+
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    if (lcnt >= sizeof(lserv)/sizeof(lserv[0]))
+		continue;
+	    lserv[lcnt++] = dep;
+#endif /* not MINIMAL_DEPEND */
 	}
 
 	if (mark) fputc('\n', out);
@@ -927,6 +1003,10 @@
 
     target = (char*)0;
     while ((serv = listscripts(&target, 'K', (LVL_NORM|LVL_BOOT)))) {
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	const service_t * lserv[100] = {0};
+	unsigned long lcnt = 0;
+#endif /* not MINIMAL_DEPEND */
 	boolean mark;
 	list_t * pos;
 
@@ -953,6 +1033,10 @@
 	np_list_for_each(pos, &serv->sort.rev) {
 	    req_t * rev = getreq(pos);
 	    service_t * dep = rev->serv;
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    boolean shadow = false;
+	    unsigned long n;
+#endif /* not MINIMAL_DEPEND */
 	    const char * name;
 
 	    if (!dep)
@@ -976,7 +1060,36 @@
 		fprintf(out, "%s:", target);
 		mark = true;
 	    }
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    for (n = 0; n < lcnt && lserv[n]; n++) {
+		list_t * red;
+		if (lserv[n]->attr.korder <= dep->attr.korder)
+		    break;
+		np_list_for_each(red, &(lserv[n])->sort.rev) {
+		    req_t * other = getreq(red);
+		    if (other->serv->attr.flags & SERV_DUPLET)
+			continue;
+		    if (other->serv->attr.ref <= 0)
+			continue;
+		    if ((serv->start->lvl & other->serv->start->lvl) == 0)
+			continue;
+		    if (!other->serv->attr.script)
+			continue;
+		    if (other->serv != dep)
+			continue;
+		    shadow = true;
+		}
+	    }
+	    if (shadow)
+		continue;
+#endif /* not MINIMAL_DEPEND */
 	    fprintf(out, " %s", name);
+
+#if defined(MINIMAL_DEPEND) && (MINIMAL_DEPEND != 0)
+	    if (lcnt >= sizeof(lserv)/sizeof(lserv[0]))
+		continue;
+	    lserv[lcnt++] = dep;
+#endif /* not MINIMAL_DEPEND */
 	}
 	if (mark) fputc('\n', out);
     }
@@ -1244,6 +1357,7 @@
 #define FOUND_LSB_DEFAULT  0x02
 #define FOUND_LSB_OVERRIDE 0x04
 #define FOUND_LSB_UPSTART  0x08
+#define FOUND_LSB_SYSTEMD  0x10
 
 static int o_flags = O_RDONLY;
 
@@ -1378,10 +1492,10 @@
 		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 +1530,7 @@
 	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 +1546,7 @@
 	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)
@@ -1478,7 +1592,7 @@
     linkbuf[PATH_MAX] = '\0';
 
     do {
-        struct stat st;
+	struct stat st;
 	int linklen;
 
 	if (deep++ > MAXSYMLINKS) {
@@ -1544,7 +1658,7 @@
 	error("snprintf(): %s\n", strerror(errno));
 
     if (stat(fullpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
-        ret = scan_lsb_headers(-1, fullpath, cache, ignore);
+	ret = scan_lsb_headers(-1, fullpath, cache, ignore);
     if (ret & FOUND_LSB_HEADER)
 	ret |= FOUND_LSB_OVERRIDE;
     return ret;
@@ -1588,27 +1702,48 @@
     }
 #endif /* SUSE */
 
-    /* Replace with headers from the script itself */
-    ret |= scan_lsb_headers(dfd, path, cache, ignore);
-
-    /* Do not override the upstarts defaults, if we allow this
-     * we have to change name to the link name otherwise the
-     * name is always "upstart-job" */
-    if (ret & FOUND_LSB_UPSTART)
-	goto out;
-
-    /* Load values if the override file exist */
-    if ((ret & FOUND_LSB_HEADER) == 0)
-	ret |= load_overrides("/usr/share/insserv/overrides", name, cache, ignore);
-    else
-	ret |= FOUND_LSB_DEFAULT;
+    if (systemd) {
+	const char *serv;
+	serv = path;
+	if (strncmp("boot.", serv, 5) == 0)
+	    serv += 5;
+	if (is_overridden_by_systemd(serv)) {
+	    ret |= FOUND_LSB_SYSTEMD;
+	}
+    }
+
+    if (is_upstart_job(path) != (char*)0) {
+	/*
+	 * Do not override the upstarts defaults, if we allow this
+	 * we have to change name to the link name otherwise the
+	 * name is always "upstart-job"
+	 */
+	ret |= scan_lsb_headers(dfd, path, cache, ignore);
+	if (ret & FOUND_LSB_UPSTART)
+	    goto out;
+    }
 
     /*
      * Allow host-specific overrides to replace the content in the
      * init.d scripts
      */
     ret |= load_overrides(override_path, name, cache, ignore);
+    if (ret & FOUND_LSB_OVERRIDE)
+	goto out;
+
+    /*
+     * Load third-party-specific values if the override file exist
+     */
+    ret |= load_overrides("/usr/share/insserv/overrides", name, cache, ignore);
+    if (ret & FOUND_LSB_OVERRIDE)
+	goto out;
+
+    /*
+     * Replace with headers from the script itself
+     */
+    ret |= scan_lsb_headers(dfd, path, cache, ignore);
 out:
+    ret |= FOUND_LSB_DEFAULT;
     free(name);
     return ret;
 }
@@ -1723,7 +1858,7 @@
 	if (!strpbrk(token, "0123456sSbB"))
 	    continue;
 
-        ret |= map_key_to_lvl(*token);
+	ret |= map_key_to_lvl(*token);
     }
 
     return ret;
@@ -1967,57 +2102,51 @@
 		real = pbuf+val->rm_so;
 	    }
 	    if (virt) {
-		list_t * ptr;
-		boolean found = false;
+		list_t *ptr;
+		list_t *r_list = (list_t*)0;
 		list_for_each(ptr, sysfaci_start) {
 		    if (!strcmp(getfaci(ptr)->name, virt)) {
-			found = true;
-			if(real) {
-			    list_t * r_list = &getfaci(ptr)->replace;
-			    char * token;
-			    while ((token = strsep(&real, delimeter))) {
-				repl_t *restrict subst;
-				string_t * r;
-				if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
-				    error("%s", strerror(errno));
-				insert(&subst->r_list, r_list->prev);
-				subst->flags = 0;
-				r = &subst->r[0];
-				if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0)
-				    error("%s", strerror(errno));
-				*r->ref = 1;
-				r->name = ((char*)(r->ref))+alignof(typeof(r->ref));
-				strcpy(r->name, token);
-			    }
-			}
+			r_list = &getfaci(ptr)->replace;
 			break;
 		    }
 		}
-		if (!found) {
+		if (!r_list) {
 		    faci_t *restrict this;
 		    if (posix_memalign((void*)&this, sizeof(void*), alignof(faci_t)) != 0)
 			error("%s", strerror(errno));
 		    else {
-			list_t * r_list = &this->replace;
-			char * token;
-			r_list->next = r_list;
-			r_list->prev = r_list;
+			r_list = &this->replace;
+			initial(r_list);
 			insert(&this->list, sysfaci_start->prev);
 			this->name = xstrdup(virt);
-			while ((token = strsep(&real, delimeter))) {
-			    repl_t *restrict subst;
-			    string_t * r;
-			    if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+		    }
+		}
+		if(real) {
+		    char *token;
+		    while ((token = strsep(&real, delimeter))) {
+			repl_t *restrict subst;
+			string_t *r = (string_t*)0;
+			if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+			    error("%s", strerror(errno));
+			insert(&subst->r_list, r_list->prev);
+			subst->flags = 0;
+			list_for_each(ptr, facistr_start) {
+			    if (strcmp(getfstr(ptr)->name, token) == 0) {
+				r = getfstr(ptr);
+				break;
+			    }
+			}
+			if (!r) {
+			    if (posix_memalign((void*)&r, sizeof(void*), alignof(string_t)+strsize(token)) != 0)
 				error("%s", strerror(errno));
-			    insert(&subst->r_list, r_list->prev);
-			    subst->flags = 0;
-			    r = &subst->r[0];
-			    if (posix_memalign((void*)&r->ref, sizeof(void*), alignof(typeof(r->ref))+strsize(token)) != 0)
-				error("%s", strerror(errno));
-			    *r->ref = 1;
-			    r->name = ((char*)(r->ref))+alignof(typeof(r->ref));
+			    r->ref = 1;
+			    insert(&r->s_list, facistr_start);
+			    r->name = ((char*)r)+alignof(string_t);
 			    strcpy(r->name, token);
-			}
+			} else
+			    r->ref++;
+			subst->addr = r;
+			subst->name = r->name;
 		    }
 		}
 	    }
@@ -2140,69 +2269,218 @@
     regfree(&creg.isactive);
 }
 
+/*
+ * Maps between systemd and SystemV
+ */
+static const char* sdmap[] = {
+    "$local-fs",	"$local_fs",
+    "$remote-fs",	"$remote_fs",
+    "cryptsetup",	"boot.crypto-early",
+    "udev",		"boot.udev",
+    "multipathd",	"boot.multipath",
+    "loadmodules",	"boot.loadmodules",
+    "device-mapper",	"boot.device-mapper",
+    "sysctl",		"boot.sysctl",
+    "fsck-root",	"boot.rootfsck",
+    "localfs",		"boot.localfs"
+};
+
+/*
+ *  Here the systemd targets are imported as system facilities 
+ */
+static void import_systemd_facilities(void)
+{
+    list_t *ptr;
+    list_for_each(ptr, &sdservs) {
+	sdserv_t *sdserv = list_entry(ptr, sdserv_t, s_list);
+	const char *facilitiy;
+	list_t *r_list;
+	list_t *iptr;
+	int n;
+
+	if (*sdserv->name != '$')
+	    continue;
+
+	facilitiy = sdserv->name;
+	for (n = 0; n < (int)(sizeof(sdmap)/sizeof(sdmap[0])); n += 2) {
+	    if (strcmp(sdmap[n], facilitiy) == 0) {
+		facilitiy = sdmap[n+1];
+		break;
+	    }
+	}
+
+	r_list = (list_t*)0;
+	np_list_for_each(iptr, sysfaci_start) {
+	    if (strcmp(getfaci(iptr)->name, facilitiy) == 0) {
+		r_list = &getfaci(iptr)->replace;
+		break;
+	    }
+	}
+	if (!r_list) {
+	    faci_t *restrict this;
+	    if (posix_memalign((void*)&this, sizeof(void*), alignof(faci_t)) != 0)
+		error("%s", strerror(errno));
+	    else {
+		r_list = &this->replace;
+		initial(r_list);
+		insert(&this->list, sysfaci_start->prev);
+		this->name = xstrdup(facilitiy);
+	    }
+	}
+
+	np_list_for_each(iptr, &sdserv->a_list) {
+	    ally_t *ally = list_entry(iptr, ally_t, a_list);
+	    repl_t *restrict subst;
+	    string_t *r = (string_t*)0;
+	    const char *token;
+	    list_t *fptr;
+
+	    if (ally->flags & SDREL_CONFLICTS)
+		continue;
+	    if (ally->flags & SDREL_BEFORE)
+		continue;
+
+	    token = ally->serv->name;
+	    for (n = 0; n < (int)(sizeof(sdmap)/sizeof(sdmap[0])); n += 2) {
+		if (strcmp(sdmap[n], token) == 0) {
+		    token = sdmap[n+1];
+		    break;
+		}
+	    }
+
+	    if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+		error("%s", strerror(errno));
+	    insert(&subst->r_list, r_list->prev);
+	    subst->flags = 0;
+	    np_list_for_each(fptr, facistr_start) {
+		if (strcmp(getfstr(fptr)->name, token) == 0) {
+		    r = getfstr(fptr);
+		    break;
+		}
+	    }
+	    if (!r) {
+		if (posix_memalign((void*)&r, sizeof(void*), alignof(string_t)+strsize(token)) != 0)
+		    error("%s", strerror(errno));
+		r->ref = 1;
+		insert(&r->s_list, facistr_start);
+		r->name = ((char*)r)+alignof(string_t);
+		strcpy(r->name, token);
+	    } else
+		    r->ref++;
+	    subst->addr = r;
+	    subst->name = r->name;
+	}
+    }
+}
+
+/*
+ *  Here the systemd servies are imported as services
+ */
+static void import_systemd_services(void)
+{
+    list_t *ptr;
+    list_for_each(ptr, &sdservs) {
+	sdserv_t *sdserv = list_entry(ptr, sdserv_t, s_list);
+	const char *this;
+	list_t *aptr;
+	int n;
+
+	if (*sdserv->name == '$')
+	    continue;
+
+	this = sdserv->name;
+	for (n = 0; n < (int)(sizeof(sdmap)/sizeof(sdmap[0])); n += 2) {
+	    if (strcmp(sdmap[n], this) == 0) {
+		this = sdmap[n+1];
+		break;
+	    }
+	}
+
+	np_list_for_each(aptr, &sdserv->a_list) {
+	    ally_t *ally = list_entry(aptr, ally_t, a_list);
+	    service_t * service;
+	    const char *token;
+
+	    if (ally->flags & SDREL_CONFLICTS)
+		continue;
+	    if (ally->flags & SDREL_BEFORE)
+		continue;
+
+	    token = ally->serv->name;
+	    for (n = 0; n < (int)(sizeof(sdmap)/sizeof(sdmap[0])); n += 2) {
+		if (strcmp(sdmap[n], token) == 0) {
+		    token = sdmap[n+1];
+		    break;
+		}
+	    }
+	    service = addservice(this);
+	    rememberreq(service, (ally->flags & SDREL_WANTS) ? REQ_SHLD : REQ_MUST, token);
+	    service->attr.flags |= SERV_SYSTEMD;
+	}
+    }
+}
+
 static void expand_faci(list_t *restrict rlist, list_t *restrict head,
 			int *restrict deep) attribute((noinline,nonnull(1,2,3)));
 static void expand_faci(list_t *restrict rlist, list_t *restrict head, int *restrict deep)
 {
-	repl_t * rent = getrepl(rlist);
-	list_t * tmp, * safe, * ptr = (list_t*)0;
-
-	list_for_each(tmp, sysfaci_start) {
-	    if (!strcmp(getfaci(tmp)->name, rent->r[0].name)) {
-		ptr = &getfaci(tmp)->replace;
-		break;
-	    }
-	}
-
-	if (!ptr || list_empty(ptr)) {
-	    delete(rlist);
-	    if (--(*rent->r[0].ref) <= 0)
-		free(rent->r[0].ref);
-	    free(rent);
-	    goto out;
-	}
-
-	list_for_each_safe(tmp, safe, ptr) {
-	    repl_t * rnxt = getrepl(tmp);
-	    if (rnxt->flags & 0x0001) {
-		error("Loop detected during expanding system facilities in the insserv.conf file(s): %s\n",
-		      rnxt->r[0].name);
-	    }
-	    if (*rnxt->r[0].name == '$') {
-		if (*deep > 10) {
-		    warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n");
-		    goto out;
-		}
-		(*deep)++;
-		rnxt->flags |= 0x0001;
-		expand_faci(tmp, head, deep);
-		rnxt->flags &= ~0x0001;
-		(*deep)--;
-	    } else if (*deep > 0) {
-		repl_t *restrict subst;
-		if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
-		    error("%s", strerror(errno));
-		insert(&subst->r_list, head->prev);
-		subst->r[0] = rnxt->r[0];
-		(*subst->r[0].ref) = 1;
-	    }
-	}
+    repl_t *rent = getrepl(rlist);
+    list_t *tmp, *safe, *ptr = (list_t*)0;
+
+    list_for_each(tmp, sysfaci_start) {
+	if (!strcmp(getfaci(tmp)->name, rent->name)) {
+	    ptr = &getfaci(tmp)->replace;
+	    break;
+	}
+    }
+
+    if (!ptr || list_empty(ptr))
+	goto out;
+
+    list_for_each_safe(tmp, safe, ptr) {
+	repl_t *rnxt = getrepl(tmp);
+	if (rnxt->flags & 0x0001) {
+	    error("Loop detected during expanding system facilities in the insserv.conf file(s): %s %s\n",
+		  rnxt->name, getrepl(head->prev)->name);
+	}
+	if (*rnxt->name == '$') {
+	    if (*deep > 10) {
+		warn("The nested level of the system facilities in the insserv.conf file(s) is to large\n");
+		goto out;
+	    }
+	    (*deep)++;
+	    rnxt->flags |= 0x0001;
+	    expand_faci(tmp, head, deep);
+	    rnxt->flags &= ~0x0001;
+	    (*deep)--;
+	} else if (*deep >= 0) {
+	    repl_t *restrict subst;
+	    if (posix_memalign((void*)&subst, sizeof(void*), alignof(repl_t)) != 0)
+		error("%s", strerror(errno));
+	    insert(&subst->r_list, head->prev);
+	    subst->addr = rnxt->addr;
+	    subst->name = rnxt->name;
+	    subst->addr->ref++;
+	}
+    }
 out:
-	return;
+    return;
 }
 
 static inline void expand_conf(void)
 {
     list_t *ptr;
     list_for_each(ptr, sysfaci_start) {
-	list_t * rlist, * safe, * head = &getfaci(ptr)->replace;
+	list_t *rlist, *safe, *head = &getfaci(ptr)->replace;
 	list_for_each_safe(rlist, safe, head) {
-	    repl_t * tmp = getrepl(rlist);
-	    if (*tmp->r[0].name == '$') {
+	    repl_t *tmp = getrepl(rlist);
+	    if (*tmp->name == '$') {
 		int deep = 0;
-		tmp->flags |= 0x0001;
-		expand_faci(rlist, rlist, &deep);
-		tmp->flags &= ~0x0001;
+		expand_faci(rlist, head, &deep);
+		delete(rlist);
+		if (--(tmp->addr->ref) <= 0)
+		    free(tmp->addr);
+		free(tmp);
 	    }
 	}
     }
@@ -2336,19 +2614,77 @@
 }
 #endif /* SUSE */
 
+/*
+ * Systemd integration
+ */
+static boolean is_overridden_by_systemd(const char *service) {
+    char *p;
+    boolean ret = false;
+
+    if (asprintf(&p, SYSTEMD_SERVICE_PATH "/%s.service", service) < 0)
+	error("asprintf(): %s\n", strerror(errno));
+
+    if (access(p, F_OK) >= 0)
+	ret = true;
+    free(p);
+    return ret;
+}
+
+static void forward_to_systemd (const char *initscript, const char *verb, boolean alternative_root) {
+    const char *name;
+
+    if (initscript == NULL)
+	return;
+
+    if (strncmp("boot.",initscript,5) == 0)
+	name = initscript+5;
+    else
+	name = initscript;
+
+    if (is_overridden_by_systemd (name)) {
+	char *p;
+	int err = 0;
+
+	if (alternative_root && root)
+	    err = asprintf (&p, "/bin/systemctl --quiet --no-reload --root %s %s %s.service", root, verb, name);
+	else {
+	    struct statfs stfs;
+	    if (statfs("/sys/fs/cgroup/systemd", &stfs) < 0 && errno != ENOENT)
+		error("statfs(): %s\n", strerror(errno));
+	    if (errno == 0 && stfs.f_type == CGROUP_SUPER_MAGIC)
+		err = asprintf (&p, "/bin/systemctl --quiet %s %s.service", verb, name);
+	    else
+		err = asprintf (&p, "/bin/systemctl --quiet --no-reload %s %s.service", verb, name);
+	}
+	if (err < 0)
+	    error("asprintf(): %s\n", strerror(errno));
+
+	warn("Note: sysvinit service %s is shadowed by systemd %s.service,\nForwarding request to '%s'.\n", initscript, name, p);
+	if (!dryrun)
+	    err = system(p);
+	if (err < 0)
+	    warn("Failed to forward service request to systemctl: %m\n");
+	else if (err > 0)
+	    warn("Forward service request to systemctl returned error status : %d\n",err);
+	free (p);
+    }
+}
+
 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'},
+    {"showall",	    0, (int*)0, 's'},
+    {"help",	    0, (int*)0, 'h'},
+    { 0,	    0, (int*)0,  0 },
 };
 
 static void help(const char *restrict const name) attribute((nonnull(1)));
@@ -2364,6 +2700,9 @@
     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("  -s, --showall    Output runlevel and sequence information.\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 +2725,9 @@
     boolean defaults = false;
     boolean ignore = false;
     boolean loadarg = false;
+    boolean recursive = false;
+    boolean showall = false;
+    boolean waserr = false;
 
     myname = basename(*argv);
 
@@ -2400,7 +2742,7 @@
     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:es", long_options, (int *)0)) != -1) {
 	size_t l;
 	switch (c) {
 	    case 'c':
@@ -2425,6 +2767,10 @@
 		verbose ++;
 		dryrun = true;
 		break;
+	    case 's':
+		showall = true;
+		dryrun = true;
+		break;
 	    case 'p':
 		if (optarg == (char*)0 || *optarg == '\0')
 		    goto err;
@@ -2445,6 +2791,9 @@
 		    goto err;
 		upstartjob_path = optarg;
 		break;
+	    case 'e':
+		recursive = true;
+		break;
 	    case '?':
 	    err:
 		error("For help use: %s -h\n", myname);
@@ -2566,15 +2915,67 @@
 	    printf("Overwrite argument for %s is %s\n", argv[c], argr[c]);
 #endif /* DEBUG */
 
+#ifdef SUSE
+    if (!underrpm())
+#endif
+    /*
+     * Systemd support
+     */
+    if (access(SYSTEMD_BINARY_PATH, F_OK) == 0 && (sbus = systemd_open_conn())) {
+
+	for (c = 0; c < argc; c++)
+	    forward_to_systemd (argv[c], del ? "disable": "enable", path != ipath);
+
+	(void)systemd_get_tree(sbus);
+	systemd_close_conn(sbus);
+	systemd = true;
+    }
+
     /*
      * Scan and set our configuration for virtual services.
      */
     scan_conf(insconf);
 
     /*
+     * Handle Systemd target as system facilities (<name>.target -> $<name>)
+     */
+    if (systemd)
+	import_systemd_facilities();
+
+    {
+	list_t *ptr;
+	list_for_each(ptr, sysfaci_start) {
+	    list_t *iptr, *head = &getfaci(ptr)->replace;
+	    printf("%s : ", getfaci(ptr)->name);
+	    np_list_for_each(iptr, head)
+		printf("%s ", getrepl(iptr)->name);
+	    printf("\n");
+	}
+    }
+
+    /*
      * Expand system facilities to real services
      */
     expand_conf();
+
+    {
+	list_t *ptr;
+	list_for_each(ptr, sysfaci_start) {
+	    list_t *iptr, *head = &getfaci(ptr)->replace;
+	    printf("%s : ", getfaci(ptr)->name);
+	    np_list_for_each(iptr, head)
+		printf("%s ", getrepl(iptr)->name);
+	    printf("\n");
+	}
+    }
+
+    /*
+     * Handle Systemd services (<name>.service -> <name>)
+     */
+    if (systemd) {
+	import_systemd_services();
+	systemd_free();		/* Not used anymore */
+    }
 
     /*
      * Initialize the regular scanner for the scripts.
@@ -2612,7 +3013,7 @@
      * Scan scripts found in the command line to be able to resolve
      * all dependcies given within those scripts.
      */
-    if (argc > 1) for (c = 0; c < argc; c++) {
+    for (c = 0; c < argc; c++) {
 	const char *const name = argv[c];
 	service_t * first = (service_t*)0;
 	char * provides, * begin, * token;
@@ -3000,8 +3401,10 @@
 		    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 +3467,9 @@
 			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,10 +3760,136 @@
     active_script();
 
     /*
+     * Check if runlevels of required scripts are a real subset
+     * of the services handled here.
+     */
+    if (!del && !ignore) {
+	list_t * ptr;
+	list_for_each(ptr, s_start) {
+	    service_t * cur = getservice(ptr);
+	    ushort clvl = cur->start->lvl & ~LVL_SINGLE;
+	    list_t * pos;
+
+	    cur = getorig(cur);
+	    if (list_empty(&cur->sort.req))
+		continue;
+
+	    if (cur->attr.flags & SERV_SYSTEMD)
+		continue;
+
+	    np_list_for_each(pos, &cur->sort.req) {
+		req_t *req = getreq(pos);
+		service_t * must;
+
+		if ((req->flags & REQ_MUST) == 0)
+		    continue;
+		must = req->serv;
+		must = getorig(must);
+
+		if (must->attr.flags & SERV_SYSTEMD)
+		    continue;
+
+		/*
+		 * Check for recursive mode the existence of the required services
+		 */
+		if (cur->attr.flags & SERV_CMDLINE) {
+
+		    if (must->attr.flags & SERV_ENABLED) {
+			ushort mlvl = must->start->lvl & ~LVL_SINGLE;
+
+			if ((mlvl & LVL_BOOT) && (clvl & LVL_BOOT) == 0)
+			    continue;
+
+			if ((mlvl & clvl) == clvl)
+			    continue;
+			if (recursive) {
+			    must->start->lvl |= clvl;
+			    must->stopp->lvl |= clvl;
+			    continue;
+			}
+			clvl &= ~mlvl;
+			if ((must->attr.flags & SERV_WARNED) == 0)
+#ifdef OSCBUILD
+			    warn("Service %s is missed in the runlevels %s to use service %s\n",
+				must->name, lvl2str(clvl), cur->name);
+#else
+			    warn("FATAL: service %s is missed in the runlevels %s to use service %s\n",
+				must->name, lvl2str(clvl), cur->name);
+			waserr = true;
+#endif
+			must->attr.flags |= SERV_WARNED;
+			continue;
+		    }
+		    if ((must->attr.flags & (SERV_ENFORCE|SERV_KNOWN)) == SERV_ENFORCE) {
+			if ((must->attr.flags & SERV_WARNED) == 0)
+#ifdef OSCBUILD
+			    warn("Service %s has to exists for service %s\n",
+				must->name, cur->name);
+#else
+			    warn("FATAL: service %s has to exists for service %s\n",
+				must->name, cur->name);
+			waserr = true;
+#endif
+			must->attr.flags |= SERV_WARNED;
+			continue;
+		    }
+		    if (recursive) {
+			must->start->lvl |= clvl;
+			must->stopp->lvl |= clvl;
+			continue;
+		    }
+		    continue;
+		}
+		if ((cur->attr.flags & SERV_ENABLED) == 0)
+		    continue;
+		if ((must->attr.flags & (SERV_CMDLINE|SERV_KNOWN)) == 0) {
+		    if ((must->attr.flags & SERV_WARNED) == 0)
+#ifdef OSCBUILD
+			warn("Service %s has to exists for service %s\n",
+			    must->name, cur->name);
+#else
+			warn("FATAL: service %s has to exists for service %s\n",
+			    must->name, cur->name);
+		    waserr = true;
+#endif
+		    must->attr.flags |= SERV_WARNED;
+		    continue;
+		}
+		if (must->attr.flags & SERV_ENABLED) {
+		    ushort mlvl = must->start->lvl & ~LVL_SINGLE;
+
+		    if ((mlvl & LVL_BOOT) && (clvl & LVL_BOOT) == 0)
+			continue;
+
+		    if ((mlvl & clvl) == clvl)
+			continue;
+		    clvl &= ~mlvl;
+		    if ((must->attr.flags & SERV_WARNED) == 0)
+#ifdef OSCBUILD
+			warn("Service %s is missed in the runlevels %s to use service %s\n",
+			    must->name, lvl2str(clvl), cur->name);
+#else
+			warn("FATAL: service %s is missed in the runlevels %s to use service %s\n",
+			    must->name, lvl2str(clvl), cur->name);
+		    waserr = true;
+#endif
+		    must->attr.flags |= SERV_WARNED;
+		}
+	    }
+	}
+    }
+
+    if (waserr)
+	error("exiting now!\n");
+
+    /*
      * Sorry but we support only [KS][0-9][0-9]<name>
      */
     if (maxstart > MAX_DEEP || maxstop > MAX_DEEP)
 	error("Maximum of %u in ordering reached\n", MAX_DEEP);
+
+    if (showall)
+	show_all();
 
 #if defined(DEBUG) && (DEBUG > 0)
     printf("Maxorder %d/%d\n", maxstart, maxstop);
@@ -3435,12 +3964,15 @@
 
 	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)
@@ -3616,13 +4148,16 @@
 
 	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;
 
 	    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) {

Modified: trunk/src/insserv/listing.c
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/listing.c?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/listing.c	(original)
+++ trunk/src/insserv/listing.c	Sat Feb  8 21:29:44 2014
@@ -86,6 +86,7 @@
 #define DIR_LOOP	0x0002
 #define DIR_LOOPREPORT	0x0004
 #define DIR_MAXDEEP	0x0008
+#define DIR_SYSTEMD	0x0010
 
 /*
  * The linked list off all services, note that the d_list
@@ -534,19 +535,16 @@
  * 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) {
     case 'K':
 	for (order = 0; order <= maxstop; order++) {
-	    list_t * ptr, * safe;
 	    list_for_each_safe(ptr, safe, d_start) {
 		dir_t * dir = getdir(ptr);
 		if (dir->stopp.deep == order)
@@ -554,28 +552,54 @@
 	    }
 	}
 	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++) {
-	    list_t * ptr, * safe;
 	    list_for_each_safe(ptr, safe, d_start) {
 		dir_t * dir = getdir(ptr);
 		if (dir->start.deep == order)
@@ -583,28 +607,54 @@
 	    }
 	}
 	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;
     }
-
-
 }
 
 /*
@@ -889,56 +939,80 @@
 /*
  * For debuging: show all services
  */
-#if defined(DEBUG) && (DEBUG > 0)
 void show_all()
 {
     list_t *tmp;
     if (maxstop > 0) list_for_each(tmp, d_start) {
-	char * script, *name, *lvlstr;
+	char * script, *lvlstr;
+#if defined(DEBUG) && (DEBUG > 0)
+	char *name;
+#endif
 	dir_t * dir = getdir(tmp);
 	handle_t * peg;
 	uchar deep;
 	ushort lvl;
 	if (!dir)
 	    continue;
+#if defined(DEBUG) && (DEBUG > 0)
 	name = dir->name;
+#endif
 	peg  = &dir->stopp;
 	lvl  = peg->run.lvl;
+	lvlstr = lvl2str(lvl);
 	deep = peg->deep;
 	if (attof(dir)->script)
 	    script = attof(dir)->script;
+#if defined(DEBUG) && (DEBUG > 0)
 	else if (*name == '$')
 	    script = "%system";
 	else
 	    script = "%guessed";
-	lvlstr = lvl2str(lvl);
-	info("K%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
+	info(1, "K%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr,
+	     script);
+#else
+	else
+	    script = NULL;
+	if (script && lvlstr)
+	    fprintf(stdout, "K:%.2d:%s:%s\n", deep, lvlstr, script);
+#endif
 	xreset(lvlstr);
     }
     if (maxstart > 0) list_for_each(tmp, d_start) {
-	char * script, *name, *lvlstr;
+	char * script, *lvlstr;
+#if defined(DEBUG) && (DEBUG > 0)
+	char *name;
+#endif
 	dir_t * dir = getdir(tmp);
 	handle_t * peg;
 	uchar deep;
 	ushort lvl;
 	if (!dir)
 	    continue;
+#if defined(DEBUG) && (DEBUG > 0)
 	name = dir->name;
+#endif
 	peg  = &dir->start;
 	lvl  = peg->run.lvl;
+	lvlstr = lvl2str(lvl);
 	deep = peg->deep;
 	if (attof(dir)->script)
 	    script = attof(dir)->script;
+#if defined(DEBUG) && (DEBUG > 0)
 	else if (*name == '$')
 	    script = "%system";
 	else
 	    script = "%guessed";
-	lvlstr = lvl2str(lvl);
-	info("S%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr, script);
+	info(1, "S%.2d %s 0x%.2x '%s' (%s)\n", deep, name, lvl, lvlstr,
+	     script);
+#else
+	else
+	    script = NULL;
+	if (script && lvlstr)
+	    fprintf(stdout, "S:%.2d:%s:%s\n", deep, lvlstr, script);
+#endif
 	xreset(lvlstr);
     }
 }
-#endif
 
 /*
  * Used within loops to get scripts not included in this runlevel
@@ -989,8 +1063,8 @@
 	prefetch(tmp->next);
 	dir = getdir(tmp);
 
-        attof(dir)->korder = dir->stopp.deep;
-        attof(dir)->sorder = dir->start.deep;
+	attof(dir)->korder = dir->stopp.deep;
+	attof(dir)->sorder = dir->start.deep;
 
 	serv = dir->serv;
 	*script = serv->attr.script;
@@ -1020,6 +1094,20 @@
 void requires(service_t *restrict this, service_t *restrict dep, const char mode)
 {
     ln_sf((dir_t*)this->dir, (dir_t*)dep->dir, mode);
+    if (this->attr.flags & SERV_SYSTEMD) {
+	dir_t *dir = (dir_t*)this->dir;
+	handle_t *peg = &dir->stopp;
+	peg->flags |= DIR_SYSTEMD;
+	peg = &dir->start;
+	peg->flags |= DIR_SYSTEMD;
+    }
+    if (dep->attr.flags & SERV_SYSTEMD) {
+	dir_t *dir = (dir_t*)dep->dir;
+	handle_t *peg = &dir->stopp;
+	peg->flags |= DIR_SYSTEMD;
+	peg = &dir->start;
+	peg->flags |= DIR_SYSTEMD;
+    }
 }
 
 /*
@@ -1027,7 +1115,7 @@
  */
 void runlevels(service_t *restrict serv, const char mode, const char *restrict lvl)
 {
-    dir_t * dir   = (dir_t *)serv->dir;
+    dir_t *dir   = (dir_t *)serv->dir;
     handle_t * peg = (mode == 'K') ? &dir->stopp : &dir->start;
     peg->run.lvl |= str2lvl(lvl);
 }

Modified: trunk/src/insserv/listing.h
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/listing.h?rev=1088&op=diff
==============================================================================
--- trunk/src/insserv/listing.h	(original)
+++ trunk/src/insserv/listing.h	Sat Feb  8 21:29:44 2014
@@ -54,6 +54,9 @@
 #ifndef  attribute
 # define attribute(attr)	__attribute__(attr)
 #endif
+#ifndef offsetof
+# define offsetof(type,memb)	__builtin_offsetof(type,memb)
+#endif
 
 /*
  * This is lent from the kernel by e.g. using
@@ -64,8 +67,7 @@
  *
  * on the appropiate architecture (here on i686 for i586).
  */
-static inline void prefetch(const void *restrict x) attribute((used,always_inline));
-static inline void prefetch(const void *restrict x)
+extern inline void attribute((used,__gnu_inline__,always_inline,__artificial__)) prefetch(const void *restrict x)
 {
 #if   defined(__x86_64__)
     asm volatile ("prefetcht0 %0"  :: "m" (*(unsigned long *)x))
@@ -91,6 +93,8 @@
 		  "   \n664:\n"
 		  ".previous"
 		  :: "i" ((0*32+25)), "r" (x))
+#else
+    __builtin_prefetch ((x), 0, 1);
 #endif
     ;
 }
@@ -158,6 +162,18 @@
     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)
 {
@@ -165,20 +181,38 @@
 
     if (first != list) {
 	list_t * last = list->prev;
-       	list_t * at = head->next;
-
-       	first->prev = head;
-       	head->next = first;
-
-       	last->next = at;
-       	at->prev = last;
+	list_t * at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
     }
 }
 
-static inline boolean list_empty(list_t *restrict head) attribute((always_inline,nonnull(1)));
-static inline boolean list_empty(list_t *restrict head)
+static inline boolean list_empty(const list_t *restrict const head) attribute((always_inline,nonnull(1)));
+static inline boolean list_empty(const list_t *restrict const head)
 {
      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)));
@@ -379,6 +413,9 @@
 #define SERV_NOSTOP	0x0100
 #define SERV_CMDLINE	0x0200
 #define SERV_FIRST	0x0400
+#define SERV_ENFORCE	0x0800
+#define SERV_WARNED	0x1000
+#define SERV_SYSTEMD	0x2000
 
 /*
  * Bits of the runlevels

Added: trunk/src/insserv/systemd.c
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/systemd.c?rev=1088&op=file
==============================================================================
--- trunk/src/insserv/systemd.c	(added)
+++ trunk/src/insserv/systemd.c	Sat Feb  8 21:29:44 2014
@@ -0,0 +1,459 @@
+/*
+ * systemd.c	    Use dbus API of systemd to import dependencies from.
+ *
+ * Copyright 2012 Werner Fink, 2012 SUSE LINUX Products GmbH, Germany.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include "listing.h"
+#include "systemd.h"
+
+/*
+ * Linked list of services, targets and their allies.
+ */
+list_t sdservs = { &sdservs, &sdservs }, *sdservs_start = &sdservs;
+
+static sdserv_t * addsysd(const char *const name) attribute((malloc,nonnull(1)));
+static sdserv_t * addsysd(const char *const name)
+{
+    sdserv_t *restrict this;
+    const char *dot;
+    boolean target;
+    list_t *ptr;
+    size_t len;
+
+    list_for_each_prev(ptr, sdservs_start) {
+	this = list_entry(ptr, sdserv_t, s_list);
+	if (!strcmp(this->unit, name))
+	    goto out;
+    }
+
+    target = false;
+    len = strsize(name);
+    if ((dot = strrchr(name, '.'))) {
+	dot++;
+	if (*dot == 't') {
+	    target = true;
+	    len++;
+	}
+    }
+    if (posix_memalign((void*)&this, sizeof(void*), alignof(sdserv_t)+len) != 0)
+	error ("addsysd() can not alloc memory for %s: %m\n", name);
+    memset(this, 0, alignof(sdserv_t)+len);
+    insert(&this->s_list, sdservs_start->prev);
+    this->name = ((char*)this)+alignof(sdserv_t);
+    if (target) {
+	*this->name = '$';
+	strcpy(this->name+1, name);
+	this->unit = this->name+1;
+    } else {
+	strcpy(this->name, name);
+	this->unit = this->name;
+    }
+    initial(&this->a_list);
+out:
+    return this;
+}
+
+static void addally(sdserv_t *restrict serv, sdserv_t *restrict ally, const ushort flags)
+{
+    ally_t *restrict this;
+    list_t *ptr, *allies;
+
+    allies = &serv->a_list;
+    list_for_each_prev(ptr, allies) {
+	this = list_entry(ptr, ally_t, a_list);
+	if (this->serv == ally) {
+	    this->flags |= flags;
+	    if (this->flags & SDREL_WANTS) {
+		if (this->flags & (SDREL_REQUIRES|SDREL_REQUISITE))
+		    warn("bogus systemd dependcy: %s %s\n", serv->unit, this->serv->unit);
+	    }
+	    return;
+	}
+    }
+    if (posix_memalign((void*)&this, sizeof(void*), alignof(ally_t)) != 0)
+	error ("addally() can not alloc memory for %s: %m\n", ally->unit);
+    memset(this, 0, alignof(ally_t));
+    insert(&this->a_list, allies->prev);
+    this->serv = ally;
+    this->flags = flags;
+}
+
+static void systemd_strip_dot(void)
+{
+    list_t *ptr;
+
+    list_for_each_prev(ptr, &sdservs) {
+	sdserv_t *sdserv = list_entry(ptr, sdserv_t, s_list);
+	char *dot = strrchr(sdserv->unit, '.');
+	const char *tag;
+	if (dot == (char*)0 || *dot == '\0')
+	    continue;
+	tag = dot+1;
+	if (strcmp(tag, "target") == 0 || strcmp(tag, "service") == 0)
+	    *dot = '\0';
+	else
+	    *dot = '_';
+    }
+}
+
+static int iter_get_and_next(DBusMessageIter *iter, int type, void *data)
+{
+    if (dbus_message_iter_get_arg_type(iter) != type)
+	goto err;
+    dbus_message_iter_get_basic(iter, data);
+    if (!dbus_message_iter_next(iter))
+	goto err;
+    return 1;
+err:
+    return 0;
+}
+
+typedef struct {
+    const char *const tag;
+    ushort flag;
+} relation_t;
+
+static int handle_one_property(sdserv_t *one, const char *prop, DBusMessageIter *iter)
+{
+    static relation_t relations[] = {
+	{ "Requires",			SDREL_REQUIRES	},
+	{ "RequiresOverridable",	SDREL_REQUIRES	},
+	{ "Requisite",			SDREL_REQUISITE	},
+	{ "RequisiteOverridable",	SDREL_REQUISITE	},
+	{ "Wants",			SDREL_WANTS	},
+	{ "Conflicts",			SDREL_CONFLICTS	},
+	{ "Before",			SDREL_BEFORE	},
+	{ "After",			SDREL_AFTER	},
+	{ (const char*)0,		0		}
+    };
+    const relation_t *relation = (relation_t*)0;
+    int i;
+
+    for (i = 0; relations[i].tag; i++) {
+	if (strcmp(relations[i].tag, prop) == 0) {
+	    relation = &relations[i];
+	    break;
+	}
+    }
+
+    if (!relation)
+	return 1;
+
+    switch (dbus_message_iter_get_arg_type(iter)) {
+    case DBUS_TYPE_ARRAY:
+	if (dbus_message_iter_get_element_type(iter) == DBUS_TYPE_STRING) {
+	    DBusMessageIter isub;
+
+	    dbus_message_iter_recurse(iter, &isub);
+
+	    do {
+		const char *ally;
+		const char *dot;
+		int type;
+
+		type = dbus_message_iter_get_arg_type(&isub);
+		if (type == DBUS_TYPE_INVALID)
+		    break;
+		if (type != DBUS_TYPE_STRING)
+		    goto failed;
+		dbus_message_iter_get_basic(&isub, &ally);
+
+		// Here we go to parse the dependcies
+		// targets are somehow like `$'
+		// services are somehow scripts
+		// Wants -> Optional
+		// Requires/Requisite -> Requires
+		// After -> ??
+
+		if ((dot = strrchr(ally, '.'))) {
+		    dot++;
+		    if (strcmp(dot, "target") == 0 || strcmp(dot, "service") == 0) {
+			sdserv_t * serv;
+#if 0
+			printf("\tdependcy (%s)\t: \"%s\" -> \"%s\"\n", relation->tag, one->unit, ally);
+#endif
+			serv = addsysd(ally);
+			addally(one, serv, relation->flag);
+		    }
+		}
+
+		dbus_message_iter_next(&isub);
+
+	    } while (TRUE);
+	}
+    }
+    return 1;
+failed:
+    warn ("failed to parse reply from systemd\n");
+    return 0;
+}
+
+static int handle_one_id(DBusConnection *bus, sdserv_t * serv, const char *path)
+{
+    DBusError error;
+    const char *device = "org.freedesktop.systemd1.Unit";
+    DBusMessage *reply, *send;
+    DBusMessageIter iter, isub;
+    int ret = 0;
+
+    dbus_error_init(&error);
+    send = dbus_message_new_method_call("org.freedesktop.systemd1",
+					 path,
+					"org.freedesktop.DBus.Properties",
+					"GetAll");
+    if (!send)
+	goto err;
+    dbus_message_set_auto_start(send, TRUE);
+    if (!dbus_message_set_destination(send, "org.freedesktop.systemd1"))
+	goto err;
+
+    dbus_message_iter_init_append(send, &iter);
+    dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &device);
+
+    reply = dbus_connection_send_with_reply_and_block(bus, send, -1, &error);
+    dbus_message_unref(send);
+
+    if (dbus_error_is_set(&error)) {
+	warn ("can not connect system dbus: %s\n", error.message);
+	dbus_error_free(&error);
+	goto err;
+    }
+    if (!reply)
+	goto err;
+    if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+	goto unref;
+
+    if (!dbus_message_iter_init(reply, &iter) ||
+	dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+	dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY)
+	goto failed;
+    dbus_message_iter_recurse(&iter, &isub);
+
+    do {
+	DBusMessageIter iisub, iiisub;
+	const char *prop;
+	int type;
+
+	type = dbus_message_iter_get_arg_type(&isub);
+	if (type == DBUS_TYPE_INVALID)
+	    break;
+	if (type != DBUS_TYPE_DICT_ENTRY)
+	    goto failed;
+
+	dbus_message_iter_recurse(&isub, &iisub);
+	if (!iter_get_and_next(&iisub, DBUS_TYPE_STRING, &prop))
+	    goto failed;
+	if (dbus_message_iter_get_arg_type(&iisub) != DBUS_TYPE_VARIANT)
+	    goto failed;
+
+	dbus_message_iter_recurse(&iisub, &iiisub);
+
+	handle_one_property(serv, prop, &iiisub);
+
+	dbus_message_iter_next(&isub);
+
+    } while (TRUE);
+
+    ret = 1;
+    goto unref;
+failed:
+    warn ("failed to parse reply from systemd\n");
+unref:
+    dbus_message_unref(reply);
+err:
+    return ret;
+}
+
+int systemd_get_tree(DBusConnection *bus)
+{
+    DBusError error;
+    DBusMessage *reply, *send;
+    DBusMessageIter iter, isub;
+    int ret = 0;
+
+    dbus_error_init(&error);
+    send = dbus_message_new_method_call("org.freedesktop.systemd1",
+					"/org/freedesktop/systemd1",
+					"org.freedesktop.systemd1.Manager",
+					"ListUnits");
+    if (!send)
+	goto err;
+    dbus_message_set_auto_start(send, TRUE);
+    if (!dbus_message_set_destination(send, "org.freedesktop.systemd1"))
+	goto err;
+
+    reply = dbus_connection_send_with_reply_and_block(bus, send, -1, &error);
+    dbus_message_unref(send);
+
+    if (dbus_error_is_set(&error)) {
+	warn ("can not connect system dbus: %s\n", error.message);
+	dbus_error_free(&error);
+	goto err;
+    }
+    if (!reply)
+	goto err;
+    if (dbus_message_get_type(reply) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
+	goto unref;
+
+    if (!dbus_message_iter_init(reply, &iter) ||
+	dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+	dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT)
+	goto failed;
+    dbus_message_iter_recurse(&iter, &isub);
+
+    do {
+	const char *id, *description, *load_state, *active_state,
+		   *sub_state, *following, *unit_path;
+	DBusMessageIter iisub;
+	const char *dot;
+	int type;
+
+	type = dbus_message_iter_get_arg_type(&isub);
+	if (type == DBUS_TYPE_INVALID)
+	    break;
+	if (type != DBUS_TYPE_STRUCT)
+	    goto failed;
+	dbus_message_iter_recurse(&isub, &iisub);
+
+	if (!iter_get_and_next(&iisub, DBUS_TYPE_STRING, &id) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_STRING, &description) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_STRING, &load_state) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_STRING, &active_state) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_STRING, &sub_state) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_STRING, &following) ||
+	    !iter_get_and_next(&iisub, DBUS_TYPE_OBJECT_PATH, &unit_path))
+	    goto failed;
+
+#if 0
+uint job_id;
+const char *sjob_type;
+const char *j_path;
+
+	iter_get_and_next(&iisub, DBUS_TYPE_UINT32, &job_id);
+	iter_get_and_next(&iisub, DBUS_TYPE_STRING, &sjob_type);
+	iter_get_and_next(&iisub, DBUS_TYPE_OBJECT_PATH, &j_path);
+
+printf("id=%s ls=%s as=%s subs=%s fl=%s %s ID=%u jt=%s jp=%s\n",
+	id, load_state, active_state, sub_state, following, unit_path,
+	job_id, sjob_type, j_path);
+#endif
+	if ((dot = strrchr(id, '.'))) {
+	    dot++;
+	    if (strcmp(dot, "target") == 0 || strcmp(dot, "service") == 0) {
+		sdserv_t * serv;
+		serv = addsysd(id);
+		handle_one_id(bus, serv, unit_path);
+	    }
+	}
+
+	dbus_message_iter_next(&isub);
+
+    } while (TRUE);
+
+    systemd_strip_dot();
+
+    ret = 1;
+    goto unref;
+failed:
+    warn ("failed to parse reply from systemd\n");
+unref:
+    dbus_message_unref(reply);
+err:
+    return ret;
+}
+
+DBusConnection * systemd_open_conn(void)
+{
+    DBusConnection *bus;
+    DBusError error;
+    struct ucred cred;
+    socklen_t len;
+    int oerrno;
+    int DBfd;
+
+    dbus_error_init(&error);
+    if (geteuid() == 0)	    /* for root use unix socket for speed */
+	bus = dbus_connection_open_private("unix:path=/run/systemd/private", &error);
+    else
+	bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
+
+    if (!bus) {
+	warn ("can not connect systemd: %s\n", error.message);
+	goto err;
+    }
+    dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+    if (!dbus_connection_get_unix_fd(bus, &DBfd))
+	goto perm;
+    len = sizeof(cred);
+    if (getsockopt(DBfd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0) 
+	goto perm;
+    oerrno = errno;
+    errno = E2BIG;
+    if (len != sizeof(cred))
+	goto perm;
+    errno = EPERM;
+    if (cred.uid != 0 && cred.uid != geteuid())
+	goto perm;
+    errno = oerrno;
+    return bus;
+perm:
+    warn ("can not connect to systemd: %m\n");
+err:
+    dbus_connection_close(bus);
+    dbus_connection_unref(bus);
+    if (dbus_error_is_set(&error))
+	dbus_error_free(&error);
+    return (DBusConnection*)0;
+}
+
+void systemd_close_conn(DBusConnection *bus)
+{
+    if (bus) {
+	dbus_connection_flush(bus);
+	dbus_connection_close(bus);
+	dbus_connection_unref(bus);
+    }
+}
+
+void systemd_free(void)
+{
+    list_t *ptr, *safe;
+    list_for_each_safe(ptr, safe, sdservs_start) {
+	sdserv_t *serv = list_entry(ptr, sdserv_t, s_list);
+	list_t *aptr, *asafe;
+	list_for_each_safe(aptr, asafe, &serv->a_list) {
+	    ally_t *ally = list_entry(aptr, ally_t, a_list);
+	    delete(aptr);
+	    free(ally);
+	}
+	delete(ptr);
+	free(serv);
+    }
+}

Added: trunk/src/insserv/systemd.h
URL: http://svn.debian.org/wsvn/initscripts-ng/trunk/src/insserv/systemd.h?rev=1088&op=file
==============================================================================
--- trunk/src/insserv/systemd.h	(added)
+++ trunk/src/insserv/systemd.h	Sat Feb  8 21:29:44 2014
@@ -0,0 +1,54 @@
+/*
+ * systemd.h
+ *
+ * Copyright 2012 Werner Fink, 2012 SuSE Linux Products GmbH Nuernberg, Germany
+ *
+ * This source is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <dbus/dbus.h>
+extern int systemd_get_tree(DBusConnection *bus);
+extern DBusConnection * systemd_open_conn(void);
+extern void systemd_close_conn(DBusConnection *bus);
+extern void systemd_free(void);
+
+/*
+ * Linked lists of services, targets and their allies.
+ */
+
+typedef struct sdserv __align sdserv_t;
+typedef struct {
+    list_t	a_list;
+    ushort	 flags;
+    sdserv_t	 *serv;
+} __align ally_t;
+
+struct sdserv {
+    list_t	s_list;
+    list_t	a_list;
+    char	 *unit;
+    char	 *name;
+};
+
+extern list_t sdservs;
+
+#define SDREL_REQUIRES		(1<<0)	    /* Requires/RequiresOverridable	*/
+#define SDREL_REQUISITE		(1<<1)	    /* Requisite/RequisiteOverridable	*/
+#define SDREL_WANTS		(1<<2)	    /* Wants		*/
+#define SDREL_CONFLICTS		(1<<3)	    /* Conflicts	*/
+#define	SDREL_BEFORE		(1<<4)	    /* Before		*/
+#define SDREL_AFTER		(1<<5)	    /* After		*/
+




More information about the Initscripts-ng-commits mailing list