From 587051ec679229632d107b24f61d01191f58bc73 Mon Sep 17 00:00:00 2001
From: Roy Marples <roy@marples.name>
Date: Tue, 3 Jun 2008 11:57:15 +0000
Subject: Add the ewaitfile function so init scripts can wait until sockts are
 created, Gentoo #175783.

---
 man/runscript.8     | 15 ++++++++++++---
 src/rc/Makefile     |  2 +-
 src/rc/rc-applets.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 57 insertions(+), 7 deletions(-)

diff --git a/man/runscript.8 b/man/runscript.8
index 6f3bd439..b219e52f 100644
--- a/man/runscript.8
+++ b/man/runscript.8
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd Mar 19, 2008
+.Dd Jun 03, 2008
 .Dt RUNSCRIPT 8 SMM
 .Os OpenRC
 .Sh NAME
@@ -173,8 +173,9 @@ If
 does not equal 0 then output the string using
 .Ic eerror
 and !! in square brackets
-at the end of the line. Otherwise output ok in square brackets at the end of
-the line. The value of
+at the end of the line.
+Otherwise output ok in square brackets at the end of the line.
+The value of
 .Ar retval
 is returned.
 .It Ic ewend Ar retval Op Ar string
@@ -193,6 +194,14 @@ output when the environment variable
 .Va EINFO_VERBOSE
 is true.
 .Bl -tag -width indent
+.It Ic ewaitfile Ar timeout Ar file1 Ar file2 ...
+Wait for
+.Ar timeout
+seconds until all files exist.
+Returns 0 if all files exist, otherwise non zero.
+If
+.Ar timeout
+is less then 1 then we wait indefinitely.
 .It Ic is_newer_than Ar file1 Ar file2 ...
 If
 .Ar file1
diff --git a/src/rc/Makefile b/src/rc/Makefile
index 17d63308..206d66b8 100644
--- a/src/rc/Makefile
+++ b/src/rc/Makefile
@@ -13,7 +13,7 @@ LINKDIR=	${PREFIX}/${LIBNAME}/${PROG}
 BINLINKS=	rc-status
 SBINLINKS=	rc-service rc-update runscript start-stop-daemon
 RC_BINLINKS=	einfon einfo ewarnn ewarn eerrorn eerror ebegin eend ewend \
-		eindent eoutdent esyslog eval_ecolors \
+		eindent eoutdent esyslog eval_ecolors ewaitfile \
 		veinfo vewarn vebegin veend vewend veindent veoutdent \
 		service_starting service_started \
 		service_stopping service_stopped \
diff --git a/src/rc/rc-applets.c b/src/rc/rc-applets.c
index 60c0c272..1649fb86 100644
--- a/src/rc/rc-applets.c
+++ b/src/rc/rc-applets.c
@@ -51,6 +51,10 @@
 #include "einfo.h"
 #include "rc-misc.h"
 
+/* usecs to wait while we poll the file existance  */
+#define WAIT_INTERVAL	20000000
+#define ONE_SECOND      690000000
+
 /* Applet is first parsed in rc.c - no point in doing it again */
 extern const char *applet;
 
@@ -77,6 +81,8 @@ static int do_e(int argc, char **argv)
 	char *p;
 	int level = 0;
 	const char *fmt = "%s";
+	struct timespec ts;
+	struct timeval stop, now;
 
 	/* Punt applet */
 	argc--;
@@ -97,11 +103,14 @@ static int do_e(int argc, char **argv)
 		if (strcmp(applet, "eend") == 0 ||
 		    strcmp(applet, "ewend") == 0 ||
 		    strcmp(applet, "veend") == 0 ||
-		    strcmp(applet, "vweend") == 0)
+		    strcmp(applet, "vweend") == 0 ||
+		    strcmp(applet, "ewaitfile") == 0)
 		{
 			errno = 0;
-			retval = (int) strtoimax(argv[0], NULL, 0);
-			if (errno != 0)
+			retval = (int)strtoimax(argv[0], &p, 0);
+			if (!p || *p != '\0')
+				errno = EINVAL;
+			if (errno)
 				retval = EXIT_FAILURE;
 			else {
 				argc--;
@@ -124,6 +133,38 @@ static int do_e(int argc, char **argv)
 		}
 	}
 
+	if (strcmp(applet, "ewaitfile") == 0) {
+		if (errno)
+			eerrorx("%s: invalid timeout", applet);
+		if (argc == 0)
+			eerrorx("%s: not enough arguments", applet);
+
+		gettimeofday(&stop, NULL);
+		/* retval stores the timeout */
+		stop.tv_sec += retval;
+		ts.tv_sec = 0;
+		ts.tv_nsec = WAIT_INTERVAL;
+		for (i = 0; i < argc; i++) {
+			ebeginv("Waiting for %s", argv[i]);
+			for (;;){
+				if (exists(argv[i]))
+					break;
+				if (nanosleep(&ts, NULL) == -1)
+					return EXIT_FAILURE;
+				gettimeofday(&now, NULL);
+				if (retval <= 0)
+					continue;
+				if (timercmp(&now, &stop, <))
+					continue;
+				eendv(EXIT_FAILURE,
+				      "timed out waiting for %s", argv[i]);
+				return EXIT_FAILURE;
+			}
+			eendv(EXIT_SUCCESS, NULL);
+		}
+		return EXIT_SUCCESS;
+	}
+
 	if (argc > 0) {
 		for (i = 0; i < argc; i++)
 			l += strlen(argv[i]) + 1;
-- 
cgit v1.2.3