From 1334485a8d97a7fa19681538f8d3272768ea186d Mon Sep 17 00:00:00 2001
From: Moe Jette <jette1@llnl.gov>
Date: Tue, 11 Sep 2007 17:17:24 +0000
Subject: [PATCH] Add multi-core options to salloc and sbatch commands
 (sbatch.patch,     from Chris Holmes, HP).

---
 NEWS                   |   2 +
 doc/man/man1/salloc.1  | 125 +++++++-
 doc/man/man1/sbatch.1  | 126 +++++++-
 src/common/Makefile.am |   3 +-
 src/common/Makefile.in |   9 +-
 src/common/proc_args.c | 651 +++++++++++++++++++++++++++++++++++++++++
 src/common/proc_args.h | 106 +++++++
 src/salloc/opt.c       | 568 +++++++++++++++++------------------
 src/salloc/opt.h       |  15 +
 src/salloc/salloc.c    |  28 ++
 src/sbatch/opt.c       | 629 +++++++++++++++++----------------------
 src/sbatch/opt.h       |  19 +-
 src/sbatch/sbatch.c    |  27 +-
 src/srun/opt.c         | 632 +++------------------------------------
 14 files changed, 1671 insertions(+), 1269 deletions(-)
 create mode 100644 src/common/proc_args.c
 create mode 100644 src/common/proc_args.h

diff --git a/NEWS b/NEWS
index 94428db409d..f2d813c233d 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ documents those changes that are of interest to users and admins.
  -- Add support for feature count in job contraints, for example
     srun --nodes=16 --constraint=graphics*4 ...
     Based upon work by Kumar Krishna (HP, India).
+ -- Add multi-core options to salloc and sbatch commands (sbatch.patch, 
+    from Chris Holmes, HP).
 
 * Changes in SLURM 1.3.0-pre2
 =============================
diff --git a/doc/man/man1/salloc.1 b/doc/man/man1/salloc.1
index 554d668750d..45da60c0270 100644
--- a/doc/man/man1/salloc.1
+++ b/doc/man/man1/salloc.1
@@ -13,6 +13,34 @@ The command may be any program the user wishes.  Some typical commands are xterm
 .SH "OPTIONS"
 .LP 
 
+.TP
+\fB\-B\fR \fB\-\-extra\-node\-info\fR=\fIsockets\fR[:\fIcores\fR[:\fIthreads\fR]]
+Request a specific allocation of resources with details as to the
+number and type of computational resources within a cluster:
+number of sockets (or physical processors) per node,
+cores per socket, and threads per core.
+The total amount of resources being requested is the product of all of
+the terms.
+As with \-\-nodes, each value can be a single number or a range (e.g. min\-max).
+An asterisk (*) can be used as a placeholder indicating that all available
+resources of that type are to be utilized.
+As with nodes, the individual levels can also be specified in separate
+options if desired:
+.nf
+    \fB\-\-sockets\-per\-node\fR=\fIsockets\fR
+    \fB\-\-cores\-per\-socket\fR=\fIcores\fR
+    \fB\-\-threads\-per\-core\fR=\fIthreads\fR
+.fi
+When the task/affinity plugin is enabled,
+specifying an allocation in this manner also instructs SLURM to use
+a CPU affinity mask to guarantee the request is filled as specified.
+NOTE: Support for these options are configuration dependent. 
+The task/affinity plugin must be configured.
+In addition either select/linear or select/cons_res plugin must be 
+configured.
+If select/cons_res is configured, it must have a parameter of CR_Core, 
+CR_Core_Memory, CR_Socket, or CR_Socket_Memory. 
+
 .TP
 \fB\-\-begin\fR[=]<\fItime\fR>
 Submit the batch script to the SLURM controller immediately, like normal, but
@@ -121,6 +149,26 @@ may be the group name or the numerical group ID.
 \fB\-h\fR, \fB\-\-help\fR
 Display help information and exit.
 
