/*
 * 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.
 *
 */
#include <pbs_config.h>   /* the master config generated by configure */

#include	<stdio.h>
#include	<stdlib.h>
#include	<ctype.h>
#include	<errno.h>
#include	<time.h>
#include	<string.h>
#include	<assert.h>
#include	<tcl.h>

#include	"pbs_error.h"
#include	"pbs_ifl.h"
#include	"log.h"
#include	"resmon.h"
#include	"rm.h"
#include	"cmds.h"
#include	"attribute.h"


char	badparm[] = "%s: bad parameter";
char	missingfd[] = "%s: missing file descriptor";
char	not_connected[] = "not connected";
char	fail[] = "failed";
#ifdef NAS /* localmod 071 */
char*	tcl_atrsep = NULL;
#endif /* localmod 071 */
Tcl_Obj	*pbserr;
Tcl_Obj	*pbsmsg;

int	connector = -1;
int	(*local_disconnect)(int connect) = pbs_disconnect;

#define	SET_PBSERR(value) \
	(void)Tcl_ObjSetVar2(interp, pbserr, NULL, \
	Tcl_NewIntObj((value)), TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)

#define	SET_PBSMSG(msg) \
	(void)Tcl_ObjSetVar2(interp, pbsmsg, NULL, \
	Tcl_NewStringObj((msg), -1), TCL_GLOBAL_ONLY)

#ifdef NAS
	#define PBS_CALL(function) \
		if ( function ) { \
			Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); \
			msg = pbs_geterrmsg(connector); \
			sprintf(log_buffer, "%s: %s (%d)", argv[1], \
				msg ? msg : fail, pbs_errno); \
		if(!quiet) \
		log_err(-1, (char *)argv[0], log_buffer); \
        } \
	else \
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
#else
	#define PBS_CALL(function) \
		if ( function ) { \
			Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); \
			msg = pbs_geterrmsg(connector); \
			sprintf(log_buffer, "%s: %s (%d)", argv[1], \
				msg ? msg : fail, pbs_errno); \
			log_err(-1, (char *)argv[0], log_buffer); \
		 } \
		else \
			Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
#endif

int
OpenRM(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[]; {
	int     port = 0;
	int	fd;
	char	*host;

	if (objc == 3) {
		if (Tcl_GetIntFromObj(interp, objv[2], &port) != TCL_OK)
			return TCL_ERROR;
	} else if (objc != 2) {
		Tcl_WrongNumArgs(interp, 1, objv, "host ?port?");
		return TCL_ERROR;
	}

	host = Tcl_GetStringFromObj(objv[1], NULL);
	if ((fd = openrm(host, port)) < 0) {
		Tcl_PosixError(interp);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, Tcl_GetStringFromObj(objv[0], NULL), host);
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(fd));
	return TCL_OK;
}

