Logo Search packages:      
Sourcecode: slurm-llnl version File versions  Download package

job_info.c

/*****************************************************************************\
 *  job_info.c - Functions related to job display 
 *  mode of sview.
 *****************************************************************************
 *  Copyright (C) 2004-2006 The Regents of the University of California.
 *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
 *  Written by Danny Auble <da@llnl.gov>
 *
 *  UCRL-CODE-226842. 
 *  
 *  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.
\*****************************************************************************/

#include "src/common/uid.h"
#include "src/common/node_select.h"
#include "src/sview/sview.h"
#include "src/common/parse_time.h"
#include <grp.h>
 
#define _DEBUG 0
#define MAX_CANCEL_RETRY 10
#define SIZE(a) (sizeof(a)/sizeof(a[0]))

/* Collection of data for printing reports. Like data is combined here */
typedef struct {
      job_info_t *job_ptr;
      char *nodes;
      int node_cnt;
      char *color;
      List step_list;
} sview_job_info_t;

enum { 
      EDIT_SIGNAL = 1,
      EDIT_SIGNAL_USER,
      EDIT_CANCEL,
      EDIT_CANCEL_USER,
      EDIT_SUSPEND,
      EDIT_EDIT
};

/* These need to be in alpha order (except POS and CNT) */
enum { 
      SORTID_POS = POS_LOC,
      SORTID_ACCOUNT,
      SORTID_ACTION,
      SORTID_ALLOC, 
      SORTID_ALLOC_NODE,
      SORTID_BATCH,
#ifdef HAVE_BG
      SORTID_BLRTSIMAGE,
      SORTID_NODELIST, 
      SORTID_BLOCK, 
#endif
      SORTID_COMMENT,
#ifdef HAVE_BG
      SORTID_CONNECTION,
#endif
      SORTID_CONTIGUOUS,
      SORTID_DEPENDENCY,      
      SORTID_CPUS_PER_TASK,
      SORTID_END_TIME,
      SORTID_EXC_NODELIST,
      SORTID_FEATURES,
      SORTID_EXIT_CODE,
#ifdef HAVE_BG
      SORTID_GEOMETRY,
#endif
      SORTID_GROUP, 
      SORTID_JOBID, 
#ifdef HAVE_BG
      SORTID_LINUXIMAGE,
#endif
      SORTID_MAX_CORES,
      SORTID_MAX_MEM,
      SORTID_MAX_NODES,
      SORTID_MAX_SOCKETS,
#ifdef HAVE_BG
      SORTID_MAX_PROCS,
#endif
      SORTID_MAX_THREADS,
      SORTID_MIN_CORES,
      SORTID_MIN_MEM,
      SORTID_MIN_NODES,
      SORTID_MIN_PROCS,
      SORTID_MIN_SOCKETS,
      SORTID_MIN_THREADS,
#ifdef HAVE_BG
      SORTID_MLOADERIMAGE,
#endif
      SORTID_NAME,
      SORTID_NETWORK,
      SORTID_NICE,
#ifndef HAVE_BG
      SORTID_NODELIST,
#endif
      SORTID_NODES,
      SORTID_NTASKS_PER_CORE,
      SORTID_NTASKS_PER_NODE,
      SORTID_NTASKS_PER_SOCKET,
      SORTID_NUM_PROCS,
      SORTID_PARTITION, 
      SORTID_PRIORITY,
#ifdef HAVE_BG
      SORTID_RAMDISKIMAGE,
#endif
      SORTID_REASON,
      SORTID_REQ_NODELIST,
      SORTID_REQ_PROCS,
#ifdef HAVE_BG
      SORTID_ROTATE,
#endif
      SORTID_SHARED,
#ifdef HAVE_BG
      SORTID_START,
#endif
      SORTID_START_TIME,
      SORTID_STATE,
      SORTID_STATE_NUM,
      SORTID_SUBMIT_TIME,
      SORTID_SUSPEND_TIME,
      SORTID_TASKS,
      SORTID_TIME,
      SORTID_TIMELIMIT,
      SORTID_TMP_DISK,
      SORTID_UPDATED,
      SORTID_USER, 
      SORTID_CNT
};

/* extra field here is for choosing the type of edit you that will
 * take place.  If you choose EDIT_MODEL (means only display a set of
 * known options) create it in function create_model_*.  
 */