+.TP
+\fB\-\-hint\fR=\fItype\fR
+Bind tasks according to application hints
+.RS
+.TP
+.B compute_bound
+Select settings for compute bound applications:
+use all cores in each physical CPU
+.TP
+.B memory_bound
+Select settings for memory bound applications:
+use only one core in each physical CPU
+.TP
+.B [no]multithread
+[don't] use extra threads with in-core multi-threading
+which can benefit communication intensive applications
+.B help
+show this help message
+.RE
+
 .TP 
 \fB\-I\fR,\fB\-\-immediate\fR
 Grab the requested resources immediately, or abort if the resources are not
@@ -161,6 +209,47 @@ new job steps on the remaining nodes in their allocation.
 By default SLURM terminates the entire job allocation if any node fails in its
 range of allocated nodes.
 
+.TP
+\fB\-m\fR, \fB\-\-distribution\fR=
+(\fIblock\fR|\fIcyclic\fR|\fIarbitrary\fR|\fIplane=<options>\fR)
+Specify an alternate distribution method for remote processes.
+.RS
+.TP
+.B block
+The block method of distribution will allocate processes in\-order to
+the cpus on a node. If the number of processes exceeds the number of 
+cpus on all of the nodes in the allocation then all nodes will be 
+utilized. For example, consider an allocation of three nodes each with 
+two cpus. A four\-process block distribution request will distribute 
+those processes to the nodes with processes one and two on the first 
+node, process three on the second node, and process four on the third node.  
+Block distribution is the default behavior if the number of tasks 
+exceeds the number of nodes requested.
+.TP
+.B cyclic
+The cyclic method distributes processes in a round\-robin fashion across
+the allocated nodes. That is, process one will be allocated to the first
+node, process two to the second, and so on. This is the default behavior
+if the number of tasks is no larger than the number of nodes requested.
+.TP
+.B plane
+The tasks are distributed in blocks of a specified size.
+The options include a number representing the size of the task block.
+This is followed by an optional specification of the task distribution 
+scheme within a block of tasks and between the blocks of tasks.
+For more details (including examples and diagrams), please see
+http://www.llnl.gov/linux/slurm/mc_support.html and
+http://www.llnl.gov/linux/slurm/dist_plane.html.
+.TP
+.B arbitrary
+The arbitrary method of distribution will allocate processes in\-order as 
+listed in file designated by the environment variable SLURM_HOSTFILE.  If
+this variable is listed it will over ride any other method specified. 
+If not set the method will default to block.  Inside the hostfile must
+contain at minimum the number of hosts requested.  If requesting tasks
+(-n) your tasks will be laid out on the nodes in the order of the file.
+.RE
+
 .TP
 \fB\-\-mail\-type\fR=\fItype\fR
 Notify user by email when certain event types occur. 
@@ -208,7 +297,7 @@ The job will be allocated as many nodes as possible within the range specified
 and without delaying the initiation of the job.
 
 .TP
-\fB\-n\fR, \fB\-\-tasks\fR[=]<\fInumber\fR>
+\fB\-n\fR, \fB\-\-ntasks\fR[=]<\fInumber\fR>
 salloc does not launch tasks, it requests an allocation of resources and submits
 a batch script.  However this \-\-tasks option advizes the SLURM controller
 that job steps run within this allocation will launch a maximum of \fInumber\fR
@@ -224,6 +313,40 @@ is from \-10000 (highest priority) to 10000 (lowest priority). Only
 privileged users can specify a negative adjustment.  NOTE: This option
 is presently ignored if SchedulerType=sched/maui.
 
+.TP
+\fB\-\-ntasks\-per\-core\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each core.
+Similar to \fB\-\-ntasks\-per\-node\fR except at the core level
+instead of the node level.  Masks will automatically be generated
+to bind the tasks to specific core unless \fB\-\-cpu_bind=none\fR
+is specified.
+NOTE: This option is not supported unless \fISelectType=CR_Core\fR
+or \fISelectType=CR_Core_Memory\fR is configured.
+
+.TP
+\fB\-\-ntasks\-per\-socket\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each socket.
+Similar to \fB\-\-ntasks\-per\-node\fR except at the socket level
+instead of the node level.  Masks will automatically be generated
+to bind the tasks to specific sockets unless \fB\-\-cpu_bind=none\fR
+is specified.
+NOTE: This option is not supported unless \fISelectType=CR_Socket\fR 
+or \fISelectType=CR_Socket_Memory\fR is configured.
+
+.TP
+\fB\-\-ntasks\-per\-node\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each node.
+This is similiar to using \fB\-\-cpus\-per\-task\fR=\fIncpus\fR
+but does not require knowledge of the actual number of cpus on
+each node.  In some cases, it is more convenient to be able to
+request that no more than a specific number of ntasks be invoked
+on each node.  Examples of this include submitting
+a hybrid MPI/OpenMP app where only one MPI "task/rank" should be
+assigned to each node while allowing the OpenMP portion to utilize
+all of the parallelism present in the node, or submitting a single
+setup/cleanup/monitoring job to each node of a pre\-existing  
+allocation as one step in a larger job script.
+
 .TP 
 \fB\-\-no\-bell\fR
 Silence salloc's use of the terminal bell. Also see the option \fB\-\-bell\fR.
diff --git a/doc/man/man1/sbatch.1 b/doc/man/man1/sbatch.1
index c156baa88cc..78e10250248 100644
--- a/doc/man/man1/sbatch.1
+++ b/doc/man/man1/sbatch.1
@@ -23,6 +23,34 @@ allocated nodes.
 .SH "OPTIONS"
 .LP 
 
+.TP
+\fB\-B\fR \fB\-\-extra\-node\-info\fR=\fIsockets\fR[:\fIcores\fR[:\fIthreads\fR]]
+Request a specific allocation of resources with details as to the
+number and type of computational resources within a cluster:
+number of sockets (or physical processors) per node,
+cores per socket, and threads per core.
+The total amount of resources being requested is the product of all of
+the terms.
+As with \-\-nodes, each value can be a single number or a range (e.g. min\-max).
+An asterisk (*) can be used as a placeholder indicating that all available
+resources of that type are to be utilized.
+As with nodes, the individual levels can also be specified in separate
+options if desired:
+.nf
+    \fB\-\-sockets\-per\-node\fR=\fIsockets\fR
+    \fB\-\-cores\-per\-socket\fR=\fIcores\fR
+    \fB\-\-threads\-per\-core\fR=\fIthreads\fR
+.fi
+When the task/affinity plugin is enabled,
+specifying an allocation in this manner also instructs SLURM to use
+a CPU affinity mask to guarantee the request is filled as specified.
+NOTE: Support for these options are configuration dependent. 
+The task/affinity plugin must be configured.
+In addition either select/linear or select/cons_res plugin must be 
+configured.
+If select/cons_res is configured, it must have a parameter of CR_Core, 
+CR_Core_Memory, CR_Socket, or CR_Socket_Memory. 
+
 .TP
 \fB\-\-begin\fR[=]<\fItime\fR>
 Submit the batch script to the SLURM controller immediately, like normal, but
@@ -146,6 +174,26 @@ may be the group name or the numerical group ID.
 \fB\-h\fR, \fB\-\-help\fR
 Display help information and exit.
 
+.TP
+\fB\-\-hint\fR=\fItype\fR
+Bind tasks according to application hints
+.RS
+.TP
+.B compute_bound
+Select settings for compute bound applications:
+use all cores in each physical CPU
+.TP
+.B memory_bound
+Select settings for memory bound applications:
+use only one core in each physical CPU
+.TP
+.B [no]multithread
+[don't] use extra threads with in-core multi-threading
+which can benefit communication intensive applications
+.B help
+show this help message
+.RE
+
 .TP 
 \fB\-I\fR,\fB\-\-immediate\fR
 The batch script will only be submitted to the controller if the resources
@@ -202,6 +250,47 @@ new job steps on the remaining nodes in their allocation.
 By default SLURM terminates the entire job allocation if any node fails in its
 range of allocated nodes.
 
+.TP
+\fB\-m\fR, \fB\-\-distribution\fR=
+(\fIblock\fR|\fIcyclic\fR|\fIarbitrary\fR|\fIplane=<options>\fR)
+Specify an alternate distribution method for remote processes.
+.RS
+.TP
+.B block
+The block method of distribution will allocate processes in\-order to
+the cpus on a node. If the number of processes exceeds the number of 
+cpus on all of the nodes in the allocation then all nodes will be 
+utilized. For example, consider an allocation of three nodes each with 
+two cpus. A four\-process block distribution request will distribute 
+those processes to the nodes with processes one and two on the first 
+node, process three on the second node, and process four on the third node.  
+Block distribution is the default behavior if the number of tasks 
+exceeds the number of nodes requested.
+.TP
+.B cyclic
+The cyclic method distributes processes in a round\-robin fashion across
+the allocated nodes. That is, process one will be allocated to the first
+node, process two to the second, and so on. This is the default behavior
+if the number of tasks is no larger than the number of nodes requested.
+.TP
+.B plane
+The tasks are distributed in blocks of a specified size.
+The options include a number representing the size of the task block.
+This is followed by an optional specification of the task distribution 
+scheme within a block of tasks and between the blocks of tasks.
+For more details (including examples and diagrams), please see
+http://www.llnl.gov/linux/slurm/mc_support.html and
+http://www.llnl.gov/linux/slurm/dist_plane.html.
+.TP
+.B arbitrary
+The arbitrary method of distribution will allocate processes in\-order as 
+listed in file designated by the environment variable SLURM_HOSTFILE.  If
+this variable is listed it will over ride any other method specified. 
+If not set the method will default to block.  Inside the hostfile must
+contain at minimum the number of hosts requested.  If requesting tasks
+(-n) your tasks will be laid out on the nodes in the order of the file.
+.RE
+
 .TP
 \fB\-\-mail\-type\fR=\fItype\fR
 Notify user by email when certain event types occur. 
@@ -249,7 +338,7 @@ The job will be allocated as many nodes as possible within the range specified
 and without delaying the initiation of the job.
 
 .TP
-\fB\-n\fR, \fB\-\-tasks\fR[=]<\fInumber\fR>
+\fB\-n\fR, \fB\-\-ntasks\fR[=]<\fInumber\fR>
 sbatch does not launch tasks, it requests an allocation of resources and submits
 a batch script.  However this \-\-tasks option advizes the SLURM controller
 that job steps run within this allocation will launch a maximum of \fInumber\fR
@@ -273,9 +362,38 @@ to restart the job (for example, after a scheduled downtime).
 When a job is requeued, the batch script is initiated from its beginning.
 
 .TP
-\fB\-\-ntasks\-per\-node\fR[=]<\fIn\fR>
-Specify the number of tasks to be launched per node.
-Equivalent to \fB\-\-tasks\-per\-node\fR.
+\fB\-\-ntasks\-per\-core\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each core.
+Similar to \fB\-\-ntasks\-per\-node\fR except at the core level
+instead of the node level.  Masks will automatically be generated
+to bind the tasks to specific core unless \fB\-\-cpu_bind=none\fR
+is specified.
+NOTE: This option is not supported unless \fISelectType=CR_Core\fR
+or \fISelectType=CR_Core_Memory\fR is configured.
+
+.TP
+\fB\-\-ntasks\-per\-socket\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each socket.
+Similar to \fB\-\-ntasks\-per\-node\fR except at the socket level
+instead of the node level.  Masks will automatically be generated
+to bind the tasks to specific sockets unless \fB\-\-cpu_bind=none\fR
+is specified.
+NOTE: This option is not supported unless \fISelectType=CR_Socket\fR 
+or \fISelectType=CR_Socket_Memory\fR is configured.
+
+.TP
+\fB\-\-ntasks\-per\-node\fR=\fIntasks\fR
+Request that no more than \fIntasks\fR be invoked on each node.
+This is similiar to using \fB\-\-cpus\-per\-task\fR=\fIncpus\fR
+but does not require knowledge of the actual number of cpus on
+each node.  In some cases, it is more convenient to be able to
+request that no more than a specific number of ntasks be invoked
+on each node.  Examples of this include submitting
+a hybrid MPI/OpenMP app where only one MPI "task/rank" should be
+assigned to each node while allowing the OpenMP portion to utilize
+all of the parallelism present in the node, or submitting a single
+setup/cleanup/monitoring job to each node of a pre\-existing  
+allocation as one step in a larger job script.
 
 .TP
 \fB\-O\fR, \fB\-\-overcommit\fR
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index a747eefa2a6..0a56656c7fe 100644
--- a/src/common/Makefile.am
+++ b/src/common/Makefile.am
@@ -81,7 +81,8 @@ libcommon_la_SOURCES = 			\
 	global_defaults.c		\
 	timers.c timers.h		\
 	slurm_xlator.h			\
-	stepd_api.c stepd_api.h		
+	stepd_api.c stepd_api.h		\
+	proc_args.c proc_args.h		
 
 EXTRA_libcommon_la_SOURCES = 	\
 	$(extra_unsetenv_src)
diff --git a/src/common/Makefile.in b/src/common/Makefile.in
index 80a4cf55fe5..5f5303b5bea 100644
--- a/src/common/Makefile.in
+++ b/src/common/Makefile.in
@@ -93,7 +93,8 @@ am__libcommon_la_SOURCES_DIST = xmalloc.c xmalloc.h xassert.c \
 	hostlist.h slurm_step_layout.c slurm_step_layout.h \
 	checkpoint.c checkpoint.h parse_time.c parse_time.h \
 	job_options.c job_options.h global_defaults.c timers.c \
-	timers.h slurm_xlator.h stepd_api.c stepd_api.h
+	timers.h slurm_xlator.h stepd_api.c stepd_api.h proc_args.c \
+	proc_args.h 
 @HAVE_UNSETENV_FALSE@am__objects_1 = unsetenv.lo
 am_libcommon_la_OBJECTS = xmalloc.lo xassert.lo xstring.lo xsignal.lo \
 	forward.lo strlcpy.lo list.lo net.lo fd.lo log.lo cbuf.lo \
@@ -108,7 +109,7 @@ am_libcommon_la_OBJECTS = xmalloc.lo xassert.lo xstring.lo xsignal.lo \
 	getopt1.lo $(am__objects_1) slurm_selecttype_info.lo \
 	slurm_resource_info.lo hostlist.lo slurm_step_layout.lo \
 	checkpoint.lo parse_time.lo job_options.lo global_defaults.lo \
-	timers.lo stepd_api.lo
+	timers.lo stepd_api.lo proc_args.lo 
 am__EXTRA_libcommon_la_SOURCES_DIST = unsetenv.c unsetenv.h
 libcommon_la_OBJECTS = $(am_libcommon_la_OBJECTS)
 libcommon_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -381,7 +382,8 @@ libcommon_la_SOURCES = \
 	global_defaults.c		\
 	timers.c timers.h		\
 	slurm_xlator.h			\
-	stepd_api.c stepd_api.h		
+	stepd_api.c stepd_api.h		\
+	proc_args.c proc_args.h		
 
 EXTRA_libcommon_la_SOURCES = \
 	$(extra_unsetenv_src)
@@ -487,6 +489,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugrack.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugstack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/proc_args.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read_config.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/safeopen.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slurm_auth.Plo@am__quote@
diff --git a/src/common/proc_args.c b/src/common/proc_args.c
new file mode 100644
index 00000000000..b6ca8ae3700
--- /dev/null
+++ b/src/common/proc_args.c
@@ -0,0 +1,651 @@
+/*****************************************************************************\
+ *  proc_args.c - helper functions for command argument processing
+ *  $Id: opt.h 11996 2007-08-10 20:36:26Z jette $
+ *****************************************************************************
+ *  Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
+ *  Written by Christopher Holmes <cholmes@hp.com>, who borrowed heavily
+ *  from existing SLURM source code, particularly src/srun/opt.c 
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#if HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <string.h>		/* strcpy, strncasecmp */
+
+#ifdef HAVE_STRINGS_H
+#  include <strings.h>
+#endif
+
+#ifndef _GNU_SOURCE
+#  define _GNU_SOURCE
+#endif
+
+#include <fcntl.h>
+#include <stdarg.h>		/* va_start   */
+#include <stdio.h>
+#include <stdlib.h>		/* getenv     */
+#include <pwd.h>		/* getpwuid   */
+#include <ctype.h>		/* isdigit    */
+#include <sys/param.h>		/* MAXPATHLEN */
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+
+#include "src/common/list.h"
+#include "src/common/xmalloc.h"
+#include "src/common/xstring.h"
+
+#include "src/common/proc_args.h"
+
+
+
+
+/* print this version of SLURM */
+void print_slurm_version(void)
+{
+	printf("%s %s\n", PACKAGE, SLURM_VERSION);
+}
+
+/* 
+ * verify that a distribution type in arg is of a known form
+ * returns the task_dist_states, or -1 if state is unknown
+ */
+task_dist_states_t verify_dist_type(const char *arg, uint32_t *plane_size)
+{
+	int len = strlen(arg);
+	char *dist_str = NULL;
+	task_dist_states_t result = SLURM_DIST_UNKNOWN;
+	bool lllp_dist = false, plane_dist = false;
+
+	dist_str = strchr(arg,':');
+	if (dist_str != NULL) {
+		/* -m cyclic|block:cyclic|block */
+		lllp_dist = true;
+	} else {
+		/* -m plane=<plane_size> */
+		dist_str = strchr(arg,'=');
+		if(dist_str != NULL) {
+			*plane_size=atoi(dist_str+1);
+			len = dist_str-arg;
+			plane_dist = true;
+		}
+	}
+
+	if (lllp_dist) {
+		if (strcasecmp(arg, "cyclic:cyclic") == 0) {
+			result = SLURM_DIST_CYCLIC_CYCLIC;
+		} else if (strcasecmp(arg, "cyclic:block") == 0) {
+			result = SLURM_DIST_CYCLIC_BLOCK;
+		} else if (strcasecmp(arg, "block:block") == 0) {
+			result = SLURM_DIST_BLOCK_BLOCK;
+		} else if (strcasecmp(arg, "block:cyclic") == 0) {
+			result = SLURM_DIST_BLOCK_CYCLIC;
+		}
+	} else if (plane_dist) {
+		if (strncasecmp(arg, "plane", len) == 0) {
+			result = SLURM_DIST_PLANE;
+		}
+	} else {
+		if (strncasecmp(arg, "cyclic", len) == 0) {
+			result = SLURM_DIST_CYCLIC;
+		} else if (strncasecmp(arg, "block", len) == 0) {
+			result = SLURM_DIST_BLOCK;
+		} else if ((strncasecmp(arg, "arbitrary", len) == 0) ||
+		           (strncasecmp(arg, "hostfile", len) == 0)) {
+			result = SLURM_DIST_ARBITRARY;
+		}
+	}
+
+	return result;
+}
+
+/*
+ * verify that a connection type in arg is of known form
+ * returns the connection_type or -1 if not recognized
+ */
+int verify_conn_type(const char *arg)
+{
+	int len = strlen(arg);
+
+	if (!strncasecmp(arg, "MESH", len))
+		return SELECT_MESH;
+	else if (!strncasecmp(arg, "TORUS", len))
+		return SELECT_TORUS;
+	else if (!strncasecmp(arg, "NAV", len))
+		return SELECT_NAV;
+
+	error("invalid --conn-type argument %s ignored.", arg);
+	return -1;
+}
+
+/*
+ * verify geometry arguments, must have proper count
+ * returns -1 on error, 0 otherwise
+ */
+int verify_geometry(const char *arg, uint16_t *geometry)
+{
+	char* token, *delimiter = ",x", *next_ptr;
+	int i, rc = 0;
+	char* geometry_tmp = xstrdup(arg);
+	char* original_ptr = geometry_tmp;
+
+	token = strtok_r(geometry_tmp, delimiter, &next_ptr);
+	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
+		if (token == NULL) {
+			error("insufficient dimensions in --geometry");
+			rc = -1;
+			break;
+		}
+		geometry[i] = (uint16_t)atoi(token);
+		if (geometry[i] == 0 || geometry[i] == (uint16_t)NO_VAL) {
+			error("invalid --geometry argument");
+			rc = -1;
+			break;
+		}
+		geometry_tmp = next_ptr;
+		token = strtok_r(geometry_tmp, delimiter, &next_ptr);
+	}
+	if (token != NULL) {
+		error("too many dimensions in --geometry");
+		rc = -1;
+	}
+
+	if (original_ptr)
+		xfree(original_ptr);
+
+	return rc;
+}
+
+/* return command name from its full path name */
+char * base_name(char* command)
+{
+	char *char_ptr, *name;
+	int i;
+
+	if (command == NULL)
+		return NULL;
+
+	char_ptr = strrchr(command, (int)'/');
+	if (char_ptr == NULL)
+		char_ptr = command;
+	else
+		char_ptr++;
+
+	i = strlen(char_ptr);
+	name = xmalloc(i+1);
+	strcpy(name, char_ptr);
+	return name;
+}
+
+/*
+ * str_to_bytes(): verify that arg is numeric with optional "G" or "M" at end
+ * if "G" or "M" is there, multiply by proper power of 2 and return
+ * number in bytes
+ */
+long str_to_bytes(const char *arg)
+{
+	char *buf;
+	char *endptr;
+	int end;
+	int multiplier = 1;
+	long result;
+
+	buf = xstrdup(arg);
+
+	end = strlen(buf) - 1;
+
+	if (isdigit(buf[end])) {
+		result = strtol(buf, &endptr, 10);
+
+		if (*endptr != '\0')
+			result = -result;
+
+	} else {
+
+		switch (toupper(buf[end])) {
+
+		case 'G':
+			multiplier = 1024;
+			break;
+
+		case 'M':
+			/* do nothing */
+			break;
+
+		default:
+			multiplier = -1;
+		}
+
+		buf[end] = '\0';
+
+		result = multiplier * strtol(buf, &endptr, 10);
+
+		if (*endptr != '\0')
+			result = -result;
+	}
+
+	return result;
+}
+
+/* Convert a string into a node count */
+static int
+_str_to_nodes(const char *num_str, char **leftover)
+{
+	long int num;
+	char *endptr;
+
+	num = strtol(num_str, &endptr, 10);
+	if (endptr == num_str) { /* no valid digits */
+		*leftover = (char *)num_str;
+		return 0;
+	} 
+	if (*endptr != '\0' && (*endptr == 'k' || *endptr == 'K')) {
+		num *= 1024;
+		endptr++;
+	}
+	*leftover = endptr;
+
+	return (int)num;
+}
+
+/* 
+ * verify that a node count in arg is of a known form (count or min-max)
+ * OUT min, max specified minimum and maximum node counts
+ * RET true if valid
+ */
+bool verify_node_count(const char *arg, int *min_nodes, int *max_nodes)
+{
+	char *ptr, *min_str, *max_str;
+	char *leftover;
+	
+	/* Does the string contain a "-" character?  If so, treat as a range.
+	 * otherwise treat as an absolute node count. */
+	if ((ptr = index(arg, '-')) != NULL) {
+		min_str = xstrndup(arg, ptr-arg);
+		*min_nodes = _str_to_nodes(min_str, &leftover);
+		if (!xstring_is_whitespace(leftover)) {
+			error("\"%s\" is not a valid node count", min_str);
+			xfree(min_str);
+			return false;
+		}
+		xfree(min_str);
+		if (*min_nodes == 0)
+			*min_nodes = 1;
+
+		max_str = xstrndup(ptr+1, strlen(arg)-((ptr+1)-arg));
+		*max_nodes = _str_to_nodes(max_str, &leftover);
+		if (!xstring_is_whitespace(leftover)) {
+			error("\"%s\" is not a valid node count", max_str);
+			xfree(max_str);
+			return false;
+		}
+		xfree(max_str);
+	} else {
+		*min_nodes = *max_nodes = _str_to_nodes(arg, &leftover);
+		if (!xstring_is_whitespace(leftover)) {
+			error("\"%s\" is not a valid node count", arg);
+			return false;
+		}
+		if (*min_nodes == 0) {
+			/* whitespace does not a valid node count make */
+			error("\"%s\" is not a valid node count", arg);
+			return false;
+		}
+	}
+
+	if ((*max_nodes != 0) && (*max_nodes < *min_nodes)) {
+		error("Maximum node count %d is less than"
+		      " minimum node count %d",
+		      *max_nodes, *min_nodes);
+		return false;
+	}
+
+	return true;
+}
+
+/* 
+ * get either 1 or 2 integers for a resource count in the form of either
+ * (count, min-max, or '*')
+ * A partial error message is passed in via the 'what' param.
+ * RET true if valid
+ */
+bool
+get_resource_arg_range(const char *arg, const char *what, int* min, int *max, 
+		       bool isFatal)
+{
+	char *p;
+	long int result;
+
+	if (*arg == '\0') return true;
+
+	/* wildcard meaning every possible value in range */
+	if (*arg == '*' ) {
+		*min = 1;
+		*max = INT_MAX;
+		return true;
+	}
+
+	result = strtol(arg, &p, 10);
+        if (*p == 'k' || *p == 'K') {
+		result *= 1024;
+		p++;
+	}
+
+	if (((*p != '\0')&&(*p != '-')) || (result <= 0L)) {
+		error ("Invalid numeric value \"%s\" for %s.", arg, what);
+		if (isFatal) exit(1);
+		return false;
+	} else if (result > INT_MAX) {
+		error ("Numeric argument (%ld) to big for %s.", result, what);
+		if (isFatal) exit(1);
+		return false;
+	}
+
+	*min = (int) result;
+
+	if (*p == '\0') return true;
+	if (*p == '-') p++;
+
+	result = strtol(p, &p, 10);
+        if (*p == 'k' || *p == 'K') {
+		result *= 1024;
+		p++;
+	}
+	
+	if (((*p != '\0')&&(*p != '-')) || (result <= 0L)) {
+		error ("Invalid numeric value \"%s\" for %s.", arg, what);
+		if (isFatal) exit(1);
+		return false;
+	} else if (result > INT_MAX) {
+		error ("Numeric argument (%ld) to big for %s.", result, what);
+		if (isFatal) exit(1);
+		return false;
+	}
+
+	*max = (int) result;
+
+	return true;
+}
+
+/* 
+ * verify that a resource counts in arg are of a known form X, X:X, X:X:X, or 
+ * X:X:X:X, where X is defined as either (count, min-max, or '*')
+ * RET true if valid
+ */
+bool verify_socket_core_thread_count(const char *arg, 
+				     int *min_sockets, int *max_sockets,
+				     int *min_cores, int *max_cores,
+				     int *min_threads, int  *max_threads,
+				     cpu_bind_type_t *cpu_bind_type)
+{
+	bool tmp_val,ret_val;
+	int i,j;
+	const char *cur_ptr = arg;
+	char buf[3][48]; /* each can hold INT64_MAX - INT64_MAX */
+	buf[0][0] = '\0';
+	buf[1][0] = '\0';
+	buf[2][0] = '\0';
+
+ 	for (j=0;j<3;j++) {	
+		for (i=0;i<47;i++) {
+			if (*cur_ptr == '\0' || *cur_ptr ==':') break;
+			buf[j][i] = *cur_ptr++;
+		}
+		if (*cur_ptr == '\0') break;
+		xassert(*cur_ptr == ':');
+		buf[j][i] = '\0';
+		cur_ptr++;
+	}
+	/* if cpu_bind_type doesn't already have a auto preference, choose
+	 * the level based on the level of the -E specification
+	 */
+	if (!(*cpu_bind_type & (CPU_BIND_TO_SOCKETS |
+				CPU_BIND_TO_CORES |
+				CPU_BIND_TO_THREADS))) {
+		if (j == 0) {
+			*cpu_bind_type |= CPU_BIND_TO_SOCKETS;
+		} else if (j == 1) {
+			*cpu_bind_type |= CPU_BIND_TO_CORES;
+		} else if (j == 2) {
+			*cpu_bind_type |= CPU_BIND_TO_THREADS;
+		}
+        }
+	buf[j][i] = '\0';
+
+	ret_val = true;
+	tmp_val = get_resource_arg_range(&buf[0][0], "first arg of -B", 
+					 min_sockets, max_sockets, true);
+	ret_val = ret_val && tmp_val;
+	tmp_val = get_resource_arg_range(&buf[1][0], "second arg of -B", 
+					 min_cores, max_cores, true);
+	ret_val = ret_val && tmp_val;
+	tmp_val = get_resource_arg_range(&buf[2][0], "third arg of -B", 
+					 min_threads, max_threads, true);
+	ret_val = ret_val && tmp_val;
+
+	return ret_val;
+}
+
+/* 
+ * verify that a hint is valid and convert it into the implied settings
+ * RET true if valid
+ */
+bool verify_hint(const char *arg, int *min_sockets, int *max_sockets,
+		 int *min_cores, int *max_cores, int *min_threads,
+		 int *max_threads, cpu_bind_type_t *cpu_bind_type)
+{
+	char *buf, *p, *tok;
+	if (!arg) {
+		return true;
+	}
+
+	buf = xstrdup(arg);
+	p = buf;
+	/* change all ',' delimiters not followed by a digit to ';'  */
+	/* simplifies parsing tokens while keeping map/mask together */
+	while (p[0] != '\0') {
+		if ((p[0] == ',') && (!isdigit(p[1])))
+			p[0] = ';';
+		p++;
+	}
+
+	p = buf;
+	while ((tok = strsep(&p, ";"))) {
+		if (strcasecmp(tok, "help") == 0) {
+			printf(
+"Application hint options:\n"
+"    --hint=             Bind tasks according to application hints\n"
+"        compute_bound   use all cores in each physical CPU\n"
+"        memory_bound    use only one core in each physical CPU\n"
+"        [no]multithread [don't] use extra threads with in-core multi-threading\n"
+"        help            show this help message\n");
+			return 1;
+		} else if (strcasecmp(tok, "compute_bound") == 0) {
+		        *min_sockets = 1;
+		        *max_sockets = INT_MAX;
+		        *min_cores   = 1;
+		        *max_cores   = INT_MAX;
+			*cpu_bind_type |= CPU_BIND_TO_CORES;
+		} else if (strcasecmp(tok, "memory_bound") == 0) {
+		        *min_cores = 1;
+		        *max_cores = 1;
+			*cpu_bind_type |= CPU_BIND_TO_CORES;
+		} else if (strcasecmp(tok, "multithread") == 0) {
+		        *min_threads = 1;
+		        *max_threads = INT_MAX;
+			*cpu_bind_type |= CPU_BIND_TO_THREADS;
+		} else if (strcasecmp(tok, "nomultithread") == 0) {
+		        *min_threads = 1;
+		        *max_threads = 1;
+			*cpu_bind_type |= CPU_BIND_TO_THREADS;
+		} else {
+			error("unrecognized --hint argument \"%s\", see --hint=help", tok);
+			xfree(buf);
+			return 1;
+		}
+	}
+
+	xfree(buf);
+	return 0;
+}
+
+uint16_t parse_mail_type(const char *arg)
+{
+	uint16_t rc;
+
+	if (strcasecmp(arg, "BEGIN") == 0)
+		rc = MAIL_JOB_BEGIN;
+	else if  (strcasecmp(arg, "END") == 0)
+		rc = MAIL_JOB_END;
+	else if (strcasecmp(arg, "FAIL") == 0)
+		rc = MAIL_JOB_FAIL;
+	else if (strcasecmp(arg, "ALL") == 0)
+		rc = MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL;
+	else
+		rc = 0;		/* failure */
+
+	return rc;
+}
+char *print_mail_type(const uint16_t type)
+{
+	if (type == 0)
+		return "NONE";
+
+	if (type == MAIL_JOB_BEGIN)
+		return "BEGIN";
+	if (type == MAIL_JOB_END)
+		return "END";
+	if (type == MAIL_JOB_FAIL)
+		return "FAIL";
+	if (type == (MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL))
+		return "ALL";
+
+	return "MULTIPLE";
+}
+
+static void
+_freeF(void *data)
+{
+	xfree(data);
+}
+
+static List
+_create_path_list(void)
+{
+	List l = list_create(_freeF);
+	char *path = xstrdup(getenv("PATH"));
+	char *c, *lc;
+
+	if (!path) {
+		error("Error in PATH environment variable");
+		list_destroy(l);
+		return NULL;
+	}
+
+	c = lc = path;
+
+	while (*c != '\0') {
+		if (*c == ':') {
+			/* nullify and push token onto list */
+			*c = '\0';
+			if (lc != NULL && strlen(lc) > 0)
+				list_append(l, xstrdup(lc));
+			lc = ++c;
+		} else
+			c++;
+	}
+
+	if (strlen(lc) > 0)
+		list_append(l, xstrdup(lc));
+
+	xfree(path);
+
+	return l;
+}
+
+char *
+search_path(char *cwd, char *cmd, bool check_current_dir, int access_mode)
+{
+	List         l        = _create_path_list();
+	ListIterator i        = NULL;
+	char *path, *fullpath = NULL;
+
+	if (l == NULL)
+		return NULL;
+
+	if (  (cmd[0] == '.' || cmd[0] == '/') 
+           && (access(cmd, access_mode) == 0 ) ) {
+		if (cmd[0] == '.')
+			xstrfmtcat(fullpath, "%s/", cwd);
+		xstrcat(fullpath, cmd);
+		goto done;
+	}
+
+	if (check_current_dir) 
+		list_prepend(l, xstrdup(cwd));
+
+	i = list_iterator_create(l);
+	while ((path = list_next(i))) {
+		xstrfmtcat(fullpath, "%s/%s", path, cmd);
+
+		if (access(fullpath, access_mode) == 0)
+			goto done;
+
+		xfree(fullpath);
+		fullpath = NULL;
+	}
+  done:
+	list_destroy(l);
+	return fullpath;
+}
+
+char *print_commandline(const int script_argc, char **script_argv)
+{
+	int i;
+	char buf[256];
+
+	buf[0] = '\0';
+	for (i = 0; i < script_argc; i++)
+		snprintf(buf, 256,  "%s", script_argv[i]);
+	return xstrdup(buf);
+}
+
+char *print_geometry(const uint16_t *geometry)
+{
+	int i;
+	char buf[32], *rc = NULL;
+
+	if ((SYSTEM_DIMENSIONS == 0)
+	||  (geometry[0] == (uint16_t)NO_VAL))
+		return NULL;
+
+	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
+		if (i > 0)
+			snprintf(buf, sizeof(buf), "x%u", geometry[i]);
+		else
+			snprintf(buf, sizeof(buf), "%u", geometry[i]);
+		xstrcat(rc, buf);
+	}
+
+	return rc;
+}
diff --git a/src/common/proc_args.h b/src/common/proc_args.h
new file mode 100644
index 00000000000..109556bad90
--- /dev/null
+++ b/src/common/proc_args.h
@@ -0,0 +1,106 @@
+/*****************************************************************************\
+ *  proc_args.h - helper functions for command argument processing
+ *  $Id: opt.h 11996 2007-08-10 20:36:26Z jette $
+ *****************************************************************************
+ *  Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
+ *  Written by Christopher Holmes <cholmes@hp.com>, who borrowed heavily
+ *  from existing SLURM source code, particularly src/srun/opt.c 
+ *  
+ *  This file is part of SLURM, a resource management program.
+ *  For details, see <http://www.llnl.gov/linux/slurm/>.
+ *  
+ *  SLURM is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *  
+ *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *  
+ *  You should have received a copy of the GNU General Public License along
+ *  with SLURM; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+\*****************************************************************************/
+
+#ifndef _PROC_ARGS_H
+#define _PROC_ARGS_H
+
+
+#if HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "src/common/macros.h" /* true and false */
+#include "src/common/env.h"
+
+
+#define format_task_dist_states(t) (t == SLURM_DIST_BLOCK) ? "block" :   \
+		                 (t == SLURM_DIST_CYCLIC) ? "cyclic" : \
+		                 (t == SLURM_DIST_PLANE) ? "plane" : \
+		                 (t == SLURM_DIST_CYCLIC_CYCLIC) ? "cyclic:cyclic" : \
+		                 (t == SLURM_DIST_CYCLIC_BLOCK) ? "cyclic:block" : \
+		                 (t == SLURM_DIST_BLOCK_CYCLIC) ? "block:cyclic" : \
+		                 (t == SLURM_DIST_BLOCK_BLOCK) ? "block:block" : \
+			         (t == SLURM_DIST_ARBITRARY) ? "arbitrary" : \
+			         "unknown"
+
+
+/* print this version of SLURM */
+void print_slurm_version(void);
+
+/* verify the requested distribution type */
+task_dist_states_t verify_dist_type(const char *arg, uint32_t *plane_size);
+
+/* verify the requested connection type */
+int verify_conn_type(const char *arg);
+
+/* verify the requested geometry arguments */
+int verify_geometry(const char *arg, uint16_t *geometry);
+
+/* return command name from its full path name */
+char * base_name(char* command);
+
+/* confirm and convert a str to it's presented numeric value */
+long str_to_bytes(const char *arg);
+
+/* verify that a node count in arg is of a known form (count or min-max) */
+bool verify_node_count(const char *arg, int *min_nodes, int *max_nodes);
+
+/* parse a possible range of values from the form: count, min-max, or '*' */
+bool get_resource_arg_range(const char *arg, const char *what,
+				   int* min, int *max, bool isFatal);
+
+/* verify resource counts from a complex form of: X, X:X, X:X:X or X:X:X:X */
+bool verify_socket_core_thread_count(const char *arg, 
+				     int *min_sockets, int *max_sockets,
+				     int *min_cores, int *max_cores,
+				     int *min_threads, int  *max_threads,
+				     cpu_bind_type_t *cpu_bind_type);
+
+/* verify a hint and convert it into the implied settings */
+bool verify_hint(const char *arg, int *min_sockets, int *max_sockets,
+		 int *min_cores, int *max_cores, int *min_threads,
+		 int  *max_threads, cpu_bind_type_t *cpu_bind_type);
+
+/* parse the mail type */
+uint16_t parse_mail_type(const char *arg);
+
+/* print the mail type */
+char *print_mail_type(const uint16_t type);
+
+/* search PATH to confirm the access of the given command */
+char *search_path(char *cwd, char *cmd, bool check_current_dir,
+		  int access_mode);
+
+/* helper function for printing options */
+char *print_commandline(const int script_argc, char **script_argv);
+
+/* helper function for printing geometry option */
+char *print_geometry(const uint16_t *geometry);
+
+#endif /* !_PROC_ARGS_H */
diff --git a/src/salloc/opt.c b/src/salloc/opt.c
index 82e37115133..cb527d919de 100644
--- a/src/salloc/opt.c
+++ b/src/salloc/opt.c
@@ -60,6 +60,7 @@
 #include "src/common/list.h"
 #include "src/common/log.h"
 #include "src/common/parse_time.h"
