diff --git a/src/slurmctld/Makefile.am b/src/slurmctld/Makefile.am
index ee5e256ce5a14c29889f18ee2d6b5cbd5db6065e..120766795eef142b2f467e7c5af942a7a140f885 100644
--- a/src/slurmctld/Makefile.am
+++ b/src/slurmctld/Makefile.am
@@ -47,7 +47,7 @@ slurmctld_SOURCES = bits_bytes.c \
 # Note: automake 1.5 will complain about these...
 #
 bits_bytes     : bits_bytes_d.o
-controller     : controller_d.o bits_bytes.o node_mgr.o partition_mgr.o read_config.o 
+controller     : controller_d.o bits_bytes.o node_mgr.o node_scheduler.o partition_mgr.o read_config.o 
 node_mgr       : node_mgr_d.o bits_bytes.o
 node_scheduler : node_scheduler_d.o bits_bytes.o node_mgr.o partition_mgr.o read_config.o
 partition_mgr  : partition_mgr_d.o bits_bytes.o node_mgr.o
diff --git a/src/slurmctld/node_scheduler.c b/src/slurmctld/node_scheduler.c
new file mode 100644
index 0000000000000000000000000000000000000000..542ceb10fc7edee4b95380d0e3a882e4ef572e1d
--- /dev/null
+++ b/src/slurmctld/node_scheduler.c
@@ -0,0 +1,401 @@
+/* 
+ * node_scheduler.c - Allocated nodes to jobs 
+ * See slurm.h for documentation on external functions and data structures
+ *
+ * NOTE: DEBUG_MODULE mode test with execution line
+ *	node_scheduler ../../etc/SLURM.conf2 ../../etc/SLURM.jobs
+ *
+ * Author: Moe Jette, jette@llnl.gov
+ */
+
+#define DEBUG_SYSTEM  1
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "slurm.h"
+
+#define BUF_SIZE 1024
+#define NO_VAL (-99)
+
+int Is_Key_Valid(int Key);
+int Match_Group(char *AllowGroups, char *UserGroups);
+int Parse_Job_Specs(char *Job_Specs, char **Req_Features, char **Req_Node_List, char **Job_Name,
+	char **Req_Group, char **Req_Partition, int *Contiguous, int *Req_CPUs, 
+	int *Req_Nodes, int *Min_CPUs, int *Min_RealMemory, int *Min_TmpDisk, int *Key);
+
+#if DEBUG_MODULE
+/* main is used here for testing purposes only */
+main(int argc, char * argv[]) {
+    int Error_Code, Line_Num;
+    FILE *Command_File;
+    char In_Line[BUF_SIZE], *Node_List;
+
+    if (argc < 3) {
+	printf("Usage: %s <slurm_conf_file> <slurm_job_file>\n", argv[0]);
+	exit(0);
+    } /* if */
+
+    Error_Code = Init_SLURM_Conf();
+    if (Error_Code) {
+	printf("controller: Error %d from Init_SLURM_Conf\n", Error_Code);
+	exit(Error_Code);
+    } /* if */
+
+    Error_Code = Read_SLURM_Conf(argv[1]);
+    if (Error_Code) {
+	printf("controller: Error %d from Read_SLURM_Conf\n", Error_Code);
+	exit(Error_Code);
+    } /* if */
+
+    Command_File = fopen(argv[2], "r");
+    if (Command_File == NULL) {
+	fprintf(stderr, "node_scheduler: error %d opening command file %s\n", 
+		errno, argv[2]);
+	exit(1);
+    } /* if */
+
+    Line_Num = 0;
+    while (fgets(In_Line, BUF_SIZE, Command_File)) {
+	Line_Num++;
+	Error_Code = Allocate_Nodes(In_Line, &Node_List);
+	if (Error_Code) {
+	    if (strncmp(In_Line, "Name=FAIL", 9) != 0) printf("ERROR:");
+	    printf("For job: %s", In_Line, Node_List);
+	    printf("node_scheduler: Error %d from Allocate_Nodes on line %d\n\n", Error_Code, Line_Num);
+	} else {
+	    if (strncmp(In_Line, "Name=FAIL", 9) == 0) printf("ERROR: ");
+	    printf("For job: %s  Nodes selected %s\n\n", In_Line, Node_List);
+	    free(Node_List);
+	} /* else */
+    } /* while */
+} /* main */
+#endif
+
+
+/*
+ * Allocate_Nodes - Allocate nodes to a job with the given specifications
+ * Input: Job_Specs - Job specifications
+ *        Node_List - Pointer to node list returned
+ * Output: Node_List - List of allocated nodes
+ *         Returns 0 on success, EINVAL if not possible to satisfy request, 
+ *		or EAGAIN if resources are presently busy
+ * NOTE: The calling program must free the memory pointed to by Node_List
+ */
+int Allocate_Nodes(char *Job_Specs, char **Node_List) {
+    char *Req_Features, *Req_Node_List, *Job_Name, *Req_Group, *Req_Partition, *Out_Line;
+    int Contiguous, Req_CPUs, Req_Nodes, Min_CPUs, Min_RealMemory, Min_TmpDisk;
+    int Error_Code, CPU_Tally, Node_Tally, Key;
+    struct Part_Record *Part_Ptr;
+    unsigned *Req_BitMap, *Part_BitMap;
+
+    Req_Features = Req_Node_List = Req_Group = Req_Partition = NULL;
+    Req_BitMap = Part_BitMap = NULL;
+    Contiguous = Req_CPUs = Req_Nodes = Min_CPUs = Min_RealMemory = Min_TmpDisk = Key = NO_VAL;
+
+    Error_Code = Parse_Job_Specs(Job_Specs, &Req_Features, &Req_Node_List, &Job_Name, &Req_Group, 
+		&Req_Partition, &Contiguous, &Req_CPUs, &Req_Nodes, &Min_CPUs, 
+		&Min_RealMemory, &Min_TmpDisk, &Key);
+    if (Error_Code == ENOMEM) {
+	Error_Code = EAGAIN;	/* Don't want to kill the job off */
+	goto cleanup;
+    } /* if */
+    if (Error_Code != 0) {
+	Error_Code =  EINVAL;	/* Permanent error, invalid parsing */
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Allocate_Nodes: Parsing failure on %s\n", Job_Specs);
+#else
+	syslog(LOG_NOTICE, "Allocate_Nodes: Parsing failure on %s\n", Job_Specs);
+#endif
+	goto cleanup;
+    } /* if */
+
+    /* Find selected partition */
+    if (Req_Partition) {
+	Part_Ptr   = list_find_first(Part_List, &List_Find_Part, Req_Partition);
+	if (Part_Ptr == NULL) {
+#if DEBUG_SYSTEM
+	    fprintf(stderr, "Allocate_Nodes: Invalid partition specified: %s\n", Req_Partition);
+#else
+	    syslog(LOG_NOTICE, "Allocate_Nodes: Invalid partition specified: %s\n", Req_Partition);
+#endif
+	    Error_Code = EINVAL;
+	    goto cleanup;
+	} /* if */
+    } else {
+	if (Default_Part_Loc == NULL) {
+#if DEBUG_SYSTEM
+	    fprintf(stderr, "Allocate_Nodes: Default partition not set.\n");
+#else
+	    syslog(LOG_ERR, "Allocate_Nodes: Default partition not set.\n");
+#endif
+	    Error_Code = EINVAL;
+	    goto cleanup;
+	} /* if */
+	Part_Ptr = Default_Part_Loc;
+    } /* if */
+
+    /* Can this user access this partition */
+    if (Part_Ptr->Key && (Is_Key_Valid(Key) == 0)) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Allocate_Nodes: Job lacks key required of partition %s\n", 
+		Part_Ptr->Name);
+#else
+	syslog(LOG_NOTICE, "Allocate_Nodes: Job lacks key required of partition %s\n", 
+		Part_Ptr->Name);
+#endif
+	Error_Code = EINVAL;
+	goto cleanup;
+    } /* if */
+    if (Match_Group(Part_Ptr->AllowGroups, Req_Group) == 0) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Allocate_Nodes: Job lacks group required of partition %s\n", 
+		Part_Ptr->Name);
+#else
+	syslog(LOG_NOTICE, "Allocate_Nodes: Job lacks group required of partition %s\n", 
+		Part_Ptr->Name);
+#endif
+	Error_Code = EINVAL;
+	goto cleanup;
+    } /* if */
+
+    /* Check if select partition has sufficient resources to satisfy request */
+    if ((Req_CPUs != NO_VAL) && (Req_CPUs > Part_Ptr->TotalCPUs)) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Allocate_Nodes: Too many CPUs (%d) requested of partition %s(%d)\n", 
+		Req_CPUs, Part_Ptr->Name, Part_Ptr->TotalCPUs);
+#else
+	syslog(LOG_NOTICE, "Allocate_Nodes: Too many CPUs (%d) requested of partition %s(%d)\n", 
+		Req_CPUs, Part_Ptr->Name, Part_Ptr->TotalCPUs);
+#endif
+	Error_Code = EINVAL;
+	goto cleanup;
+    } /* if */
+    if ((Req_Nodes != NO_VAL) && (Req_Nodes > Part_Ptr->TotalNodes)) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Allocate_Nodes: Too many nodes (%d) requested of partition %s(%d)\n", 
+		Req_Nodes, Part_Ptr->Name, Part_Ptr->TotalNodes);
+#else
+	syslog(LOG_NOTICE, "Allocate_Nodes: Too many nodes (%d) requested of partition %s(%d)\n", 
+		Req_Nodes, Part_Ptr->Name, Part_Ptr->TotalNodes);
+#endif
+	Error_Code = EINVAL;
+	goto cleanup;
+    } /* if */
+    if (Req_Node_List) { /* Insure that selected nodes are in this partition */
+	Error_Code = NodeName2BitMap(Req_Node_List, &Req_BitMap);
+	if (Error_Code == EINVAL) goto cleanup;
+	if (Error_Code != 0) {
+	    Error_Code = EAGAIN;  /* No memory */
+	    goto cleanup;
+	} /* if */
+	Part_BitMap = BitMapCopy(Part_Ptr->NodeBitMap);
+	if (Part_BitMap == NULL)  {
+	    Error_Code = EAGAIN;  /* No memory */
+	    goto cleanup;
+	} /* if */
+	BitMapAND(Part_BitMap, Req_BitMap);
+	if (BitMapCount(Part_BitMap) != BitMapCount(Req_BitMap)) {
+#if DEBUG_SYSTEM
+	    fprintf(stderr, "Allocate_Nodes: Requested nodes %s not in partition %s\n", 
+		Req_Node_List, Part_Ptr->Name);
+#else
+	    syslog(LOG_NOTICE, "Allocate_Nodes: Requested nodes %s not in partition %s\n", 
+		Req_Node_List, Part_Ptr->Name);
+#endif
+	    Error_Code = EINVAL;
+	    goto cleanup;
+	} /* if */
+    } else
+	Req_BitMap = (unsigned *)NULL;
+
+    /* Pick up nodes from the Weight ordered configuration list */
+
+    /* Pick the nodes providing a best-fit */
+
+    /* Mark the selected nodes as STATE_STAGING */
+
+    Error_Code = BitMap2NodeName(Req_BitMap, Node_List);
+    if (Error_Code) printf("BitMap2NodeName error %d\n", Error_Code);
+
+cleanup:
+    if (Req_Features)	free(Req_Features);
+    if (Req_Node_List)	free(Req_Node_List);
+    if (Req_Group)	free(Req_Group);
+    if (Req_Partition)	free(Req_Partition);
+    if (Req_BitMap)	free(Req_BitMap);
+    if (Part_BitMap)	free(Part_BitMap);
+    return Error_Code;
+} /* Allocate_Nodes */
+
+
+/* 
+ * Is_Key_Valid - Determine if supplied key is valid
+ * Input: Key - A SLURM key acquired by user root
+ * Output: Returns 1 if key is valid, 0 otherwise
+ * NOTE: This is only a placeholder for a future function
+ */
+int Is_Key_Valid(int Key) {
+    if (Key == NO_VAL) return 0;
+    return 1;
+}  /* Is_Key_Valid */
+
+
+/*
+ * Match_Group - Determine if the user is a member of any groups permitted to use this partition
+ * Input: AllowGroups - Comma delimited list of groups permitted to use the partition, 
+ *			NULL is for ALL groups
+ *        UserGroups - Comma delimited list of groups the user belongs to
+ * Output: Returns 1 if user is member, 0 otherwise
+ */
+int Match_Group(char *AllowGroups, char *UserGroups) {
+    char *Tmp_Allow_Group, *str_ptr1, *str_ptr2;
+    char *Tmp_User_Group, *str_ptr3, *str_ptr4;
+
+    if (AllowGroups == NULL) return 1;	/* Anybody can use it */
+    if (UserGroups  == NULL) return 0;	/* Empty group list */
+
+    Tmp_Allow_Group = malloc(strlen(AllowGroups)+1);
+    if (Tmp_Allow_Group == NULL) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Match_Group: unable to allocate memory\n");
+#else
+	syslog(LOG_ALERT, "Match_Group: unable to allocate memory\n");
+#endif
+	return 1; /* Assume good for now */
+    } /* if */
+    strcpy(Tmp_Allow_Group, AllowGroups);
+
+    Tmp_User_Group = malloc(strlen(UserGroups)+1);
+    if (Tmp_User_Group == NULL) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Match_Group: unable to allocate memory\n");
+#else
+	syslog(LOG_ALERT, "Match_Group: unable to allocate memory\n");
+#endif
+	free(Tmp_Allow_Group);
+	return 1; /* Assume good for now */
+    } /* if */
+    strcpy(Tmp_User_Group, UserGroups);
+
+    str_ptr1 = (char *)strtok_r(Tmp_Allow_Group, ",", &str_ptr2);
+    while (str_ptr1) {
+	strcpy(Tmp_User_Group, UserGroups);
+	str_ptr3 = (char *)strtok_r(Tmp_User_Group, ",", &str_ptr4);
+	while (str_ptr3) {
+	    if (strcmp(str_ptr1, str_ptr3) == 0) {  /* We have a match */
+		free(Tmp_Allow_Group);
+		free(Tmp_User_Group);
+		return 1;
+	    } /* if */
+	    str_ptr3 = (char *)strtok_r(NULL, ",", &str_ptr4);
+	} /* while (str_ptr3) */
+	str_ptr1 = (char *)strtok_r(NULL, ",", &str_ptr2);
+    } /* while (str_ptr1)*/
+    free(Tmp_Allow_Group);
+    free(Tmp_User_Group);
+    return 0;  /* No match */
+} /* Match_Group */
+
+
+/* 
+ * Parse_Job_Specs - Pick the appropriate fields out of a job request specification
+ * Input: Job_Specs - String containing the specification
+ *        Req_Features, etc. - Pointers to storage for the specifications
+ * Output: Req_Features, etc. - The job's specifications
+ *         Returns 0 if no error, errno otherwise
+ * NOTE: The calling function must free memory at Req_Features[0], Req_Node_List[0],
+	Req_Group[0], and Req_Partition[0]
+ */
+int Parse_Job_Specs(char *Job_Specs, char **Req_Features, char **Req_Node_List, char **Job_Name,
+	char **Req_Group, char **Req_Partition, int *Contiguous, int *Req_CPUs, 
+	int *Req_Nodes, int *Min_CPUs, int *Min_RealMemory, int *Min_TmpDisk, int *Key) {
+    int Bad_Index, Error_Code, i;
+    char *Temp_Specs;
+
+    Req_Features[0] = Req_Node_List[0] = Req_Group[0] = Req_Partition[0] = Job_Name[0] = NULL;
+    *Contiguous = *Req_CPUs = *Req_Nodes = *Min_CPUs = *Min_RealMemory = *Min_TmpDisk = NO_VAL;
+
+    Temp_Specs = malloc(strlen(Job_Specs)+1);
+    if (Temp_Specs == NULL) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Parse_Job_Specs: unable to allocate memory\n");
+#else
+	syslog(LOG_ALERT, "Parse_Job_Specs: unable to allocate memory\n");
+#endif
+	return ENOMEM;
+    } /* if */
+    strcpy(Temp_Specs, Job_Specs);
+
+    Error_Code = Load_String (Job_Name, "Name=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_String (Req_Features, "Features=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_String (Req_Node_List, "Node_List=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_String (Req_Group, "Groups=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_String (Req_Partition, "PartitionName=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Contiguous, "Contiguous", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Req_CPUs, "Req_CPUs=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Req_Nodes, "Req_Nodes=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Min_CPUs, "Min_CPUs=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Min_RealMemory, "Min_RealMemory=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Min_TmpDisk, "Min_TmpDisk=", Temp_Specs);
+    if (Error_Code) goto cleanup;
+
+    Error_Code = Load_Integer (Key, "Key=", Temp_Specs);
+    if (Error_Code) {
+	return Error_Code;
+    } /* if */
+
+    Bad_Index = -1;
+    for (i=0; i<strlen(Temp_Specs); i++) {
+	if (Temp_Specs[i] == '\n') Temp_Specs[i]=' ';
+	if (isspace((int)Temp_Specs[i])) continue;
+	Bad_Index=i;
+	break;
+    } /* if */
+
+    if (Bad_Index != -1) {
+#if DEBUG_SYSTEM
+	fprintf(stderr, "Parse_Job_Specs: Bad job specification input: %s\n", &Temp_Specs[Bad_Index]);
+#else
+	syslog(LOG_ERR, "Parse_Job_Specs: Bad job specification input: %s\n", &Temp_Specs[Bad_Index]);
+#endif
+	Error_Code = EINVAL;
+    } /* if */
+
+    free(Temp_Specs);
+    return Error_Code;
+
+cleanup:
+    free(Temp_Specs);
+    if (Job_Name[0])      free(Job_Name[0]);
+    if (Req_Features[0])  free(Req_Features[0]);
+    if (Req_Node_List[0]) free(Req_Node_List[0]);
+    if (Req_Group[0])     free(Req_Group[0]);
+    if (Req_Partition[0]) free(Req_Partition[0]);
+} /* Parse_Job_Specs */