Index: /trunk/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4705)
+++ /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4706)
@@ -145,4 +145,5 @@
 int CheckHost (Host *host);
 Stack *GetJobStack (int StackID);
+Stack *GetJobStackByName (char *name);
 int PutJob (Job *job, int StackID, int where);
 Job *GetJob (int StackID, int where);
Index: /trunk/Ohana/src/opihi/pantasks/CheckController.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckController.c	(revision 4706)
+++ /trunk/Ohana/src/opihi/pantasks/CheckController.c	(revision 4706)
@@ -0,0 +1,77 @@
+# include "psched.h"
+
+int CheckController () {
+
+  char *p, *q;
+  int i, Njobs, status, JobID;
+  Job *job;
+  IOBuffer buffer;
+  
+
+  /* get the list of completed jobs (exit / crash), update the job status */
+
+  if (!CheckControllerStatus()) return (TRUE);
+
+  /*** check EXIT jobs ***/
+  InitIOBuffer (&buffer, 0x100);
+  status = ControllerCommand ("jobstack exit", CONTROLLER_PROMPT, &buffer);
+  if (!status) {
+    FreeIOBuffer (&buffer);
+    return (FALSE);
+  }
+
+  /** parse job list **/
+  sscanf (buffer.buffer, "%*s %s", &Njobs);
+  p = buffer.buffer;
+  
+  for (i = 0; i < Njobs; i++) {
+    q = strchr (p, '\n');
+    if (q == NULL) {
+      fprintf (stderr, "controller message error: incomplete job list\n");
+      FreeIOBuffer (&buffer);
+      break;
+    }
+    p = q++;
+    sscanf (p, "%d", &JobID);
+    job = FindJob (JobID);
+    if (job == NULL) {
+      fprintf (stderr, "misplaced job? %d not in job list\n");
+      continue;
+    }
+    /* this checks the individual job status, grabs stdout/stderr */
+    CheckControllerJob (job);
+  }
+    
+  /*** check CRASH jobs ***/
+  InitIOBuffer (&buffer, 0x100);
+  status = ControllerCommand ("jobstack crash", CONTROLLER_PROMPT, &buffer);
+  if (!status) {
+    FreeIOBuffer (&buffer);
+    return (FALSE);
+  }
+
+  /** parse job list **/
+  sscanf (buffer.buffer, "%*s %s", &Njobs);
+  p = buffer.buffer;
+  
+  for (i = 0; i < Njobs; i++) {
+    q = strchr (p, '\n');
+    if (q == NULL) {
+      fprintf (stderr, "controller message error: incomplete job list\n");
+      FreeIOBuffer (&buffer);
+      break;
+    }
+    p = q++;
+    sscanf (p, "%d", &JobID);
+    job = FindJob (JobID);
+    if (job == NULL) {
+      fprintf (stderr, "misplaced job? %d not in job list\n");
+      continue;
+    }
+    /* this checks the individual job status, grabs stdout/stderr */
+    CheckControllerJob (job);
+  }
+  return (TRUE);
+}
+
+    
Index: /trunk/Ohana/src/opihi/pantasks/CheckSystem.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckSystem.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/CheckSystem.c	(revision 4706)
@@ -3,6 +3,13 @@
 int CheckSystem () {
 
+  /* need to make a timeout: if this process lasts too long, 
+     we should return so the user can get input in.  this cannot
+     just be a return, because we need to hit each of the elements
+     eventually
+  */
+
   CheckTasks ();
   CheckJobs ();
+  CheckController ();
   CheckControllerOutput ();
   return (TRUE);
Index: /trunk/Ohana/src/opihi/pantasks/ControllerOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4706)
@@ -24,8 +24,22 @@
     GetJobOutput ("stdout", job[0].pid, &job[0].stdout, job[0].stdout_size);
     GetJobOutput ("stderr", job[0].pid, &job[0].stderr, job[0].stderr_size);
+    DeleteControllerJob (job);
   }  
   return (TRUE);
 }
 
