From 0084bc41ef5db968cac0f64ae9d0b31dc7621818 Mon Sep 17 00:00:00 2001
From: Roy Marples <roy@marples.name>
Date: Thu, 9 Aug 2007 14:33:20 +0000
Subject: Don't link to rt anymore as it makes dlopen leak - we now use
 nanosleeps to achieve the same goal (a loop + timeout). No longer put / at
 the end of directories, instead prefix like so RC_LIBDIR "/foo" to ensure
 more robust code.

---
 src/Makefile            |  1 -
 src/librc-depend.c      | 22 ++++++------
 src/librc-misc.c        | 45 +++++++++++++-----------
 src/librc.c             | 59 ++++++++++---------------------
 src/librc.h             |  1 -
 src/rc-misc.h           | 26 +++++++-------
 src/rc-plugin.c         |  4 +--
 src/rc.c                | 13 +++----
 src/rc.h                |  1 +
 src/runscript.c         | 19 +++++-----
 src/start-stop-daemon.c | 93 ++++++++++++++++++-------------------------------
 11 files changed, 119 insertions(+), 165 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index 5c50cfd4..dc6d86f5 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -70,7 +70,6 @@ endif
 ifeq ($(OS),Linux)
 LDLIBS_RC = -ldl
 LDLIBS_RS = -ldl
-LDLIBS_SSD = -lrt
 # Shouldn't need this, but it's the easiest workaround for silly
 # Linux headers that don't work with -std=c99
 override CPPFLAGS += -D_GNU_SOURCE
diff --git a/src/librc-depend.c b/src/librc-depend.c
index c8dfd02a..b51fc3cb 100644
--- a/src/librc-depend.c
+++ b/src/librc-depend.c
@@ -582,17 +582,17 @@ static const deppair_t deppairs[] = {
 
 static const char *depdirs[] =
 {
-	RC_SVCDIR "starting",
-	RC_SVCDIR "started",
-	RC_SVCDIR "stopping",
-	RC_SVCDIR "inactive",
-	RC_SVCDIR "wasinactive",
-	RC_SVCDIR "failed",
-	RC_SVCDIR "coldplugged",
-	RC_SVCDIR "daemons",
-	RC_SVCDIR "options",
-	RC_SVCDIR "exclusive",
-	RC_SVCDIR "scheduled",
+	RC_SVCDIR "/starting",
+	RC_SVCDIR "/started",
+	RC_SVCDIR "/stopping",
+	RC_SVCDIR "/inactive",
+	RC_SVCDIR "/wasinactive",
+	RC_SVCDIR "/failed",
+	RC_SVCDIR "/coldplugged",
+	RC_SVCDIR "/daemons",
+	RC_SVCDIR "/options",
+	RC_SVCDIR "/exclusive",
+	RC_SVCDIR "/scheduled",
 	NULL
 };
 
diff --git a/src/librc-misc.c b/src/librc-misc.c
index b52c2507..2aee5d43 100644
--- a/src/librc-misc.c
+++ b/src/librc-misc.c
@@ -9,11 +9,11 @@
 #define ERRX            eerrorx("out of memory");
 
 #define PROFILE_ENV     "/etc/profile.env"
-#define SYS_WHITELIST   RC_LIBDIR "conf.d/env_whitelist"
+#define SYS_WHITELIST   RC_LIBDIR "/conf.d/env_whitelist"
 #define USR_WHITELIST   "/etc/conf.d/env_whitelist"
 #define RC_CONFIG       "/etc/conf.d/rc"
 
-#define PATH_PREFIX     RC_LIBDIR "bin:/bin:/sbin:/usr/bin:/usr/sbin"
+#define PATH_PREFIX     RC_LIBDIR "/bin:/bin:/sbin:/usr/bin:/usr/sbin"
 
 #ifndef S_IXUGO
 # define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
@@ -95,30 +95,33 @@ char *rc_strcatpaths (const char *path1, const char *paths, ...)
 	if (! path1 || ! paths)
 		return (NULL);
 
-	length = strlen (path1) + strlen (paths) + 3;
-	i = 0;
+	length = strlen (path1) + strlen (paths) + 1;
+	if (*paths != '/')
+		length ++;
+
 	va_start (ap, paths);
-	while ((p = va_arg (ap, char *)) != NULL)
-		length += strlen (p) + 1;
+	while ((p = va_arg (ap, char *)) != NULL) {
+		if (*p != '/')
+			length ++;
+		length += strlen (p);
+	}
 	va_end (ap);
 
-	path = rc_xmalloc (length);
+	pathp = path = rc_xmalloc (length * sizeof (char *));
 	memset (path, 0, length);
-	memcpy (path, path1, strlen (path1));
-	pathp = path + strlen (path1) - 1;
-	if (*pathp != '/') {
-		pathp++;
-		*pathp++ = '/';
-	}
-	else
-		pathp++;
-	memcpy (pathp, paths, strlen (paths));
-	pathp += strlen (paths);
+	i = strlen (path1);
+	memcpy (path, path1, i);
+	pathp += i;
+	if (*paths != '/')
+		*pathp ++ = '/';
+	i = strlen (paths);
+	memcpy (pathp, paths, i);
+	pathp += i;
 
 	va_start (ap, paths);
 	while ((p = va_arg (ap, char *)) != NULL) {
-		if (*pathp != '/')
-			*pathp++ = '/';
+		if (*p != '/')
+			*pathp ++= '/';
 		i = strlen (p);
 		memcpy (pathp, p, i);
 		pathp += i;
@@ -615,14 +618,14 @@ char **rc_config_env (char **env)
 	rc_strlist_free (config);
 
 	/* One char less to drop the trailing / */
-	i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR);
+	i = strlen ("RC_LIBDIR=") + strlen (RC_LIBDIR) + 1;
 	line = rc_xmalloc (sizeof (char *) * i);
 	snprintf (line, i, "RC_LIBDIR=" RC_LIBDIR);
 	env = rc_strlist_add (env, line);
 	free (line);
 
 	/* One char less to drop the trailing / */
-	i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR);
+	i = strlen ("RC_SVCDIR=") + strlen (RC_SVCDIR) + 1;
 	line = rc_xmalloc (sizeof (char *) * i);
 	snprintf (line, i, "RC_SVCDIR=" RC_SVCDIR);
 	env = rc_strlist_add (env, line);