+#include "src/common/proc_args.h"
 #include "src/common/slurm_protocol_api.h"
 #include "src/common/uid.h"
 #include "src/common/xmalloc.h"
@@ -109,6 +110,14 @@
 #define LONG_OPT_NO_BELL     0x117
 #define LONG_OPT_COMMENT     0x118
 #define LONG_OPT_REBOOT      0x119
+#define LONG_OPT_SOCKETSPERNODE  0x130
+#define LONG_OPT_CORESPERSOCKET  0x131
+#define LONG_OPT_THREADSPERCORE  0x132
+#define LONG_OPT_NTASKSPERNODE   0x136
+#define LONG_OPT_NTASKSPERSOCKET 0x137
+#define LONG_OPT_NTASKSPERCORE   0x138
+#define LONG_OPT_JOBMEM          0x13a
+#define LONG_OPT_HINT            0x13b
 
 /*---- global variables, defined in opt.h ----*/
 opt_t opt;
@@ -117,9 +126,6 @@ opt_t opt;
 
 typedef struct env_vars env_vars_t;
 
-/* return command name from its full path name */
-static char * _base_name(char* command);
-
 /* Get a decimal integer from arg */
 static int  _get_int(const char *arg, const char *what);
 
@@ -139,16 +145,9 @@ static void  _opt_list(void);
 /* verify options sanity  */
 static bool _opt_verify(void);
 
-static void  _print_version(void);
 static void _process_env_var(env_vars_t *e, const char *val);
-static uint16_t _parse_mail_type(const char *arg);
-static char *_print_mail_type(const uint16_t type);
 static int _parse_signal(const char *signal_name);
-static long  _to_bytes(const char *arg);
 static void  _usage(void);
-static bool  _verify_node_count(const char *arg, int *min, int *max);
-static int   _verify_geometry(const char *arg, uint16_t *geometry);
-static int   _verify_conn_type(const char *arg);
 
 /*---[ end forward declarations of static functions ]---------------------*/
 
@@ -170,216 +169,6 @@ int initialize_and_process_args(int argc, char *argv[])
 
 }
 
-static void _print_version(void)
-{
-	printf("%s %s\n", PACKAGE, SLURM_VERSION);
-}
-
-/*
- * verify that a connection type in arg is of known form
- * returns the connection_type or -1 if not recognized
- */
-static int _verify_conn_type(const char *arg)
-{
-	int len = strlen(arg);
-
-	if (!strncasecmp(arg, "MESH", len))
-		return SELECT_MESH;
-	else if (!strncasecmp(arg, "TORUS", len))
-		return SELECT_TORUS;
-	else if (!strncasecmp(arg, "NAV", len))
-		return SELECT_NAV;
-
-	error("invalid --conn-type argument %s ignored.", arg);
-	return -1;
-}
-
-/*
- * verify geometry arguments, must have proper count
- * returns -1 on error, 0 otherwise
- */
-static int _verify_geometry(const char *arg, uint16_t *geometry)
-{
-	char* token, *delimiter = ",x", *next_ptr;
-	int i, rc = 0;
-	char* geometry_tmp = xstrdup(arg);
-	char* original_ptr = geometry_tmp;
-
-	token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (token == NULL) {
-			error("insufficient dimensions in --geometry");
-			rc = -1;
-			break;
-		}
-		geometry[i] = (uint16_t)atoi(token);
-		if (geometry[i] == 0 || geometry[i] == (uint16_t)NO_VAL) {
-			error("invalid --geometry argument");
-			rc = -1;
-			break;
-		}
-		geometry_tmp = next_ptr;
-		token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	}
-	if (token != NULL) {
-		error("too many dimensions in --geometry");
-		rc = -1;
-	}
-
-	if (original_ptr)
-		xfree(original_ptr);
-
-	return rc;
-}
-
-/* Convert a string into a node count */
-static int
-_str_to_nodes(const char *num_str, char **leftover)
-{
-	long int num;
-	char *endptr;
-
-	num = strtol(num_str, &endptr, 10);
-	if (endptr == num_str) { /* no valid digits */
-		*leftover = (char *)num_str;
-		return 0;
-	} 
-	if (*endptr != '\0' && (*endptr == 'k' || *endptr == 'K')) {
-		num *= 1024;
-		endptr++;
-	}
-	*leftover = endptr;
-
-	return (int)num;
-}
-
-/* 
- * verify that a node count in arg is of a known form (count or min-max)
- * OUT min, max specified minimum and maximum node counts
- * RET true if valid
- */
-static bool 
-_verify_node_count(const char *arg, int *min_nodes, int *max_nodes)
-{
-	char *ptr, *min_str, *max_str;
-	char *leftover;
-	
-	/* Does the string contain a "-" character?  If so, treat as a range.
-	 * otherwise treat as an absolute node count. */
-	if ((ptr = index(arg, '-')) != NULL) {
-		min_str = xstrndup(arg, ptr-arg);
-		*min_nodes = _str_to_nodes(min_str, &leftover);
-		if (!xstring_is_whitespace(leftover)) {
-			error("\"%s\" is not a valid node count", min_str);
-			xfree(min_str);
-			return false;
-		}
-		xfree(min_str);
-		if (*min_nodes == 0)
-			*min_nodes = 1;
-
-		max_str = xstrndup(ptr+1, strlen(arg)-((ptr+1)-arg));
-		*max_nodes = _str_to_nodes(max_str, &leftover);
-		if (!xstring_is_whitespace(leftover)) {
-			error("\"%s\" is not a valid node count", max_str);
-			xfree(max_str);
-			return false;
-		}
-		xfree(max_str);
-	} else {
-		*min_nodes = *max_nodes = _str_to_nodes(arg, &leftover);
-		if (!xstring_is_whitespace(leftover)) {
-			error("\"%s\" is not a valid node count", arg);
-			return false;
-		}
-		if (*min_nodes == 0) {
-			/* whitespace does not a valid node count make */
-			error("\"%s\" is not a valid node count", arg);
-			return false;
-		}
-	}
-
-	if ((*max_nodes != 0) && (*max_nodes < *min_nodes)) {
-		error("Maximum node count %d is less than"
-		      " minimum node count %d",
-		      *max_nodes, *min_nodes);
-		return false;
-	}
-
-	return true;
-}
-
-/* return command name from its full path name */
-static char * _base_name(char* command)
-{
-	char *char_ptr, *name;
-	int i;
-
-	if (command == NULL)
-		return NULL;
-
-	char_ptr = strrchr(command, (int)'/');
-	if (char_ptr == NULL)
-		char_ptr = command;
-	else
-		char_ptr++;
-
-	i = strlen(char_ptr);
-	name = xmalloc(i+1);
-	strcpy(name, char_ptr);
-	return name;
-}
-
-/*
- * _to_bytes(): verify that arg is numeric with optional "G" or "M" at end
- * if "G" or "M" is there, multiply by proper power of 2 and return
- * number in bytes
- */
-static long _to_bytes(const char *arg)
-{
-	char *buf;
-	char *endptr;
-	int end;
-	int multiplier = 1;
-	long result;
-
-	buf = xstrdup(arg);
-
-	end = strlen(buf) - 1;
-
-	if (isdigit(buf[end])) {
-		result = strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-
-	} else {
-
-		switch (toupper(buf[end])) {
-
-		case 'G':
-			multiplier = 1024;
-			break;
-
-		case 'M':
-			/* do nothing */
-			break;
-
-		default:
-			multiplier = -1;
-		}
-
-		buf[end] = '\0';
-
-		result = multiplier * strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-	}
-
-	return result;
-}
-
 /*
  * print error message to stderr with opt.progname prepended
  */
@@ -426,6 +215,16 @@ static void _opt_default()
 	opt.min_nodes = 1;
 	opt.max_nodes = 0;
 	opt.nodes_set = false;
+	opt.min_sockets_per_node = NO_VAL; /* requested min/maxsockets */
+	opt.max_sockets_per_node = NO_VAL;
+	opt.min_cores_per_socket = NO_VAL; /* requested min/maxcores */
+	opt.max_cores_per_socket = NO_VAL;
+	opt.min_threads_per_core = NO_VAL; /* requested min/maxthreads */
+	opt.max_threads_per_core = NO_VAL;
+	opt.ntasks_per_node      = NO_VAL; /* ntask max limits */
+	opt.ntasks_per_socket    = NO_VAL;
+	opt.ntasks_per_core      = NO_VAL;
+	opt.cpu_bind_type = 0;		/* local dummy variable for now */
 	opt.time_limit = NO_VAL;
 	opt.time_limit_str = NULL;
 	opt.partition = NULL;
@@ -436,6 +235,9 @@ static void _opt_default()
 	opt.account  = NULL;
 	opt.comment  = NULL;
 
+	opt.distribution = SLURM_DIST_UNKNOWN;
+	opt.plane_size   = NO_VAL;
+
 	opt.shared = (uint16_t)NO_VAL;
 	opt.no_kill = false;
 	opt.kill_command_signal = SIGTERM;
@@ -453,6 +255,7 @@ static void _opt_default()
 	opt.minsockets      = -1;
 	opt.mincores        = -1;
 	opt.minthreads      = -1;
+	opt.jobmem	    = -1;
 	opt.realmem	    = -1;
 	opt.tmpdisk	    = -1;
 
@@ -579,16 +382,16 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_NODES:
-		opt.nodes_set = _verify_node_count( val, 
-						    &opt.min_nodes, 
-						    &opt.max_nodes );
+		opt.nodes_set = verify_node_count( val, 
+						   &opt.min_nodes, 
+						   &opt.max_nodes );
 		if (opt.nodes_set == false) {
 			error("invalid node count in env variable, ignoring");
 		}
 		break;
 
 	case OPT_CONN_TYPE:
-		opt.conn_type = _verify_conn_type(val);
+		opt.conn_type = verify_conn_type(val);
 		break;
 
 	case OPT_NO_ROTATE:
@@ -596,7 +399,7 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_GEOMETRY:
-		if (_verify_geometry(val, opt.geometry)) {
+		if (verify_geometry(val, opt.geometry)) {
 			error("\"%s=%s\" -- invalid geometry, ignoring...",
 			      e->var, val);
 		}
@@ -653,6 +456,7 @@ void set_options(const int argc, char **argv)
 	int opt_char, option_index = 0;
 	char *tmp;
 	static struct option long_options[] = {
+		{"extra-node-info", required_argument, 0, 'B'},
 		{"cpus-per-task", required_argument, 0, 'c'},
 		{"constraint",    required_argument, 0, 'C'},
 		{"dependency",    required_argument, 0, 'd'},
@@ -664,7 +468,8 @@ void set_options(const int argc, char **argv)
 		{"job-name",      required_argument, 0, 'J'},
 		{"no-kill",       no_argument,       0, 'k'},
 		{"kill-command",  optional_argument, 0, 'K'},
-		{"tasks",         required_argument, 0, 'n'},
+		{"distribution",  required_argument, 0, 'm'},
+		{"ntasks",        required_argument, 0, 'n'},
 		{"nodes",         required_argument, 0, 'N'},
 		{"overcommit",    no_argument,       0, 'O'},
 		{"partition",     required_argument, 0, 'p'},
@@ -686,6 +491,15 @@ void set_options(const int argc, char **argv)
 		{"mincores",      required_argument, 0, LONG_OPT_MINCORES},
 		{"minthreads",    required_argument, 0, LONG_OPT_MINTHREADS},
 		{"mem",           required_argument, 0, LONG_OPT_MEM},
+		{"job-mem",       required_argument, 0, LONG_OPT_JOBMEM},
+		{"hint",          required_argument, 0, LONG_OPT_HINT},
+		{"sockets-per-node", required_argument, 0, LONG_OPT_SOCKETSPERNODE},
+		{"cores-per-socket", required_argument, 0, LONG_OPT_CORESPERSOCKET},
+		{"threads-per-core", required_argument, 0, LONG_OPT_THREADSPERCORE},
+		{"ntasks-per-node",  required_argument, 0, LONG_OPT_NTASKSPERNODE},
+		{"ntasks-per-socket",required_argument, 0, LONG_OPT_NTASKSPERSOCKET},
+		{"ntasks-per-core",  required_argument, 0, LONG_OPT_NTASKSPERCORE},
+		{"tasks-per-node",  required_argument, 0, LONG_OPT_NTASKSPERNODE},
 		{"tmp",           required_argument, 0, LONG_OPT_TMP},
 		{"uid",           required_argument, 0, LONG_OPT_UID},
 		{"gid",           required_argument, 0, LONG_OPT_GID},
@@ -701,7 +515,7 @@ void set_options(const int argc, char **argv)
 		{"reboot",	  no_argument,       0, LONG_OPT_REBOOT},
 		{NULL,            0,                 0, 0}
 	};
-	char *opt_string = "+a:c:C:d:F:g:hHIJ:kK::n:N:Op:qR:st:uU:vVw:W:x:";
+	char *opt_string = "+a:B:c:C:d:F:g:hHIJ:kK:m:n:N:Op:qR:st:uU:vVw:W:x:";
 
 	opt.progname = xbasename(argv[0]);
 	optind = 0;		
@@ -714,6 +528,24 @@ void set_options(const int argc, char **argv)
 				"information\n");
 			exit(1);
 			break;
+		case 'B':
+			opt.extra_set = verify_socket_core_thread_count(
+				optarg,
+				&opt.min_sockets_per_node,
+				&opt.max_sockets_per_node,
+				&opt.min_cores_per_socket,
+				&opt.max_cores_per_socket,
+				&opt.min_threads_per_core,
+				&opt.max_threads_per_core,
+				&opt.cpu_bind_type);
+
+
+			if (opt.extra_set == false) {
+				error("invalid resource allocation -B `%s'",
+					optarg);
+				exit(1);
+			}
+			break;
 		case 'c':
 			opt.cpus_set = true;
 			opt.cpus_per_task = 
