/*
 * Copyright (C) 1994-2018 Altair Engineering, Inc.
 * For more information, contact Altair at www.altair.com.
 *
 * This file is part of the PBS Professional ("PBS Pro") software.
 *
 * Open Source License Information:
 *
 * PBS Pro is free software. You can redistribute it and/or modify it under the
 * terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * PBS Pro 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Commercial License Information:
 *
 * For a copy of the commercial license terms and conditions,
 * go to: (http://www.pbspro.com/UserArea/agreement.html)
 * or contact the Altair Legal Department.
 *
 * Altair’s dual-license business model allows companies, individuals, and
 * organizations to create proprietary derivative works of PBS Pro and
 * distribute them - whether embedded or bundled with other software -
 * under a commercial license agreement.
 *
 * Use of Altair’s trademarks, including but not limited to "PBS™",
 * "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
 * trademark licensing policies.
 *
 */
/**
 * @file    pbsd_init.c
 *
 * @brief
 * pbsd_init.c - contains functions to initialize several pbs data structures.
 *
 * Functions included are:
 *	init_server_attrs()
 *	pbsd_init()
 *	reassign_resc()
 *	pbsd_init_job()
 *	pbsd_init_reque()
 *	catch_child()
 *	change_logs()
 *	stop_me()
 *	chk_save_file()
 *	resume_net_move()
 *	need_y_response()
 *	init_abt_job()
 *	Rmv_if_resv_not_possible()
 *	attach_queue_to_reservation()
 *	call_log_license()
 */
#include <pbs_config.h>   /* the master config generated by configure */

#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <memory.h>
#include <signal.h>
#include <time.h>
#include <sys/stat.h>
#include <libutil.h>

#ifdef WIN32

#include <direct.h>
#include <windows.h>
#include <io.h>
#include "win.h"

#else	/* !WIN32 */
#include <dirent.h>
#include <grp.h>
#include <netdb.h>
#include <pwd.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/time.h>

#endif 	/* WIN32 */

#include "libpbs.h"
#include "pbs_ifl.h"
#include "net_connect.h"
#include "log.h"
#include "list_link.h"
#include "attribute.h"
#include "server_limits.h"
#include "server.h"
#include "credential.h"
#include "ticket.h"
#include "batch_request.h"
#include "work_task.h"
#include "resv_node.h"
#include "job.h"
#include "queue.h"
#include "reservation.h"
#include "pbs_db.h"
#include "pbs_nodes.h"
#include "tracking.h"
#include "provision.h"
#include "avltree.h"
#include "svrfunc.h"
#include "acct.h"
#include "pbs_version.h"
#include "rpp.h"
#include "pbs_license.h"
#include "resource.h"
#include "pbs_python.h"
#include "hook.h"
#include "hook_func.h"
#include "pbs_share.h"

#ifndef SIGKILL
/* there is some weid stuff in gcc include files signal.h & sys/params.h */
#include <signal.h>
#endif


/* global Data Items */

extern char	*msg_startup3;
extern char     *msg_daemonname;
extern char	*msg_init_abt;
extern char	*msg_init_queued;
extern char	*msg_init_substate;
extern char	*msg_err_noqueue;
extern char	*msg_err_noqueue1;
extern char	*msg_init_noqueues;
extern char	*msg_init_noresvs;
extern char	*msg_init_resvNOq;
extern char	*msg_init_recovque;
extern char	*msg_init_recovresv;
extern char	*msg_init_expctq;
extern char	*msg_init_nojobs;
extern char	*msg_init_exptjobs;
extern char	*msg_init_norerun;
extern char	*msg_init_unkstate;
extern char	*msg_init_baddb;
extern char	*msg_init_chdir;
extern char	*msg_init_badjob;
extern char	*msg_script_open;
extern char	*msg_unkresc;
extern char	*msg_corelimit;

extern char	*acct_file;
extern int	 ext_license_server;
extern char	*log_file;
extern char	*path_acct;
extern char     *path_usedlicenses;
extern char	path_log[];
extern char	*path_priv;
extern char	*path_jobs;
extern char	*path_users;
extern char	*path_rescdef;
extern char	*path_resvs;
extern char	*path_queues;
extern char	*path_spool;
extern char	*path_svrdb;
extern char	*path_svrdb_new;
extern char	*path_scheddb;
extern char	*path_scheddb_new;
extern char	*path_track;
extern char	*path_prov_track;
extern char	*path_nodes;
extern char	*path_nodes_new;
extern char	*path_nodestate;
extern long	 new_log_event_mask;
extern char	 server_host[];
extern char	 server_name[];
extern int	 svr_delay_entry;
extern pbs_list_head svr_newjobs;
extern pbs_list_head svr_alljobs;
extern pbs_list_head svr_allresvs;
extern pbs_list_head task_list_event;
extern time_t	 time_now;

extern struct server server;
extern struct attribute attr_jobscript_max_size;
extern int      pbs_mom_port;
struct license_block licenses;
struct license_used  usedlicenses;
extern struct resc_sum *svr_resc_sum;
extern char   *path_hooks;
extern char   *path_hooks_workdir;
extern pbs_list_head       prov_allvnodes;
extern int 		max_concurrent_prov;
extern int		brought_up_db;
extern pbs_db_conn_t	*svr_db_conn;

extern	pbs_list_head	svr_allhooks;


#ifdef WIN32
extern int	stalone;
#endif

/* External Functions Called */

extern void   on_job_exit(struct work_task *);
extern void   on_job_rerun(struct work_task *);
extern int resize_prov_table(int newsize);
extern void offline_all_provisioning_vnodes(void);
extern void stop_db();
extern job * job_recov_db_spl(pbs_db_job_info_t *dbjob);
/* Private functions in this file */

static void  catch_child(int);
static void  init_abt_job(job *);
static void  change_logs(int);
int   chk_save_file(char *filename);
static void  need_y_response(int, char *);
static int   pbsd_init_job(job *pjob, int type);
static int   pbsd_init_reque(job *job, int change_state);
static void  resume_net_move(struct work_task *);
static void  stop_me(int);
static int   Rmv_if_resv_not_possible(job *);
static int   attach_queue_to_reservation(resc_resv *);
static void  call_log_license(struct work_task *);
extern int create_resreleased(job *pjob);

extern pbs_sched *sched_alloc(char *sched_name);
/* private data */

#define CHANGE_STATE 1
#define KEEP_STATE   0
static char badlicense[] = "One or more PBS license keys are invalid, jobs may not run";

/**
 * @brief
 *		Initializes the server attribute array with default values which are
 * 		necessary for recovery and action routines to work properly.
 *
 * @return	void
 */
void
init_server_attrs()
{
	resource_def    *prdef = NULL;
	resource        *presc = NULL;
	attribute	attrib;
	int 		i = 0;


	for (i = 0; i < SRV_ATR_LAST; i++)
		clear_attr(&server.sv_attr[i], &svr_attr_def[i]);

	set_attr_svr(&(server.sv_attr[(int)SRV_ATR_scheduler_iteration]), &svr_attr_def[(int) SRV_ATR_scheduler_iteration],
		TOSTR(PBS_SCHEDULE_CYCLE));

	server.sv_attr[(int)SRV_ATR_State].at_val.at_long = SV_STATE_INIT;
	server.sv_attr[(int)SRV_ATR_State].at_flags =
		ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_ResvEnable].at_val.at_long = 1;
	server.sv_attr[(int)SRV_ATR_ResvEnable].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_SvrHost].at_val.at_str =strdup(server_host);
	server.sv_attr[(int)SRV_ATR_SvrHost].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_NodeFailReq].at_val.at_long = PBS_NODE_FAIL_REQUEUE_DEFAULT;
	server.sv_attr[(int)SRV_ATR_NodeFailReq].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SVR_ATR_maxarraysize].at_val.at_long = PBS_MAX_ARRAY_JOB_DFL;
	server.sv_attr[(int)SVR_ATR_maxarraysize].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_license_min].at_val.at_long =
		PBS_MIN_LICENSING_LICENSES;
	server.sv_attr[(int)SRV_ATR_license_min].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_license_max].at_val.at_long =
		PBS_MAX_LICENSING_LICENSES;
	server.sv_attr[(int)SRV_ATR_license_max].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_license_linger].at_val.at_long = PBS_LIC_LINGER_TIME;
	server.sv_attr[(int)SRV_ATR_license_linger].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SVR_ATR_FLicenses].at_val.at_long = 0;
	server.sv_attr[(int)SVR_ATR_FLicenses].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_EligibleTimeEnable].at_val.at_long = 0;
	server.sv_attr[(int)SRV_ATR_EligibleTimeEnable].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_max_concurrent_prov].at_val.at_long =
		PBS_MAX_CONCURRENT_PROV;
	server.sv_attr[(int)SRV_ATR_max_concurrent_prov].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	server.sv_attr[(int)SRV_ATR_max_job_sequence_id].at_val.at_ll = SVR_MAX_JOB_SEQ_NUM_DEFAULT;
	server.sv_attr[(int)SRV_ATR_max_job_sequence_id].at_flags =
		ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

	clear_attr(&attrib, &svr_attr_def[(int)	SVR_ATR_jobscript_max_size]);
	svr_attr_def[(int)SVR_ATR_jobscript_max_size].at_decode(&attrib,ATTR_jobscript_max_size,NULL,DFLT_JOBSCRIPT_MAX_SIZE);
	attr_jobscript_max_size.at_type  |= ATR_TYPE_SIZE;  /* get_bytes_from_attr() is checking for at_type */
	set_size(&attr_jobscript_max_size,&attrib,SET);

	/* an update_to FLicenses()  and pbs_float_lic must already exist */
	pbs_float_lic = &server.sv_attr[(int)SVR_ATR_FLicenses];

	prdef = find_resc_def(svr_resc_def, "ncpus", svr_resc_size);
	if (prdef) {
		presc = add_resource_entry(
			&server.sv_attr[(int)SVR_ATR_DefaultChunk], prdef);
		if (presc) {
			presc->rs_value.at_val.at_long = 1;
			presc->rs_value.at_flags =
				ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;
			server.sv_attr[(int)SVR_ATR_DefaultChunk].at_flags =
				ATR_VFLAG_DEFLT|ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;
			(void)deflt_chunk_action(
				&server.sv_attr[(int)SVR_ATR_DefaultChunk],
				(void *)&server, ATR_ACTION_NEW);
		}
	}
}