static display_data_t display_data_job[] = {
      {G_TYPE_INT, SORTID_POS, NULL, FALSE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_INT, SORTID_JOBID, "JobID", TRUE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_ACTION, "Action", FALSE,
       EDIT_MODEL, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_INT, SORTID_ALLOC, NULL, FALSE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_PARTITION, "Partition", TRUE,
       EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
#ifdef HAVE_BG
      {G_TYPE_STRING, SORTID_BLOCK, "BG Block", TRUE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_GEOMETRY, "Geometry", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_START, "Start", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_ROTATE, "Rotate", 
       FALSE, EDIT_MODEL, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_CONNECTION, "Connection", 
       FALSE, EDIT_MODEL, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_BLRTSIMAGE, "Blrts Image",
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_LINUXIMAGE, "linux Image",
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MLOADERIMAGE, "Mloader Image",
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_RAMDISKIMAGE, "Ramdisk Image",
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
#endif
      {G_TYPE_STRING, SORTID_USER, "User", TRUE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_GROUP, "Group", FALSE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NAME, "Name", TRUE, EDIT_TEXTBOX, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_STATE, "State", TRUE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_INT, SORTID_STATE_NUM, NULL, FALSE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_TIME, "Running Time", TRUE,
       EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_SUBMIT_TIME, "Submit Time", FALSE,
       EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_START_TIME, "Start Time", FALSE,
       EDIT_TEXTBOX, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_END_TIME, "End Time", FALSE,
       EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_SUSPEND_TIME, "Suspended Time", FALSE,
       EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_TIMELIMIT, "Time Limit", FALSE,
       EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NODES, "Nodes", TRUE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
#ifdef HAVE_BG
      {G_TYPE_STRING, SORTID_NODELIST, "BP List", TRUE, EDIT_NONE,
       refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_REQ_NODELIST, "Requested BP List",
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_EXC_NODELIST, "Excluded BP List",
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
#else
      {G_TYPE_STRING, SORTID_NODELIST, "Nodelist", TRUE,
       EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_REQ_NODELIST, "Requested NodeList", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_EXC_NODELIST, "Excluded NodeList", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
#endif
      {G_TYPE_STRING, SORTID_CONTIGUOUS, "Contiguous", FALSE, EDIT_MODEL, 
       refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_PRIORITY, "Priority", FALSE, 
       EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_EXIT_CODE, "Exit Code", FALSE,
       EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_BATCH, "Batch Flag", FALSE, 
       EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NUM_PROCS, "Num Processors", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_TASKS, "Num Tasks", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_SHARED, "Shared", FALSE,
       EDIT_MODEL, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_CPUS_PER_TASK, "Cpus per Task", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_REQ_PROCS, "Requested Procs", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MIN_NODES, "Min Nodes", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MAX_NODES, "Max Nodes", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MIN_PROCS, "Min Procs", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
#ifdef HAVE_BG
      {G_TYPE_STRING, SORTID_MAX_PROCS, "Max Procs", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
#endif
      {G_TYPE_STRING, SORTID_MIN_SOCKETS, "Min Sockets", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MAX_SOCKETS, "Max Sockets", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MIN_CORES, "Min Cores", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MAX_CORES, "Max Cores", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MIN_THREADS, "Min Threads", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MAX_THREADS, "Max Threads", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MIN_MEM, "Min Memory", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_MAX_MEM, "Max Memory", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_TMP_DISK, "Tmp Disk", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NICE, "Nice", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_ACCOUNT, "Account Charged", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_REASON, "Wait Reason", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_FEATURES, "Features", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_DEPENDENCY, "Dependency", 
       FALSE, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_ALLOC_NODE, "Alloc Node : Sid",
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NTASKS_PER_NODE, "Num tasks per Node", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NTASKS_PER_SOCKET, "Num tasks per Socket", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NTASKS_PER_CORE, "Num tasks per Core", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_NETWORK, "Network", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_STRING, SORTID_COMMENT, "Comment", 
       FALSE, EDIT_NONE, refresh_job, create_model_job, admin_edit_job},
      {G_TYPE_INT, SORTID_UPDATED, NULL, FALSE, EDIT_NONE, refresh_job,
       create_model_job, admin_edit_job},
      {G_TYPE_NONE, EDIT_NONE, NULL, FALSE, EDIT_NONE}
};

static display_data_t options_data_job[] = {
      {G_TYPE_INT, SORTID_POS, NULL, FALSE, EDIT_NONE},
      {G_TYPE_STRING, INFO_PAGE, "Full Info", TRUE, JOB_PAGE},
      {G_TYPE_STRING, JOB_PAGE, "Signal", TRUE, ADMIN_PAGE},
      {G_TYPE_STRING, JOB_PAGE, "Cancel", TRUE, ADMIN_PAGE},
      {G_TYPE_STRING, JOB_PAGE, "Suspend/Resume", TRUE, ADMIN_PAGE},
      {G_TYPE_STRING, JOB_PAGE, "Edit Job", TRUE, ADMIN_PAGE},
      {G_TYPE_STRING, PART_PAGE, "Partition", TRUE, JOB_PAGE},
#ifdef HAVE_BG
      {G_TYPE_STRING, BLOCK_PAGE, "Block", TRUE, JOB_PAGE},
      {G_TYPE_STRING, NODE_PAGE, "Base Partitions", TRUE, JOB_PAGE},
#else
      {G_TYPE_STRING, NODE_PAGE, "Nodes", TRUE, JOB_PAGE},
#endif
      {G_TYPE_NONE, -1, NULL, FALSE, EDIT_NONE}
};

struct signv {
      char *name;
      uint16_t val;
} sig_name_num[ ] = {
      { "HUP",    SIGHUP  },
      { "INT",    SIGINT  },
      { "QUIT",   SIGQUIT },
      { "ABRT",   SIGABRT },
      { "KILL",   SIGKILL },
      { "ALRM",   SIGALRM },
      { "TERM",   SIGTERM },
      { "USR1",   SIGUSR1 },
      { "USR2",   SIGUSR2 },
      { "CONT",   SIGCONT },
      { "STOP",   SIGSTOP },
      { "TSTP",   SIGTSTP },
      { "TTIN",   SIGTTIN },
      { "TTOU",   SIGTTOU },
      { "SIGHUP", SIGHUP  },
      { "SIGINT", SIGINT  },
      { "SIGQUIT",      SIGQUIT },
      { "SIGABRT",      SIGABRT },
      { "SIGKILL",      SIGKILL },
      { "SIGALRM",      SIGALRM },
      { "SIGTERM",      SIGTERM },
      { "SIGUSR1",      SIGUSR1 },
      { "SIGUSR2",      SIGUSR2 },
      { "SIGCONT",      SIGCONT },
      { "SIGSTOP",      SIGSTOP },
      { "SIGTSTP",      SIGTSTP },
      { "SIGTTIN",      SIGTTIN },
      { "SIGTTOU",      SIGTTOU }
};

static display_data_t *local_display_data = NULL;

static char *got_edit_signal = NULL;

static void _update_info_step(sview_job_info_t *sview_job_info_ptr, 
                        GtkTreeModel *model, 
                        GtkTreeIter *step_iter,
                        GtkTreeIter *iter);


/* translate name name to number */
static uint16_t _xlate_signal_name(const char *signal_name) 
{
      uint16_t sig_num = (uint16_t)NO_VAL;
      char *end_ptr, *sig_names = NULL;
      int i;
      
      sig_num = (uint16_t) strtol(signal_name, &end_ptr, 10);
      
      if ((*end_ptr == '\0') && (sig_num != 0))
            return sig_num;
      
      for (i=0; i<SIZE(sig_name_num); i++) {
            if (strcasecmp(sig_name_num[i].name, signal_name) == 0) {
                  xfree(sig_names);
                  return sig_name_num[i].val;
            }
            if (i == 0)
                  sig_names = xstrdup(sig_name_num[i].name);
            else {
                  xstrcat(sig_names, ",");
                  xstrcat(sig_names, sig_name_num[i].name);
            }                 
      }
      xfree(sig_names);
      return (uint16_t)NO_VAL;
} 

static void _cancel_job_id (uint32_t job_id, uint16_t signal)
{
      int error_code = SLURM_SUCCESS, i;
      char *temp = NULL;

      for (i=0; i<MAX_CANCEL_RETRY; i++) {
            if ((signal == (uint16_t)-1) || (signal == SIGKILL)) {
                  signal = 9;
                  error_code = slurm_kill_job(job_id, SIGKILL,
                                        false);
            } else {
                  error_code = slurm_signal_job(job_id, signal);
            }
            if (error_code == 0
                || (errno != ESLURM_TRANSITION_STATE_NO_UPDATE
                  && errno != ESLURM_JOB_PENDING))
                  break;
            temp = g_strdup_printf("Sending signal %u to job %u",
                               signal, job_id);
            display_edit_note(temp);
            g_free(temp);
            sleep ( 5 + i );
      }
      if (error_code) {
            error_code = slurm_get_errno();
            if ((error_code != ESLURM_ALREADY_DONE) &&
                (error_code != ESLURM_INVALID_JOB_ID)) {
                  temp = g_strdup_printf(
                        "Kill job error on job id %u: %s", 
                        job_id, slurm_strerror(slurm_get_errno()));
                  display_edit_note(temp);
                  g_free(temp);     
            } else {
                  display_edit_note(slurm_strerror(slurm_get_errno()));
            }
      } else {
            temp = g_strdup_printf("Signal successfully sent to job %u",
                               job_id);
            display_edit_note(temp);
            g_free(temp);           
      }
}

static void _cancel_step_id(uint32_t job_id, uint32_t step_id,
                      uint16_t signal)
{
      int error_code = SLURM_SUCCESS, i;
      char *temp = NULL;

      for (i=0; i<MAX_CANCEL_RETRY; i++) {
            if (signal == (uint16_t)-1 || (signal == SIGKILL)) {
                  signal = 9;
                  error_code = slurm_terminate_job_step(job_id, step_id);
            } else {
                  error_code = slurm_signal_job_step(job_id, step_id,
                                             signal);
            }
            if (error_code == 0
                || (errno != ESLURM_TRANSITION_STATE_NO_UPDATE
                  && errno != ESLURM_JOB_PENDING))
                  break;
            temp = g_strdup_printf("Sending signal %u to job step %u.%u",
                               signal, job_id, step_id);
            display_edit_note(temp);
            g_free(temp);
            sleep ( 5 + i );
      }

      if (error_code) {
            error_code = slurm_get_errno();
            if (error_code != ESLURM_ALREADY_DONE) {
                  temp = g_strdup_printf(
                        "Kill job error on job step id %u.%u: %s", 
                        job_id, step_id, 
                        slurm_strerror(slurm_get_errno()));
                  display_edit_note(temp);
                  g_free(temp);
            } else {
                  display_edit_note(slurm_strerror(slurm_get_errno()));
            }
      } else {
            temp = g_strdup_printf(
                  "Signal successfully sent to job step %u.%u",
                  job_id, step_id);
            display_edit_note(temp);
            g_free(temp);     
      }
}

static void _set_active_combo_job(GtkComboBox *combo, 
                          GtkTreeModel *model, GtkTreeIter *iter,
                          int type)
{
      char *temp_char = NULL;
      int action = 0;

      gtk_tree_model_get(model, iter, type, &temp_char, -1);
      if(!temp_char)
            goto end_it;
      switch(type) {
      case SORTID_ACTION:
            if(!strcmp(temp_char, "none"))
                  action = 0;
            else if(!strcmp(temp_char, "cancel"))
                  action = 1;
            else if(!strcmp(temp_char, "suspend"))
                  action = 2;
            else if(!strcmp(temp_char, "resume"))
                  action = 3;
            else if(!strcmp(temp_char, "checkpoint"))
                  action = 4;
            else if(!strcmp(temp_char, "requeue"))
                  action = 5;
            else 
                  action = 0;
                        
            break;
      case SORTID_SHARED:
            if(!strcmp(temp_char, "yes"))
                  action = 0;
            else if(!strcmp(temp_char, "no"))
                  action = 1;
            else 
                  action = 0;
                        
            break;
      case SORTID_CONTIGUOUS:
            if(!strcmp(temp_char, "yes"))
                  action = 0;
            else if(!strcmp(temp_char, "no"))
                  action = 1;
            else 
                  action = 0;
            break;
#ifdef HAVE_BG
      case SORTID_ROTATE:
            if(!strcmp(temp_char, "yes"))
                  action = 0;
            else if(!strcmp(temp_char, "no"))
                  action = 1;
            else 
                  action = 0;
            break;
      case SORTID_CONNECTION:
            if(!strcmp(temp_char, "torus"))
                  action = 0;
            else if(!strcmp(temp_char, "mesh"))
                  action = 1;
            else if(!strcmp(temp_char, "nav"))
                  action = 2;
            else 
                  action = 0;
            break;
#endif
      default:
            break;
      }
      g_free(temp_char);
end_it:
      gtk_combo_box_set_active(combo, action);
      
}


/* don't free this char */
static const char *_set_job_msg(job_desc_msg_t *job_msg, const char *new_text,
                        int column)
{
      char *type = NULL;
      int temp_int = 0;
#ifdef HAVE_BG
      uint16_t rotate;
      uint16_t conn_type;
      char* token, *delimiter = ",x", *next_ptr;
      int j;
      uint16_t geo[SYSTEM_DIMENSIONS];
      char* geometry_tmp = xstrdup(new_text);
      char* original_ptr = geometry_tmp;
#endif
      if(!job_msg)
            return NULL;
      
      switch(column) {
      case SORTID_ACTION:
            xfree(got_edit_signal);
            if(!strcasecmp(new_text, "None"))
                  got_edit_signal = NULL;
            else
                  got_edit_signal = xstrdup(new_text);
            break;
      case SORTID_TIMELIMIT:
            if(!strcasecmp(new_text, "infinite"))
                  temp_int = INFINITE;
            else
                  temp_int = time_str2mins((char *)new_text);
            
            type = "timelimit";
            if(temp_int <= 0 && temp_int != INFINITE)
                  goto return_error;
            job_msg->time_limit = (uint32_t)temp_int;
            break;
      case SORTID_PRIORITY:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "priority";
            if(temp_int < 0)
                  goto return_error;
            job_msg->priority = (uint32_t)temp_int;
            break;
      case SORTID_NICE:
            temp_int = strtol(new_text, (char **)NULL, 10);
            type = "nice";
            if (abs(temp_int) > NICE_OFFSET) {
                  //error("Invalid nice value, must be between "
                  //      "-%d and %d", NICE_OFFSET, NICE_OFFSET);
                  goto return_error;
            }
            job_msg->nice = NICE_OFFSET + temp_int;
            
            break;
      case SORTID_REQ_PROCS:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "requested procs";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->num_procs = (uint32_t)temp_int;
            break;
      case SORTID_MIN_NODES:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "min nodes";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->min_nodes = (uint32_t)temp_int;
            break;
      case SORTID_MAX_NODES:
            temp_int = strtol(new_text, (char **)NULL, 10);

            type = "max nodes";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->max_nodes = (uint32_t)temp_int;
            break;
      case SORTID_MIN_PROCS:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "min procs";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->job_min_procs = (uint32_t)temp_int;
            break;
      case SORTID_MIN_MEM:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "min memory";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->job_min_memory = (uint32_t)temp_int;
            break;
      case SORTID_TMP_DISK:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "min tmp disk";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->job_min_tmp_disk = (uint32_t)temp_int;
            break;
      case SORTID_PARTITION:        
            job_msg->partition = xstrdup(new_text);
            type = "partition";
            break;
      case SORTID_NAME:       
            job_msg->name = xstrdup(new_text);
            type = "name";
            break;
      case SORTID_SHARED:
            if (!strcasecmp(new_text, "yes")) {
                  job_msg->shared = 1;
                  
            } else {
                  job_msg->shared = 0;
                  
            }
            type = "shared";
            break;
      case SORTID_CONTIGUOUS:
            if (!strcasecmp(new_text, "yes")) {
                  job_msg->contiguous = 1;
                  
            } else {
                  job_msg->contiguous = 0;
                  
            }
            type = "contiguous";    
            break;
      case SORTID_REQ_NODELIST:           
            job_msg->req_nodes = xstrdup(new_text);
            type = "requested nodelist";
            break;
      case SORTID_EXC_NODELIST:
            job_msg->exc_nodes = xstrdup(new_text);
            type = "excluded nodelist";
            break;
      case SORTID_FEATURES:         
            job_msg->features = xstrdup(new_text);
            type = "features";
            break;
      case SORTID_ACCOUNT:          
            job_msg->account = xstrdup(new_text);
            type = "account";
            break;
      case SORTID_DEPENDENCY:
            temp_int = strtol(new_text, (char **)NULL, 10);
            
            type = "dependency";
            if(temp_int <= 0)
                  goto return_error;
            job_msg->dependency = (uint32_t)temp_int;
            break;
#ifdef HAVE_BG
      case SORTID_GEOMETRY:
            type = "geometry";
            token = strtok_r(geometry_tmp, delimiter, &next_ptr);
            for (j=0; j<SYSTEM_DIMENSIONS; j++)
                  geo[j] = (uint16_t) NO_VAL;
            for (j=0; j<SYSTEM_DIMENSIONS; j++) {
                  if (token == NULL) {
                        //error("insufficient dimensions in "
                        //      "Geometry");
                        goto return_error;
                  }
                  geo[j] = (uint16_t) atoi(token);
                  if (geo[j] <= 0) {
                        //error("invalid --geometry argument");
                        xfree(original_ptr);
                        goto return_error;
                        break;
                  }
                  geometry_tmp = next_ptr;
                  token = strtok_r(geometry_tmp, delimiter, 
                               &next_ptr);
            }
            if (token != NULL) {
                  //error("too many dimensions in Geometry");
                  xfree(original_ptr);
                  goto return_error;
            }
            
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_GEOMETRY,
                             (void *) &geo);
            
            break;
      case SORTID_START:
            type = "start";
            token = strtok_r(geometry_tmp, delimiter, &next_ptr);
            for (j=0; j<SYSTEM_DIMENSIONS; j++)
                  geo[j] = (uint16_t) NO_VAL;
            for (j=0; j<SYSTEM_DIMENSIONS; j++) {
                  if (token == NULL) {
                        //error("insufficient dimensions in "
                        //      "Geometry");
                        goto return_error;
                  }
                  geo[j] = (uint16_t) atoi(token);
                  if (geo[j] <= 0) {
                        //error("invalid --geometry argument");
                        xfree(original_ptr);
                        goto return_error;
                        break;
                  }
                  geometry_tmp = next_ptr;
                  token = strtok_r(geometry_tmp, delimiter, 
                               &next_ptr);
            }
            if (token != NULL) {
                  //error("too many dimensions in Geometry");
                  xfree(original_ptr);
                  goto return_error;
            }
            
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_START,
                             (void *) &geo);
            
            break;
      case SORTID_ROTATE:
            type = "rotate";  
            if (!strcasecmp(new_text, "yes")) {
                  rotate = 1;
                  
            } else {
                  rotate = 0;
                  
            }
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_ROTATE,
                             (void *) &rotate);
            break;
      case SORTID_CONNECTION:
            type = "connection";
            if (!strcasecmp(new_text, "torus")) {
                  conn_type = SELECT_TORUS;
            } else if (!strcasecmp(new_text, "mesh")) {
                  conn_type = SELECT_MESH;
            } else {
                  conn_type = SELECT_NAV;
            }
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_CONN_TYPE,
                             (void *) &conn_type);
            
            break;
      case SORTID_BLRTSIMAGE:
            type = "BlrtsImage";
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_BLRTS_IMAGE,
                             (void *) new_text);
            break;
      case SORTID_LINUXIMAGE:       
            type = "LinuxImage";
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_LINUX_IMAGE,
                             (void *) new_text);
            break;
      case SORTID_MLOADERIMAGE:           
            type = "MloaderImage";
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_MLOADER_IMAGE,
                             (void *) new_text);
            break;
       case SORTID_RAMDISKIMAGE:          
            type = "RamdiskImage";
            if(!job_msg->select_jobinfo)
                  select_g_alloc_jobinfo(&job_msg->select_jobinfo);
            select_g_set_jobinfo(job_msg->select_jobinfo,
                             SELECT_DATA_RAMDISK_IMAGE,
                             (void *) new_text);
            break;
#endif
      case SORTID_START_TIME:
            job_msg->begin_time = parse_time((char *)new_text);
            type = "start time";
            break;
      default:
            type = "unknown";
            break;
      }

#ifdef HAVE_BG
      xfree(geometry_tmp);
#endif
      return type;

return_error:
#ifdef HAVE_BG
      xfree(geometry_tmp);
#endif
      errno = 1;
      return type;
}

