--- minit-0.9.1.cvs20040208.orig/Makefile
+++ minit-0.9.1.cvs20040208/Makefile
@@ -1,4 +1,4 @@
-all: minit msvc pidfilehack hard-reboot write_proc killall5 shutdown \
+all: minit msvc enitdir pidfilehack hard-reboot write_proc killall5 shutdown \
 minit-update
 
 #CFLAGS=-pipe -march=i386 -fomit-frame-pointer -Os -I../dietlibc/include
@@ -18,6 +18,9 @@
 str_start.o
 	$(DIET) $(CROSS)$(CC) $(LDFLAGS) -o msvc $^
 
+enitdir: enitdir.o str_len.o str_start.o
+	$(DIET) $(CROSS)$(CC) $(LDFLAGS) -o enitdir $^
+
 minit-update: minit-update.o buffer_1.o buffer_2.o buffer_puts.o \
 buffer_putsflush.o buffer_put.o buffer_flush.o buffer_stubborn.o \
 buffer_putflush.o byte_copy.o split.o str_len.o openreadclose.o
@@ -30,7 +33,7 @@
 	$(DIET) $(CROSS)$(CC) $(CFLAGS) -c $<
 
 clean:
-	rm -f *.o minit msvc pidfilehack hard-reboot write_proc killall5 \
+	rm -f *.o minit msvc minit-update enitdir pidfilehack hard-reboot write_proc killall5 \
 	shutdown
 
 test: test.c
@@ -53,6 +56,7 @@
 	install minit pidfilehack $(DESTDIR)/sbin
 	install write_proc hard-reboot minit-update $(DESTDIR)/sbin
 	install msvc $(DESTDIR)/bin
+	install enitdir $(DESTDIR)/sbin
 	install -m 4750 shutdown $(DESTDIR)/sbin
	test -f $(DESTDIR)/sbin/init || ln $(DESTDIR)/sbin/minit $(DESTDIR)/sbin/init
 
@@ -85,6 +89,7 @@
 killall5.o: killall5.c
 minit.o: minit.c fmt.h str.h
 msvc.o: msvc.c str.h fmt.h buffer.h
+enitdir.o: enitdir.c str.h buffer.h
 openreadclose.o: openreadclose.c
 pidfilehack.o: pidfilehack.c
 shutdown.o: shutdown.c
--- minit-0.9.1.cvs20040208.orig/minit.c
+++ minit-0.9.1.cvs20040208/minit.c
@@ -345,8 +345,8 @@
   time_t last=time(0);
   int nfds=1;
 
-  infd=open(MINITROOT "/in",O_RDWR);
-  outfd=open(MINITROOT "/out",O_RDWR|O_NONBLOCK);
+  infd=open(MINITFIFOS "/in",O_RDWR);
+  outfd=open(MINITFIFOS "/out",O_RDWR|O_NONBLOCK);
 
   if (getpid()==1) {
     int fd;
@@ -371,7 +371,7 @@
   }
   
   if (infd<0 || outfd<0) {
-    _puts("minit: could not open " MINITROOT "/in or " MINITROOT "/out\n");
+    _puts("minit: could not open " MINITFIFOS "/in or " MINITFIFOS "/out\n");
     sulogin();
     nfds=0;
   } else
--- minit-0.9.1.cvs20040208.orig/msvc.c
+++ minit-0.9.1.cvs20040208/msvc.c
@@ -107,8 +107,8 @@
 	" -C\tClear; remove service form active list\n\n");
     return 0;
   }
-  infd=open(MINITROOT "/in",O_WRONLY);
-  outfd=open(MINITROOT "/out",O_RDONLY);
+  infd=open(MINITFIFOS "/in",O_WRONLY);
+  outfd=open(MINITFIFOS "/out",O_RDONLY);
   if (infd>=0) {
     while (lockf(infd,F_LOCK,1)) {
       buffer_putsflush(buffer_2,"could not acquire lock!\n");
@@ -238,7 +238,7 @@
       return ret;
     }
   } else {
-    buffer_putsflush(buffer_2,"minit: could not open " MINITROOT "/in or " MINITROOT "/out\n");
+    buffer_putsflush(buffer_2,"minit: could not open " MINITFIFOS "/in or " MINITFIFOS "/out\n");
     return 1;
   }
 }
--- minit-0.9.1.cvs20040208.orig/shutdown.c
+++ minit-0.9.1.cvs20040208/shutdown.c
@@ -130,8 +130,8 @@
   int retval;
 
   __write2("Shutting down minit services: \n");
