Hi folks,

Pursuant to bug #591791 against Debian Policy about permitting alternate
init systems in Debian, I've prepared a patch against sysvinit which would
make startpar aware that a given job is implemented as an upstart job
instead of a SysV init script and that startpar should defer to upstart to
satisfy the dependency.

This enables insserv/startpar-based dependency boot to be used for sysvinit
in conjunction with upstart as /sbin/init and native upstart jobs as
dependencies, and is the first step towards having upstart be genuinely
usable on Debian.  It also rolls back the previous /lib/init/upstart-job
approach, which never worked right with startpar due to the inability to
express dependency information.  As a result, packages shipping upstart jobs
should now ship real init scripts in parallel (per the policy bug
discussion), which means some changes to debhelper are wanted before this
goes into effect.

It does *not* allow bidirectional dependencies between upstart jobs and init
scripts.  It's assumed that a system that runs upstart will be converted
from the bottom up - starting with rcS.d, which more or less needs to be
converted as a block anyway.

I've tested this patch to be regression-free on sysvinit as well as working
with upstart, and verified that the package still builds on non-Linux Debian
ports after applying (upstart doesn't run there anyway, so it's a simple
#ifdef :P).  I've also taken care to avoid adding any new runtime library
dependencies here; it would have been nice to use libdbus for talking to
upstart, but I guess some might resist such a change. :-)

Would any of the Debian sysvinit maintainers care to comment on this patch?
I can't help but notice the 12 consecutive NMUs to the package.  I don't
mind making this number 13, but would appreciate feedback if there's any to
be had.

Cheers,
-- 
Steve Langasek                   Give me a lever long enough and a Free OS
Debian Developer                   to set it on, and I can move the world.
Ubuntu Developer                                    http://www.debian.org/
slanga...@ubuntu.com                                     vor...@debian.org
diff -u sysvinit-2.88dsf/debian/rules sysvinit-2.88dsf/debian/rules
--- sysvinit-2.88dsf/debian/rules
+++ sysvinit-2.88dsf/debian/rules
@@ -61,6 +61,9 @@
 	dh_testdir
 	$(MAKE) $(CROSS) $(CONFFLAGS) -C src DISTRO=Debian LIBDIR=/usr/lib/$(DEB_HOST_MULTIARCH)
 	$(MAKE) $(CROSS) -C debian/startpar
+ifeq ($(DEB_HOST_ARCH_OS),linux)
+	$(MAKE) $(CROSS) -C debian/startpar startpar-upstart-inject
+endif
 	touch $@
 
 # Make a binary package (.deb file)
@@ -71,6 +74,7 @@
 	dh_installdirs
 	$(MAKE) -C src $(CROSS) ROOT=$(tmp) DISTRO=Debian install
 	dh_install
+	dh_installinit --name startpar-bridge --upstart-only -n
 	dh_link
 	# Used by sysvinit and sysvinit-utils
 	cat debian/copyright.in COPYRIGHT > debian/copyright
@@ -105,6 +109,9 @@
 	# sysvinit-utils package
 	#
 	$(MAKE) $(CROSS) -C debian/startpar DESTDIR=$(utiltmp) install
+ifeq ($(DEB_HOST_ARCH_OS),linux)
+	install -m755 debian/startpar/startpar-upstart-inject $(utiltmp)/sbin/
+endif
 	dh_installchangelogs -psysvinit-utils doc/Changelog
 	sed -i -ne '/sysvinit (2.86.ds1-47)/q' -e p \
 		$(inittmp)$(doc)/initscripts/changelog.Debian
@@ -166,6 +173,9 @@
 clean:
 	dh_testdir
 	$(MAKE) -C src clobber
+ifeq ($(DEB_HOST_ARCH_OS),linux)
+	rm -f debian/startpar/startpar-upstart-inject
+endif
 	$(MAKE) -C debian/startpar clean
 	$(MAKE) -f debian/rules unpatch
 	dh_clean build-stamp debian/copyright