static void _admin_edit_combo_box_job(GtkComboBox *combo,
                              job_desc_msg_t *job_msg)
{
      GtkTreeModel *model = NULL;
      GtkTreeIter iter;
      int column = 0;
      char *name = NULL;
      
      if(!job_msg)
            return;

      if(!gtk_combo_box_get_active_iter(combo, &iter)) {
            g_print("nothing selected\n");
            return;
      }
      model = gtk_combo_box_get_model(combo);
      if(!model) {
            g_print("nothing selected\n");
            return;
      }
      
      gtk_tree_model_get(model, &iter, 0, &name, -1);
      gtk_tree_model_get(model, &iter, 1, &column, -1);
 
      _set_job_msg(job_msg, name, column);

      g_free(name);
}

static gboolean _admin_focus_out_job(GtkEntry *entry,
                             GdkEventFocus *event, 
                             job_desc_msg_t *job_msg)
{
      int type = gtk_entry_get_max_length(entry);
      const char *name = gtk_entry_get_text(entry);
      type -= DEFAULT_ENTRY_LENGTH;
      _set_job_msg(job_msg, name, type);
      
      return false;
}

static GtkWidget *_admin_full_edit_job(job_desc_msg_t *job_msg, 
                               GtkTreeModel *model, GtkTreeIter *iter)
{
      GtkScrolledWindow *window = create_scrolled_window();
      GtkBin *bin = NULL;
      GtkViewport *view = NULL;
      GtkTable *table = NULL;
      GtkWidget *label = NULL;
      GtkWidget *entry = NULL;
      GtkTreeModel *model2 = NULL; 
      GtkCellRenderer *renderer = NULL;
      int i = 0, row = 0;
      char *temp_char = NULL;

      gtk_scrolled_window_set_policy(window,
                               GTK_POLICY_NEVER,
                               GTK_POLICY_AUTOMATIC);
      bin = GTK_BIN(&window->container);
      view = GTK_VIEWPORT(bin->child);
      bin = GTK_BIN(&view->bin);
      table = GTK_TABLE(bin->child);
      gtk_table_resize(table, SORTID_CNT, 2);
      
      gtk_table_set_homogeneous(table, FALSE);  

      for(i = 0; i < SORTID_CNT; i++) {
            if(display_data_job[i].extra == EDIT_MODEL) {
                  /* edittable items that can only be known
                     values */
                  model2 = GTK_TREE_MODEL(
                        create_model_job(display_data_job[i].id));
                  if(!model2) {
                        g_print("no model set up for %d(%s)\n",
                              display_data_job[i].id,
                              display_data_job[i].name);
                        continue;
                  }
                  entry = gtk_combo_box_new_with_model(model2);
                  g_object_unref(model2);
                  
                  _set_active_combo_job(GTK_COMBO_BOX(entry), model,
                                    iter, display_data_job[i].id);
                  
                  g_signal_connect(entry, "changed",
                               G_CALLBACK(_admin_edit_combo_box_job),
                               job_msg);
                  
                  renderer = gtk_cell_renderer_text_new();
                  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(entry),
                                       renderer, TRUE);
                  gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(entry),
                                          renderer, "text", 0);
            } else if(display_data_job[i].extra == EDIT_TEXTBOX) {
                  /* other edittable items that are unknown */
                  entry = create_entry();
                  gtk_tree_model_get(model, iter, display_data_job[i].id,
                                 &temp_char, -1);
                  gtk_entry_set_max_length(GTK_ENTRY(entry), 
                                     (DEFAULT_ENTRY_LENGTH +
                                      display_data_job[i].id));
                  
                  if(temp_char) {
                        gtk_entry_set_text(GTK_ENTRY(entry),
                                       temp_char);
                        g_free(temp_char);
                  }
                  g_signal_connect(entry, "focus-out-event",
                               G_CALLBACK(_admin_focus_out_job),
                               job_msg);
            } else /* others can't be altered by the user */
                  continue;
            label = gtk_label_new(display_data_job[i].name);
            gtk_table_attach(table, label, 0, 1, row, row+1,
                         GTK_FILL | GTK_EXPAND, GTK_SHRINK, 
                         0, 0);
            gtk_table_attach(table, entry, 1, 2, row, row+1,
                         GTK_FILL, GTK_SHRINK,
                         0, 0);
            row++;
      }
      gtk_table_resize(table, row, 2);
      
      return GTK_WIDGET(window);
}

static int _nodes_in_list(char *node_list)
{
      hostset_t host_set = hostset_create(node_list);
      int count = hostset_count(host_set);
      hostset_destroy(host_set);
      return count;
}

static int _get_node_cnt(job_info_t * job)
{
      int node_cnt = 0;
      bool completing = job->job_state & JOB_COMPLETING;
      uint16_t base_job_state = job->job_state & (~JOB_COMPLETING);

      if (base_job_state == JOB_PENDING || completing) {
            node_cnt = _nodes_in_list(job->req_nodes);
            node_cnt = MAX(node_cnt, job->num_nodes);
      } else
            node_cnt = _nodes_in_list(job->nodes);
      return node_cnt;
}

/* this needs to be freed by xfree() */
static void _convert_char_to_job_and_step(const char *data,
                                int *jobid, int *stepid) 
{
      int i = 0;

      if(!data)
            return;
      *jobid = atoi(data);
      *stepid = NO_VAL;
      while(data[i]) {
            if(data[i] == '.') {
                  i++;
                  if(data[i])
                        *stepid = atoi(&data[i]);
                  break;
            }
            i++;
      }

      return;
}

static void _layout_job_record(GtkTreeView *treeview, 
                         sview_job_info_t *sview_job_info_ptr, 
                         int update)
{
      char *nodes = NULL;
      char tmp_char[50];
      time_t now_time = time(NULL);
      job_info_t *job_ptr = sview_job_info_ptr->job_ptr;
      struct group *group_info = NULL;
      uint16_t term_sig = 0;

      GtkTreeIter iter;
      GtkTreeStore *treestore = 
            GTK_TREE_STORE(gtk_tree_view_get_model(treeview));

      if(!treestore)
            return;
      if(!job_ptr->nodes || !strcasecmp(job_ptr->nodes,"waiting...")) {
            sprintf(tmp_char,"0:00:00");
            nodes = "waiting...";
      } else {
            if (job_ptr->job_state == JOB_SUSPENDED)
                  now_time = job_ptr->pre_sus_time;
            else {
                  if ((job_ptr->job_state != JOB_RUNNING)
                      && (job_ptr->end_time != 0))
                        now_time = job_ptr->end_time;
                  if (job_ptr->suspend_time)
                        now_time = (difftime(now_time,
                                         job_ptr->suspend_time)
                                  + job_ptr->pre_sus_time);
                  now_time = difftime(now_time, job_ptr->start_time);
            }
            secs2time_str(now_time, tmp_char, sizeof(tmp_char));
            nodes = sview_job_info_ptr->nodes;  
      }
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_TIME), 
                           tmp_char);

      slurm_make_time_str((time_t *)&job_ptr->submit_time, tmp_char,
                      sizeof(tmp_char));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_SUBMIT_TIME), 
                           tmp_char);
      slurm_make_time_str((time_t *)&job_ptr->start_time, tmp_char,
                      sizeof(tmp_char));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_START_TIME), 
                           tmp_char);
      if ((job_ptr->time_limit == INFINITE) && 
          (job_ptr->end_time > time(NULL)))
            sprintf(tmp_char, "NONE");
      else 
            slurm_make_time_str((time_t *)&job_ptr->end_time, tmp_char,
                            sizeof(tmp_char));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_END_TIME), 
                           tmp_char);
      secs2time_str(job_ptr->suspend_time, tmp_char, sizeof(tmp_char));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_SUSPEND_TIME), 
                           tmp_char);

      if (job_ptr->time_limit == NO_VAL)
            sprintf(tmp_char, "Partition Limit");
      else
            secs2time_str((job_ptr->time_limit * 60),
                        tmp_char, sizeof(tmp_char));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_TIMELIMIT), 
                           tmp_char);
            
      snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->job_id);      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_JOBID), 
                           tmp_char);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_PARTITION),
                           job_ptr->partition);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NODELIST), 
                           nodes);

#ifdef HAVE_BG
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_BLOCK), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_BG_ID));
#endif
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_USER), 
                           uid_to_string((uid_t)job_ptr->user_id));
      group_info = getgrgid((gid_t) job_ptr->group_id );
      if ( group_info && group_info->gr_name[ 0 ] ) {
            snprintf(tmp_char, sizeof(tmp_char), "%s",
                   group_info->gr_name);
      } else {
            snprintf(tmp_char, sizeof(tmp_char), "%u", 
                  job_ptr->group_id );
      }
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_GROUP), 
                           tmp_char);
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NAME), 
                           job_ptr->name);
      
      sprintf(tmp_char, "%u", job_ptr->priority);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_PRIORITY),
                           tmp_char);

      if(job_ptr->batch_flag)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_BATCH),
                           tmp_char);
      
      if (WIFSIGNALED(job_ptr->exit_code))
            term_sig = WTERMSIG(job_ptr->exit_code);
      snprintf(tmp_char, sizeof(tmp_char), "%u:%u",
             WEXITSTATUS(job_ptr->exit_code), term_sig);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_EXIT_CODE),
                           tmp_char);
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job, 
                                     SORTID_STATE), 
                           job_state_string(job_ptr->job_state));
      
#ifdef HAVE_BG
      convert_num_unit((float)sview_job_info_ptr->node_cnt,
                   tmp_char, sizeof(tmp_char), UNIT_NONE);
#else
      snprintf(tmp_char, sizeof(tmp_char), "%u", 
             sview_job_info_ptr->node_cnt);
#endif
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NODES), 
                           tmp_char);

#ifdef HAVE_BG
      convert_num_unit((float)job_ptr->num_procs, tmp_char, sizeof(tmp_char), 
                   UNIT_NONE);
#else
      snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_procs);
#endif
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NUM_PROCS),
                           tmp_char);     
      
      snprintf(tmp_char, sizeof(tmp_char), "%s:%u",
             job_ptr->alloc_node, job_ptr->alloc_sid);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_ALLOC_NODE),
                           tmp_char);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_REQ_NODELIST),
                           job_ptr->req_nodes);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_EXC_NODELIST),
                           job_ptr->exc_nodes);
#ifdef HAVE_BG
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_BLOCK), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_BG_ID));
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_CONNECTION), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_CONNECTION));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_ROTATE), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_ROTATE));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_GEOMETRY), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_GEOMETRY));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_START), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_START));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MAX_PROCS), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_MAX_PROCS));
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_BLRTSIMAGE), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_BLRTS_IMAGE));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_LINUXIMAGE), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_LINUX_IMAGE));
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MLOADERIMAGE), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_MLOADER_IMAGE));
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_RAMDISKIMAGE), 
                           select_g_sprint_jobinfo(
                                 job_ptr->select_jobinfo, 
                                 tmp_char, 
                                 sizeof(tmp_char), 
                                 SELECT_PRINT_RAMDISK_IMAGE));
      
