[klibc] [PATCH v3 1/2] kinit: Add run_parts()

Mike Waychison mikew at google.com
Wed Aug 3 12:38:22 PDT 2011


This patch implements support for executing files present in drop
directories.  This is implemented by a new function called run_parts,
which takes the name of the base drop-directory to search for scripts.

It is implemented by simply doing a single-depth search for files
present in the directory using scandir().  It then will synchronously
execute each file in order.  Failure to execute anything that looks like
a file is treated as a fatal error, which should be easy to catch as
these directories are essentially configuration directories and failure
to execute should be immediately visible to developers.

run_parts() is available as a standalone binary named run-parts, which
for the moment only ever accepts a single argument, the directory to
search for parts to run.

Signed-off-by: Mike Waychison <mikew at google.com>
---
 usr/kinit/Kbuild                |   11 ++-
 usr/kinit/kinit.h               |    2 +
 usr/kinit/run-parts/Kbuild      |   22 +++++++
 usr/kinit/run-parts/run-parts.c |  125 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 155 insertions(+), 5 deletions(-)
 create mode 100644 usr/kinit/run-parts/Kbuild
 create mode 100644 usr/kinit/run-parts/run-parts.c

diff --git a/usr/kinit/Kbuild b/usr/kinit/Kbuild
index ff1d449..849cb02 100644
--- a/usr/kinit/Kbuild
+++ b/usr/kinit/Kbuild
@@ -16,6 +16,7 @@ kinit-y  += nfsmount/
 kinit-y  += run-init/
 kinit-y  += fstype/
 kinit-y  += resume/
+kinit-y  += run-parts/
 
 static-y := kinit
 shared-y := kinit.shared
@@ -24,14 +25,14 @@ kinit.shared-y := $(kinit-y)
 # Additional include paths files
 KLIBCCFLAGS += -I$(srctree)/$(src)/fstype \
 	       -I$(srctree)/$(src)/ipconfig \
-  	       -I$(srctree)/$(src)/nfsmount \
-  	       -I$(srctree)/$(src)/resume \
- 	       -I$(srctree)/$(src)/run-init
+	       -I$(srctree)/$(src)/nfsmount \
+	       -I$(srctree)/$(src)/resume \
+	       -I$(srctree)/$(src)/run-init \
+	       -I$(srctree)/$(src)/run-parts \
 
 # Cleaning
 targets += kinit kinit.g kinit.shared kinit.shared.g
-subdir- := fstype ipconfig nfsmount resume run-init
-
+subdir- := fstype ipconfig nfsmount resume run-init run-parts
 
 # install binary
 install-y := kinit kinit.shared
diff --git a/usr/kinit/kinit.h b/usr/kinit/kinit.h
index c2e67b7..a7a101e 100644
--- a/usr/kinit/kinit.h
+++ b/usr/kinit/kinit.h
@@ -65,4 +65,6 @@ static inline void dump_args(int argc, char *argv[])
 }
 #endif
 
+void run_parts(const char *, int, char **);
+
 #endif				/* KINIT_H */
diff --git a/usr/kinit/run-parts/Kbuild b/usr/kinit/run-parts/Kbuild
new file mode 100644
index 0000000..9d16a9e
--- /dev/null
+++ b/usr/kinit/run-parts/Kbuild
@@ -0,0 +1,22 @@
+#
+# Kbuild file for run-parts
+#
+
+static-y := static/run-parts
+shared-y := shared/run-parts
+
+# common .o files
+objs := run-parts.o
+
+# Create built-in.o with all object files (used by kinit)
+lib-y := $(objs)
+
+# .o files used to built executables
+static/run-parts-y := $(objs)
+shared/run-parts-y := $(objs)
+
+# Cleaning
+clean-dirs := static shared
+
+# install binary
+install-y := $(shared-y)
diff --git a/usr/kinit/run-parts/run-parts.c b/usr/kinit/run-parts/run-parts.c
new file mode 100644
index 0000000..4201d19
--- /dev/null
+++ b/usr/kinit/run-parts/run-parts.c
@@ -0,0 +1,125 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int is_file(const struct dirent *dirent)
+{
+	return (dirent->d_type == DT_REG);
+}
+
+static void run_part(const char *basepath, const char *filename,
+		     int cmdc, char **cmdv)
+{
+	char *fullpath;
+	char **args;
+	pid_t pid;
+	int status;
+	int ret;
+	int i;
+
+	/* Figure out fullpath */
+	fullpath = malloc(strlen(basepath) + strlen(filename) + 2);
+	if (!fullpath) {
+		fprintf(stderr, "Ran out of memory!\n");
+		exit(1);
+	}
+	sprintf(fullpath, "%s/%s", basepath, filename);
+
+	/* Prepare args for call */
+	args = malloc(sizeof(*args) * (cmdc + 2)); /* NULL + ARGV[0} */
+	if (!args) {
+		fprintf(stderr, "Ran out of memory!\n");
+		free(fullpath);
+		exit(1);
+	}
+	args[0] = fullpath;
+	for (i = 0; i < cmdc; i++)
+		args[i + 1] = cmdv[i];
+	args[cmdc + 1] = NULL;
+
+	/* Run the child */
+	pid = fork();
+	if (pid == -1) {
+		fprintf(stderr, "Failed to fork in run-parts(%s)\n",
+			basepath);
+		exit(1);
+	}
+	if (pid == 0) {
+		/* Child */
+		execv(fullpath, args);
+		fprintf(stderr, "Failed to exec %s: %s\n", fullpath,
+			strerror(errno));
+		exit(1);
+	}
+
+	/* Parent */
+	while (1) {
+		ret = waitpid(pid, &status, 0);
+		if (ret == pid)
+			break;
+		if (ret == -1 && errno == EINTR)
+			continue;
+		fprintf(stderr, "failed to wait on child: ret=%d errno=%d\n",
+			ret, errno);
+		exit(1);
+	}
+
+	if (WIFEXITED(status)) {
+		if (WEXITSTATUS(status) != 0)
+			fprintf(stderr, "%s exited with status: %d\n",
+				fullpath, WEXITSTATUS(status));
+	} else if (WIFSIGNALED(status)) {
+		fprintf(stderr, "%s terminated by signal %d\n",
+			fullpath, WTERMSIG(status));
+	} else {
+		fprintf(stderr, "Failed to understand status code 0x%x\n",
+			status);
+	}
+
+	free(args);
+	free(fullpath);
+}
+
+void run_parts(const char *basepath, int cmdc, char **cmdv)
+{
+	struct dirent **namelist;
+	int i;
+	int count;
+
+	count = scandir(basepath, &namelist, is_file, alphasort);
+	if (count < 0) {
+		if (errno == ENOENT)
+			return;
+		fprintf(stderr, "WARNING: could not run-parts(%s): %s\n",
+			basepath, strerror(errno));
+		return;
+	}
+
+	for (i = 0; i < count; i++) {
+		run_part(basepath, namelist[i]->d_name, cmdc, cmdv);
+		free(namelist[i]);
+	}
+	free(namelist);
+}
+
+int main(int argc, char *argv[])
+    __attribute__ ((weak, alias("run_parts_main")));
+
+static int run_parts_main(int argc, char **argv)
+{
+	if (argc != 2) {
+		fprintf(stderr, "usage: run-parts DIRECTORY\n");
+		return EXIT_FAILURE;
+	}
+
+	/* TODO: Handle --arg and build an argument vector. */
+
+	run_parts(argv[1], 0, NULL);
+
+	return EXIT_SUCCESS;
+}



More information about the klibc mailing list