+int DeleteControllerJob (Job *job) {
+
+  int status;
+  char cmd[128]; 
+  IOBuffer buffer;
+
+  sprintf (cmd, "delete %d", job[0].pid);
+  InitIOBuffer (&buffer, 0x100);
+  status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
+  FreeIOBuffer (&buffer);
+  return (status);
+}
+  
 /* ask controller about job status */
 int CheckControllerJobStatus (Job *job) {
@@ -39,24 +53,7 @@
   InitIOBuffer (&buffer, 0x100);
   status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
-
-  /* check on success of controller command */
-  switch (status) {
-    case CONTROLLER_DOWN:
-      if (VerboseMode()) fprintf (stderr, "controller is down\n");
-      FreeIOBuffer (&buffer);
-      return (FALSE);
-
-    case CONTROLLER_HUNG:
-      if (VerboseMode()) fprintf (stderr, "controller is not responding\n");
-      FreeIOBuffer (&buffer);
-      return (FALSE);
-
-    case CONTROLLER_GOOD:
-      if (VerboseMode()) fprintf (stderr, "message received (CheckControllerJobStatus)\n");
-      break;
-
-    default:
-      if (VerboseMode()) fprintf (stderr, "unknown status for controller command: programming error\n");  
-      exit (1);
+  if (!status) {
+    FreeIOBuffer (&buffer);
+    return (FALSE);
   }
 
@@ -137,5 +134,5 @@
 int SubmitControllerJob (Job *job) {
 
-  int i, Nchar;
+  int i, Nchar, status;
   char *cmd, *p, string[64];
   IOBuffer buffer;
@@ -177,5 +174,5 @@
 
   InitIOBuffer (&buffer, 0x100);
-  ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
+  status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
   free (cmd);
 
@@ -317,5 +314,9 @@
   /* send command, is pipe still open? */
   status = write_fmt (stdin_cntl, "%s\n", cmd);
-  if ((status == -1) && (errno == EPIPE)) return (CONTROLLER_DOWN);
+  if ((status == -1) && (errno == EPIPE)) {
+    ControllerStatus = FALSE;
+    if (VerboseMode()) fprintf (stderr, "controller is down\n");
+    return (FALSE);
+  }
   
   /* watch for response - wait up to 1 second */
@@ -329,7 +330,11 @@
   if (status ==  0) {
     ControllerStatus = FALSE;
-    return (CONTROLLER_DOWN);
-  }
-  if (status == -1) return (CONTROLLER_HUNG);
+    if (VerboseMode()) fprintf (stderr, "controller is down\n");
+    return (FALSE);
+  }
+  if (status == -1) {
+    if (VerboseMode()) fprintf (stderr, "controller is not responding\n");
+    return (FALSE);
+  }
 
   /* need to strip off the prompt */
@@ -339,5 +344,6 @@
     bzero (buffer[0].buffer + buffer[0].Nbuffer, buffer[0].Nalloc - buffer[0].Nbuffer);
   }
-  return (CONTROLLER_GOOD);
+  if (VerboseMode()) fprintf (stderr, "message received\n");
+  return (TRUE);
 }
 
@@ -396,8 +402,8 @@
   InitIOBuffer (&buffer, 0x100);
   status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
+  FreeIOBuffer (&buffer);
+  return (status);
 
   /** need to interpret output message & free things **/
-  FreeIOBuffer (&buffer);
-  return (TRUE);
 }
 
Index: /trunk/Ohana/src/opihi/pantasks/JobOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/JobOps.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/JobOps.c	(revision 4706)
@@ -172,5 +172,6 @@
     CheckLocalJob (job);
   } else {
-    CheckControllerJob (job);
+    /* controller jobs are now checked en masse by CheckController */
+    /* CheckControllerJob (job); */
   }
   return (job[0].state);
Index: /trunk/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4706)
@@ -30,4 +30,5 @@
 $(SDIR)/CheckJobs.$(ARCH).o \
 $(SDIR)/CheckSystem.$(ARCH).o \