/**
 * @brief
 *		This file contains the functions to initialize the PBS Batch Server.
 *		The code is called once when the server is brought up.
 *
 * @param[in]	type	- The type of initialization
 *							RECOV_CREATE - reinitializes all serverdb data
 *
 * @return	Error code
 * @retval	0	- Success
 * @retval	Non-Zero	- Failure
 *
 */
int
pbsd_init(int type)
{
	int	a_opt = -1;
	int	baselen;
	struct dirent *pdirent;
	DIR	*dir;
	int	 fd;
	int	 had;
	int	 i = 0;
	char	 zone_dir[MAXPATHLEN];
	char	*hook_suffix = HOOK_FILE_SUFFIX;
	int	hook_suf_len = strlen(hook_suffix);
	int	 logtype;
	int	 numjobs;
	job	*pjob;
	hook	*phook, *phook_current;
	pbs_queue *pque;
	resc_resv *presv;
	char	*psuffix;
	int	 rc;
	struct stat statbuf;
	char	hook_msg[HOOK_MSG_SIZE];
#ifndef WIN32
	struct sigaction act;
	struct sigaction oact;
#endif
	struct tm	*ptm;
	pbs_db_job_info_t	dbjob;
	pbs_db_resv_info_t	dbresv;
	pbs_db_que_info_t	dbque;
	pbs_db_sched_info_t	dbsched;
	pbs_db_obj_info_t	obj;
	void		*state = NULL;
	pbs_db_conn_t	*conn = (pbs_db_conn_t *) svr_db_conn;
	char *buf = NULL;
	int buf_len = 0;
	pbs_sched *psched;

#ifndef WIN32
#ifdef  RLIMIT_CORE
	int      char_in_cname = 0;
#endif  /* RLIMIT_CORE */
#endif  /* WIN32 */

#ifdef WIN32
	save_env();
#endif

	/* The following is code to reduce security risks                */

	if (setup_env(pbs_conf.pbs_environment)==-1)
		return (-1);

#ifndef WIN32
	i = getgid();
	(void)setgroups(1, (gid_t *)&i);	/* secure suppl. groups */

#ifdef  RLIMIT_CORE
	if (pbs_conf.pbs_core_limit) {
		char *pc = pbs_conf.pbs_core_limit;
		while (*pc != '\0') {
			if (!isdigit(*pc)) {
				/* there is a character in core limit */
				char_in_cname = 1;
				break;
			}
			pc++;
		}
	}
#endif	/* RLIMIT_CORE */
#endif  /* WIN32 */

#if defined(RLIM64_INFINITY)
#ifndef WIN32
	{
		struct rlimit64 rlimit;

		rlimit.rlim_cur = RLIM64_INFINITY;
		rlimit.rlim_max = RLIM64_INFINITY;

		(void)setrlimit64(RLIMIT_CPU,   &rlimit);
		(void)setrlimit64(RLIMIT_FSIZE, &rlimit);
		(void)setrlimit64(RLIMIT_DATA,  &rlimit);
		(void)setrlimit64(RLIMIT_STACK, &rlimit);
#ifdef	RLIMIT_RSS
		(void)setrlimit64(RLIMIT_RSS  , &rlimit);
#endif	/* RLIMIT_RSS */
#ifdef	RLIMIT_VMEM
		(void)setrlimit64(RLIMIT_VMEM  , &rlimit);
#endif	/* RLIMIT_VMEM */
#ifdef	RLIMIT_CORE
		if (pbs_conf.pbs_core_limit) {
			struct rlimit64 corelimit;
			corelimit.rlim_max = RLIM64_INFINITY;
			if (strcmp("unlimited", pbs_conf.pbs_core_limit) == 0)
				corelimit.rlim_cur = RLIM64_INFINITY;
			else if (char_in_cname == 1) {
				log_record(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER, LOG_WARNING,
					__func__, msg_corelimit);
				corelimit.rlim_cur = RLIM64_INFINITY;
			} else
				corelimit.rlim_cur =
					(rlim64_t)atol(pbs_conf.pbs_core_limit);
			(void)setrlimit64(RLIMIT_CORE, &corelimit);
		}
#endif	/* RLIMIT_CORE */
	}
#endif	/* WIN32 */

#else	/* setrlimit 32 bit */

#ifndef WIN32
	{
		struct rlimit rlimit;
		int curerror;

		rlimit.rlim_cur = RLIM_INFINITY;
		rlimit.rlim_max = RLIM_INFINITY;
		(void)setrlimit(RLIMIT_CPU,   &rlimit);
#ifdef	RLIMIT_RSS
		(void)setrlimit(RLIMIT_RSS  , &rlimit);
#endif	/* RLIMIT_RSS */
#ifdef	RLIMIT_VMEM
		(void)setrlimit(RLIMIT_VMEM  , &rlimit);
#endif	/* RLIMIT_VMEM */
#ifdef	RLIMIT_CORE
		if (pbs_conf.pbs_core_limit) {
			struct rlimit corelimit;
			corelimit.rlim_max = RLIM_INFINITY;
			if (strcmp("unlimited", pbs_conf.pbs_core_limit) == 0)
				corelimit.rlim_cur = RLIM_INFINITY;
			else if (char_in_cname == 1) {
				log_record(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER, LOG_WARNING,
					__func__, msg_corelimit);
				corelimit.rlim_cur = RLIM_INFINITY;
			} else
#ifdef	_SX
				corelimit.rlim_cur =
					atol(pbs_conf.pbs_core_limit);
#else
				corelimit.rlim_cur =
					(rlim_t)atol(pbs_conf.pbs_core_limit);
#endif	/* _SX */
			(void)setrlimit(RLIMIT_CORE, &corelimit);
		}
#endif	/* RLIMIT_CORE */
#ifndef linux
		(void)setrlimit(RLIMIT_FSIZE, &rlimit);
		(void)setrlimit(RLIMIT_DATA,  &rlimit);
		(void)setrlimit(RLIMIT_STACK, &rlimit);
#else
		if (getrlimit(RLIMIT_STACK, &rlimit) != -1) {
			if((rlimit.rlim_cur != RLIM_INFINITY) && (rlimit.rlim_cur < MIN_STACK_LIMIT)) {
				rlimit.rlim_cur = MIN_STACK_LIMIT;
				rlimit.rlim_max = MIN_STACK_LIMIT;
				if (setrlimit(RLIMIT_STACK, &rlimit) == -1) {
					curerror = errno;
					sprintf(log_buffer, "Stack limit setting failed");
					log_err(curerror, __func__, log_buffer);
					sprintf(log_buffer, "%s errno=%d", log_buffer, curerror);
					log_record(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER, LOG_ERR, (char *)__func__, log_buffer);
					exit(1);
				}
			}
		} else {
			curerror = errno;
			sprintf(log_buffer, "Getting current Stack limit failed");
			log_err(curerror, __func__, log_buffer);
			sprintf(log_buffer, "%s errno=%d", log_buffer, curerror);
			log_record(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER, LOG_ERR, (char *)__func__, log_buffer);
			exit(1);
		}
#endif  /* not linux */
	}
#endif	/* WIN32 */
#endif	/* !RLIM64_INFINITY */

	/* 1. set up to catch or ignore various signals */

#ifdef WIN32
	signal(SIGABRT, stop_me);
	signal(SIGILL, stop_me);
	signal(SIGINT, stop_me);
	signal(SIGSEGV, stop_me);
	signal(SIGTERM, stop_me);
#else
	sigemptyset(&act.sa_mask);
	act.sa_flags   = 0;
	act.sa_handler = change_logs;
	if (sigaction(SIGHUP, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for HUP");
		return (2);
	}
	act.sa_handler = stop_me;
	if (sigaction(SIGINT, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for INT");
		return (2);
	}
	if (sigaction(SIGTERM, &act, &oact) != 0) {
		log_err(errno, __func__, "sigactin for TERM");
		return (2);
	}
#ifdef NDEBUG
	if (sigaction(SIGQUIT, &act, &oact) != 0) {
		log_err(errno, __func__, "sigactin for QUIT");
		return (2);
	}
#endif	/* NDEBUG */
#ifdef SIGSHUTDN
	if (sigaction(SIGSHUTDN, &act, &oact) != 0) {
		log_err(errno, __func__, "sigactin for SHUTDN");
		return (2);
	}
#endif	/* SIGSHUTDN */

	act.sa_handler = catch_child;
	if (sigaction(SIGCHLD, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for CHLD");
		return (2);
	}

	act.sa_handler = SIG_IGN;
	if (sigaction(SIGPIPE, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for PIPE");
		return (2);
	}
	if (sigaction(SIGUSR1, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for USR1");
		return (2);
	}
	if (sigaction(SIGUSR2, &act, &oact) != 0) {
		log_err(errno, __func__, "sigaction for USR2");
		return (2);
	}
#endif 	/* WIN32 */

	/* 2. check security and set up various global variables we need */

#if !defined(DEBUG) && !defined(NO_SECURITY_CHECK)
#ifdef WIN32
	/* For windows, DO NOT check full path - allow Windows system */
	/* to put in appropriate defaults for permission */
	rc  = chk_file_sec(path_jobs,   1, 0, WRITES_MASK, 0);

	/* my version of lstat() using Windows call is more reliable */
	if (lstat(path_users, &statbuf) != 0) {
		(void)CreateDirectory(path_users, 0);
		secure_file(path_users, NULL, 0);
	}

	rc |= chk_file_sec(path_users,  1, 0, WRITES_MASK, 0);
	rc |= chk_file_sec(path_hooks,  1, 0, WRITES_MASK, 0);
	rc |= chk_file_sec(path_hooks_workdir,  1, 0, WRITES_MASK, 0);
	rc |= chk_file_sec(path_spool,  1, 1, 0, 0);	/* allows others to write */
	rc |= chk_file_sec(path_acct,	1, 1, WRITES_MASK, 0);
	rc |= chk_file_sec(pbs_conf.pbs_environment, 0, 0, WRITES_MASK, 0);
#else
	rc  = chk_file_sec(path_jobs,   1, 0, S_IWGRP|S_IWOTH, 1);
	if (stat(path_users, &statbuf) != 0)
		(void)mkdir(path_users, 0750);
	rc |= chk_file_sec(path_users,  1, 0, S_IWGRP|S_IWOTH, 1);
	rc |= chk_file_sec(path_hooks, 1, 0, S_IWGRP|S_IWOTH, 0);
	rc |= chk_file_sec(path_hooks_workdir, 1, 0, S_IWGRP|S_IWOTH, 0);
	rc |= chk_file_sec(path_spool,  1, 1, 0, 0);
	rc |= chk_file_sec(path_acct,	1, 1, S_IWGRP|S_IWOTH, 0);
	rc |= chk_file_sec(pbs_conf.pbs_environment, 0, 0, S_IWGRP|S_IWOTH, 1);
#endif	/* WIN32 */
	if (rc) {
		log_err(-1, __func__, "chk_file_sec has a failure");
		return (3);
	}
#endif	/* not DEBUG and not NO_SECURITY_CHECK */

	time_now = time(NULL);

	rc = setup_resc(1);
	if (rc != 0) {
		/* log_buffer set in setup_resc */
		log_err(-1, __func__, log_buffer);
		/* return value of -1 means a fatal error, -2 means errors
		 * were "auto-corrected" */
		if (rc == -1)
			return (-1);
	}

	/* 3. Set default server attibutes values */

	if (server.sv_attr[(int)SRV_ATR_scheduling].at_flags & ATR_VFLAG_SET)
		a_opt = server.sv_attr[(int)SRV_ATR_scheduling].at_val.at_long;

	init_server_attrs();

	/* 5. If not a "create" initialization, recover server db */
	/*    and sched db					  */
	rc =svr_recov_db();
	if ((rc != 0) && (type != RECOV_CREATE)) {
#ifdef WIN32
		if (stalone == 1)
#endif
			need_y_response(type, "no server database exists");
		type = RECOV_CREATE;
	}
	if (type != RECOV_CREATE) {
		int count;
		/* Server read success full ?*/

		if (rc != 0) {
			log_err(rc, __func__, msg_init_baddb);
			return (-1);
		}
		/*
		 * Retrieve the jobidnumber from the database and use it to generate jobid's locally
		 * see: get_next_svr_sequence_id(void)
		 */
		svr_jobidnumber = server.sv_qs.sv_jobidnumber;
		if (server.sv_attr[(int)SRV_ATR_resource_assn].at_flags &
			ATR_VFLAG_SET) {
			svr_attr_def[(int)SRV_ATR_resource_assn].at_free(
				&server.sv_attr[(int)SRV_ATR_resource_assn]);
		}
		if (new_log_event_mask) {
			/* set to what was given on command line -e option */
			server.sv_attr[(int)SRV_ATR_log_events].at_val.at_long =
				new_log_event_mask;
			server.sv_attr[(int)SRV_ATR_log_events].at_flags =
				ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;

		}
		/* if server comment is a default, clear it */
		/* it will be reset as needed               */
		if ((server.sv_attr[(int)SRV_ATR_Comment].at_flags &
			(ATR_VFLAG_SET | ATR_VFLAG_DEFLT)) ==
			(ATR_VFLAG_SET | ATR_VFLAG_DEFLT)) {
			svr_attr_def[(int)SRV_ATR_Comment].at_free(
				&server.sv_attr[(int)SRV_ATR_Comment]);
		}

		/* now do sched db */
		/* start a transaction */
		if (pbs_db_begin_trx(conn, 0, 0) != 0)
			return (-1);

		obj.pbs_db_obj_type = PBS_DB_SCHED;
		obj.pbs_db_un.pbs_db_sched = &dbsched;

		state = pbs_db_cursor_init(conn, &obj, NULL);
		if (state == NULL) {
			snprintf(log_buffer, LOG_BUF_SIZE, "%s", (char *) conn->conn_db_err);
			log_err(-1, "pbsd_init", log_buffer);
			pbs_db_cursor_close(conn, state);
			(void) pbs_db_end_trx(conn, PBS_DB_ROLLBACK);
			return (-1);
		}

		count = pbs_db_get_rowcount(state);
		if (count <= 0) {
			/* no schedulers found in DB*/
			pbs_db_cursor_close(conn, state);
			(void) pbs_db_end_trx(conn, PBS_DB_ROLLBACK);
			/* No Schedulers found in DB */
			/* Create and save default to DB*/
			dflt_scheduler = sched_alloc(PBS_DFLT_SCHED_NAME);
			set_sched_default(dflt_scheduler, 0);
			(void)sched_save_db(dflt_scheduler, SVR_SAVE_NEW);
		} else {
			while ((rc = pbs_db_cursor_next(conn, state, &obj)) == 0) {
				/* recover sched */
				if ((psched = sched_recov_db(dbsched.sched_name)) != NULL) {
					if(!strncmp(dbsched.sched_name, PBS_DFLT_SCHED_NAME,
						strlen(PBS_DFLT_SCHED_NAME))) {
						dflt_scheduler = psched;

					}
					if (pbs_conf.pbs_use_tcp == 0) {
						/* check if throughput mode is visible in non-TPP mode, if so make it invisible */
						psched->sch_attr[SCHED_ATR_throughput_mode].at_flags = 0;
					}
					psched->pbs_scheduler_port = psched->sch_attr[SCHED_ATR_sched_port].at_val.at_long;
					psched->pbs_scheduler_addr = get_hostaddr(psched->sch_attr[SCHED_ATR_SchedHost].at_val.at_str);
				}
				pbs_db_reset_obj(&obj);
			}

			pbs_db_cursor_close(conn, state);

			if (server.sv_attr[SRV_ATR_scheduling].at_val.at_long)
				set_scheduler_flag(SCH_SCHEDULE_ETE_ON, NULL);

			/* end the transaction */
			if (pbs_db_end_trx(conn, PBS_DB_COMMIT) != 0)
				return (-1);
		}
	} else {	/* init type is "create" */
		if (rc == 0) {		/* server was loaded */
#ifdef WIN32
			if (stalone == 1)
#endif
				need_y_response(type, "server database exists");

			/* reinitialize schema by dropping PBS schema */
			if (pbs_db_truncate_all(svr_db_conn) == -1) {
				sprintf(log_buffer,
					"Could not truncate PBS data:[%s]",
					(char *) conn->conn_db_err);
				log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER,
					LOG_ALERT, msg_daemonname, log_buffer);
				printf("%s\n", log_buffer);
				return -1;
			}
		}
		svr_save_db(&server, SVR_SAVE_NEW);
		dflt_scheduler = sched_alloc(PBS_DFLT_SCHED_NAME);
		set_sched_default(dflt_scheduler, 0);
		(void)sched_save_db(dflt_scheduler, SVR_SAVE_NEW);
	}

	/* 4. Check License information */

	init_fl_license_attrs(&licenses);

	fd = open(path_usedlicenses, O_RDONLY, 0400);

#ifdef WIN32
	if (fd != -1)
		setmode(fd, O_BINARY);
#endif
	if ((fd == -1) ||
		(read(fd, &usedlicenses, sizeof(usedlicenses)) !=
		sizeof(usedlicenses))) {
		usedlicenses.lu_max_hr      = 0;
		usedlicenses.lu_max_day     = 0;
		usedlicenses.lu_max_month   = 0;
		usedlicenses.lu_max_forever = 0;
		ptm = localtime(&time_now);
		usedlicenses.lu_day   = ptm->tm_mday;
		usedlicenses.lu_month = ptm->tm_mon;
	}
	if (fd != -1)
		close(fd);

	(void)svr_attr_def[(int)SRV_ATR_version].at_decode(
		&server.sv_attr[(int)SRV_ATR_version], 0, 0,
		PBS_VERSION);

	if (check_license(&licenses) < 0) {
		printf("%s\n", badlicense);
		log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, LOG_ALERT,
			msg_daemonname, badlicense);
	} else {
		if (ext_license_server) {
			sprintf(log_buffer, "Using license server at %s",
				PBS_LICENSE_LOCATION);
			log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, LOG_NOTICE,
				msg_daemonname, log_buffer);
			printf("%s\n", log_buffer);
		} 
		if (licenses.lb_aval_floating > 0) {
			sprintf(log_buffer,
				"Licenses valid for %d Floating hosts",
				licenses.lb_aval_floating);
			log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, LOG_NOTICE,
				msg_daemonname, log_buffer);
			printf("%s\n", log_buffer);
		}
	}
	/* start a timed-event every hour to long the number of floating used */
	if ((licenses.lb_aval_floating > 0) || ext_license_server)
		(void)set_task(WORK_Timed, (long)(((time_now+3600)/3600)*3600),
			call_log_license, 0);

	server.sv_attr[(int)SVR_ATR_FLicenses].at_val.at_long = licenses.lb_aval_floating + licenses.lb_glob_floating;
	server.sv_attr[(int)SVR_ATR_FLicenses].at_flags = ATR_VFLAG_SET | ATR_VFLAG_MODCACHE;

	/* 6. open accounting file */

	if (acct_open(acct_file) != 0) {
		log_err(-1, __func__, "Could not open accounting file");
		return (-1);
	}

	/* 7. Set up other server and global variables */

	if (a_opt != -1) {
		/* a_option was set, overrides saved value of scheduling attr */

		server.sv_attr[(int)SRV_ATR_scheduling].at_val.at_long = a_opt;
		server.sv_attr[(int)SRV_ATR_scheduling].at_flags |=
			ATR_VFLAG_SET|ATR_VFLAG_MODCACHE;
	}

	/*
	 * 8A. If not a "create" initialization, recover queues.
	 *    If a create, remove any queues that might be there.
	 */

	had = server.sv_qs.sv_numque;
	server.sv_qs.sv_numque = 0;

	/* start a transaction */
	if (pbs_db_begin_trx(conn, 0, 0) != 0)
		return (-1);

	/* get jobs from DB for this instance of server, by port and address */
	obj.pbs_db_obj_type = PBS_DB_QUEUE;
	obj.pbs_db_un.pbs_db_que = &dbque;

	state = pbs_db_cursor_init(conn, &obj, NULL);
	if (state == NULL) {
		sprintf(log_buffer, "%s", (char *) conn->conn_db_err);
		log_err(-1, __func__, log_buffer);
		pbs_db_cursor_close(conn, state);
		(void) pbs_db_end_trx(conn, PBS_DB_ROLLBACK);
		return (-1);
	}
	while ((rc = pbs_db_cursor_next(conn, state, &obj)) == 0) {
		/* recover queue */
		if ((pque = que_recov_db(dbque.qu_name)) != NULL) {
			/* que_recov increments sv_numque */
			sprintf(log_buffer, msg_init_recovque,
				pque->qu_qs.qu_name);
			log_event(PBSEVENT_SYSTEM | PBSEVENT_ADMIN |
				PBSEVENT_DEBUG, PBS_EVENTCLASS_SERVER,
				LOG_INFO, msg_daemonname, log_buffer);
			if (pque->qu_attr[(int) QE_ATR_ResourceAssn].at_flags &
				ATR_VFLAG_SET) {
				que_attr_def[(int) QE_ATR_ResourceAssn].at_free(
					&pque->qu_attr[(int) QE_ATR_ResourceAssn]);
			}
		}
		pbs_db_reset_obj(&obj);
	}

	pbs_db_cursor_close(conn, state);

	/* end the transaction */
	if (pbs_db_end_trx(conn, PBS_DB_COMMIT) != 0)
		return (-1);

	if ((had != server.sv_qs.sv_numque) && (type != RECOV_CREATE))
		logtype = PBSEVENT_ERROR | PBSEVENT_SYSTEM;
	else
		logtype = PBSEVENT_SYSTEM;
	sprintf(log_buffer, msg_init_expctq, had, server.sv_qs.sv_numque);
	log_event(logtype, PBS_EVENTCLASS_SERVER, LOG_INFO,
		msg_daemonname, log_buffer);


	/* Open and read in node list if one exists */
	if ((rc = setup_nodes()) == -1) {
		/* log_buffer set in setup_nodes */
		log_err(-1, __func__, log_buffer);
		return (-1);
	}
	mark_which_queues_have_nodes();
	(void) license_sanity_check();

	/* at this point, we know all the resource types have been defined,        */
	/* build the resource summation table for validating the Select directives */
	update_resc_sum();

	/*
	 * 8B. If not a "create" initialization, recover reservations.
	 */
	/* set the zoneinfo directory to $PBS_EXEC/zoneinfo.
	 * This is used for standing reservations user of libical */
	sprintf(zone_dir, "%s%s", pbs_conf.pbs_exec_path, ICAL_ZONEINFO_DIR);
	set_ical_zoneinfo(zone_dir);

	/* start a transaction */
	if (pbs_db_begin_trx(conn, 0, 0) != 0)
		return (-1);

	/* load reservations */
	obj.pbs_db_obj_type = PBS_DB_RESV;
	obj.pbs_db_un.pbs_db_resv = &dbresv;
	state = pbs_db_cursor_init(conn, &obj, NULL);
	if (state == NULL) {
		sprintf(log_buffer, "%s", (char *) conn->conn_db_err);
		log_err(-1, __func__, log_buffer);
		pbs_db_cursor_close(conn, state);
		(void) pbs_db_end_trx(conn, PBS_DB_ROLLBACK);
		return (-1);
	}
	while ((rc = pbs_db_cursor_next(conn, state, &obj)) == 0) {
		/* recover reservation */
		presv = (resc_resv *) job_or_resv_recov(dbresv.ri_resvid,
			RESC_RESV_OBJECT);
		if (presv != NULL) {

			is_resv_window_in_future(presv);
			set_old_subUniverse(presv);

			append_link(&svr_allresvs, &presv->ri_allresvs, presv);
			if (attach_queue_to_reservation(presv)) {

				/* reservation needed queue; failed to find it */
				sprintf(log_buffer, msg_init_resvNOq,
					presv->ri_qs.ri_queue, presv->ri_qs.ri_resvID);
				log_event(PBSEVENT_SYSTEM | PBSEVENT_ADMIN |
					PBSEVENT_DEBUG, PBS_EVENTCLASS_RESV,
					LOG_NOTICE, msg_daemonname, log_buffer);
			} else {

				sprintf(log_buffer, msg_init_recovresv,
					presv->ri_qs.ri_resvID);
				log_event(PBSEVENT_SYSTEM | PBSEVENT_ADMIN |
					PBSEVENT_DEBUG, PBS_EVENTCLASS_SERVER,
					LOG_INFO, msg_daemonname, log_buffer);
			}
		}
		pbs_db_reset_obj(&obj);
	}
	pbs_db_cursor_close(conn, state);

	/*
	 * 9. If not "create" or "clean" recovery, recover the jobs.
	 *    If a create or clean recovery, delete any jobs.
	 *    Before job creation/recovery, create the AVL tree.
	 */
	AVL_jctx = (AVL_IX_DESC *) malloc(sizeof(AVL_IX_DESC));
	if (AVL_jctx == NULL) {
		log_err(-1, __func__, "Creating AVL tree for job-lookup failed!");
		return (-1);
	}
	avl_create_index(AVL_jctx, AVL_NO_DUP_KEYS, 0);

	server.sv_qs.sv_numjobs = 0;

	/* get jobs from DB */
	obj.pbs_db_obj_type = PBS_DB_JOB;
	obj.pbs_db_un.pbs_db_job = &dbjob;
	state = pbs_db_cursor_init(conn, &obj, NULL);
	if (state == NULL) {
		sprintf(log_buffer, "%s", (char *) conn->conn_db_err);
		log_err(-1, __func__, log_buffer);
		pbs_db_cursor_close(conn, state);
		(void) pbs_db_end_trx(conn, PBS_DB_ROLLBACK);
		return (-1);
	}
	if (pbs_db_get_rowcount(state) <= 0) {
		if ((type != RECOV_CREATE) && (type != RECOV_COLD)) {
				log_event(PBSEVENT_DEBUG, PBS_EVENTCLASS_SERVER,
					LOG_DEBUG,
					msg_daemonname, msg_init_nojobs);
		}
	} else {
		/* Now, for each job found ... */
		numjobs = 0;
		while ((rc = pbs_db_cursor_next(conn, state, &obj)) == 0) {
			if ((pjob = job_recov_db_spl(&dbjob)) == NULL) {
				if ((type == RECOV_COLD) || (type == RECOV_CREATE)) {
					/* remove the loaded job from db */
					if (pbs_db_delete_obj(conn, &obj) != 0) {
						sprintf(log_buffer, "job %s not purged", dbjob.ji_jobid);
						log_err(-1, __func__, log_buffer);
					}
				} else {
					sprintf(log_buffer, "Failed to recover job %s", dbjob.ji_jobid);
					log_event(PBSEVENT_SYSTEM,
						PBS_EVENTCLASS_SERVER, LOG_NOTICE,
						msg_daemonname, log_buffer);
				}
				continue;
			}
			pbs_db_reset_obj(&obj);

			/*chk if job belongs to a reservation or
			 *is a reservation job.  If this is true
			 *and the reservation is no longer possible,
			 *return (1) else return (0)
			 */
			if (Rmv_if_resv_not_possible(pjob)) {
				account_record(PBS_ACCT_ABT, pjob, "");
				svr_mailowner(pjob, MAIL_ABORT, MAIL_NORMAL,
					msg_init_abt);
				check_block(pjob, msg_init_abt);
				job_purge(pjob);
				continue;
			}

			rc = pbsd_init_job(pjob, type);
			/*
			 *	in the db version, job always has job script
			 *	since they are saved together, so nothing to
			 *	check
			 *
			 */
			if ((++numjobs % 20) == 0) {
				/* periodically touch the file so the  */
				/* world knows we are alive and active */
				(void)update_svrlive();
			}
		}

		sprintf(log_buffer, msg_init_exptjobs,
			server.sv_qs.sv_numjobs);
		log_event(PBSEVENT_SYSTEM, PBS_EVENTCLASS_SERVER, LOG_NOTICE,
			msg_daemonname, log_buffer);
	}

	pbs_db_cursor_close(conn, state);
	/* close transaction */
	if (pbs_db_end_trx(conn, PBS_DB_COMMIT) != 0)
		return (-1);

	/* If we have trial licenses, we would need to immediately   */
	/* license the jobs under svr_unlicensedjobs list.           */
	/* If we have a license server, then                         */
	/* relicense_svr_unlicensedjobs() is periodically called by  */
	/* return_licenses() in checkkey.c.                          */

	if( ( (server.sv_attr[SRV_ATR_pbs_license_info].at_flags & \
                                                ATR_VFLAG_SET) == 0) ||
	(server.sv_attr[SRV_ATR_pbs_license_info].at_val.at_str[0] \
                                                               == '\0') ) {
		relicense_svr_unlicensedjobs();
	}

	/* Now, cause any reservations marked RESV_FINISHED to be
	 * removed and place "begin" and "end" tasks onto the
	 * "work_task_timed" list, as appropriate, for those that
	 * remain
	 */

	remove_deleted_resvs();
	add_resv_beginEnd_tasks();

	cnvrt_timer_init(); /* !! */

	/* Put us back in the Server's Private directory */

	if (chdir(path_priv) != 0) {
		(void)sprintf(log_buffer, msg_init_chdir, path_priv);
		log_err(-1, __func__, log_buffer);
		return (3);
	}

	/*
	 * 10. Recover the hooks.
	 *
	 */

	if (chdir(path_hooks) != 0) {
		(void)sprintf(log_buffer, msg_init_chdir, path_hooks);
		log_err(errno, __func__, log_buffer);
		return (-1);
	}

	dir = opendir(".");
	if (dir == NULL) {
		log_event(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER,
			LOG_DEBUG, msg_daemonname,
			"Could not open hooks dir");
	} else {
		/* Now, for each hook found ... */

		while (errno = 0,
			(pdirent = readdir(dir)) != NULL) {

			if (chk_save_file(pdirent->d_name) != 0) {
				continue;
			}

			/* recover the hooks */

			baselen = strlen(pdirent->d_name) - hook_suf_len;
			psuffix = pdirent->d_name + baselen;
			if (strcmp(psuffix, hook_suffix)) {
				continue;
			}

			if ((phook = \
			       hook_recov(pdirent->d_name, NULL, hook_msg,
				sizeof(hook_msg),
				pbs_python_ext_alloc_python_script,
				pbs_python_ext_free_python_script)) == NULL) {
				sprintf(log_buffer,
					"hook_recov(%s): can't recover - %s",
					pdirent->d_name, hook_msg);
				log_event(PBSEVENT_SYSTEM,
					PBS_EVENTCLASS_SERVER, LOG_NOTICE,
					msg_daemonname, log_buffer);
			} else {
				sprintf(log_buffer, "Found hook %s type=%s",
					phook->hook_name,
					((phook->type == HOOK_SITE)?"site":"pbs"));
				log_event(PBSEVENT_SYSTEM|PBSEVENT_ADMIN |
					PBSEVENT_DEBUG, PBS_EVENTCLASS_SERVER,
					LOG_INFO, msg_daemonname, log_buffer);
				if (phook->event & MOM_EVENTS)
					mark_mom_hooks_seen();
			}
		}

		if (errno != 0 && errno != ENOENT)
			log_event(PBSEVENT_ERROR, PBS_EVENTCLASS_SERVER,
				LOG_DEBUG, msg_daemonname,
				"Could not read hooks dir");
		(void)closedir(dir);
	}
	print_hooks(0);
	print_hooks(HOOK_EVENT_QUEUEJOB);
	print_hooks(HOOK_EVENT_MODIFYJOB);
	print_hooks(HOOK_EVENT_RESVSUB);
	print_hooks(HOOK_EVENT_MOVEJOB);
	print_hooks(HOOK_EVENT_RUNJOB);
	print_hooks(HOOK_EVENT_PROVISION);
	print_hooks(HOOK_EVENT_PERIODIC);
	print_hooks(HOOK_EVENT_RESV_END);

	/*
	 * cleanup  the hooks work directory
	 */

	cleanup_hooks_workdir(0);

	/* Put us back in the Server's Private directory */

	if (chdir(path_priv) != 0) {
		(void)sprintf(log_buffer, msg_init_chdir, path_priv);
		log_err(-1, __func__, log_buffer);
		return (3);
	}

	/* 11. Open and read in tracking records */

	fd = open(path_track, O_RDONLY | O_CREAT, 0600);
	if (fd < 0) {
		log_err(errno, __func__, "unable to open tracking file");
		return (-1);
	}
#if !defined(DEBUG) && !defined(NO_SECURITY_CHECK)
#ifdef WIN32
	secure_file(path_track, "Administrators", READS_MASK|WRITES_MASK|STANDARD_RIGHTS_REQUIRED);
	setmode(fd, O_BINARY);
	if (chk_file_sec(path_track,  0, 0, WRITES_MASK, 0) != 0)
#else
	if (chk_file_sec(path_track,  0, 0, S_IWGRP|S_IWOTH, 0) != 0)
#endif
		return (-1);
#endif  /* not DEBUG and not NO_SECURITY_CHECK */

	if (fstat(fd, &statbuf) < 0) {
		log_err(errno, "pbs_init", "unable to stat tracking file");
		return (-1);
	} else {

		size_t amt;
		size_t rd;
		char  *w;

		/* validate the size of the file, it should be a multiple */
		/* of the tracking structure size                         */

		i = statbuf.st_size / sizeof(struct tracking);
		amt = i * sizeof(struct tracking);

		if (amt != statbuf.st_size) {
			log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER,
				LOG_ALERT, msg_daemonname,
				"tracking file has invalid length");
		}
		if (i < PBS_TRACK_MINSIZE)
			server.sv_tracksize = PBS_TRACK_MINSIZE;
		else
			server.sv_tracksize = i;
		server.sv_track = (struct tracking *)calloc(server.sv_tracksize,
			sizeof(struct tracking));
		if (server.sv_track == NULL) {
			log_err(errno, "init", "out of memory");
			return -1;
		}
		for (i = 0; i < server.sv_tracksize; i++)
			(server.sv_track + i)->tk_mtime = 0;

		w = (char *)server.sv_track;

		/* read in the file (a mutiple of the struct size) */

		while (amt > 0) {
			rd = read(fd, w, amt);
			if ((rd == -1) && (errno == EINTR)) {
				continue;
			} else if (rd <= 0) {
				break;
			}
			amt -= rd;
			w   += rd;
		}
		(void)close(fd);
		server.sv_trackmodifed = 0;
	}

	/* set work task to periodically save the tracking records */

	(void)set_task(WORK_Timed, (long)(time_now + PBS_SAVE_TRACK_TM),
		track_save, 0);

	fd = open(path_prov_track, O_RDONLY | O_CREAT, 0600);
	if (fd < 0) {
		log_err(errno, __func__, "unable to open prov_tracking file");
		return (-1);
	}
#if !defined(DEBUG) && !defined(NO_SECURITY_CHECK)
#ifdef WIN32
	secure_file(path_prov_track, "Administrators", READS_MASK|WRITES_MASK|STANDARD_RIGHTS_REQUIRED);
	setmode(fd, O_BINARY);
	if (chk_file_sec(path_prov_track,  0, 0, WRITES_MASK, 0) != 0)
#else
	if (chk_file_sec(path_prov_track,  0, 0, S_IWGRP|S_IWOTH, 0) != 0)
#endif
		return (-1);
#endif  /* not DEBUG and not NO_SECURITY_CHECK */

	if (fstat(fd, &statbuf) < 0) {
		log_err(errno, "pbs_init", "unable to stat prov_tracking file");
		return (-1);
	} else {
		size_t amt;
		size_t rd;
		char  *p, *buffer;	/* to hold entire file data */
		int   ctrl_flag = 0;	/* we always write pvtk_mtime first */
		char *token;
		long  mtime;
		i = 0;

		/* whats the size of data in file */
		amt = statbuf.st_size;

		server.sv_provtracksize =
			server.sv_attr[(int)SRV_ATR_max_concurrent_prov].at_val.at_long;
		DBPRT(("%s: server.sv_provtracksize=%d amt=%ld\n", __func__, server.sv_provtracksize, (long)amt))

		p = malloc(amt + 1);
		if (p == NULL) {
			log_err(errno, "pbs_init", "unable to malloc");
			close(fd);
			return (-1);
		}
		buffer = p;

		/* read entire file into buffer */
		while (amt > 0) {
			rd = read(fd, p, amt);
			if ((rd == -1) && (errno == EINTR)) {
				continue;
			} else if (rd <= 0) {
				break;
			}
			amt -= rd;
			p += rd;
		}
		(void)close(fd);
		buffer[statbuf.st_size] = '\0';

		server.sv_prov_track = (struct prov_tracking *)calloc(server.sv_provtracksize,
			sizeof(struct prov_tracking));
		if (server.sv_prov_track == NULL) {
			free(buffer);
			log_err(errno, "pbs_init", "unable to calloc");
			return (-1);
		}

		for (i = 0; i < server.sv_provtracksize; i++) {
			server.sv_prov_track[i].pvtk_mtime = 0;
#ifdef	WIN32
			server.sv_prov_track[i].pvtk_pid = INVALID_HANDLE_VALUE;
#else
			server.sv_prov_track[i].pvtk_pid = -1;
#endif
			server.sv_prov_track[i].pvtk_vnode = NULL;
			server.sv_prov_track[i].pvtk_aoe_req = NULL;
			server.sv_prov_track[i].prov_vnode_info = NULL;
		}

		/* start tokenizing by '|' */
		i = 0;
		token = strtok(buffer, "|");
		while (token != NULL && i < server.sv_provtracksize) {
			switch (ctrl_flag) {
				case 0:
					errno = 0;
					mtime = strtol(token, NULL, 10);
					if (errno) {
						free(buffer);
						free(server.sv_prov_track);
						log_err(errno, "pbs_init",
							"bad data in prov_tracking");
						return (-1);
					}
					server.sv_prov_track[i].pvtk_mtime = mtime;
					++ctrl_flag;
					break;
				case 1:
					/* after first save, 0 is written if */
					/* value is null. If reading 0, then */
					/* pvtk_vnode should be null else it */
					/* becomes "0" */
					if (strcmp(token, "0") != 0) {
						server.sv_prov_track[i].pvtk_vnode =
							(char*)malloc(strlen(token)+1);
						if (server.sv_prov_track[i].pvtk_vnode
							== NULL) {
							free(buffer);
							free(server.sv_prov_track);
							log_err(errno, "pbs_init",
								"unable to malloc");
							return (-1);
						}
						strcpy(server.sv_prov_track[i].pvtk_vnode,
							token);
					}
					++ctrl_flag;
					break;
				case 2:
					if (strcmp(token, "0") != 0) {
						server.sv_prov_track[i].pvtk_aoe_req =
							(char*)malloc(strlen(token)+1);
						if (server.sv_prov_track[i].pvtk_vnode
							== NULL) {
							free(buffer);
							free(server.sv_prov_track);
							log_err(errno, "pbs_init",
								"unable to malloc");
							return (-1);
						}
						strcpy(server.sv_prov_track[i].pvtk_aoe_req,
							token);
					}
					ctrl_flag = 0;
					++i;
					break;
			}
			token = strtok(NULL, "|");
		}
		server.sv_provtrackmodifed = 0;
		free(buffer);
		/* less data recovered than expected */
		if ((i != server.sv_provtracksize) && (statbuf.st_size != 0)) {
			sprintf(log_buffer, "Recovered prov_tracking, "
				"Expected %d, recovered %d records",
				server.sv_provtracksize, i);
			log_event(PBSEVENT_ADMIN, PBS_EVENTCLASS_SERVER, LOG_WARNING,
				msg_daemonname, log_buffer);
		}
	}

	/* mark all nodes that are in the prov tracking table as offline,
	 * also do away with all jobs that were waiting on such nodes
	 */
	offline_all_provisioning_vnodes();
	server.sv_cur_prov_records = 0;

	(void)resize_prov_table(max_concurrent_prov);
	CLEAR_HEAD(prov_allvnodes);


	/* trigger degraded reservations on offlined nodes */
	degrade_offlined_nodes_reservations();

#ifdef WIN32
	/* Under WIN32, create structure that will be used to track child processes. */
	if (initpids() == 0) {
		log_err(-1, __func__, "Creating pid handles table failed!");
		return (-1);
	}
#endif

	hook_track_recov();

	/* Check to see that jobs in the maintenance_jobs attribute on a node still exist
	 * If they don't exist any more, remove them from a node's maintenance_jobs attribute
	 */
	buf = NULL;
	buf_len = 0;
	for (i=0; i<svr_totnodes; i++) {
		struct array_strings *arst;
		arst = pbsndlist[i]->nd_attr[(int)ND_ATR_MaintJobs].at_val.at_arst;
		if (pbsndlist[i]->nd_attr[(int)ND_ATR_MaintJobs].at_flags & ATR_VFLAG_SET &&
		    arst->as_usedptr > 0) {
			int j;
			int len = 0;
			int cur_len = 0;
			attribute new;

			for(j = 0; j < arst->as_usedptr; j++)
				len += strlen(arst->as_string[j]) + 1; /* 1 for the comma*/

			if(len > buf_len) {
				char *tmp_buf;
				tmp_buf = realloc(buf, len + 1);
				if(tmp_buf == NULL) {
					free(buf);
					return (-1);
				}
				else {
					buf = tmp_buf;
					buf_len = len;
				}
			}
			buf[0] = '\0';
			for(j = 0; j < arst->as_usedptr; j++) {
				if(find_job(arst->as_string[j]) == NULL) {
					strncat(buf, arst->as_string[j], len);
					strncat(buf, ",", len);
					buf[len] = '\0';
				}
			}
			/* Did we find a string we need to remove*/
			cur_len = strlen(buf);
			if(cur_len > 0) {
				buf[cur_len - 1] = '\0'; /* remove trailing comma */
				clear_attr(&new, &node_attr_def[(int) ND_ATR_MaintJobs]);
				decode_arst(&new, ATTR_NODE_MaintJobs, NULL, buf);
				set_arst(&pbsndlist[i]->nd_attr[(int) ND_ATR_MaintJobs], &new, DECR);
			}

			if(arst->as_usedptr > 0)
				set_vnode_state(pbsndlist[i], INUSE_MAINTENANCE, Nd_State_Or);
		}
	}
	free(buf);

	/* purge deleted hooks */
	phook = (hook *)GET_NEXT(svr_allhooks);
	while (phook) {
		phook_current = phook;
		phook = (hook *)GET_NEXT(phook->hi_allhooks);

		if (phook_current->pending_delete &&
			!has_pending_mom_action_delete(
			phook_current->hook_name)) {
			hook_purge(phook_current,
				pbs_python_ext_free_python_script);
		}
	}
	send_rescdef(0);
	hook_track_save(NULL, -1); /* refresh path_hooks_tracking file */

#ifndef WIN32
	(void)set_task(WORK_Immed, time_now, memory_debug_log, NULL);
#endif /* !WIN32 */

	return (0);
}