#endif

      if(job_ptr->contiguous)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_CONTIGUOUS),
                           tmp_char);
      if(job_ptr->shared)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_SHARED),
                           tmp_char);
      
      if(job_ptr->cpus_per_task > 0) 
            sprintf(tmp_char, "%u", job_ptr->cpus_per_task);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_CPUS_PER_TASK),
                           tmp_char);
      
      if(job_ptr->job_min_procs > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_procs);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MIN_PROCS),
                           tmp_char);
      
      if(job_ptr->job_min_sockets > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_sockets);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MIN_SOCKETS),
                           tmp_char);
      
      if(job_ptr->job_min_cores > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_cores);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MIN_CORES),
                           tmp_char);
      
      if(job_ptr->job_min_threads > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_threads);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MIN_THREADS),
                           tmp_char);
      
      if(job_ptr->job_min_memory > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_memory);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_MIN_MEM),
                           tmp_char);
      
      if(job_ptr->job_min_tmp_disk > 0) 
            sprintf(tmp_char, "%u", job_ptr->job_min_tmp_disk);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_TMP_DISK),
                           tmp_char);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_FEATURES),
                           job_ptr->features);
      
      if(job_ptr->dependency > 0) 
            sprintf(tmp_char, "%u", job_ptr->dependency);
      else 
            sprintf(tmp_char, " ");
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_DEPENDENCY),
                           tmp_char);
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_ACCOUNT),
                           job_ptr->account);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_REASON),
                           job_reason_string(job_ptr->state_reason));

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NETWORK),
                           job_ptr->network);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_COMMENT),
                           job_ptr->comment);
}

static void _update_job_record(sview_job_info_t *sview_job_info_ptr, 
                         GtkTreeStore *treestore,
                         GtkTreeIter *iter)
{
      char *nodes = NULL;
      char tmp_char[50];
      time_t now_time = time(NULL);
      GtkTreeIter step_iter;
      int childern = 0;
      job_info_t *job_ptr = sview_job_info_ptr->job_ptr;
      struct group *group_info = NULL;
      uint16_t term_sig = 0;
      
      gtk_tree_store_set(treestore, iter, SORTID_UPDATED, 1, -1);
      if(!job_ptr->nodes || !strcasecmp(job_ptr->nodes,"waiting...")) {
            sprintf(tmp_char,"0:00:00");
            nodes = "waiting...";
      } else {
            if (job_ptr->job_state == JOB_SUSPENDED)
                  now_time = job_ptr->pre_sus_time;
            else {
                  if ((job_ptr->job_state != JOB_RUNNING)
                      && (job_ptr->end_time != 0)) 
                        now_time = job_ptr->end_time;
                  if (job_ptr->suspend_time)
                        now_time = (difftime(now_time,
                                         job_ptr->suspend_time)
                                  + job_ptr->pre_sus_time);
                  now_time = difftime(now_time, job_ptr->start_time);
            }
            secs2time_str(now_time, tmp_char, sizeof(tmp_char));
            nodes = sview_job_info_ptr->nodes;  
      }
      gtk_tree_store_set(treestore, iter, SORTID_TIME, tmp_char, -1);
      slurm_make_time_str((time_t *)&job_ptr->submit_time, tmp_char,
                      sizeof(tmp_char));
      gtk_tree_store_set(treestore, iter, SORTID_SUBMIT_TIME, tmp_char, -1);
      slurm_make_time_str((time_t *)&job_ptr->start_time, tmp_char,
                      sizeof(tmp_char));
      gtk_tree_store_set(treestore, iter, SORTID_START_TIME, tmp_char, -1);
      if ((job_ptr->time_limit == INFINITE) && 
          (job_ptr->end_time > time(NULL)))
            sprintf(tmp_char, "NONE");
      else 
            slurm_make_time_str((time_t *)&job_ptr->end_time, tmp_char,
                            sizeof(tmp_char));
      gtk_tree_store_set(treestore, iter, SORTID_END_TIME, tmp_char, -1);
      slurm_make_time_str((time_t *)&job_ptr->suspend_time, tmp_char,
                      sizeof(tmp_char));
      gtk_tree_store_set(treestore, iter, SORTID_SUSPEND_TIME, tmp_char, -1);

      if (job_ptr->time_limit == NO_VAL)
            sprintf(tmp_char, "Partition Limit");
      else
            secs2time_str((job_ptr->time_limit * 60),
                        tmp_char, sizeof(tmp_char));
      gtk_tree_store_set(treestore, iter, SORTID_TIMELIMIT, tmp_char, -1);
      
      gtk_tree_store_set(treestore, iter, SORTID_ALLOC, 1, -1);
      gtk_tree_store_set(treestore, iter, SORTID_JOBID, job_ptr->job_id, -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_PARTITION, job_ptr->partition, -1);
      snprintf(tmp_char, sizeof(tmp_char), "%s:%u",
             job_ptr->alloc_node, job_ptr->alloc_sid);
      gtk_tree_store_set(treestore, iter, SORTID_ALLOC_NODE, tmp_char, -1);
            
#ifdef HAVE_BG
      gtk_tree_store_set(treestore, iter, 
                     SORTID_BLOCK, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_BG_ID), -1);
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_CONNECTION, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_CONNECTION), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_ROTATE, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_ROTATE), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_GEOMETRY, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_GEOMETRY), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_START, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_START), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_MAX_PROCS, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_MAX_PROCS), -1);
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_BLRTSIMAGE, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_BLRTS_IMAGE), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_LINUXIMAGE, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_LINUX_IMAGE), -1);
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_MLOADERIMAGE, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_MLOADER_IMAGE), -1);
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_RAMDISKIMAGE, 
                     select_g_sprint_jobinfo(
                           job_ptr->select_jobinfo, 
                           tmp_char, 
                           sizeof(tmp_char), 
                           SELECT_PRINT_RAMDISK_IMAGE), -1);
      
#endif
      gtk_tree_store_set(treestore, iter, 
                     SORTID_USER, 
                     uid_to_string((uid_t)job_ptr->user_id), -1);
      group_info = getgrgid((gid_t) job_ptr->group_id );
      if ( group_info && group_info->gr_name[ 0 ] ) {
            snprintf(tmp_char, sizeof(tmp_char), "%s",
                   group_info->gr_name);
      } else {
            snprintf(tmp_char, sizeof(tmp_char), "%u", 
                  job_ptr->group_id );
      }
      gtk_tree_store_set(treestore, iter, 
                     SORTID_GROUP, 
                     tmp_char, -1);
            
      gtk_tree_store_set(treestore, iter, SORTID_NAME, job_ptr->name, -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_STATE, 
                     job_state_string(job_ptr->job_state), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_STATE_NUM, 
                     job_ptr->job_state, -1);
      
#ifdef HAVE_BG
      convert_num_unit((float)sview_job_info_ptr->node_cnt,
                   tmp_char, sizeof(tmp_char), UNIT_NONE);
#else
      sprintf(tmp_char, "%u", sview_job_info_ptr->node_cnt);
#endif
      gtk_tree_store_set(treestore, iter, 
                     SORTID_NODES, tmp_char, -1);

#ifdef HAVE_BG
      convert_num_unit((float)job_ptr->num_procs, tmp_char, sizeof(tmp_char),
                   UNIT_NONE);
#else
      snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_procs);
#endif
      gtk_tree_store_set(treestore, iter, 
                     SORTID_NUM_PROCS, tmp_char, -1);
      
      gtk_tree_store_set(treestore, iter, SORTID_NODELIST, nodes, -1);
      gtk_tree_store_set(treestore, iter, SORTID_REQ_NODELIST,
                     job_ptr->req_nodes, -1);
      gtk_tree_store_set(treestore, iter, SORTID_EXC_NODELIST,
                     job_ptr->exc_nodes, -1);

      if(job_ptr->contiguous)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_CONTIGUOUS, tmp_char, -1);
      if(job_ptr->shared)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      gtk_tree_store_set(treestore, iter, 
                     SORTID_SHARED, tmp_char, -1);
      
      if(job_ptr->batch_flag)
            sprintf(tmp_char, "yes");
      else
            sprintf(tmp_char, "no");
      gtk_tree_store_set(treestore, iter, 
                     SORTID_BATCH, tmp_char, -1);
      
      sprintf(tmp_char, "%u", job_ptr->num_nodes);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_MIN_NODES, tmp_char, -1);
      if(job_ptr->max_nodes > 0) {
            sprintf(tmp_char, "%u", job_ptr->max_nodes);
            gtk_tree_store_set(treestore, iter, 
                           SORTID_MAX_NODES, tmp_char, -1);
      }
      if(job_ptr->cpus_per_task > 0) {
            sprintf(tmp_char, "%u", job_ptr->cpus_per_task);
            gtk_tree_store_set(treestore, iter, 
                           SORTID_CPUS_PER_TASK, tmp_char, -1);
      }
      sprintf(tmp_char, "%u", job_ptr->job_min_procs);
      gtk_tree_store_set(treestore, iter,
                     SORTID_REQ_PROCS, tmp_char, -1);

      sprintf(tmp_char, "%u", job_ptr->min_sockets);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MIN_SOCKETS, tmp_char, -1);
      sprintf(tmp_char, "%u", job_ptr->max_sockets);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MAX_SOCKETS, tmp_char, -1);
      
      sprintf(tmp_char, "%u", job_ptr->min_cores);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MIN_CORES, tmp_char, -1);
      sprintf(tmp_char, "%u", job_ptr->max_cores);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MAX_CORES, tmp_char, -1);
      
      sprintf(tmp_char, "%u", job_ptr->min_threads);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MIN_THREADS, tmp_char, -1);
      sprintf(tmp_char, "%u", job_ptr->max_threads);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MAX_THREADS, tmp_char, -1);
      
      sprintf(tmp_char, "%u", job_ptr->job_min_memory);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MIN_MEM, tmp_char, -1);

      sprintf(tmp_char, "%u", job_ptr->job_max_memory);
      gtk_tree_store_set(treestore, iter,
                     SORTID_MAX_MEM, tmp_char, -1);
      
      sprintf(tmp_char, "%u", job_ptr->job_min_tmp_disk);
      gtk_tree_store_set(treestore, iter,
                     SORTID_TMP_DISK, tmp_char, -1);

      gtk_tree_store_set(treestore, iter,
                     SORTID_ACCOUNT, job_ptr->account, -1);
      if(job_ptr->dependency > 0) {
            sprintf(tmp_char, "%u", job_ptr->dependency);
            gtk_tree_store_set(treestore, iter,
                           SORTID_DEPENDENCY, tmp_char, -1);
      }
      sprintf(tmp_char, "%u", job_ptr->priority);
      gtk_tree_store_set(treestore, iter,
                     SORTID_PRIORITY, tmp_char, -1);
      
      if(WIFSIGNALED(job_ptr->exit_code))
            term_sig = WTERMSIG(job_ptr->exit_code);
      snprintf(tmp_char, sizeof(tmp_char), "%u:%u",
             WEXITSTATUS(job_ptr->exit_code), term_sig);
      gtk_tree_store_set(treestore, iter,
                     SORTID_EXIT_CODE, tmp_char, -1);


      gtk_tree_store_set(treestore, iter,
                     SORTID_FEATURES, job_ptr->features, -1);
      gtk_tree_store_set(treestore, iter,
                     SORTID_REASON,
                     job_reason_string(job_ptr->state_reason), -1);
      gtk_tree_store_set(treestore, iter,
                     SORTID_NETWORK, job_ptr->network, -1);
      gtk_tree_store_set(treestore, iter,
                     SORTID_COMMENT, job_ptr->comment, -1);


      childern = gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore),
                                    &step_iter, iter);
      if(gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore),
                              &step_iter, iter))
            _update_info_step(sview_job_info_ptr, 
                          GTK_TREE_MODEL(treestore), &step_iter, iter);
      else
            _update_info_step(sview_job_info_ptr, 
                          GTK_TREE_MODEL(treestore), NULL, iter);
            
      return;
}

static void _layout_step_record(GtkTreeView *treeview, 
                        job_step_info_t *step_ptr,
                        int update)
{
      char *nodes = NULL;
      char tmp_char[50];
      char tmp_time[50];
      time_t now_time = time(NULL);
      GtkTreeIter iter;
      enum job_states state;
      GtkTreeStore *treestore = 
            GTK_TREE_STORE(gtk_tree_view_get_model(treeview));

      if(!treestore)
            return;
      if(!step_ptr->nodes 
         || !strcasecmp(step_ptr->nodes,"waiting...")) {
            sprintf(tmp_time,"0:00:00");
            nodes = "waiting...";
            state = JOB_PENDING;
      } else {
            now_time -= step_ptr->start_time;
            secs2time_str(now_time, tmp_time, sizeof(tmp_time));
            nodes = step_ptr->nodes;
#ifdef HAVE_BG
            convert_num_unit((float)step_ptr->num_tasks,
                         tmp_char, sizeof(tmp_char), UNIT_NONE);
#else
            convert_num_unit((float)_nodes_in_list(nodes), 
                         tmp_char, sizeof(tmp_char), UNIT_NONE);
#endif
            add_display_treestore_line(update, treestore, &iter, 
                                 find_col_name(display_data_job,
                                           SORTID_NODES),
                                 tmp_char);
            state = JOB_RUNNING;
      }

      add_display_treestore_line(update, treestore, &iter,
                           find_col_name(display_data_job,
                                     SORTID_STATE),
                           job_state_string(state));
      
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_TIME), 
                           tmp_time);
            
      snprintf(tmp_char, sizeof(tmp_char), "%u.%u", 
             step_ptr->job_id,
             step_ptr->step_id);    
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_JOBID),
                           tmp_char);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_PARTITION),
                           step_ptr->partition);