@@ -738,7 +570,7 @@ void set_options(const int argc, char **argv)
 			}
 			break;
 		case 'g':
-			if (_verify_geometry(optarg, opt.geometry))
+			if (verify_geometry(optarg, opt.geometry))
 				exit(1);
 			break;
 		case 'h':
@@ -765,6 +597,15 @@ void set_options(const int argc, char **argv)
 			}
 			opt.kill_command_signal_set = true;
 			break;
+		case 'm':
+			opt.distribution = verify_dist_type(optarg, 
+							    &opt.plane_size);
+			if (opt.distribution == SLURM_DIST_UNKNOWN) {
+				error("distribution type `%s' " 
+				      "is not recognized", optarg);
+				exit(1);
+			}
+			break;
 		case 'n':
 			opt.nprocs_set = true;
 			opt.nprocs = 
@@ -772,9 +613,9 @@ void set_options(const int argc, char **argv)
 			break;
 		case 'N':
 			opt.nodes_set = 
-				_verify_node_count(optarg, 
-						   &opt.min_nodes,
-						   &opt.max_nodes);
+				verify_node_count(optarg, 
+						  &opt.min_nodes,
+						  &opt.max_nodes);
 			if (opt.nodes_set == false) {
 				exit(1);
 			}
@@ -810,7 +651,7 @@ void set_options(const int argc, char **argv)
 			opt.verbose++;
 			break;
 		case 'V':
-			_print_version();
+			print_slurm_version();
 			exit(0);
 			break;
 		case 'w':
@@ -869,15 +710,23 @@ void set_options(const int argc, char **argv)
 			}
 			break;
 		case LONG_OPT_MEM:
-			opt.realmem = (int) _to_bytes(optarg);
+			opt.realmem = (int) str_to_bytes(optarg);
 			if (opt.realmem < 0) {
 				error("invalid memory constraint %s", 
 				      optarg);
 				exit(1);
 			}
 			break;
+		case LONG_OPT_JOBMEM:
+			opt.jobmem = (int) str_to_bytes(optarg);
+			if (opt.jobmem < 0) {
+				error("invalid memory constraint %s", 
+				      optarg);
+				exit(1);
+			}
+			break;
 		case LONG_OPT_TMP:
-			opt.tmpdisk = _to_bytes(optarg);
+			opt.tmpdisk = str_to_bytes(optarg);
 			if (opt.tmpdisk < 0) {
 				error("invalid tmp value %s", optarg);
 				exit(1);
@@ -894,7 +743,7 @@ void set_options(const int argc, char **argv)
 				fatal ("--gid=\"%s\" invalid", optarg);
 			break;
 		case LONG_OPT_CONNTYPE:
-			opt.conn_type = _verify_conn_type(optarg);
+			opt.conn_type = verify_conn_type(optarg);
 			break;
 		case LONG_OPT_BEGIN:
 			opt.begin = parse_time(optarg);
@@ -905,7 +754,7 @@ void set_options(const int argc, char **argv)
 			}
 			break;
 		case LONG_OPT_MAIL_TYPE:
-			opt.mail_type |= _parse_mail_type(optarg);
+			opt.mail_type |= parse_mail_type(optarg);
 			if (opt.mail_type == 0)
 				fatal("--mail-type=%s invalid", optarg);
 			break;
@@ -937,6 +786,48 @@ void set_options(const int argc, char **argv)
 			xfree(opt.comment);
 			opt.comment = xstrdup(optarg);
 			break;
+		case LONG_OPT_SOCKETSPERNODE:
+			get_resource_arg_range( optarg, "sockets-per-node",
+						&opt.min_sockets_per_node,
+						&opt.max_sockets_per_node,
+						true );
+			break;
+		case LONG_OPT_CORESPERSOCKET:
+			get_resource_arg_range( optarg, "cores-per-socket",
+						&opt.min_cores_per_socket,
+						&opt.max_cores_per_socket,
+						true);
+			break;
+		case LONG_OPT_THREADSPERCORE:
+			get_resource_arg_range( optarg, "threads-per-core",
+						&opt.min_threads_per_core,
+						&opt.max_threads_per_core,
+						true );
+			break;
+		case LONG_OPT_HINT:
+			if (verify_hint(optarg,
+				&opt.min_sockets_per_node,
+				&opt.max_sockets_per_node,
+				&opt.min_cores_per_socket,
+				&opt.max_cores_per_socket,
+				&opt.min_threads_per_core,
+				&opt.max_threads_per_core,
+				&opt.cpu_bind_type)) {
+				exit(1);
+			}
+			break;
+		case LONG_OPT_NTASKSPERNODE:
+			opt.ntasks_per_node = _get_int(optarg,
+				"ntasks-per-node");
+			break;
+		case LONG_OPT_NTASKSPERSOCKET:
+			opt.ntasks_per_socket = _get_int(optarg, 
+				"ntasks-per-socket");
+			break;
+		case LONG_OPT_NTASKSPERCORE:
+			opt.ntasks_per_core = _get_int(optarg,
+				"ntasks-per-core");
+			break;
 		case LONG_OPT_REBOOT:
 			opt.reboot = true;
 			break;
@@ -990,7 +881,7 @@ static bool _opt_verify(void)
 		opt.mincpus = opt.cpus_per_task;
 
 	if ((opt.job_name == NULL) && (command_argc > 0))
-		opt.job_name = _base_name(command_argv[0]);
+		opt.job_name = base_name(command_argv[0]);
 
 	if (command_argc == 0) {
 		error("A local command is a required parameter!");
@@ -1018,11 +909,87 @@ static bool _opt_verify(void)
 		verified = false;
 	}
 
+        /* When CR with memory as a CR is enabled we need to assign
+	   adequate value or check the value to opt.mem */
+	if ((opt.realmem >= -1) && (opt.jobmem > 0)) {
+		if (opt.realmem == -1) {
+			opt.realmem = opt.jobmem;
+		} else if (opt.realmem < opt.jobmem) {
+			info("mem < job-mem - resizing mem to be equal to job-mem");
+			opt.realmem = opt.jobmem;
+		}
+	}
+	
+        /* Check to see if user has specified enough resources to
+	 * satisfy the plane distribution with the specified
+	 * plane_size.  
+	 * if (n/plane_size < N) and ((N-1) * plane_size >= n) -->
+	 * problem Simple check will not catch all the problem/invalid
+	 * cases.
+	 * The limitations of the plane distribution in the cons_res
+	 * environment are more extensive and are documented in the
+	 * SLURM reference guide.  */
+	if (opt.distribution == SLURM_DIST_PLANE && opt.plane_size) {
+		if ((opt.nprocs/opt.plane_size) < opt.min_nodes) {
+			if (((opt.min_nodes-1)*opt.plane_size) >= opt.nprocs) {
+#if(0)
+				info("Too few processes ((n/plane_size) %d < N %d) "
+				     "and ((N-1)*(plane_size) %d >= n %d)) ",
+				     opt.nprocs/opt.plane_size, opt.min_nodes, 
+				     (opt.min_nodes-1)*opt.plane_size, opt.nprocs);
+#endif
+				error("Too few processes for the requested "
+				      "{plane,node} distribution");
+				exit(1);
+			}
+		}
+	}
+
+	/* bound max_threads/cores from ntasks_cores/sockets */ 
+	if ((opt.max_threads_per_core <= 0) &&
+	    (opt.ntasks_per_core > 0)) {
+		opt.max_threads_per_core = opt.ntasks_per_core;
+		/* if cpu_bind_type doesn't already have a auto pref,
+		 * choose the level based on the level of ntasks
+		 */
+		if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
+					   CPU_BIND_TO_CORES |
+					   CPU_BIND_TO_THREADS))) {
+			opt.cpu_bind_type |= CPU_BIND_TO_CORES;
+		}
+	}
+	if ((opt.max_cores_per_socket <= 0) &&
+	    (opt.ntasks_per_socket > 0)) {
+		opt.max_cores_per_socket = opt.ntasks_per_socket;
+		/* if cpu_bind_type doesn't already have a auto pref,
+		 * choose the level based on the level of ntasks
+		 */
+		if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
+					   CPU_BIND_TO_CORES |
+					   CPU_BIND_TO_THREADS))) {
+			opt.cpu_bind_type |= CPU_BIND_TO_SOCKETS;
+		}
+	}
+
 	/* massage the numbers */
 	if (opt.nodes_set && !opt.nprocs_set) {
 		/* 1 proc / node default */
 		opt.nprocs = opt.min_nodes;
 
+		/* 1 proc / min_[socket * core * thread] default */
+		if (opt.min_sockets_per_node > 0) {
+			opt.nprocs *= opt.min_sockets_per_node;
+			opt.nprocs_set = true;
+		}
+		if (opt.min_cores_per_socket > 0) {
+			opt.nprocs *= opt.min_cores_per_socket;
+			opt.nprocs_set = true;
+		}
+		if (opt.min_threads_per_core > 0) {
+			opt.nprocs *= opt.min_threads_per_core;
+			opt.nprocs_set = true;
+		}
+
 	} else if (opt.nodes_set && opt.nprocs_set) {
 
 		/* 
@@ -1074,40 +1041,6 @@ static bool _opt_verify(void)
 	return verified;
 }
 
-static uint16_t _parse_mail_type(const char *arg)
-{
-	uint16_t rc;
-
-	if (strcasecmp(arg, "BEGIN") == 0)
-		rc = MAIL_JOB_BEGIN;
-	else if  (strcasecmp(arg, "END") == 0)
-		rc = MAIL_JOB_END;
-	else if (strcasecmp(arg, "FAIL") == 0)
-		rc = MAIL_JOB_FAIL;
-	else if (strcasecmp(arg, "ALL") == 0)
-		rc = MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL;
-	else
-		rc = 0;		/* failure */
-
-	return rc;
-}
-static char *_print_mail_type(const uint16_t type)
-{
-	if (type == 0)
-		return "NONE";
-
-	if (type == MAIL_JOB_BEGIN)
-		return "BEGIN";
-	if (type == MAIL_JOB_END)
-		return "END";
-	if (type == MAIL_JOB_FAIL)
-		return "FAIL";
-	if (type == (MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL))
-		return "ALL";
-
-	return "MULTIPLE";
-}
-
 /* helper function for printing options
  * 
  * warning: returns pointer to memory allocated on the stack.
@@ -1119,9 +1052,21 @@ static char *print_constraints()
 	if (opt.mincpus > 0)
 		xstrfmtcat(buf, "mincpus=%d ", opt.mincpus);
 
+	if (opt.minsockets > 0)
+		xstrfmtcat(buf, "minsockets=%d ", opt.minsockets);
+
+	if (opt.mincores > 0)
+		xstrfmtcat(buf, "mincores=%d ", opt.mincores);
+
+	if (opt.minthreads > 0)
+		xstrfmtcat(buf, "minthreads=%d ", opt.minthreads);
+
 	if (opt.realmem > 0)
 		xstrfmtcat(buf, "mem=%dM ", opt.realmem);
 
+	if (opt.jobmem > 0)
+		xstrfmtcat(buf, "job-mem=%dM ", opt.jobmem);
+
 	if (opt.tmpdisk > 0)
 		xstrfmtcat(buf, "tmp=%ld ", opt.tmpdisk);
 
@@ -1140,39 +1085,6 @@ static char *print_constraints()
 	return buf;
 }
 
-static char * 
-print_commandline()
-{
-	int i;
-	char buf[256];
-
-	buf[0] = '\0';
-	for (i = 0; i < command_argc; i++)
-		snprintf(buf, 256,  "%s", command_argv[i]);
-	return xstrdup(buf);
-}
-
-static char *
-print_geometry()
-{
-	int i;
-	char buf[32], *rc = NULL;
-
-	if ((SYSTEM_DIMENSIONS == 0)
-	||  (opt.geometry[0] == (uint16_t)NO_VAL))
-		return NULL;
-
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (i > 0)
-			snprintf(buf, sizeof(buf), "x%u", opt.geometry[i]);
-		else
-			snprintf(buf, sizeof(buf), "%u", opt.geometry[i]);
-		xstrcat(rc, buf);
-	}
-
-	return rc;
-}
-
 /*
  * Takes a string containing the number or name of a signal and returns
  * the signal number.  The signal name is case insensitive, and may be of
@@ -1255,6 +1167,9 @@ static void _opt_list()
 	info("job name       : `%s'", opt.job_name);
 	if (opt.jobid != NO_VAL)
 		info("jobid          : %u", opt.jobid);
+	info("distribution   : %s", format_task_dist_states(opt.distribution));
+	if(opt.distribution == SLURM_DIST_PLANE)
+		info("plane size   : %u", opt.plane_size);
 	info("verbose        : %d", opt.verbose);
 	info("immediate      : %s", tf_(opt.immediate));
 	info("overcommit     : %s", tf_(opt.overcommit));
@@ -1276,7 +1191,7 @@ static void _opt_list()
 	xfree(str);
 	if (opt.conn_type >= 0)
 		info("conn_type      : %u", opt.conn_type);
-	str = print_geometry();
+	str = print_geometry(opt.geometry);
 	info("geometry       : %s", str);
 	xfree(str);
 	info("reboot         : %s", opt.reboot ? "no" : "yes");
@@ -1286,9 +1201,19 @@ static void _opt_list()
 		slurm_make_time_str(&opt.begin, time_str, sizeof(time_str));
 		info("begin          : %s", time_str);
 	}
-	info("mail_type      : %s", _print_mail_type(opt.mail_type));
+	info("mail_type      : %s", print_mail_type(opt.mail_type));
 	info("mail_user      : %s", opt.mail_user);
-	str = print_commandline();
+	info("sockets-per-node  : %d - %d", opt.min_sockets_per_node,
+					    opt.max_sockets_per_node);
+	info("cores-per-socket  : %d - %d", opt.min_cores_per_socket,
+					    opt.max_cores_per_socket);
+	info("threads-per-core  : %d - %d", opt.min_threads_per_core,
+					    opt.max_threads_per_core);
+	info("ntasks-per-node   : %d", opt.ntasks_per_node);
+	info("ntasks-per-socket : %d", opt.ntasks_per_socket);
+	info("ntasks-per-core   : %d", opt.ntasks_per_core);
+	info("plane_size        : %u", opt.plane_size);
+	str = print_commandline(command_argc, command_argv);
 	info("user command   : `%s'", str);
 	xfree(str);
 
@@ -1316,6 +1241,8 @@ static void _usage(void)
 
 static void _help(void)
 {
+	slurm_ctl_conf_t *conf;
+
         printf (
 "Usage: salloc [OPTIONS...] executable [args...]\n"
 "\n"
@@ -1323,6 +1250,7 @@ static void _help(void)
 "  -N, --nodes=N               number of nodes on which to run (N = min[-max])\n"
 "  -n, --tasks=N               number of processors required\n"
 "  -c, --cpus-per-task=ncpus   number of cpus required per task\n"
+"      --ntasks-per-node=n     number of tasks to invoke on each node\n"
 "  -p, --partition=partition   partition requested\n"
 "  -H, --hold                  submit job in held state\n"
 "  -t, --time=minutes          time limit\n"
@@ -1331,6 +1259,8 @@ static void _help(void)
 "  -K, --kill-command[=signal] signal to send terminating job\n"
 "  -O, --overcommit            overcommit resources\n"
 "  -s, --share                 share nodes with other jobs\n"
+"  -m, --distribution=type     distribution method for processes to nodes\n"
+"                              (type = block|cyclic|arbitrary)\n"
 "  -J, --job-name=jobname      name of job\n"
 "      --jobid=id              specify jobid to use\n"
 "  -W, --wait=sec              seconds to wait for allocation if not\n"
@@ -1365,8 +1295,32 @@ static void _help(void)
 "Consumable resources related options:\n" 
 "      --exclusive             allocate nodes in exclusive mode when\n" 
 "                              cpu consumable resource is enabled\n"
+"      --job-mem=MB            maximum amount of real memory per node\n"
+"                              required by the job.\n" 
+"                              --mem >= --job-mem if --mem is specified.\n" 
 "\n"
+"Affinity/Multi-core options: (when the task/affinity plugin is enabled)\n" 
+"  -B --extra-node-info=S[:C[:T]]            Expands to:\n"
+"      --sockets-per-node=S    number of sockets per node to allocate\n"
+"      --cores-per-socket=C    number of cores per socket to allocate\n"
+"      --threads-per-core=T    number of threads per core to allocate\n"
+"                              each field can be 'min[-max]' or wildcard '*'\n"
+"                              total cpus requested = (N x S x C x T)\n"
+"\n"
+"      --ntasks-per-socket=n   number of tasks to invoke on each socket\n"
+"      --ntasks-per-core=n     number of tasks to invoke on each core\n");
+	conf = slurm_conf_lock();
+	if (conf->task_plugin != NULL
+	    && strcasecmp(conf->task_plugin, "task/affinity") == 0) {
+		printf(
+"      --hint=                 Bind tasks according to application hints\n"
+"                              (see \"--hint=help\" for options)\n");
+	}
+	slurm_conf_unlock();
+
+        printf("\n"
 #ifdef HAVE_BG				/* Blue gene specific options */
+"\n"
   "Blue Gene related options:\n"
   "  -g, --geometry=XxYxZ        geometry constraints of the job\n"
   "  -R, --no-rotate             disable geometry rotation\n"
