From df3b2abe9ae1492afb9dcf6765105a4c99b24d4b Mon Sep 17 00:00:00 2001
From: Moe Jette <jette1@llnl.gov>
Date: Fri, 27 Feb 2009 21:24:03 +0000
Subject: [PATCH] forward spank plugin options set in allocator context to
 remote context PATCH 7/9 from Mark Grondona

---
 src/common/plugstack.c | 109 +++++++++++++++++++++++++++++++++++++++++
 src/common/plugstack.h |  16 ++++++
 2 files changed, 125 insertions(+)

diff --git a/src/common/plugstack.c b/src/common/plugstack.c
index 19089b549b9..ddac6097e75 100644
--- a/src/common/plugstack.c
+++ b/src/common/plugstack.c
@@ -56,6 +56,7 @@
 #include "src/common/plugstack.h"
 #include "src/common/optz.h"
 #include "src/common/job_options.h"
+#include "src/common/env.h"
 
 #include "src/slurmd/slurmstepd/slurmstepd_job.h"
 /*#include "src/srun/srun_job.h"*/
@@ -103,6 +104,9 @@ struct spank_plugin {
 /*
  *  SPANK Plugin options 
  */
+
+#define SPANK_OPTION_ENV_PREFIX "_SLURM_SPANK_OPTION_"
+
 struct spank_plugin_opt {
 	struct spank_option *opt;   /* Copy of plugin option info           */
 	struct spank_plugin *plugin;/* Link back to plugin structure        */
@@ -664,6 +668,11 @@ int _spank_init(enum spank_context_type context, slurmd_job_t * job)
 		return (-1);
 	}
 
+	if (job && spank_get_remote_options_env(job->env) < 0) {
+		error("spank: Unable to get remote options from environment");
+		return (-1);
+	}
+
 	if (_do_call_stack(SPANK_INIT_POST_OPT, job, -1) < 0)
 		return (-1);
 
@@ -1110,6 +1119,78 @@ int spank_print_options(FILE * fp, int left_pad, int width)
 
 #define OPT_TYPE_SPANK 0x4400
 
+static char _canonical_char (char c)
+{
+	if (!isalnum (c))
+		return '_';
+	else
+		return c;
+}
+
+/*
+ *  Create spank option environment variable name from option name.
+ */
+static char * _opt_env_name (struct spank_plugin_opt *p, char *buf, size_t siz)
+{
+	const char * name = p->opt->name;
+	const char * pname = p->plugin->name;
+	int i, n;
+
+	strlcpy (buf, SPANK_OPTION_ENV_PREFIX, siz);
+
+	/*
+	 *  First append the plugin name associated with this option:
+	 */
+	n = 0;
+	for (i = strlen (buf); i < siz - 1 && n < strlen (pname); i++)
+	    buf[i] = _canonical_char (pname[n++]);
+
+	/*
+	 *  Append _
+	 */
+	buf[i] = '_';
+	buf[i+1] = '\0';
+
+	/*
+	 *  Now incorporate the option name:
+	 */
+	n = 0;
+	for (i = strlen (buf); i < siz - 1 && n < strlen (name); i++)
+	    buf[i] = _canonical_char (name[n++]);
+	buf[i] = '\0';
+
+	return (buf);
+}
+
+static int _option_setenv (struct spank_plugin_opt *option)
+{
+	char var [1024];
+
+	_opt_env_name (option, var, sizeof (var));
+
+	if (setenv (var, option->optarg, 1) < 0)
+	    error ("failed to set %s=%s in env", var, option->optarg);
+
+	return (0);
+}
+
+int spank_set_remote_options_env(void)
+{
+	struct spank_plugin_opt *p;
+	ListIterator i;
+
+	if ((option_cache == NULL) || (list_count(option_cache) == 0))
+		return (0);
+
+	i = list_iterator_create(option_cache);
+	while ((p = list_next(i))) {
+		if (p->found)
+			_option_setenv (p);
+	}
+	list_iterator_destroy(i);
+	return (0);
+}
+
 int spank_set_remote_options(job_options_t opts)
 {
 	struct spank_plugin_opt *p;
@@ -1185,6 +1266,34 @@ static struct spank_plugin_opt *_find_remote_option_by_name(const char
 	return (opt);
 }
 
+int spank_get_remote_options_env (char **env)
+{
+	char var [1024];
+	const char *arg;
+	struct spank_plugin_opt *option;
+
+	ListIterator i = list_iterator_create (option_cache);
+	while ((option = list_next (i))) {
+		struct spank_option *p = option->opt;
+
+		if (!(arg = getenvp (env, _opt_env_name (option, var, sizeof(var)))))
+			continue;
+
+		if (p->cb && (((*p->cb) (p->val, arg, 1)) < 0))
+			error ("spank: failed to process option %s=%s", p->name, arg);
+
+		/*
+		 *  Now remove the environment variable.
+		 *   It is no longer needed.
+		 */
+		unsetenvp (env, var);
+
+	}
+	list_iterator_destroy (i);
+
+	return (0);
+}
+
 int spank_get_remote_options(job_options_t opts)
 {
 	const struct job_option_info *j;
diff --git a/src/common/plugstack.h b/src/common/plugstack.h
index 9ffb59b91e7..16e551265f1 100644
--- a/src/common/plugstack.h
+++ b/src/common/plugstack.h
@@ -127,6 +127,12 @@ int spank_print_options (FILE *fp, int width, int left_pad);
  */
 int spank_set_remote_options (job_options_t options);
 
+/*  Set all registered remote options (i.e. those passed to
+ *   spank_process_option) in the current environment for later
+ *   retreival by spank_get_remote_options_env().
+ */
+int spank_set_remote_options_env (void);
+
 /*  Register any remote spank options that exist in `options'
  *    to their respective spank plugins. This function ends up invoking
  *    all plugin option callbacks, and will fail (return < 0) if
@@ -137,4 +143,14 @@ int spank_set_remote_options (job_options_t options);
  */
 int spank_get_remote_options (job_options_t options);
 
+/*  Register any remote spank options that exist in the environment `env'
+ *    to their respective spank plugins. This function ends up invoking
+ *    all plugin option callbacks, and will fail (return < 0) if
+ *    a *required* plugin callback returns < 0.
+ *
+ *  A warning is printed if no plugin matches a remote option
+ *   in the job_options structure, but the funtion does not return failure.
+ */
+int spank_get_remote_options_env (char **env);
+
 #endif /* !_PLUGSTACK_H */
-- 
GitLab