=== modified file 'Makefile'
Index: sysvinit-2.88dsf/startpar/Makefile
===================================================================
--- sysvinit-2.88dsf.orig/startpar/Makefile
+++ sysvinit-2.88dsf/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)
 
 ifneq ($(INC),)
Index: sysvinit-2.88dsf/startpar/makeboot.c
===================================================================
--- sysvinit-2.88dsf.orig/startpar/makeboot.c
+++ sysvinit-2.88dsf/startpar/makeboot.c
@@ -21,6 +21,7 @@
  */
 
 #include <stdio.h>
+#include <stddef.h>
 #include <string.h>
 #include <malloc.h>
 #include <ctype.h>
@@ -30,6 +31,8 @@
 #include <stdarg.h>
 #include <errno.h>
 #include <limits.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
 # include <sys/types.h>
 # include <sys/stat.h>
@@ -47,6 +50,7 @@
 #endif
 #include "makeboot.h"
 
+#define DBUS_ADDRESS_UPSTART "@/com/ubuntu/upstart"
 
 int tree_entries = 0;
 struct makenode *tree_list = NULL;
@@ -57,7 +61,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;
 
@@ -409,6 +413,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 blogd
@@ -461,6 +564,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: sysvinit-2.88dsf/startpar/makeboot.h
===================================================================
--- sysvinit-2.88dsf.orig/startpar/makeboot.h
+++ sysvinit-2.88dsf/startpar/makeboot.h
@@ -23,6 +23,8 @@
 	T_READY, T_RUNNING, T_FINISHED
 };
 
+typedef enum _boolean {false, true} boolean;
+
 /* target nodes */
 struct makenode {
 	char *name;
@@ -34,6 +36,7 @@
 	int status;
 	struct makenode *next;
 	int interactive;
+	int upstart;
 	int importance;
 	int filter_prefix;
 };
@@ -49,10 +52,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: sysvinit-2.88dsf/startpar/startpar.c
===================================================================
--- sysvinit-2.88dsf.orig/startpar/startpar.c
+++ sysvinit-2.88dsf/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
@@ -30,6 +31,7 @@
 # define CHECK_FORDEVPTS
 #endif
 #include <stdio.h>
+#include <stddef.h>
 #include <termios.h>
 #include <signal.h>
 #include <sys/types.h>
@@ -51,6 +53,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <poll.h>
 #ifdef USE_BLOGD
 # include <libblogger.h>
 #else
@@ -59,6 +62,7 @@
 #endif
 #include "makeboot.h"
 #include "proc.h"
+#include "startpar.h"
 
 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
 # ifndef  inline
@@ -80,7 +84,6 @@
 
 #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;
 
@@ -114,6 +117,7 @@
   pid_t pid;
   struct timeval lastio;
   int splashadd;
+  int upstart;
   int status;
   int flags;
   size_t len;
@@ -831,6 +835,9 @@
   int limit;
   int notty = 0;
   int *resvec;
+#ifdef __linux__
+  int upstart_fd = -1;
+#endif
   struct timeval tv;
   struct prg *p;
   struct prg *gtimo_running = 0;
@@ -919,6 +926,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, SOMAXCONN))
+    {
+      fprintf(stderr, "Failed to listen for upstart events: %m\n");
+      close(upstart_fd);
+      upstart_fd = -1;
+    }
+  }
+#endif
+
   if (run_mode)
     {
       char makefile[64];
@@ -993,6 +1030,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)
@@ -1102,7 +1145,10 @@
   for (;;)
     {
 #ifdef CHECK_FORDEVPTS
-      int devpts = 0;
+      /* if we don't initialize this to a proper value, jobs get marked as
+         interactive when they shouldn't be and get lost when there are
+         upstart jobs in the mix. */
+      int devpts = checkdevpts();
 #endif
       int maxfd = -1;
       int last = -1;
@@ -1114,6 +1160,14 @@
       gettimeofday(&now, 0);
       pid = (pid_t)-1;
       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)