diff --git a/src/salloc/opt.h b/src/salloc/opt.h
index c101b0bcb4d..ed974a07042 100644
--- a/src/salloc/opt.h
+++ b/src/salloc/opt.h
@@ -62,11 +62,25 @@ typedef struct salloc_options {
 	int  min_nodes;		/* --nodes=n,       -N n	*/ 
 	int  max_nodes;		/* --nodes=x-n,       -N x-n	*/ 
 	bool nodes_set;		/* true if nodes explicitly set */
+	int min_sockets_per_node; /* --sockets-per-node=n      */
+	int max_sockets_per_node; /* --sockets-per-node=x-n    */
+	int min_cores_per_socket; /* --cores-per-socket=n      */
+	int max_cores_per_socket; /* --cores-per-socket=x-n    */
+	int min_threads_per_core; /* --threads-per-core=n      */
+	int max_threads_per_core; /* --threads-per-core=x-n    */
+	int ntasks_per_node;   /* --ntasks-per-node=n	    */
+	int ntasks_per_socket; /* --ntasks-per-socket=n     */
+	int ntasks_per_core;   /* --ntasks-per-core=n	    */
+	cpu_bind_type_t cpu_bind_type; /* --cpu_bind=           */
+	bool extra_set;		/* true if extra node info explicitly set */
 	int  time_limit;	/* --time,   -t	(int minutes)	*/
 	char *time_limit_str;	/* --time,   -t (string)	*/
 	char *partition;	/* --partition=n,   -p n   	*/
 	enum task_dist_states
 		distribution;	/* --distribution=, -m dist	*/
+        uint32_t plane_size;    /* lllp distribution -> plane_size for
+				 * when -m plane=<# of lllp per
+				 * plane> */      
 	char *job_name;		/* --job-name=,     -J name	*/
 	unsigned int jobid;	/* --jobid=jobid		*/
 	unsigned int dependency;/* --dependency, -P jobid	*/
@@ -91,6 +105,7 @@ typedef struct salloc_options {
 	int minsockets;		/* --minsockets=n		*/
 	int mincores;		/* --mincores=n			*/
 	int minthreads;		/* --minthreads=n		*/
+	int jobmem;		/* --job-mem=n			*/
 	int realmem;		/* --mem=n			*/
 	long tmpdisk;		/* --tmp=n			*/
 	char *constraints;	/* --constraints=, -C constraint*/
diff --git a/src/salloc/salloc.c b/src/salloc/salloc.c
index 06da0579f86..7b13e4e9e1d 100644
--- a/src/salloc/salloc.c
+++ b/src/salloc/salloc.c
@@ -249,6 +249,9 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 	desc->user_id = opt.uid;
 	desc->group_id = opt.gid;
 	desc->dependency = opt.dependency;
+	desc->task_dist  = opt.distribution;
+	if (opt.plane_size != NO_VAL)
+		desc->plane_size = opt.plane_size;
 	if (opt.nice)
 		desc->nice = NICE_OFFSET + opt.nice;
 	desc->mail_type = opt.mail_type;
@@ -276,6 +279,8 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 		desc->reboot = 1;
 	if (opt.no_rotate)
 		desc->rotate = 0;
+
+	/* job constraints */
 	if (opt.mincpus > -1)
 		desc->job_min_procs = opt.mincpus;
 	if (opt.minsockets > -1)
@@ -284,6 +289,8 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 		desc->job_min_cores = opt.mincores;
 	if (opt.minthreads > -1)
 		desc->job_min_threads = opt.minthreads;
+	if (opt.jobmem > -1)
+		desc->job_max_memory = opt.jobmem;
 	if (opt.realmem > -1)
 		desc->job_min_memory = opt.realmem;
 	if (opt.tmpdisk > -1)
@@ -297,6 +304,27 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 		desc->num_tasks = opt.nprocs;
 	if (opt.cpus_set)
 		desc->cpus_per_task = opt.cpus_per_task;
+	if (opt.ntasks_per_node > -1)
+		desc->ntasks_per_node = opt.ntasks_per_node;
+	if (opt.ntasks_per_socket > -1)
+		desc->ntasks_per_socket = opt.ntasks_per_socket;
+	if (opt.ntasks_per_core > -1)
+		desc->ntasks_per_core = opt.ntasks_per_core;
+
+	/* node constraints */
+	if (opt.min_sockets_per_node > -1)
+		desc->min_sockets = opt.min_sockets_per_node;
+	if (opt.max_sockets_per_node > -1)
+		desc->max_sockets = opt.max_sockets_per_node;
+	if (opt.min_cores_per_socket > -1)
+		desc->min_cores = opt.min_cores_per_socket;
+	if (opt.max_cores_per_socket > -1)
+		desc->max_cores = opt.max_cores_per_socket;
+	if (opt.min_threads_per_core > -1)
+		desc->min_threads = opt.min_threads_per_core;
+	if (opt.max_threads_per_core > -1)
+		desc->max_threads = opt.max_threads_per_core;
+
 	if (opt.no_kill)
 		desc->kill_on_node_fail = 0;
 	if (opt.time_limit  != NO_VAL)
diff --git a/src/sbatch/opt.c b/src/sbatch/opt.c
index 3b43bf05335..41bd06b7afe 100644
--- a/src/sbatch/opt.c
+++ b/src/sbatch/opt.c
@@ -60,6 +60,7 @@
 #include "src/common/list.h"
 #include "src/common/log.h"
 #include "src/common/parse_time.h"
+#include "src/common/proc_args.h"
 #include "src/common/slurm_protocol_api.h"
 #include "src/common/uid.h"
 #include "src/common/xmalloc.h"
@@ -105,12 +106,19 @@
 #define LONG_OPT_NO_REQUEUE  0x116
 #define LONG_OPT_COMMENT     0x117
 #define LONG_OPT_WRAP        0x118
+#define LONG_OPT_SOCKETSPERNODE  0x130
+#define LONG_OPT_CORESPERSOCKET  0x131
+#define LONG_OPT_THREADSPERCORE  0x132
+#define LONG_OPT_NTASKSPERNODE   0x136
+#define LONG_OPT_NTASKSPERSOCKET 0x137
+#define LONG_OPT_NTASKSPERCORE   0x138
+#define LONG_OPT_JOBMEM          0x13a
+#define LONG_OPT_HINT            0x13b
 #define LONG_OPT_BLRTS_IMAGE     0x140
 #define LONG_OPT_LINUX_IMAGE     0x141
 #define LONG_OPT_MLOADER_IMAGE   0x142
 #define LONG_OPT_RAMDISK_IMAGE   0x143
 #define LONG_OPT_REBOOT          0x144
-#define LONG_OPT_TASKSPERNODE    0x145
 #define LONG_OPT_GET_USER_ENV    0x146
 
 /*---- global variables, defined in opt.h ----*/
@@ -120,10 +128,6 @@ opt_t opt;
 
 typedef struct env_vars env_vars_t;
 
-/* return command name from its full path name */
-static char * _base_name(char* command);
-
-static List  _create_path_list(void);
 
 /* Get a decimal integer from arg */
 static int  _get_int(const char *arg, const char *what);
@@ -148,23 +152,11 @@ static void  _opt_list(void);
 /* verify options sanity  */
 static bool _opt_verify(void);
 
-static void  _print_version(void);
-
 static void _process_env_var(env_vars_t *e, const char *val);
 
-static uint16_t _parse_mail_type(const char *arg);
 static uint16_t _parse_pbs_mail_type(const char *arg);
-static char *_print_mail_type(const uint16_t type);
-
-/* search PATH for command returns full path */
-static char *_search_path(char *, bool, int);
-
-static long  _to_bytes(const char *arg);
 
 static void  _usage(void);
-static bool  _verify_node_count(const char *arg, int *min, int *max);
-static int   _verify_geometry(const char *arg, uint16_t *geometry);
-static int   _verify_conn_type(const char *arg);
 static char *_fullpath(const char *filename);
 static void _set_options(int argc, char **argv);
 static void _set_pbs_options(int argc, char **argv);
@@ -172,179 +164,6 @@ static void _parse_pbs_resource_list(char *rl);
 
 /*---[ end forward declarations of static functions ]---------------------*/
 
-static void _print_version(void)
-{
-	printf("%s %s\n", PACKAGE, SLURM_VERSION);
-}
-
-/*
- * verify that a connection type in arg is of known form
- * returns the connection_type or -1 if not recognized
- */
-static int _verify_conn_type(const char *arg)
-{
-	int len = strlen(arg);
-
-	if (!strncasecmp(arg, "MESH", len))
-		return SELECT_MESH;
-	else if (!strncasecmp(arg, "TORUS", len))
-		return SELECT_TORUS;
-	else if (!strncasecmp(arg, "NAV", len))
-		return SELECT_NAV;
-
-	error("invalid --conn-type argument %s ignored.", arg);
-	return -1;
-}
-
-/*
- * verify geometry arguments, must have proper count
- * returns -1 on error, 0 otherwise
- */
-static int _verify_geometry(const char *arg, uint16_t *geometry)
-{
-	char* token, *delimiter = ",x", *next_ptr;
-	int i, rc = 0;
-	char* geometry_tmp = xstrdup(arg);
-	char* original_ptr = geometry_tmp;
-
-	token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (token == NULL) {
-			error("insufficient dimensions in --geometry");
-			rc = -1;
-			break;
-		}
-		geometry[i] = (uint16_t)atoi(token);
-		if (geometry[i] == 0 || geometry[i] == (uint16_t)NO_VAL) {
-			error("invalid --geometry argument");
-			rc = -1;
-			break;
-		}
-		geometry_tmp = next_ptr;
-		token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	}
-	if (token != NULL) {
-		error("too many dimensions in --geometry");
-		rc = -1;
-	}
-
-	if (original_ptr)
-		xfree(original_ptr);
-
-	return rc;
-}
-
-/* 
- * verify that a node count in arg is of a known form (count or min-max)
- * OUT min, max specified minimum and maximum node counts
- * RET true if valid
- */
-static bool 
-_verify_node_count(const char *arg, int *min_nodes, int *max_nodes)
-{
-	char *end_ptr;
-	double val1, val2;
-	
-	val1 = strtod(arg, &end_ptr);
-	if (end_ptr[0] == 'k' || end_ptr[0] == 'K') {
-		val1 *= 1024;
-		end_ptr++;
-	}
-
- 	if (end_ptr[0] == '\0') {
-		*min_nodes = val1;
-		return true;
-	}
-	
-	if (end_ptr[0] != '-')
-		return false;
-
-	val2 = strtod(&end_ptr[1], &end_ptr);
-	if (end_ptr[0] == 'k' || end_ptr[0] == 'K') {
-		val2 *= 1024;
-		end_ptr++;
-	}
-
-	if (end_ptr[0] == '\0') {
-		*min_nodes = val1;
-		*max_nodes = val2;
-		return true;
-	} else
-		return false;
-
-}
-
-/* return command name from its full path name */
-static char * _base_name(char* command)
-{
-	char *char_ptr, *name;
-	int i;
-
-	if (command == NULL)
-		return NULL;
-
-	char_ptr = strrchr(command, (int)'/');
-	if (char_ptr == NULL)
-		char_ptr = command;
-	else
-		char_ptr++;
-
-	i = strlen(char_ptr);
-	name = xmalloc(i+1);
-	strcpy(name, char_ptr);
-	return name;
-}
-
-/*
- * _to_bytes(): verify that arg is numeric with optional "G" or "M" at end
- * if "G" or "M" is there, multiply by proper power of 2 and return
- * number in bytes
- */
-static long _to_bytes(const char *arg)
-{
-	char *buf;
-	char *endptr;
-	int end;
-	int multiplier = 1;
-	long result;
-
-	buf = xstrdup(arg);
-
-	end = strlen(buf) - 1;
-
-	if (isdigit(buf[end])) {
-		result = strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-
-	} else {
-
-		switch (toupper(buf[end])) {
-
-		case 'G':
-			multiplier = 1024;
-			break;
-
-		case 'M':
-			/* do nothing */
-			break;
-
-		default:
-			multiplier = -1;
-		}
-
-		buf[end] = '\0';
-
-		result = multiplier * strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-	}
-
-	return result;
-}
-
 /*
  * print error message to stderr with opt.progname prepended
  */
@@ -398,8 +217,17 @@ static void _opt_default()
 	opt.cpus_set = false;
 	opt.min_nodes = 1;
 	opt.max_nodes = 0;
-	opt.tasks_per_node   = -1;
 	opt.nodes_set = false;
+	opt.min_sockets_per_node = NO_VAL; /* requested min/maxsockets */
+	opt.max_sockets_per_node = NO_VAL;
+	opt.min_cores_per_socket = NO_VAL; /* requested min/maxcores */
+	opt.max_cores_per_socket = NO_VAL;
+	opt.min_threads_per_core = NO_VAL; /* requested min/maxthreads */
+	opt.max_threads_per_core = NO_VAL;
+	opt.ntasks_per_node      = NO_VAL; /* ntask max limits */
+	opt.ntasks_per_socket    = NO_VAL;
+	opt.ntasks_per_core      = NO_VAL;
+	opt.cpu_bind_type = 0;		/* local dummy variable for now */
 	opt.time_limit = NO_VAL;
 	opt.partition = NULL;
 
@@ -410,6 +238,9 @@ static void _opt_default()
 	opt.account  = NULL;
 	opt.comment  = NULL;
 
+	opt.distribution = SLURM_DIST_UNKNOWN;
+	opt.plane_size   = NO_VAL;
+
 	opt.shared = (uint16_t)NO_VAL;
 	opt.no_kill = false;
 
@@ -425,6 +256,7 @@ static void _opt_default()
 	opt.minsockets      = -1;
 	opt.mincores        = -1;
 	opt.minthreads      = -1;
+	opt.jobmem	    = -1;
 	opt.realmem	    = -1;
 	opt.tmpdisk	    = -1;
 
@@ -556,9 +388,9 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_NODES:
-		opt.nodes_set = _verify_node_count( val, 
-						    &opt.min_nodes, 
-						    &opt.max_nodes );
+		opt.nodes_set = verify_node_count( val, 
+						   &opt.min_nodes, 
+						   &opt.max_nodes );
 		if (opt.nodes_set == false) {
 			error("\"%s=%s\" -- invalid node count. ignoring...",
 			      e->var, val);
@@ -566,7 +398,7 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_CONN_TYPE:
-		opt.conn_type = _verify_conn_type(val);
+		opt.conn_type = verify_conn_type(val);
 		break;
 	
 	case OPT_NO_ROTATE:
@@ -574,7 +406,7 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_GEOMETRY:
-		if (_verify_geometry(val, opt.geometry)) {
+		if (verify_geometry(val, opt.geometry)) {
 			error("\"%s=%s\" -- invalid geometry, ignoring...",
 			      e->var, val);
 		}
@@ -602,6 +434,7 @@ static struct option long_options[] = {
 							 is only here for
 							 moab tansition
 							 doesn't do anything */
+	{"extra-node-info", required_argument, 0, 'B'},
 	{"cpus-per-task", required_argument, 0, 'c'},
 	{"constraint",    required_argument, 0, 'C'},
 	{"dependency",    required_argument, 0, 'd'},
@@ -615,7 +448,8 @@ static struct option long_options[] = {
 	{"immediate",     no_argument,       0, 'I'},
 	{"job-name",      required_argument, 0, 'J'},
 	{"no-kill",       no_argument,       0, 'k'},
-	{"tasks",         required_argument, 0, 'n'},
+	{"distribution",  required_argument, 0, 'm'},
+	{"ntasks",        required_argument, 0, 'n'},
 	{"nodes",         required_argument, 0, 'N'},
 	{"output",        required_argument, 0, 'o'},
 	{"overcommit",    no_argument,       0, 'O'},
@@ -637,6 +471,8 @@ static struct option long_options[] = {
 	{"mincores",      required_argument, 0, LONG_OPT_MINCORES},
 	{"minthreads",    required_argument, 0, LONG_OPT_MINTHREADS},
 	{"mem",           required_argument, 0, LONG_OPT_MEM},
+	{"job-mem",       required_argument, 0, LONG_OPT_JOBMEM},
+	{"hint",          required_argument, 0, LONG_OPT_HINT},
 	{"tmp",           required_argument, 0, LONG_OPT_TMP},
 	{"jobid",         required_argument, 0, LONG_OPT_JOBID},
 	{"uid",           required_argument, 0, LONG_OPT_UID},
@@ -648,20 +484,25 @@ static struct option long_options[] = {
 	{"nice",          optional_argument, 0, LONG_OPT_NICE},
 	{"no-requeue",    no_argument,       0, LONG_OPT_NO_REQUEUE},
 	{"comment",       required_argument, 0, LONG_OPT_COMMENT},
+	{"sockets-per-node", required_argument, 0, LONG_OPT_SOCKETSPERNODE},
+	{"cores-per-socket", required_argument, 0, LONG_OPT_CORESPERSOCKET},
+	{"threads-per-core", required_argument, 0, LONG_OPT_THREADSPERCORE},
+	{"ntasks-per-node",  required_argument, 0, LONG_OPT_NTASKSPERNODE},
+	{"ntasks-per-socket",required_argument, 0, LONG_OPT_NTASKSPERSOCKET},
+	{"ntasks-per-core",  required_argument, 0, LONG_OPT_NTASKSPERCORE},
 	{"blrts-image",   required_argument, 0, LONG_OPT_BLRTS_IMAGE},
 	{"linux-image",   required_argument, 0, LONG_OPT_LINUX_IMAGE},
 	{"mloader-image", required_argument, 0, LONG_OPT_MLOADER_IMAGE},
 	{"ramdisk-image", required_argument, 0, LONG_OPT_RAMDISK_IMAGE},
 	{"reboot",        no_argument,       0, LONG_OPT_REBOOT},
-	{"tasks-per-node",  required_argument,0,LONG_OPT_TASKSPERNODE},
-	{"ntasks-per-node", required_argument,0,LONG_OPT_TASKSPERNODE}, 
+	{"tasks-per-node",required_argument, 0, LONG_OPT_NTASKSPERNODE},
 	{"wrap",          required_argument, 0, LONG_OPT_WRAP},
 	{"get-user-env",  no_argument,       0, LONG_OPT_GET_USER_ENV},
 	{NULL,            0,                 0, 0}
 };
 
 static char *opt_string =
-	"+a:bc:C:d:D:e:F:g:hHi:IJ:kn:N:o:Op:qR:st:uU:vVw:x:";
+	"+a:bB:c:C:d:D:e:F:g:hHi:IJ:km:n:N:o:Op:qR:st:uU:vVw:x:";
 
 
 /*
@@ -712,7 +553,7 @@ char *process_options_first_pass(int argc, char **argv)
 			opt.verbose++;
 			break;
 		case 'V':
-			_print_version();
+			print_slurm_version();
 			exit(0);
 			break;
 		case LONG_OPT_WRAP:
@@ -746,7 +587,7 @@ char *process_options_first_pass(int argc, char **argv)
 		char *cmd       = opt.script_argv[0];
 		int  mode       = R_OK;
 
-		if ((fullpath = _search_path(cmd, true, mode))) {
+		if ((fullpath = search_path(opt.cwd, cmd, true, mode))) {
 			xfree(opt.script_argv[0]);
 			opt.script_argv[0] = fullpath;
 		} 
@@ -1010,6 +851,24 @@ static void _set_options(int argc, char **argv)
 			/* Only here for Moab transition not suppose
 			   to do anything */
 			break;
+		case 'B':
+			opt.extra_set = verify_socket_core_thread_count(
+				optarg,
+				&opt.min_sockets_per_node,
+				&opt.max_sockets_per_node,
+				&opt.min_cores_per_socket,
+				&opt.max_cores_per_socket,
+				&opt.min_threads_per_core,
+				&opt.max_threads_per_core,
+				&opt.cpu_bind_type);
+
+
+			if (opt.extra_set == false) {
+				error("invalid resource allocation -B `%s'",
+					optarg);
+				exit(1);
+			}
+			break;
 		case 'c':
 			opt.cpus_set = true;
 			opt.cpus_per_task = 
@@ -1045,7 +904,7 @@ static void _set_options(int argc, char **argv)
 			}
 			break;
 		case 'g':
-			if (_verify_geometry(optarg, opt.geometry))
+			if (verify_geometry(optarg, opt.geometry))
 				exit(1);
 			break;
 		case 'h':
@@ -1071,6 +930,15 @@ static void _set_options(int argc, char **argv)
 		case 'k':
 			opt.no_kill = true;
 			break;
+		case 'm':
+			opt.distribution = verify_dist_type(optarg, 
+							    &opt.plane_size);
+			if (opt.distribution == SLURM_DIST_UNKNOWN) {
+				error("distribution type `%s' " 
+				      "is not recognized", optarg);
+				exit(1);
+			}
+			break;
 		case 'n':
 			opt.nprocs_set = true;
 			opt.nprocs = 
@@ -1078,9 +946,9 @@ static void _set_options(int argc, char **argv)
 			break;
 		case 'N':
 			opt.nodes_set = 
-				_verify_node_count(optarg, 
-						   &opt.min_nodes,
-						   &opt.max_nodes);
+				verify_node_count(optarg, 
+						  &opt.min_nodes,
+						  &opt.max_nodes);
 			if (opt.nodes_set == false) {
 				error("invalid node count `%s'", 
 				      optarg);
@@ -1125,7 +993,7 @@ static void _set_options(int argc, char **argv)
 			opt.verbose++;
 			break;
 		case 'V':
-			_print_version();
+			print_slurm_version();
 			exit(0);
 			break;
 		case 'w':
@@ -1181,15 +1049,23 @@ static void _set_options(int argc, char **argv)
 			}
 			break;
 		case LONG_OPT_MEM:
-			opt.realmem = (int) _to_bytes(optarg);
+			opt.realmem = (int) str_to_bytes(optarg);
 			if (opt.realmem < 0) {
 				error("invalid memory constraint %s", 
 				      optarg);
 				exit(1);
 			}
 			break;
+		case LONG_OPT_JOBMEM:
+			opt.jobmem = (int) str_to_bytes(optarg);
+			if (opt.jobmem < 0) {
+				error("invalid memory constraint %s", 
+				      optarg);
+				exit(1);
+			}
+			break;
 		case LONG_OPT_TMP:
-			opt.tmpdisk = _to_bytes(optarg);
+			opt.tmpdisk = str_to_bytes(optarg);
 			if (opt.tmpdisk < 0) {
 				error("invalid tmp value %s", optarg);
 				exit(1);
@@ -1210,13 +1086,13 @@ static void _set_options(int argc, char **argv)
 				fatal ("--gid=\"%s\" invalid", optarg);
 			break;
 		case LONG_OPT_CONNTYPE:
-			opt.conn_type = _verify_conn_type(optarg);
+			opt.conn_type = verify_conn_type(optarg);
 			break;
 		case LONG_OPT_BEGIN:
 			opt.begin = parse_time(optarg);
 			break;
 		case LONG_OPT_MAIL_TYPE:
-			opt.mail_type |= _parse_mail_type(optarg);
+			opt.mail_type |= parse_mail_type(optarg);
 			if (opt.mail_type == 0)
 				fatal("--mail-type=%s invalid", optarg);
 			break;
@@ -1242,6 +1118,48 @@ static void _set_options(int argc, char **argv)
 			xfree(opt.comment);
 			opt.comment = xstrdup(optarg);
 			break;
+		case LONG_OPT_SOCKETSPERNODE:
+			get_resource_arg_range( optarg, "sockets-per-node",
+						&opt.min_sockets_per_node,
+						&opt.max_sockets_per_node,
+						true );
+			break;
+		case LONG_OPT_CORESPERSOCKET:
+			get_resource_arg_range( optarg, "cores-per-socket",
+						&opt.min_cores_per_socket,
+						&opt.max_cores_per_socket,
+						true);
+			break;
+		case LONG_OPT_THREADSPERCORE:
+			get_resource_arg_range( optarg, "threads-per-core",
+						&opt.min_threads_per_core,
+						&opt.max_threads_per_core,
+						true );
+			break;
+		case LONG_OPT_HINT:
+			if (verify_hint(optarg,
+				&opt.min_sockets_per_node,
+				&opt.max_sockets_per_node,
+				&opt.min_cores_per_socket,
+				&opt.max_cores_per_socket,
+				&opt.min_threads_per_core,
+				&opt.max_threads_per_core,
+				&opt.cpu_bind_type)) {
+				exit(1);
+			}
+			break;
+		case LONG_OPT_NTASKSPERNODE:
+			opt.ntasks_per_node = _get_int(optarg,
+				"ntasks-per-node");
+			break;
+		case LONG_OPT_NTASKSPERSOCKET:
+			opt.ntasks_per_socket = _get_int(optarg, 
+				"ntasks-per-socket");
+			break;
+		case LONG_OPT_NTASKSPERCORE:
+			opt.ntasks_per_core = _get_int(optarg,
+				"ntasks-per-core");
+			break;
 		case LONG_OPT_BLRTS_IMAGE:
 			xfree(opt.blrtsimage);
 			opt.blrtsimage = xstrdup(optarg);
@@ -1261,9 +1179,6 @@ static void _set_options(int argc, char **argv)
 		case LONG_OPT_REBOOT:
 			opt.reboot = true;
 			break;
-		case LONG_OPT_TASKSPERNODE:
-			opt.tasks_per_node = _get_int(optarg, "ntasks-per-node");
-			break;
 		case LONG_OPT_WRAP:
 			/* handled in process_options_first_pass() */
 			break;
@@ -1554,7 +1469,7 @@ static void _parse_pbs_resource_list(char *rl)
 				 */
 				temp[end] = '\0';
 			}
-			opt.tmpdisk = _to_bytes(temp);
+			opt.tmpdisk = str_to_bytes(temp);
 			if (opt.tmpdisk < 0) {
 				error("invalid tmp value %s", temp);
 				exit(1);
@@ -1578,7 +1493,7 @@ static void _parse_pbs_resource_list(char *rl)
 				 */
 				temp[end] = '\0';
 			}
-			opt.realmem = (int) _to_bytes(temp);
+			opt.realmem = (int) str_to_bytes(temp);
 			if (opt.realmem < 0) {
 				error("invalid memory constraint %s", 
 				      temp);
@@ -1663,7 +1578,7 @@ static bool _opt_verify(void)
 		opt.mincpus = opt.cpus_per_task;
 
 	if ((opt.job_name == NULL) && (opt.script_argc > 0))
-		opt.job_name = _base_name(opt.script_argv[0]);
+		opt.job_name = base_name(opt.script_argv[0]);
 
 	/* check for realistic arguments */
 	if (opt.nprocs <= 0) {
@@ -1685,11 +1600,87 @@ static bool _opt_verify(void)
 		verified = false;
 	}
 
+        /* When CR with memory as a CR is enabled we need to assign
+	   adequate value or check the value to opt.mem */
+	if ((opt.realmem >= -1) && (opt.jobmem > 0)) {
+		if (opt.realmem == -1) {
+			opt.realmem = opt.jobmem;
+		} else if (opt.realmem < opt.jobmem) {
+			info("mem < job-mem - resizing mem to be equal to job-mem");
+			opt.realmem = opt.jobmem;
+		}
+	}
+	
+        /* Check to see if user has specified enough resources to
+	 * satisfy the plane distribution with the specified
+	 * plane_size.  
+	 * if (n/plane_size < N) and ((N-1) * plane_size >= n) -->
+	 * problem Simple check will not catch all the problem/invalid
+	 * cases.
+	 * The limitations of the plane distribution in the cons_res
+	 * environment are more extensive and are documented in the
+	 * SLURM reference guide.  */
+	if (opt.distribution == SLURM_DIST_PLANE && opt.plane_size) {
+		if ((opt.nprocs/opt.plane_size) < opt.min_nodes) {
+			if (((opt.min_nodes-1)*opt.plane_size) >= opt.nprocs) {
+#if(0)
+				info("Too few processes ((n/plane_size) %d < N %d) "
+				     "and ((N-1)*(plane_size) %d >= n %d)) ",
+				     opt.nprocs/opt.plane_size, opt.min_nodes, 
+				     (opt.min_nodes-1)*opt.plane_size, opt.nprocs);
+#endif
+				error("Too few processes for the requested "
+				      "{plane,node} distribution");
+				exit(1);
+			}
+		}
+	}
+
+	/* bound max_threads/cores from ntasks_cores/sockets */ 
+	if ((opt.max_threads_per_core <= 0) &&
+	    (opt.ntasks_per_core > 0)) {
+		opt.max_threads_per_core = opt.ntasks_per_core;
+		/* if cpu_bind_type doesn't already have a auto pref,
+		 * choose the level based on the level of ntasks
+		 */
+		if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
+					   CPU_BIND_TO_CORES |
+					   CPU_BIND_TO_THREADS))) {
+			opt.cpu_bind_type |= CPU_BIND_TO_CORES;
+		}
+	}
+	if ((opt.max_cores_per_socket <= 0) &&
+	    (opt.ntasks_per_socket > 0)) {
+		opt.max_cores_per_socket = opt.ntasks_per_socket;
+		/* if cpu_bind_type doesn't already have a auto pref,
+		 * choose the level based on the level of ntasks
+		 */
+		if (!(opt.cpu_bind_type & (CPU_BIND_TO_SOCKETS |
+					   CPU_BIND_TO_CORES |
+					   CPU_BIND_TO_THREADS))) {
+			opt.cpu_bind_type |= CPU_BIND_TO_SOCKETS;
+		}
+	}
+
 	/* massage the numbers */
-	if (opt.nodes_set && !opt.nprocs_set) {
+	if ((opt.nodes_set || opt.extra_set) && !opt.nprocs_set) {
 		/* 1 proc / node default */
 		opt.nprocs = opt.min_nodes;
 
+		/* 1 proc / min_[socket * core * thread] default */
+		if (opt.min_sockets_per_node > 0) {
+			opt.nprocs *= opt.min_sockets_per_node;
+			opt.nprocs_set = true;
+		}
+		if (opt.min_cores_per_socket > 0) {
+			opt.nprocs *= opt.min_cores_per_socket;
+			opt.nprocs_set = true;
+		}
+		if (opt.min_threads_per_core > 0) {
+			opt.nprocs *= opt.min_threads_per_core;
+			opt.nprocs_set = true;
+		}
+
 	} else if (opt.nodes_set && opt.nprocs_set) {
 
 		/* 
@@ -1741,24 +1732,6 @@ static bool _opt_verify(void)
 	return verified;
 }
 
-static uint16_t _parse_mail_type(const char *arg)
-{
-	uint16_t rc;
-
-	if (strcasecmp(arg, "BEGIN") == 0)
-		rc = MAIL_JOB_BEGIN;
-	else if  (strcasecmp(arg, "END") == 0)
-		rc = MAIL_JOB_END;
-	else if (strcasecmp(arg, "FAIL") == 0)
-		rc = MAIL_JOB_FAIL;
-	else if (strcasecmp(arg, "ALL") == 0)
-		rc = MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL;
-	else
-		rc = 0;		/* failure */
-
-	return rc;
-}
-
 static uint16_t _parse_pbs_mail_type(const char *arg)
 {
 	uint16_t rc;
@@ -1789,97 +1762,6 @@ static uint16_t _parse_pbs_mail_type(const char *arg)
 	return rc;
 }
 
-static char *_print_mail_type(const uint16_t type)
-{
-	if (type == 0)
-		return "NONE";
-
-	if (type == MAIL_JOB_BEGIN)
-		return "BEGIN";
-	if (type == MAIL_JOB_END)
-		return "END";
-	if (type == MAIL_JOB_FAIL)
-		return "FAIL";
-	if (type == (MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL))
-		return "ALL";
-
-	return "MULTIPLE";
-}
-
-static void
-_freeF(void *data)
-{
-	xfree(data);
-}
-
-static List
-_create_path_list(void)
-{
-	List l = list_create(_freeF);
-	char *path = xstrdup(getenv("PATH"));
-	char *c, *lc;
-
-	if (!path) {
-		error("Error in PATH environment variable");
-		list_destroy(l);
-		return NULL;
-	}
-
-	c = lc = path;
-
-	while (*c != '\0') {
-		if (*c == ':') {
-			/* nullify and push token onto list */
-			*c = '\0';
-			if (lc != NULL && strlen(lc) > 0)
-				list_append(l, xstrdup(lc));
-			lc = ++c;
-		} else
-			c++;
-	}
-
-	if (strlen(lc) > 0)
-		list_append(l, xstrdup(lc));
-
-	xfree(path);
-
-	return l;
-}
-
-static char *
-_search_path(char *cmd, bool check_current_dir, int access_mode)
-{
-	List         l        = _create_path_list();
-	ListIterator i        = NULL;
-	char *path, *fullpath = NULL;
-
-	if (  (cmd[0] == '.' || cmd[0] == '/') 
-           && (access(cmd, access_mode) == 0 ) ) {
-		if (cmd[0] == '.')
-			xstrfmtcat(fullpath, "%s/", opt.cwd);
-		xstrcat(fullpath, cmd);
-		goto done;
-	}
-
-	if (check_current_dir) 
-		list_prepend(l, xstrdup(opt.cwd));
-
-	i = list_iterator_create(l);
-	while ((path = list_next(i))) {
-		xstrfmtcat(fullpath, "%s/%s", path, cmd);
-
-		if (access(fullpath, access_mode) == 0)
-			goto done;
-
-		xfree(fullpath);
-		fullpath = NULL;
-	}
-  done:
-	list_destroy(l);
-	return fullpath;
-}
-
-
 /* helper function for printing options
  * 
  * warning: returns pointer to memory allocated on the stack.
@@ -1891,9 +1773,21 @@ static char *print_constraints()
 	if (opt.mincpus > 0)
 		xstrfmtcat(buf, "mincpus=%d ", opt.mincpus);
 
+	if (opt.minsockets > 0)
+		xstrfmtcat(buf, "minsockets=%d ", opt.minsockets);
+
+	if (opt.mincores > 0)
+		xstrfmtcat(buf, "mincores=%d ", opt.mincores);
+
+	if (opt.minthreads > 0)
+		xstrfmtcat(buf, "minthreads=%d ", opt.minthreads);
+
 	if (opt.realmem > 0)
 		xstrfmtcat(buf, "mem=%dM ", opt.realmem);
 
+	if (opt.jobmem > 0)
+		xstrfmtcat(buf, "job-mem=%dM ", opt.jobmem);
+
 	if (opt.tmpdisk > 0)
 		xstrfmtcat(buf, "tmp=%ld ", opt.tmpdisk);
 
@@ -1912,40 +1806,6 @@ static char *print_constraints()
 	return buf;
 }
 
-static char * 
-print_commandline()
-{
-	int i;
-	char buf[256];
-
-	buf[0] = '\0';
-	for (i = 0; i < opt.script_argc; i++)
-		snprintf(buf, 256,  "%s", opt.script_argv[i]);
-	return xstrdup(buf);
-}
-
-static char *
-print_geometry()
-{
-	int i;
-	char buf[32], *rc = NULL;
-
-	if ((SYSTEM_DIMENSIONS == 0)
-	||  (opt.geometry[0] == (uint16_t)NO_VAL))
-		return NULL;
-
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (i > 0)
-			snprintf(buf, sizeof(buf), "x%u", opt.geometry[i]);
-		else
-			snprintf(buf, sizeof(buf), "%u", opt.geometry[i]);
-		xstrcat(rc, buf);
-	}
-
-	return rc;
-}
-
-
 /*
  *  Get a decimal integer from arg.
  *
@@ -2022,6 +1882,9 @@ static void _opt_list()
 	info("partition      : %s",
 		opt.partition == NULL ? "default" : opt.partition);
 	info("job name       : `%s'", opt.job_name);
+	info("distribution   : %s", format_task_dist_states(opt.distribution));
+	if(opt.distribution == SLURM_DIST_PLANE)
+		info("plane size   : %u", opt.plane_size);
 	info("verbose        : %d", opt.verbose);
 	info("immediate      : %s", tf_(opt.immediate));
 	info("no-requeue     : %s", tf_(opt.no_requeue));
@@ -2043,7 +1906,7 @@ static void _opt_list()
 	xfree(str);
 	if (opt.conn_type != (uint16_t) NO_VAL)
 		info("conn_type      : %u", opt.conn_type);
-	str = print_geometry();
+	str = print_geometry(opt.geometry);
 	info("geometry       : %s", str);
 	xfree(str);
 	info("reboot         : %s", opt.reboot ? "no" : "yes");
@@ -2063,10 +1926,19 @@ static void _opt_list()
 		slurm_make_time_str(&opt.begin, time_str, sizeof(time_str));
 		info("begin          : %s", time_str);
 	}
-	info("mail_type      : %s", _print_mail_type(opt.mail_type));
+	info("mail_type      : %s", print_mail_type(opt.mail_type));
 	info("mail_user      : %s", opt.mail_user);
-	info("tasks-per-node : %d", opt.tasks_per_node);
-	str = print_commandline();
+	info("sockets-per-node  : %d - %d", opt.min_sockets_per_node,
+					    opt.max_sockets_per_node);
+	info("cores-per-socket  : %d - %d", opt.min_cores_per_socket,
+					    opt.max_cores_per_socket);
+	info("threads-per-core  : %d - %d", opt.min_threads_per_core,
+					    opt.max_threads_per_core);
+	info("ntasks-per-node   : %d", opt.ntasks_per_node);
+	info("ntasks-per-socket : %d", opt.ntasks_per_socket);
+	info("ntasks-per-core   : %d", opt.ntasks_per_core);
+	info("plane_size        : %u", opt.plane_size);
+	str = print_commandline(opt.script_argc, opt.script_argv);
 	info("remote command : `%s'", str);
 	xfree(str);
 
@@ -2097,6 +1969,8 @@ static void _usage(void)
 
 static void _help(void)
 {
+	slurm_ctl_conf_t *conf;
+
         printf (
 "Usage: sbatch [OPTIONS...] executable [args...]\n"
 "\n"
@@ -2149,7 +2023,30 @@ static void _help(void)
 "Consumable resources related options:\n" 
 "      --exclusive             allocate nodes in exclusive mode when\n" 
 "                              cpu consumable resource is enabled\n"
+"      --job-mem=MB            maximum amount of real memory per node\n"
+"                              required by the job.\n" 
+"                              --mem >= --job-mem if --mem is specified.\n" 
 "\n"
+"Affinity/Multi-core options: (when the task/affinity plugin is enabled)\n" 
+"  -B --extra-node-info=S[:C[:T]]            Expands to:\n"
+"      --sockets-per-node=S    number of sockets per node to allocate\n"
+"      --cores-per-socket=C    number of cores per socket to allocate\n"
+"      --threads-per-core=T    number of threads per core to allocate\n"
+"                              each field can be 'min[-max]' or wildcard '*'\n"
+"                              total cpus requested = (N x S x C x T)\n"
+"\n"
+"      --ntasks-per-socket=n   number of tasks to invoke on each socket\n"
+"      --ntasks-per-core=n     number of tasks to invoke on each core\n");
+	conf = slurm_conf_lock();
+	if (conf->task_plugin != NULL
+	    && strcasecmp(conf->task_plugin, "task/affinity") == 0) {
+		printf(
+"      --hint=                 Bind tasks according to application hints\n"
+"                              (see \"--hint=help\" for options)\n");
+	}
+	slurm_conf_unlock();
+
+        printf("\n"
 #ifdef HAVE_BG				/* Blue gene specific options */
 "Blue Gene related options:\n"
 "  -g, --geometry=XxYxZ        geometry constraints of the job\n"
@@ -2161,8 +2058,8 @@ static void _help(void)
 "      --linux-image=path      path to linux image for bluegene block.  Default if not set\n"
 "      --mloader-image=path    path to mloader image for bluegene block.  Default if not set\n"
 "      --ramdisk-image=path    path to ramdisk image for bluegene block.  Default if not set\n"
-"\n"
 #endif
+"\n"
 "Help options:\n"
 "  -h, --help                  show this help message\n"
 "  -u, --usage                 display brief usage message\n"
diff --git a/src/sbatch/opt.h b/src/sbatch/opt.h
index 1b10d7c5391..330ecf7d07c 100644
--- a/src/sbatch/opt.h
+++ b/src/sbatch/opt.h
@@ -42,6 +42,7 @@
 
 #define MAX_USERNAME	9
 
+
 typedef struct sbatch_options {
 	char *progname;		/* argv[0] of this program or   */
 
@@ -63,9 +64,25 @@ typedef struct sbatch_options {
 	int  min_nodes;		/* --nodes=n,       -N n	*/ 
 	int  max_nodes;		/* --nodes=x-n,       -N x-n	*/ 
 	bool nodes_set;		/* true if nodes explicitly set */
+	int min_sockets_per_node; /* --sockets-per-node=n      */
+	int max_sockets_per_node; /* --sockets-per-node=x-n    */
+	int min_cores_per_socket; /* --cores-per-socket=n      */
+	int max_cores_per_socket; /* --cores-per-socket=x-n    */
+	int min_threads_per_core; /* --threads-per-core=n      */
+	int max_threads_per_core; /* --threads-per-core=x-n    */
+	int ntasks_per_node;   /* --ntasks-per-node=n	    */
+	int ntasks_per_socket; /* --ntasks-per-socket=n     */
+	int ntasks_per_core;   /* --ntasks-per-core=n	    */
+	cpu_bind_type_t cpu_bind_type; /* --cpu_bind=           */
+	bool extra_set;		/* true if extra node info explicitly set */
 	int  time_limit;	/* --time,   -t	(int minutes)	*/
 	char *time_limit_str;	/* --time,   -t (string)	*/
 	char *partition;	/* --partition=n,   -p n   	*/
+	enum task_dist_states
+	        distribution;	/* --distribution=, -m dist	*/
+        uint32_t plane_size;    /* lllp distribution -> plane_size for
+				 * when -m plane=<# of lllp per
+				 * plane> */      
 	char *job_name;		/* --job-name=,     -J name	*/
 	unsigned int jobid;     /* --jobid=jobid                */
 	bool jobid_set;		/* true of jobid explicitly set */
@@ -91,9 +108,9 @@ typedef struct sbatch_options {
 	int minsockets;		/* --minsockets=n		*/
 	int mincores;		/* --mincores=n			*/
 	int minthreads;		/* --minthreads=n		*/
+	int jobmem;		/* --job-mem=n			*/
 	int realmem;		/* --mem=n			*/
 	long tmpdisk;		/* --tmp=n			*/
-	int tasks_per_node;	/* --tasks-per-node=n		*/
 	char *constraints;	/* --constraints=, -C constraint*/
 	bool contiguous;	/* --contiguous			*/
 	char *nodelist;		/* --nodelist=node1,node2,...	*/
diff --git a/src/sbatch/sbatch.c b/src/sbatch/sbatch.c
index 165f108625d..c0fe4f113ef 100644
--- a/src/sbatch/sbatch.c
+++ b/src/sbatch/sbatch.c
@@ -128,6 +128,9 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 	desc->user_id = opt.uid;
 	desc->group_id = opt.gid;
 	desc->dependency = opt.dependency;
+	desc->task_dist  = opt.distribution;
+	if (opt.plane_size != NO_VAL)
+		desc->plane_size = opt.plane_size;
 	if (opt.nice)
 		desc->nice = NICE_OFFSET + opt.nice;
 	desc->mail_type = opt.mail_type;
@@ -164,6 +167,7 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 	if (opt.ramdiskimage)
 		desc->ramdiskimage = xstrdup(opt.ramdiskimage);
 
+	/* job constraints */
 	if (opt.mincpus > -1)
 		desc->job_min_procs = opt.mincpus;
 	if (opt.minsockets > -1)
@@ -172,6 +176,8 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 		desc->job_min_cores = opt.mincores;
 	if (opt.minthreads > -1)
 		desc->job_min_threads = opt.minthreads;
+	if (opt.jobmem > -1)
+		desc->job_max_memory = opt.jobmem;
 	if (opt.realmem > -1)
 		desc->job_min_memory = opt.realmem;
 	if (opt.tmpdisk > -1)
@@ -181,12 +187,29 @@ static int fill_job_desc_from_opts(job_desc_msg_t *desc)
 		desc->overcommit = opt.overcommit;
 	} else
 		desc->num_procs = opt.nprocs * opt.cpus_per_task;
-	if (opt.tasks_per_node > -1)
-		desc->ntasks_per_node = opt.tasks_per_node;
 	if (opt.nprocs_set)
 		desc->num_tasks = opt.nprocs;
 	if (opt.cpus_set)
 		desc->cpus_per_task = opt.cpus_per_task;
+	if (opt.ntasks_per_socket > -1)
+		desc->ntasks_per_socket = opt.ntasks_per_socket;
+	if (opt.ntasks_per_core > -1)
+		desc->ntasks_per_core = opt.ntasks_per_core;
+
+	/* node constraints */
+	if (opt.min_sockets_per_node > -1)
+		desc->min_sockets = opt.min_sockets_per_node;
+	if (opt.max_sockets_per_node > -1)
+		desc->max_sockets = opt.max_sockets_per_node;
+	if (opt.min_cores_per_socket > -1)
+		desc->min_cores = opt.min_cores_per_socket;
+	if (opt.max_cores_per_socket > -1)
+		desc->max_cores = opt.max_cores_per_socket;
+	if (opt.min_threads_per_core > -1)
+		desc->min_threads = opt.min_threads_per_core;
+	if (opt.max_threads_per_core > -1)
+		desc->max_threads = opt.max_threads_per_core;
+
 	if (opt.no_kill)
 		desc->kill_on_node_fail = 0;
 	if (opt.time_limit != NO_VAL)
diff --git a/src/srun/opt.c b/src/srun/opt.c
index e0188bef21b..e5541dce4a1 100644
--- a/src/srun/opt.c
+++ b/src/srun/opt.c
@@ -72,6 +72,7 @@
 #include "src/common/list.h"
 #include "src/common/log.h"
 #include "src/common/parse_time.h"
+#include "src/common/proc_args.h"
 #include "src/common/slurm_protocol_api.h"
 #include "src/common/slurm_protocol_interface.h"
 #include "src/common/uid.h"
@@ -169,15 +170,9 @@ opt_t opt;
 
 typedef struct env_vars env_vars_t;
 
-/* return command name from its full path name */
-static char * _base_name(char* command);
-
-static List  _create_path_list(void);
 
 /* Get a decimal integer from arg */
 static int  _get_int(const char *arg, const char *what, bool positive);
-static bool _get_resource_range(const char *arg, const char *what, 
-                                int *min, int *max, bool isFatal);
 
 static void  _help(void);
 
@@ -198,39 +193,16 @@ static void  _opt_list(void);
 /* verify options sanity  */
 static bool _opt_verify(void);
 
-static void  _print_version(void);
-
 static void _process_env_var(env_vars_t *e, const char *val);
 
-static uint16_t _parse_mail_type(const char *arg);
-static char *_print_mail_type(const uint16_t type);
-
-/* search PATH for command returns full path */
-static char *_search_path(char *, bool, int);
-
-static long  _to_bytes(const char *arg);
-
 static bool  _under_parallel_debugger(void);
 
 static void  _usage(void);
 static bool  _valid_node_list(char **node_list_pptr);
-static task_dist_states_t _verify_dist_type(const char *arg, uint32_t *psize);
-static bool  _verify_socket_core_thread_count(const char *arg,
-					   int *min_sockets, int *max_sockets,
-					   int *min_cores, int *max_cores,
-					   int *min_threads, int  *max_threads,
-					   cpu_bind_type_t *cpu_bind_type);
-static bool  _verify_hint(const char *arg,
-					   int *min_sockets, int *max_sockets,
-					   int *min_cores, int *max_cores,
-					   int *min_threads, int  *max_threads,
-					   cpu_bind_type_t *cpu_bind_type);
 static int   _verify_cpu_bind(const char *arg, char **cpu_bind,
 			      cpu_bind_type_t *flags);
-static int   _verify_geometry(const char *arg, uint16_t *geometry);
 static int   _verify_mem_bind(const char *arg, char **mem_bind,
 			      mem_bind_type_t *flags);
-static int   _verify_conn_type(const char *arg);
 
 /*---[ end forward declarations of static functions ]---------------------*/
 
@@ -255,11 +227,6 @@ int initialize_and_process_args(int argc, char *argv[])
 
 }
 
-static void _print_version(void)
-{
-	printf("%s %s\n", PACKAGE, SLURM_VERSION);
-}
-
 /*
  * If the node list supplied is a file name, translate that into 
  *	a list of nodes, we orphan the data pointed to
@@ -297,117 +264,6 @@ static bool _valid_node_list(char **node_list_pptr)
 	return true;
 }
 
-/* 
- * verify that a distribution type in arg is of a known form
- * returns the task_dist_states, or -1 if state is unknown
- */
-static task_dist_states_t _verify_dist_type(const char *arg, 
-					    uint32_t *plane_size)
-{
-	int len = strlen(arg);
-	char *dist_str = NULL;
-	task_dist_states_t result = SLURM_DIST_UNKNOWN;
-	bool lllp_dist = false, plane_dist = false;
-
-	dist_str = strchr(arg,':');
-	if (dist_str != NULL) {
-		/* -m cyclic|block:cyclic|block */
-		lllp_dist = true;
-	} else {
-		/* -m plane=<plane_size> */
-		dist_str = strchr(arg,'=');
-		if(dist_str != NULL) {
-			*plane_size=atoi(dist_str+1);
-			len = dist_str-arg;
-			plane_dist = true;
-		}
-	}
-
-	if (lllp_dist) {
-		if (strcasecmp(arg, "cyclic:cyclic") == 0) {
-			result = SLURM_DIST_CYCLIC_CYCLIC;
-		} else if (strcasecmp(arg, "cyclic:block") == 0) {
-			result = SLURM_DIST_CYCLIC_BLOCK;
-		} else if (strcasecmp(arg, "block:block") == 0) {
-			result = SLURM_DIST_BLOCK_BLOCK;
-		} else if (strcasecmp(arg, "block:cyclic") == 0) {
-			result = SLURM_DIST_BLOCK_CYCLIC;
-		}
-	} else if (plane_dist) {
-		if (strncasecmp(arg, "plane", len) == 0) {
-			result = SLURM_DIST_PLANE;
-		}
-	} else {
-		if (strncasecmp(arg, "cyclic", len) == 0) {
-			result = SLURM_DIST_CYCLIC;
-		} else if (strncasecmp(arg, "block", len) == 0) {
-			result = SLURM_DIST_BLOCK;
-		} else if ((strncasecmp(arg, "arbitrary", len) == 0) ||
-		           (strncasecmp(arg, "hostfile", len) == 0)) {
-			result = SLURM_DIST_ARBITRARY;
-		}
-	}
-
-	return result;
-}
-
-/*
- * verify that a connection type in arg is of known form
- * returns the connection_type or -1 if not recognized
- */
-static int _verify_conn_type(const char *arg)
-{
-	int len = strlen(arg);
-
-	if (!strncasecmp(arg, "MESH", len))
-		return SELECT_MESH;
-	else if (!strncasecmp(arg, "TORUS", len))
-		return SELECT_TORUS;
-	else if (!strncasecmp(arg, "NAV", len))
-		return SELECT_NAV;
-
-	error("invalid --conn-type argument %s ignored.", arg);
-	return -1;
-}
-
-/*
- * verify geometry arguments, must have proper count
- * returns -1 on error, 0 otherwise
- */
-static int _verify_geometry(const char *arg, uint16_t *geometry)
-{
-	char* token, *delimiter = ",x", *next_ptr;
-	int i, rc = 0;
-	char* geometry_tmp = xstrdup(arg);
-	char* original_ptr = geometry_tmp;
-
-	token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (token == NULL) {
-			error("insufficient dimensions in --geometry");
-			rc = -1;
-			break;
-		}
-		geometry[i] = (uint16_t)atoi(token);
-		if (geometry[i] == 0 || geometry[i] == (uint16_t)NO_VAL) {
-			error("invalid --geometry argument");
-			rc = -1;
-			break;
-		}
-		geometry_tmp = next_ptr;
-		token = strtok_r(geometry_tmp, delimiter, &next_ptr);
-	}
-	if (token != NULL) {
-		error("too many dimensions in --geometry");
-		rc = -1;
-	}
-
-	if (original_ptr)
-		xfree(original_ptr);
-
-	return rc;
-}
-
 /*
  * _isvalue
  * returns 1 is the argument appears to be a value, 0 otherwise
@@ -675,203 +531,6 @@ static int _verify_mem_bind(const char *arg, char **mem_bind,
 	return 0;
 }
 
-/* 
- * verify that a resource counts in arg are of a known form X, X:X, X:X:X, or 
- * X:X:X:X, where X is defined as either (count, min-max, or '*')
- * RET true if valid
- */
-static bool
-_verify_socket_core_thread_count(const char *arg, 
-			      int *min_sockets, int *max_sockets,
-			      int *min_cores, int *max_cores,
-			      int *min_threads, int  *max_threads,
-			      cpu_bind_type_t *cpu_bind_type)
-{
-	bool tmp_val,ret_val;
-	int i,j;
-	const char *cur_ptr = arg;
-	char buf[3][48]; /* each can hold INT64_MAX - INT64_MAX */
-	buf[0][0] = '\0';
-	buf[1][0] = '\0';
-	buf[2][0] = '\0';
-
- 	for (j=0;j<3;j++) {	
-		for (i=0;i<47;i++) {
-			if (*cur_ptr == '\0' || *cur_ptr ==':') break;
-			buf[j][i] = *cur_ptr++;
-		}
-		if (*cur_ptr == '\0') break;
-		xassert(*cur_ptr == ':');
-		buf[j][i] = '\0';
-		cur_ptr++;
-	}
-	/* if cpu_bind_type doesn't already have a auto preference, choose
-	 * the level based on the level of the -E specification
-	 */
-	if (!(*cpu_bind_type & (CPU_BIND_TO_SOCKETS |
-				CPU_BIND_TO_CORES |
-				CPU_BIND_TO_THREADS))) {
-		if (j == 0) {
-			*cpu_bind_type |= CPU_BIND_TO_SOCKETS;
-		} else if (j == 1) {
-			*cpu_bind_type |= CPU_BIND_TO_CORES;
-		} else if (j == 2) {
-			*cpu_bind_type |= CPU_BIND_TO_THREADS;
-		}
-        }
-	buf[j][i] = '\0';
-
-	ret_val = true;
-	tmp_val = _get_resource_range(&buf[0][0], "first arg of -B", 
-				      min_sockets, max_sockets, true);
-	ret_val = ret_val && tmp_val;
-	tmp_val = _get_resource_range(&buf[1][0], "second arg of -B", 
-				      min_cores, max_cores, true);
-	ret_val = ret_val && tmp_val;
-	tmp_val = _get_resource_range(&buf[2][0], "third arg of -B", 
-				      min_threads, max_threads, true);
-	ret_val = ret_val && tmp_val;
-
-	return ret_val;
-}
-
-/* 
- * verify that a hint is valid and convert it into the implied settings
- * RET true if valid
- */
-static bool
-_verify_hint(const char *arg, 
-			      int *min_sockets, int *max_sockets,
-			      int *min_cores, int *max_cores,
-			      int *min_threads, int  *max_threads,
-			      cpu_bind_type_t *cpu_bind_type)
-{
-	char *buf, *p, *tok;
-	if (!arg) {
-		return true;
-	}
-
-	buf = xstrdup(arg);
-	p = buf;
-	/* change all ',' delimiters not followed by a digit to ';'  */
-	/* simplifies parsing tokens while keeping map/mask together */
-	while (p[0] != '\0') {
-		if ((p[0] == ',') && (!isdigit(p[1])))
-			p[0] = ';';
-		p++;
-	}
-
-	p = buf;
-	while ((tok = strsep(&p, ";"))) {
-		if (strcasecmp(tok, "help") == 0) {
-			printf(
-"Application hint options:\n"
-"    --hint=             Bind tasks according to application hints\n"
-"        compute_bound   use all cores in each physical CPU\n"
-"        memory_bound    use only one core in each physical CPU\n"
-"        [no]multithread [don't] use extra threads with in-core multi-threading\n"
-"        help            show this help message\n");
-			return 1;
-		} else if (strcasecmp(tok, "compute_bound") == 0) {
-		        *min_sockets = 1;
-		        *max_sockets = INT_MAX;
-		        *min_cores   = 1;
-		        *max_cores   = INT_MAX;
-			*cpu_bind_type |= CPU_BIND_TO_CORES;
-		} else if (strcasecmp(tok, "memory_bound") == 0) {
-		        *min_cores = 1;
-		        *max_cores = 1;
-			*cpu_bind_type |= CPU_BIND_TO_CORES;
-		} else if (strcasecmp(tok, "multithread") == 0) {
-		        *min_threads = 1;
-		        *max_threads = INT_MAX;
-			*cpu_bind_type |= CPU_BIND_TO_THREADS;
-		} else if (strcasecmp(tok, "nomultithread") == 0) {
-		        *min_threads = 1;
-		        *max_threads = 1;
-			*cpu_bind_type |= CPU_BIND_TO_THREADS;
-		} else {
-			error("unrecognized --hint argument \"%s\", see --hint=help", tok);
-			xfree(buf);
-			return 1;
-		}
-	}
-
-	xfree(buf);
-	return 0;
-}
-
-/* return command name from its full path name */
-static char * _base_name(char* command)
-{
-	char *char_ptr, *name;
-	int i;
-
-	if (command == NULL)
-		return NULL;
-
-	char_ptr = strrchr(command, (int)'/');
-	if (char_ptr == NULL)
-		char_ptr = command;
-	else
-		char_ptr++;
-
-	i = strlen(char_ptr);
-	name = xmalloc(i+1);
-	strcpy(name, char_ptr);
-	return name;
-}
-
-/*
- * _to_bytes(): verify that arg is numeric with optional "G" or "M" at end
- * if "G" or "M" is there, multiply by proper power of 2 and return
- * number in bytes
- */
-static long _to_bytes(const char *arg)
-{
-	char *buf;
-	char *endptr;
-	int end;
-	int multiplier = 1;
-	long result;
-
-	buf = xstrdup(arg);
-
-	end = strlen(buf) - 1;
-
-	if (isdigit(buf[end])) {
-		result = strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-
-	} else {
-
-		switch (toupper(buf[end])) {
-
-		case 'G':
-			multiplier = 1024;
-			break;
-
-		case 'M':
-			/* do nothing */
-			break;
-
-		default:
-			multiplier = -1;
-		}
-
-		buf[end] = '\0';
-
-		result = multiplier * strtol(buf, &endptr, 10);
-
-		if (*endptr != '\0')
-			result = -result;
-	}
-
-	return result;
-}
-
 /*
  * print error message to stderr with opt.progname prepended
  */
@@ -1156,7 +815,7 @@ _process_env_var(env_vars_t *e, const char *val)
 	case OPT_DISTRIB:
 		if (strcmp(val, "unknown") == 0)
 			break;	/* ignore it, passed from salloc */
-		dt = _verify_dist_type(val, &opt.plane_size);
+		dt = verify_dist_type(val, &opt.plane_size);
 		if (dt == SLURM_DIST_UNKNOWN) {
 			error("\"%s=%s\" -- invalid distribution type. " 
 			      "ignoring...", e->var, val);
@@ -1177,9 +836,9 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_NODES:
-		opt.nodes_set = _get_resource_range( val ,"OPT_NODES", 
-						     &opt.min_nodes, 
-						     &opt.max_nodes, false);
+		opt.nodes_set = get_resource_arg_range( val ,"OPT_NODES", 
+							&opt.min_nodes, 
+							&opt.max_nodes, false);
 		if (opt.nodes_set == false) {
 			error("\"%s=%s\" -- invalid node count. ignoring...",
 			      e->var, val);
@@ -1200,7 +859,7 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 	    
 	case OPT_CONN_TYPE:
-		opt.conn_type = _verify_conn_type(val);
+		opt.conn_type = verify_conn_type(val);
 		break;
 
 	case OPT_NO_ROTATE:
@@ -1208,7 +867,7 @@ _process_env_var(env_vars_t *e, const char *val)
 		break;
 
 	case OPT_GEOMETRY:
-		if (_verify_geometry(val, opt.geometry)) {
+		if (verify_geometry(val, opt.geometry)) {
 			error("\"%s=%s\" -- invalid geometry, ignoring...",
 			      e->var, val);
 		}
@@ -1253,70 +912,6 @@ _get_int(const char *arg, const char *what, bool positive)
 	return (int) result;
 }
 
-/* 
- * get either 1 or 2 integers for a resource count in the form of either
- * (count, min-max, or '*')
- * A partial error message is passed in via the 'what' param.
- * RET true if valid
- */
-static bool
-_get_resource_range(const char *arg, const char *what, int* min, int *max, 
-              	    bool isFatal)
-{
-	char *p;
-	long int result;
-
-	if (*arg == '\0') return true;
-
-	/* wildcard meaning every possible value in range */
-	if (*arg == '*' ) {
-		*min = 1;
-		*max = INT_MAX;
-		return true;
-	}
-
-	result = strtol(arg, &p, 10);
-        if (*p == 'k' || *p == 'K') {
-		result *= 1024;
-		p++;
-	}
-
-	if (((*p != '\0')&&(*p != '-')) || (result <= 0L)) {
-		error ("Invalid numeric value \"%s\" for %s.", arg, what);
-		if (isFatal) exit(1);
-		return false;
-	} else if (result > INT_MAX) {
-		error ("Numeric argument (%ld) to big for %s.", result, what);
-		if (isFatal) exit(1);
-		return false;
-	}
-
-	*min = (int) result;
-
-	if (*p == '\0') return true;
-	if (*p == '-') p++;
-
-	result = strtol(p, &p, 10);
-        if (*p == 'k' || *p == 'K') {
-		result *= 1024;
-		p++;
-	}
-	
-	if (((*p != '\0')&&(*p != '-')) || (result <= 0L)) {
-		error ("Invalid numeric value \"%s\" for %s.", arg, what);
-		if (isFatal) exit(1);
-		return false;
-	} else if (result > INT_MAX) {
-		error ("Numeric argument (%ld) to big for %s.", result, what);
-		if (isFatal) exit(1);
-		return false;
-	}
-
-	*max = (int) result;
-
-	return true;
-}
-
 static void set_options(const int argc, char **argv)
 {
 	int opt_char, option_index = 0;
@@ -1407,6 +1002,7 @@ static void set_options(const int argc, char **argv)
 		{"ntasks-per-node",  required_argument, 0, LONG_OPT_NTASKSPERNODE},
 		{"ntasks-per-socket",required_argument, 0, LONG_OPT_NTASKSPERSOCKET},
 		{"ntasks-per-core",  required_argument, 0, LONG_OPT_NTASKSPERCORE},
+		{"tasks-per-node",   required_argument, 0, LONG_OPT_NTASKSPERNODE},
 		{"blrts-image",      required_argument, 0, LONG_OPT_BLRTS_IMAGE},
 		{"linux-image",      required_argument, 0, LONG_OPT_LINUX_IMAGE},
 		{"mloader-image",    required_argument, 0, LONG_OPT_MLOADER_IMAGE},
@@ -1454,7 +1050,7 @@ static void set_options(const int argc, char **argv)
 			      "\"srun -b/--batch\".");
 			exit(1);
 		case (int)'B':
-			opt.extra_set = _verify_socket_core_thread_count(
+			opt.extra_set = verify_socket_core_thread_count(
 				optarg,
 				&opt.min_sockets_per_node,
 				&opt.max_sockets_per_node,
@@ -1499,7 +1095,7 @@ static void set_options(const int argc, char **argv)
 				opt.efname = xstrdup(optarg);
 			break;
 		case (int)'g':
-			if (_verify_geometry(optarg, opt.geometry))
+			if (verify_geometry(optarg, opt.geometry))
 				exit(1);
 			break;
 		case (int)'H':
@@ -1535,7 +1131,7 @@ static void set_options(const int argc, char **argv)
 			opt.labelio = true;
 			break;
 		case (int)'m':
-			opt.distribution = _verify_dist_type(optarg, 
+			opt.distribution = verify_dist_type(optarg, 
 							     &opt.plane_size);
 			if (opt.distribution == SLURM_DIST_UNKNOWN) {
 				error("distribution type `%s' " 
@@ -1550,10 +1146,10 @@ static void set_options(const int argc, char **argv)
 			break;
 		case (int)'N':
 			opt.nodes_set = 
-				_get_resource_range(optarg, 
-						    "requested node count",
-						    &opt.min_nodes,
-						    &opt.max_nodes, true);
+				get_resource_arg_range( optarg, 
+							"requested node count",
+							&opt.min_nodes,
+							&opt.max_nodes, true );
 			
 			if (opt.nodes_set == false) {
 				error("invalid resource allocation -N `%s'", 
@@ -1616,7 +1212,7 @@ static void set_options(const int argc, char **argv)
 			_verbose++;
 			break;
 		case (int)'V':
-			_print_version();
+			print_slurm_version();
 			exit(0);
 			break;
 		case (int)'w':
@@ -1685,7 +1281,7 @@ static void set_options(const int argc, char **argv)
 				true);
 			break;
 		case LONG_OPT_MEM:
-			opt.job_min_memory = (int) _to_bytes(optarg);
+			opt.job_min_memory = (int) str_to_bytes(optarg);
 			if (opt.job_min_memory < 0) {
 				error("invalid memory constraint %s", 
 				      optarg);
@@ -1693,7 +1289,7 @@ static void set_options(const int argc, char **argv)
 			}
 			break;
 		case LONG_OPT_JOBMEM:
-			opt.job_max_memory = (int) _to_bytes(optarg);
+			opt.job_max_memory = (int) str_to_bytes(optarg);
 			if (opt.job_max_memory < 0) {
 				error("invalid memory constraint %s", 
 				      optarg);
@@ -1709,7 +1305,7 @@ static void set_options(const int argc, char **argv)
 			}
 			break;
 		case LONG_OPT_TMP:
-			opt.job_min_tmp_disk = _to_bytes(optarg);
+			opt.job_min_tmp_disk = str_to_bytes(optarg);
 			if (opt.job_min_tmp_disk < 0) {
 				error("invalid tmp value %s", optarg);
 				exit(1);
@@ -1759,7 +1355,7 @@ static void set_options(const int argc, char **argv)
 			_usage();
 			exit(0);
 		case LONG_OPT_CONNTYPE:
-			opt.conn_type = _verify_conn_type(optarg);
+			opt.conn_type = verify_conn_type(optarg);
 			break;
 		case LONG_OPT_TEST_ONLY:
 			opt.test_only = true;
@@ -1788,7 +1384,7 @@ static void set_options(const int argc, char **argv)
 			opt.begin = parse_time(optarg);
 			break;
 		case LONG_OPT_MAIL_TYPE:
-			opt.mail_type |= _parse_mail_type(optarg);
+			opt.mail_type |= parse_mail_type(optarg);
 			if (opt.mail_type == 0)
 				fatal("--mail-type=%s invalid", optarg);
 			break;
@@ -1827,22 +1423,25 @@ static void set_options(const int argc, char **argv)
 			opt.comment = xstrdup(optarg);
 			break;
 		case LONG_OPT_SOCKETSPERNODE:
-			_get_resource_range( optarg, "sockets-per-node",
-				             &opt.min_sockets_per_node,
-				             &opt.max_sockets_per_node, true );
+			get_resource_arg_range( optarg, "sockets-per-node",
+						&opt.min_sockets_per_node,
+						&opt.max_sockets_per_node,
+						true );
 			break;
 		case LONG_OPT_CORESPERSOCKET:
-			_get_resource_range( optarg, "cores-per-socket",
-				             &opt.min_cores_per_socket,
-				             &opt.max_cores_per_socket, true);
+			get_resource_arg_range( optarg, "cores-per-socket",
+						&opt.min_cores_per_socket,
+						&opt.max_cores_per_socket,
+						true);
 			break;
 		case LONG_OPT_THREADSPERCORE:
-			_get_resource_range( optarg, "threads-per-core",
-				             &opt.min_threads_per_core,
-				             &opt.max_threads_per_core, true );
+			get_resource_arg_range( optarg, "threads-per-core",
+						&opt.min_threads_per_core,
+						&opt.max_threads_per_core,
+						true );
 			break;
 		case LONG_OPT_HINT:
-			if (_verify_hint(optarg,
+			if (verify_hint(optarg,
 				&opt.min_sockets_per_node,
 				&opt.max_sockets_per_node,
 				&opt.min_cores_per_socket,
@@ -2031,7 +1630,7 @@ static void _opt_args(int argc, char **argv)
 	else if (opt.argc > 0) {
 		char *fullpath;
 
-		if ((fullpath = _search_path(opt.argv[0], false, R_OK|X_OK))) {
+		if ((fullpath = search_path(opt.cwd, opt.argv[0], false, R_OK|X_OK))) {
 			xfree(opt.argv[0]);
 			opt.argv[0] = fullpath;
 		} 
@@ -2088,7 +1687,7 @@ static bool _opt_verify(void)
 		opt.job_min_cpus = opt.cpus_per_task;
 
 	if ((opt.job_name == NULL) && (opt.argc > 0))
-		opt.job_name = _base_name(opt.argv[0]);
+		opt.job_name = base_name(opt.argv[0]);
 
 	if(!opt.nodelist) {
 		if((opt.nodelist = xstrdup(getenv("SLURM_HOSTFILE")))) {
@@ -2262,10 +1861,10 @@ static bool _opt_verify(void)
 	} else if (opt.nodes_set && opt.nprocs_set) {
 
 		/*
-		 * Make sure in a non allocate situation that
-		 * the number of max_nodes is <= number of tasks
+		 * Make sure that the number of 
+		 * max_nodes is <= number of tasks
 		 */
-		if (!opt.allocate && opt.nprocs < opt.max_nodes) 
+		if (opt.nprocs < opt.max_nodes) 
 			opt.max_nodes = opt.nprocs;
 		
 		/* 
@@ -2366,114 +1965,6 @@ static bool _opt_verify(void)
 	return verified;
 }
 
-static uint16_t _parse_mail_type(const char *arg)
-{
-	uint16_t rc;
-
-	if (strcasecmp(arg, "BEGIN") == 0)
-		rc = MAIL_JOB_BEGIN;
-	else if  (strcasecmp(arg, "END") == 0)
-		rc = MAIL_JOB_END;
-	else if (strcasecmp(arg, "FAIL") == 0)
-		rc = MAIL_JOB_FAIL;
-	else if (strcasecmp(arg, "ALL") == 0)
-		rc = MAIL_JOB_BEGIN |  MAIL_JOB_END |  MAIL_JOB_FAIL;
-	else
-		rc = 0;		/* failure */
-
-	return rc;
-}
-
-static char *_print_mail_type(const uint16_t type)
-{
-	if (type == 0)
-		return "NONE";
-
-	if (type == MAIL_JOB_BEGIN)
-		return "BEGIN";
-	if (type == MAIL_JOB_END)
-		return "END";
-	if (type == MAIL_JOB_FAIL)
-		return "FAIL";
-	if (type == (MAIL_JOB_BEGIN | MAIL_JOB_END | MAIL_JOB_FAIL))
-		return "ALL";
-
-	return "MULTIPLE";
-}
-
-static void
-_freeF(void *data)
-{
-	xfree(data);
-}
-
-static List
-_create_path_list(void)
-{
-	List l = list_create(_freeF);
-	char *path = xstrdup(getenv("PATH"));
-	char *c, *lc;
-
-	if (!path) {
-		verbose("No PATH environment variable");
-		return l;
-	}
-
-	c = lc = path;
-
-	while (*c != '\0') {
-		if (*c == ':') {
-			/* nullify and push token onto list */
-			*c = '\0';
-			if (lc != NULL && strlen(lc) > 0)
-				list_append(l, xstrdup(lc));
-			lc = ++c;
-		} else
-			c++;
-	}
-
-	if (strlen(lc) > 0)
-		list_append(l, xstrdup(lc));
-
-	xfree(path);
-
-	return l;
-}
-
-static char *
-_search_path(char *cmd, bool check_current_dir, int access_mode)
-{
-	List         l        = _create_path_list();
-	ListIterator i        = NULL;
-	char *path, *fullpath = NULL;
-
-	if (  (cmd[0] == '.' || cmd[0] == '/') 
-	      && (access(cmd, access_mode) == 0 ) ) {
-		if (cmd[0] == '.')
-			xstrfmtcat(fullpath, "%s/", opt.cwd);
-		xstrcat(fullpath, cmd);
-		goto done;
-	}
-
-	if (check_current_dir) 
-		list_prepend(l, xstrdup(opt.cwd));
-
-	i = list_iterator_create(l);
-	while ((path = list_next(i))) {
-		xstrfmtcat(fullpath, "%s/%s", path, cmd);
-
-		if (access(fullpath, access_mode) == 0)
-			goto done;
-
-		xfree(fullpath);
-		fullpath = NULL;
-	}
-done:
-	list_destroy(l);
-	return fullpath;
-}
-
-
 /* helper function for printing options
  * 
  * warning: returns pointer to memory allocated on the stack.
@@ -2518,39 +2009,6 @@ static char *print_constraints()
 	return buf;
 }
 
-static char * 
-print_commandline()
-{
-	int i;
-	char buf[256];
-
-	buf[0] = '\0';
-	for (i = 0; i < opt.argc; i++)
-		snprintf(buf, 256,  "%s", opt.argv[i]);
-	return xstrdup(buf);
-}
-
-static char *
-print_geometry()
-{
-	int i;
-	char buf[32], *rc = NULL;
-
-	if ((SYSTEM_DIMENSIONS == 0)
-	    ||  (opt.geometry[0] == (uint16_t)NO_VAL))
-		return NULL;
-
-	for (i=0; i<SYSTEM_DIMENSIONS; i++) {
-		if (i > 0)
-			snprintf(buf, sizeof(buf), "x%u", opt.geometry[i]);
-		else
-			snprintf(buf, sizeof(buf), "%u", opt.geometry[i]);
-		xstrcat(rc, buf);
-	}
-
-	return rc;
-}
-
 #define tf_(b) (b == true) ? "true" : "false"
 
 static void _opt_list()
@@ -2617,7 +2075,7 @@ static void _opt_list()
 	xfree(str);
 	if (opt.conn_type != (uint16_t) NO_VAL)
 		info("conn_type      : %u", opt.conn_type);
-	str = print_geometry();
+	str = print_geometry(opt.geometry);
 	info("geometry       : %s", str);
 	xfree(str);
 	info("reboot         : %s", opt.reboot ? "no" : "yes");
@@ -2642,17 +2100,23 @@ static void _opt_list()
 	}
 	info("prolog         : %s", opt.prolog);
 	info("epilog         : %s", opt.epilog);
-	info("mail_type      : %s", _print_mail_type(opt.mail_type));
+	info("mail_type      : %s", print_mail_type(opt.mail_type));
 	info("mail_user      : %s", opt.mail_user);
 	info("task_prolog    : %s", opt.task_prolog);
 	info("task_epilog    : %s", opt.task_epilog);
 	info("ctrl_comm_ifhn : %s", opt.ctrl_comm_ifhn);
 	info("multi_prog     : %s", opt.multi_prog ? "yes" : "no");
+	info("sockets-per-node  : %d - %d", opt.min_sockets_per_node,
+					    opt.max_sockets_per_node);
+	info("cores-per-socket  : %d - %d", opt.min_cores_per_socket,
+					    opt.max_cores_per_socket);
+	info("threads-per-core  : %d - %d", opt.min_threads_per_core,
+					    opt.max_threads_per_core);
 	info("ntasks-per-node   : %d", opt.ntasks_per_node);
 	info("ntasks-per-socket : %d", opt.ntasks_per_socket);
 	info("ntasks-per-core   : %d", opt.ntasks_per_core);
 	info("plane_size        : %u", opt.plane_size);
-	str = print_commandline();
+	str = print_commandline(opt.argc, opt.argv);
 	info("remote command    : `%s'", str);
 	xfree(str);
 
-- 
GitLab