/* #ifdef HAVE_BG */
/*    add_display_treestore_line(update, treestore, &iter,  */
/*                   find_col_name(display_data_job, SORTID_BLOCK),  */
/*                   select_g_sprint_jobinfo( */
/*                         step_ptr->select_jobinfo,  */
/*                         tmp_char,  */
/*                         sizeof(tmp_char),  */
/*                         SELECT_PRINT_BG_ID)); */
/* #endif */
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_USER), 
                           uid_to_string((uid_t)step_ptr->user_id));
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NAME),
                           step_ptr->name);
            
      convert_num_unit((float)step_ptr->num_tasks, tmp_char, sizeof(tmp_char),
                   UNIT_NONE);
      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_TASKS),
                           tmp_char);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NUM_PROCS),
                           tmp_char);

      add_display_treestore_line(update, treestore, &iter, 
                           find_col_name(display_data_job,
                                     SORTID_NODELIST),
                           nodes);
}

static void _update_step_record(job_step_info_t *step_ptr, 
                        GtkTreeStore *treestore,
                        GtkTreeIter *iter)
{
      char *nodes = NULL;
      char tmp_char[50];
      char tmp_time[50];
      time_t now_time = time(NULL);
      enum job_states state;

      gtk_tree_store_set(treestore, iter, SORTID_UPDATED, 1, -1);
      if(!step_ptr->nodes 
         || !strcasecmp(step_ptr->nodes,"waiting...")) {
            sprintf(tmp_char,"0:00:00");
            nodes = "waiting...";
            state = JOB_PENDING;
      } else {
            now_time -= step_ptr->start_time;
            secs2time_str(now_time, tmp_time, sizeof(tmp_time));
            nodes = step_ptr->nodes;
#ifdef HAVE_BG
            convert_num_unit((float)step_ptr->num_tasks,
                         tmp_char, sizeof(tmp_char), UNIT_NONE);
#else
            convert_num_unit((float)_nodes_in_list(nodes), 
                         tmp_char, sizeof(tmp_char), UNIT_NONE);
#endif
            gtk_tree_store_set(treestore, iter, 
                           SORTID_NODES, tmp_char, -1);
            state = JOB_RUNNING;
      }

      gtk_tree_store_set(treestore, iter,
                     SORTID_STATE,
                     job_state_string(state), -1);
      
      gtk_tree_store_set(treestore, iter, 
                     SORTID_TIME, tmp_time, -1);
      
      gtk_tree_store_set(treestore, iter, SORTID_ALLOC, 0, -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_JOBID, step_ptr->step_id, -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_PARTITION, step_ptr->partition, -1);
/* #ifdef HAVE_BG */
/*    gtk_tree_store_set(treestore, iter,  */
/*                   SORTID_BLOCK,  */
/*                   select_g_sprint_jobinfo( */
/*                         step_ptr->select_jobinfo,  */
/*                         tmp_char,  */
/*                         sizeof(tmp_char),  */
/*                         SELECT_PRINT_BG_ID), -1); */
/* #endif */
      gtk_tree_store_set(treestore, iter, 
                     SORTID_USER, 
                     uid_to_string((uid_t)step_ptr->user_id), -1);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_NAME, step_ptr->name, -1);
            
      convert_num_unit((float)step_ptr->num_tasks, tmp_char, sizeof(tmp_char),
                   UNIT_NONE);
      gtk_tree_store_set(treestore, iter, 
                     SORTID_TASKS, tmp_char, -1);

      gtk_tree_store_set(treestore, iter, 
                     SORTID_NUM_PROCS, tmp_char, -1);

      gtk_tree_store_set(treestore, iter, 
                     SORTID_NODELIST, nodes, -1);
            
      return;
}

static void _append_job_record(sview_job_info_t *sview_job_info_ptr, 
                         GtkTreeStore *treestore, GtkTreeIter *iter,
                         int line)
{
      gtk_tree_store_append(treestore, iter, NULL);
      gtk_tree_store_set(treestore, iter, SORTID_POS, line, -1);
      _update_job_record(sview_job_info_ptr, treestore, iter);    
}

static void _append_step_record(job_step_info_t *step_ptr,
                        GtkTreeStore *treestore, GtkTreeIter *iter,
                        int jobid)
{
      GtkTreeIter step_iter;

      gtk_tree_store_append(treestore, &step_iter, iter);
      gtk_tree_store_set(treestore, &step_iter, SORTID_POS, jobid, -1);
      _update_step_record(step_ptr, treestore, &step_iter);
}

static void _update_info_step(sview_job_info_t *sview_job_info_ptr, 
                        GtkTreeModel *model, 
                        GtkTreeIter *step_iter,
                        GtkTreeIter *iter)
{
      int stepid = 0;
      int i;
      GtkTreeIter first_step_iter;
      int set = 0;
      ListIterator itr = NULL;
      job_step_info_t *step_ptr = NULL;
                        
      memset(&first_step_iter, 0, sizeof(GtkTreeIter));

      /* make sure all the steps are still here */
      if (step_iter) {
            first_step_iter = *step_iter;
            while(1) {
                  gtk_tree_store_set(GTK_TREE_STORE(model), step_iter, 
                                 SORTID_UPDATED, 0, -1);    
                  if(!gtk_tree_model_iter_next(model, step_iter)) {
                        break;
                  }
            }
            memcpy(step_iter, &first_step_iter, sizeof(GtkTreeIter));
            set = 1;
      }
      itr = list_iterator_create(sview_job_info_ptr->step_list);
      while((step_ptr = list_next(itr))) {
            /* get the iter, or find out the list is empty goto add */
            if (!step_iter) {
                  goto adding;
            } else {
                  memcpy(step_iter, &first_step_iter, 
                         sizeof(GtkTreeIter));
            }
            while(1) {
                  /* search for the jobid and check to see if 
                     it is in the list */
                  gtk_tree_model_get(model, step_iter, SORTID_JOBID, 
                                 &stepid, -1);
                  if(stepid == (int)step_ptr->step_id) {
                        /* update with new info */
                        _update_step_record(step_ptr,
                                        GTK_TREE_STORE(model), 
                                        step_iter);
                        goto found;
                  }                 
                  
                  if(!gtk_tree_model_iter_next(model, step_iter)) {
                        step_iter = NULL;
                        break;
                  }
            }
      adding:
            _append_step_record(step_ptr, GTK_TREE_STORE(model), 
                            iter, sview_job_info_ptr->job_ptr->job_id);
      found:
            ;
      }
      list_iterator_destroy(itr);

      if(set) {
            step_iter = &first_step_iter;
            /* clear all steps that aren't active */
            while(1) {
                  gtk_tree_model_get(model, step_iter, 
                                 SORTID_UPDATED, &i, -1);
                  if(!i) {
                        if(!gtk_tree_store_remove(
                                 GTK_TREE_STORE(model), 
                                 step_iter))
                              break;
                        else
                              continue;
                  }
                  if(!gtk_tree_model_iter_next(model, step_iter)) {
                        break;
                  }
            }
      }
      return;
}                        

static void _update_info_job(List info_list,
                       GtkTreeView *tree_view)
{
      GtkTreePath *path = gtk_tree_path_new_first();
      GtkTreeModel *model = gtk_tree_view_get_model(tree_view);
      GtkTreeIter iter;
      int jobid = 0;
      job_info_t *job_ptr = NULL;
      int line = 0;
      char *host = NULL;
      ListIterator itr = NULL;
      sview_job_info_t *sview_job_info = NULL;

      /* make sure all the jobs are still here */
      if (gtk_tree_model_get_iter(model, &iter, path)) {
            while(1) {
                  gtk_tree_store_set(GTK_TREE_STORE(model), &iter, 
                                 SORTID_UPDATED, 0, -1);    
                  if(!gtk_tree_model_iter_next(model, &iter)) {
                        break;
                  }
            }
      }
      
      itr = list_iterator_create(info_list);
      while ((sview_job_info = (sview_job_info_t*) list_next(itr))) {
            job_ptr = sview_job_info->job_ptr;
            /* get the iter, or find out the list is empty goto add */
            if (!gtk_tree_model_get_iter(model, &iter, path)) {
                  goto adding;
            }

            while(1) {
                  /* search for the jobid and check to see if 
                     it is in the list */
                  gtk_tree_model_get(model, &iter, SORTID_JOBID, 
                                 &jobid, -1);
                  if(jobid == job_ptr->job_id) {
                        /* update with new info */
                        _update_job_record(sview_job_info,
                                       GTK_TREE_STORE(model), 
                                       &iter);
                        goto found;
                  }
                  
                  /* see what line we were on to add the next one 
                     to the list */
                  gtk_tree_model_get(model, &iter, SORTID_POS, 
                                 &line, -1);
                  if(!gtk_tree_model_iter_next(model, &iter)) {
                        line++;
                        break;
                  }
            }
      adding:                 
            _append_job_record(sview_job_info, GTK_TREE_STORE(model), 
                           &iter, line);
      found:
            ;
      }
      list_iterator_destroy(itr);
      if(host)
            free(host);
      gtk_tree_path_free(path);
      /* remove all old jobs */
      remove_old(model, SORTID_UPDATED);
      return;     
}

static void _job_info_list_del(void *object)
{
      sview_job_info_t *sview_job_info = (sview_job_info_t *)object;

      if (sview_job_info) {
            xfree(sview_job_info->nodes);
            if(sview_job_info->step_list)
                  list_destroy(sview_job_info->step_list);
            xfree(sview_job_info);
      }
}


static List _create_job_info_list(job_info_msg_t *job_info_ptr,
                          job_step_info_response_msg_t *step_info_ptr,
                          int changed, int want_odd_states)
{
      static List info_list = NULL;
      static List odd_info_list = NULL;
      int i = 0, j = 0;
      sview_job_info_t *sview_job_info_ptr = NULL;
      job_info_t *job_ptr = NULL;
      job_step_info_t *step_ptr = NULL;
#ifdef HAVE_BG
      char *ionodes = NULL;
      char tmp_char[50];
#endif

#ifdef HAVE_FRONT_END
      int count = 0;
#endif
      if(!changed && info_list) {
            goto update_color;
      }
      
      if(info_list) {
            list_destroy(info_list);
            list_destroy(odd_info_list);
      }

      info_list = list_create(NULL);
      odd_info_list = list_create(_job_info_list_del);
      if (!info_list || !odd_info_list) {
            g_print("malloc error\n");
            return NULL;
      }
      
      for(i=0; i<job_info_ptr->record_count; i++) {
            job_ptr = &(job_info_ptr->job_array[i]);
            sview_job_info_ptr = xmalloc(sizeof(sview_job_info_t));
            sview_job_info_ptr->job_ptr = job_ptr;
            sview_job_info_ptr->step_list = list_create(NULL);
            sview_job_info_ptr->node_cnt = 0;
            sview_job_info_ptr->nodes = NULL;
#ifdef HAVE_BG
            select_g_get_jobinfo(job_ptr->select_jobinfo, 
                             SELECT_DATA_IONODES, 
                             &ionodes);
            select_g_get_jobinfo(job_ptr->select_jobinfo, 
                             SELECT_DATA_NODE_CNT, 
                             &sview_job_info_ptr->node_cnt);
            if(ionodes) {
                  snprintf(tmp_char, sizeof(tmp_char), "%s[%s]",
                               job_ptr->nodes, ionodes);
                  xfree(ionodes);
                  sview_job_info_ptr->nodes = xstrdup(tmp_char);
            }
#endif
            if(!sview_job_info_ptr->nodes)
                  sview_job_info_ptr->nodes = xstrdup(job_ptr->nodes);

            if(!sview_job_info_ptr->node_cnt)
                  sview_job_info_ptr->node_cnt = _get_node_cnt(job_ptr);

#ifdef HAVE_FRONT_END
            /* set this up to copy it if we are on a front end
               system */
            count = 0;
            while(job_ptr->node_inx[count] != -1)
                  count++;
#endif
      
            for(j = 0; j < step_info_ptr->job_step_count; j++) {
                  step_ptr = &(step_info_ptr->job_steps[j]);
                  if(step_ptr->job_id == job_ptr->job_id) {
#ifdef HAVE_FRONT_END
                        /* On front end systems the steps are only
                         * given the first node to run off of
                         * so we need to make them appear like
                         * they are running on the entire
                         * space (which they really are).
                         */
                        xfree(step_ptr->nodes);
                        step_ptr->nodes =
                              xstrdup(sview_job_info_ptr->nodes);
                        step_ptr->num_tasks =
                              sview_job_info_ptr->node_cnt;
                        xfree(step_ptr->node_inx);
                        step_ptr->node_inx =
                              xmalloc(sizeof(int) * count);
                        memcpy(step_ptr->node_inx, job_ptr->node_inx, 
                               sizeof(int) * count);
#endif
                        list_push(sview_job_info_ptr->step_list, 
                                step_ptr);
                  }                 
            }
            list_append(odd_info_list, sview_job_info_ptr);
            if((job_ptr->job_state != JOB_PENDING)
               && (job_ptr->job_state != JOB_RUNNING)
               && (job_ptr->job_state != JOB_SUSPENDED)
               && (!(job_ptr->job_state 
                   & JOB_COMPLETING))) {
                  continue;
            }
            list_append(info_list, sview_job_info_ptr);
      }
update_color:
      if(want_odd_states)
            return odd_info_list;
      else
            return info_list;

}