diff --git a/src/librc.c b/src/librc.c
index 5b815720..9b48b6bb 100644
--- a/src/librc.c
+++ b/src/librc.c
@@ -8,12 +8,12 @@
 #include "librc.h"
 
 /* usecs to wait while we poll the fifo */
-#define WAIT_INTERVAL	20000
+#define WAIT_INTERVAL	20000000
 
-/* max secs to wait until a service comes up */
-#define WAIT_MAX	60
+/* max nsecs to wait until a service comes up */
+#define WAIT_MAX	60000000000
 
-#define SOFTLEVEL	RC_SVCDIR "softlevel"
+#define SOFTLEVEL	RC_SVCDIR "/softlevel"
 
 /* File stream used for plugins to write environ vars to */
 FILE *rc_environ_fd = NULL;
@@ -33,13 +33,13 @@ static const char *rc_service_state_names[] = {
 
 bool rc_runlevel_starting (void)
 {
-	return (rc_is_dir (RC_SVCDIR "softscripts.old"));
+	return (rc_is_dir (RC_SVCDIR "/softscripts.old"));
 }
 librc_hidden_def(rc_runlevel_starting)
 
 bool rc_runlevel_stopping (void)
 {
-	return (rc_is_dir (RC_SVCDIR "softscripts.new"));
+	return (rc_is_dir (RC_SVCDIR "/softscripts.new"));
 }
 librc_hidden_def(rc_runlevel_stopping)
 
@@ -142,7 +142,7 @@ char *rc_resolve_service (const char *service)
 			return (rc_xstrdup (buffer));
 	}
 
-	snprintf (buffer, sizeof (buffer), RC_INITDIR "%s", service);
+	snprintf (buffer, sizeof (buffer), RC_INITDIR "/%s", service);
 	return (strdup (buffer));
 }
 librc_hidden_def(rc_resolve_service)
