From ec10a5eeb4ad9b8f681b5b8217885f788c2e2354 Mon Sep 17 00:00:00 2001
From: Morris Jette <jette@schedmd.com>
Date: Wed, 18 Jan 2012 14:20:31 -0800
Subject: [PATCH] Modify sbatch to read env vars from open file

---
 doc/man/man1/sbatch.1 | 18 ++++++----
 src/common/env.c      | 81 +++++++++++++++++++++++++------------------
 src/sbatch/opt.c      |  4 +--
 3 files changed, 61 insertions(+), 42 deletions(-)

diff --git a/doc/man/man1/sbatch.1 b/doc/man/man1/sbatch.1
index 44aa023829d..61dbfa723b1 100644
--- a/doc/man/man1/sbatch.1
+++ b/doc/man/man1/sbatch.1
@@ -376,13 +376,17 @@ option will implicitly be set to load other environment variables based upon
 the user's configuration on the cluster which executes the job.
 
 .TP
-\fB\-\-export\-file\fR=<\filename\fR>
-Export environment variables defined in <\filename\fR> to the job's
-execution environment. The file contains one or more environemnt
-variable definitions of the form NAME=VALUE spearated by a null
-character to allow the use of special characters in environment
-definitions. The \fB\-\-get\-user\-env\fR option will be ignored if
-\-\-export\-file is defined.
+\fB\-\-export\-file\fR=<\fIfilename\fR | \fIpipe_fd\fR>
+If a number between 3 and OPEN_MAX is specified as the argument to
+this option, a pipe's read file descriptor will be assumed (STDIN and
+STDOUT are not supported as valid arguments).  Otherwise a filename is
+assumed.  Export environment variables defined in <\fIfilename\fR> or
+read from <\fIpipe_fd\fR> to the job's execution environment. The
+content is one or more environment variable definitions of the form
+NAME=value, each separated by a null character.  This allows the use
+of special characters in environment definitions. The
+\fB\-\-get\-user\-env\fR option will be ignored if \-\-export\-file is
+defined.
 
 .TP
 \fB\-F\fR, \fB\-\-nodefile\fR=<\fInode file\fR>
diff --git a/src/common/env.c b/src/common/env.c
index fec09c98845..529f1af4950 100644
--- a/src/common/env.c
+++ b/src/common/env.c
@@ -1580,13 +1580,13 @@ static int _bracket_cnt(char *value)
 	return count;
 }
 
-/* 
- * Load user environment from a specified file.
- * 
- * This will read in a user specified file, that is invoked
- * via the --export-file option in sbatch. This file must
- * have NULL separated line. The NULL character is to allow
- * special characters in the environment definitons.
+/*
+ * Load user environment from a specified file or pipe.
+ *
+ * This will read in a user specified file or pipe, that is invoked
+ * via the --export-file option in sbatch. The NAME=value entries must
+ * be NULL separated to support special characters in the environment
+ * definitions.
  *
  * (Note: This is being added to a minor release. For the
  * next major release, it might be a consideration to merge
@@ -1596,44 +1596,59 @@ static int _bracket_cnt(char *value)
 char **env_array_from_file(const char *fname)
 {
 	char *buf = NULL, *ptr = NULL, *eptr = NULL;
-	char *line, *value;
+	char *line, *value, *p;
 	char **env = NULL;
 	char name[256];
-	struct stat buffer;
-	ssize_t n;
+	int buf_size = BUFSIZ, buf_left;
+	int file_size = 0, tmp_size;
 	int separator = '\0';
-	int file_size = 0;
 	int fd;
 
-	fd = open(fname,O_RDONLY );
-	if (fd == -1) {
-		error("Could not open user environment file at %s",
-			fname);
-		return NULL;
-	}
+	/*
+	 * If file name is a numeric value, then it is assumed to be a pipe.
+	 */
+	fd = (int)strtol(fname, &p, 10);
+	if ((*p != '\0') || (fd < 3) || (fd > sysconf(_SC_OPEN_MAX)) ||
+	    (fcntl(fd, F_GETFL) < 0)) {
+		fd = open(fname, O_RDONLY);
+		if (fd == -1) {
+			error("Could not open user environment file %s", fname);
+			return NULL;
+		}
+		verbose("Getting environment variables from %s", fname);
+	} else
+		verbose("Getting environment variables from pipe %d", fd);
 
 	/*
-	 * Then read in the user's environment file data.
+	 * Read in the user's environment data.
 	 */