void _display_info_job(List info_list, popup_info_t *popup_win)
{
      job_step_info_t *step_ptr;
      specific_info_t *spec_info = popup_win->spec_info;
      ListIterator itr = NULL;
      sview_job_info_t *sview_job_info = NULL;
      int found = 0;
      GtkTreeView *treeview = NULL;
      int update = 0;
      int i = -1, j = 0;
      int first_time = 0;

      if(spec_info->search_info->int_data == NO_VAL) {
      /*    info = xstrdup("No pointer given!"); */
            goto finished;
      }
      if(!list_count(popup_win->grid_button_list)) 
            first_time = 1;
need_refresh:
      if(!spec_info->display_widget) {
            treeview = create_treeview_2cols_attach_to_table(
                  popup_win->table);
            spec_info->display_widget = 
                  gtk_widget_ref(GTK_WIDGET(treeview));
      } else {
            treeview = GTK_TREE_VIEW(spec_info->display_widget);
            update = 1;
      }
      
      itr = list_iterator_create(info_list);
      while((sview_job_info = (sview_job_info_t*) list_next(itr))) {
            i++;
            if(sview_job_info->job_ptr->job_id ==
               spec_info->search_info->int_data) 
                  break;
      }
      list_iterator_destroy(itr);
      
      if(!sview_job_info) {
            /* not found */
      } else if(spec_info->search_info->int_data2 == NO_VAL) {
            j=0;
            while(sview_job_info->job_ptr->node_inx[j] >= 0) {
                  if(!first_time)
                        change_grid_color(
                              popup_win->grid_button_list,
                              sview_job_info->job_ptr->node_inx[j],
                              sview_job_info->job_ptr->node_inx[j+1],
                              i);
                  else
                        get_button_list_from_main(
                              &popup_win->grid_button_list,
                              sview_job_info->job_ptr->node_inx[j],
                              sview_job_info->job_ptr->node_inx[j+1],
                              i);
                  j += 2;
            }
            _layout_job_record(treeview, sview_job_info, update);
            found = 1;
      } else {
            itr = list_iterator_create(sview_job_info->step_list);
            i=-1;
            while ((step_ptr = list_next(itr))) {
                  i++;
                  if(step_ptr->step_id ==
                     spec_info->search_info->int_data2) {
                        j=0;
                        while(step_ptr->node_inx[j] >= 0) {
                              if(!first_time) 
                                    change_grid_color(
                                          popup_win->
                                          grid_button_list,
                                          step_ptr->node_inx[j],
                                          step_ptr->
                                          node_inx[j+1],
                                          i);
                              else
                                    get_button_list_from_main(
                                          &popup_win->
                                          grid_button_list,
                                          step_ptr->node_inx[j],
                                          step_ptr->
                                          node_inx[j+1],
                                          i);

                              j += 2;
                        }
                        _layout_step_record(treeview, 
                                        step_ptr, update);
                        found = 1;
                        break;
                  }
            }
            list_iterator_destroy(itr);
      }
      
      if(!found) {
            if(!popup_win->not_found) { 
                  char *temp = "JOB ALREADY FINISHED OR NOT FOUND\n";
                  GtkTreeIter iter;
                  GtkTreeModel *model = NULL;
      
                  /* only time this will be run so no update */
                  model = gtk_tree_view_get_model(treeview);
                  add_display_treestore_line(0, 
                                       GTK_TREE_STORE(model), 
                                       &iter,
                                       temp, "");
                  if(spec_info->search_info->int_data2 != NO_VAL) 
                        add_display_treestore_line(
                              1, 
                              GTK_TREE_STORE(model), 
                              &iter,
                              find_col_name(display_data_job,
                                          SORTID_STATE),
                              job_state_string(JOB_COMPLETE));
            }
            popup_win->not_found = true;
      } else {
            if(popup_win->not_found) { 
                  popup_win->not_found = false;
                  gtk_widget_destroy(spec_info->display_widget);
                  
                  goto need_refresh;
            }
            
            put_buttons_in_table(popup_win->grid_table,
                             popup_win->grid_button_list);
      }
      gtk_widget_show_all(spec_info->display_widget);

finished:
      return;
}

extern void refresh_job(GtkAction *action, gpointer user_data)
{
      popup_info_t *popup_win = (popup_info_t *)user_data;
      xassert(popup_win != NULL);
      xassert(popup_win->spec_info != NULL);
      xassert(popup_win->spec_info->title != NULL);
      popup_win->force_refresh = 1;
      specific_info_job(popup_win);
}

extern int get_new_info_job(job_info_msg_t **info_ptr, 
                      int force)
{
      static job_info_msg_t *job_info_ptr = NULL, *new_job_ptr = NULL;
      uint16_t show_flags = 0;
      int error_code = SLURM_NO_CHANGE_IN_DATA;
      time_t now = time(NULL);
      static time_t last;
      static bool changed = 0;
            
      if(!force && ((now - last) < global_sleep_time)) {
            error_code = SLURM_NO_CHANGE_IN_DATA;
            *info_ptr = job_info_ptr;
            if(changed) 
                  return SLURM_SUCCESS;
            return error_code;
      }
      last = now;
      show_flags |= SHOW_ALL;
      if (job_info_ptr) {
            error_code = slurm_load_jobs(job_info_ptr->last_update,
                                   &new_job_ptr, show_flags);
            if (error_code == SLURM_SUCCESS) {
                  slurm_free_job_info_msg(job_info_ptr);
                  changed = 1;
            } else if (slurm_get_errno() == SLURM_NO_CHANGE_IN_DATA) {
                  error_code = SLURM_NO_CHANGE_IN_DATA;
                  new_job_ptr = job_info_ptr;
                  changed = 0;
            }
      } else {
            error_code = slurm_load_jobs((time_t) NULL, &new_job_ptr, 
                                   show_flags);
            changed = 1;
      }
      job_info_ptr = new_job_ptr;
      *info_ptr = new_job_ptr;
      return error_code;
}

extern int get_new_info_job_step(job_step_info_response_msg_t **info_ptr, 
                         int force)
{
      static job_step_info_response_msg_t *old_step_ptr = NULL;
      static job_step_info_response_msg_t *new_step_ptr = NULL;
      uint16_t show_flags = 0;
      int error_code = SLURM_NO_CHANGE_IN_DATA;
      time_t now = time(NULL);
      static time_t last;
            
      if(!force && ((now - last) < global_sleep_time)) {
            error_code = SLURM_NO_CHANGE_IN_DATA;
            *info_ptr = old_step_ptr;
            return error_code;
      }
      last = now;
      show_flags |= SHOW_ALL;
      if (old_step_ptr) {
            error_code = slurm_get_job_steps(old_step_ptr->last_update, 
                                     0, 0, &new_step_ptr, 
                                     show_flags);
            if (error_code ==  SLURM_SUCCESS)
                  slurm_free_job_step_info_response_msg(old_step_ptr);
            else if (slurm_get_errno () == SLURM_NO_CHANGE_IN_DATA) {
                  error_code = SLURM_NO_CHANGE_IN_DATA;
                  new_step_ptr = old_step_ptr;
            }
      } else
            error_code = slurm_get_job_steps((time_t) NULL, 0, 0, 
                                     &new_step_ptr, show_flags);
      old_step_ptr = new_step_ptr;
      *info_ptr = new_step_ptr;
      return error_code;
}

extern GtkListStore *create_model_job(int type)
{
      GtkListStore *model = NULL;
      GtkTreeIter iter;
      
      switch(type) {
      case SORTID_ACTION:
            model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           1, SORTID_ACTION,
                           0, "None",
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           1, SORTID_ACTION,
                           0, "Cancel",
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           1, SORTID_ACTION,
                           0, "Suspend/Resume",
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           1, SORTID_ACTION,
                           0, "Checkpoint",
                           -1);                 
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           1, SORTID_ACTION,
                           0, "requeue",
                           -1);                 
            break;
      case SORTID_SHARED:
            model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "yes",
                           1, SORTID_SHARED,
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "no",
                           1, SORTID_SHARED,
                           -1);     
            break;
      case SORTID_CONTIGUOUS:
            model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "yes",
                           1, SORTID_CONTIGUOUS,
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "no",
                           1, SORTID_CONTIGUOUS,
                           -1);     
            break;
#ifdef HAVE_BG
      case SORTID_ROTATE:
            model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "yes",
                           1, SORTID_ROTATE,
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "no",
                           1, SORTID_ROTATE,
                           -1);     
            break;
      case SORTID_CONNECTION:
            model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "torus",
                           1, SORTID_CONNECTION,
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "mesh",
                           1, SORTID_CONNECTION,
                           -1);     
            gtk_list_store_append(model, &iter);
            gtk_list_store_set(model, &iter,
                           0, "nav",
                           1, SORTID_CONNECTION,
                           -1);     
            break;
#endif
      default:
            break;
      }

      return model;
}

extern void admin_edit_job(GtkCellRendererText *cell,
                     const char *path_string,
                     const char *new_text,
                     gpointer data)
{
      GtkTreeStore *treestore = GTK_TREE_STORE(data);
      GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
      GtkTreeIter iter;
      job_desc_msg_t *job_msg = xmalloc(sizeof(job_desc_msg_t));
      
      char *temp = NULL;
      char *old_text = NULL;
      const char *type = NULL;
      int stepid = NO_VAL;
      int column = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), 
                                           "column"));

      if(!new_text || !strcmp(new_text, ""))
            goto no_input;
      
      gtk_tree_model_get_iter(GTK_TREE_MODEL(treestore), &iter, path);

      slurm_init_job_desc_msg(job_msg);   
      gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, 
                     SORTID_JOBID, &job_msg->job_id, 
                     column, &old_text,
                     -1);
      gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, 
                     SORTID_ALLOC, &stepid, -1);
      if(stepid)
            stepid = NO_VAL;
      else {
            stepid = job_msg->job_id;
            gtk_tree_model_get(GTK_TREE_MODEL(treestore), &iter, 
                           SORTID_POS, &job_msg->job_id, -1);
      }
      
      type = _set_job_msg(job_msg, new_text, column);
      if(errno)
            goto print_error;
      
      if(got_edit_signal) {
            temp = got_edit_signal;
            got_edit_signal = NULL;
            admin_job(GTK_TREE_MODEL(treestore), &iter, temp);
            xfree(temp);
            goto no_input;
      }
                  

      if(old_text && !strcmp(old_text, new_text)) {
            temp = g_strdup_printf("No change in value.");
            display_edit_note(temp);
            g_free(temp);     
      } else if(slurm_update_job(job_msg) == SLURM_SUCCESS) {
            gtk_tree_store_set(treestore, &iter, column, new_text, -1);
            temp = g_strdup_printf("Job %d %s changed to %s",
                               job_msg->job_id,
                               type,
                               new_text);
            display_edit_note(temp);
            g_free(temp);
      } else {
      print_error:
            temp = g_strdup_printf("Job %d %s can't be "
                               "set to %s",
                               job_msg->job_id,
                               type,
                               new_text);
            display_edit_note(temp);
            g_free(temp);
      }