diff -u sysvinit-2.88dsf/debian/changelog sysvinit-2.88dsf/debian/changelog
--- sysvinit-2.88dsf/debian/changelog
+++ sysvinit-2.88dsf/debian/changelog
@@ -1,3 +1,10 @@
+sysvinit (2.88dsf-13.13) UNRELEASED; urgency=low
+
+  * Fix startpar to not run init scripts that have matching upstart jobs,
+    instead waiting for a signal from upstart.
+
+ -- Steve Langasek <vor...@debian.org>  Sat, 15 Oct 2011 16:44:41 -0700
+
 sysvinit (2.88dsf-13.12) unstable; urgency=low
 
   * Non-maintainer upload.
diff -u sysvinit-2.88dsf/debian/startpar/patches/series sysvinit-2.88dsf/debian/startpar/patches/series
--- sysvinit-2.88dsf/debian/startpar/patches/series
+++ sysvinit-2.88dsf/debian/startpar/patches/series
@@ -10,0 +11 @@
+upstart_support.patch
only in patch2:
unchanged:
--- sysvinit-2.88dsf.orig/debian/sysvinit-utils.startpar-bridge.upstart
+++ sysvinit-2.88dsf/debian/sysvinit-utils.startpar-bridge.upstart
@@ -0,0 +1,15 @@
+# startpar-bridge - inject upstart start/stop events into startpar
+#
+# This job serves as a bridge to make startpar aware when an upstart job has
+# started or stopped, in order to make a soft transition between sysvinit
+# scripts and upstart jobs possible
+
+description	"startpar bridge for notification of upstart job start/stop"
+author		"Steve Langasek <steve.langa...@ubuntu.com>"
+
+start on started JOB!=startpar-bridge
+instance $JOB-$INSTANCE-$UPSTART_EVENTS
+
+task
+
+exec startpar-upstart-inject "$JOB" "$INSTANCE" "$UPSTART_EVENTS"
only in patch2:
unchanged:
--- sysvinit-2.88dsf.orig/debian/startpar/patches/upstart_support.patch
+++ sysvinit-2.88dsf/debian/startpar/patches/upstart_support.patch
@@ -0,0 +1,610 @@
+=== modified file 'Makefile'
+Index: startpar/Makefile
+===================================================================
+--- startpar.orig/Makefile
++++ startpar/Makefile
+@@ -9,8 +9,8 @@
+ man8dir		= $(mandir)/man8
+ 
+ SRCS		= startpar.c makeboot.c proc.c
+-HDRS		= makeboot.h proc.h
+-REST		= COPYING Makefile startpar.8
++HDRS		= makeboot.h proc.h startpar.h
++REST		= COPYING Makefile startpar.8 startpar-upstart-inject.c
+ OBJS		= $(SRCS:.c=.o)
+ 
+ CC = gcc
+Index: startpar/makeboot.c
+===================================================================
+--- startpar.orig/makeboot.c
++++ startpar/makeboot.c
+@@ -3,6 +3,7 @@
+  */
+ 
+ #include <stdio.h>
++#include <stddef.h>
+ #include <string.h>
+ #include <malloc.h>
+ #include <ctype.h>
+@@ -12,6 +13,8 @@
+ #include <stdarg.h>
+ #include <errno.h>
+ #include <limits.h>
++#include <sys/socket.h>
++#include <sys/un.h>
+ #include "makeboot.h"
+ #if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+ # include <sys/types.h>
+@@ -26,6 +29,7 @@
+ static int o_flags = O_RDONLY;
+ #endif
+ 
++#define DBUS_ADDRESS_UPSTART "@/com/ubuntu/upstart"
+ 
+ int tree_entries = 0;
+ struct makenode *tree_list = NULL;
+@@ -36,7 +40,7 @@
+  *
+  * FIXME: we should use hash for the effective search.
+  */
+-static struct makenode *lookup_target(const char *name)
++struct makenode *lookup_target(const char *name)
+ {
+ 	struct makenode *t;
+ 
+@@ -384,6 +388,105 @@
+ 	}
+ }
+ 
++#ifdef __linux__
++/*
++ * mark upstart services as finished.
++ *
++ * action is either boot, start or stop.
++ */
++int check_upstart_jobs(const char *action, const struct makenode **nodevec)
++{
++	struct makenode *t;
++	int count = 0;
++
++	if (!init_is_upstart())
++		return 0;
++
++	for (t = tree_list; t; t = t->next)
++	{
++		char path[131]; /* three bytes longer than the max allowed init script name... */
++		struct stat job;
++
++		snprintf(path, sizeof(path), "/etc/init/%s.conf", t->name);
++		if (!stat(path,&job)) {
++			int ret;
++			char *command;
++
++			t->upstart = 1;
++			/* Upstart jobs are never interactive in this sense */
++			t->interactive = 0;
++			if (!strcmp(action,"start") || !strcmp(action,"boot"))
++			{
++				asprintf(&command,
++				         "/sbin/initctl status %s | grep -q start/running",
++				         t->name);
++			} else {
++				asprintf(&command,
++				         "/sbin/initctl status %s | grep -q stop/waiting",
++				         t->name);
++			}
++			ret = system(command);
++			if (WEXITSTATUS(ret) == 0) {
++				nodevec[count] = t;
++				finish_task(t);
++				count++;
++			}
++			free(command);
++		}
++	}
++	return count;
++}
++
++/*
++ * return true if PID 1 is upstart, false otherwise.
++ */
++boolean init_is_upstart(void) {
++	static int is_upstart = -1;
++	int fd;
++	struct sockaddr_un saddr;
++	socklen_t addrlen;
++	struct ucred ucred;
++	socklen_t slen;
++
++	if (is_upstart != -1)
++		return is_upstart;
++
++	fd = socket(AF_LOCAL, SOCK_STREAM, 0);
++	/* Weird, but we'll just have to assume no upstart. */
++	if (fd < 0)
++		goto fail;
++
++	saddr.sun_family = AF_LOCAL;
++	strcpy(saddr.sun_path, DBUS_ADDRESS_UPSTART);
++	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
++
++	/* translate leading '@' to abstract namespace */
++	if (saddr.sun_path[0] == '@')
++		saddr.sun_path[0] = '\0';
++
++	if (connect(fd, (struct sockaddr *)&saddr, addrlen) < 0)
++		goto fail;
++
++	/* Make sure it's really upstart and not something lying to us! */
++	slen = sizeof(ucred);
++	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0)
++		goto fail;
++
++	close(fd);
++	if (ucred.uid == 0)
++		is_upstart = 1;
++	else
++		is_upstart = 0;
++
++	return is_upstart;
++
++fail:
++	if (fd >= 0)
++		close(fd);
++	is_upstart = 0;
++	return is_upstart;
++}
++#endif
+ 
+ /*
+  * call blogger
+@@ -449,6 +552,8 @@
+ 
+ 	if (! node)
+ 		return;
++	/* Ignore any further upstart signals for this job */
++	node->upstart = 0;
+ 	for (n = node->select; n; n = n->next)
+ 		n->node->num_deps--;
+ #if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+Index: startpar/makeboot.h
+===================================================================
+--- startpar.orig/makeboot.h
++++ startpar/makeboot.h
+@@ -5,6 +5,8 @@
+ 	T_READY, T_RUNNING, T_FINISHED
+ };
+ 
++typedef enum _boolean {false, true} boolean;
++
+ /* target nodes */
+ struct makenode {
+ 	char *name;
+@@ -16,6 +18,7 @@
+ 	int status;
+ 	struct makenode *next;
+ 	int interactive;
++	int upstart;
+ 	int importance;
+ };
+ 
+@@ -30,10 +33,13 @@
+ 
+ extern void parse_makefile(const char *path);
+ extern void check_run_files(const char *action, const char *prev, const char *run);
++extern int check_upstart_jobs(const char *action, const struct makenode **nodevec);
+ extern struct makenode *pickup_task(void);
++extern struct makenode *lookup_target(const char *name);
+ extern void finish_task(struct makenode *n);
+ extern void *xcalloc(size_t nmemb, size_t size);
+ extern void print_run_result(int *resvec, struct makenode **nodevec, const char *action);
++extern boolean init_is_upstart(void);
+ 
+ #define alignof(type)		((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
+ #define strsize(string)		((strlen(string)+1)*sizeof(char))
+Index: startpar/startpar.c
+===================================================================
+--- startpar.orig/startpar.c
++++ startpar/startpar.c
+@@ -1,4 +1,5 @@
+ /* Copyright (c) 2003 SuSE Linux AG
++ * Copyright 2011 Canonical Ltd
+  *
+  * 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
+@@ -23,6 +24,7 @@
+ #endif
+ 
+ #include <stdio.h>
++#include <stddef.h>
+ #include <termios.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -42,12 +44,13 @@
+ #include <string.h>
+ #include <stdlib.h>
+ #include <unistd.h>
++#include <poll.h>
+ #include "makeboot.h"
+ #include "proc.h"
++#include "startpar.h"
+ 
+ #define timerdiff(n,l) (__extension__ ({ (((n).tv_sec-(l).tv_sec)*1000)+(((n).tv_usec-(l).tv_usec)/1000); }))
+ 
+-typedef enum _boolean {false, true} boolean;
+ extern char *optarg;
+ extern int optind;
+ 
+@@ -81,6 +84,7 @@
+   struct timeval lastio;
+   size_t len;
+   int splashadd;
++  int upstart;
+   char buf[PBUF_SIZE];
+ };
+ 
+@@ -690,6 +694,9 @@
+   int c, i, num;
+   int limit;
+   int *resvec;
++#ifdef __linux__
++  int upstart_fd = -1;
++#endif
+   fd_set rset;
+   struct timeval tv;
+   struct prg *p;
+@@ -780,6 +787,36 @@
+ 	  splashopt = 0;
+ 	}
+     }
++#ifdef __linux__
++  if (init_is_upstart())
++  {
++    struct sockaddr_un saddr;
++    socklen_t addrlen;
++    upstart_fd = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
++    if (upstart_fd < 0)
++      fprintf(stderr, "Failed to open control socket for upstart events\n");
++
++    saddr.sun_family = AF_LOCAL;
++    strcpy(saddr.sun_path, UPSTART_SOCKET_PATH);
++    addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
++    /* translate leading '@' to abstract namespace */
++    if (saddr.sun_path[0] == '@')
++      saddr.sun_path[0] = '\0';
++    if (bind(upstart_fd, (struct sockaddr *)&saddr, addrlen) < 0)
++    {
++      fprintf(stderr, "Failed to bind address for upstart events: %m\n");
++      close(upstart_fd);
++      upstart_fd = -1;
++    }
++    if (listen(upstart_fd, 0))
++    {
++      fprintf(stderr, "Failed to listen for upstart events: %m\n");
++      close(upstart_fd);
++      upstart_fd = -1;
++    }
++  }
++#endif
++
+   if (run_mode)
+     {
+       char makefile[64];
+@@ -854,6 +891,12 @@
+   for (i = 0; i < argc; i++)
+     resvec[i] = 255;
+ 
++#ifdef __linux__
++  num += check_upstart_jobs(run_mode, nodevec);
++  for (i = 0; i < num; i++)
++    resvec[i] = 0;
++#endif
++
+   if (argc == 1)
+     {
+       if (run_mode)
+@@ -928,6 +971,14 @@
+ 
+       gettimeofday(&now, 0);
+       FD_ZERO(&rset);
++
++#ifdef __linux__
++      if (upstart_fd >= 0)
++	FD_SET(upstart_fd, &rset);
++      if (upstart_fd > maxfd)
++	maxfd = upstart_fd;
++#endif
++
+       tv = now;
+ 
+       if ((diff = timerdiff(now, lastlim)) >= 300 || diff < 0)
+@@ -951,9 +1002,9 @@
+ 	  p = prgs + s;
+ 	  if (p == interactive_task)
+ 	    continue;				/* don't count this here */
+-	  if (p->fd || p->pid)
++	  if (p->fd || p->pid || p->upstart)
+ 	    active++;				/* count all running procs */
+-	  if (p->fd == 0)
++	  if (p->fd == 0 && p->upstart == 0)
+ 	    {
+ 	      if (interactive_task)
+ 		continue;			/* dont't start new processes */
+@@ -971,6 +1022,7 @@
+ 			interactive_task = p;
+ 		      p->name = nodevec[num]->name;
+ 		      p->arg0 = nodevec[num]->arg0 ? nodevec[num]->arg0 : nodevec[num]->name;
++		      p->upstart = nodevec[num]->upstart;
+ 		    }
+ 		  else {
+ 		    p->name = *argv++;
+@@ -980,13 +1032,16 @@
+ 		  p->num = num++;
+ 		  if (interactive_task)
+ 		    continue;			/* don't start this here */
+-		  if (!devpts || notty)
++		  if ((!devpts || notty) && !p->upstart)
+ 		    {
+ 		      interactive_task = p;	/* no /dev/pts or tty, treat as interactive */
+ 		      continue;
+ 		    }
+-		  run(p);
+-		  if (p->pid == 0)
++		  if (p->upstart == 0)
++		  {
++		    run(p);
++		  }
++		  if (p->pid == 0 && p->upstart == 0)
+ 		    {
+ 		      resvec[p->num] = 1;
+ 		      if (run_mode)
+@@ -998,6 +1053,8 @@
+ 		}
+ 	      continue;
+ 	    }
++	  if (p->upstart)
++	    continue;
+ 	  FD_SET(p->fd, &rset);
+ 	  if (p->fd > maxfd)
+ 	    maxfd = p->fd;
+@@ -1185,6 +1242,119 @@
+ 	}
+       else
+ 	{
++#ifdef __linux__
++	  if (upstart_fd >= 0 && FD_ISSET(upstart_fd, &rset))
++	  {
++	    int client;
++	    /* Process new upstart events, marking the related process
++	       as started */
++	    while ((client = accept4(upstart_fd, NULL, NULL, SOCK_CLOEXEC)) >= 0)
++	    {
++	      struct ucred *cred;
++	      char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
++	      ssize_t size;
++	      char buf[8192];
++	      struct iovec iov;
++	      struct msghdr smsg;
++	      struct cmsghdr *cmsg;
++	      struct makenode *node;
++	      char *event, *name;
++	      int b = true;
++
++	      if (setsockopt(client, SOL_SOCKET, SO_PASSCRED, &b, sizeof(b)) < 0)
++	      {
++		/* Without this, we can't trust the client. */
++		close(client);
++		continue;
++	      }
++
++	      /* Wait for the actual message */
++	      for (;;) {
++		/* Yes, we're already using select elsewhere, but let's not
++		   perpetuate the badness more than necessary. */
++		struct pollfd pfd[1];
++		int r;
++
++		pfd[0].fd = client;
++		pfd[0].events = POLLIN;
++
++		r = poll(pfd, 1, 2000);
++		if (r < 0) {
++		  if (errno == EINTR)
++		    continue;
++		  close(client);
++		  client = -1;
++		}
++		if (r == 0 || !(pfd[0].revents & POLLIN)) {
++		  close(client);
++		  client = -1;
++		}
++		break;
++	      }
++	      /* Error waiting for read, move along */
++	      if (client == -1)
++		continue;
++
++	      memset(&smsg, 0, sizeof(struct msghdr));
++	      iov.iov_base = &buf;
++	      iov.iov_len = sizeof(buf);
++	      smsg.msg_iov = &iov;
++	      smsg.msg_iovlen = 1;
++	      smsg.msg_control = cred_msg;
++	      smsg.msg_controllen = sizeof(cred_msg);
++
++	      size = recvmsg(client, &smsg, 0);
++
++	      /* Each client is only allowed one message. */
++	      close(client);
++	      if (size <= 0)
++		continue;
++
++	      cmsg = CMSG_FIRSTHDR(&smsg);
++	      cred = (struct ucred *) CMSG_DATA(cmsg);
++	      if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS
++	          || cred->uid != 0)
++	      {
++		/* we don't trust the client. */
++		continue;
++	      }
++
++	      /* Make sure our message is NUL-terminated... */
++	      buf[size-1] = '\0';
++	      /* No room for the job name, malformed message */
++	      if (strlen(buf) >= size-2)
++		continue;
++	      event = buf;
++	      name = buf+strlen(event)+1;
++	      if ((!strcmp(run_mode, "boot") || !strcmp(run_mode, "start"))
++	          && strcmp(event,"started"))
++		continue;
++	      if ((!strcmp(run_mode, "halt") || !strcmp(run_mode, "stop"))
++	          && strcmp(event,"stopped"))
++		continue;
++	      node = lookup_target(name);
++	      if (node && node->upstart)
++	      {
++	        int found = 0;
++	        finish_task(node);
++	        for (s = 0; s < par; s++)
++		{
++		  p = prgs + s;
++		  /* FIXME: should have a better way to check the job
++		     identity besides strcmp */
++		  if (p->name && !strcmp(p->name,name))
++		  {
++		    found = 1;
++		    p->upstart = 0;
++		    resvec[p->num] = 0;
++		  }
++		}
++		if (!found)
++		  nodevec[++num] = node;
++	      }
++	    }
++	  }
++#endif
+ 	  for (s = 0; s < par; s++)
+ 	    {
+ 	      p = prgs + s;
+Index: startpar/startpar-upstart-inject.c
+===================================================================
+--- /dev/null
++++ startpar/startpar-upstart-inject.c
+@@ -0,0 +1,90 @@
++/* Copyright 2011 Canonical Ltd.
++ *
++ * 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, 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 (see the file COPYING); if not, write to the
++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ *
++ ****************************************************************
++ */
++
++#include <stddef.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <sys/un.h>
++#include <errno.h>
++#include "startpar.h"
++
++int main(int argc, char **argv)
++{
++	int fd, len;
++	ssize_t written = 0;
++	struct sockaddr_un saddr;
++	socklen_t addrlen;
++	char *buf;
++
++	if (argc < 4) {
++		fprintf(stderr, "Usage: %s jobname instance upstart_events\n",
++		        argv[0]);
++		exit(1);
++	}
++
++	fd = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK, 0);
++	if (!fd)
++		exit(1);
++
++	saddr.sun_family = AF_LOCAL;
++	strcpy(saddr.sun_path, UPSTART_SOCKET_PATH);
++	addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
++	/* translate leading '@' to abstract namespace */
++	if (saddr.sun_path[0] == '@')
++		saddr.sun_path[0] = '\0';
++
++	/* If the socket isn't there yet, we can assume startpar hasn't
++	 * started, and will catch this job itself once it does. */
++	if (connect(fd, (struct sockaddr *)&saddr, addrlen) < 0)
++		exit(0);
++
++	/* FIXME: should be able to unambiguously parse the arguments instead
++	 * of relying on whitespace. */
++	if (!strcmp(argv[3],"started") || !strcmp(argv[3],"stopped"))
++	{
++		len = asprintf(&buf, "%s %s %s",argv[3],argv[1],argv[2]);
++		buf[strlen(argv[3])] = '\0';
++		buf[strlen(argv[3])+strlen(argv[1])+1] = '\0';
++	}
++	else
++		/* Unhandled upstart event. */
++		exit(0);
++	if (len < 1)
++		exit(1);
++	do {
++		ssize_t s = send(fd, buf+written, len-written, MSG_NOSIGNAL);
++		if (s < 0 && errno != EINTR)
++		{
++			close(fd);
++			exit(1);
++		}
++		if (s > 0)
++			written += s;
++	} while (written < len);
++	close(fd);
++	exit(0);
++}
+Index: startpar/startpar.h
+===================================================================
+--- /dev/null
++++ startpar/startpar.h
+@@ -0,0 +1,21 @@
++/* Copyright 2011 Canonical Ltd.
++ *
++ * 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, 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 (see the file COPYING); if not, write to the
++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ *
++ ****************************************************************
++ */
++
++#define UPSTART_SOCKET_PATH "@/com/ubuntu/upstart_startpar_bridge"

Attachment: signature.asc
Description: Digital signature

_______________________________________________
initscripts-ng-devel mailing list
initscripts-ng-devel@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/initscripts-ng-devel

Reply via email to