+$(SDIR)/CheckController.$(ARCH).o \
 $(SDIR)/CheckTasks.$(ARCH).o \
 $(SDIR)/CheckTimeRanges.$(ARCH).o \
Index: /trunk/Ohana/src/opihi/pantasks/controller_check.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_check.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/controller_check.c	(revision 4706)
@@ -27,25 +27,5 @@
   }
   FreeIOBuffer (&buffer);
-
-  /* check on success of controller command */
-  switch (status) {
-    case CONTROLLER_DOWN:
-      fprintf (stderr, "controller is down\n");
-      return (FALSE);
-
-    case CONTROLLER_HUNG:
-      fprintf (stderr, "controller is not responding\n");
-      return (FALSE);
-
-    case CONTROLLER_GOOD:
-      return (TRUE);
-
-    default:
-      fprintf (stderr, "unknown status for controller command: programming error\n");  
-      exit (1);
-  }
-
-  fprintf (stderr, "programming error: should not reach here\n");  
-  exit (1);
+  return (TRUE);
 
 usage:
Index: /trunk/Ohana/src/opihi/pantasks/controller_host.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_host.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/controller_host.c	(revision 4706)
@@ -18,26 +18,6 @@
   InitIOBuffer (&buffer, 0x100);
   status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
-  fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
+  if (status) fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
   FreeIOBuffer (&buffer);
 
-  /* check on success of controller command */
-  switch (status) {
-    case CONTROLLER_DOWN:
-      fprintf (stderr, "controller is down\n");
-      return (FALSE);
-
-    case CONTROLLER_HUNG:
-      fprintf (stderr, "controller is not responding\n");
-      return (FALSE);
-
-    case CONTROLLER_GOOD:
-      return (TRUE);
-
-    default:
-      fprintf (stderr, "unknown status for controller command: programming error\n");  
-      exit (1);
-  }
-
-  fprintf (stderr, "programming error: should not reach here\n");  
-  exit (1);
 }
Index: /trunk/Ohana/src/opihi/pantasks/controller_status.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 4706)
@@ -22,28 +22,7 @@
   InitIOBuffer (&buffer, 0x100);
   status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+  if (status) fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
+  FreeIOBuffer (&buffer);
+  return (TRUE);
 
-  /* check on success of controller command */
-  switch (status) {
-    case CONTROLLER_DOWN:
-      fprintf (stderr, "controller is down\n");
-      FreeIOBuffer (&buffer);
-      return (FALSE);
-
-    case CONTROLLER_HUNG:
-      fprintf (stderr, "controller is not responding\n");
-      FreeIOBuffer (&buffer);
-      return (FALSE);
-
-    case CONTROLLER_GOOD:
-      fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
-      FreeIOBuffer (&buffer);
-      return (TRUE);
-
-    default:
-      fprintf (stderr, "unknown status for controller command: programming error\n");  
-      exit (1);
-  }
-
-  fprintf (stderr, "programming error: should not reach here\n");  
-  exit (1);
 }
Index: /trunk/Ohana/src/opihi/pcontrol/JobOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/JobOps.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pcontrol/JobOps.c	(revision 4706)
@@ -35,4 +35,19 @@
 }
 