no_input:
      slurm_free_job_desc_msg(job_msg);
                    
      gtk_tree_path_free (path);
      g_free(old_text);
      g_static_mutex_unlock(&sview_mutex);
}

extern void get_info_job(GtkTable *table, display_data_t *display_data)
{
      int job_error_code = SLURM_SUCCESS;
      int step_error_code = SLURM_SUCCESS;
      static int view = -1;
      static job_info_msg_t *job_info_ptr = NULL;
      static job_step_info_response_msg_t *step_info_ptr = NULL;
      char error_char[100];
      GtkWidget *label = NULL;
      GtkTreeView *tree_view = NULL;
      static GtkWidget *display_widget = NULL;
      List info_list = NULL;
      int changed = 1;
      int i = 0, j = 0;
      sview_job_info_t *sview_job_info_ptr = NULL;
      job_info_t *job_ptr = NULL;
      ListIterator itr = NULL;
            
      if(display_data)
            local_display_data = display_data;
      if(!table) {
            display_data_job->set_menu = local_display_data->set_menu;
            return;
      }
      if(display_widget && toggled) {
            gtk_widget_destroy(display_widget);
            display_widget = NULL;
            goto display_it;
      }

      if((job_error_code = get_new_info_job(&job_info_ptr, force_refresh))
         == SLURM_NO_CHANGE_IN_DATA){
            
      } else if (job_error_code != SLURM_SUCCESS) {
            if(view == ERROR_VIEW)
                  goto end_it;
            if(display_widget)
                  gtk_widget_destroy(display_widget);
            view = ERROR_VIEW;
            sprintf(error_char, "slurm_load_job: %s",
                  slurm_strerror(slurm_get_errno()));
            label = gtk_label_new(error_char);
            gtk_table_attach_defaults(table, label, 0, 1, 0, 1); 
            gtk_widget_show(label); 
            display_widget = gtk_widget_ref(GTK_WIDGET(label));
            goto end_it;
      }

      if((step_error_code = get_new_info_job_step(&step_info_ptr, 
                                        force_refresh))
         == SLURM_NO_CHANGE_IN_DATA){
            if((!display_widget || view == ERROR_VIEW)
               || (job_error_code != SLURM_NO_CHANGE_IN_DATA))
                  goto display_it;
            changed = 0;
      } else if (step_error_code != SLURM_SUCCESS) {
            if(view == ERROR_VIEW)
                  goto end_it;
            if(display_widget)
                  gtk_widget_destroy(display_widget);
            view = ERROR_VIEW;
            sprintf(error_char, "slurm_load_job_step: %s",
                  slurm_strerror(slurm_get_errno()));
            label = gtk_label_new(error_char);
            gtk_table_attach_defaults(table, label, 0, 1, 0, 1); 
            gtk_widget_show(label); 
            display_widget = gtk_widget_ref(GTK_WIDGET(label));
            goto end_it;
      }
display_it:
      
      info_list = _create_job_info_list(job_info_ptr, step_info_ptr,
                                changed, 0);
      if(!info_list)
            return;
      i=0;
      /* set up the grid */
      itr = list_iterator_create(info_list);
      while ((sview_job_info_ptr = list_next(itr))) {
            job_ptr = sview_job_info_ptr->job_ptr;
            j=0;
            while(job_ptr->node_inx[j] >= 0) {
                  sview_job_info_ptr->color =
                        change_grid_color(grid_button_list,
                                      job_ptr->node_inx[j],
                                      job_ptr->node_inx[j+1],
                                      i);
                  j += 2;
            }
            i++;
      }
      list_iterator_destroy(itr);

      if(view == ERROR_VIEW && display_widget) {
            gtk_widget_destroy(display_widget);
            display_widget = NULL;
      }
      if(!display_widget) {
            tree_view = create_treeview(local_display_data);
                        
            display_widget = gtk_widget_ref(GTK_WIDGET(tree_view));
            gtk_table_attach_defaults(GTK_TABLE(table), 
                                GTK_WIDGET(tree_view),
                                0, 1, 0, 1); 
            /* since this function sets the model of the tree_view 
               to the treestore we don't really care about 
               the return value */
            create_treestore(tree_view, display_data_job, SORTID_CNT);
      }

      view = INFO_VIEW;
      _update_info_job(info_list, GTK_TREE_VIEW(display_widget));
end_it:
      toggled = FALSE;
      force_refresh = FALSE;
      
      return;
}

extern void specific_info_job(popup_info_t *popup_win)
{
      int job_error_code = SLURM_SUCCESS;
      int step_error_code = SLURM_SUCCESS;
      static job_info_msg_t *job_info_ptr = NULL;
      static job_step_info_response_msg_t *step_info_ptr = NULL;
      specific_info_t *spec_info = popup_win->spec_info;
      sview_search_info_t *search_info = spec_info->search_info;
      char error_char[100];
      GtkWidget *label = NULL;
      GtkTreeView *tree_view = NULL;
      List info_list = NULL;
      List send_info_list = NULL;
      int changed = 1;
      int j=0, i=-1;
      sview_job_info_t *sview_job_info_ptr = NULL;
      job_info_t *job_ptr = NULL;   
      ListIterator itr = NULL;
      char name[30];
      char *host = NULL, *host2 = NULL;
      hostlist_t hostlist = NULL;
      int found = 0;
      
      if(!spec_info->display_widget)
            setup_popup_info(popup_win, display_data_job, SORTID_CNT);

      if(spec_info->display_widget && popup_win->toggled) {
            gtk_widget_destroy(spec_info->display_widget);
            spec_info->display_widget = NULL;
            goto display_it;
      }

      if((job_error_code =
          get_new_info_job(&job_info_ptr, popup_win->force_refresh))
         == SLURM_NO_CHANGE_IN_DATA) {
            
      } else if (job_error_code != SLURM_SUCCESS) {
            if(spec_info->view == ERROR_VIEW)
                  goto end_it;
            spec_info->view = ERROR_VIEW;
            if(spec_info->display_widget)
                  gtk_widget_destroy(spec_info->display_widget);
            
            sprintf(error_char, "slurm_load_job: %s",
                  slurm_strerror(slurm_get_errno()));
            label = gtk_label_new(error_char);
            gtk_table_attach_defaults(GTK_TABLE(popup_win->table), 
                                label,
                                0, 1, 0, 1); 
            gtk_widget_show(label); 
            spec_info->display_widget = gtk_widget_ref(GTK_WIDGET(label));
            goto end_it;
      }

      if((step_error_code = 
          get_new_info_job_step(&step_info_ptr, popup_win->force_refresh))
         == SLURM_NO_CHANGE_IN_DATA) {
            if((!spec_info->display_widget 
                || spec_info->view == ERROR_VIEW)
               || (job_error_code != SLURM_NO_CHANGE_IN_DATA)) 
                  goto display_it;
            changed = 0;
      } else if (step_error_code != SLURM_SUCCESS) {
            if(spec_info->view == ERROR_VIEW)
                  goto end_it;
            if(spec_info->display_widget)
                  gtk_widget_destroy(spec_info->display_widget);
            spec_info->view = ERROR_VIEW;
            sprintf(error_char, "slurm_load_job_step: %s",
                  slurm_strerror(slurm_get_errno()));
            label = gtk_label_new(error_char);
            gtk_table_attach_defaults(popup_win->table, label, 
                                0, 1, 0, 1); 
            gtk_widget_show(label); 
            spec_info->display_widget = gtk_widget_ref(GTK_WIDGET(label));
            goto end_it;
      }
display_it:
      info_list = _create_job_info_list(job_info_ptr, step_info_ptr,
                                changed, 1);
      if(!info_list)
            return;
            
      if(spec_info->view == ERROR_VIEW && spec_info->display_widget) {
            gtk_widget_destroy(spec_info->display_widget);
            spec_info->display_widget = NULL;
      }
      
      if(spec_info->type != INFO_PAGE && !spec_info->display_widget) {
            tree_view = create_treeview(local_display_data);
                        
            spec_info->display_widget = 
                  gtk_widget_ref(GTK_WIDGET(tree_view));
            gtk_table_attach_defaults(popup_win->table, 
                                GTK_WIDGET(tree_view),
                                0, 1, 0, 1); 
            /* since this function sets the model of the tree_view 
               to the treestore we don't really care about 
               the return value */
            create_treestore(tree_view, popup_win->display_data, 
                         SORTID_CNT);
      }

      if(popup_win->grid_button_list) {
            list_destroy(popup_win->grid_button_list);
      }            
      
#ifdef HAVE_BG
      popup_win->grid_button_list = copy_main_button_list();
#else
      popup_win->grid_button_list = list_create(destroy_grid_button);
#endif      

      spec_info->view = INFO_VIEW;
      if(spec_info->type == INFO_PAGE) {
            _display_info_job(info_list, popup_win);
            goto end_it;
      }

      
      /* just linking to another list, don't free the inside, just
         the list */
      send_info_list = list_create(NULL); 
      itr = list_iterator_create(info_list);
      i = -1;
      while ((sview_job_info_ptr = list_next(itr))) {
            i++;
            job_ptr = sview_job_info_ptr->job_ptr;
            switch(spec_info->type) {
            case JOB_PAGE:
                  switch(search_info->search_type) {
                  case SEARCH_JOB_ID:
                        if(search_info->int_data
                           == NO_VAL) {
                              if(!search_info->gchar_data)
                                    continue;
                              _convert_char_to_job_and_step(
                                    search_info->gchar_data,
                                    &search_info->int_data,
                                    &search_info->int_data2);
                        }
                        if(job_ptr->job_id != search_info->int_data) {
                              continue;
                        }
                        /* if we ever want to display just the step
                           this is where we would do it */
/*                      if(spec_info->search_info->int_data2 */
/*                         == NO_VAL) */
/*                      break; */
/*                step_itr = list_iterator_create( */
/*                      sview_job_info->step_list); */
/*                while ((step_ptr = list_next(itr))) { */
/*                      if(step_ptr->step_id  */
/*                         == spec_info->search_info->int_data2) { */
/*                            break; */
/*                      } */
/*                } */
                        break;
                  case SEARCH_JOB_USER:
                        if(!search_info->gchar_data)
                              continue;
                        if(strcmp(uid_to_string(job_ptr->user_id),
                                search_info->gchar_data))
                              continue;
                        break;
                  case SEARCH_JOB_STATE:
                        if(search_info->int_data == NO_VAL)
                              continue;

                        if(job_ptr->job_state != search_info->int_data)
                              continue;
                        break;
                  default:
                        break;
                  }
                  break;      
            case PART_PAGE:
                  if(strcmp(search_info->gchar_data,
                          job_ptr->partition))
                        continue;
                  break;
            case BLOCK_PAGE:
                  select_g_sprint_jobinfo(
                        job_ptr->select_jobinfo, 
                        name, 
                        sizeof(name), 
                        SELECT_PRINT_BG_ID);
                  if(strcmp(search_info->gchar_data, name))
                        continue;
                  break;
            case NODE_PAGE:
                  if(!job_ptr->nodes)
                        continue;
                  
                  hostlist = hostlist_create(search_info->gchar_data);
                  host = hostlist_shift(hostlist);
                  hostlist_destroy(hostlist);
                  if(!host)
                        continue;
                  
                  hostlist = hostlist_create(job_ptr->nodes);
                  found = 0;
                  while((host2 = hostlist_shift(hostlist))) { 
                        if(!strcmp(host, host2)) {
                              free(host2);
                              found = 1;
                              break; 
                        }
                        free(host2);
                  }
                  hostlist_destroy(hostlist);
                  if(!found)
                        continue;
                  break;
            default:
                  continue;
            }
            
            list_push(send_info_list, sview_job_info_ptr);
            j=0;
            while(job_ptr->node_inx[j] >= 0) {
#ifdef HAVE_BG
                  change_grid_color(
                        popup_win->grid_button_list,
                        job_ptr->node_inx[j],
                        job_ptr->node_inx[j+1], i);
#else
                  get_button_list_from_main(
                        &popup_win->grid_button_list,
                        job_ptr->node_inx[j],
                        job_ptr->node_inx[j+1], i);
#endif
                  j += 2;
            }
      }
      list_iterator_destroy(itr);

      put_buttons_in_table(popup_win->grid_table,
                       popup_win->grid_button_list);

      _update_info_job(send_info_list,
                   GTK_TREE_VIEW(spec_info->display_widget));
                  
      list_destroy(send_info_list);
end_it:
      popup_win->toggled = 0;
      popup_win->force_refresh = 0;
      return;
}