/**
 * @brief
 * 		reassign_resc - for a recovered running job, reassign the resources and
 *		nodes to the job.
 *
 * @param[in,out]	pjob	- the job.
 *
 * @return	void
 */
static void
reassign_resc(job *pjob)
{
	int   set_exec_vnode;
	int   rc;
	int unset_resc_released = 0;
	char *hoststr  = pjob->ji_wattr[(int)JOB_ATR_exec_host].at_val.at_str;
	char *hoststr2 = pjob->ji_wattr[(int)JOB_ATR_exec_host2].at_val.at_str;
	char *vnodein;
	char *vnodeout;
	attribute deallocated_attr;

	/* safety check: if no hoststr, no node (hosts) assigned, just return */
	if (hoststr == NULL)
		return;

	if ((pjob->ji_wattr[(int)JOB_ATR_exec_vnode].at_flags & ATR_VFLAG_SET) == 0) {
		/*
		 * if exec_vnode is not set, we must be dealing with a
		 * pre-8.0 job.   Then we need to set exec_vnode anew based
		 * on the select spec that was auto generated when the job
		 * was requeued and the existing exec_host.  This is done in
		 * the same as as when a "qrun -H vn+vn+... jobid" is done.
		 */
		set_exec_vnode = 1;
		vnodein = hoststr;
	} else {
		set_exec_vnode = 0;
		vnodein = pjob->ji_wattr[(int)JOB_ATR_exec_vnode].at_val.at_str;
	}

	rc = set_nodes((void *)pjob, JOB_OBJECT,
		vnodein,
		&vnodeout,
		&hoststr,
		&hoststr2,
		set_exec_vnode,
		TRUE);

	if (rc != 0) {
		sprintf(log_buffer, "Unable to reallocate resources from nodes for job, error %d", rc);
		log_event(PBSEVENT_ERROR, PBS_EVENTCLASS_JOB, LOG_NOTICE,
			pjob->ji_qs.ji_jobid, log_buffer);
	} else if (set_exec_vnode == 1) {
		/* need to recreate the exec_host/exec_vnode values */
		job_attr_def[(int)JOB_ATR_exec_host].at_free(
			&pjob->ji_wattr[(int)JOB_ATR_exec_host]);
		job_attr_def[(int)JOB_ATR_exec_vnode].at_free(
			&pjob->ji_wattr[(int)JOB_ATR_exec_vnode]);
		(void)job_attr_def[(int)JOB_ATR_exec_vnode].at_decode(
			&pjob->ji_wattr[(int)JOB_ATR_exec_vnode],
			NULL,
			NULL,
			vnodeout);
		(void)job_attr_def[(int)JOB_ATR_exec_host].at_decode(
			&pjob->ji_wattr[(int)JOB_ATR_exec_host],
			NULL,
			NULL,
			hoststr);
		pjob->ji_modified = 1;
	}
	deallocated_attr = pjob->ji_wattr[(int)JOB_ATR_exec_vnode_deallocated];

	if ((rc == 0) && (deallocated_attr.at_flags & ATR_VFLAG_SET)) {
		char	*hstr = NULL;
		char	*hstr2 = NULL;
		char	*vnalloc = NULL;
		char	*new_exec_vnode_deallocated;

	 	new_exec_vnode_deallocated = deallocated_attr.at_val.at_str;

		rc = set_nodes((void *)pjob, JOB_OBJECT, new_exec_vnode_deallocated,
			 &vnalloc, &hstr, &hstr2, 1, TRUE);
		if (rc != 0) {
			log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, LOG_WARNING,
				pjob->ji_qs.ji_jobid, "warning: Failed to make some nodes aware of a deleted job");
		}
	}

	if ( (pjob->ji_qs.ji_substate == JOB_SUBSTATE_SCHSUSP || pjob->ji_qs.ji_substate == JOB_SUBSTATE_SUSPEND) &&
		(pjob->ji_wattr[(int) JOB_ATR_resc_released].at_flags & ATR_VFLAG_SET) ) {
		/*
		 * Allocating resources back to a suspended job is tricky.
		 * Suspended jobs only hold part of their resources
		 * If set_resc_assigned() is called by a job with the JOB_ATR_resc_released set,
		 * only some of the resources will be acted upon.  Since this
		 * is a fresh job from disk, we need to allocate all of
		 * its resources to it before we partially release some.
		 * We do this by temporarily unsetting JOB_ATR_resc_released attribute while
		 * restoring the job's resources.  This will allocate all of the
		 * requested resources to the job.  We add the flag back to the job
		 * and then decrement the resources released when the job was originally suspended.
		 */
		pjob->ji_wattr[(int) JOB_ATR_resc_released].at_flags &= ~ATR_VFLAG_SET;
		unset_resc_released = 1;
	}

	set_resc_assigned((void *)pjob, 0, INCR);

	if (unset_resc_released == 1) {
		pjob->ji_wattr[(int) JOB_ATR_resc_released].at_flags |= ATR_VFLAG_SET;
		set_resc_assigned((void *) pjob, 0, DECR);
	}
}