@@ -639,32 +639,13 @@ void rc_schedule_clear (const char *service)
 }
 librc_hidden_def(rc_schedule_clear)
 
-static time_t get_uptime(void)
-{
-#ifdef __linux__
-	struct sysinfo info;
-
-	sysinfo (&info);
-	return (time_t) info.uptime;
-#else
-	struct timespec tp;
-
-	if (clock_gettime (CLOCK_MONOTONIC, &tp) == -1) {
-		eerror ("clock_gettime: %s", strerror (errno));
-		return -1;
-	}
-
-	return tp.tv_sec;
-#endif
-}
-
 bool rc_wait_service (const char *service)
 {
 	char *svc;
 	char *base;
 	char *fifo;
-	struct timeval tv;
-	time_t start = get_uptime ();
+	struct timespec ts;
+	int nloops = WAIT_MAX / WAIT_INTERVAL;
 	bool retval = false;
 	bool forever = false;
 
@@ -680,26 +661,24 @@ bool rc_wait_service (const char *service)
 		forever = true;
 	free (svc);
 
-	while (true) {
+	ts.tv_sec = 0;
+	ts.tv_nsec = WAIT_INTERVAL;
+
+	while (nloops) {
 		if (! rc_exists (fifo)) {
 			retval = true;
 			break;
 		}
 
-		tv.tv_sec = 0;
-		tv.tv_usec = WAIT_INTERVAL;
-		if (select (0, 0, 0, 0, &tv) < 0) {
+		if (nanosleep (&ts, NULL) == -1) {
 			if (errno != EINTR) {
-				eerror ("select: %s",strerror (errno));
+				eerror ("nanosleep: %s", strerror (errno));
 				break;
 			}
 		}
 
-		if (! forever) {
-			time_t now = get_uptime();
-			if (now - start > WAIT_MAX)
-				break;
-		}
+		if (! forever)
+			nloops --;
 	}
 
 	free (fifo);
@@ -819,13 +798,13 @@ librc_hidden_def(rc_service_delete)
 
 char **rc_services_scheduled_by (const char *service)
 {
-	char **dirs = rc_ls_dir (NULL, RC_SVCDIR "scheduled", 0);
+	char **dirs = rc_ls_dir (NULL, RC_SVCDIR "/scheduled", 0);
 	char **list = NULL;
 	char *dir;
 	int i;
 
 	STRLIST_FOREACH (dirs, dir, i) {
-		char *file = rc_strcatpaths (RC_SVCDIR "scheduled", dir, service,
+		char *file = rc_strcatpaths (RC_SVCDIR, "scheduled", dir, service,
 									 (char *) NULL);
 		if (rc_exists (file))
 			list = rc_strlist_add (list, file);
diff --git a/src/librc.h b/src/librc.h
index ec126aba..6118f48b 100644
--- a/src/librc.h
+++ b/src/librc.h
@@ -8,7 +8,6 @@
 #ifndef _LIBRC_H_
 #define _LIBRC_H_
 
-#include <sys/select.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
diff --git a/src/rc-misc.h b/src/rc-misc.h
index 20dc74f7..6ffc868f 100644
--- a/src/rc-misc.h
+++ b/src/rc-misc.h
@@ -11,19 +11,19 @@
 #  define LIB "lib"
 #endif
 
-#define RC_LIBDIR	"/" LIB "/rcscripts/"
-#define RC_SVCDIR	RC_LIBDIR "init.d/"
-#define RC_DEPTREE 	RC_SVCDIR "deptree"
-#define RC_RUNLEVELDIR 	"/etc/runlevels/"
-#define RC_INITDIR	"/etc/init.d/"
-#define RC_CONFDIR	"/etc/conf.d/"
-
-#define RC_SVCDIR_STARTING	RC_SVCDIR "starting/"
-#define RC_SVCDIR_INACTIVE	RC_SVCDIR "inactive/"
-#define RC_SVCDIR_STARTED	RC_SVCDIR "started/"
-#define RC_SVCDIR_COLDPLUGGED	RC_SVCDIR "coldplugged/"
-
-#define RC_PLUGINDIR	RC_LIBDIR "plugins/"
+#define RC_LIBDIR	"/" LIB "/rcscripts"
+#define RC_SVCDIR	RC_LIBDIR "/init.d"
+#define RC_DEPTREE 	RC_SVCDIR "/deptree"
+#define RC_RUNLEVELDIR 	"/etc/runlevels"
+#define RC_INITDIR	"/etc/init.d"
+#define RC_CONFDIR	"/etc/conf.d"
+
+#define RC_SVCDIR_STARTING	RC_SVCDIR "/starting"
+#define RC_SVCDIR_INACTIVE	RC_SVCDIR "/inactive"
+#define RC_SVCDIR_STARTED	RC_SVCDIR "/started"
+#define RC_SVCDIR_COLDPLUGGED	RC_SVCDIR "/coldplugged"
+
+#define RC_PLUGINDIR	RC_LIBDIR "/plugins"
 
 /* Max buffer to read a line from a file */
 #define RC_LINEBUFFER	4096 
diff --git a/src/rc-plugin.c b/src/rc-plugin.c
index d8db975a..1103e469 100644
--- a/src/rc-plugin.c
+++ b/src/rc-plugin.c
@@ -8,6 +8,7 @@
 #include <dlfcn.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -69,9 +70,9 @@ void rc_plugin_load (void)
 		int (*fptr) (rc_hook_t, const char *); 
 		int len;
 
+		free (p);
 		if (! h) {
 			eerror ("dlopen: %s", dlerror ());
-			free (p);
 			continue;
 		}
 
@@ -99,7 +100,6 @@ void rc_plugin_load (void)
 		}
 
 		free (func);
-		free (p);
 	}
 
 	rc_strlist_free (files);
diff --git a/src/rc.c b/src/rc.c
index f7c4f98a..c8bbb2e9 100644
--- a/src/rc.c
+++ b/src/rc.c
@@ -37,17 +37,12 @@
 #include "rc-plugin.h"
 #include "strlist.h"
 
-#define INITSH                  RC_LIBDIR "sh/init.sh"
-#define INITEARLYSH             RC_LIBDIR "sh/init-early.sh"
-#define HALTSH                  RC_INITDIR "halt.sh"
+#define INITSH                  RC_LIBDIR "/sh/init.sh"
+#define INITEARLYSH             RC_LIBDIR "/sh/init-early.sh"
+#define HALTSH                  RC_INITDIR "/halt.sh"
 #define SULOGIN                 "/sbin/sulogin"
 
-#define RC_SVCDIR_STARTING      RC_SVCDIR "starting/"
-#define RC_SVCDIR_INACTIVE      RC_SVCDIR "inactive/"
-#define RC_SVCDIR_STARTED       RC_SVCDIR "started/"
-#define RC_SVCDIR_COLDPLUGGED   RC_SVCDIR "coldplugged/"
-
-#define INTERACTIVE             RC_SVCDIR "interactive"
+#define INTERACTIVE             RC_SVCDIR "/interactive"
 
 #define DEVBOOT					"/dev/.rcboot"
 
diff --git a/src/rc.h b/src/rc.h
index 9920901c..829f8b95 100644
--- a/src/rc.h
+++ b/src/rc.h
@@ -19,6 +19,7 @@
 
 #include <sys/types.h>
 #include <stdbool.h>
+#include <stdio.h>
 
 /* Special level names */
 #define RC_LEVEL_SYSINIT    "sysinit"
diff --git a/src/runscript.c b/src/runscript.c
index 14d3c7bf..20e7561d 100644
--- a/src/runscript.c
+++ b/src/runscript.c
@@ -8,6 +8,7 @@
 
 #define APPLET "runscript"
 
+#include <sys/select.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/stat.h>
@@ -81,8 +82,10 @@ static void setup_selinux (int argc, char **argv)
 		return;
 	}
 
-	selinux_run_init_old = (void (*)(void)) dlfunc (lib_handle, "selinux_runscript");
-	selinux_run_init_new = (void (*)(int, char **)) dlfunc (lib_handle, "selinux_runscript2");
+	selinux_run_init_old = (void (*)(void))
+		dlfunc (lib_handle, "selinux_runscript");
+	selinux_run_init_new = (void (*)(int, char **))
+		dlfunc (lib_handle, "selinux_runscript2");
 
 	/* Use new run_init if it rc_exists, else fall back to old */
 	if (selinux_run_init_new)
@@ -198,7 +201,7 @@ static bool in_control ()
 
 static void uncoldplug ()
 {
-	char *cold = rc_strcatpaths (RC_SVCDIR "coldplugged", applet, (char *) NULL);
+	char *cold = rc_strcatpaths (RC_SVCDIR, "coldplugged", applet, (char *) NULL);
 	if (rc_exists (cold) && unlink (cold) != 0)
 		eerror ("%s: unlink `%s': %s", applet, cold, strerror (errno));
 	free (cold);
@@ -368,16 +371,16 @@ static bool svc_exec (const char *arg1, const char *arg2)
 				eerror ("fcntl: %s", strerror (errno));
 		}
 
-		if (rc_exists (RC_SVCDIR "runscript.sh")) {
-			execl (RC_SVCDIR "runscript.sh", service, service, arg1, arg2,
+		if (rc_exists (RC_SVCDIR "/runscript.sh")) {
+			execl (RC_SVCDIR "/runscript.sh", service, service, arg1, arg2,
 				   (char *) NULL);
-			eerror ("%s: exec `" RC_SVCDIR "runscript.sh': %s",
+			eerror ("%s: exec `" RC_SVCDIR "/runscript.sh': %s",
 					service, strerror (errno));
 			_exit (EXIT_FAILURE);
 		} else {
-			execl (RC_LIBDIR "sh/runscript.sh", service, service, arg1, arg2,
+			execl (RC_LIBDIR "/sh/runscript.sh", service, service, arg1, arg2,
 				   (char *) NULL);
-			eerror ("%s: exec `" RC_LIBDIR "sh/runscript.sh': %s",
+			eerror ("%s: exec `" RC_LIBDIR "/sh/runscript.sh': %s",
 					service, strerror (errno));
 			_exit (EXIT_FAILURE);
 		}
diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c
index 05325dfb..ddf55e25 100644
--- a/src/start-stop-daemon.c
+++ b/src/start-stop-daemon.c
@@ -9,8 +9,10 @@
    system so we can monitor daemons a little.
    */
 
-#define POLL_INTERVAL 20000
-#define START_WAIT    100000
+/* nano seconds */
+#define POLL_INTERVAL   20000000
+#define START_WAIT     100000000
+#define ONE_SECOND    1000000000
 
 #include <sys/types.h>
 #include <sys/ioctl.h>
@@ -92,20 +94,6 @@ static void cleanup (void)
 		rc_strlist_free (newenv);
 }
 
-static int get_time(struct timeval *tp)
-{
-	struct timespec ts;
-
-	if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1) {
-		eerror ("clock_gettime: %s", strerror (errno));
-		return (-1);
-	}
-
-	tp->tv_sec = ts.tv_sec;
-	tp->tv_usec = ts.tv_nsec / 1000;
-	return (0);
-}
-
 static int parse_signal (const char *sig)
 {
 	typedef struct signalpair
@@ -347,9 +335,8 @@ static int run_stop_schedule (const char *exec, const char *cmd,
 	int nkilled = 0;
 	int tkilled = 0;
 	int nrunning = 0;
-	struct timeval tv;
-	struct timeval now;
-	struct timeval stopat;
+	long nloops;
+	struct timespec ts;
 
 	if (verbose) {
 		if (pidfile)
@@ -390,30 +377,24 @@ static int run_stop_schedule (const char *exec, const char *cmd,
 					break;
 				}
 
-				if (get_time (&stopat) != 0)
-					return (0);
+				nloops = (ONE_SECOND / POLL_INTERVAL) * item->value;
+				ts.tv_sec = 0;
+				ts.tv_nsec = POLL_INTERVAL;
 
-				stopat.tv_sec += item->value;
-				while (1) {
+				while (nloops) {
 					if ((nrunning = do_stop (exec, cmd, pidfile,
 											 uid, 0, true, false, true)) == 0)
 						return (true);
 
-					tv.tv_sec = 0;
-					tv.tv_usec = POLL_INTERVAL;
-					if (select (0, 0, 0, 0, &tv) < 0) {
+					if (nanosleep (&ts, NULL) == -1) {
 						if (errno == EINTR)
 							eerror ("%s: caught an interupt", progname);
 						else {
-							eerror ("%s: select: %s", progname, strerror (errno));
+							eerror ("%s: nanosleep: %s", progname, strerror (errno));
 							return (0);
 						}
 					}
-
-					if (get_time (&now) != 0)
-						return (0);
-					if (timercmp (&now, &stopat, >))
-						break;
+					nloops --;
 				}
 				break;
 
@@ -538,7 +519,6 @@ int start_stop_daemon (int argc, char **argv)
 	int stdout_fd;
 	int stderr_fd;
 	pid_t pid;
-	struct timeval tv;
 	int i;
 	char *svcname = getenv ("SVCNAME");
 	char *env;
@@ -733,7 +713,7 @@ int start_stop_daemon (int argc, char **argv)
 	argc -= optind;
 	argv += optind;
 
-	/* Validate that the binary rc_exists if we are starting */
+	/* Validate that the binary exists if we are starting */
 	if (exec && start) {
 		char *tmp;
 		if (ch_root)
@@ -893,14 +873,14 @@ int start_stop_daemon (int argc, char **argv)
 		/* Clean the environment of any RC_ variables */
 		STRLIST_FOREACH (environ, env, i)
 			if (env && strncmp (env, "RC_", 3) != 0) {
-				/* For the path character, remove the rcscript bin dir from it */
-				if (strncmp (env, "PATH=" RC_LIBDIR "bin:",
-							 strlen ("PATH=" RC_LIBDIR "bin:")) == 0)
+				/* For the path r, remove the rcscript bin dir from it */
+				if (strncmp (env, "PATH=" RC_LIBDIR "/bin:",
+							 strlen ("PATH=" RC_LIBDIR "/bin:")) == 0)
 				{
 					char *path = env;
 					char *newpath;
 					int len;
-					path += strlen ("PATH=" RC_LIBDIR "bin:");
+					path += strlen ("PATH=" RC_LIBDIR "/bin:");
 					len = sizeof (char *) * strlen (path) + 6;
 					newpath = rc_xmalloc (len);
 					snprintf (newpath, len, "PATH=%s", path);
@@ -974,24 +954,24 @@ int start_stop_daemon (int argc, char **argv)
 	/* Wait a little bit and check that process is still running
 	   We do this as some badly written daemons fork and then barf */
 	if (START_WAIT > 0) {
-		struct timeval stopat;
-		struct timeval now;
+		struct timespec ts;
+		int nloops = START_WAIT / POLL_INTERVAL;
+		bool alive = false;
 		bool retestpid = false;
-
-		if (get_time (&stopat) != 0)
-			exit (EXIT_FAILURE);
-
-		stopat.tv_usec += START_WAIT;
-		while (1) {
-			bool alive = false;
-
-			tv.tv_sec = 0;
-			tv.tv_usec = POLL_INTERVAL;
-			if (select (0, 0, 0, 0, &tv) < 0) {
-				/* Let our signal handler handle the interupt */
-				if (errno != EINTR)
-					eerrorx ("%s: select: %s", progname, strerror (errno));
+		
+		ts.tv_sec = 0;
+		ts.tv_nsec = POLL_INTERVAL;
+
+		while (nloops) {
+			if (nanosleep (&ts, NULL) == -1) {
+				if (errno == EINTR)
+					eerror ("%s: caught an interupt", progname);
+				else {
+					eerror ("%s: nanosleep: %s", progname, strerror (errno));
+					return (0);
+				}
 			}
+			nloops --;
 
 			/* This is knarly.
 			   If we backgrounded then we know the exact pid.
@@ -1023,11 +1003,6 @@ int start_stop_daemon (int argc, char **argv)
 
 			if (! alive)
 				eerrorx ("%s: %s died", progname, exec);
-
-			if (get_time (&now) != 0)
-				exit (EXIT_FAILURE);
-			if (timercmp (&now, &stopat, >)) 
-				break;
 		}
 
 		if (retestpid) {
-- 
cgit v1.2.3