-	fstat(fd, &buffer);
-	file_size = buffer.st_size;
-	buf = xmalloc(file_size);
-	if ((n = fd_read_n(fd, buf, file_size)) < 0) {
-		error("Could not read of environment file at %s", fname);
-		close (fd);
-		xfree(buf);
-		return NULL;
+	buf = ptr = xmalloc(buf_size);
+	buf_left = buf_size;
+	while ((tmp_size = read(fd, ptr, buf_left))) {
+		if (tmp_size < 0) {
+			if (errno == EINTR)
+				continue;
+			error("read(environment_file): %m");
+			break;
+		}
+		buf_left  -= tmp_size;
+		file_size += tmp_size;
+		if (buf_left == 0) {
+			buf_size += BUFSIZ;
+			xrealloc(buf, buf_size);
+		}
+		ptr = buf + file_size;
+		buf_left = buf_size - file_size;
 	}
 	close(fd);
 
 	/*
-	 * Parse the buffer into indivudal environment variable names
+	 * Parse the buffer into individual environment variable names
 	 * and build the environment.
 	 */
-	verbose("Getting file of  environment variables at %s", fname);
-	env = env_array_create();
-	line   = xmalloc(ENV_BUFSIZE);
-	value  = xmalloc(ENV_BUFSIZE);
+	env   = env_array_create();
+	line  = xmalloc(ENV_BUFSIZE);
+	value = xmalloc(ENV_BUFSIZE);
 	ptr = buf;
 	while (ptr) {
 		memset(line, 0, ENV_BUFSIZE);
@@ -1641,12 +1656,12 @@ char **env_array_from_file(const char *fname)
 		if ((ptr == eptr) || (eptr == NULL))
 			break;
 		strncpy(line, ptr,(eptr - ptr));
- 		ptr = eptr+1;
+ 		ptr = eptr + 1;
 		if (_env_array_entry_splitter(line, name, sizeof(name),
 					      value, ENV_BUFSIZE) &&
 		    (!_discard_env(name, value)) &&
 		    (name[0] != ' ')) {
-                        env_array_overwrite(&env, name, value);
+			env_array_overwrite(&env, name, value);
 		}
 	}
 	xfree(buf);
diff --git a/src/sbatch/opt.c b/src/sbatch/opt.c
index 9e8153c3989..88aa8b03455 100644
--- a/src/sbatch/opt.c
+++ b/src/sbatch/opt.c
@@ -2803,7 +2803,7 @@ static void _usage(void)
 "              [--network=type] [--mem-per-cpu=MB] [--qos=qos] [--gres=list]\n"
 "              [--cpu_bind=...] [--mem_bind=...] [--reservation=name]\n"
 "              [--switch=max-switches{@max-time-to-wait}]\n"
-"              [--export[=names]] [--export-file=file] executable [args...]\n");
+"              [--export[=names]] [--export-file=file|pipe] executable [args...]\n");
 }
 
 static void _help(void)
@@ -2822,7 +2822,7 @@ static void _help(void)
 "  -D, --workdir=directory     set working directory for batch script\n"
 "  -e, --error=err             file for batch script's standard error\n"
 "      --export[=names]        specify environment variables to export\n"
-"      --export-file=file      specify environment variables file to export\n"
+"      --export-file=file|pipe specify environment variables file or pipe to export\n"
 "      --get-user-env          load environment from local cluster\n"
 "      --gid=group_id          group ID to run job as (user root only)\n"
 "      --gres=list             required generic resources\n"
-- 
GitLab