/**
 * @brief
 * 		pbsd_init_job - decide what to do with the recovered job structure
 *
 *		The action depends on the type of initialization.
 *
 * @param[in,out]	pjob	- the job.
 * @param[in]	type		- type of initialization.
 *
 * @return	int
 * @retval	0	- success
 * @retval	-1	- error.
 */
static int
pbsd_init_job(job *pjob, int type)
{
	unsigned int d;
	int	 newstate;
	int	 newsubstate;

	pjob->ji_momhandle = -1;
	pjob->ji_mom_prot = PROT_INVALID;

	/* update at_server attribute in case name changed */

	job_attr_def[(int)JOB_ATR_at_server].at_free(
		&pjob->ji_wattr[(int)JOB_ATR_at_server]);
	job_attr_def[(int)JOB_ATR_at_server].at_decode(
		&pjob->ji_wattr[(int)JOB_ATR_at_server],
		NULL, NULL, server_name);

	/* now based on the initialization type */

	if ((type == RECOV_COLD) || (type == RECOV_CREATE)) {
#ifdef WIN32
		if (stalone == 1)
#endif
			need_y_response(type, "jobs exists");
		init_abt_job(pjob);

	} else {

		if (type != RECOV_HOT)
			pjob->ji_qs.ji_svrflags &= ~JOB_SVFLG_HOTSTART;

		/* make sure JOB_SVFLG_RescAssn is cleared,		   */
		/* we will reassign resources if needed	based on the job's */
		/* substate (if the job had resources when server exited   */
		/* JOB_SVFLG_RescAssn is reset when the resources are	   */
		/* reassigned by calling reassign_resc().		   */
		pjob->ji_qs.ji_svrflags &= ~JOB_SVFLG_RescAssn;

		/* Update run_version if it is not set but run_count is,   */
		/* Likely means recovering a job from a older version      */
		if (((pjob->ji_wattr[(int)JOB_ATR_run_version].at_flags & ATR_VFLAG_SET) == 0) && ((pjob->ji_wattr[(int)JOB_ATR_runcount].at_flags & ATR_VFLAG_SET) != 0)) {
			pjob->ji_wattr[(int)JOB_ATR_run_version].at_val.at_long = pjob->ji_wattr[(int)JOB_ATR_runcount].at_val.at_long;
			pjob->ji_wattr[(int)JOB_ATR_run_version].at_flags |= (ATR_VFLAG_SET & ATR_VFLAG_MODCACHE);
		}

		if (pjob->ji_qs.ji_svrflags & JOB_SVFLG_SubJob) {
			if ((pjob->ji_parentaj = find_arrayparent(pjob->ji_qs.ji_jobid)) == NULL) {
				/* parent job object not found */
				init_abt_job(pjob);
				return -1;
			}

			pjob->ji_subjindx = subjob_index_to_offset(pjob->ji_parentaj, get_index_from_jid(pjob->ji_qs.ji_jobid));
			pjob->ji_parentaj->ji_ajtrk->tkm_tbl[pjob->ji_subjindx].trk_psubjob = pjob;
			/* update the tracking table */
			set_subjob_tblstate(pjob->ji_parentaj, pjob->ji_subjindx, pjob->ji_qs.ji_state);
		}

		switch (pjob->ji_qs.ji_substate) {

			case JOB_SUBSTATE_TRANSICM:
				if (pjob->ji_qs.ji_svrflags & JOB_SVFLG_HERE) {

					/*
					 * This server created the job, so client
					 * was qsub (a transient client), it won't be
					 * arround to recommit, so auto-commit now
					 */

					pjob->ji_qs.ji_state = JOB_STATE_QUEUED;
					pjob->ji_qs.ji_substate = JOB_SUBSTATE_QUEUED;
					if (pbsd_init_reque(pjob, CHANGE_STATE) == -1)
						return -1;
				} else {
					/*
					 * another server is sending, append to new job
					 * list and wait for commit; need to clear
					 * receiving sock number though
					 */
					pjob->ji_qs.ji_un.ji_newt.ji_fromsock = -1;
					append_link(&svr_newjobs,
						&pjob->ji_alljobs, pjob);

				}
				break;

			case JOB_SUBSTATE_TRNOUT:
				pjob->ji_qs.ji_state = JOB_STATE_QUEUED;
				pjob->ji_qs.ji_substate = JOB_SUBSTATE_QUEUED;
				/* requeue as queued */
				if (pbsd_init_reque(pjob, CHANGE_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_TRNOUTCM:

				if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) {
					/* was sending to Mom, requeue for now */

					svr_evaljobstate(pjob, &newstate, &newsubstate, 1);
					(void)svr_setjobstate(pjob, newstate, newsubstate);
				} else {
					/* requeue as is - rdy to cmt */

					/* resend rtc */
					set_task(WORK_Immed, 0, resume_net_move, (void *)pjob);
				}
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_QUEUED:
			case JOB_SUBSTATE_PRESTAGEIN:
			case JOB_SUBSTATE_STAGEIN:
			case JOB_SUBSTATE_STAGECMP:
			case JOB_SUBSTATE_STAGEFAIL:
			case JOB_SUBSTATE_STAGEGO:
			case JOB_SUBSTATE_HELD:
			case JOB_SUBSTATE_SYNCHOLD:
			case JOB_SUBSTATE_DEPNHOLD:
			case JOB_SUBSTATE_WAITING:
			case JOB_SUBSTATE_PRERUN:
				if (pbsd_init_reque(pjob, CHANGE_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_PROVISION:
				if (pjob->ji_wattr[(int)JOB_ATR_prov_vnode].at_flags &
					ATR_VFLAG_SET) {
					/* If JOB_ATR_prov_vnode is set, free it */
					job_attr_def[(int)JOB_ATR_prov_vnode].at_free(
						&pjob->ji_wattr[(int)JOB_ATR_prov_vnode]);
				}
				if (pbsd_init_reque(pjob, CHANGE_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_RUNNING:
			case JOB_SUBSTATE_SUSPEND:
			case JOB_SUBSTATE_SCHSUSP:
			case JOB_SUBSTATE_BEGUN:
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				if (pjob->ji_qs.ji_substate == JOB_SUBSTATE_RUNNING ||
					((pjob->ji_wattr[(int) JOB_ATR_resc_released].at_flags & ATR_VFLAG_SET)
					 && (pjob->ji_qs.ji_substate ==  JOB_SUBSTATE_SCHSUSP ||
					pjob->ji_qs.ji_substate == JOB_SUBSTATE_SUSPEND))) {

					reassign_resc(pjob);
					if (type == RECOV_HOT)
						pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HOTSTART;
				}
				break;


			case JOB_SUBSTATE_SYNCRES:

				/* clear all dependent job ready flags */

				if (pbsd_init_reque(pjob, CHANGE_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_TERM:
			case JOB_SUBSTATE_EXITING:
			case JOB_SUBSTATE_STAGEOUT:
			case JOB_SUBSTATE_STAGEDEL:
			case JOB_SUBSTATE_EXITED:
				set_task(WORK_Immed, 0, on_job_exit, (void *)pjob);
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				reassign_resc(pjob);
				break;

			case JOB_SUBSTATE_ABORT:
				/* requeue job and if no nodes assigned,thats all */
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				if ((pjob->ji_qs.ji_svrflags & JOB_SVFLG_HasNodes) != 0) {
					/* has nodes so reassign */
					set_task(WORK_Immed, 0, on_job_exit, (void *)pjob);
					reassign_resc(pjob);
				}
				break;

			case JOB_SUBSTATE_MOVED:
			case JOB_SUBSTATE_FAILED:
			case JOB_SUBSTATE_FINISHED:
			case JOB_SUBSTATE_TERMINATED:
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_RERUN:
				if (pjob->ji_qs.ji_state == JOB_STATE_EXITING)
					set_task(WORK_Immed, 0, on_job_rerun, (void *)pjob);
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				break;

			case JOB_SUBSTATE_RERUN1:
			case JOB_SUBSTATE_RERUN2:
			case JOB_SUBSTATE_RERUN3:
				set_task(WORK_Immed, 0, on_job_rerun, (void *)pjob);
				if (pbsd_init_reque(pjob, KEEP_STATE) == -1)
					return -1;
				break;

			default:
				(void)sprintf(log_buffer,
					msg_init_unkstate, pjob->ji_qs.ji_substate);
				log_event(PBSEVENT_ERROR, PBS_EVENTCLASS_JOB,
					LOG_NOTICE,
					pjob->ji_qs.ji_jobid, log_buffer);
				job_abt(pjob, log_buffer);
				return -1;
		}

		/* update entity limit sums for this job */
		(void)account_entity_limit_usages(pjob, NULL, NULL, INCR, ETLIM_ACC_ALL);

		/* if job has IP address of Mom, it may have changed */
		/* reset based on hostname                           */

		if ((pjob->ji_qs.ji_un_type == JOB_UNION_TYPE_EXEC) &&
			(pjob->ji_qs.ji_un.ji_exect.ji_momaddr != 0)) {

			if (pjob->ji_wattr[(int)JOB_ATR_exec_host].at_flags & ATR_VFLAG_SET) {
				pjob->ji_qs.ji_un.ji_exect.ji_momaddr =
					get_addr_of_nodebyname(
					pjob->ji_wattr[(int)JOB_ATR_exec_host].
					at_val.at_str, &d);
				pjob->ji_qs.ji_un.ji_exect.ji_momport = d;
			} else {
				pjob->ji_qs.ji_un.ji_exect.ji_momaddr = 0;
				pjob->ji_qs.ji_un.ji_exect.ji_momport = 0;
			}
		}
	}
	return 0;
}

/**
 * @brief
 * 		pbsd_init_reque - re-enqueue the job into the queue it was in
 *
 *		update the state, typically to some form of QUEUED.
 *		make sure substate attributes match actual value.
 *
 * @param[in,out]	pjob	- the job.
 * @param[in]	change_state- possible  values,
 * 								CHANGE_STATE - 1
 * 								KEEP_STATE	 - 0
 *
 * @return	int
 * @retval	0	- success
 * @retval	-1	- error.
 */
static int
pbsd_init_reque(job *pjob, int change_state)
{
	char logbuf[384];
	int newstate;
	int newsubstate;
	int rc;

	(void)sprintf(logbuf, msg_init_substate,
		pjob->ji_qs.ji_substate);

	/* re-enqueue the job into the queue it was in */

	if (change_state) {
		/* update the state, typically to some form of QUEUED */
		unset_extra_attributes(pjob);
		svr_evaljobstate(pjob, &newstate, &newsubstate, 1);
		pjob->ji_qs.ji_state =  newstate;
		pjob->ji_qs.ji_substate =  newsubstate;
		if (pjob->ji_qs.ji_svrflags & JOB_SVFLG_SubJob)
			set_subjob_tblstate(pjob->ji_parentaj, pjob->ji_subjindx, newstate);
	}
	set_statechar(pjob);
	/* make sure substate attributes match actual value */
	pjob->ji_wattr[(int)JOB_ATR_substate].at_val.at_long =
		pjob->ji_qs.ji_substate;
	pjob->ji_wattr[(int)JOB_ATR_substate].at_flags |=
		ATR_VFLAG_SET | ATR_VFLAG_MODCACHE;


	if ((rc = svr_enquejob(pjob)) == 0) {
		(void)strcat(logbuf, msg_init_queued);
		(void)strcat(logbuf, pjob->ji_qs.ji_queue);
		log_event(PBSEVENT_SYSTEM | PBSEVENT_ADMIN | PBSEVENT_DEBUG,
			PBS_EVENTCLASS_JOB, LOG_INFO,
			pjob->ji_qs.ji_jobid, logbuf);
	} else {
		if (rc == PBSE_UNKQUE) {

			/* Oops, this should never happen */

			sprintf(logbuf, "%s %s; job %s queue %s",
				msg_err_noqueue, msg_err_noqueue1,
				pjob->ji_qs.ji_jobid, pjob->ji_qs.ji_queue);
		} else if (rc == PBSE_UNKRESC) {
			sprintf(logbuf, "%s %s; job %s",
				msg_err_noqueue, msg_unkresc,
				pjob->ji_qs.ji_jobid);
		} else {
			sprintf(logbuf, "%s; job %s queue %s error %d",
				msg_err_noqueue,
				pjob->ji_qs.ji_jobid, pjob->ji_qs.ji_queue, rc);
		}
		log_err(-1, "pbsd_init", logbuf);
		(void)job_abt(pjob, logbuf);
		return (-1);
	}
	return (0);
}

/**
 * @brief
 * 		catch_child() - the signal handler for  SIGCHLD.
 *		Set a flag for the main loop to know that a child processes
 *		needs to be reaped.
 *
 * @param[in]	sig	- not used in fun.
 *
 * @return	void
 */
static void
catch_child(int sig)
{
	extern int reap_child_flag;

	reap_child_flag = 1;
}

/**
 * @brief
 * 		change_logs - signal handler for SIGHUP
 *		Causes the accounting file and log file to be closed and reopened.
 *		Thus the old one can be renamed.
 *
 * @param[in]	sig	- not used in fun.
 *
 * @return	void
 */
static void
change_logs(int sig)
{
	acct_close();
	log_close(1);
	log_open(log_file, path_log);
	(void)acct_open(acct_file);
	rpp_dbprt = 1 - rpp_dbprt;	/* toggle debug prints for RPP */
}

/**
 * @brief
 * 		stop_me - signal handler for all caught signals which terminate the server
 *
 *		Record the signal so an log_event call can be made outside of
 *		the handler, and set the server state to indicate we should shut down.
 *
 * @param[in]	sig	- not used in fun.
 *
 * @return	void
 */
/*ARGSUSED*/
static void
stop_me(int sig)
{
	server.sv_attr[(int)SRV_ATR_State].at_val.at_long = SV_STATE_SHUTSIG;
}
/**
 * @brief
 * 		chk_save_file - check whether data can be saved into file.
 *
 *		checks include the file permission checks and regular file check.
 *
 * @param[in]	filename	- file which needs to be checked.
 *
 * @return	error code
 * @retval	0	- success
 * @retval	-1	- failure
 */
int
chk_save_file(char *filename)
{
	struct stat sb;

	if (stat(filename, &sb) == -1)
		return (errno);

	if (S_ISREG(sb.st_mode))
		return (0);
	return (-1);
}

/**
 * @brief
 * 		resume_net_move - call net_move() to complete the routing of a job
 *		This is invoked via a work task created on recovery of a job
 *		in JOB_SUBSTATE_TRNOUTCM state.
 *
 * @param[in]	ptask	- work task created on recovery of a job
 *
 * @return	void
 */
static void
resume_net_move(struct work_task *ptask)
{
	net_move((job *)ptask->wt_parm1, 0);
}

/**
 * @brief
 * 		need_y_response - on create/clean initialization that would delete
 *		information, obtain the operator approval first.
 *
 * @param[in]	type	- server initialization mode
 * @param[in]	txt	- text field in msg_startup3 string
 *
 * @return	void
 *
 * @par MT-safe: No
 */
static void
need_y_response(int type, char *txt)
{
	static int answ = -2;
	int c;
	char *t[] = {	"Hot",
		"Warm",
		"Cold",
		"Create"
	};

	char *tp;

	if (answ > 0)
		return;		/* already gotten a response */

	fflush(stdin);
	if ((type > RECOV_CREATE) || (type < RECOV_HOT)) {
		stop_db();
		exit(1);
	}

	tp = t[type];

	printf(msg_startup3, msg_daemonname, server_name, tp, txt);
	while (1) {
		answ = getchar();
		c    = answ;
		while ((c != '\n') && (c != EOF))
			c = getchar();
		switch (answ) {
			case 'y':
			case 'Y':
				return;

			case  EOF:
			case '\n':
			case 'n':
			case 'N':
				printf("PBS server %s initialization aborted\n", server_name);
				stop_db();
				exit(0);
		}
		printf("y(es) or n(o) please:\n");
	}
}

/**
 * @brief
 * 		init_abt_job() - log and email owner message that job is being aborted at
 *		initialization; then purge job (must be called after job is enqueued).
 *
 * @param[in]	pjob	- job
 *
 * @return	void
 */
static void
init_abt_job(job *pjob)
{
	log_event(PBSEVENT_SYSTEM|PBSEVENT_ADMIN| PBSEVENT_DEBUG,
		PBS_EVENTCLASS_JOB, LOG_INFO,
		pjob->ji_qs.ji_jobid, msg_init_abt);
	svr_mailowner(pjob, MAIL_ABORT, MAIL_NORMAL, msg_init_abt);
	check_block(pjob, msg_init_abt);
	job_purge(pjob);
}


/**
 * @brief
 * 		Rmv_if_resv_not_possible - If the job belongs to a reservation that
 *		is no longer possible, or it is a reservation job that is no
 *		longer possible then report back that it should not be requeued.
 *
 * 		If the job is in a standing reservation queue then do not check whether it is
 * 		viable as this will be handled as part of the end event for the occurrence.
 * 		Note that the end event is added to the work task by remove_delete_resvs.
 *
 * @param[in,out]	pjob	- reservation job
 *
 * @return	return code
 * @retval	0	- OK to requeue
 * @retval	1	- should not be requeued
 */
static int
Rmv_if_resv_not_possible(job *pjob)
{
	int	    rc=0;	/*assume OK to requeue*/
	resc_resv   *presv;
	pbs_queue   *pque;



	if (pjob->ji_wattr[JOB_ATR_reserve_state].at_flags &
		ATR_VFLAG_SET) {
		/*we are dealing with a reservation job.  Check
		 *that it's still viable as a reservation, that it's
		 *resc_resv structure exists and, if so, rejoin
		 */

		presv = find_resv(pjob->ji_qs.ji_jobid);
		if (presv == NULL ||
			pjob->ji_wattr[JOB_ATR_reserve_end]
			.at_val.at_long < time_now)
			rc = 1;
		else {
			presv->ri_jbp = pjob;
			pjob->ji_resvp = presv;
		}
	} else {
		if ((pque = find_queuebyname(pjob->ji_qs.ji_queue)) !=0) {
			if ((presv = pque->qu_resvp) !=0) {

				/*we are dealing with a job in a reservation*/

				pjob->ji_myResv = presv;

				/* If a standing reservation then ignore the check for end time
				 * The behavior of a standing reservation differs from that of an
				 * advance one in that only running jobs are deleted at the end of
				 *  an occurrence (be it missed or not).
				 */
				if (presv->ri_wattr[RESV_ATR_resv_count].at_val.at_long > 1)
					return 0;

				if (presv->ri_qs.ri_etime < time_now)
					rc = 1;
			}
		}
	}
	return  (rc);
}


/**
 * @brief
 *  	attach_queue_to_reservation - if the reservation happens to
 *		be supported by a pbs_queue, find the queue and attach
 *		it to the reservation
 *
 * @param[in,out]	presv	- reservation.
 *
 * @return	int
 * @retval	0	- success
 * @retval	-1	- failure
 */
static int
attach_queue_to_reservation(resc_resv *presv)
{
	if (presv == NULL || presv->ri_qs.ri_type != RESC_RESV_OBJECT)
		return (0);
	presv->ri_qp = find_queuebyname(presv->ri_qs.ri_queue);

	if (presv->ri_qp) {
		/*resv points to queue and queue points back*/
		presv->ri_qp->qu_resvp = presv;
		return (0);
	}
	else
		return (-1);
}


/**
 * @brief
 * 		call_log_license - call the routine to long the floating license info
 *
 * @param[in]	ptask	- work task structure.
 *
 * @return	void
 */
static void
call_log_license(struct work_task *ptask)
{
	int	   fd;
	long       ntime;
	struct tm *tms;

	/* log the floating license info */

	log_licenses(&usedlicenses);

	/* reset values for time periods that have passed */

	usedlicenses.lu_max_hr = 0;
	ntime = ptask->wt_event;
	tms = localtime((time_t *)&ntime);
	if (tms->tm_mday != usedlicenses.lu_day) {
		usedlicenses.lu_max_day = 0;
		usedlicenses.lu_day = tms->tm_mday;
	}
	if (tms->tm_mon != usedlicenses.lu_month) {
		usedlicenses.lu_max_month = 0;
		usedlicenses.lu_month = tms->tm_mon;
	}

	/* write current info to file */
	fd = open(path_usedlicenses, O_WRONLY | O_CREAT | O_TRUNC, 0600);
	if (fd != -1) {
		(void)write(fd, &usedlicenses, sizeof(usedlicenses));
		close(fd);
	}

	/* call myself again at the top of the next hour */
	ntime = ((ntime+3601)/3600)*3600;
	(void)set_task(WORK_Timed, ntime, call_log_license, 0);
}