extern void set_menus_job(void *arg, GtkTreePath *path, 
                    GtkMenu *menu, int type)
{
      GtkTreeView *tree_view = (GtkTreeView *)arg;
      popup_info_t *popup_win = (popup_info_t *)arg;
      switch(type) {
      case TAB_CLICKED:
            make_fields_menu(menu, display_data_job, SORTID_CNT);
            break;
      case ROW_CLICKED:
            make_options_menu(tree_view, path, menu, options_data_job);
            break;
      case POPUP_CLICKED:
            make_popup_fields_menu(popup_win, menu);
            break;
      default:
            g_error("UNKNOWN type %d given to set_fields\n", type);
      }
}

extern void popup_all_job(GtkTreeModel *model, GtkTreeIter *iter, int id)
{
      char *name = NULL;
      char title[100];
      ListIterator itr = NULL;
      popup_info_t *popup_win = NULL;
      int jobid = NO_VAL;
      int stepid = NO_VAL;
      GError *error = NULL;

      gtk_tree_model_get(model, iter, SORTID_JOBID, &jobid, -1);
      gtk_tree_model_get(model, iter, SORTID_ALLOC, &stepid, -1);
      if(stepid)
            stepid = NO_VAL;
      else {
            stepid = jobid;
            gtk_tree_model_get(model, iter, SORTID_POS, &jobid, -1);
      }

      switch(id) {
      case PART_PAGE:
            if(stepid == NO_VAL)
                  snprintf(title, 100, "Partition with job %d", jobid);
            else
                  snprintf(title, 100, "Partition with job %d.%d",
                         jobid, stepid);              
            break;
      case NODE_PAGE:
            if(stepid == NO_VAL) {
#ifdef HAVE_BG
                  snprintf(title, 100, 
                         "Base partition(s) running job %d", jobid);
#else
                  snprintf(title, 100, "Node(s) running job %d", jobid);
#endif
            } else {
#ifdef HAVE_BG
                  snprintf(title, 100, 
                         "Base partition(s) running job %d.%d",
                         jobid, stepid);
#else
                  snprintf(title, 100, "Node(s) running job %d.%d",
                         jobid, stepid);
#endif
            }
            break;
      case BLOCK_PAGE: 
            if(stepid == NO_VAL)
                  snprintf(title, 100, "Block with job %d", jobid);
            else
                  snprintf(title, 100, "Block with job %d.%d",
                         jobid, stepid);
            break;
      case SUBMIT_PAGE: 
            if(stepid == NO_VAL)
                  snprintf(title, 100, "Submit job on job %d", jobid);
            else
                  snprintf(title, 100, "Submit job on job %d.%d",
                         jobid, stepid);
                  
            break;
      case INFO_PAGE: 
            if(stepid == NO_VAL)
                  snprintf(title, 100, "Full info for job %d", jobid);
            else
                  snprintf(title, 100, "Full info for job %d.%d",
                         jobid, stepid);              
            break;
      default:
            g_print("jobs got id %d\n", id);
      }
      
      itr = list_iterator_create(popup_list);
      while((popup_win = list_next(itr))) {
            if(popup_win->spec_info)
                  if(!strcmp(popup_win->spec_info->title, title)) {
                        break;
                  } 
      }
      list_iterator_destroy(itr);
      
      if(!popup_win) {
            if(id == INFO_PAGE)
                  popup_win = create_popup_info(id, JOB_PAGE, title);
            else
                  popup_win = create_popup_info(JOB_PAGE, id, title);
      } else {
            gtk_window_present(GTK_WINDOW(popup_win->popup));
            return;
      }
      
      switch(id) {
      case NODE_PAGE:
            gtk_tree_model_get(model, iter, SORTID_NODELIST, &name, -1);
            popup_win->spec_info->search_info->gchar_data = name;
            break;
      case PART_PAGE:
            gtk_tree_model_get(model, iter, SORTID_PARTITION, &name, -1);
            popup_win->spec_info->search_info->gchar_data = name;
            break;
#ifdef HAVE_BG
      case BLOCK_PAGE: 
            gtk_tree_model_get(model, iter, SORTID_BLOCK, &name, -1);
            popup_win->spec_info->search_info->gchar_data = name;
            break;
#endif
      case SUBMIT_PAGE: 
            break;
      case INFO_PAGE:
            popup_win->spec_info->search_info->int_data = jobid;
            popup_win->spec_info->search_info->int_data2 = stepid;
            break;
      
      default:
            g_print("jobs got %d\n", id);
      }
      if (!g_thread_create((gpointer)popup_thr, popup_win, FALSE, &error))
      {
            g_printerr ("Failed to create part popup thread: %s\n", 
                      error->message);
            return;
      }
}

extern void admin_job(GtkTreeModel *model, GtkTreeIter *iter, char *type)
{
      int jobid = NO_VAL;
      int stepid = NO_VAL;
      int state = 0;
      int response = 0; 
      char tmp_char[255];
      char *tmp_char_ptr = NULL;
      int edit_type = 0;
      uint16_t signal = SIGKILL;
      job_desc_msg_t *job_msg = xmalloc(sizeof(job_desc_msg_t));

      GtkWidget *label = NULL;
      GtkWidget *entry = NULL;
      GtkWidget *popup = gtk_dialog_new_with_buttons(
            type,
            GTK_WINDOW(main_window),
            GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
            NULL);
      gtk_window_set_transient_for(GTK_WINDOW(popup), NULL);
      
      gtk_tree_model_get(model, iter, SORTID_JOBID, &jobid, -1);
      gtk_tree_model_get(model, iter, SORTID_ALLOC, &stepid, -1);
      if(stepid)
            stepid = NO_VAL;
      else {
            stepid = jobid;
            gtk_tree_model_get(model, iter, SORTID_POS, &jobid, -1);
      }
      slurm_init_job_desc_msg(job_msg);
            
      
      if(!strcasecmp("Signal", type)) {
            label = gtk_dialog_add_button(GTK_DIALOG(popup),
                                    GTK_STOCK_OK, GTK_RESPONSE_OK);
            gtk_window_set_default(GTK_WINDOW(popup), label);
            gtk_dialog_add_button(GTK_DIALOG(popup),
                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);

            entry = create_entry();
            label = gtk_label_new("Signal?");
            edit_type = EDIT_SIGNAL;
      } else if(!strcasecmp("Cancel", type)) {
            label = gtk_dialog_add_button(GTK_DIALOG(popup),
                                    GTK_STOCK_YES, GTK_RESPONSE_OK);
            gtk_window_set_default(GTK_WINDOW(popup), label);
            gtk_dialog_add_button(GTK_DIALOG(popup),
                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
            
            if(stepid != NO_VAL)
                  snprintf(tmp_char, sizeof(tmp_char), 
                         "Are you sure you want to cancel job %u.%u?",
                         jobid, stepid);
            else
                  snprintf(tmp_char, sizeof(tmp_char), 
                         "Are you sure you want to cancel job %u?",
                         jobid);
            label = gtk_label_new(tmp_char);
            edit_type = EDIT_CANCEL;
      } else if(!strcasecmp("Suspend/Resume", type)) {
            label = gtk_dialog_add_button(GTK_DIALOG(popup),
                                    GTK_STOCK_YES, GTK_RESPONSE_OK);
            gtk_window_set_default(GTK_WINDOW(popup), label);
            gtk_dialog_add_button(GTK_DIALOG(popup),
                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);

            gtk_tree_model_get(model, iter, SORTID_STATE_NUM, &state, -1);
            if(state == JOB_SUSPENDED)
                  tmp_char_ptr = "resume";
            else
                  tmp_char_ptr = "suspend";

            if(stepid != NO_VAL)
                  snprintf(tmp_char, sizeof(tmp_char), 
                         "Are you sure you want to %s job %u.%u?",
                         tmp_char_ptr, jobid, stepid);
            else
                  snprintf(tmp_char, sizeof(tmp_char), 
                         "Are you sure you want to %s job %u?",
                         tmp_char_ptr, jobid);
            label = gtk_label_new(tmp_char);
            edit_type = EDIT_SUSPEND;
      } else {
            label = gtk_dialog_add_button(GTK_DIALOG(popup),
                                    GTK_STOCK_OK, GTK_RESPONSE_OK);
            gtk_window_set_default(GTK_WINDOW(popup), label);
            gtk_dialog_add_button(GTK_DIALOG(popup),
                              GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);

            gtk_window_set_default_size(GTK_WINDOW(popup), 200, 400);
            snprintf(tmp_char, sizeof(tmp_char), 
                   "Editing job %u think before you type",
                   jobid);
            label = gtk_label_new(tmp_char);
            edit_type = EDIT_EDIT;
            job_msg->job_id = jobid;
            entry = _admin_full_edit_job(job_msg, model, iter);
      }

      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), 
                     label, FALSE, FALSE, 0);
      if(entry)
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), 
                           entry, TRUE, TRUE, 0);
      gtk_widget_show_all(popup);
      response = gtk_dialog_run (GTK_DIALOG(popup));
      if (response == GTK_RESPONSE_OK) {
            switch(edit_type) {
            case EDIT_SIGNAL:
                  signal = _xlate_signal_name(
                        gtk_entry_get_text(GTK_ENTRY(entry)));
                  if(signal == (uint16_t)NO_VAL) {
                        tmp_char_ptr = g_strdup_printf(
                              "%s is not a valid signal.",
                              gtk_entry_get_text(GTK_ENTRY(entry)));
                        display_edit_note(tmp_char_ptr);
                        g_free(tmp_char_ptr);
                        break;
                  }
                  
                  /* fall through to the cancel now the signal
                   * is set (Default is SIGKILL from above for
                   * just a regular cancel).
                   */
            case EDIT_CANCEL:
                  if(stepid == NO_VAL)
                        _cancel_job_id(jobid, signal);
                  else 
                        _cancel_step_id(jobid, stepid, signal);
                  
                  break;
            case EDIT_SUSPEND:
                  if(state == JOB_SUSPENDED)
                        response = slurm_resume(jobid);
                  else
                        response = slurm_suspend(jobid);
                  if(response) {
                        tmp_char_ptr = g_strdup_printf(
                              "Error happened trying to %s job %u.",
                              tmp_char_ptr, jobid);
                        display_edit_note(tmp_char_ptr);
                        g_free(tmp_char_ptr);
                        
                  } else {
                        if(state == JOB_SUSPENDED)
                              tmp_char_ptr = "resumed";
                        else
                              tmp_char_ptr = "suspended";
                        tmp_char_ptr = g_strdup_printf(
                              "Job %s %u successfully.",
                              tmp_char_ptr, jobid);
                        display_edit_note(tmp_char_ptr);
                        g_free(tmp_char_ptr);
                  } 
                  break;
            case EDIT_EDIT:
                  if(got_edit_signal) 
                        goto end_it;
                  if(slurm_update_job(job_msg) == SLURM_SUCCESS) {
                        tmp_char_ptr = g_strdup_printf(
                              "Job %u updated successfully",
                              jobid);
                  } else {
                        tmp_char_ptr = g_strdup_printf(
                              "Problem updating job %u.",
                               jobid);
                  }
                  display_edit_note(tmp_char_ptr);
                  g_free(tmp_char_ptr);
                  break;
            default:
                  break;
            }
      }
end_it:
      slurm_free_job_desc_msg(job_msg);
      gtk_widget_destroy(popup);
      if(got_edit_signal) {
            type = got_edit_signal;
            got_edit_signal = NULL;
            admin_job(model, iter, type);
            xfree(type);
      }                 
      return;
}


Generated by  Doxygen 1.6.0   Back to index