| /*****************************************************************************\ | 
 |  *  job_info.c - Functions related to job display mode of sview. | 
 |  ***************************************************************************** | 
 |  *  Copyright (C) SchedMD LLC. | 
 |  *  Copyright (C) 2008-2011 Lawrence Livermore National Security. | 
 |  *  Copyright (C) 2004-2007 The Regents of the University of California. | 
 |  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER). | 
 |  *  Written by Danny Auble <da@llnl.gov> | 
 |  * | 
 |  *  CODE-OCEC-09-009. All rights reserved. | 
 |  * | 
 |  *  This file is part of Slurm, a resource management program. | 
 |  *  For details, see <https://slurm.schedmd.com/>. | 
 |  *  Please also read the included file: DISCLAIMER. | 
 |  * | 
 |  *  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., | 
 |  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA. | 
 | \*****************************************************************************/ | 
 |  | 
 | #include <fcntl.h> | 
 | #include <grp.h> | 
 | #include <limits.h> | 
 | #include <sys/stat.h> | 
 | #include <sys/types.h> | 
 |  | 
 | #include "src/common/parse_time.h" | 
 | #include "src/common/proc_args.h" | 
 | #include "src/interfaces/select.h" | 
 | #include "src/common/uid.h" | 
 | #include "src/common/xstring.h" | 
 |  | 
 | #include "src/sview/sview.h" | 
 |  | 
 | #define _DEBUG 0 | 
 | #define MAX_CANCEL_RETRY 10 | 
 | #define SIZE(a) (sizeof(a)/sizeof(a[0])) | 
 |  | 
 | /* We do not read the node table here, but allocated space for up to | 
 |  * MAX_NODE_SPACE nodes and generate fatal error if we go higher. Increase | 
 |  * this value if needed */ | 
 | #ifndef SVIEW_MAX_NODE_SPACE | 
 | #define SVIEW_MAX_NODE_SPACE (24 * 1024) | 
 | #endif | 
 |  | 
 | /* Collection of data for printing reports. Like data is combined here */ | 
 | typedef struct { | 
 | 	int color_inx; | 
 | 	GtkTreeIter iter_ptr; | 
 | 	bool iter_set; | 
 | 	uint32_t job_id; | 
 | 	char *job_id_str; | 
 | 	job_info_t *job_ptr; | 
 | 	int node_cnt; | 
 | 	char *nodes; | 
 | 	int pos; | 
 | 	list_t *step_list; | 
 | 	hostlist_t *task_hl; | 
 | 	char *task_hl_str; | 
 | 	hostlist_t *task_pending_hl; | 
 | 	char *task_pending_hl_str; | 
 | 	list_t *task_list; | 
 | 	list_t *task_pending_list; | 
 | } sview_job_info_t; | 
 |  | 
 | static list_t *foreach_list = NULL; | 
 | static char *stacked_job_list = NULL; | 
 |  | 
 | typedef struct { | 
 | 	int state; | 
 | 	slurm_step_id_t step_id; | 
 | 	int array_job_id; | 
 | 	int array_task_id; | 
 | 	int het_job_id; | 
 | 	int het_job_offset; | 
 | } jobs_foreach_t; | 
 |  | 
 | typedef struct { | 
 | 	int edit_type; | 
 | 	GtkWidget *entry; | 
 | 	job_desc_msg_t *job_msg; | 
 | 	char *type; | 
 | } jobs_foreach_common_t; | 
 |  | 
 | enum { | 
 | 	EDIT_SIGNAL = 1, | 
 | 	EDIT_SIGNAL_USER, | 
 | 	EDIT_CANCEL, | 
 | 	EDIT_CANCEL_USER, | 
 | 	EDIT_REQUEUE, | 
 | 	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_ARRAY_JOB_ID, | 
 | 	SORTID_ARRAY_TASK_ID, | 
 | 	SORTID_BATCH, | 
 | 	SORTID_BATCH_HOST, | 
 | 	SORTID_BURST_BUFFER, | 
 | 	SORTID_CLUSTER_NAME, | 
 | 	SORTID_COLOR, | 
 | 	SORTID_COLOR_INX, | 
 | 	SORTID_COMMAND, | 
 | 	SORTID_COMMENT, | 
 | 	SORTID_CONTIGUOUS, | 
 | 	SORTID_CORE_SPEC, | 
 | /* 	SORTID_CORES_MAX, */ | 
 | /* 	SORTID_CORES_MIN, */ | 
 | 	SORTID_CPUS, | 
 | 	SORTID_CPUS_PER_TRES, | 
 | 	SORTID_CPU_MAX, | 
 | 	SORTID_CPU_MIN, | 
 | 	SORTID_CPUS_PER_TASK, | 
 | 	SORTID_DEADLINE, | 
 | 	SORTID_DEPENDENCY, | 
 | 	SORTID_DERIVED_EC, | 
 | 	SORTID_EXIT_CODE, | 
 | 	SORTID_EXTRA, | 
 | 	SORTID_FEATURES, | 
 | 	SORTID_FED_ACTIVE_SIBS, | 
 | 	SORTID_FED_ORIGIN, | 
 | 	SORTID_FED_VIABLE_SIBS, | 
 | 	SORTID_GRES, | 
 | 	SORTID_GROUP_ID, | 
 | 	SORTID_HET_JOB_ID, | 
 | 	SORTID_HET_JOB_ID_SET, | 
 | 	SORTID_HET_JOB_OFFSET, | 
 | 	SORTID_JOBID, | 
 | 	SORTID_JOBID_FORMATTED, | 
 | 	SORTID_LAST_SCHED_EVAL, | 
 | 	SORTID_LICENSES, | 
 | 	SORTID_MCS_LABEL, | 
 | 	SORTID_CPU_REQ, | 
 | 	SORTID_MEM_MIN, | 
 | 	SORTID_MEM_PER_TRES, | 
 | 	SORTID_TMP_DISK, | 
 | 	SORTID_NAME, | 
 | 	SORTID_NETWORK, | 
 | 	SORTID_NICE, | 
 | 	SORTID_NODELIST, | 
 | 	SORTID_NODELIST_EXC, | 
 | 	SORTID_NODELIST_REQ, | 
 | 	SORTID_NODELIST_SCHED, | 
 | 	SORTID_NODE_INX, | 
 | 	SORTID_NODES, | 
 | 	SORTID_NODES_MAX, | 
 | 	SORTID_NODES_MIN, | 
 | /* 	SORTID_NTASKS_PER_CORE, */ | 
 | /* 	SORTID_NTASKS_PER_NODE, */ | 
 | /* 	SORTID_NTASKS_PER_SOCKET, */ | 
 | 	SORTID_OVER_SUBSCRIBE, | 
 | 	SORTID_PARTITION, | 
 | 	SORTID_PREEMPT_TIME, | 
 | 	SORTID_PREFER, | 
 | 	SORTID_PRIORITY, | 
 | 	SORTID_QOS, | 
 | 	SORTID_REASON, | 
 | 	SORTID_REBOOT, | 
 | 	SORTID_REQUEUE, | 
 | 	SORTID_RESV_NAME, | 
 | 	SORTID_RESTARTS, | 
 | /* 	SORTID_SOCKETS_MAX, */ | 
 | /* 	SORTID_SOCKETS_MIN, */ | 
 | 	SORTID_STATE, | 
 | 	SORTID_STATE_NUM, | 
 | 	SORTID_STD_ERR, | 
 | 	SORTID_STD_IN, | 
 | 	SORTID_STD_OUT, | 
 | 	SORTID_SWITCHES, | 
 | 	SORTID_TASKS, | 
 | 	SORTID_THREAD_SPEC, | 
 | /* 	SORTID_THREADS_MAX, */ | 
 | /* 	SORTID_THREADS_MIN, */ | 
 | 	SORTID_TIME_ACCRUE, | 
 | 	SORTID_TIME_ELIGIBLE, | 
 | 	SORTID_TIME_END, | 
 | 	SORTID_TIMELIMIT, | 
 | 	SORTID_TIME_RESIZE, | 
 | 	SORTID_TIME_RUNNING, | 
 | 	SORTID_TIME_START, | 
 | 	SORTID_TIME_SUBMIT, | 
 | 	SORTID_TIME_SUSPEND, | 
 | 	SORTID_TRES_ALLOC, | 
 | 	SORTID_TRES_BIND, | 
 | 	SORTID_TRES_FREQ, | 
 | 	SORTID_TRES_PER_JOB, | 
 | 	SORTID_TRES_PER_NODE, | 
 | 	SORTID_TRES_PER_SOCKET, | 
 | 	SORTID_TRES_PER_TASK, | 
 | 	SORTID_UPDATED, | 
 | 	SORTID_USER_ID, | 
 | 	SORTID_WCKEY, | 
 | 	SORTID_WORKDIR, | 
 | 	SORTID_CNT | 
 | }; | 
 |  | 
 | /* extra field here is for choosing the type of edit that will | 
 |  * take place.  If you choose EDIT_MODEL (means only display a set of | 
 |  * known options) create it in function create_model_*. | 
 |  */ | 
 | static char *_initial_page_opts = ("JobID,Partition,UserID,Name," | 
 | 				   "State,Time_Running,Node_Count,NodeList"); | 
 |  | 
 | 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_STRING, SORTID_JOBID, "JobID", false, EDIT_NONE, refresh_job, | 
 | 	 create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_JOBID_FORMATTED, NULL, false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_COLOR, NULL, true, EDIT_COLOR, | 
 | 	 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_ARRAY_JOB_ID, "Array_Job_ID", false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_ARRAY_TASK_ID, "Array_Task_ID", false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_PARTITION, "Partition", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_HET_JOB_ID, "Hetjob JobID", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_HET_JOB_ID_SET, "Hetjob JobID Set", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_HET_JOB_OFFSET, "Hetjob Offset", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_USER_ID, "UserID", false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_GROUP_ID, "GroupID", false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_WCKEY, "WCKey", false, EDIT_TEXTBOX, refresh_job, | 
 | 	 create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NAME, "Name", false, EDIT_TEXTBOX, refresh_job, | 
 | 	 create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_STATE, "State", false, 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_PREEMPT_TIME, "Preempt Time", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_RESIZE, "Time Resize", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_RUNNING, "Time Running", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_SUBMIT, "Time Submit", false, | 
 | 	 EDIT_NONE, refresh_job, | 
 | 	 create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_ACCRUE, "Time Accrue", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_ELIGIBLE, "Time Eligible", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_START, "Time Start", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_END, "Time End", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_DEADLINE, "Deadline", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TIME_SUSPEND, "Time Suspended", 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, "Node Count", false, EDIT_TEXTBOX, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPUS, "CPU Count", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODELIST, "NodeList", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODELIST_EXC, "NodeList Excluded", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODELIST_REQ, "NodeList Requested", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODELIST_SCHED, "NodeList Scheduled", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CONTIGUOUS, "Contiguous", false, EDIT_MODEL, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CORE_SPEC, "CoreSpec", false, EDIT_TEXTBOX, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_THREAD_SPEC, "ThreadSpec", false, EDIT_TEXTBOX, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_REBOOT, "Reboot", false, EDIT_MODEL, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_REQUEUE, "Requeue", false, EDIT_MODEL, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_INT, SORTID_RESTARTS, "Restart Count", false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	/* Priority is a string so we can edit using a text box */ | 
 | 	{G_TYPE_STRING, SORTID_PRIORITY, "Priority", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_DERIVED_EC, "Derived Exit Code", false, | 
 | 	 EDIT_NONE, 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_BATCH_HOST, "Batch Host", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_BURST_BUFFER, "Burst Buffer", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CLUSTER_NAME, "ClusterName", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPU_MIN, "CPUs Min", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPU_MAX, "CPUs Max", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TASKS, "Task Count", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_OVER_SUBSCRIBE, "OverSubscribe", false, | 
 | 	 EDIT_MODEL, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_STD_ERR, "Standard Error", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_STD_IN, "Standard In", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_STD_OUT, "Standard Out", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPUS_PER_TASK, "CPUs per Task", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_RESV_NAME, "Reservation Name", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODES_MIN, "Nodes (minimum)", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_NODES_MAX, "Nodes Max", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPU_REQ, "Min CPUs Per Node", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_MEM_MIN, "Min Memory", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TMP_DISK, "Min Tmp Disk Per Node", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	/* Nice is a string so we can edit using a text box */ | 
 | 	{G_TYPE_STRING, SORTID_NICE, "Nice", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_ACCOUNT, "Account", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_QOS, "QOS", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_REASON, "Reason Waiting", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_SWITCHES, "Switches", | 
 | 	 false, EDIT_TEXTBOX, 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_PREFER, "Prefer", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_FED_ACTIVE_SIBS, "FedActiveSiblings", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_FED_ORIGIN, "FedOrigin", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_FED_VIABLE_SIBS, "FedViableSiblings", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	/* "gres" replaced by "tres_per_node" in v18.08 */ | 
 | 	{G_TYPE_STRING, SORTID_GRES, "Gres", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_LAST_SCHED_EVAL, "Last Sched Eval", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_LICENSES, "Licenses", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_MCS_LABEL, "MCS_Label", | 
 | 	 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_NETWORK, "Network", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_COMMAND, "Command", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_COMMENT, "Comment", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_EXTRA, "Extra", | 
 | 	 false, EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_WORKDIR, "Work Dir", | 
 | 	 false, EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_INT, SORTID_COLOR_INX, NULL, false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_POINTER, SORTID_NODE_INX, NULL, false, EDIT_NONE, | 
 | 	 refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_CPUS_PER_TRES, "CPUs per TRES",  false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_MEM_PER_TRES, "Mem per TRES", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_ALLOC, "TRES Alloc", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_BIND, "TRES Bind", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_FREQ, "TRES Freq", false, | 
 | 	 EDIT_NONE, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_PER_JOB, "TRES Per Job", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_PER_NODE, "TRES Per Node", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_PER_SOCKET, "TRES Per Socket", false, | 
 | 	 EDIT_TEXTBOX, refresh_job, create_model_job, admin_edit_job}, | 
 | 	{G_TYPE_STRING, SORTID_TRES_PER_TASK, "TRES Per Task", false, | 
 | 	 EDIT_TEXTBOX, 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, -1, 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, "Requeue", 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}, | 
 | 	{G_TYPE_STRING, NODE_PAGE, "Nodes", true, JOB_PAGE}, | 
 | 	{G_TYPE_STRING, RESV_PAGE, "Reservation", true, JOB_PAGE}, | 
 | 	{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 }, | 
 | 	{ "XCPU",	SIGXCPU }, | 
 | 	{ "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 }, | 
 | 	{ "SIGXCPU",	SIGXCPU }, | 
 | }; | 
 |  | 
 | static display_data_t *local_display_data = NULL; | 
 | static char *got_edit_signal = NULL; | 
 | static GtkTreeModel *last_model = NULL; | 
 |  | 
 | static void _update_info_task(sview_job_info_t *sview_job_info_ptr, | 
 | 			      GtkTreeModel *model, | 
 | 			      GtkTreeIter *task_iter, | 
 | 			      GtkTreeIter *iter, bool handle_pending); | 
 |  | 
 | static void _update_info_step(sview_job_info_t *sview_job_info_ptr, | 
 | 			      GtkTreeModel *model, | 
 | 			      GtkTreeIter *step_iter, | 
 | 			      GtkTreeIter *iter); | 
 |  | 
 | static char *_read_file(const char *f_name) | 
 | { | 
 | 	int fd, f_size, offset = 0; | 
 | 	ssize_t rd_size; | 
 | 	struct stat f_stat; | 
 | 	char *buf; | 
 |  | 
 | 	fd = open(f_name, 0); | 
 | 	if (fd < 0) | 
 | 		return NULL; | 
 | 	if (fstat(fd, &f_stat)) { | 
 | 		close(fd); | 
 | 		return NULL; | 
 | 	} | 
 | 	f_size = f_stat.st_size; | 
 | 	buf = xmalloc(f_size + 1); | 
 | 	while (offset < f_size) { | 
 | 		rd_size = read(fd, buf+offset, f_size-offset); | 
 | 		if (rd_size < 0) { | 
 | 			if ((errno == EAGAIN) || (errno == EINTR)) | 
 | 				continue; | 
 | 			xfree(buf); | 
 | 			break; | 
 | 		} | 
 | 		offset += rd_size; | 
 | 	} | 
 | 	close(fd); | 
 | 	buf[f_size] = '\0'; | 
 | 	return buf; | 
 | } | 
 |  | 
 | static void _job_info_free(sview_job_info_t *sview_job_info) | 
 | { | 
 | 	if (sview_job_info) { | 
 | 		xfree(sview_job_info->job_id_str); | 
 | 		xfree(sview_job_info->nodes); | 
 |  | 
 | 		FREE_NULL_LIST(sview_job_info->step_list); | 
 | 		FREE_NULL_LIST(sview_job_info->task_list); | 
 | 		FREE_NULL_LIST(sview_job_info->task_pending_list); | 
 |  | 
 | 		xfree(sview_job_info->task_hl_str); | 
 | 		xfree(sview_job_info->task_pending_hl_str); | 
 |  | 
 | 		FREE_NULL_HOSTLIST(sview_job_info->task_hl); | 
 | 		FREE_NULL_HOSTLIST(sview_job_info->task_pending_hl); | 
 | 	} | 
 | } | 
 |  | 
 | static void _job_info_list_del(void *object) | 
 | { | 
 | 	sview_job_info_t *sview_job_info = (sview_job_info_t *)object; | 
 |  | 
 | 	if (sview_job_info) { | 
 | 		_job_info_free(sview_job_info); | 
 | 		xfree(sview_job_info); | 
 | 	} | 
 | } | 
 |  | 
 | /* translate signal name to number */ | 
 | static uint16_t _xlate_signal_name(const char *signal_name) | 
 | { | 
 | 	uint16_t sig_num = NO_VAL16; | 
 | 	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 (xstrcasecmp(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 NO_VAL16; | 
 | } | 
 |  | 
 | static int _cancel_job_id (uint32_t job_id, uint16_t signal) | 
 | { | 
 | 	int error_code = SLURM_SUCCESS, i; | 
 | 	char *temp = NULL; | 
 |  | 
 | 	if (signal == (uint16_t)-1) | 
 | 		signal = SIGKILL; | 
 | 	for (i = 0; i < MAX_CANCEL_RETRY; i++) { | 
 | 		/* NOTE: RPC always sent to slurmctld rather than directly | 
 | 		 * to slurmd daemons */ | 
 | 		error_code = slurm_kill_job(job_id, signal, false); | 
 | 		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 = 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(errno)); | 
 | 			display_edit_note(temp); | 
 | 			g_free(temp); | 
 | 		} else { | 
 | 			display_edit_note(slurm_strerror(errno)); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return error_code; | 
 | } | 
 |  | 
 | static int _cancel_step_id(uint32_t job_id, uint32_t step_id, | 
 | 			   uint16_t signal) | 
 | { | 
 | 	int error_code = SLURM_SUCCESS, i; | 
 | 	char *temp = NULL; | 
 | 	char tmp_char[45]; | 
 | 	slurm_step_id_t step_id_tmp = { | 
 | 		.job_id = job_id, | 
 | 		.step_het_comp = NO_VAL, | 
 | 		.step_id = step_id, | 
 | 	}; | 
 |  | 
 | 	log_build_step_id_str(&step_id_tmp, tmp_char, sizeof(tmp_char), | 
 | 			      STEP_ID_FLAG_NONE); | 
 |  | 
 | 	if (signal == (uint16_t)-1) | 
 | 		signal = SIGKILL; | 
 |  | 
 | 	for (i = 0; i < MAX_CANCEL_RETRY; i++) { | 
 | 		/* NOTE: RPC always sent to slurmctld rather than directly | 
 | 		 * to slurmd daemons */ | 
 | 		error_code = slurm_kill_job_step(job_id, step_id, signal, 0); | 
 |  | 
 | 		if (error_code == 0 | 
 | 		    || (errno != ESLURM_TRANSITION_STATE_NO_UPDATE | 
 | 			&& errno != ESLURM_JOB_PENDING)) | 
 | 			break; | 
 | 		temp = g_strdup_printf("Sending signal %u to %s", | 
 | 				       signal, tmp_char); | 
 | 		display_edit_note(temp); | 
 | 		g_free(temp); | 
 | 		sleep ( 5 + i ); | 
 | 	} | 
 |  | 
 | 	if (error_code) { | 
 | 		error_code = errno; | 
 | 		if (error_code != ESLURM_ALREADY_DONE) { | 
 | 			temp = g_strdup_printf( | 
 | 				"Kill job error on %s: %s", | 
 | 				tmp_char, slurm_strerror(errno)); | 
 | 			display_edit_note(temp); | 
 | 			g_free(temp); | 
 | 		} else { | 
 | 			display_edit_note(slurm_strerror(errno)); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return error_code; | 
 | } | 
 |  | 
 | static void _set_active_combo_job(GtkComboBox *combo, | 
 | 				  GtkTreeModel *model, GtkTreeIter *iter, | 
 | 				  int type) | 
 | { | 
 | 	char *temp_char = NULL; | 
 | 	int action = 0; | 
 |  | 
 | 	if (model) | 
 | 		gtk_tree_model_get(model, iter, type, &temp_char, -1); | 
 | 	if (!temp_char) | 
 | 		goto end_it; | 
 | 	switch(type) { | 
 | 	case SORTID_ACTION: | 
 | 		if (!xstrcasecmp(temp_char, "None")) | 
 | 			action = 0; | 
 | 		else if (!xstrcasecmp(temp_char, "Cancel")) | 
 | 			action = 1; | 
 | 		else if (!xstrcasecmp(temp_char, "Suspend")) | 
 | 			action = 2; | 
 | 		else if (!xstrcasecmp(temp_char, "Resume")) | 
 | 			action = 3; | 
 | 		else if (!xstrcasecmp(temp_char, "Requeue")) | 
 | 			action = 5; | 
 | 		else | 
 | 			action = 0; | 
 |  | 
 | 		break; | 
 | 	case SORTID_CONTIGUOUS: | 
 | 	case SORTID_REBOOT: | 
 | 	case SORTID_REQUEUE: | 
 | 	case SORTID_OVER_SUBSCRIBE: | 
 | 		if (!xstrcasecmp(temp_char, "yes")) | 
 | 			action = 0; | 
 | 		else if (!xstrcasecmp(temp_char, "no")) | 
 | 			action = 1; | 
 | 		else | 
 | 			action = 0; | 
 | 		break; | 
 | 	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 = ""; | 
 | 	int temp_int = 0; | 
 | 	long long int temp_ll = 0; | 
 | 	char *p; | 
 | 	char *token; | 
 | 	char *sep_char; | 
 | 	int j; | 
 |  | 
 | 	/* need to clear global_edit_error here (just in case) */ | 
 | 	global_edit_error = 0; | 
 | 	if (!job_msg) | 
 | 		return NULL; | 
 |  | 
 | 	switch (column) { | 
 | 	case SORTID_ACTION: | 
 | 		xfree(got_edit_signal); | 
 | 		if (!xstrcasecmp(new_text, "None")) | 
 | 			got_edit_signal = NULL; | 
 | 		else | 
 | 			got_edit_signal = xstrdup(new_text); | 
 | 		break; | 
 | 	case SORTID_COMMENT: | 
 | 		job_msg->comment = xstrdup(new_text); | 
 | 		type = "comment"; | 
 | 		break; | 
 | 	case SORTID_TIMELIMIT: | 
 | 		if (!xstrcasecmp(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: | 
 | 		if (!xstrcasecmp(new_text, "infinite")) | 
 | 			temp_int = INFINITE; | 
 | 		else | 
 | 			temp_int = strtol(new_text, (char **)NULL, 10); | 
 |  | 
 | 		type = "priority"; | 
 | 		if ((temp_int < 0) && (temp_int != INFINITE)) | 
 | 			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) > (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_CPU_REQ: | 
 | 		temp_int = strtol(new_text, &p, 10); | 
 | 		if (*p == 'k' || *p == 'K') | 
 | 			temp_int *= 1024; | 
 | 		else if (*p == 'm' || *p == 'M') | 
 | 			temp_int *= 1048576; | 
 |  | 
 | 		type = "min cpus per node"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->pn_min_cpus = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_TASKS: | 
 | 		temp_int = strtol(new_text, (char **)NULL, 10); | 
 |  | 
 | 		type = "requested tasks"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->num_tasks = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_CPUS_PER_TASK: | 
 | 		temp_int = strtol(new_text, (char **)NULL, 10); | 
 |  | 
 | 		type = "cpus per task"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->cpus_per_task = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_RESV_NAME: | 
 | 		job_msg->reservation = xstrdup(new_text); | 
 | 		type = "reservation name"; | 
 | 		break; | 
 | 	case SORTID_NODES_MIN: | 
 | 		temp_int = strtol(new_text, &p, 10); | 
 | 		if (*p == 'k' || *p == 'K') | 
 | 			temp_int *= 1024; | 
 | 		else if (*p == 'm' || *p == 'M') | 
 | 			temp_int *= 1048576; | 
 |  | 
 | 		type = "min nodes"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->min_nodes = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_NODES: | 
 | 		temp_int = strtol(new_text, &p, 10); | 
 | 		if (*p == 'k' || *p == 'K') | 
 | 			temp_int *= 1024; | 
 | 		else if (*p == 'm' || *p == 'M') | 
 | 			temp_int *= 1048576; | 
 |  | 
 | 		type = "node count"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->min_nodes = job_msg->max_nodes = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_NODES_MAX: | 
 | 		temp_int = strtol(new_text, &p, 10); | 
 | 		if (*p == 'k' || *p == 'K') | 
 | 			temp_int *= 1024; | 
 | 		else if (*p == 'm' || *p == 'M') | 
 | 			temp_int *= 1048576; | 
 |  | 
 | 		type = "max nodes"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->max_nodes = (uint32_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_MEM_MIN: | 
 | 		temp_ll = strtoll(new_text, &p, 10); | 
 | 		if (*p == 'g' || *p == 'G') | 
 | 			temp_ll *= 1024; | 
 | 		else if (*p == 't' || *p == 'T') | 
 | 			temp_ll *= 1048576; | 
 |  | 
 | 		p = xstrcasestr((char *)new_text, "tres"); | 
 | 		if (p) | 
 | 			goto return_error; | 
 |  | 
 | 		p = xstrcasestr((char *)new_text, "cpu"); | 
 | 		if (p) | 
 | 			type = "min memory per cpu"; | 
 | 		else | 
 | 			type = "min memory per node"; | 
 |  | 
 | 		if (temp_ll <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->pn_min_memory = (uint64_t) temp_ll; | 
 | 		if (p) | 
 | 			job_msg->pn_min_memory |= MEM_PER_CPU; | 
 | 		break; | 
 | 	case SORTID_TMP_DISK: | 
 | 		temp_int = strtol(new_text, &p, 10); | 
 | 		if (*p == 'g' || *p == 'G') | 
 | 			temp_int *= 1024; | 
 | 		else if (*p == 't' || *p == 'T') | 
 | 			temp_int *= 1048576; | 
 |  | 
 | 		type = "min tmp disk per node"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->pn_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_HET_JOB_ID: | 
 | 		job_msg->name = xstrdup(new_text); | 
 | 		type = "hetjob jobid"; | 
 | 		break; | 
 | 	case SORTID_HET_JOB_ID_SET: | 
 | 		job_msg->name = xstrdup(new_text); | 
 | 		type = "hetjob id set"; | 
 | 		break; | 
 | 	case SORTID_HET_JOB_OFFSET: | 
 | 		job_msg->name = xstrdup(new_text); | 
 | 		type = "hetjob offset"; | 
 | 		break; | 
 | 	case SORTID_WCKEY: | 
 | 		job_msg->wckey = xstrdup(new_text); | 
 | 		type = "wckey"; | 
 | 		break; | 
 | 	case SORTID_OVER_SUBSCRIBE: | 
 | 		if (!xstrcasecmp(new_text, "yes")) | 
 | 			job_msg->shared = 1; | 
 | 		else | 
 | 			job_msg->shared = 0; | 
 |  | 
 | 		type = "oversubscribe"; | 
 | 		break; | 
 | 	case SORTID_CONTIGUOUS: | 
 | 		if (!xstrcasecmp(new_text, "yes")) | 
 | 			job_msg->contiguous = 1; | 
 | 		else | 
 | 			job_msg->contiguous = 0; | 
 |  | 
 | 		type = "contiguous"; | 
 | 		break; | 
 | 	case SORTID_CORE_SPEC: | 
 | 		temp_int = strtol(new_text, (char **)NULL, 10); | 
 |  | 
 | 		type = "specialized cores"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->core_spec = (uint16_t)temp_int; | 
 | 		break; | 
 | 	case SORTID_THREAD_SPEC: | 
 | 		temp_int = strtol(new_text, (char **)NULL, 10); | 
 |  | 
 | 		type = "specialized threads"; | 
 | 		if (temp_int <= 0) | 
 | 			goto return_error; | 
 | 		job_msg->core_spec = (uint16_t)temp_int | CORE_SPEC_THREAD; | 
 | 		break; | 
 | 	case SORTID_REBOOT: | 
 | 		if (!xstrcasecmp(new_text, "yes")) | 
 | 			job_msg->reboot = 1; | 
 | 		else | 
 | 			job_msg->reboot = 0; | 
 | 		type = "reboot"; | 
 | 		break; | 
 | 	case SORTID_REQUEUE: | 
 | 		if (!xstrcasecmp(new_text, "yes")) | 
 | 			job_msg->requeue = 1; | 
 | 		else | 
 | 			job_msg->requeue = 0; | 
 | 		type = "requeue"; | 
 | 		break; | 
 | 	case SORTID_NODELIST_REQ: | 
 | 		job_msg->req_nodes = xstrdup(new_text); | 
 | 		type = "requested nodelist"; | 
 | 		break; | 
 | 	case SORTID_NODELIST_EXC: | 
 | 		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_PREFER: | 
 | 		job_msg->prefer = xstrdup(new_text); | 
 | 		type = "prefer"; | 
 | 		break; | 
 | 	case SORTID_CPUS_PER_TRES: | 
 | 		job_msg->cpus_per_tres = xstrdup(new_text); | 
 | 		type = "cpus_per_tres"; | 
 | 		break; | 
 | 	case SORTID_MEM_PER_TRES: | 
 | 		job_msg->mem_per_tres = xstrdup(new_text); | 
 | 		type = "mem_per_tres"; | 
 | 		break; | 
 | 	case SORTID_TRES_PER_JOB: | 
 | 		job_msg->tres_per_job = xstrdup(new_text); | 
 | 		type = "tres_per_job"; | 
 | 		break; | 
 | 	case SORTID_TRES_PER_NODE: | 
 | 		job_msg->tres_per_node = xstrdup(new_text); | 
 | 		type = "tres_per_node"; | 
 | 		break; | 
 | 	case SORTID_TRES_PER_SOCKET: | 
 | 		job_msg->tres_per_socket = xstrdup(new_text); | 
 | 		type = "tres_per_socket"; | 
 | 		break; | 
 | 	case SORTID_TRES_PER_TASK: | 
 | 		job_msg->tres_per_task = xstrdup(new_text); | 
 | 		type = "tres_per_task"; | 
 | 		break; | 
 | 	case SORTID_LICENSES: | 
 | 		job_msg->licenses = xstrdup(new_text); | 
 | 		type = "licenses"; | 
 | 		break; | 
 | 	case SORTID_MCS_LABEL: | 
 | 		job_msg->mcs_label = xstrdup(new_text); | 
 | 		type = "mcs_label"; | 
 | 		break; | 
 | 	case SORTID_ACCOUNT: | 
 | 		job_msg->account = xstrdup(new_text); | 
 | 		type = "account"; | 
 | 		break; | 
 | 	case SORTID_BURST_BUFFER: | 
 | 		job_msg->burst_buffer = xstrdup(new_text); | 
 | 		type = "burst buffer"; | 
 | 		break; | 
 | 	case SORTID_QOS: | 
 | 		job_msg->qos = xstrdup(new_text); | 
 | 		type = "qos"; | 
 | 		break; | 
 | 	case SORTID_COMMAND: | 
 | 		type = "script_file"; | 
 | 		xfree(job_msg->script); | 
 | 		job_msg->script = _read_file(new_text); | 
 | 		if (job_msg->script == NULL) | 
 | 			goto return_error; | 
 | 		if (job_msg->argc) { | 
 | 			for (j = 0; j < job_msg->argc; j++) | 
 | 				xfree(job_msg->argv[j]); | 
 | 		} | 
 | 		xfree(job_msg->argv); | 
 | 		xfree(job_msg->name); | 
 | 		job_msg->argc = 1; | 
 | 		job_msg->argv = xmalloc(sizeof(char *) * job_msg->argc); | 
 | 		if (new_text[0] == '/') { | 
 | 			job_msg->argv[0] = xstrdup(new_text); | 
 | 			token = strrchr(new_text, (int) '/'); | 
 | 			if (token) | 
 | 				job_msg->name = xstrdup(token + 1); | 
 | 		} else { | 
 | 			job_msg->argv[0] = xmalloc(PATH_MAX); | 
 | 			if (!getcwd(job_msg->argv[0], PATH_MAX)) | 
 | 				goto return_error; | 
 | 			xstrcat(job_msg->argv[0], "/"); | 
 | 			xstrcat(job_msg->argv[0], new_text); | 
 | 			job_msg->name = xstrdup(new_text); | 
 | 		} | 
 | 		break; | 
 | 	case SORTID_DEPENDENCY: | 
 | 		job_msg->dependency = xstrdup(new_text); | 
 | 		type = "dependency"; | 
 | 		break; | 
 | 	case SORTID_TIME_ELIGIBLE: | 
 | 	case SORTID_TIME_START: | 
 | 		type = "start time"; | 
 | 		job_msg->begin_time = parse_time((char *)new_text, 0); | 
 | 		if (!job_msg->begin_time) | 
 | 			goto return_error; | 
 |  | 
 | 		if (job_msg->begin_time < time(NULL)) | 
 | 			job_msg->begin_time = time(NULL); | 
 | 		break; | 
 | 	case SORTID_DEADLINE: | 
 | 		type = "deadline"; | 
 | 		job_msg->deadline = parse_time((char *)new_text, 0); | 
 | 		if (!job_msg->deadline) | 
 | 			goto return_error; | 
 | 		if (job_msg->deadline < time(NULL)) | 
 | 			goto return_error; | 
 | 		break; | 
 | 	case SORTID_EXTRA: | 
 | 		job_msg->extra = xstrdup(new_text); | 
 | 		type = "extra"; | 
 | 		break; | 
 | 	case SORTID_STD_OUT: | 
 | 		type = "StdOut"; | 
 | 		job_msg->std_out = xstrdup(new_text); | 
 | 		break; | 
 | 	case SORTID_SWITCHES: | 
 | 		type = "switches"; | 
 | 		job_msg->req_switch = | 
 | 			(uint32_t) strtol(new_text, &sep_char, 10); | 
 | 		if (sep_char && sep_char[0] == '@') { | 
 | 			job_msg->wait4switch = time_str2mins(sep_char+1) * 60; | 
 | 		} | 
 | 		break; | 
 | 	default: | 
 | 		type = "unknown"; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	if (xstrcmp(type, "unknown")) | 
 | 		global_send_update_msg = 1; | 
 |  | 
 | 	return type; | 
 |  | 
 | return_error: | 
 | 	global_edit_error = 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) | 
 | { | 
 | 	if (global_entry_changed) { | 
 | 		const char *col_name = NULL; | 
 | 		int type = gtk_entry_get_max_length(entry); | 
 | 		const char *name = gtk_entry_get_text(entry); | 
 | 		type -= DEFAULT_ENTRY_LENGTH; | 
 |  | 
 | 		col_name = _set_job_msg(job_msg, name, type); | 
 | 		if (global_edit_error) { | 
 | 			if (global_edit_error_msg) | 
 | 				g_free(global_edit_error_msg); | 
 | 			global_edit_error_msg = g_strdup_printf( | 
 | 				"Job %d %s can't be set to %s", | 
 | 				job_msg->job_id, | 
 | 				col_name, | 
 | 				name); | 
 | 		} | 
 | 		global_entry_changed = 0; | 
 | 	} | 
 | 	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; | 
 | 	int i = 0, row = 0; | 
 | 	display_data_t *display_data = display_data_job; | 
 |  | 
 | 	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++) { | 
 | 		while (display_data++) { | 
 | 			if (display_data->id == -1) | 
 | 				break; | 
 | 			if (!display_data->name) | 
 | 				continue; | 
 | 			if (display_data->id != i) | 
 | 				continue; | 
 | 			display_admin_edit( | 
 | 				table, job_msg, &row, model, iter, | 
 | 				display_data, | 
 | 				G_CALLBACK(_admin_edit_combo_box_job), | 
 | 				G_CALLBACK(_admin_focus_out_job), | 
 | 				_set_active_combo_job); | 
 | 			break; | 
 | 		} | 
 | 		display_data = display_data_job; | 
 | 	} | 
 | 	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; | 
 | } | 
 |  | 
 | /* 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, *uname = NULL; | 
 | 	const char *reason = NULL; | 
 | 	char *group; | 
 | 	char tmp_char[256]; | 
 | 	char time_buf[32]; | 
 | 	char tmp1[128]; | 
 | 	char running_char[50]; | 
 | 	time_t now_time = time(NULL); | 
 | 	int suspend_secs = 0; | 
 | 	job_info_t *job_ptr = sview_job_info_ptr->job_ptr; | 
 | 	uint16_t term_code = 0, term_sig = 0; | 
 | 	uint64_t min_mem = 0; | 
 |  | 
 | 	GtkTreeIter iter; | 
 | 	GtkTreeStore *treestore = | 
 | 		GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); | 
 |  | 
 | 	if (!treestore) | 
 | 		return; | 
 |  | 
 | 	if (!job_ptr->nodes || IS_JOB_PENDING(job_ptr) || | 
 | 	    !xstrcasecmp(job_ptr->nodes,"waiting...")) { | 
 | 		sprintf(running_char,"00:00:00"); | 
 | 		nodes = xstrdup("waiting..."); | 
 | 	} else { | 
 | 		if (IS_JOB_SUSPENDED(job_ptr)) | 
 | 			now_time = job_ptr->pre_sus_time; | 
 | 		else { | 
 | 			if (!IS_JOB_RUNNING(job_ptr) && | 
 | 			    (job_ptr->end_time != 0)) | 
 | 				now_time = job_ptr->end_time; | 
 | 			if (job_ptr->suspend_time) { | 
 | 				now_time = (time_t) | 
 | 					(difftime(now_time, | 
 | 						  job_ptr->suspend_time) | 
 | 					 + job_ptr->pre_sus_time); | 
 | 			} else | 
 | 				now_time = (time_t)difftime( | 
 | 					now_time, job_ptr->start_time); | 
 | 		} | 
 | 		suspend_secs = (time(NULL) - job_ptr->start_time) - now_time; | 
 | 		secs2time_str(now_time, running_char, sizeof(running_char)); | 
 |  | 
 | 		nodes = slurm_sort_node_list_str(sview_job_info_ptr->nodes); | 
 | 	} | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_ACCOUNT), | 
 | 				   job_ptr->account); | 
 |  | 
 | 	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); | 
 |  | 
 | 	if (job_ptr->array_task_str || | 
 | 	    (job_ptr->array_task_id != NO_VAL)) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 			 job_ptr->array_job_id); | 
 | 	} else { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "N/A"); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_ARRAY_JOB_ID), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->array_task_str) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "[%s]", | 
 | 			 job_ptr->array_task_str); | 
 | 	} else if (job_ptr->array_task_id != NO_VAL) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 			 job_ptr->array_task_id); | 
 | 	} else { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "N/A"); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_ARRAY_TASK_ID), | 
 | 				   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); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_BATCH_HOST), | 
 | 				   job_ptr->batch_host); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_BURST_BUFFER), | 
 | 				   job_ptr->burst_buffer); | 
 |  | 
 | 	if (job_ptr->cluster) { | 
 | 		add_display_treestore_line(update, treestore, &iter, | 
 | 					   find_col_name(display_data_job, | 
 | 							 SORTID_CLUSTER_NAME), | 
 | 					   job_ptr->cluster); | 
 | 	} | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_COMMAND), | 
 | 				   job_ptr->command); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_COMMENT), | 
 | 				   job_ptr->comment); | 
 |  | 
 | 	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->core_spec == NO_VAL16) || | 
 | 	    (job_ptr->core_spec & CORE_SPEC_THREAD)) { | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	} else { | 
 | 		sprintf(tmp_char, "%u", job_ptr->core_spec); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CORE_SPEC), | 
 | 				   tmp_char); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_cpus); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPUS), | 
 | 				   tmp_char); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->max_cpus); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPU_MAX), | 
 | 				   tmp_char); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->num_cpus); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPU_MIN), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->cpus_per_task == NO_VAL16) | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	else | 
 | 		sprintf(tmp_char, "%u", job_ptr->cpus_per_task); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPUS_PER_TASK), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPUS_PER_TRES), | 
 | 				   job_ptr->cpus_per_tres); | 
 |  | 
 | 	if (job_ptr->deadline) | 
 | 		slurm_make_time_str((time_t *)&job_ptr->deadline, tmp_char, | 
 | 				     sizeof(tmp_char)); | 
 | 	else | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_DEADLINE), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_DEPENDENCY), | 
 | 				   job_ptr->dependency); | 
 |  | 
 | 	if (WIFEXITED(job_ptr->derived_ec)) | 
 | 		term_code = WEXITSTATUS(job_ptr->derived_ec); | 
 | 	else | 
 | 		term_code = 0; | 
 | 	if (WIFSIGNALED(job_ptr->derived_ec)) | 
 | 		term_sig = WTERMSIG(job_ptr->derived_ec); | 
 | 	else | 
 | 		term_sig = 0; | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u:%u", term_code, term_sig); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_DERIVED_EC), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (WIFEXITED(job_ptr->exit_code)) | 
 | 		term_code = WEXITSTATUS(job_ptr->exit_code); | 
 | 	else | 
 | 		term_code = 0; | 
 | 	if (WIFSIGNALED(job_ptr->exit_code)) | 
 | 		term_sig = WTERMSIG(job_ptr->exit_code); | 
 | 	else | 
 | 		term_sig = 0; | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u:%u", term_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_EXTRA), | 
 | 				   job_ptr->extra); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_FEATURES), | 
 | 				   job_ptr->features); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_PREFER), | 
 | 				   job_ptr->prefer); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_FED_ACTIVE_SIBS), | 
 | 				   job_ptr->fed_siblings_active_str); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_FED_ORIGIN), | 
 | 				   job_ptr->fed_origin_str); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_FED_VIABLE_SIBS), | 
 | 				   job_ptr->fed_siblings_viable_str); | 
 |  | 
 | 	/* "gres" replaced by "tres_per_node" in v18.08 */ | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_GRES), | 
 | 				   job_ptr->tres_per_node); | 
 |  | 
 | 	group = gid_to_string(job_ptr->group_id); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_GROUP_ID), | 
 | 				   group); | 
 | 	xfree(group); | 
 |  | 
 | 	if (job_ptr->array_task_str) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u_[%s] (%u)", | 
 | 			 job_ptr->array_job_id, job_ptr->array_task_str, | 
 | 			 job_ptr->job_id); | 
 | 	} else if (job_ptr->array_task_id != NO_VAL) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u_%u (%u)", | 
 | 			 job_ptr->array_job_id, job_ptr->array_task_id, | 
 | 			 job_ptr->job_id); | 
 | 	} else if (job_ptr->het_job_id) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u+%u (%u)", | 
 | 			 job_ptr->het_job_id, | 
 | 			 job_ptr->het_job_offset, | 
 | 			 job_ptr->job_id); | 
 | 	} else { | 
 | 		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); | 
 |  | 
 | 	slurm_make_time_str(&job_ptr->last_sched_eval, tmp_char, | 
 | 			    sizeof(tmp_char)); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_LAST_SCHED_EVAL), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_LICENSES), | 
 | 				   job_ptr->licenses); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_MCS_LABEL), | 
 | 				   (job_ptr->mcs_label==NULL) ? "N/A" : | 
 | 						 job_ptr->mcs_label); | 
 |  | 
 | 	convert_num_unit((float)job_ptr->pn_min_cpus, tmp_char, | 
 | 			 sizeof(tmp_char), UNIT_NONE, NO_VAL, | 
 | 			 working_sview_config.convert_flags); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPU_REQ), | 
 | 				   tmp_char); | 
 |  | 
 | 	min_mem = job_ptr->pn_min_memory; | 
 | 	if (min_mem & MEM_PER_CPU) | 
 | 		min_mem &= (~MEM_PER_CPU); | 
 |  | 
 | 	if (min_mem > 0) { | 
 | 		int len; | 
 | 		convert_num_unit((float)min_mem, tmp_char, sizeof(tmp_char), | 
 | 				 UNIT_MEGA, NO_VAL, | 
 | 				 working_sview_config.convert_flags); | 
 | 		len = strlen(tmp_char); | 
 | 		if (job_ptr->mem_per_tres) { | 
 | 			sprintf(tmp_char+len, " Per TRES"); | 
 | 		} else if (job_ptr->pn_min_memory & MEM_PER_CPU) | 
 | 			sprintf(tmp_char+len, " Per CPU"); | 
 | 		else | 
 | 			sprintf(tmp_char+len, " Per Node"); | 
 | 	} else | 
 | 		sprintf(tmp_char, " "); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_MEM_MIN), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_MEM_PER_TRES), | 
 | 				   job_ptr->mem_per_tres); | 
 |  | 
 | 	if (job_ptr->pn_min_tmp_disk > 0) | 
 | 		convert_num_unit((float)job_ptr->pn_min_tmp_disk, tmp_char, | 
 | 				 sizeof(tmp_char), UNIT_MEGA, NO_VAL, | 
 | 				 working_sview_config.convert_flags); | 
 | 	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_NAME), | 
 | 				   job_ptr->name); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NETWORK), | 
 | 				   job_ptr->network); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%"PRIi64, | 
 | 		 (((int64_t)job_ptr->nice) - NICE_OFFSET)); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NICE), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODELIST), | 
 | 				   nodes); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODELIST_EXC), | 
 | 				   job_ptr->exc_nodes); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODELIST_REQ), | 
 | 				   job_ptr->req_nodes); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODELIST_SCHED), | 
 | 				   job_ptr->sched_nodes); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 		 sview_job_info_ptr->node_cnt); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODES), | 
 | 				   tmp_char); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->max_nodes); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODES_MAX), | 
 | 				   tmp_char); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 		 sview_job_info_ptr->node_cnt); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODES_MIN), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_OVER_SUBSCRIBE), | 
 | 				   job_share_string(job_ptr->shared)); | 
 |  | 
 | 	if (job_ptr->het_job_id) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 			 job_ptr->het_job_id); | 
 | 	} else { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "N/A"); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_HET_JOB_ID), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->het_job_offset) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u", | 
 | 			 job_ptr->het_job_offset); | 
 | 	} else { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "N/A"); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_HET_JOB_OFFSET), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->het_job_id_set) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%s", | 
 | 			 job_ptr->het_job_id_set); | 
 | 	} else { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "N/A"); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_HET_JOB_ID_SET), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_PARTITION), | 
 | 				   job_ptr->partition); | 
 |  | 
 | 	if (job_ptr->preempt_time) { | 
 | 		slurm_make_time_str((time_t *)&job_ptr->preempt_time, tmp_char, | 
 | 				    sizeof(tmp_char)); | 
 | 	} else | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_PREEMPT_TIME), | 
 | 				   tmp_char); | 
 |  | 
 | 	sprintf(tmp_char, "%u", job_ptr->priority); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_PRIORITY), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_QOS), | 
 | 				   job_ptr->qos); | 
 |  | 
 | 	if (job_ptr->state_desc) | 
 | 		reason = job_ptr->state_desc; | 
 | 	else | 
 | 		reason = job_state_reason_string(job_ptr->state_reason); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_REASON), reason); | 
 |  | 
 | 	if (job_ptr->reboot) | 
 | 		sprintf(tmp_char, "yes"); | 
 | 	else | 
 | 		sprintf(tmp_char, "no"); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_REBOOT), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->requeue) | 
 | 		sprintf(tmp_char, "yes"); | 
 | 	else | 
 | 		sprintf(tmp_char, "no"); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_REQUEUE), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_RESV_NAME), | 
 | 				   job_ptr->resv_name); | 
 |  | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u", job_ptr->restart_cnt); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_RESTARTS), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_STATE), | 
 | 				   job_state_string(job_ptr->job_state)); | 
 |  | 
 | 	slurm_get_job_stderr(tmp1, sizeof(tmp1), job_ptr); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_STD_ERR), | 
 | 				   tmp1); | 
 |  | 
 | 	slurm_get_job_stdin(tmp1, sizeof(tmp1), job_ptr); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_STD_IN), | 
 | 				   tmp1); | 
 |  | 
 | 	slurm_get_job_stdout(tmp1, sizeof(tmp1), job_ptr); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_STD_OUT), | 
 | 				   tmp1); | 
 |  | 
 | 	secs2time_str((time_t) job_ptr->wait4switch, time_buf, | 
 | 			sizeof(time_buf)); | 
 | 	snprintf(tmp_char, sizeof(tmp_char), "%u@%s", | 
 | 			job_ptr->req_switch, time_buf); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_SWITCHES), | 
 | 				   tmp_char); | 
 |  | 
 | 	if ((job_ptr->core_spec == NO_VAL16) || | 
 | 	    ((job_ptr->core_spec & CORE_SPEC_THREAD) == 0)) { | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	} else { | 
 | 		sprintf(tmp_char, "%u", | 
 | 			job_ptr->core_spec & (~CORE_SPEC_THREAD)); | 
 | 	} | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_THREAD_SPEC), | 
 | 				   tmp_char); | 
 |  | 
 | 	slurm_make_time_str((time_t *)&job_ptr->accrue_time, tmp_char, | 
 | 			    sizeof(tmp_char)); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_ACCRUE), | 
 | 				   tmp_char); | 
 | 	slurm_make_time_str((time_t *)&job_ptr->eligible_time, tmp_char, | 
 | 			    sizeof(tmp_char)); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_ELIGIBLE), | 
 | 				   tmp_char); | 
 | 	if ((job_ptr->time_limit == INFINITE) && | 
 | 	    (job_ptr->end_time > time(NULL))) | 
 | 		sprintf(tmp_char, "Unknown"); | 
 | 	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_TIME_END), | 
 | 				   tmp_char); | 
 |  | 
 | 	if (job_ptr->time_limit == NO_VAL) | 
 | 		sprintf(tmp_char, "Partition Limit"); | 
 | 	else if (job_ptr->time_limit == INFINITE) | 
 | 		sprintf(tmp_char, "Infinite"); | 
 | 	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); | 
 |  | 
 | 	if (job_ptr->resize_time) { | 
 | 		slurm_make_time_str((time_t *)&job_ptr->resize_time, tmp_char, | 
 | 				    sizeof(tmp_char)); | 
 | 	} else | 
 | 		sprintf(tmp_char, "N/A"); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_RESIZE), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_RUNNING), | 
 | 				   running_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_TIME_START), | 
 | 				   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_TIME_SUBMIT), | 
 | 				   tmp_char); | 
 | 	secs2time_str(suspend_secs, tmp_char, sizeof(tmp_char)); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_SUSPEND), | 
 | 				   tmp_char); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_ALLOC), | 
 | 				   job_ptr->tres_alloc_str); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_BIND), | 
 | 				   job_ptr->tres_bind); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_FREQ), | 
 | 				   job_ptr->tres_freq); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_JOB), | 
 | 				   job_ptr->tres_per_job); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_NODE), | 
 | 				   job_ptr->tres_per_node); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_SOCKET), | 
 | 				   job_ptr->tres_per_socket); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_TASK), | 
 | 				   job_ptr->tres_per_task); | 
 |  | 
 | 	uname = uid_to_string_cached((uid_t)job_ptr->user_id); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_USER_ID), uname); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_WCKEY), | 
 | 				   job_ptr->wckey); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_WORKDIR), | 
 | 				   job_ptr->work_dir); | 
 |  | 
 | 	xfree(nodes); | 
 | } | 
 |  | 
 | static void _update_job_record(sview_job_info_t *sview_job_info_ptr, | 
 | 			       GtkTreeStore *treestore, | 
 | 			       GtkTreeIter *iter, bool check_task, | 
 | 			       bool handle_pending) | 
 | { | 
 | 	char tmp_array_job_id[20], tmp_array_task_id[20]; | 
 | 	char tmp_time_run[40],  tmp_time_resize[256], tmp_time_submit[256]; | 
 | 	char tmp_time_elig[256], tmp_time_start[256],  tmp_time_end[256]; | 
 | 	char tmp_time_sus[40],  tmp_time_limit[40],  tmp_alloc_node[40]; | 
 | 	char tmp_exit[40], tmp_derived_ec[40]; | 
 | 	char tmp_cpu_cnt[40],   tmp_node_cnt[40],    tmp_disk[40]; | 
 | 	char tmp_cpus_max[40],  tmp_mem_min[40],     tmp_cpu_req[40]; | 
 | 	char tmp_nodes_min[40], tmp_nodes_max[40],   tmp_cpus_per_task[40]; | 
 | 	char tmp_prio[40], tmp_nice[40], tmp_preempt_time[256]; | 
 | 	char tmp_rqswitch[40],  tmp_core_spec[40],   tmp_job_id[40]; | 
 | 	char tmp_std_err[128],  tmp_std_in[128],     tmp_std_out[128]; | 
 | 	char tmp_thread_spec[40], tmp_time_deadline[256], tmp_het_job_id[40]; | 
 | 	char tmp_het_job_id_set[40], tmp_het_job_offset[40]; | 
 | 	char tmp_time_accrue[256]; | 
 | 	char *tmp_batch,  *tmp_cont, *tmp_requeue, *tmp_uname, *tmp_gname; | 
 | 	char *tmp_reboot,*tmp_nodes; | 
 | 	const char *tmp_reason; | 
 | 	char time_buf[32]; | 
 | 	time_t now_time = time(NULL); | 
 | 	int suspend_secs = 0; | 
 | 	GtkTreeIter step_iter; | 
 | 	job_info_t *job_ptr = sview_job_info_ptr->job_ptr; | 
 | 	uint16_t term_code = 0, term_sig = 0; | 
 | 	uint64_t min_mem = 0; | 
 |  | 
 | 	if (!iter) | 
 | 		iter = &sview_job_info_ptr->iter_ptr; | 
 |  | 
 | 	snprintf(tmp_alloc_node, sizeof(tmp_alloc_node), "%s:%u", | 
 | 		 job_ptr->alloc_node, job_ptr->alloc_sid); | 
 |  | 
 | 	/* | 
 | 	 * These need to be set up first, or they could be NULL when | 
 | 	 * they need to be set.  Since we do a xstrcmp on these later | 
 | 	 * we need to make sure they are exactly the same (length wise). | 
 | 	 */ | 
 | 	if (!sview_job_info_ptr->task_hl_str && sview_job_info_ptr->task_hl) { | 
 | 		sview_job_info_ptr->task_hl_str = | 
 | 			hostlist_ranged_string_xmalloc( | 
 | 				sview_job_info_ptr->task_hl); | 
 | 		if (!job_ptr->het_job_id) { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%s", | 
 | 				 job_ptr->array_job_id, | 
 | 				 sview_job_info_ptr->task_hl_str); | 
 | 		} else { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%s", | 
 | 				 job_ptr->het_job_id, | 
 | 				 sview_job_info_ptr->task_hl_str); | 
 | 		} | 
 | 		xfree(sview_job_info_ptr->task_hl_str); | 
 | 		sview_job_info_ptr->task_hl_str = xstrdup(tmp_job_id); | 
 | 	} | 
 |  | 
 | 	if (!sview_job_info_ptr->task_pending_hl_str | 
 | 	    && sview_job_info_ptr->task_pending_hl) { | 
 | 		sview_job_info_ptr->task_pending_hl_str = | 
 | 			hostlist_ranged_string_xmalloc( | 
 | 				sview_job_info_ptr->task_pending_hl); | 
 | 		if (!job_ptr->het_job_id) { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%s", | 
 | 				 job_ptr->array_job_id, | 
 | 				 sview_job_info_ptr->task_pending_hl_str); | 
 | 		} else { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%s", | 
 | 				 job_ptr->het_job_id, | 
 | 				 sview_job_info_ptr->task_pending_hl_str); | 
 | 		} | 
 | 		xfree(sview_job_info_ptr->task_pending_hl_str); | 
 | 		sview_job_info_ptr->task_pending_hl_str = | 
 | 			xstrdup(tmp_job_id); | 
 | 	} | 
 |  | 
 | 	if (handle_pending && | 
 | 	    (job_ptr->het_job_id || job_ptr->array_job_id)) { | 
 | 		if (job_ptr->array_task_str || | 
 | 		    (job_ptr->array_task_id != NO_VAL)) { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 				 sview_job_info_ptr->task_pending_hl_str); | 
 | 			snprintf(tmp_array_job_id, | 
 | 				 sizeof(tmp_array_job_id),  "N/A"); | 
 | 			snprintf(tmp_array_task_id, | 
 | 				 sizeof(tmp_array_task_id), "%s", | 
 | 				 sview_job_info_ptr->task_pending_hl_str); | 
 | 		} else if (job_ptr->het_job_id) { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 				 sview_job_info_ptr->task_pending_hl_str); | 
 | 		} | 
 | 	} else if (check_task && | 
 | 		   (job_ptr->het_job_id || job_ptr->array_job_id)) { | 
 | 		if (job_ptr->array_task_str || | 
 | 		    (job_ptr->array_task_id != NO_VAL)) { | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 				 sview_job_info_ptr->task_hl_str); | 
 | 			snprintf(tmp_array_job_id, | 
 | 				 sizeof(tmp_array_job_id),  "N/A"); | 
 | 			snprintf(tmp_array_task_id, | 
 | 				 sizeof(tmp_array_task_id), "%s", | 
 | 				 sview_job_info_ptr->task_hl_str); | 
 | 		} else if (job_ptr->het_job_id) | 
 | 			snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 					sview_job_info_ptr->task_hl_str); | 
 | 	} else if (job_ptr->array_task_str) { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 			 sview_job_info_ptr->job_id_str); | 
 | 		snprintf(tmp_array_job_id,  sizeof(tmp_array_job_id),  "%u", | 
 | 			 job_ptr->array_job_id); | 
 | 		snprintf(tmp_array_task_id, sizeof(tmp_array_task_id), "[%s]", | 
 | 			 job_ptr->array_task_str); | 
 | 	} else if (job_ptr->array_task_id != NO_VAL) { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 			 sview_job_info_ptr->job_id_str); | 
 | 		snprintf(tmp_array_job_id,  sizeof(tmp_array_job_id),  "%u", | 
 | 			 job_ptr->array_job_id); | 
 | 		snprintf(tmp_array_task_id, sizeof(tmp_array_task_id), "%u", | 
 | 			 job_ptr->array_task_id); | 
 | 	} else if (job_ptr->het_job_id) { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 			 sview_job_info_ptr->job_id_str); | 
 | 		snprintf(tmp_het_job_id,      sizeof(tmp_het_job_id), | 
 | 			 "%u", job_ptr->het_job_id); | 
 | 		snprintf(tmp_het_job_id_set,  sizeof(tmp_het_job_id_set), | 
 | 			 "%s", job_ptr->het_job_id_set); | 
 | 		snprintf(tmp_het_job_offset,  sizeof(tmp_het_job_offset), | 
 | 			 "%u", job_ptr->het_job_offset); | 
 | 	 } else { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id),  "%s", | 
 | 			 sview_job_info_ptr->job_id_str); | 
 | 	} | 
 |  | 
 |  | 
 | 	if (!job_ptr->het_job_id) { | 
 | 		snprintf(tmp_het_job_id, | 
 | 			 sizeof(tmp_het_job_id),      "N/A"); | 
 | 		snprintf(tmp_het_job_id_set, | 
 | 			 sizeof(tmp_het_job_id_set),  "N/A"); | 
 | 		snprintf(tmp_het_job_offset, | 
 | 			 sizeof(tmp_het_job_offset),  "N/A"); | 
 | 	 } | 
 |  | 
 | 	if (!job_ptr->array_job_id) { | 
 | 		snprintf(tmp_array_job_id, | 
 | 			 sizeof(tmp_array_job_id),     "N/A"); | 
 | 		snprintf(tmp_array_task_id, | 
 | 			 sizeof(tmp_array_task_id),    "N/A"); | 
 | 	} | 
 |  | 
 | 	if (job_ptr->batch_flag) | 
 | 		tmp_batch = "yes"; | 
 | 	else | 
 | 		tmp_batch = "no"; | 
 |  | 
 | 	if (job_ptr->contiguous) | 
 | 		tmp_cont = "yes"; | 
 | 	else | 
 | 		tmp_cont = "no"; | 
 |  | 
 | 	if ((job_ptr->core_spec == NO_VAL16) || | 
 | 	    (job_ptr->core_spec & CORE_SPEC_THREAD)) { | 
 | 		sprintf(tmp_core_spec, "N/A"); | 
 | 	} else { | 
 | 		sprintf(tmp_core_spec, "%u", job_ptr->core_spec); | 
 | 	} | 
 | 	if ((job_ptr->core_spec == NO_VAL16) || | 
 | 	    ((job_ptr->core_spec & CORE_SPEC_THREAD) == 0)) { | 
 | 		sprintf(tmp_thread_spec, "N/A"); | 
 | 	} else { | 
 | 		sprintf(tmp_thread_spec, "%u", | 
 | 			job_ptr->core_spec & (~CORE_SPEC_THREAD)); | 
 | 	} | 
 |  | 
 |  | 
 | 	if (job_ptr->cpus_per_task == NO_VAL16) | 
 | 		sprintf(tmp_cpus_per_task, "N/A"); | 
 | 	else | 
 | 		sprintf(tmp_cpus_per_task, "%u", job_ptr->cpus_per_task); | 
 |  | 
 | 	snprintf(tmp_cpu_cnt, sizeof(tmp_cpu_cnt), "%u", job_ptr->num_cpus); | 
 | 	convert_num_unit((float)job_ptr->pn_min_cpus, tmp_cpu_req, | 
 | 			 sizeof(tmp_cpu_req), UNIT_NONE, NO_VAL, | 
 | 			 working_sview_config.convert_flags); | 
 |  | 
 | 	snprintf(tmp_cpus_max, sizeof(tmp_cpus_max), "%u", | 
 | 		 job_ptr->max_cpus); | 
 | 	convert_num_unit((float)job_ptr->pn_min_tmp_disk, tmp_disk, | 
 | 			 sizeof(tmp_disk), UNIT_MEGA, NO_VAL, | 
 | 			 working_sview_config.convert_flags); | 
 |  | 
 | 	if (WIFEXITED(job_ptr->derived_ec)) | 
 | 		term_code = WEXITSTATUS(job_ptr->derived_ec); | 
 | 	else | 
 | 		term_code = 0; | 
 | 	if (WIFSIGNALED(job_ptr->derived_ec)) | 
 | 		term_sig = WTERMSIG(job_ptr->derived_ec); | 
 | 	else | 
 | 		term_sig = 0; | 
 | 	snprintf(tmp_derived_ec, sizeof(tmp_derived_ec), "%u:%u", | 
 | 		 term_code, term_sig); | 
 |  | 
 | 	if (WIFEXITED(job_ptr->exit_code)) | 
 | 		term_code = WEXITSTATUS(job_ptr->exit_code); | 
 | 	else | 
 | 		term_code = 0; | 
 | 	if (WIFSIGNALED(job_ptr->exit_code)) | 
 | 		term_sig = WTERMSIG(job_ptr->exit_code); | 
 | 	else | 
 | 		term_sig = 0; | 
 | 	snprintf(tmp_exit, sizeof(tmp_exit), "%u:%u", term_code, term_sig); | 
 |  | 
 | 	tmp_gname = gid_to_string(job_ptr->group_id); | 
 |  | 
 | 	min_mem = job_ptr->pn_min_memory; | 
 | 	if (min_mem & MEM_PER_CPU) | 
 | 		min_mem &= (~MEM_PER_CPU); | 
 |  | 
 | 	if (min_mem > 0) { | 
 | 		int len; | 
 | 		convert_num_unit((float)min_mem, tmp_mem_min, | 
 | 				 sizeof(tmp_mem_min), UNIT_MEGA, NO_VAL, | 
 | 				 working_sview_config.convert_flags); | 
 | 		len = strlen(tmp_mem_min); | 
 | 		if (job_ptr->mem_per_tres) { | 
 | 			sprintf(tmp_mem_min+len, " Per TRES"); | 
 | 		} else if (job_ptr->pn_min_memory & MEM_PER_CPU) | 
 | 			sprintf(tmp_mem_min+len, " Per CPU"); | 
 | 		else | 
 | 			sprintf(tmp_mem_min+len, " Per Node"); | 
 | 	} else | 
 | 		sprintf(tmp_mem_min, " "); | 
 |  | 
 | 	sprintf(tmp_node_cnt, "%u", sview_job_info_ptr->node_cnt); | 
 |  | 
 | 	sprintf(tmp_nodes_min, "%u", sview_job_info_ptr->node_cnt); | 
 |  | 
 | 	if (job_ptr->state_desc) | 
 | 		tmp_reason = job_ptr->state_desc; | 
 | 	else | 
 | 		tmp_reason = job_state_reason_string(job_ptr->state_reason); | 
 |  | 
 | 	if (job_ptr->reboot) | 
 | 		tmp_reboot = "yes"; | 
 | 	else | 
 | 		tmp_reboot =  "no"; | 
 |  | 
 | 	if (job_ptr->requeue) | 
 | 		tmp_requeue = "yes"; | 
 | 	else | 
 | 		tmp_requeue =  "no"; | 
 |  | 
 | 	snprintf(tmp_nice, sizeof(tmp_nice), "%"PRIi64, | 
 | 		 (((int64_t)job_ptr->nice) - NICE_OFFSET)); | 
 |  | 
 | 	if (!job_ptr->nodes || IS_JOB_PENDING(job_ptr) || | 
 | 	    !xstrcasecmp(job_ptr->nodes,"waiting...")) { | 
 | 		sprintf(tmp_time_run,"00:00:00"); | 
 | 		tmp_nodes = xstrdup("waiting..."); | 
 | 	} else { | 
 | 		if (IS_JOB_SUSPENDED(job_ptr)) | 
 | 			now_time = job_ptr->pre_sus_time; | 
 | 		else { | 
 | 			if (!IS_JOB_RUNNING(job_ptr) && | 
 | 			    (job_ptr->end_time != 0)) | 
 | 				now_time = job_ptr->end_time; | 
 | 			if (job_ptr->suspend_time) { | 
 | 				now_time = (time_t) | 
 | 					(difftime(now_time, | 
 | 						  job_ptr->suspend_time) | 
 | 					 + job_ptr->pre_sus_time); | 
 | 			} else | 
 | 				now_time = (time_t)difftime( | 
 | 					now_time, job_ptr->start_time); | 
 | 		} | 
 | 		suspend_secs = (time(NULL) - job_ptr->start_time) - now_time; | 
 | 		secs2time_str(now_time, tmp_time_run, sizeof(tmp_time_run)); | 
 | 		tmp_nodes = slurm_sort_node_list_str(sview_job_info_ptr->nodes); | 
 | 	} | 
 |  | 
 | 	if (job_ptr->max_nodes > 0) | 
 | 		sprintf(tmp_nodes_max, "%u", sview_job_info_ptr->node_cnt); | 
 | 	else | 
 | 		tmp_nodes_max[0] = '\0'; | 
 |  | 
 | 	sprintf(tmp_prio, "%u", job_ptr->priority); | 
 |  | 
 | 	slurm_make_time_str((time_t *)&job_ptr->accrue_time, tmp_time_accrue, | 
 | 			    sizeof(tmp_time_accrue)); | 
 |  | 
 | 	slurm_make_time_str((time_t *)&job_ptr->eligible_time, tmp_time_elig, | 
 | 			    sizeof(tmp_time_elig)); | 
 |  | 
 | 	if ((job_ptr->time_limit == INFINITE) && | 
 | 	    (job_ptr->end_time > time(NULL))) | 
 | 		sprintf(tmp_time_end, "Unknown"); | 
 | 	else | 
 | 		slurm_make_time_str((time_t *)&job_ptr->end_time, tmp_time_end, | 
 | 				    sizeof(tmp_time_end)); | 
 |  | 
 | 	if (job_ptr->time_limit == NO_VAL) | 
 | 		sprintf(tmp_time_limit, "Partition Limit"); | 
 | 	else if (job_ptr->time_limit == INFINITE) | 
 | 		sprintf(tmp_time_limit, "Infinite"); | 
 | 	else | 
 | 		secs2time_str((job_ptr->time_limit * 60), | 
 | 			      tmp_time_limit, sizeof(tmp_time_limit)); | 
 |  | 
 | 	if (job_ptr->preempt_time) { | 
 | 		slurm_make_time_str((time_t *)&job_ptr->preempt_time, | 
 | 				    tmp_preempt_time, sizeof(tmp_preempt_time)); | 
 | 	} else | 
 | 		sprintf(tmp_preempt_time, "N/A"); | 
 |  | 
 | 	if (job_ptr->resize_time) { | 
 | 		slurm_make_time_str((time_t *)&job_ptr->resize_time, | 
 | 				    tmp_time_resize, sizeof(tmp_time_resize)); | 
 | 	} else | 
 | 		sprintf(tmp_time_resize, "N/A"); | 
 |  | 
 | 	slurm_make_time_str((time_t *)&job_ptr->start_time, tmp_time_start, | 
 | 			    sizeof(tmp_time_start)); | 
 |  | 
 | 	slurm_make_time_str((time_t *)&job_ptr->submit_time, tmp_time_submit, | 
 | 			    sizeof(tmp_time_submit)); | 
 |  | 
 | 	if (job_ptr->deadline) | 
 | 		slurm_make_time_str((time_t *)&job_ptr->deadline, | 
 | 				    tmp_time_deadline, | 
 | 				    sizeof(tmp_time_deadline)); | 
 | 	else | 
 | 		sprintf(tmp_time_deadline, "N/A"); | 
 |  | 
 | 	slurm_get_job_stderr(tmp_std_err, sizeof(tmp_std_err), job_ptr); | 
 |  | 
 | 	slurm_get_job_stdin(tmp_std_in, sizeof(tmp_std_in), job_ptr); | 
 |  | 
 | 	slurm_get_job_stdout(tmp_std_out, sizeof(tmp_std_out), job_ptr); | 
 |  | 
 | 	secs2time_str(suspend_secs, tmp_time_sus, sizeof(tmp_time_sus)); | 
 |  | 
 | 	if (job_ptr->req_switch != NO_VAL) { | 
 | 		if (job_ptr->wait4switch != NO_VAL) { | 
 | 			secs2time_str((time_t) job_ptr->wait4switch, time_buf, | 
 | 					sizeof(time_buf)); | 
 | 			sprintf(tmp_rqswitch, "%u@%s", | 
 | 					job_ptr->req_switch, time_buf); | 
 | 		} else { | 
 | 			sprintf(tmp_rqswitch, "%u", job_ptr->req_switch); | 
 | 		} | 
 |  | 
 | 	} else { | 
 | 		sprintf(tmp_rqswitch, "N/A"); | 
 | 	} | 
 |  | 
 | 	tmp_uname = uid_to_string_cached((uid_t)job_ptr->user_id); | 
 |  | 
 | 	if ((handle_pending || check_task) && | 
 | 	    (job_ptr->array_task_str || (job_ptr->array_task_id != NO_VAL) || | 
 | 	     job_ptr->het_job_id)) { | 
 | 		gtk_tree_store_set(treestore, iter, | 
 | 				   SORTID_ACCOUNT,      job_ptr->account, | 
 | 				   SORTID_ALLOC,        1, | 
 | 				   SORTID_ALLOC_NODE,   tmp_alloc_node, | 
 | 				   SORTID_ARRAY_JOB_ID, tmp_array_job_id, | 
 | 				   SORTID_ARRAY_TASK_ID,tmp_array_task_id, | 
 | 				   SORTID_BATCH,        tmp_batch, | 
 | 				   SORTID_BATCH_HOST,   job_ptr->batch_host, | 
 | 				   SORTID_BURST_BUFFER, job_ptr->burst_buffer, | 
 | 				   SORTID_CLUSTER_NAME, job_ptr->cluster, | 
 | 				   SORTID_COLOR, | 
 | 				   sview_colors[sview_job_info_ptr->color_inx], | 
 | 				   SORTID_COLOR_INX, | 
 | 				   sview_job_info_ptr->color_inx, | 
 | 				   SORTID_COMMAND,      job_ptr->command, | 
 | 				   SORTID_COMMENT,      job_ptr->comment, | 
 | 				   SORTID_CONTIGUOUS,   tmp_cont, | 
 | 				   SORTID_EXTRA, job_ptr->extra, | 
 | 				   SORTID_JOBID,        tmp_job_id, | 
 | 				   SORTID_JOBID_FORMATTED, tmp_job_id, | 
 | 				   SORTID_HET_JOB_ID,     tmp_het_job_id, | 
 | 				   SORTID_HET_JOB_ID_SET, tmp_het_job_id_set, | 
 | 				   SORTID_HET_JOB_OFFSET, tmp_het_job_offset, | 
 | 				   SORTID_PARTITION,    job_ptr->partition, | 
 | 				   SORTID_UPDATED,      1, | 
 | 				   SORTID_USER_ID,      tmp_uname, | 
 | 				   -1); | 
 | 		if (handle_pending) | 
 | 			gtk_tree_store_set(treestore, iter, | 
 | 					   SORTID_ACCOUNT, job_ptr->account, | 
 | 					   SORTID_STATE, | 
 | 					   job_state_string(JOB_PENDING), | 
 | 					   -1); | 
 | 	} else { | 
 | 		gtk_tree_store_set(treestore, iter, | 
 | 				   SORTID_ACCOUNT,      job_ptr->account, | 
 | 				   SORTID_ALLOC,        1, | 
 | 				   SORTID_ALLOC_NODE,   tmp_alloc_node, | 
 | 				   SORTID_ARRAY_JOB_ID, tmp_array_job_id, | 
 | 				   SORTID_ARRAY_TASK_ID,tmp_array_task_id, | 
 | 				   SORTID_BATCH,        tmp_batch, | 
 | 				   SORTID_BATCH_HOST,   job_ptr->batch_host, | 
 | 				   SORTID_BURST_BUFFER, job_ptr->burst_buffer, | 
 | 				   SORTID_CLUSTER_NAME, job_ptr->cluster, | 
 | 				   SORTID_COLOR, | 
 | 				   sview_colors[sview_job_info_ptr->color_inx], | 
 | 				   SORTID_COLOR_INX, | 
 | 				   sview_job_info_ptr->color_inx, | 
 | 				   SORTID_COMMAND,      job_ptr->command, | 
 | 				   SORTID_COMMENT,      job_ptr->comment, | 
 | 				   SORTID_CONTIGUOUS,   tmp_cont, | 
 | 				   SORTID_CORE_SPEC,    tmp_core_spec, | 
 | 				   SORTID_CPUS,         tmp_cpu_cnt, | 
 | 				   SORTID_CPU_MAX,      tmp_cpus_max, | 
 | 				   SORTID_CPU_MIN,      tmp_cpu_cnt, | 
 | 				   SORTID_CPUS_PER_TASK,tmp_cpus_per_task, | 
 | 				   SORTID_CPUS_PER_TRES,job_ptr->cpus_per_tres, | 
 | 				   SORTID_CPU_REQ,      tmp_cpu_req, | 
 | 				   SORTID_DEADLINE,     tmp_time_deadline, | 
 | 				   SORTID_DEPENDENCY,   job_ptr->dependency, | 
 | 				   SORTID_DERIVED_EC,   tmp_derived_ec, | 
 | 				   SORTID_EXIT_CODE,    tmp_exit, | 
 | 				   SORTID_EXTRA, job_ptr->extra, | 
 | 				   SORTID_FEATURES,     job_ptr->features, | 
 | 				   SORTID_PREFER, job_ptr->prefer, | 
 | 				   SORTID_FED_ACTIVE_SIBS, | 
 | 				   job_ptr->fed_siblings_active_str, | 
 | 				   SORTID_FED_ORIGIN,   job_ptr->fed_origin_str, | 
 | 				   SORTID_FED_VIABLE_SIBS, | 
 | 				   job_ptr->fed_siblings_viable_str, | 
 | 				   SORTID_GROUP_ID, tmp_gname, | 
 | 				   SORTID_JOBID,        tmp_job_id, | 
 | 				   SORTID_JOBID_FORMATTED, tmp_job_id, | 
 | 				   SORTID_LICENSES,     job_ptr->licenses, | 
 | 				   SORTID_MCS_LABEL,	job_ptr->mcs_label, | 
 | 				   SORTID_MEM_MIN,      tmp_mem_min, | 
 | 				   SORTID_MEM_PER_TRES, job_ptr->cpus_per_tres, | 
 | 				   SORTID_NAME,         job_ptr->name, | 
 | 				   SORTID_NICE,         tmp_nice, | 
 | 				   SORTID_NODE_INX,     job_ptr->node_inx, | 
 | 				   SORTID_NODELIST,     tmp_nodes, | 
 | 				   SORTID_NODELIST_EXC, job_ptr->exc_nodes, | 
 | 				   SORTID_NODELIST_REQ, job_ptr->req_nodes, | 
 | 				   SORTID_NODELIST_SCHED, | 
 | 				   job_ptr->sched_nodes, | 
 | 				   SORTID_NODES,        tmp_node_cnt, | 
 | 				   SORTID_NODES_MAX,    tmp_nodes_max, | 
 | 				   SORTID_NODES_MIN,    tmp_nodes_min, | 
 | 				   SORTID_OVER_SUBSCRIBE, | 
 | 				   job_share_string(job_ptr->shared), | 
 | 				   SORTID_HET_JOB_ID,     tmp_het_job_id, | 
 | 				   SORTID_HET_JOB_ID_SET, tmp_het_job_id_set, | 
 | 				   SORTID_HET_JOB_OFFSET, tmp_het_job_offset, | 
 | 				   SORTID_PARTITION,    job_ptr->partition, | 
 | 				   SORTID_PREEMPT_TIME, tmp_preempt_time, | 
 | 				   SORTID_PRIORITY,     tmp_prio, | 
 | 				   SORTID_QOS,          job_ptr->qos, | 
 | 				   SORTID_REASON,       tmp_reason, | 
 | 				   SORTID_REBOOT,       tmp_reboot, | 
 | 				   SORTID_REQUEUE,      tmp_requeue, | 
 | 				   SORTID_RESTARTS,     job_ptr->restart_cnt, | 
 | 				   SORTID_RESV_NAME,    job_ptr->resv_name, | 
 | 				   SORTID_STATE, | 
 | 				   job_state_string(job_ptr->job_state), | 
 | 				   SORTID_STATE_NUM,    job_ptr->job_state, | 
 | 				   SORTID_STD_ERR,      tmp_std_err, | 
 | 				   SORTID_STD_IN,       tmp_std_in, | 
 | 				   SORTID_STD_OUT,      tmp_std_out, | 
 | 				   SORTID_SWITCHES,     tmp_rqswitch, | 
 | 				   SORTID_THREAD_SPEC,  tmp_thread_spec, | 
 | 				   SORTID_TIME_ACCRUE,  tmp_time_accrue, | 
 | 				   SORTID_TIME_ELIGIBLE,tmp_time_elig, | 
 | 				   SORTID_TIME_END,     tmp_time_end, | 
 | 				   SORTID_TIME_RESIZE,  tmp_time_resize, | 
 | 				   SORTID_TIME_RUNNING, tmp_time_run, | 
 | 				   SORTID_TIME_START,   tmp_time_start, | 
 | 				   SORTID_TIME_SUBMIT,  tmp_time_submit, | 
 | 				   SORTID_TIME_SUSPEND, tmp_time_sus, | 
 | 				   SORTID_TIMELIMIT,    tmp_time_limit, | 
 | 				   SORTID_TMP_DISK,     tmp_disk, | 
 | 				   SORTID_TRES_ALLOC,   job_ptr->tres_alloc_str, | 
 | 				   SORTID_TRES_BIND,    job_ptr->tres_bind, | 
 | 				   SORTID_TRES_FREQ,    job_ptr->tres_freq, | 
 | 				   SORTID_TRES_PER_JOB, job_ptr->tres_per_job, | 
 | 				   SORTID_TRES_PER_NODE,job_ptr->tres_per_node, | 
 | 				   SORTID_TRES_PER_SOCKET, | 
 | 				   job_ptr->tres_per_socket, | 
 | 				   SORTID_TRES_PER_TASK,job_ptr->tres_per_task, | 
 | 				   SORTID_UPDATED,      1, | 
 | 				   SORTID_USER_ID,      tmp_uname, | 
 | 				   SORTID_WCKEY,        job_ptr->wckey, | 
 | 				   SORTID_WORKDIR,      job_ptr->work_dir, | 
 | 				   -1); | 
 | 	} | 
 |  | 
 | 	gtk_tree_store_set(treestore, iter, | 
 | 			   SORTID_NETWORK, job_ptr->network, -1); | 
 |  | 
 | 	if (check_task && | 
 | 	    (job_ptr->array_task_str || | 
 | 	     ((job_ptr->array_task_id != NO_VAL) || job_ptr->het_job_id))) { | 
 | 		if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), | 
 | 						 &step_iter, | 
 | 						 iter)) | 
 | 			_update_info_task(sview_job_info_ptr, | 
 | 					  GTK_TREE_MODEL(treestore), &step_iter, | 
 | 					  iter, false); | 
 | 		else | 
 | 			_update_info_task(sview_job_info_ptr, | 
 | 					  GTK_TREE_MODEL(treestore), NULL, | 
 | 					  iter, false); | 
 | 	} else if (handle_pending && | 
 | 		   (job_ptr->array_task_str || | 
 | 		    (job_ptr->array_task_id != NO_VAL || | 
 | 		     job_ptr->het_job_id))) { | 
 | 		if (gtk_tree_model_iter_children(GTK_TREE_MODEL(treestore), | 
 | 						 &step_iter, | 
 | 						 iter)) | 
 | 			_update_info_task(sview_job_info_ptr, | 
 | 					  GTK_TREE_MODEL(treestore), &step_iter, | 
 | 					  iter, true); | 
 | 		else | 
 | 			_update_info_task(sview_job_info_ptr, | 
 | 					  GTK_TREE_MODEL(treestore), NULL, | 
 | 					  iter, true); | 
 | 	} else { | 
 | 		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); | 
 | 	} | 
 |  | 
 | 	xfree(tmp_gname); | 
 | 	xfree(tmp_nodes); | 
 |  | 
 | 	return; | 
 | } | 
 |  | 
 | static int _id_from_stepstr(char *str) { | 
 | 	char *end = NULL; | 
 | 	int id = strtol(str, &end, 10); | 
 | 	/* if no digits found, it must be text */ | 
 | 	if (end == str) { | 
 | 		if (!strcasecmp(str, "TBD")) | 
 | 			id = SLURM_PENDING_STEP; | 
 | 		else if (!strcasecmp(str, "Batch")) | 
 | 			id = SLURM_BATCH_SCRIPT; | 
 | 		else if (!strcasecmp(str, "Extern")) | 
 | 			id = SLURM_EXTERN_CONT; | 
 | 		else if (!strcasecmp(str, "Interactive")) | 
 | 			id = SLURM_INTERACTIVE_STEP; | 
 | 		else | 
 | 			id = NO_VAL; | 
 | 	} | 
 | 	return id; | 
 | } | 
 |  | 
 | static void _stepstr_from_step(job_step_info_t *step_ptr, char *dest, | 
 | 			       uint32_t len) { | 
 | 	if (step_ptr->step_id.step_id == SLURM_PENDING_STEP) | 
 | 		snprintf(dest, len, "TBD"); | 
 | 	else if (step_ptr->step_id.step_id == SLURM_EXTERN_CONT) | 
 | 		snprintf(dest, len, "Extern"); | 
 | 	else if (step_ptr->step_id.step_id == SLURM_INTERACTIVE_STEP) | 
 | 		snprintf(dest, len, "Interactive"); | 
 | 	else if (step_ptr->step_id.step_id == SLURM_BATCH_SCRIPT) | 
 | 		snprintf(dest, len, "Batch"); | 
 | 	else | 
 | 		snprintf(dest, len, "%u", | 
 | 			 step_ptr->step_id.step_id); | 
 | } | 
 |  | 
 | static void _layout_step_record(GtkTreeView *treeview, | 
 | 				job_step_info_t *step_ptr, | 
 | 				int update, bool suspended) | 
 | { | 
 | 	char *uname; | 
 | 	char *tmp_nodes; | 
 | 	char tmp_char[100], tmp_str[50], tmp_time[50]; | 
 | 	GtkTreeIter iter; | 
 | 	uint32_t state; | 
 | 	GtkTreeStore *treestore = | 
 | 		GTK_TREE_STORE(gtk_tree_view_get_model(treeview)); | 
 |  | 
 | 	if (!treestore) | 
 | 		return; | 
 |  | 
 | 	convert_num_unit((float)step_ptr->num_cpus, tmp_char, sizeof(tmp_char), | 
 | 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_CPUS), | 
 | 				   tmp_char); | 
 |  | 
 | 	uname = uid_to_string_cached((uid_t)step_ptr->user_id); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_USER_ID), uname); | 
 |  | 
 | 	if (step_ptr->array_job_id) { | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u_%u.%u (%u.%u)", | 
 | 			 step_ptr->array_job_id, step_ptr->array_task_id, | 
 | 			 step_ptr->step_id.step_id, | 
 | 			 step_ptr->step_id.job_id, step_ptr->step_id.step_id); | 
 | //	} else if (step_ptr->het_job_id) { | 
 | //		snprintf(tmp_char, sizeof(tmp_char), "%u+%u.%u (%u.%u)", | 
 | //			 step_ptr->het_job_id, step_ptr->het_job_offset, | 
 | //			 step_ptr->step_id.step_id, | 
 | //			 step_ptr->step_id.job_id, step_ptr->step_id.step_id); | 
 | 	} else { | 
 | 		_stepstr_from_step(step_ptr, tmp_str, sizeof(tmp_str)); | 
 | 		snprintf(tmp_char, sizeof(tmp_char), "%u.%s", | 
 | 			 step_ptr->step_id.job_id, tmp_str); | 
 | 	} | 
 | 	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_CPUS_PER_TRES), | 
 | 				   step_ptr->cpus_per_tres); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_MEM_PER_TRES), | 
 | 				   step_ptr->mem_per_tres); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_BIND), | 
 | 				   step_ptr->tres_bind); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_FREQ), | 
 | 				   step_ptr->tres_freq); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_JOB), | 
 | 				   step_ptr->tres_per_step); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_NODE), | 
 | 				   step_ptr->tres_per_node); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_SOCKET), | 
 | 				   step_ptr->tres_per_socket); | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TRES_PER_TASK), | 
 | 				   step_ptr->tres_per_task); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NAME), | 
 | 				   step_ptr->name); | 
 |  | 
 |  | 
 | 	if (suspended) | 
 | 		state = JOB_SUSPENDED; | 
 | 	else | 
 | 		state = step_ptr->state; | 
 |  | 
 | 	if (!step_ptr->nodes | 
 | 	    || !xstrcasecmp(step_ptr->nodes, "waiting...")) { | 
 | 		sprintf(tmp_time,"00:00:00"); | 
 | 		tmp_nodes = xstrdup("waiting..."); | 
 | 		state = JOB_PENDING; | 
 | 	} else { | 
 | 		secs2time_str(step_ptr->run_time, tmp_time, sizeof(tmp_time)); | 
 | 		tmp_nodes = slurm_sort_node_list_str(step_ptr->nodes); | 
 | 		convert_num_unit((float)_nodes_in_list(tmp_nodes), | 
 | 				 tmp_char, sizeof(tmp_char), UNIT_NONE, | 
 | 				 NO_VAL, | 
 | 				 working_sview_config.convert_flags); | 
 | 		add_display_treestore_line(update, treestore, &iter, | 
 | 					   find_col_name(display_data_job, | 
 | 							 SORTID_NODES), | 
 | 					   tmp_char); | 
 | 	} | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_NODELIST), | 
 | 				   tmp_nodes); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_PARTITION), | 
 | 				   step_ptr->partition); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_STATE), | 
 | 				   job_state_string(state)); | 
 |  | 
 | 	if (step_ptr->time_limit == NO_VAL) | 
 | 		sprintf(tmp_char, "Partition Limit"); | 
 | 	else if (step_ptr->time_limit == INFINITE) | 
 | 		sprintf(tmp_char, "Infinite"); | 
 | 	else | 
 | 		secs2time_str((step_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); | 
 |  | 
 | 	add_display_treestore_line(update, treestore, &iter, | 
 | 				   find_col_name(display_data_job, | 
 | 						 SORTID_TIME_RUNNING), | 
 | 				   tmp_time); | 
 |  | 
 | 	convert_num_unit((float)step_ptr->num_tasks, tmp_char, sizeof(tmp_char), | 
 | 			 UNIT_NONE, NO_VAL, working_sview_config.convert_flags); | 
 | 	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_TRES_ALLOC), | 
 | 				   step_ptr->tres_fmt_alloc_str); | 
 |  | 
 | 	xfree(tmp_nodes); | 
 | } | 
 |  | 
 | static void _update_step_record(job_step_info_t *step_ptr, | 
 | 				GtkTreeStore *treestore, | 
 | 				GtkTreeIter *iter, bool suspended) | 
 | { | 
 | 	char *tmp_uname; | 
 | 	char *tmp_nodes; | 
 | 	char tmp_cpu_min[40],  tmp_time_run[40],   tmp_time_limit[40]; | 
 | 	char tmp_node_cnt[40], tmp_time_start[256], tmp_task_cnt[40]; | 
 | 	char tmp_step_id[40], tmp_job_id[400]; | 
 | 	char tmp_fmt_stepid[40]; | 
 | 	uint32_t state; | 
 | 	int color_inx = step_ptr->step_id.step_id % sview_colors_cnt; | 
 |  | 
 | 	convert_num_unit((float)step_ptr->num_cpus, tmp_cpu_min, | 
 | 			 sizeof(tmp_cpu_min), UNIT_NONE, NO_VAL, | 
 | 			 working_sview_config.convert_flags); | 
 |  | 
 | 	if (suspended) | 
 | 		state = JOB_SUSPENDED; | 
 | 	else | 
 | 		state = step_ptr->state; | 
 |  | 
 | 	if (!step_ptr->nodes || | 
 | 	    !xstrcasecmp(step_ptr->nodes,"waiting...")) { | 
 | 		sprintf(tmp_time_run, "00:00:00"); | 
 | 		tmp_nodes = xstrdup("waiting..."); | 
 | 		tmp_node_cnt[0] = '\0'; | 
 | 		state = JOB_PENDING; | 
 | 	} else { | 
 | 		secs2time_str(step_ptr->run_time, | 
 | 			      tmp_time_run, sizeof(tmp_time_run)); | 
 | 		tmp_nodes = slurm_sort_node_list_str(step_ptr->nodes); | 
 | 		convert_num_unit((float)_nodes_in_list(tmp_nodes), | 
 | 				 tmp_node_cnt, sizeof(tmp_node_cnt), | 
 | 				 UNIT_NONE, NO_VAL, | 
 | 				 working_sview_config.convert_flags); | 
 | 	} | 
 |  | 
 | 	convert_num_unit((float)step_ptr->num_tasks, tmp_task_cnt, | 
 | 			 sizeof(tmp_task_cnt), UNIT_NONE, NO_VAL, | 
 | 			 working_sview_config.convert_flags); | 
 |  | 
 | 	if ((step_ptr->time_limit == NO_VAL) || | 
 | 	    (step_ptr->time_limit == INFINITE)) { | 
 | 		sprintf(tmp_time_limit, "Job Limit"); | 
 | 	} else { | 
 | 		secs2time_str((step_ptr->time_limit * 60), | 
 | 			      tmp_time_limit, sizeof(tmp_time_limit)); | 
 | 	} | 
 |  | 
 | 	slurm_make_time_str((time_t *)&step_ptr->start_time, tmp_time_start, | 
 | 			    sizeof(tmp_time_start)); | 
 |  | 
 | 	_stepstr_from_step(step_ptr, tmp_fmt_stepid, sizeof(tmp_fmt_stepid)); | 
 | 	snprintf(tmp_step_id, sizeof(tmp_step_id), "%u", | 
 | 		 step_ptr->step_id.step_id); | 
 |  | 
 | 	if (step_ptr->array_job_id) { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id), "%u_%u.%u (%u.%u)", | 
 | 			 step_ptr->array_job_id, step_ptr->array_task_id, | 
 | 			 step_ptr->step_id.step_id, | 
 | 			 step_ptr->step_id.job_id, step_ptr->step_id.step_id); | 
 | //	} else if (step_ptr->het_job_id) { | 
 | //		snprintf(tmp_job_id, sizeof(tmp_job_id), "%u+%u.%u (%u.%u)", | 
 | //			 step_ptr->het_job_id, step_ptr->het_job_offset, | 
 | //			 step_ptr->step_id.step_id, | 
 | //			 step_ptr->step_id.job_id, step_ptr->step_id.step_id); | 
 | 	} else { | 
 | 		snprintf(tmp_job_id, sizeof(tmp_job_id), "%u.%s", | 
 | 			 step_ptr->step_id.job_id, tmp_fmt_stepid); | 
 | 	} | 
 |  | 
 | 	tmp_uname = uid_to_string_cached((uid_t)step_ptr->user_id); | 
 |  | 
 | 	gtk_tree_store_set(treestore, iter, | 
 | 			   SORTID_ALLOC,        0, | 
 | 			   SORTID_COLOR,	sview_colors[color_inx], | 
 | 			   SORTID_COLOR_INX,    color_inx, | 
 | 			   SORTID_CPUS,         tmp_cpu_min, | 
 | 			   SORTID_CPUS_PER_TRES, step_ptr->cpus_per_tres, | 
 | 			   SORTID_JOBID,        tmp_fmt_stepid, | 
 | 			   SORTID_JOBID_FORMATTED, tmp_job_id, | 
 | 			   SORTID_MEM_PER_TRES,	step_ptr->mem_per_tres, | 
 | 			   SORTID_NAME,         step_ptr->name, | 
 | 			   SORTID_NODE_INX,     step_ptr->node_inx, | 
 | 			   SORTID_NODELIST,     tmp_nodes, | 
 | 			   SORTID_NODES,        tmp_node_cnt, | 
 | 			   SORTID_PARTITION,    step_ptr->partition, | 
 | 			   SORTID_STATE,        job_state_string(state), | 
 | 			   SORTID_TASKS,        tmp_task_cnt, | 
 | 			   SORTID_TIME_RUNNING, tmp_time_run, | 
 | 			   SORTID_TIME_START,   tmp_time_start, | 
 | 			   SORTID_TIMELIMIT,    tmp_time_limit, | 
 | 			   SORTID_TRES_ALLOC,   step_ptr->tres_fmt_alloc_str, | 
 | 			   SORTID_TRES_BIND,	step_ptr->tres_bind, | 
 | 			   SORTID_TRES_FREQ,	step_ptr->tres_freq, | 
 | 			   SORTID_TRES_PER_JOB,	step_ptr->tres_per_step, | 
 | 			   SORTID_TRES_PER_NODE, step_ptr->tres_per_node, | 
 | 			   SORTID_TRES_PER_SOCKET, step_ptr->tres_per_socket, | 
 | 			   SORTID_TRES_PER_TASK, step_ptr->tres_per_task, | 
 | 			   SORTID_UPDATED,      1, | 
 | 			   SORTID_USER_ID,      tmp_uname, | 
 | 			   -1); | 
 |  | 
 | 	xfree(tmp_nodes); | 
 |  | 
 | 	return; | 
 | } | 
 |  | 
 | static void _append_job_record(sview_job_info_t *sview_job_info_ptr, | 
 | 			       GtkTreeStore *treestore) | 
 | { | 
 | 	gtk_tree_store_append(treestore, &sview_job_info_ptr->iter_ptr, NULL); | 
 | 	gtk_tree_store_set(treestore, &sview_job_info_ptr->iter_ptr, SORTID_POS, | 
 | 			   sview_job_info_ptr->pos, -1); | 
 | 	_update_job_record(sview_job_info_ptr, treestore, NULL, true, false); | 
 | } | 
 |  | 
 | static void _append_task_record(sview_job_info_t *sview_job_info_ptr, | 
 | 				GtkTreeStore *treestore, GtkTreeIter *iter, | 
 | 				bool handle_pending) | 
 | { | 
 | 	GtkTreeIter task_iter; | 
 |  | 
 | 	gtk_tree_store_append(treestore, &task_iter, iter); | 
 | 	gtk_tree_store_set(treestore, &task_iter, SORTID_POS, | 
 | 			   sview_job_info_ptr->pos, -1); | 
 | 	_update_job_record(sview_job_info_ptr, treestore, &task_iter, false, | 
 | 			   handle_pending); | 
 | } | 
 |  | 
 |  | 
 | static void _append_step_record(job_step_info_t *step_ptr, | 
 | 				GtkTreeStore *treestore, GtkTreeIter *iter, | 
 | 				int jobid, bool suspended) | 
 | { | 
 | 	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, suspended); | 
 | } | 
 |  | 
 | static void _handle_task_check(sview_job_info_t *task_ptr, | 
 | 			       GtkTreeModel *model, | 
 | 			       GtkTreeIter **task_iter, | 
 | 			       GtkTreeIter *first_task_iter, | 
 | 			       GtkTreeIter *iter, | 
 | 			       bool handle_pending) | 
 | { | 
 | 	/* get the iter, or find out the list is empty goto add */ | 
 | 	if (!*task_iter) | 
 | 		goto adding; | 
 | 	else | 
 | 		memcpy(*task_iter, first_task_iter, sizeof(GtkTreeIter)); | 
 |  | 
 | 	while (1) { | 
 | 		char *tmp_taskid, *use_id; | 
 | 		/* search for the jobid and check to see if | 
 | 		 * it is in the list */ | 
 | 		gtk_tree_model_get(model, *task_iter, SORTID_JOBID, | 
 | 				   &tmp_taskid, -1); | 
 |  | 
 | 		if (handle_pending) | 
 | 			use_id = task_ptr->task_pending_hl_str; | 
 | 		else | 
 | 			use_id = task_ptr->job_id_str; | 
 |  | 
 | 		if (tmp_taskid && use_id && !xstrcmp(tmp_taskid, use_id)) { | 
 | 			/* update with new info */ | 
 | 			_update_job_record(task_ptr, | 
 | 					   GTK_TREE_STORE(model), | 
 | 					   *task_iter, false, handle_pending); | 
 | 			g_free(tmp_taskid); | 
 | 			goto found; | 
 | 		} | 
 | 		g_free(tmp_taskid); | 
 |  | 
 | 		if (!gtk_tree_model_iter_next(model, *task_iter)) { | 
 | 			*task_iter = NULL; | 
 | 			break; | 
 | 		} | 
 | 	} | 
 | adding: | 
 | 	_append_task_record(task_ptr, GTK_TREE_STORE(model), | 
 | 			    iter, handle_pending); | 
 | found: | 
 | 	return; | 
 |  | 
 |  | 
 | } | 
 |  | 
 |  | 
 | static void _update_info_task(sview_job_info_t *sview_job_info_ptr, | 
 | 			      GtkTreeModel *model, | 
 | 			      GtkTreeIter *task_iter, | 
 | 			      GtkTreeIter *iter, bool handle_pending) | 
 | { | 
 | 	int i; | 
 | 	GtkTreeIter first_task_iter; | 
 | 	int set = 0; | 
 | 	list_itr_t *itr = NULL; | 
 | 	sview_job_info_t *task_ptr = NULL; | 
 |  | 
 | 	memset(&first_task_iter, 0, sizeof(GtkTreeIter)); | 
 |  | 
 | 	/* make sure all the tasks are still here */ | 
 | 	if (task_iter) { | 
 | 		first_task_iter = *task_iter; | 
 | 		while (1) { | 
 | 			gtk_tree_store_set(GTK_TREE_STORE(model), task_iter, | 
 | 					   SORTID_UPDATED, 0, -1); | 
 | 			if (!gtk_tree_model_iter_next(model, task_iter)) { | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 		memcpy(task_iter, &first_task_iter, sizeof(GtkTreeIter)); | 
 | 		set = 1; | 
 | 	} | 
 | 	if (handle_pending) | 
 | 		itr = list_iterator_create( | 
 | 			sview_job_info_ptr->task_pending_list); | 
 | 	else { | 
 | 		/* First handle the pending list if one exists.  This | 
 | 		   will make a dummy job record that holds all the | 
 | 		   pending jobs. | 
 | 		*/ | 
 | 		if (sview_job_info_ptr->task_pending_list && | 
 | 		    list_count(sview_job_info_ptr->task_pending_list)) | 
 | 			_handle_task_check(sview_job_info_ptr, model, | 
 | 					   &task_iter, &first_task_iter, | 
 | 					   iter, true); | 
 | 		itr = list_iterator_create(sview_job_info_ptr->task_list); | 
 | 	} | 
 | 	while ((task_ptr = list_next(itr))) | 
 | 		_handle_task_check(task_ptr, model, &task_iter, | 
 | 				   &first_task_iter, iter, false); | 
 | 	list_iterator_destroy(itr); | 
 |  | 
 | 	if (set) { | 
 | 		task_iter = &first_task_iter; | 
 | 		/* clear all tasks that aren't active */ | 
 | 		while (1) { | 
 | 			gtk_tree_model_get(model, task_iter, | 
 | 					   SORTID_UPDATED, &i, -1); | 
 | 			if (!i) { | 
 | 				if (!gtk_tree_store_remove( | 
 | 					    GTK_TREE_STORE(model), | 
 | 					    task_iter)) | 
 | 					break; | 
 | 				else | 
 | 					continue; | 
 | 			} | 
 | 			if (!gtk_tree_model_iter_next(model, task_iter)) { | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	return; | 
 | } | 
 |  | 
 | 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; | 
 | 	list_itr_t *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) { | 
 | 			char *tmp_stepid; | 
 | 			/* search for the jobid and check to see if | 
 | 			 * it is in the list */ | 
 | 			gtk_tree_model_get(model, step_iter, SORTID_JOBID, | 
 | 					   &tmp_stepid, -1); | 
 | 			stepid = atoi(tmp_stepid); | 
 | 			g_free(tmp_stepid); | 
 | 			if (stepid == (int)step_ptr->step_id.step_id) { | 
 | 				/* update with new info */ | 
 | 				_update_step_record( | 
 | 					step_ptr, GTK_TREE_STORE(model), | 
 | 					step_iter, IS_JOB_SUSPENDED( | 
 | 						sview_job_info_ptr->job_ptr)); | 
 | 				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, | 
 | 				    IS_JOB_SUSPENDED( | 
 | 					    sview_job_info_ptr->job_ptr)); | 
 | 	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_t *info_list, GtkTreeView *tree_view) | 
 | { | 
 | 	GtkTreeModel *model = gtk_tree_view_get_model(tree_view); | 
 | 	int jobid = 0; | 
 | 	job_info_t *job_ptr = NULL; | 
 | 	list_itr_t *itr = NULL; | 
 | 	sview_job_info_t *sview_job_info = NULL; | 
 |  | 
 | 	set_for_update(model, SORTID_UPDATED); | 
 |  | 
 | 	itr = list_iterator_create(info_list); | 
 | 	while ((sview_job_info = list_next(itr))) { | 
 | 		job_ptr = sview_job_info->job_ptr; | 
 |  | 
 | 		/* This means the tree_store changed (added new column | 
 | 		 * or something). */ | 
 | 		if (last_model != model) | 
 | 			sview_job_info->iter_set = false; | 
 |  | 
 | 		if (sview_job_info->iter_set) { | 
 | 			char *tmp_jobid = NULL, *offset = NULL; | 
 | 			gtk_tree_model_get(model, &sview_job_info->iter_ptr, | 
 | 					   SORTID_JOBID, &tmp_jobid, -1); | 
 | 			if (!tmp_jobid) | 
 | 				continue; | 
 |  | 
 | 			offset = strchr(tmp_jobid, '('); | 
 | 			if (offset) | 
 | 				offset++; | 
 | 			else | 
 | 				offset = tmp_jobid; | 
 | 			jobid = atoi(offset); | 
 | 			g_free(tmp_jobid); | 
 |  | 
 | 			if ((jobid != job_ptr->job_id) | 
 | 			    && (jobid != job_ptr->array_job_id) && | 
 | 				(jobid != job_ptr->het_job_id)) { | 
 | 				/* Bad pointer */ | 
 | 				sview_job_info->iter_set = false; | 
 | 			} | 
 | 		} | 
 | 		if (sview_job_info->iter_set) | 
 | 			_update_job_record(sview_job_info, | 
 | 					   GTK_TREE_STORE(model), NULL, true, | 
 | 					   false); | 
 | 		else { | 
 | 			_append_job_record(sview_job_info, | 
 | 					   GTK_TREE_STORE(model)); | 
 | 			sview_job_info->iter_set = true; | 
 | 		} | 
 | 	} | 
 | 	list_iterator_destroy(itr); | 
 |  | 
 | 	/* remove all old jobs */ | 
 | 	remove_old(model, SORTID_UPDATED); | 
 | 	last_model = model; | 
 | 	return; | 
 | } | 
 |  | 
 | static int _sview_job_sort_aval_dec(void *s1, void *s2) | 
 | { | 
 | 	sview_job_info_t* rec_a = *(sview_job_info_t **)s1; | 
 | 	sview_job_info_t* rec_b = *(sview_job_info_t **)s2; | 
 | 	int size_a; | 
 | 	int size_b; | 
 |  | 
 | 	size_a = rec_a->node_cnt; | 
 | 	size_b = rec_b->node_cnt; | 
 |  | 
 | 	if (size_a < size_b) | 
 | 		return -1; | 
 | 	else if (size_a > size_b) | 
 | 		return 1; | 
 |  | 
 | 	if (rec_a->nodes && rec_b->nodes) { | 
 | 		size_a = xstrcmp(rec_a->nodes, rec_b->nodes); | 
 | 		if (size_a < 0) | 
 | 			return -1; | 
 | 		else if (size_a > 0) | 
 | 			return 1; | 
 | 	} | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int _task_array_match(void *x, void *key) | 
 | { | 
 | 	sview_job_info_t *sview_job_info_ptr = (sview_job_info_t *) x; | 
 | 	job_info_t *job_ptr = (job_info_t *) key; | 
 |  | 
 | 	if (sview_job_info_ptr->job_ptr->array_job_id  == job_ptr->array_job_id) | 
 | 		return 1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int _het_job_id_match(void *x, void *key) | 
 | { | 
 | 	sview_job_info_t *sview_job_info_ptr = (sview_job_info_t *) x; | 
 | 	job_info_t *job_ptr = (job_info_t *) key; | 
 |  | 
 | 	if (sview_job_info_ptr->job_ptr->het_job_id  == job_ptr->het_job_id) | 
 | 		return 1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static list_t *_create_job_info_list(job_info_msg_t *job_info_ptr, | 
 | 				     job_step_info_response_msg_t *step_info_ptr, | 
 | 				     int want_odd_states) | 
 | { | 
 | 	static list_t *info_list = NULL; | 
 | 	static list_t *odd_info_list = NULL; | 
 | 	list_t *last_list = NULL; | 
 | 	list_itr_t *last_list_itr = NULL; | 
 | 	static job_info_msg_t *last_job_info_ptr = NULL; | 
 | 	static job_step_info_response_msg_t *last_step_info_ptr = 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; | 
 |  | 
 | 	if (info_list && (job_info_ptr == last_job_info_ptr) | 
 | 	    && (step_info_ptr == last_step_info_ptr)) | 
 | 		goto update_color; | 
 |  | 
 | 	last_job_info_ptr = job_info_ptr; | 
 | 	last_step_info_ptr = step_info_ptr; | 
 |  | 
 | 	if (info_list) { | 
 | 		list_flush(info_list); | 
 | 		last_list = odd_info_list; | 
 | 		odd_info_list = list_create(_job_info_list_del); | 
 | 	} else { | 
 | 		info_list = list_create(NULL); | 
 | 		odd_info_list = list_create(_job_info_list_del); | 
 | 	} | 
 | 	if (last_list) | 
 | 		last_list_itr = list_iterator_create(last_list); | 
 | 	for (i=0; i<job_info_ptr->record_count; i++) { | 
 | 		bool added_task = false; | 
 |  | 
 | 		job_ptr = &(job_info_ptr->job_array[i]); | 
 | 		if (job_ptr->job_id == 0) | 
 | 			continue; | 
 |  | 
 | 		sview_job_info_ptr = NULL; | 
 |  | 
 | 		if (last_list_itr) { | 
 | 			while ((sview_job_info_ptr = | 
 | 				list_next(last_list_itr))) { | 
 | 				if (sview_job_info_ptr->job_id == | 
 | 				    job_ptr->job_id) { | 
 | 					list_remove(last_list_itr); | 
 | 					_job_info_free(sview_job_info_ptr); | 
 | 					break; | 
 | 				} | 
 | 			} | 
 | 			list_iterator_reset(last_list_itr); | 
 | 		} | 
 |  | 
 | 		if (!sview_job_info_ptr) | 
 | 			sview_job_info_ptr = xmalloc(sizeof(sview_job_info_t)); | 
 |  | 
 | 		sview_job_info_ptr->job_ptr = job_ptr; | 
 | 		sview_job_info_ptr->job_id = job_ptr->job_id; | 
 |  | 
 | 		if (job_ptr->array_task_str || | 
 | 		    (job_ptr->array_task_id != NO_VAL)) { | 
 | 			char task_str[64]; | 
 | 			sview_job_info_t *first_job_info_ptr = | 
 | 				list_find_first(info_list, | 
 | 						_task_array_match, job_ptr); | 
 | 			if (job_ptr->array_task_str) { | 
 | 				snprintf(task_str, sizeof(task_str), "[%s]", | 
 | 					 job_ptr->array_task_str); | 
 | 			} else { | 
 | 				snprintf(task_str, sizeof(task_str), "%u", | 
 | 					 job_ptr->array_task_id); | 
 | 			} | 
 |  | 
 | 			if (!first_job_info_ptr) { | 
 | 				sview_job_info_ptr->task_list = | 
 | 					list_create(NULL); | 
 | 				sview_job_info_ptr->task_hl = | 
 | 					hostlist_create(NULL); | 
 | 				first_job_info_ptr = sview_job_info_ptr; | 
 | 			} else if (!IS_JOB_COMPLETED(job_ptr)) | 
 | 				added_task = true; | 
 |  | 
 | 			hostlist_push_host(first_job_info_ptr->task_hl, | 
 | 					   task_str); | 
 |  | 
 | 			if (IS_JOB_PENDING(job_ptr)) { | 
 | 				if (!first_job_info_ptr->task_pending_list) | 
 | 					first_job_info_ptr->task_pending_list = | 
 | 						list_create(NULL); | 
 | 				if (!first_job_info_ptr->task_pending_hl) | 
 | 					first_job_info_ptr->task_pending_hl = | 
 | 						hostlist_create(NULL); | 
 | 				hostlist_push_host( | 
 | 					first_job_info_ptr->task_pending_hl, | 
 | 					task_str); | 
 | 				list_append(first_job_info_ptr-> | 
 | 					    task_pending_list, | 
 | 					    sview_job_info_ptr); | 
 | 			} else if (!IS_JOB_COMPLETED(job_ptr)) | 
 | 				list_append(first_job_info_ptr->task_list, | 
 | 					    sview_job_info_ptr); | 
 | 			if (job_ptr->array_task_str) { | 
 | 				sview_job_info_ptr->job_id_str = | 
 | 					xstrdup_printf("%u_[%s] (%u)", | 
 | 					 job_ptr->array_job_id, | 
 | 					 job_ptr->array_task_str, | 
 | 					 job_ptr->job_id); | 
 | 			} else { | 
 | 				sview_job_info_ptr->job_id_str = | 
 | 					xstrdup_printf("%u_%u (%u)", | 
 | 					 job_ptr->array_job_id, | 
 | 					 job_ptr->array_task_id, | 
 | 					 job_ptr->job_id); | 
 | 			} | 
 | 		} else if (job_ptr->het_job_id) { | 
 | 			char comp_str[64]; | 
 | 			snprintf(comp_str, sizeof(comp_str), "%u", | 
 | 				 job_ptr->het_job_offset); | 
 | 			sview_job_info_t *first_job_info_ptr = | 
 | 				list_find_first(info_list, | 
 | 						_het_job_id_match, job_ptr); | 
 | 			if (!first_job_info_ptr) { | 
 | 				sview_job_info_ptr->task_list = | 
 | 					list_create(NULL); | 
 | 				sview_job_info_ptr->task_hl = | 
 | 					hostlist_create(NULL); | 
 | 				first_job_info_ptr = sview_job_info_ptr; | 
 | 			} else if (!IS_JOB_COMPLETED(job_ptr)) | 
 | 				added_task = true; | 
 |  | 
 | 			hostlist_push_host(first_job_info_ptr->task_hl, | 
 | 					   comp_str); | 
 | 			if (!IS_JOB_COMPLETED(job_ptr)) | 
 | 				list_append(first_job_info_ptr->task_list, | 
 | 					    sview_job_info_ptr); | 
 | 			sview_job_info_ptr->job_id_str = | 
 | 				xstrdup_printf("%u+%u (%u)", | 
 | 				 job_ptr->het_job_id, | 
 | 				 job_ptr->het_job_offset, | 
 | 				 job_ptr->job_id); | 
 | 		} else | 
 | 			sview_job_info_ptr->job_id_str = | 
 | 				xstrdup_printf("%u", job_ptr->job_id); | 
 |  | 
 | 		sview_job_info_ptr->step_list = list_create(NULL); | 
 | 		sview_job_info_ptr->pos = i; | 
 | 		sview_job_info_ptr->node_cnt = 0; | 
 | 		sview_job_info_ptr->color_inx = | 
 | 			job_ptr->job_id % sview_colors_cnt; | 
 | 		sview_job_info_ptr->nodes = xstrdup(job_ptr->nodes); | 
 | 		sview_job_info_ptr->node_cnt = job_ptr->num_nodes; | 
 |  | 
 | 		for (j = 0; j < step_info_ptr->job_step_count; j++) { | 
 | 			step_ptr = &(step_info_ptr->job_steps[j]); | 
 | 			if ((step_ptr->step_id.job_id == job_ptr->job_id) && | 
 | 			    (step_ptr->state == JOB_RUNNING)) { | 
 | 				list_append(sview_job_info_ptr->step_list, | 
 | 					    step_ptr); | 
 | 			} | 
 | 		} | 
 | 		if (!added_task) | 
 | 			list_append(odd_info_list, sview_job_info_ptr); | 
 |  | 
 | 		if (!IS_JOB_PENDING(job_ptr) && | 
 | 		    !IS_JOB_RUNNING(job_ptr) && | 
 | 		    !IS_JOB_SUSPENDED(job_ptr) && | 
 | 		    !IS_JOB_COMPLETING(job_ptr)) { | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		if (!added_task) | 
 | 			list_append(info_list, sview_job_info_ptr); | 
 | 	} | 
 |  | 
 | 	list_sort(info_list, (ListCmpF)_sview_job_sort_aval_dec); | 
 |  | 
 | 	list_sort(odd_info_list, (ListCmpF)_sview_job_sort_aval_dec); | 
 |  | 
 | 	if (last_list) { | 
 | 		list_iterator_destroy(last_list_itr); | 
 | 		FREE_NULL_LIST(last_list); | 
 | 	} | 
 |  | 
 | update_color: | 
 |  | 
 | 	if (want_odd_states) | 
 | 		return odd_info_list; | 
 | 	else | 
 | 		return info_list; | 
 |  | 
 | } | 
 |  | 
 | void _display_info_job(list_t *info_list, popup_info_t *popup_win) | 
 | { | 
 | 	job_step_info_t *step_ptr; | 
 | 	specific_info_t *spec_info = popup_win->spec_info; | 
 | 	list_itr_t *itr = NULL, *itr2 = NULL; | 
 | 	sview_job_info_t *sview_job_info = NULL, *sview_job_info2 = NULL; | 
 | 	int found = 0; | 
 | 	GtkTreeView *treeview = NULL; | 
 | 	int update = 0; | 
 | 	int j, k; | 
 |  | 
 | 	if (spec_info->search_info->int_data == NO_VAL) { | 
 | 		/* 	info = xstrdup("No pointer given!"); */ | 
 | 		goto finished; | 
 | 	} | 
 |  | 
 | need_refresh: | 
 | 	if (!spec_info->display_widget) { | 
 | 		treeview = create_treeview_2cols_attach_to_table( | 
 | 			popup_win->table); | 
 | 		spec_info->display_widget = | 
 | 			g_object_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 = list_next(itr))) { | 
 | 		if (sview_job_info->job_ptr->job_id == | 
 | 		    spec_info->search_info->int_data) | 
 | 			break; | 
 | 		if (sview_job_info->task_list) { | 
 | 			itr2 = list_iterator_create(sview_job_info->task_list); | 
 | 			while ((sview_job_info2 = list_next(itr2))) { | 
 | 				if (sview_job_info2->job_ptr->job_id == | 
 | 				    spec_info->search_info->int_data) | 
 | 					break; | 
 | 			} | 
 | 			list_iterator_destroy(itr2); | 
 | 			if (sview_job_info2) { | 
 | 				sview_job_info = sview_job_info2; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 		if (sview_job_info->task_pending_list) { | 
 | 			itr2 = list_iterator_create( | 
 | 				sview_job_info->task_pending_list); | 
 | 			while ((sview_job_info2 = list_next(itr2))) { | 
 | 				if (sview_job_info2->job_ptr->job_id == | 
 | 				    spec_info->search_info->int_data) | 
 | 					break; | 
 | 			} | 
 | 			list_iterator_destroy(itr2); | 
 | 			if (sview_job_info2) { | 
 | 				sview_job_info = sview_job_info2; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	list_iterator_destroy(itr); | 
 |  | 
 | 	if (!sview_job_info) { | 
 | 		/* not found */ | 
 | 	} else if (spec_info->search_info->int_data2 == NO_VAL) { | 
 | 		int top_node_inx = 0; | 
 | 		int array_size = SVIEW_MAX_NODE_SPACE; | 
 | 		int  *color_inx = xmalloc(sizeof(int) * array_size); | 
 | 		bool *color_set_flag = xmalloc(sizeof(bool) * array_size); | 
 | 		j = 0; | 
 | 		while (sview_job_info->job_ptr->node_inx[j] >= 0) { | 
 | 			top_node_inx = MAX(top_node_inx, | 
 | 					   sview_job_info->job_ptr-> | 
 | 					   node_inx[j+1]); | 
 | 			if (top_node_inx > SVIEW_MAX_NODE_SPACE) | 
 | 				fatal("Expand SVIEW_MAX_NODE_SPACE in sview"); | 
 | 			for (k = sview_job_info->job_ptr->node_inx[j]; | 
 | 			     k <= sview_job_info->job_ptr->node_inx[j+1]; | 
 | 			     k++) { | 
 | 				color_set_flag[k] = true; | 
 | 				color_inx[k] = sview_job_info-> | 
 | 					       color_inx; | 
 | 			} | 
 | 			j += 2; | 
 | 		} | 
 | 		change_grid_color_array(popup_win->grid_button_list, | 
 | 					top_node_inx+1, color_inx, | 
 | 					color_set_flag, true, 0); | 
 | 		xfree(color_inx); | 
 | 		xfree(color_set_flag); | 
 | 		_layout_job_record(treeview, sview_job_info, update); | 
 | 		found = 1; | 
 | 	} else { | 
 | 		int top_node_inx = 0; | 
 | 		int array_size = SVIEW_MAX_NODE_SPACE; | 
 | 		int  *color_inx = xmalloc(sizeof(int) * array_size); | 
 | 		bool *color_set_flag = xmalloc(sizeof(bool) * array_size); | 
 | 		itr = list_iterator_create(sview_job_info->step_list); | 
 | 		while ((step_ptr = list_next(itr))) { | 
 | 			if (step_ptr->step_id.step_id == | 
 | 			    spec_info->search_info->int_data2) { | 
 | 				j = 0; | 
 | 				while (step_ptr->node_inx[j] >= 0) { | 
 | 					top_node_inx = MAX(top_node_inx, | 
 | 							   step_ptr-> | 
 | 							   node_inx[j+1]); | 
 | 					if (top_node_inx > SVIEW_MAX_NODE_SPACE) | 
 | 						fatal("Expand " | 
 | 						      "SVIEW_MAX_NODE_SPACE " | 
 | 						      "in sview"); | 
 | 					for (k = step_ptr->node_inx[j]; | 
 | 					     k <= step_ptr->node_inx[j+1]; | 
 | 					     k++) { | 
 | 						color_set_flag[k] = true; | 
 | 						color_inx[k] = step_ptr->step_id.step_id | 
 | 							% sview_colors_cnt; | 
 | 					} | 
 | 					j += 2; | 
 | 				} | 
 | 				change_grid_color_array( | 
 | 					popup_win->grid_button_list, | 
 | 					top_node_inx+1, color_inx, | 
 | 					color_set_flag, false, 0); | 
 | 				xfree(color_inx); | 
 | 				xfree(color_set_flag); | 
 |  | 
 | 				_layout_step_record( | 
 | 					treeview, step_ptr, update, | 
 | 					IS_JOB_SUSPENDED( | 
 | 						sview_job_info->job_ptr)); | 
 | 				found = 1; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 		list_iterator_destroy(itr); | 
 | 		xfree(color_inx); | 
 | 		xfree(color_set_flag); | 
 | 	} | 
 | 	post_setup_popup_grid_list(popup_win); | 
 |  | 
 | 	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; | 
 | 		} | 
 | 	} | 
 | 	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); | 
 | 	xassert(popup_win->spec_info); | 
 | 	xassert(popup_win->spec_info->title); | 
 | 	popup_win->force_refresh = 1; | 
 | 	specific_info_job(popup_win); | 
 | } | 
 |  | 
 | extern int get_new_info_job(job_info_msg_t **info_ptr, | 
 | 			    int force) | 
 | { | 
 | 	job_info_msg_t *new_job_ptr = NULL; | 
 | 	uint16_t show_flags = 0; | 
 | 	int error_code = SLURM_NO_CHANGE_IN_DATA, i; | 
 | 	time_t now = time(NULL); | 
 | 	static time_t last; | 
 | 	static bool changed = 0; | 
 | 	static uint16_t last_flags = 0; | 
 | 	slurm_job_info_t *job_ptr; | 
 | 	char *local_cluster; | 
 |  | 
 | 	if (g_job_info_ptr && !force | 
 | 	    && ((now - last) < working_sview_config.refresh_delay)) { | 
 | 		if (*info_ptr != g_job_info_ptr) | 
 | 			error_code = SLURM_SUCCESS; | 
 | 		*info_ptr = g_job_info_ptr; | 
 | 		if (changed) | 
 | 			error_code = SLURM_SUCCESS; | 
 | 		goto end_it; | 
 | 	} | 
 | 	last = now; | 
 |  | 
 | 	if (cluster_flags & CLUSTER_FLAG_FED) | 
 | 		show_flags |= SHOW_FEDERATION; | 
 | 	if (working_sview_config.show_hidden) | 
 | 		show_flags |= SHOW_ALL; | 
 | 	if (g_job_info_ptr) { | 
 | 		if (show_flags != last_flags) | 
 | 			g_job_info_ptr->last_update = 0; | 
 | 		error_code = slurm_load_jobs(g_job_info_ptr->last_update, | 
 | 					     &new_job_ptr, show_flags); | 
 | 		if (error_code == SLURM_SUCCESS) { | 
 | 			slurm_free_job_info_msg(g_job_info_ptr); | 
 | 			changed = 1; | 
 | 		} else if (errno == SLURM_NO_CHANGE_IN_DATA) { | 
 | 			error_code = SLURM_NO_CHANGE_IN_DATA; | 
 | 			new_job_ptr = g_job_info_ptr; | 
 | 			changed = 0; | 
 | 		} | 
 | 	} else { | 
 | 		new_job_ptr = NULL; | 
 | 		error_code = slurm_load_jobs((time_t) NULL, &new_job_ptr, | 
 | 					     show_flags); | 
 | 		changed = 1; | 
 | 	} | 
 |  | 
 | 	/* If job not local, clear node_inx to avoid setting node colors */ | 
 | 	if (working_cluster_rec && working_cluster_rec->name) | 
 | 		local_cluster = xstrdup(working_cluster_rec->name); | 
 | 	else | 
 | 		local_cluster = xstrdup(slurm_conf.cluster_name); | 
 | 	if (error_code == SLURM_SUCCESS) { | 
 | 		for (i = 0, job_ptr = new_job_ptr->job_array; | 
 | 		     i < new_job_ptr->record_count; i++, job_ptr++) { | 
 | 			if (job_ptr->node_inx && job_ptr->cluster && | 
 | 			     xstrcmp(job_ptr->cluster, local_cluster)) { | 
 | 				job_ptr->node_inx[0] = -1; | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	xfree(local_cluster); | 
 |  | 
 | 	last_flags = show_flags; | 
 | 	g_job_info_ptr = new_job_ptr; | 
 |  | 
 | 	if (g_job_info_ptr && (*info_ptr != g_job_info_ptr)) | 
 | 		error_code = SLURM_SUCCESS; | 
 |  | 
 | 	*info_ptr = g_job_info_ptr; | 
 | end_it: | 
 | 	return error_code; | 
 | } | 
 |  | 
 | extern int get_new_info_job_step(job_step_info_response_msg_t **info_ptr, | 
 | 				 int force) | 
 | { | 
 | 	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; | 
 | 	static bool changed = 0; | 
 |  | 
 | 	if (g_step_info_ptr && !force | 
 | 	    && ((now - last) < working_sview_config.refresh_delay)) { | 
 | 		if (*info_ptr != g_step_info_ptr) | 
 | 			error_code = SLURM_SUCCESS; | 
 | 		*info_ptr = g_step_info_ptr; | 
 | 		if (changed) | 
 | 			error_code = SLURM_SUCCESS; | 
 | 		goto end_it; | 
 | 	} | 
 | 	last = now; | 
 |  | 
 | 	/* This needs to always be like this even if you are only | 
 | 	   looking for non-hidden jobs or you will get an error below. | 
 | 	*/ | 
 | 	show_flags |= SHOW_ALL; | 
 | 	if (g_step_info_ptr) { | 
 | 		/* Use a last_update time of NULL so that we can get an updated | 
 | 		 * run_time for jobs rather than just its start_time */ | 
 | 		error_code = slurm_get_job_steps((time_t) NULL, | 
 | 						 NO_VAL, NO_VAL, &new_step_ptr, | 
 | 						 show_flags); | 
 | 		if (error_code == SLURM_SUCCESS) { | 
 | 			slurm_free_job_step_info_response_msg(g_step_info_ptr); | 
 | 			changed = 1; | 
 | 		} else if (errno == SLURM_NO_CHANGE_IN_DATA) { | 
 | 			error_code = SLURM_NO_CHANGE_IN_DATA; | 
 | 			new_step_ptr = g_step_info_ptr; | 
 | 			changed = 0; | 
 | 		} | 
 | 	} else { | 
 | 		new_step_ptr = NULL; | 
 | 		error_code = slurm_get_job_steps((time_t) NULL, NO_VAL, NO_VAL, | 
 | 						 &new_step_ptr, show_flags); | 
 | 		changed = 1; | 
 | 	} | 
 |  | 
 | 	g_step_info_ptr = new_step_ptr; | 
 |  | 
 | 	if (g_step_info_ptr && (*info_ptr != g_step_info_ptr)) | 
 | 		error_code = SLURM_SUCCESS; | 
 |  | 
 | 	*info_ptr = g_step_info_ptr; | 
 | end_it: | 
 | 	return error_code; | 
 | } | 
 |  | 
 | extern GtkListStore *create_model_job(int type) | 
 | { | 
 | 	GtkListStore *model = NULL; | 
 | 	GtkTreeIter iter; | 
 |  | 
 | 	last_model = NULL;	/* Reformat display */ | 
 | 	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, "Requeue", | 
 | 				   -1); | 
 | 		break; | 
 | 	case SORTID_CONTIGUOUS: | 
 | 	case SORTID_REBOOT: | 
 | 	case SORTID_REQUEUE: | 
 | 	case SORTID_OVER_SUBSCRIBE: | 
 | 		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, type, | 
 | 				   -1); | 
 | 		gtk_list_store_append(model, &iter); | 
 | 		gtk_list_store_set(model, &iter, | 
 | 				   0, "no", | 
 | 				   1, type, | 
 | 				   -1); | 
 | 		break; | 
 | 	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 *tmp_jobid = NULL, *offset; | 
 |  | 
 | 	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 || !xstrcmp(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, &tmp_jobid, | 
 | 			   column, &old_text, | 
 | 			   -1); | 
 | 	if (!tmp_jobid) | 
 | 		goto no_input; | 
 |  | 
 | 	offset = strchr(tmp_jobid, '('); | 
 | 	if (offset) | 
 | 		offset++; | 
 | 	else | 
 | 		offset = tmp_jobid; | 
 | 	job_msg->job_id = atoi(offset); | 
 | 	g_free(tmp_jobid); | 
 |  | 
 | 	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 (global_edit_error) | 
 | 		goto print_error; | 
 |  | 
 | 	if (got_edit_signal) { | 
 | 		temp = got_edit_signal; | 
 | 		got_edit_signal = NULL; | 
 | 		admin_job(GTK_TREE_MODEL(treestore), &iter, temp, NULL); | 
 | 		xfree(temp); | 
 | 		goto no_input; | 
 | 	} | 
 |  | 
 | 	if (old_text && !xstrcmp(old_text, new_text)) { | 
 | 		temp = g_strdup_printf("No change in value."); | 
 | 	} 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); | 
 | 	} else if (errno == ESLURM_DISABLED) { | 
 | 		temp = g_strdup_printf( | 
 | 			"Can only edit %s on pending jobs.", type); | 
 | 	} 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_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_t *info_list = NULL; | 
 | 	int j, k; | 
 | 	sview_job_info_t *sview_job_info_ptr = NULL; | 
 | 	job_info_t *job_ptr = NULL; | 
 | 	list_itr_t *itr = NULL; | 
 | 	GtkTreePath *path = NULL; | 
 | 	static bool set_opts = false; | 
 |  | 
 | 	if (!set_opts) | 
 | 		set_page_opts(JOB_PAGE, display_data_job, | 
 | 			      SORTID_CNT, _initial_page_opts); | 
 | 	set_opts = true; | 
 |  | 
 | 	/* reset */ | 
 | 	if (!table && !display_data) { | 
 | 		if (display_widget) | 
 | 			gtk_widget_destroy(display_widget); | 
 | 		display_widget = NULL; | 
 | 		job_info_ptr = NULL; | 
 | 		step_info_ptr = NULL; | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	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_jobs: %s", | 
 | 			slurm_strerror(errno)); | 
 | 		label = gtk_label_new(error_char); | 
 | 		gtk_table_attach_defaults(table, label, 0, 1, 0, 1); | 
 | 		gtk_widget_show(label); | 
 | 		display_widget = g_object_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) | 
 | 		    || (step_error_code != SLURM_NO_CHANGE_IN_DATA)) | 
 | 			goto display_it; | 
 | 	} 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(errno)); | 
 | 		label = gtk_label_new(error_char); | 
 | 		gtk_table_attach_defaults(table, label, 0, 1, 0, 1); | 
 | 		gtk_widget_show(label); | 
 | 		display_widget = g_object_ref(GTK_WIDGET(label)); | 
 | 		goto end_it; | 
 | 	} | 
 | display_it: | 
 |  | 
 | 	info_list = _create_job_info_list(job_info_ptr, step_info_ptr, 0); | 
 | 	if (!info_list) | 
 | 		goto reset_curs; | 
 |  | 
 | 	/* set up the grid */ | 
 | 	if (display_widget && GTK_IS_TREE_VIEW(display_widget) | 
 | 	    && gtk_tree_selection_count_selected_rows( | 
 | 		    gtk_tree_view_get_selection( | 
 | 			    GTK_TREE_VIEW(display_widget)))) { | 
 | 		GtkTreeViewColumn *focus_column = NULL; | 
 | 		/* highlight the correct nodes from the last selection */ | 
 | 		gtk_tree_view_get_cursor(GTK_TREE_VIEW(display_widget), | 
 | 					 &path, &focus_column); | 
 | 	} | 
 | 	if (!path) { | 
 | 		int top_node_inx = 0; | 
 | 		int array_size = SVIEW_MAX_NODE_SPACE; | 
 | 		int  *color_inx = xmalloc(sizeof(int) * array_size); | 
 | 		bool *color_set_flag = xmalloc(sizeof(bool) * array_size); | 
 | 		itr = list_iterator_create(info_list); | 
 | 		while ((sview_job_info_ptr = list_next(itr))) { | 
 | 			uint32_t base_state; | 
 | 			job_ptr = sview_job_info_ptr->job_ptr; | 
 | 			base_state = job_ptr->job_state & JOB_STATE_BASE; | 
 | 			if (base_state != JOB_RUNNING) | 
 | 				continue; | 
 | 			j = 0; | 
 | 			while (job_ptr->node_inx[j] >= 0) { | 
 | 				top_node_inx = MAX(top_node_inx, | 
 | 						   job_ptr->node_inx[j+1]); | 
 | 				if (top_node_inx > SVIEW_MAX_NODE_SPACE) { | 
 | 					fatal("Increase SVIEW_MAX_NODE_SPACE " | 
 | 					      "in sview"); | 
 | 				} | 
 | 				for (k = job_ptr->node_inx[j]; | 
 | 				     k <= job_ptr->node_inx[j+1]; k++) { | 
 | 					color_set_flag[k] = true; | 
 | 					color_inx[k] = sview_job_info_ptr-> | 
 | 						       color_inx; | 
 | 				} | 
 | 				j += 2; | 
 | 			} | 
 | 		} | 
 | 		list_iterator_destroy(itr); | 
 | 		change_grid_color_array(grid_button_list, top_node_inx+1, | 
 | 					color_inx, color_set_flag, true, 0); | 
 | 		xfree(color_inx); | 
 | 		xfree(color_set_flag); | 
 | 		change_grid_color(grid_button_list, -1, -1, | 
 | 				  MAKE_WHITE, true, 0); | 
 | 	} else { | 
 | 		highlight_grid(GTK_TREE_VIEW(display_widget), | 
 | 			       SORTID_NODE_INX, SORTID_COLOR_INX, | 
 | 			       grid_button_list); | 
 | 		gtk_tree_path_free(path); | 
 | 	} | 
 |  | 
 | 	if (view == ERROR_VIEW && display_widget) { | 
 | 		gtk_widget_destroy(display_widget); | 
 | 		display_widget = NULL; | 
 | 	} | 
 | 	if (!display_widget) { | 
 | 		tree_view = create_treeview(local_display_data, | 
 | 					    &grid_button_list); | 
 | 		/* set multiple capability here */ | 
 | 		gtk_tree_selection_set_mode( | 
 | 			gtk_tree_view_get_selection(tree_view), | 
 | 			GTK_SELECTION_MULTIPLE); | 
 | 		display_widget = g_object_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, SORTID_TIME_SUBMIT, SORTID_COLOR); | 
 |  | 
 | 		set_column_width_fixed(tree_view, SORTID_NODELIST, 100); | 
 | 		set_column_width_fixed(tree_view, SORTID_NODELIST_EXC, 100); | 
 | 		set_column_width_fixed(tree_view, SORTID_NODELIST_REQ, 100); | 
 | 		set_column_width_fixed(tree_view, SORTID_NODELIST_SCHED, 100); | 
 | 	} | 
 |  | 
 | 	view = INFO_VIEW; | 
 | 	/* If the system has a large number of jobs then not all lines | 
 | 	 * will be displayed. You can try different values for the third | 
 | 	 * argument of gtk_widget_set_size_request() in an attempt to | 
 | 	 * maximumize the data displayed in your environment. These are my | 
 | 	 * results: Y=1000 good for 43 lines, Y=-1 good for 1151 lines, | 
 | 	 *  Y=64000 good for 2781 lines, Y=99000 good for 1453 lines */ | 
 | 	/* gtk_widget_set_size_request(display_widget, -1, -1); */ | 
 | 	_update_info_job(info_list, GTK_TREE_VIEW(display_widget)); | 
 | end_it: | 
 | 	toggled = false; | 
 | 	force_refresh = false; | 
 |  | 
 | reset_curs: | 
 | 	if (main_window && main_window->window) | 
 | 		gdk_window_set_cursor(main_window->window, NULL); | 
 | 	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_t *info_list = NULL; | 
 | 	list_t *send_info_list = NULL; | 
 | 	int j, k; | 
 | 	sview_job_info_t *sview_job_info_ptr = NULL; | 
 | 	job_info_t *job_ptr = NULL; | 
 | 	list_itr_t *itr = NULL; | 
 | 	char *uname = NULL; | 
 | 	hostset_t *hostset = NULL; | 
 | 	int name_diff; | 
 | 	int top_node_inx, array_size, *color_inx; | 
 | 	bool *color_set_flag; | 
 |  | 
 | 	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_jobs: %s", | 
 | 			slurm_strerror(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 = g_object_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) | 
 | 		    || (step_error_code != SLURM_NO_CHANGE_IN_DATA)) | 
 | 			goto display_it; | 
 | 	} 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(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 = g_object_ref(GTK_WIDGET(label)); | 
 | 		goto end_it; | 
 | 	} | 
 | display_it: | 
 | 	info_list = _create_job_info_list(job_info_ptr, step_info_ptr, 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, | 
 | 					    &popup_win->grid_button_list); | 
 | 		/*set multiple capability here*/ | 
 | 		gtk_tree_selection_set_mode( | 
 | 			gtk_tree_view_get_selection(tree_view), | 
 | 			GTK_SELECTION_MULTIPLE); | 
 | 		spec_info->display_widget = | 
 | 			g_object_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, SORTID_TIME_SUBMIT, SORTID_COLOR); | 
 | 	} | 
 |  | 
 | 	setup_popup_grid_list(popup_win); | 
 |  | 
 | 	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); | 
 | 	while ((sview_job_info_ptr = list_next(itr))) { | 
 | 		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 0 | 
 | 				/* 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.step_id == | 
 | 					    spec_info->search_info->int_data2) { | 
 | 						break; | 
 | 					} | 
 | 				} | 
 | #endif | 
 | 				break; | 
 | 			case SEARCH_JOB_USER: | 
 | 				if (!search_info->gchar_data) | 
 | 					continue; | 
 | 				uname = uid_to_string_cached(job_ptr->user_id); | 
 | 				name_diff = xstrcmp(uname, | 
 | 						    search_info->gchar_data); | 
 | 				if (name_diff) | 
 | 					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 (xstrcmp(search_info->gchar_data, | 
 | 				    job_ptr->partition)) | 
 | 				continue; | 
 |  | 
 | 			if (search_info->cluster_name && | 
 | 			    xstrcmp(search_info->cluster_name, | 
 | 				    job_ptr->cluster)) | 
 | 				continue; | 
 | 			break; | 
 | 		case RESV_PAGE: | 
 | 			if (!job_ptr->resv_name | 
 | 			    || xstrcmp(search_info->gchar_data, | 
 | 				       job_ptr->resv_name)) | 
 | 				continue; | 
 | 			break; | 
 | 		case NODE_PAGE: | 
 | 			if (!job_ptr->nodes) | 
 | 				continue; | 
 |  | 
 | 			if (!(hostset = hostset_create( | 
 | 				      search_info->gchar_data))) | 
 | 				continue; | 
 | 			if (!hostset_intersects(hostset, job_ptr->nodes)) { | 
 | 				hostset_destroy(hostset); | 
 | 				continue; | 
 | 			} | 
 | 			hostset_destroy(hostset); | 
 | 			break; | 
 | 		default: | 
 | 			continue; | 
 | 		} | 
 |  | 
 | 		list_push(send_info_list, sview_job_info_ptr); | 
 | 		top_node_inx = 0; | 
 | 		array_size = SVIEW_MAX_NODE_SPACE; | 
 | 		color_inx = xmalloc(sizeof(int) * array_size); | 
 | 		color_set_flag = xmalloc(sizeof(bool) * array_size); | 
 | 		j = 0; | 
 | 		while (job_ptr->node_inx[j] >= 0) { | 
 | 			top_node_inx = MAX(top_node_inx, | 
 | 					   job_ptr->node_inx[j+1]); | 
 | 			if (top_node_inx > SVIEW_MAX_NODE_SPACE) | 
 | 				fatal("Increase SVIEW_MAX_NODE_SPACE in sview"); | 
 | 			for (k = job_ptr->node_inx[j]; | 
 | 			     k <= job_ptr->node_inx[j+1]; k++) { | 
 | 				color_set_flag[k] = true; | 
 | 				color_inx[k] = sview_job_info_ptr->color_inx; | 
 | 			} | 
 | 			j += 2; | 
 | 		} | 
 | 		change_grid_color_array(popup_win->grid_button_list, | 
 | 					top_node_inx+1, color_inx, | 
 | 					color_set_flag, true, 0); | 
 | 		xfree(color_inx); | 
 | 		xfree(color_set_flag); | 
 | 	} | 
 | 	list_iterator_destroy(itr); | 
 | 	post_setup_popup_grid_list(popup_win); | 
 |  | 
 | 	_update_info_job(send_info_list, | 
 | 			 GTK_TREE_VIEW(spec_info->display_widget)); | 
 |  | 
 | 	FREE_NULL_LIST(send_info_list); | 
 | end_it: | 
 | 	popup_win->toggled = 0; | 
 | 	popup_win->force_refresh = 0; | 
 | 	return; | 
 | } | 
 |  | 
 | extern void set_menus_job(void *arg, void *arg2, GtkTreePath *path, int type) | 
 | { | 
 | 	GtkTreeView *tree_view = (GtkTreeView *)arg; | 
 | 	popup_info_t *popup_win = (popup_info_t *)arg; | 
 | 	GtkMenu *menu = (GtkMenu *)arg2; | 
 | 	list_t *button_list = arg2; | 
 |  | 
 | 	switch(type) { | 
 | 	case TAB_CLICKED: | 
 | 		make_fields_menu(NULL, menu, display_data_job, SORTID_CNT); | 
 | 		break; | 
 | 	case ROW_CLICKED: | 
 | 		make_options_menu(tree_view, path, menu, options_data_job); | 
 | 		break; | 
 | 	case ROW_LEFT_CLICKED: | 
 | 		highlight_grid(tree_view, SORTID_NODE_INX, | 
 | 			       SORTID_COLOR_INX, button_list); | 
 | 		break; | 
 | 	case FULL_CLICKED: | 
 | 	{ | 
 | 		GtkTreeModel *model = gtk_tree_view_get_model(tree_view); | 
 | 		GtkTreeIter iter; | 
 | 		if (!gtk_tree_model_get_iter(model, &iter, path)) { | 
 | 			g_error("job error getting iter from model\n"); | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		popup_all_job(model, &iter, INFO_PAGE); | 
 |  | 
 | 		break; | 
 | 	} | 
 | 	case POPUP_CLICKED: | 
 | 		make_fields_menu(popup_win, menu, | 
 | 				 popup_win->display_data, SORTID_CNT); | 
 | 		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, *cluster_name = NULL; | 
 | 	char title[100] = {0}; | 
 | 	list_itr_t *itr = NULL; | 
 | 	popup_info_t *popup_win = NULL; | 
 | 	int jobid = NO_VAL; | 
 | 	int stepid = NO_VAL; | 
 | 	GError *error = NULL; | 
 | 	char *tmp_jobid = NULL, *offset; | 
 |  | 
 | 	gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); | 
 | 	if (!tmp_jobid) | 
 | 		return; | 
 |  | 
 | 	offset = strchr(tmp_jobid, '('); | 
 | 	if (offset) | 
 | 		offset++; | 
 | 	else | 
 | 		offset = tmp_jobid; | 
 | 	jobid = _id_from_stepstr(offset); | 
 | 	g_free(tmp_jobid); | 
 | 	gtk_tree_model_get(model, iter, SORTID_JOBID_FORMATTED, &tmp_jobid, -1); | 
 | 	gtk_tree_model_get(model, iter, SORTID_CLUSTER_NAME, &cluster_name, -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 %s", | 
 | 				 tmp_jobid); | 
 | 		else | 
 | 			snprintf(title, 100, "Partition with job step %s", | 
 | 				 tmp_jobid); | 
 | 		break; | 
 | 	case RESV_PAGE: | 
 | 		if (stepid == NO_VAL) | 
 | 			snprintf(title, 100, "Reservation with job %s", | 
 | 				 tmp_jobid); | 
 | 		else | 
 | 			snprintf(title, 100, "Reservation with job step %s", | 
 | 				 tmp_jobid); | 
 | 		break; | 
 | 	case NODE_PAGE: | 
 | 		if (stepid == NO_VAL) | 
 | 			snprintf(title, 100, | 
 | 				 "Node(s) running job %s", tmp_jobid); | 
 | 		else | 
 | 			snprintf(title, 100, "Node(s) running job step %s", | 
 | 				 tmp_jobid); | 
 | 		break; | 
 | 	case INFO_PAGE: | 
 | 		if (stepid == NO_VAL) | 
 | 			snprintf(title, 100, "Full info for job %s", tmp_jobid); | 
 | 		else | 
 | 			snprintf(title, 100, "Full info for job step %s", | 
 | 				 tmp_jobid); | 
 | 		break; | 
 | 	default: | 
 | 		g_print("jobs got id %d\n", id); | 
 | 	} | 
 |  | 
 | 	if (cluster_name && federation_name && | 
 | 	    (cluster_flags & CLUSTER_FLAG_FED)) { | 
 | 		char *tmp_cname = | 
 | 			xstrdup_printf(" (%s:%s)", | 
 | 				       federation_name, cluster_name); | 
 | 		strncat(title, tmp_cname, sizeof(title) - strlen(title) - 1); | 
 | 		xfree(tmp_cname); | 
 | 	} | 
 |  | 
 | 	if (tmp_jobid) | 
 | 		g_free(tmp_jobid); | 
 |  | 
 | 	itr = list_iterator_create(popup_list); | 
 | 	while ((popup_win = list_next(itr))) { | 
 | 		if (popup_win->spec_info) | 
 | 			if (!xstrcmp(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)); | 
 | 		g_free(cluster_name); | 
 | 		return; | 
 | 	} | 
 |  | 
 | 	/* Pass the model and the structs from the iter so we can always get | 
 | 	   the current node_inx. | 
 | 	*/ | 
 | 	popup_win->model = model; | 
 | 	popup_win->iter = *iter; | 
 | 	popup_win->node_inx_id = SORTID_NODE_INX; | 
 |  | 
 | 	if (cluster_flags & CLUSTER_FLAG_FED) { | 
 | 		popup_win->spec_info->search_info->cluster_name = cluster_name; | 
 | 		cluster_name = NULL; | 
 | 	} | 
 | 	g_free(cluster_name); | 
 |  | 
 | 	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; | 
 | 	case RESV_PAGE: | 
 | 		gtk_tree_model_get(model, iter, SORTID_RESV_NAME, &name, -1); | 
 | 		popup_win->spec_info->search_info->gchar_data = name; | 
 | 		break; | 
 | 	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 (!sview_thread_new((gpointer)popup_thr, popup_win, &error)) { | 
 | 		g_printerr ("Failed to create part popup thread: %s\n", | 
 | 			    error->message); | 
 | 		return; | 
 | 	} | 
 | } | 
 |  | 
 | static void process_foreach_list(jobs_foreach_common_t *jobs_foreach_common) | 
 | { | 
 | 	int jobid; | 
 | 	int state; | 
 | 	int stepid; | 
 | 	uint16_t signal = SIGKILL; | 
 | 	int response = 0; | 
 | 	char *tmp_char_ptr = ""; | 
 | 	jobs_foreach_t *job_foreach = NULL; | 
 | 	list_itr_t *itr = NULL; | 
 |  | 
 | 	if (jobs_foreach_common->edit_type == EDIT_SIGNAL) { | 
 | 		const gchar *entry_txt = gtk_entry_get_text( | 
 | 			GTK_ENTRY(jobs_foreach_common->entry)); | 
 | 		signal = _xlate_signal_name(entry_txt); | 
 | 		if (signal == NO_VAL16) { | 
 | 			tmp_char_ptr = g_strdup_printf( | 
 | 				"%s is not a valid signal.", | 
 | 				entry_txt); | 
 | 			display_edit_note(tmp_char_ptr); | 
 | 			g_free(tmp_char_ptr); | 
 | 			goto end_it; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	itr = list_iterator_create(foreach_list); | 
 | 	while ((job_foreach = list_next(itr))) { | 
 | 		/*stop processing remaining jobs on any error*/ | 
 | 		if (global_error_code) | 
 | 			break; | 
 |  | 
 | 		jobid = job_foreach->step_id.job_id; | 
 | 		stepid = job_foreach->step_id.step_id; | 
 | 		state = job_foreach->state; | 
 |  | 
 | 		switch(jobs_foreach_common->edit_type) { | 
 | 		case EDIT_SIGNAL: | 
 | 			/* 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) | 
 | 				global_error_code = | 
 | 					_cancel_job_id(jobid, signal); | 
 | 			else | 
 | 				global_error_code = | 
 | 					_cancel_step_id(jobid, | 
 | 							stepid, signal); | 
 | 			break; | 
 | 		case EDIT_REQUEUE: | 
 | 			response = slurm_requeue(jobid, 0); | 
 |  | 
 | 			if (response) { | 
 | 				/* stop rest of jobs */ | 
 | 				global_error_code = response; | 
 | 				tmp_char_ptr = g_strdup_printf( | 
 | 					"Error happened trying " | 
 | 					"to requeue job %u: %s", | 
 | 					jobid, slurm_strerror(response)); | 
 | 				display_edit_note(tmp_char_ptr); | 
 | 				g_free(tmp_char_ptr); | 
 | 			} | 
 | 			break; | 
 | 		case EDIT_SUSPEND: | 
 | 			//note: derive state from job_foreach.. | 
 | 			if (state == JOB_SUSPENDED) | 
 | 				response = slurm_resume(jobid); | 
 | 			else | 
 | 				response = slurm_suspend(jobid); | 
 | 			if (!response) { | 
 | 				/* stop rest of jobs */ | 
 | 				global_error_code = response; | 
 | 				tmp_char_ptr = g_strdup_printf( | 
 | 					"Error happened trying to " | 
 | 					"SUSPEND/RESUME job %u.", | 
 | 					jobid); | 
 | 				display_edit_note(tmp_char_ptr); | 
 | 				g_free(tmp_char_ptr); | 
 | 			} | 
 | 			break; | 
 | 		default: | 
 | 			break; | 
 |  | 
 | 		}/*end switch*/ | 
 | 	} /*spin thru selected jobs*/ | 
 |  | 
 | 	if (global_edit_error || global_error_code) | 
 | 		goto end_it; | 
 |  | 
 | 	switch (jobs_foreach_common->edit_type) { | 
 | 	case EDIT_SIGNAL: | 
 | 		tmp_char_ptr = g_strdup_printf( | 
 | 			"Signal successfully sent to job(s)%s", | 
 | 			stacked_job_list); | 
 | 		display_edit_note(tmp_char_ptr); | 
 | 		g_free(tmp_char_ptr); | 
 | 		break; | 
 | 	case EDIT_CANCEL: | 
 | 		tmp_char_ptr = g_strdup_printf( | 
 | 			"Cancel successful for job(s)%s", | 
 | 			stacked_job_list); | 
 | 		display_edit_note(tmp_char_ptr); | 
 | 		g_free(tmp_char_ptr); | 
 | 		break; | 
 | 	case EDIT_REQUEUE: | 
 | 		tmp_char_ptr = g_strdup_printf( | 
 | 			"Requeue successful for job(s)%s", | 
 | 			stacked_job_list); | 
 | 		display_edit_note(tmp_char_ptr); | 
 | 		g_free(tmp_char_ptr); | 
 | 		break; | 
 | 	case EDIT_SUSPEND: | 
 | 		tmp_char_ptr = g_strdup_printf( | 
 | 			"SUSPEND/RESUME action successful for job(s)%s", | 
 | 			stacked_job_list); | 
 | 		display_edit_note(tmp_char_ptr); | 
 | 		g_free(tmp_char_ptr); | 
 | 		break; | 
 | 	default: | 
 | 		break; | 
 |  | 
 | 	}/*end switch*/ | 
 |  | 
 | end_it: | 
 | 	xfree(stacked_job_list); | 
 |  | 
 | } /*process_foreach_list ^^^*/ | 
 |  | 
 | static void selected_foreach_build_list(GtkTreeModel  *model, | 
 | 					GtkTreePath   *path, | 
 | 					GtkTreeIter   *iter, | 
 | 					gpointer       userdata) | 
 | { | 
 | 	uint32_t jobid = NO_VAL; | 
 | 	uint32_t stepid = NO_VAL; | 
 | 	uint32_t array_job_id = NO_VAL, array_task_id = NO_VAL; | 
 | 	uint32_t het_job_id = NO_VAL,  het_job_offset = NO_VAL; | 
 | 	int state; | 
 | 	jobs_foreach_t *fe_ptr = NULL; | 
 | 	char *tmp_jobid, *offset, *end_ptr; | 
 |  | 
 | 	gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); | 
 |  | 
 | 	if (!tmp_jobid) | 
 | 		return; | 
 |  | 
 | 	offset = strchr(tmp_jobid, '('); | 
 | 	if (offset) { | 
 | 		if (strchr(tmp_jobid, '_')) { | 
 | 			array_job_id  = strtol(tmp_jobid, &end_ptr, 10); | 
 | 			array_task_id = strtol(end_ptr+1, NULL, 10); | 
 | 		} else { | 
 | 			het_job_id  = strtol(tmp_jobid, &end_ptr, 10); | 
 | 			het_job_offset = strtol(end_ptr+1, NULL, 10); | 
 | 		} | 
 | 		offset++; | 
 | 	} else | 
 | 		offset = tmp_jobid; | 
 | 	jobid = atoi(offset); | 
 | 	g_free(tmp_jobid); | 
 |  | 
 | 	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); | 
 | 	} | 
 |  | 
 | 	gtk_tree_model_get(model, iter, SORTID_STATE_NUM, &state, -1); | 
 |  | 
 | 	/* alc mem for individual job processor target */ | 
 | 	fe_ptr = xmalloc(sizeof(jobs_foreach_t)); | 
 | 	fe_ptr->step_id.job_id = jobid; | 
 | 	fe_ptr->step_id.step_id = stepid; | 
 | 	fe_ptr->step_id.step_het_comp = NO_VAL; | 
 | 	fe_ptr->state = state; | 
 | 	fe_ptr->array_job_id = array_job_id; | 
 | 	fe_ptr->array_task_id = array_task_id; | 
 | 	fe_ptr->het_job_id = het_job_id; | 
 | 	fe_ptr->het_job_offset = het_job_offset; | 
 |  | 
 | 	list_append(foreach_list, fe_ptr); /* stuff target away*/ | 
 |  | 
 | 	if (stacked_job_list) | 
 | 		xstrcat(stacked_job_list, ", "); | 
 | 	else | 
 | 		xstrcat(stacked_job_list, ": "); | 
 |  | 
 | 	if (array_task_id == NO_VAL && het_job_id == NO_VAL) | 
 | 		xstrfmtcat(stacked_job_list, "%u", jobid); | 
 | 	else if (het_job_id != NO_VAL) | 
 | 		xstrfmtcat(stacked_job_list, "%u+%u", het_job_id, | 
 | 			   het_job_offset); | 
 | 	else | 
 | 		xstrfmtcat(stacked_job_list, "%u_%u", | 
 | 			   array_job_id, array_task_id); | 
 | 	if (stepid != SLURM_BATCH_SCRIPT) | 
 | 		xstrfmtcat(stacked_job_list, ".%u", stepid); | 
 | } | 
 |  | 
 | static void _edit_each_job(GtkTreeModel *model, GtkTreeIter *iter, | 
 | 			    jobs_foreach_common_t *jobs_foreach_common) | 
 | { | 
 | 	int response; | 
 | 	GtkWidget *popup; | 
 | 	GtkWidget *label = NULL; | 
 | 	GtkWidget *entry = NULL; | 
 | 	char tmp_char[255]; | 
 | 	char *tmp_char_ptr = ""; | 
 | 	jobs_foreach_t *job_foreach = NULL; | 
 | 	job_desc_msg_t *job_msg; | 
 | 	list_itr_t *itr = NULL; | 
 |  | 
 | 	itr = list_iterator_create(foreach_list); | 
 | 	while ((job_foreach = list_next(itr))) { | 
 | 		/*stop processing remaining jobs on any error*/ | 
 | 		if (global_error_code || got_edit_signal) | 
 | 			break; | 
 |  | 
 | 		popup = gtk_dialog_new_with_buttons( | 
 | 				"Edit Job", | 
 | 				GTK_WINDOW(main_window), | 
 | 				GTK_DIALOG_MODAL | | 
 | 				GTK_DIALOG_DESTROY_WITH_PARENT, | 
 | 				NULL); | 
 | 		gtk_window_set_type_hint(GTK_WINDOW(popup), | 
 | 					 GDK_WINDOW_TYPE_HINT_NORMAL); | 
 | 		gtk_window_set_transient_for(GTK_WINDOW(popup), NULL); | 
 | 		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_dialog_add_button(GTK_DIALOG(popup), "Cancel all", | 
 | 				      GTK_RESPONSE_DELETE_EVENT); | 
 | 		gtk_window_set_default_size(GTK_WINDOW(popup), 200, 400); | 
 | 		snprintf(tmp_char, sizeof(tmp_char), | 
 | 			 "Editing job %u think before you type", | 
 | 			 job_foreach->step_id.job_id); | 
 | 		label = gtk_label_new(tmp_char); | 
 |  | 
 | 		job_msg = xmalloc(sizeof(job_desc_msg_t)); | 
 | 		slurm_init_job_desc_msg(job_msg); | 
 | 		job_msg->job_id = job_foreach->step_id.job_id; | 
 | 		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)); | 
 | 		gtk_widget_destroy(popup); | 
 |  | 
 | 		if (got_edit_signal || | 
 | 		    (response == GTK_RESPONSE_DELETE_EVENT)) { | 
 | 			slurm_free_job_desc_msg(job_msg); | 
 | 			break; | 
 | 		} | 
 |  | 
 | 		if (global_edit_error) { | 
 | 			tmp_char_ptr = global_edit_error_msg; | 
 | 		} else if (!global_send_update_msg || | 
 | 			   (response == GTK_RESPONSE_CANCEL)) { | 
 | 			tmp_char_ptr = g_strdup_printf("No change detected."); | 
 | 		} else if (slurm_update_job(job_msg) | 
 | 			   == SLURM_SUCCESS) { | 
 | 			tmp_char_ptr = g_strdup_printf( | 
 | 				"Job %u updated successfully", | 
 | 				job_foreach->step_id.job_id); | 
 | 		} else if (errno == ESLURM_DISABLED) { | 
 | 			tmp_char_ptr = g_strdup_printf( | 
 | 				"Can't edit that part of non-pending job %u.", | 
 | 				job_foreach->step_id.job_id); | 
 | 		} else { | 
 | 			tmp_char_ptr = g_strdup_printf( | 
 | 				"Problem updating job %u.", | 
 | 				job_foreach->step_id.job_id); | 
 | 		} | 
 | 		display_edit_note(tmp_char_ptr); | 
 | 		g_free(tmp_char_ptr); | 
 | 		slurm_free_job_desc_msg(job_msg); | 
 | 	} /*spin thru selected jobs*/ | 
 |  | 
 | 	xfree(stacked_job_list); | 
 |  | 
 | } /*process_foreach_list ^^^*/ | 
 |  | 
 | static void _edit_jobs(GtkTreeModel *model, GtkTreeIter *iter, | 
 | 		       char *type, GtkTreeView *treeview) | 
 | { | 
 | 	jobs_foreach_common_t job_foreach_common; | 
 | 	global_error_code = SLURM_SUCCESS; | 
 | 	/* setup working_sview_config that applies to ALL selections */ | 
 | 	memset(&job_foreach_common, 0, sizeof(jobs_foreach_common_t)); | 
 | 	job_foreach_common.type = type; | 
 | 	job_foreach_common.edit_type = EDIT_EDIT; | 
 |  | 
 | 	/* create a list to stack the selected jobs */ | 
 | 	foreach_list = list_create(xfree_ptr); | 
 | 	/* build array of job(s) to process */ | 
 | 	if (treeview) { | 
 | 		gtk_tree_selection_selected_foreach( | 
 | 			gtk_tree_view_get_selection(treeview), | 
 | 			selected_foreach_build_list, NULL); | 
 | 	} else | 
 | 		selected_foreach_build_list(model, NULL, iter, NULL); | 
 | 	/* determine what to do with them/it */ | 
 | 	_edit_each_job(model, iter, &job_foreach_common); /*go do them*/ | 
 | 	FREE_NULL_LIST(foreach_list); | 
 |  | 
 | 	return; | 
 |  | 
 | } | 
 |  | 
 | extern void admin_job(GtkTreeModel *model, GtkTreeIter *iter, | 
 | 		      char *type, GtkTreeView *treeview) | 
 | { | 
 | 	int jobid = NO_VAL; | 
 | 	int stepid = NO_VAL; | 
 | 	int response = 0; | 
 | 	char tmp_char[255]; | 
 | 	int edit_type = 0; | 
 | 	job_desc_msg_t *job_msg; | 
 | 	GtkWidget *label = NULL; | 
 | 	GtkWidget *entry = NULL; | 
 | 	GtkWidget *popup; | 
 | 	char *tmp_jobid, *offset; | 
 |  | 
 | 	if (xstrcmp(type, "Edit Job") == 0) | 
 | 		return _edit_jobs(model, iter, type, treeview); | 
 |  | 
 | 	popup = gtk_dialog_new_with_buttons( | 
 | 			type, | 
 | 			GTK_WINDOW(main_window), | 
 | 			GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, | 
 | 			NULL); | 
 | 	gtk_window_set_type_hint(GTK_WINDOW(popup), | 
 | 				 GDK_WINDOW_TYPE_HINT_NORMAL); | 
 |  | 
 | 	gtk_window_set_transient_for(GTK_WINDOW(popup), NULL); | 
 |  | 
 | 	gtk_tree_model_get(model, iter, SORTID_JOBID, &tmp_jobid, -1); | 
 |  | 
 | 	if (!tmp_jobid) | 
 | 		return; | 
 |  | 
 | 	offset = strchr(tmp_jobid, '('); | 
 | 	if (offset) | 
 | 		offset++; | 
 | 	else | 
 | 		offset = tmp_jobid; | 
 | 	jobid = atoi(offset); | 
 | 	g_free(tmp_jobid); | 
 |  | 
 | 	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); | 
 | 	} | 
 |  | 
 | 	job_msg = xmalloc(sizeof(job_desc_msg_t)); | 
 | 	slurm_init_job_desc_msg(job_msg); | 
 |  | 
 | 	if (!xstrcasecmp("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 (!xstrcasecmp("Requeue", 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); | 
 | 		snprintf(tmp_char, sizeof(tmp_char), | 
 | 			 "Are you sure you want to requeue these job(s)?"); | 
 | 		label = gtk_label_new(tmp_char); | 
 | 		edit_type = EDIT_REQUEUE; | 
 | 	} else if (!xstrcasecmp("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_NO, GTK_RESPONSE_CANCEL); | 
 |  | 
 | 		if (stepid != SLURM_BATCH_SCRIPT) | 
 | 			snprintf(tmp_char, sizeof(tmp_char), | 
 | 				 "Are you sure you want to cancel " | 
 | 				 "these job step(s)?"); | 
 | 		else | 
 | 			snprintf(tmp_char, sizeof(tmp_char), | 
 | 				 "Are you sure you want to cancel " | 
 | 				 "these job(s)?"); | 
 | 		label = gtk_label_new(tmp_char); | 
 | 		edit_type = EDIT_CANCEL; | 
 | 	} else if (!xstrcasecmp("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); | 
 |  | 
 | 		if (stepid != SLURM_BATCH_SCRIPT) | 
 | 			snprintf(tmp_char, sizeof(tmp_char), | 
 | 				 "Are you sure you want to toggle " | 
 | 				 "suspend/resume on these job steps?"); | 
 | 		else | 
 | 			snprintf(tmp_char, sizeof(tmp_char), | 
 | 				 "Are you sure you want to toggle " | 
 | 				 "suspend/resume on these jobs?"); | 
 | 		label = gtk_label_new(tmp_char); | 
 | 		edit_type = EDIT_SUSPEND; | 
 | 	} | 
 |  | 
 | 	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) { | 
 | 		jobs_foreach_common_t job_foreach_common; | 
 | 		global_error_code = SLURM_SUCCESS; | 
 | 		/* setup working_sview_config that applies to ALL selections */ | 
 | 		memset(&job_foreach_common, 0, sizeof(jobs_foreach_common_t)); | 
 | 		job_foreach_common.type = type; | 
 | 		job_foreach_common.edit_type = edit_type; | 
 | 		job_foreach_common.entry = entry; | 
 |  | 
 | 		/* pass this ptr for single job selections */ | 
 | 		job_foreach_common.job_msg = job_msg; | 
 |  | 
 | 		/* create a list to stack the selected jobs */ | 
 | 		foreach_list = list_create(xfree_ptr); | 
 | 		/* build array of job(s) to process */ | 
 | 		if (treeview) | 
 | 			gtk_tree_selection_selected_foreach( | 
 | 				gtk_tree_view_get_selection(treeview), | 
 | 				selected_foreach_build_list, NULL); | 
 | 		else | 
 | 			selected_foreach_build_list(model, NULL, iter, NULL); | 
 | 		/* determine what to do with them/it */ | 
 | 		process_foreach_list(&job_foreach_common); /*go do them*/ | 
 | 		FREE_NULL_LIST(foreach_list); | 
 | 	}/*response OK ^^*/ | 
 | 	/* switch back to standard cursor*/ | 
 |  | 
 | 	global_entry_changed = 0; | 
 | 	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, treeview); | 
 | 		xfree(type); | 
 | 	} | 
 | 	return; | 
 | } | 
 |  | 
 | extern void cluster_change_job(void) | 
 | { | 
 | 	display_data_t *display_data = display_data_job; | 
 | 	while (display_data++) { | 
 | 		if (display_data->id == -1) | 
 | 			break; | 
 |  | 
 | 		if (cluster_flags & CLUSTER_FLAG_FED) { | 
 | 			switch(display_data->id) { | 
 | 			case SORTID_CLUSTER_NAME: | 
 | 				display_data->show = true; | 
 | 				break; | 
 | 			} | 
 | 		} else { | 
 | 			switch(display_data->id) { | 
 | 			case SORTID_CLUSTER_NAME: | 
 | 				display_data->show = false; | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	get_info_job(NULL, NULL); | 
 | } |