+Stack *GetJobStackByName (char *name) {
+
+  if (!strcasecmp (name, "pending")) 
+    return (JobPool_Pending);
+  if (!strcasecmp (name, "busy")) 
+    return (JobPool_Busy);
+  if (!strcasecmp (name, "done")) 
+    return (JobPool_Done);
+  if (!strcasecmp (name, "exit")) 
+    return (JobPool_Exit);
+  if (!strcasecmp (name, "crash")) 
+    return (JobPool_Crash);
+  return (NULL);
+}
+
 Job *FindJobStack (IDtype JobID) {
 
Index: /trunk/Ohana/src/opihi/pcontrol/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/Makefile	(revision 4705)
+++ /trunk/Ohana/src/opihi/pcontrol/Makefile	(revision 4706)
@@ -48,9 +48,10 @@
 
 cmds = \
+$(SDIR)/check.$(ARCH).o \
+$(SDIR)/delete.$(ARCH).o \
+$(SDIR)/host.$(ARCH).o \
 $(SDIR)/job.$(ARCH).o \
-$(SDIR)/host.$(ARCH).o \
+$(SDIR)/jobstack.$(ARCH).o \
 $(SDIR)/kill.$(ARCH).o \
-$(SDIR)/delete.$(ARCH).o \
-$(SDIR)/check.$(ARCH).o \
 $(SDIR)/status.$(ARCH).o \
 $(SDIR)/stdout.$(ARCH).o \
Index: /trunk/Ohana/src/opihi/pcontrol/init.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/init.c	(revision 4705)
+++ /trunk/Ohana/src/opihi/pcontrol/init.c	(revision 4706)
@@ -1,23 +1,25 @@
 # include "pcontrol.h"
 
+int check       PROTO((int, char **));
+int delete      PROTO((int, char **));
+int host        PROTO((int, char **));
+int job	        PROTO((int, char **));
+int jobstack    PROTO((int, char **));
 int kill_pc     PROTO((int, char **));
-int delete      PROTO((int, char **));
-int job	        PROTO((int, char **));
-int host        PROTO((int, char **));
-int check       PROTO((int, char **));
 int status      PROTO((int, char **));
+int stderr_pc   PROTO((int, char **));
+int stdout_pc   PROTO((int, char **));
 int verbose     PROTO((int, char **));
-int stdout_pc   PROTO((int, char **));
-int stderr_pc   PROTO((int, char **));
 
 static Command cmds[] = {  
+  {"check",     check,     "get job or host status"},
+  {"delete",    delete,    "delete job"},
+  {"host",      host,      "add / delete / modify host"},
+  {"job",       job,       "add job"},
+  {"jobstack",  jobstack,  "list jobs for a single stack"},
   {"kill",      kill_pc,   "kill job"},
-  {"delete",    delete,    "delete job"},
-  {"job",       job,       "add job"},
-  {"host",      host,      "add / delete / modify host"},
-  {"check",     check,     "get job or host status"},
   {"status",    status,    "get system status"},
+  {"stderr",    stderr_pc, "get stderr buffer for job"},
   {"stdout",    stdout_pc, "get stdout buffer for job"},
-  {"stderr",    stderr_pc, "get stderr buffer for job"},
   {"verbose",   verbose,   "set the verbose mode for job"},
 }; 
Index: /trunk/Ohana/src/opihi/pcontrol/jobstack.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/jobstack.c	(revision 4706)
+++ /trunk/Ohana/src/opihi/pcontrol/jobstack.c	(revision 4706)
@@ -0,0 +1,33 @@
+# include "pcontrol.h"
+
+int jobstack (int argc, char **argv) {
+
+  int i;
+  Stack *stack;
+  Job *job;
+  Host *host;
+  int JobID, HostID;
+
+  if (argc != 3) {
+    fprintf (stdout, "USAGE: jobstack (jobstack)\n");
+    fprintf (stdout, "       (jobstack) : pending, busy, exit, crash, hung, done\n");
+    return (FALSE);
+  }
+
+  /* select jobstack */
+  stack = GetJobStackByName (argv[1]);
+  if (stack == NULL) {
+    fprintf (stderr, "jobstack not found\n");
+    return (FALSE);
+  }
+
+  /* print list */
+  fprintf (stdout, "Njobs: %d\n", stack[0].Nobject);
+  for (i = 0; i < stack[0].Nobject; i++) {
+    job = stack[0].object[i];
+    /* PrintID (stdout, job[0].JobID); */
+    fprintf (stdout, "%d ", job[0].JobID);
+    fprintf (stdout, "%s  %s\n", job[0].argv[0], job[0].hostname);
+  }
+  return (TRUE);
+}