int
CloseRM(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int	fd, ret;
	char	*cmd;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (objc != 2) {
		sprintf(log_buffer, missingfd, cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &fd) != TCL_OK)
		return TCL_ERROR;

	if ((ret = closerm(fd)) == -1) {
		Tcl_PosixError(interp);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, cmd, Tcl_GetStringFromObj(objv[1], NULL));
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
DownRM(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int	fd, ret;
	char	*cmd;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (objc != 2) {
		sprintf(log_buffer, missingfd, cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &fd) != TCL_OK)
		return TCL_ERROR;

	if ((ret = downrm(fd)) == -1) {
		Tcl_PosixError(interp);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, cmd, Tcl_GetStringFromObj(objv[1], NULL));
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
ConfigRM(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int	fd, ret;
	char	*cmd, *filename;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (objc != 3) {
		sprintf(log_buffer,
			"%s: missing file descriptor or filename", cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &fd) != TCL_OK)
		return TCL_ERROR;

	filename = Tcl_GetStringFromObj(objv[2], NULL);
	ret = configrm(fd, filename);
	if (ret == -1) {
		Tcl_PosixError(interp);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, cmd, filename);
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
AddREQ(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int	fd, ret;
	char	*cmd, *request;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (objc != 3) {
		sprintf(log_buffer,
			"%s: missing file descriptor or request", cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &fd) != TCL_OK)
		return TCL_ERROR;

	request = Tcl_GetStringFromObj(objv[2], NULL);
	ret = addreq(fd, request);
	if (ret == -1) {
		Tcl_PosixError(interp);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, cmd, request);
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
AllREQ(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	int	ret;

	if (argc != 2) {
		sprintf(log_buffer, "%s: missing request", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	ret = allreq((char *)argv[1]);
	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
GetREQ(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int	fd;
	char	*ret, *getreq();
	char	*cmd;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (objc != 2) {
		sprintf(log_buffer, missingfd, cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &fd) != TCL_OK)
		return TCL_ERROR;

	if ((ret = getreq(fd)) == NULL) {
		if (pbs_errno) {
			Tcl_PosixError(interp);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(pbs_errno, cmd,
				Tcl_GetStringFromObj(objv[1], NULL));
		}
		SET_PBSERR(pbs_errno);
	}
	else {
		int	err = 0;

		Tcl_SetResult(interp, ret, (Tcl_FreeProc *)free);
		if (*ret == '?') {
			if (strlen(ret) > (size_t)2 &&	/* look for err num */
				Tcl_GetInt(interp, &ret[2], &err) != TCL_OK)
				return TCL_ERROR;

		}
		SET_PBSERR(err);
	}

	return TCL_OK;
}

int
FlushREQ(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	if (argc != 1) {
		sprintf(log_buffer, badparm, (char *)argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	flushreq();

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
ActiveREQ(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	int	ret;

	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	ret = activereq();
	if (ret == -1) {
		Tcl_PosixError(interp);
		sprintf(log_buffer, "result %d", ret);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(pbs_errno, (char *)argv[0], log_buffer);
	}

	SET_PBSERR(pbs_errno);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));
	return TCL_OK;
}

int
FullResp(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	int	flag;

	if (argc != 2) {
		sprintf(log_buffer, "%s: missing flag", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetBoolean(interp, (char *)argv[1], &flag) != TCL_OK)
		return TCL_ERROR;

	fullresp(flag);
	SET_PBSERR(0);
	return TCL_OK;
}

int
PBS_Connect(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*server = NULL;

	if (argc == 2)
		server = argv[1];
	else if (argc != 1) {
		sprintf(log_buffer, "%s: wrong # args: ?server?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	local_disconnect(connector);
	pbs_errno = PBSE_NONE;
	if ((connector = pbs_connect(server)) < 0) {
		Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));
		sprintf(log_buffer, "%s (%d)",
			server ? server : "DefaultServer",
			pbs_errno);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], log_buffer);
	}
	else
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_Disconnect(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	pbs_errno = PBSE_NONE;
	local_disconnect(connector);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	connector = -1;

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

Tcl_Obj	*
attrlist(interp, ap)
Tcl_Interp	*interp;
struct	attrl	*ap;
{
	Tcl_Obj	*ret;

	ret = Tcl_NewListObj(0, NULL);	/* null list */
	while (ap) {
		Tcl_Obj	*twol[2];

		twol[0] = Tcl_NewStringObj(ap->name, -1);
		if (ap->resource) {
			Tcl_AppendStringsToObj(twol[0],
#ifdef NAS /* localmod 071 */
				tcl_atrsep, ap->resource, NULL);
#else
				TCL_ATRSEP, ap->resource, NULL);
#endif /* localmod 071 */
		}
		twol[1] = Tcl_NewStringObj(ap->value, -1);
		Tcl_ListObjAppendElement(interp, ret, Tcl_NewListObj(2, twol));

		ap = ap->next;
	}
	return (ret);
}

void
batresult(interp, bs)
Tcl_Interp	*interp;
struct	batch_status	*bs;
{
	Tcl_Obj	*batchl;
	struct	batch_status	*bp;

	batchl = Tcl_NewObj();		/* empty list */
	for (bp=bs; bp; bp=bp->next) {
		Tcl_Obj	*threel[3];

		threel[0] = Tcl_NewStringObj(bp->name, -1);
		threel[1] = attrlist(interp, bp->attribs);
		threel[2] = Tcl_NewStringObj(bp->text, -1);

		Tcl_ListObjAppendElement(interp, batchl,
			Tcl_NewListObj(3, threel));

	}
	Tcl_SetObjResult(interp, batchl);
	pbs_statfree(bs);
}

int
PBS_StatServ(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	struct	batch_status	*bs;
	Tcl_Obj	*threel[3];

	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((bs = pbs_statserver(connector, NULL, NULL)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, (char *)argv[0], log_buffer);
		}
	}
	else {
		threel[0] = Tcl_NewStringObj(bs->name, -1);
		threel[1] = attrlist(interp, bs->attribs);
		threel[2] = Tcl_NewStringObj(bs->text, -1);

		Tcl_SetObjResult(interp, Tcl_NewListObj(3, threel));

		pbs_statfree(bs);
	}

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_StatJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	struct	batch_status	*bs;
	char    *extend = NULL;

	if (argc > 2) {  /* can have one argument for extend field */
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	if (argc == 2) {
		extend = (char *)argv[1];
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((bs = pbs_statjob(connector, NULL, NULL, extend)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, (char *)argv[0], log_buffer);
		}
	}
	else
		batresult(interp, bs);

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_SelStat(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	struct	batch_status	*bs;

	static	struct	attropl	att1 = {
		NULL,
		"queue_type",
		NULL,
		"E",
		EQ
	};
	static	struct	attropl	att2 = {
		&att1,
		"job_state",
		NULL,
		"Q",
		EQ
	};

	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((bs = pbs_selstat(connector, &att2, NULL, NULL)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, (char *)argv[0], log_buffer);
		}
	}
	else
		batresult(interp, bs);

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_StatQue(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	struct	batch_status	*bs;

	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((bs = pbs_statque(connector, NULL, NULL, NULL)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, (char *)argv[0], log_buffer);
		}
	}
	else
		batresult(interp, bs);

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_StatNode(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	char	*msg, *cmd;
	char	*node = NULL;
	struct	batch_status	*bs;

	if (objc == 2)
		node = Tcl_GetStringFromObj(objv[1], NULL);
	else if (objc != 1) {
		Tcl_WrongNumArgs(interp, 1, objv, "?node?");
		return TCL_ERROR;
	}

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((bs = pbs_statnode(connector, node, NULL, NULL)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, cmd, log_buffer);
		}
	}
	else
		batresult(interp, bs);

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_AsyRunJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	char	*location = NULL;

	if (argc == 3)
		location = (char *)argv[2];
	else if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id ?location?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	PBS_CALL(pbs_asyrunjob(connector, (char *)argv[1], location, NULL))

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}


int
PBS_RunJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	char	*location = NULL;

	if (argc == 3)
		location = (char *)argv[2];
	else if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id ?location?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	PBS_CALL(pbs_runjob(connector, (char *)argv[1], location, NULL))

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_ReRun(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int	argc;
char	*argv[];
{
	char	*msg;
	char	*extend = "0";

	if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	PBS_CALL(pbs_rerunjob(connector, (char *)argv[1], extend))

	SET_PBSERR(pbs_errno);

	return TCL_OK;
}


int
PBS_MoveJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	char	*location = NULL;
	char	job_id_out[PBS_MAXCLTJOBID];
	char	server_out[MAXSERVERNAME];

	if (argc == 3)
		location = (char *)argv[2];
	else if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id ?location?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if (get_server((char *)argv[1], job_id_out, server_out)) {
		msg = pbs_geterrmsg(connector);
		sprintf(log_buffer, "%s: %s (%d)", argv[1],
			msg ? msg : fail, pbs_errno);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	PBS_CALL(pbs_movejob(connector, job_id_out, location, NULL))

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_DelJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;
	char	*message = NULL;

	if (argc == 3)
		message = (char *)argv[2];
	else if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id ?message?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	PBS_CALL(pbs_deljob(connector, (char *)argv[1], message))

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}


int
PBS_HoldJob(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	char	*msg;

	if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: job_id", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	PBS_CALL(pbs_holdjob(connector, (char *)argv[1], SYSTEM_HOLD, NULL))

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_QueueOp(clientData, interp, argc, argv, attr)
ClientData		clientData;
Tcl_Interp		*interp;
int			argc;
char		*argv[];
struct attropl	*attr;
{
	int	merr;

	if (argc != 2) {
		sprintf(log_buffer,
			"%s: wrong # args: queue", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, (char *)argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	merr = pbs_manager(connector, MGR_CMD_SET, MGR_OBJ_QUEUE,
		(char *)argv[1], attr, NULL);
	if (merr != 0) {
		sprintf(log_buffer, "%s: %s %s", argv[0], argv[1],
			pbs_geterrmsg(connector));
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_EnableQueue(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	static struct attropl attr = {NULL, "enabled", NULL, "TRUE", SET};
	return PBS_QueueOp(clientData, interp, argc, argv, &attr);
}

int
PBS_DisableQueue(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	static struct attropl attr = {NULL, "enabled", NULL, "FALSE", SET};
	return PBS_QueueOp(clientData, interp, argc, argv, &attr);
}

int
PBS_StartQueue(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	static struct attropl attr = {NULL, "started", NULL, "TRUE", SET};
	return PBS_QueueOp(clientData, interp, argc, argv, &attr);
}

int
PBS_StopQueue(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	static struct attropl attr = {NULL, "started", NULL, "FALSE", SET};
	return PBS_QueueOp(clientData, interp, argc, argv, &attr);
}

int
PBS_AlterJob(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	static char id[] = "PBS_AlterJob";
	char	*msg;
	int	i, num, tre, ret;
	Tcl_Obj	**listp, **indp;
	struct	attrl	*attrs, *atp = NULL;
	char	*cmd, *jobid;

	if (objc != 3) {
		Tcl_WrongNumArgs(interp, 1, objv, "job_id attribute(s)");
		return TCL_ERROR;
	}

	if ((ret = Tcl_ListObjGetElements(interp, objv[2],
		&num, &listp)) != TCL_OK)
		return ret;
	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	attrs = NULL;
	for (i=0; i<num; i++) {
		if ((ret = Tcl_ListObjGetElements(interp, listp[i],
			&tre, &indp)) != TCL_OK)
			goto done;
		if (tre != 3) {
			sprintf(log_buffer,
				"%s: bad attribute format: %s",
				cmd, Tcl_GetStringFromObj(listp[i], NULL));
			Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
			ret = TCL_ERROR;
			goto done;
		}
		atp = new_attrl();
		if (atp == NULL) {
			sprintf(log_buffer, "Unable to allocate memory (malloc error)");
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(errno, id, log_buffer);
			return TCL_ERROR;
		}
		if ((atp->name = strdup(Tcl_GetStringFromObj(indp[0], NULL))) == NULL) {
			sprintf(log_buffer, "Unable to allocate memory (malloc error)");
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(errno, id, log_buffer);
			free(atp);
			return TCL_ERROR;
		}
		if ((atp->resource = strdup(Tcl_GetStringFromObj(indp[1], NULL))) == NULL) {
			sprintf(log_buffer, "Unable to allocate memory (malloc error)");
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(errno, id, log_buffer);
			free(atp->name);
			free(atp);
			return TCL_ERROR;
		}
		if ((atp->value = strdup(Tcl_GetStringFromObj(indp[2], NULL))) == NULL) {
			sprintf(log_buffer, "Unable to allocate memory (malloc error)");
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(errno, id, log_buffer);
			free(atp->resource);
			free(atp->name);
			free(atp);
			return TCL_ERROR;
		}
		atp->next = attrs;
		attrs = atp;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		goto done;
	}

	jobid = Tcl_GetStringFromObj(objv[1], NULL);
	if (pbs_alterjob(connector, jobid, atp, NULL)) {
		Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));
		msg = pbs_geterrmsg(connector);
		sprintf(log_buffer, "%s: %s (%d)", jobid,
			msg ? msg : fail, pbs_errno);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, log_buffer);
	}
	else
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));

done:
	for (atp=attrs; attrs; atp=attrs) {
		attrs = atp->next;
		free(atp->name);
		free(atp->resource);
		free(atp->value);
		free(atp);
	}

	SET_PBSERR(pbs_errno);
	return ret;
}

int
PBS_RescQuery(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	static char id[] = "PBS_RescQuery";
	char	*msg;
	int	i, num, ret;
	Tcl_Obj	**listp, *fourl[4], *retl;
	char	*cmd;
	char	**res_array;
	int	*avail_array, *alloc_array, *reser_array, *down_array;

	if (objc != 2) {
		Tcl_WrongNumArgs(interp, 1, objv, "{resource1 resource2 ...}");
		return TCL_ERROR;
	}

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if ((ret = Tcl_ListObjGetElements(interp, objv[1],
		&num, &listp)) != TCL_OK)
		return ret;
	if (num == 0) {
		sprintf(log_buffer, "%s: null resource list", cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	res_array = (char **)malloc(sizeof(char *) * num);
	if (res_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		return TCL_ERROR;
	}
	avail_array = (int *)malloc(sizeof(int) * num);
	if (avail_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		free(res_array);
		return TCL_ERROR;
	}
	alloc_array = (int *)malloc(sizeof(int) * num);
	if (alloc_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		free(res_array);
		free(avail_array);
		return TCL_ERROR;
	}
	reser_array = (int *)malloc(sizeof(int) * num);
	if (reser_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		free(res_array);
		free(avail_array);
		free(alloc_array);
		return TCL_ERROR;
	}
	down_array = (int *)malloc(sizeof(int) * num);
	if (down_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		free(res_array);
		free(avail_array);
		free(alloc_array);
		free(reser_array);
		return TCL_ERROR;
	}
	for (i=0; i<num; i++)
		res_array[i] = Tcl_GetStringFromObj(listp[i], NULL);

	retl = Tcl_NewObj();		/* empty list */
	if (pbs_rescquery(connector, res_array, num,
		avail_array, alloc_array, reser_array, down_array)) {
		msg = pbs_geterrmsg(connector);
		sprintf(log_buffer, "%s (%d)", msg ? msg : fail, pbs_errno);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, log_buffer);
	}
	else {
		for (i=0; i<num; i++) {
			fourl[0] = Tcl_NewIntObj(avail_array[i]);
			fourl[1] = Tcl_NewIntObj(alloc_array[i]);
			fourl[2] = Tcl_NewIntObj(reser_array[i]);
			fourl[3] = Tcl_NewIntObj(down_array[i]);

			Tcl_ListObjAppendElement(interp, retl,
				Tcl_NewListObj(4, fourl));
		}
	}
	Tcl_SetObjResult(interp, retl);

	free(res_array);
	free(avail_array);
	free(alloc_array);
	free(reser_array);
	free(down_array);

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_RescReserve(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	static char id[] = "PBS_RescReserve";
	char	*msg;
	int	i, num, ret;
	Tcl_Obj	**listp;
	char	*cmd;
	char	**res_array;
	pbs_resource_t	resid;

	if (objc != 3) {
		Tcl_WrongNumArgs(interp, 1, objv,
			"resource_id {resource1 resource2 ...}");
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &resid) != TCL_OK)
		return TCL_ERROR;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);
	if ((ret = Tcl_ListObjGetElements(interp, objv[2],
		&num, &listp)) != TCL_OK)
		return ret;
	if (num == 0) {
		sprintf(log_buffer, "%s: null resource list", cmd);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	res_array = (char **)malloc(sizeof(char *) * num);
	if (res_array == NULL) {
		sprintf(log_buffer, "Unable to allocate memory (malloc error)");
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(errno, id, log_buffer);
		return TCL_ERROR;
	}
	for (i=0; i<num; i++)
		res_array[i] = Tcl_GetStringFromObj(listp[i], NULL);

	pbs_errno = 0;
	if (pbs_rescreserve(connector, res_array, num, &resid) != 0) {
		msg = pbs_geterrmsg(connector);
		sprintf(log_buffer, "%s (%d)", msg ? msg : fail, pbs_errno);
		SET_PBSMSG(log_buffer);
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(resid));

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_RescRelease(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	char	*msg;
	int	ret;
	char	*cmd;
	pbs_resource_t	resid;

	if (objc != 2) {
		Tcl_WrongNumArgs(interp, 1, objv, "resource_id");
		return TCL_ERROR;
	}

	if (Tcl_GetIntFromObj(interp, objv[1], &resid) != TCL_OK)
		return TCL_ERROR;

	cmd = Tcl_GetStringFromObj(objv[0], NULL);

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}

	if ((ret = pbs_rescrelease(connector, resid)) != 0) {
		msg = pbs_geterrmsg(connector);
		sprintf(log_buffer, "%s (%d)", msg ? msg : fail, pbs_errno);
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, cmd, log_buffer);
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(ret));

	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_ResvStatus(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*CONST	argv[];
{
	char			*msg;
	struct batch_status	*bs;

	if (argc != 1) {
		sprintf(log_buffer, badparm, argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}
	if ((bs = pbs_statresv(connector, NULL, NULL, NULL)) == NULL) {
		if (pbs_errno != PBSE_NONE) {
			msg = pbs_geterrmsg(connector);
			sprintf(log_buffer, "%s (%d)",
				msg ? msg : fail, pbs_errno);
			#ifdef NAS
				if(!quiet)
			#endif
			log_err(-1, argv[0], log_buffer);
		}
	}
	else
		batresult(interp, bs);
	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_ResvConfirm(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*CONST	argv[];
{
	char		*msg = NULL;
	unsigned long	stime = 0;

	if (argc < 2 || argc > 4) {
		sprintf(log_buffer,
			"%s: wrong # args: resv_id vnodes ?stime? ?reason?",
			argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	if (argc == 4) {
		msg = argv[3];
	}
	if (argc == 3) {
		stime = strtoul(argv[2], NULL, 10);
	}
	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}
	PBS_CALL(pbs_confirmresv(connector, argv[1], argv[2], stime, msg))
	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
PBS_ResvDelete(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*CONST	argv[];
{
	char	*msg = NULL;

	if (argc < 2 || argc > 3) {
		sprintf(log_buffer,
			"%s: wrong # args: resv_id ?reason?", argv[0]);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	if (argc == 3)
		msg = argv[2];
	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, argv[0], not_connected);
		SET_PBSERR(PBSE_NOSERVER);
		return TCL_OK;
	}
	PBS_CALL(pbs_delresv(connector, argv[1], msg))
	SET_PBSERR(pbs_errno);
	return TCL_OK;
}

int
LogMsg(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	char	*tag = NULL;
	char	*msg = NULL;

	if (objc != 3) {
		Tcl_WrongNumArgs(interp, 1, objv, "tag message");
		return TCL_ERROR;
	} else {
		tag = Tcl_GetStringFromObj(objv[1], NULL);
		msg = Tcl_GetStringFromObj(objv[2], NULL);
	}

	if (connector < 0) {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, tag, not_connected);
		Tcl_SetObjResult(interp, Tcl_NewIntObj(-1));
	} else {
		#ifdef NAS
			if(!quiet)
		#endif
		log_err(-1, tag, msg);
		Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
	}

	return TCL_OK;
}

int
DateTime(clientData, interp, argc, argv)
ClientData	clientData;
Tcl_Interp	*interp;
int		argc;
char	*argv[];
{
	time_t		when;
	struct	tm	tm, *t = NULL;
	int		i, yyy, len;
	char		rtime[64], hold[8];
	static	char	*wkday[] = { "Sun", "Mon", "Tue", "Wed",
		"Thu", "Fri", "Sat", NULL };

	switch (argc) {

		case 1:			/* current date/time */
			when = time(NULL);
			sprintf(log_buffer, "%ld", (long)when);
			Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
			return TCL_OK;

		case 2:
			snprintf(rtime, sizeof(rtime), "%s", argv[1]);
			len = strlen(rtime);
			when = 0;
			if (len < 12)
				break;

			/* absolute date/time */
			for (i=0; i<len; i++) {
				if (!isdigit(rtime[i]))
					break;
			}
			if (i != len || len > 14) {
				sprintf(log_buffer,
					"%s: bad absolute date format: %s",
					argv[0], rtime);
				Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
				return TCL_ERROR;
			}

			yyy = len - 10;
			for (i=0; i<yyy; i++)
				hold[i] = rtime[i];
			hold[i] = '\0';
			tm.tm_year = atoi(hold);

			hold[0] = rtime[i++];
			hold[1] = rtime[i++];
			hold[2] = '\0';
			tm.tm_mon = atoi(hold) - 1;

			hold[0] = rtime[i++];
			hold[1] = rtime[i++];
			tm.tm_mday = atoi(hold);

			hold[0] = rtime[i++];
			hold[1] = rtime[i++];
			tm.tm_hour = atoi(hold);

			hold[0] = rtime[i++];
			hold[1] = rtime[i++];
			tm.tm_min = atoi(hold);

			hold[0] = rtime[i++];
			hold[1] = rtime[i];
			tm.tm_sec = atoi(hold);
			tm.tm_isdst = -1;

			when = mktime(&tm);
			if (when == -1) {
				sprintf(log_buffer,
					"%s: could not convert date: %s",
					argv[0], rtime);
				Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
				return TCL_ERROR;
			}
			Tcl_SetObjResult(interp, Tcl_NewLongObj((long)when));
			return TCL_OK;

		case 3:			/* relative weekday */
			for (i=0; wkday[i]; i++) {
				if (strcmp(argv[1], wkday[i]) == 0)
					break;
			}
			if (wkday[i] == NULL) {
				sprintf(log_buffer,
					"%s: unrecognized weekday: %s",
					argv[0], argv[1]);
				Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
				return TCL_ERROR;
			}
			when = time(NULL);
			t = localtime(&when);
			t->tm_mday += (i - t->tm_wday + 7) % 7;
			t->tm_hour = 0;
			t->tm_min = 0;
			t->tm_sec = 0;
			t->tm_isdst = -1;
			when = mktime(t);
			snprintf(rtime, sizeof(rtime), "%s", argv[2]);
			len = strlen(rtime);
			break;

		default:
			sprintf(log_buffer,
				"%s: wrong # args: ?day? ?time?", argv[0]);
			Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
			return TCL_ERROR;
	}

	if (len != 8 || rtime[2] != ':' || rtime[5] != ':' ||
		!isdigit(rtime[0]) || !isdigit(rtime[1]) ||
		!isdigit(rtime[3]) || !isdigit(rtime[4]) ||
		!isdigit(rtime[6]) || !isdigit(rtime[7])) {
		sprintf(log_buffer,
			"%s: bad relative time format: %s", argv[0], rtime);
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}
	rtime[2] = rtime[5] = '\0';
	when += atoi(&rtime[0])*3600 +
		atoi(&rtime[3])*60 + atoi(&rtime[6]);

	Tcl_SetObjResult(interp, Tcl_NewLongObj((long)when));
	return TCL_OK;
}

int
StrFtime(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	struct	tm	*t;
	long		hold;
	time_t		when;

	if (objc != 3) {
		sprintf(log_buffer,
			"%s: wrong # args: format time",
			Tcl_GetStringFromObj(objv[0], NULL));
		Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);
		return TCL_ERROR;
	}

	if (Tcl_GetLongFromObj(interp, objv[2], &hold) != TCL_OK)
		return TCL_ERROR;

	when = (time_t)hold;
	t = localtime(&when);
	(void)strftime(log_buffer, LOG_BUF_SIZE,
		Tcl_GetStringFromObj(objv[1], NULL), t);
	Tcl_SetResult(interp, log_buffer, TCL_VOLATILE);

	return TCL_OK;
}

int
PBS_PbsPortInfoCmd(clientData, interp, objc, objv)
ClientData	clientData;
Tcl_Interp	*interp;
int		objc;
Tcl_Obj	*CONST	objv[];
{
	int index, result;
	static const char *subCmds[] = {
		"batch_service_port", "batch_service_port_dis",
		"mom_service_port", "manager_service_port",
		"scheduler_service_port", NULL};
	enum ISubCmdIdx {
		IBatchSvcIdx, IBatchSvcDisIdx,
		IMomSvcIdx, IManSvcIdx,
		ISchedSvcIdx
	};

	if (objc != 2) {
		Tcl_WrongNumArgs(interp, 1, objv, "batch_service_port|batch_service_port_dis|mom_service_port|manager_service_port|scheduler_service_port");
		return TCL_ERROR;
	}

	result = Tcl_GetIndexFromObj(interp, objv[1], subCmds, "option", 0, &index);
	if (result != TCL_OK) {
		return result;
	}

	switch (index) {
		case IBatchSvcIdx:
			result = pbs_conf.batch_service_port;
			break;
		case IBatchSvcDisIdx:
			result = pbs_conf.batch_service_port_dis;
			break;
		case IMomSvcIdx:
			result = pbs_conf.mom_service_port;
			break;
		case IManSvcIdx:
			result = pbs_conf.manager_service_port;
			break;
		case ISchedSvcIdx:
			result = pbs_conf.scheduler_service_port;
			break;
	}

	Tcl_SetObjResult(interp, Tcl_NewIntObj(result));
	return TCL_OK;
}

void
add_cmds(interp)
Tcl_Interp	*interp;
{
	extern	void	site_cmds(Tcl_Interp *interp);

	Tcl_CreateObjCommand(interp, "openrm", OpenRM, NULL, NULL);
	Tcl_CreateObjCommand(interp, "closerm", CloseRM, NULL, NULL);
	Tcl_CreateObjCommand(interp, "downrm", DownRM, NULL, NULL);
	Tcl_CreateObjCommand(interp, "configrm", ConfigRM, NULL, NULL);
	Tcl_CreateObjCommand(interp, "getreq", GetREQ, NULL, NULL);
	Tcl_CreateObjCommand(interp, "addreq", AddREQ, NULL, NULL);
	Tcl_CreateCommand(interp, "allreq", AllREQ, NULL, NULL);
	Tcl_CreateCommand(interp, "flushreq", FlushREQ, NULL, NULL);
	Tcl_CreateCommand(interp, "activereq", ActiveREQ, NULL, NULL);
	Tcl_CreateCommand(interp, "fullresp", FullResp, NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsportinfo", PBS_PbsPortInfoCmd,
		NULL, NULL);
	Tcl_CreateCommand(interp, "pbsconnect", PBS_Connect, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsdisconnect", PBS_Disconnect, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsstatserv", PBS_StatServ, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsstatjob", PBS_StatJob, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsstatque", PBS_StatQue, NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsstatnode", PBS_StatNode, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsselstat", PBS_SelStat, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsrunjob", PBS_RunJob, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsmovejob", PBS_MoveJob, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsqenable", PBS_EnableQueue, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsqdisable", PBS_DisableQueue, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsqstart", PBS_StartQueue, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsqstop", PBS_StopQueue, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsasyrunjob", PBS_AsyRunJob, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsdeljob", PBS_DelJob, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsholdjob", PBS_HoldJob, NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsalterjob", PBS_AlterJob, NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsrescquery", PBS_RescQuery, NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsrescreserve", PBS_RescReserve,
		NULL, NULL);
	Tcl_CreateObjCommand(interp, "pbsrescrelease", PBS_RescRelease,
		NULL, NULL);
	Tcl_CreateCommand(interp, "pbsresvstat", PBS_ResvStatus, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsresvconf", PBS_ResvConfirm, NULL, NULL);
	Tcl_CreateCommand(interp, "pbsresvdel", PBS_ResvDelete, NULL, NULL);
	Tcl_CreateObjCommand(interp, "logmsg", LogMsg, NULL, NULL);
	Tcl_CreateCommand(interp, "datetime", DateTime, NULL, NULL);
	Tcl_CreateObjCommand(interp, "strftime", StrFtime, NULL, NULL);

	/*
	 * Extended scheduler commands from Univ. of Colorado
	 */
	Tcl_CreateCommand(interp, "pbsrerunjob", PBS_ReRun, NULL, NULL);

	/*
	 * Initialize global variables pbs_errno and pbs_errmsg
	 */
	pbserr = Tcl_NewStringObj("pbs_errno", -1);
	Tcl_ObjSetVar2(interp, pbserr, NULL, Tcl_NewIntObj((0)),
		TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
	pbsmsg = Tcl_NewStringObj("pbs_errmsg", -1);
	Tcl_ObjSetVar2(interp, pbsmsg, NULL, Tcl_NewStringObj("no msg", -1),
		TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);

#ifdef NAS /* localmod 071 */
	if (tcl_atrsep)
		free(tcl_atrsep);
	tcl_atrsep = strdup(TCL_ATRSEP);
#endif /* localmod 071 */
	site_cmds(interp);
}