@@ -1134,7 +1188,7 @@
 	  p = prgs + s;
 	  if (p == interactive_task)
 	    continue;				/* don't count this here */
-	  if (p->fd == 0)
+	  if (p->fd == 0 && p->upstart == 0)
 	    {
 	      if (interactive_task)
 		continue;			/* dont't start new processes */
@@ -1153,6 +1207,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++;
@@ -1161,15 +1216,16 @@
 		  p->splashadd = calcsplash(num, argc, splashopt);
 		  p->num = num++;
 #ifdef CHECK_FORDEVPTS
-		  if (!devpts)
+		  if (!devpts && !p->upstart)
 		    interactive_task = p;	/* no /dev/pts, treat as interactive */
 #endif
-		  if (notty)
+		  if (notty && !p->upstart)
 		    interactive_task = p;	/* no tty, treat as interactive */
 		  if (interactive_task)
 		    continue;			/* don't start this here */
-		  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)
@@ -1192,6 +1248,8 @@
 		}
 	    }
 
+	  if (p->upstart)
+	    continue;
 	  FD_SET(p->fd, &rset);
 	  if (p->fd > maxfd)
 	    maxfd = p->fd;
@@ -1393,6 +1451,120 @@
 	}
       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;
+		    active--;
+		    resvec[p->num] = 0;
+		  }
+		}
+		if (!found)
+		  nodevec[++num] = node;
+	      }
+	    }
+	  }
+#endif
 	  for (s = 0; s < par; s++)
 	    {
 	      p = prgs + s;
Index: sysvinit-2.88dsf/startpar/startpar-upstart-inject.c
===================================================================
--- /dev/null
+++ sysvinit-2.88dsf/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: sysvinit-2.88dsf/startpar/startpar.h
===================================================================
--- /dev/null
+++ sysvinit-2.88dsf/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"
Index: sysvinit-2.88dsf/startpar/startpar-upstart-inject.8
===================================================================
--- /dev/null
+++ sysvinit-2.88dsf/startpar/startpar-upstart-inject.8
@@ -0,0 +1,73 @@
+.TH startpar-upstart-inject 8 2012-06-05 
+.SH NAME
+startpar-upstart-inject \- notify startpar of started/stopped upstart jobs
+.
+.SH SYNOPSIS
+.B startpar-upstart-inject
+.I job-name
+.I instance
+.I [started|stopped]
+.
+.SH DESCRIPTION
+.B startpar-upstart-inject
+is a helper command for notifying
+.B startpar
+whenever an upstart job has started or stopped.  It allows
+.B startpar
+to run in a manner compatible with upstart\-based systems, where
+many/most jobs are started directly by upstart and not by
+.BR startpar .
+In this scenario,
+.B startpar
+must be notified whenever an upstart job has started so that it can run
+the init scripts for services that declare a dependency on that job.
+.
+.SH OPTIONS
+The
+.B startpar-upstart-inject
+command takes three arguments, all of which are mandatory.
+.TP
+.I job-name
+The name of the
+.B upstart
+job.  Normally this will match the name of a script in the
+.I /etc/init.d
+directory.
+.
+.TP
+.I instance
+The instance of the
+.B upstart
+job, if any; otherwise, an empty string.  This is currently ignored by
+.BR startpar ,
+which has no concept of service instances.
+.
+.TP
+.I [started|stopped]
+The single word
+.I started
+or
+.I stopped
+which indicates whether the listed job has been started or stopped.
+.
+.SH FILES
+.TP
+.I /etc/init/startpar-bridge.conf
+upstart job which invokes
+.B startpar-upstart-inject
+each time another upstart job starts
+.
+.SH SEE ALSO
+.BR init (8)
+.BR insserv (8)
+.BR startpar (8)
+.BR upstart-events (7)
+.
+.SH AUTHOR
+Written by Steve Langasek <steve.langasek@canonical.com>
+.
+.SH COPYRIGHT
+Copyright \(co 2012 Canonical Ltd.
+.br
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