-  infd=open(MINITROOT "/in", O_WRONLY);
-  outfd=open(MINITROOT "/out", O_RDONLY);
+  infd=open(MINITFIFOS "/in", O_WRONLY);
+  outfd=open(MINITFIFOS "/out", O_RDONLY);
   if (infd>=0) {
     while (lockf(infd, F_TLOCK, 1)) {
       __write2("could not acquire lock!\n");
--- minit-0.9.1.cvs20040208.orig/minit.h
+++ minit-0.9.1.cvs20040208/minit.h
@@ -1,4 +1,5 @@
 #define MINITROOT "/etc/minit"
+#define MINITFIFOS "/etc/minit"
 
 #ifndef NOVARS
 static struct process {
--- minit-0.9.1.cvs20040208.orig/minit-update.c
+++ minit-0.9.1.cvs20040208/minit-update.c
@@ -187,10 +187,10 @@
    } else die(USAGE);
  }
 
- infd=open(MINITROOT "/in",O_WRONLY);
- outfd=open(MINITROOT "/out",O_RDONLY);
+ infd=open(MINITFIFOS "/in",O_WRONLY);
+ outfd=open(MINITFIFOS "/out",O_RDONLY);
  
- if (infd<0 || outfd<0) die("could not open " MINITROOT "/in or " MINITROOT "/out\n");
+ if (infd<0 || outfd<0) die("could not open " MINITFIFOS "/in or " MINITFIFOS "/out\n");
 
  while (lockf(infd,F_TLOCK,1)) {
     buffer_puts_strerror("could not acquire lock: ");
--- minit-0.9.1.cvs20040208.orig/enitdir.c
+++ minit-0.9.1.cvs20040208/enitdir.c
@@ -0,0 +1,494 @@
+/*
+ * Simple runlevel system for minit
+ * Copyright 2004 by Erich Schubert <erich@debian.org>
+ *
+ * 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.
+*/
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+/* we really really need F_NOTIFY */
+#ifndef F_NOTIFY
+# include "fcntl-linux.h"
+#endif
+
+#include <sys/file.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+
+/* debugging options */
+#define DEBUG_VERBOSE
+/*#define NDEBUG */
+#include <assert.h>
+
+/* use minit */
+#define NOVARS
+#include "str.h"
+#include "minit.h"
+
+/* minmalistic IO */
+#ifdef __dietlibc__
+#include <write12.h>
+#else
+#include <unistd.h>
+static inline int __write1(const char*s) { return write(1,s,str_len(s)); }
+static inline int __write2(const char*s) { return write(2,s,str_len(s)); }
+#endif
+
+/* maximum number of services in a directory */
+#define MAX_SERVICES	250
+/* buffer size, determines maximum path length */
+#define BUFSIZE 1000
+
+#define SV_GO_DOWN	0x01
+#define SV_GO_UP	0x02
+
+struct service {
+	/* to identify a service dir uniquely */
+	dev_t	device;
+	ino_t	inode;
+	char*	name;
+	int	flags;
+};
+
+/* primitive busy "lock" */
+#define SD_BUSY		0x01
+
+struct servicedir {
+	struct service	s[MAX_SERVICES];
+	int	nums;
+	char*	dir;
+	int	dirfd;
+	dev_t	dirdevice;
+	ino_t	dirinode;
+	char*	parentdir;
+	int	parentfd;
+	int	flags;
+};
+
+/* global sd */
+static struct servicedir sd;
+
+/* minit interface */
+static int minit_infd;
+
+static char buf[BUFSIZE+1];
+
+/* copied from msvc with minimal adoption */
+void addservice(char* service) {
+	char* x;
+	if (str_start(service,MINITROOT "/"))
+		service+=11;
+	x=service+str_len(service)-1;
+	while (x>service && *x=='/') { *x=0; --x; }
+	strncpy(buf+1,service,1400);
+	buf[1400]=0;
+}
+
+int addreadwrite(char* service) {
+	int outfd;
+	int result;
+	addservice(service);
+	/* lock the in fd and open the out fd... */
+	while (lockf(minit_infd, F_TLOCK, 1)) {
+		__write2("could not acquire lock!\n");
+		sleep(1);
+	}
+	/* open the output fd */
+	outfd=open(MINITFIFOS "/out",O_RDONLY);
+	if (!outfd) {
+		__write2("Couldn't open minit out fifo.\n");
+		lockf(minit_infd, F_ULOCK, 1);
+		return -1;
+	}
+	write(minit_infd,buf,str_len(buf));
+	result = read(outfd,buf,1500);
+	/* close output fd, unlock input fd */
+	close(outfd);
+	lockf(minit_infd, F_ULOCK, 1);
+	return result;
+}
+
+/* return PID, 0 if error */
+pid_t __readpid(char *service) {
+	int len;
+	buf[0]='p';
+	len=addreadwrite(service);
+	if (len<0) return 0;
+	buf[len]=0;
+	return atoi(buf);
+}
+
+/* return nonzero if error */
+int startservice(char *service) {
+	int len;
+	buf[0]='s';
+	len=addreadwrite(service);
+	return (len!=1 || buf[0]=='0');
+}
+
+/* return nonzero if error */
+int respawn(char *service,int yesno) {
+	int len;
+	buf[0]=yesno?'R':'r';
+	len=addreadwrite(service);
+	return (len!=1 || buf[0]=='0');
+}
+
+inline void
+add_service(struct servicedir* s, struct stat* sbuf, char* name) {
+	char buffer[BUFSIZE+1];
+	int len;
+	assert(s); assert(sbuf); assert(name);
+
+	len = readlink(name, buffer, BUFSIZE);
+	buffer[len] = '\0';
+
+	s->s[s->nums].device = sbuf->st_dev;
+	s->s[s->nums].inode = sbuf->st_ino;
+	s->s[s->nums].flags = SV_GO_UP;
+	if (len && *buffer)
+		s->s[s->nums].name = strdup(buffer);
+	else
+		s->s[s->nums].name = strdup(name);
+	s->nums++;
+}
+
+inline void
+do_shutdown_services(struct servicedir* s) {
+	int num;
+	assert(s);
+
+	for (num = s->nums - 1; num >= 0; num--)
+		if (s->s[num].flags & SV_GO_DOWN) {
+			if (s->s[num].name) {
+				int pid;
+#ifdef DEBUG_VERBOSE
+				__write2("Terminating service '");
+				__write2(s->s[num].name);
+				__write2("'\n");
+#endif
+				pid = __readpid(s->s[num].name);
+				/* TODO: we might want to avoid killing ourselves, too? */
+				if (pid && (pid != 1)) {
+					if (respawn(s->s[num].name,0) || kill(pid,SIGTERM)) kill(pid,SIGCONT);
+				}
+				/* free the service name pointer */
+				free(s->s[num].name);
+			}
+			s->s[num] = s->s[s->nums-1];
+			s->nums--;
+		}
+}
+
+inline void
+do_start_services(struct servicedir* s) {
+	int num;
+	assert(s);
+	for (num=0; num < s->nums; num++)
+		if (s->s[num].flags & SV_GO_UP)
+			if (s->s[num].name) {
+#ifdef DEBUG_VERBOSE
+				__write2("Starting service '");
+				__write2(s->s[num].name);
+				__write2("'\n");
+#endif
+				/* FIXME: Dependency management */
+				s->s[s->nums].flags &= ~SV_GO_UP;
+				startservice(s->s[num].name);
+				/* FIXME: failure logging? */
+			}
+}
+
+int
+check_dir(struct servicedir* s) {
+	DIR *dir;
+	struct dirent* de;
+	struct stat sbuf;
+	int i;
+
+	if (!s)
+		return -EINVAL;
+#ifdef DEBUG_VERBOSE
+	__write2("Rechecking ");
+	__write2(s->dir);
+	__write2("\n");
+#endif
+
+	/* dir found? */
+	if (! (dir = opendir(s->dir)))
+		return -ENOENT;
+	/* try to chdir */
+	if (chdir(s->dir) < 0) {
+		__write2("Couldn't chdir to ");
+		__write2(s->dir);
+		__write2("\n");
+		return -ENOENT;
+	}
+
+	/* already busy? */
+	if (s->flags & SD_BUSY)
+		return -EBUSY;
+	s->flags |= SD_BUSY;
+
+	/* assume services have to go down */
+	for (i=0; i < s->nums; i++)
+		s->s[i].flags |= SV_GO_DOWN;
+
+	errno = 0;
+	while ( (de = readdir(dir)) ) {
+		/* ignore hidden dirs and "." ".." */
+		if (de->d_name[0] == '.') continue;
+		/* stat file to check if it is a dir */
+		if (stat(de->d_name, &sbuf) == -1) {
+			__write2("unable to stat ");
+			__write2(de->d_name);
+			__write2("\n");
+			/* reset errno */
+			errno = 0;
+			continue;
+		}
+		__write2("Got ");
+		__write2(de->d_name);
+		__write2("\n");
+		/* skip non-dirs */
+		if (! S_ISDIR(sbuf.st_mode) ) continue;
+		/* search the service list */
+		for (i=0; i < s->nums; i++) {
+			if ( (s->s[i].device == sbuf.st_dev)
+			  && (s->s[i].inode  == sbuf.st_ino) ) {
+				s->s[i].flags &= ~SV_GO_DOWN;
+				break;
+			}
+		}
+		/* new service? */
+		if (i >= MAX_SERVICES) {
+			__write2("maximum number of services reached for ");
+			__write2(de->d_name);
+			__write2("\n");
+			continue;
+		} else if (i >= s->nums) {
+			add_service(s,&sbuf,de->d_name);
+		}
+	}
+	/* so closedir(dir) doesn't change errno */
+	if (errno) {
+		__write2("Error reading directory contents.\n");
+		closedir(dir);
+		s->flags &= ~SD_BUSY;
+		return errno;
+	}
+	closedir(dir);
+
+	/* shut down services */
+	do_shutdown_services(s);
+	/* start services */
+	do_start_services(s);
+	/* unbusy */
+	s->flags &= ~SD_BUSY;
+	return 0;
+}
+
+int
+enit_manage(struct servicedir* s, const char* mdir) {
+	struct stat sbuf;
+
+	char* lastslash	= NULL;
+	char* parentdir = NULL;
+	char* dir	= NULL;
+
+	if (!mdir) goto onerror;
+
+#ifdef DEBUG_VERBOSE
+	__write2("enit_manage for ");
+	__write2(mdir);
+	__write2("\n");
+#endif
+
+	/* duplicate dir name */
+	dir = strdup(mdir);
+	if (!dir) goto onerror;
+	/* find the last slash */
+	/* TODO: maybe support other dir seperators? */
+	lastslash = strrchr(dir,'/');
+	/* truncate and forget trailing slashes */
+	while (lastslash && (lastslash >= dir + str_len(dir))) {
+		*lastslash = '\0';
+		lastslash = strrchr(dir,'/');
+	}
+	/* no parent dir found? */
+	if (!lastslash) {
+		__write2("You need to give the directory name at least including the parent directory.\n");
+		errno = -ENOENT;
+		goto onerror;
+	}
+
+	/** setup parent monitoring **/
+	/* split at last slash */
+	*lastslash = '\0';
+	parentdir = strdup(dir);
+	*lastslash = '/';
+	/* does parent dir exist */
+	if (stat(parentdir, &sbuf) == -1) {
+		__write2("Parent directory not found.\n");
+		errno = -ENOENT;
+		goto onerror;
+	}
+	/* is this a directory? */
+	if (! S_ISDIR(sbuf.st_mode) ) {
+		__write2("Parent directory not a directory.\n");
+		errno = -EINVAL;
+		goto onerror;
+	}
+
+	/* open the parent dir */
+	s->parentfd = open(parentdir, O_RDONLY);
+	if (!s->parentfd) goto onerror;
+	
+	/** setup real dir fd **/
+	/* does dir exist */
+	if (stat(dir, &sbuf) == -1) {
+		__write2("Given directory not found.\n");
+		errno = -ENOENT;
+		goto onerror;
+	}
+	/* is this a directory? */
+	if (! S_ISDIR(sbuf.st_mode) ) {
+		__write2("Given path not a directory.\n");
+		errno = -EINVAL;
+		goto onerror;
+	}
+
+	/* open the dir */
+	s->dirfd = open(dir, O_RDONLY);
+	if (!s->dirfd) {
+		__write2("Couldn't read directory contents.\n");
+		goto onerror;
+	}
+	/* remember device and inode */
+	s->dirdevice = sbuf.st_dev;
+	s->dirinode  = sbuf.st_ino;
+
+	/* store the dir name */
+	s->parentdir = parentdir;
+	s->dir = dir;
+
+	/* start services */
+	check_dir(s);
+
+	/** setup signalling **/
+	/* use dnotify to monitor parent dir, so we don't have to poll */
+	fcntl(s->parentfd,F_SETSIG, SIGUSR1);
+	fcntl(s->parentfd,F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME | DN_MULTISHOT);
+	/* use dnotify to monitor dir, so we don't have to poll */
+	fcntl(s->dirfd,F_SETSIG, SIGHUP);
+	fcntl(s->dirfd,F_NOTIFY, DN_MODIFY|DN_CREATE|DN_DELETE|DN_RENAME | DN_MULTISHOT);
+
+#ifdef DEBUG_VERBOSE
+	__write2("Finished setup monitoring.\n");
+#endif
+	return 1;
+onerror:
+	if (parentdir) free(parentdir);
+	if (dir) free(dir);
+	if (s->parentfd) close(s->parentfd);
+	if (s->dirfd)    close(s->dirfd);
+	return 0;
+}
+
+void
+usage(char* argv0) {
+	__write2("Usage: ");
+	__write2(argv0);
+	__write2(" <dir>\n");
+	exit(1);
+}
+
+void sighup() {
+#ifdef DEBUG_VERBOSE
+	__write2("SigHUP triggered.\n");
+#endif
+	check_dir(&sd);
+}
+
+void sigusr1() {
+	struct stat sbuf;
+#ifdef DEBUG_VERBOSE
+	__write2("SigUSR1 triggered.\n");
+#endif
+	/* ignore if the parent dir has disappeared */
+	if (stat(sd.dir, &sbuf) == -1) return;
+	if ( (sd.dirdevice != sbuf.st_dev) || (sd.dirinode != sbuf.st_ino)) {
+		sd.dirdevice = sbuf.st_dev; sd.dirinode = sbuf.st_ino;
+		check_dir(&sd);
+	}
+}
+
+void sigterm() {
+	int i;
+	/* assume services have to go down */
+	for (i=0; i < sd.nums; i++)
+		sd.s[i].flags |= SV_GO_DOWN;
+	do_shutdown_services(&sd);
+
+	if (sd.dirfd) { close(sd.dirfd); sd.dirfd = 0; }
+	if (sd.dir) { free(sd.dir); sd.dir = NULL; }
+	if (sd.parentfd) { close(sd.parentfd); sd.parentfd = 0; }
+	if (sd.parentdir) { free(sd.parentdir); sd.parentdir = NULL; }
+	exit(0);
+}
+
+int main(int argc, char **argv) {
+	struct sigaction sa;
+
+	if (argc != 2 || !argv[1])
+		usage(argv[0]);
+
+	/* open minit fifos */
+	minit_infd=open(MINITFIFOS "/in",O_WRONLY);
+	if (!minit_infd) {
+		__write2("Couldn't open minit in fifo.\n");
+		exit(1);
+	}
+
+	/* initialize service dir */
+	memset(&sd,0,sizeof(struct servicedir));
+
+	/* setup signal handling */
+	sa.sa_handler = &sighup;
+	sigemptyset (&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGHUP,&sa, NULL);
+	sa.sa_handler = &sigusr1;
+	sigemptyset (&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGUSR1,&sa, NULL);
+	sa.sa_handler = &sigterm;
+	sigemptyset (&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGTERM,&sa, NULL);
+
+	/* start managing */
+	if (!enit_manage(&sd, argv[1])) {
+		__write2("An error occurred while initiating monitoring '");
+		__write2(argv[1]);
+		__write2("'\n");
+		exit(2);
+	}
+
+	/* sleep 24/7. cool. ;-) */
+	while(1)
+		sleep(7*24*60*60);
+	
+	/* while(true) type "All work and no play makes jack a dull boy" */
+	exit(2);
+}
--- minit-0.9.1.cvs20040208.orig/fcntl-linux.h
+++ minit-0.9.1.cvs20040208/fcntl-linux.h
@@ -0,0 +1,19 @@
+#ifndef _LINUX_FCNTL_H
+/*
+ * Request nofications on a directory.
+ * See below for events that may be notified.
+ */
+#define F_NOTIFY	(F_LINUX_SPECIFIC_BASE+2)
+
+/*
+ * Types of directory notifications that may be requested.
+ */
+#define DN_ACCESS	0x00000001	/* File accessed */
+#define DN_MODIFY	0x00000002	/* File modified */
+#define DN_CREATE	0x00000004	/* File created */
+#define DN_DELETE	0x00000008	/* File removed */
+#define DN_RENAME	0x00000010	/* File renamed */
+#define DN_ATTRIB	0x00000020	/* File changed attibutes */
+#define DN_MULTISHOT	0x80000000	/* Don't remove notifier */
+
+#endif
