Ejemplo n.º 1
0
int
job_or_resv_save_fs(void *pobj, int updatetype, int objtype)
{
	int	fds;
	int	openflags;
	int	redo;
	char	*filename;
	char	namebuf1[MAXPATHLEN+1];
	char	namebuf2[MAXPATHLEN+1];

	char		*path = (char*)0;
	char		*err_msg = (char*)0;
	char		*err_msgl = (char*)0;
	char		*prefix = (char*)0;
	char		*suffix = (char*)0;
	char		*cpsuffix = (char*)0;

	char		*p_oid = (char*)0;
	long		*p_mtime = (long*)0;
	int		*p_modified = (int*)0;
	void		*pfixed = (void*)0;
	ssize_t		i;
	size_t		fixed_size;
	attribute_def	*p_attr_def = (attribute_def*)0;
	attribute	*wattr = (attribute*)0;
	int		final_attr;
	int		eventclass;
	int		pmode;

#ifdef WIN32
	pmode = _S_IWRITE | _S_IREAD;
#else
	pmode = 0600;
#endif

	if (objtype == RESC_RESV_OBJECT || objtype == RESV_JOB_OBJECT) {
#ifndef PBS_MOM	/* MOM knows not of resc_resv structs */
		resc_resv  *presv;
		presv = (resc_resv *)pobj;
		err_msg = "reservation_save";
		err_msgl = "Link in reservation_save failed";
		path = path_resvs;
		prefix = presv->ri_qs.ri_fileprefix;
		suffix = RESV_FILE_SUFFIX;
		cpsuffix = RESV_FILE_COPY;
		p_modified = &presv->ri_modified;
		pfixed = (void *)&presv->ri_qs;
		fixed_size = sizeof(struct resvfix);
		p_attr_def = resv_attr_def;
		wattr = presv->ri_wattr;
		final_attr = RESV_ATR_LAST;
		p_mtime = &presv->ri_wattr[RESV_ATR_mtime].at_val.at_long;
		p_oid = presv->ri_qs.ri_resvID;
		eventclass = PBS_EVENTCLASS_RESV;
#else	/* PBS_MOM only: Execution will never come here for MOM */
		return (-1);
#endif
	}
	else if (objtype == JOB_OBJECT) {
		job   *pj = (job *)pobj;

#ifndef PBS_MOM	/*MOM knows not of resc_resv structs*/
		if (pj->ji_resvp) {
			int	rc = 0;

			if (updatetype == SAVEJOB_QUICK)
				rc = job_or_resv_save((void *)pj->ji_resvp,
					SAVERESV_QUICK,
					RESC_RESV_OBJECT);
			else if ((updatetype == SAVEJOB_FULL) ||
				(updatetype == SAVEJOB_FULLFORCE)  ||
				(updatetype == SAVEJOB_NEW))
				rc = job_or_resv_save((void *)pj->ji_resvp,
					SAVERESV_FULL,
					RESC_RESV_OBJECT);
			if (rc)
				return (rc);
		}
#endif
		err_msg = "job_save";
		err_msgl = "Link in job_save failed";
		path = path_jobs;
		if (*pj->ji_qs.ji_fileprefix != '\0')
			prefix = pj->ji_qs.ji_fileprefix;
		else
			prefix = pj->ji_qs.ji_jobid;
		suffix = JOB_FILE_SUFFIX;
		cpsuffix = JOB_FILE_COPY;
		p_modified = &pj->ji_modified;
		pfixed = (void *)&pj->ji_qs;
		fixed_size = sizeof(struct jobfix);
		p_attr_def = job_attr_def;
		wattr = pj->ji_wattr;
		final_attr = JOB_ATR_LAST;
		p_mtime = &pj->ji_wattr[JOB_ATR_mtime].at_val.at_long;
		p_oid = pj->ji_qs.ji_jobid;
		eventclass = PBS_EVENTCLASS_JOB;
		return (job_save_fs(pj, updatetype));
	} else {
		/*Don't expect to get here; incorrect object type*/
		return (-1);
	}

	(void)strcpy(namebuf1, path);		/* directory path */
	(void)strcat(namebuf1, prefix);
	(void)strcpy(namebuf2, namebuf1);	/* setup for later */
	(void)strcat(namebuf1, suffix);

	/*if an attribute changed (modified==1) update mtime*/

	if (*p_modified) {
		*p_mtime = time_now;
	}

	if (updatetype == SAVEJOB_QUICK || updatetype == SAVERESV_QUICK) {

		openflags =  O_WRONLY | O_Sync;
		fds = open(namebuf1, openflags, pmode);
		if (fds < 0) {
			log_err(errno, err_msg, "error on open");
			return (-1);
		}
#ifdef WIN32
		secure_file(namebuf1, "Administrators",
			READS_MASK|WRITES_MASK|STANDARD_RIGHTS_REQUIRED);
		setmode(fds, O_BINARY);
#endif
		/* just write the "critical" base structure to the file */

		while ((i = write(fds, (char *)pfixed, fixed_size)) !=
			fixed_size) {
			if ((i < 0) && (errno == EINTR)) {
				/* retry the write */
				if (lseek(fds, (off_t)0, SEEK_SET) < 0) {
					log_err(errno, err_msg, "lseek");
					(void)close(fds);
					return (-1);
				}
				continue;
			} else {
				log_err(errno, err_msg, "quickwrite");
				(void)close(fds);
				return (-1);
			}
		}
#ifdef WIN32
		if (_commit(fds) != 0) {
			log_err(errno, err_msg,
				"flushing job file to disk failed!");
			(void)close(fds);
			return (-1);
		}
#endif
		(void)close(fds);

	} else {

		/*
		 * write the whole structure to the file.
		 * For a update, this is done to a new file to protect the
		 * old against crashs.
		 * The file is written in four parts:
		 * (1) the job (resc_resv) structure,
		 * (2) the attributes in "encoded" form,
		 * (3) the attributes in the "external" form, and last
		 * (4) the dependency list.
		 */

		(void)strcat(namebuf2, cpsuffix);
		openflags =  O_CREAT | O_WRONLY | O_Sync;
#ifdef WIN32
		fix_perms2(namebuf2, namebuf1);
#endif
		if (updatetype == SAVEJOB_NEW || updatetype == SAVERESV_NEW)
			filename = namebuf1;
		else
			filename = namebuf2;

		fds = open(filename, openflags, pmode);
		if (fds < 0) {
			log_err(errno, err_msg, "open for full save");
			return (-1);
		}

#ifdef WIN32
		secure_file(filename, "Administrators",
			READS_MASK|WRITES_MASK|STANDARD_RIGHTS_REQUIRED);
		setmode(fds, O_BINARY);
#endif

		redo = 0;	/* try to save twice */
		do {
			save_setup(fds);
			if (save_struct((char *)pfixed, fixed_size) != 0) {
				redo++;
			} else if (save_attr_fs(p_attr_def, wattr, final_attr) != 0) {
				redo++;
			} else if (save_flush() != 0) {
				redo++;
			}
			if (redo != 0) {
				if (lseek(fds, (off_t)0, SEEK_SET) < 0) {
					log_err(errno, err_msg, "full lseek");
					redo++;
				}
			}
		} while (redo == 1);

#ifdef WIN32
		if (_commit(fds) != 0) {
			log_err(errno, err_msg,
				"flush job file to disk failed!");
			close(fds);
			return (-1);
		}
#endif

		(void)close(fds);
		if (redo > 1) {
			if (updatetype == SAVEJOB_FULL ||
				updatetype == SAVEJOB_FULLFORCE ||
				updatetype == SAVERESV_FULL)
				(void)unlink(namebuf2);
			return (-1);
		}

		if (updatetype == SAVEJOB_FULL ||
			updatetype == SAVEJOB_FULLFORCE ||
			updatetype == SAVERESV_FULL) {

#ifdef WIN32
			if (MoveFileEx(namebuf2, namebuf1,
				MOVEFILE_REPLACE_EXISTING|MOVEFILE_WRITE_THROUGH) ==
				0) {
				errno = GetLastError();
				sprintf(log_buffer, "MoveFileEx(%s,%s) failed!",
					namebuf2, namebuf1);
				log_err(errno, err_msg, log_buffer);
			}
			secure_file(namebuf1, "Administrators",
				READS_MASK|WRITES_MASK|STANDARD_RIGHTS_REQUIRED);
#else
			if (rename(namebuf2, namebuf1) == -1) {
				log_event(PBSEVENT_ERROR|PBSEVENT_SECURITY,
					eventclass, LOG_ERR, p_oid, err_msgl);
			}
#endif
		}
		*p_modified = 0;
	}
	return (0);
}
Ejemplo n.º 2
0
void
req_confirmresv(struct batch_request *preq)
{
	char		buf[PBS_MAXQRESVNAME+PBS_MAXHOSTNAME+256] = {0}; /* FQDN resvID+text */
	time_t		newstart = 0;
	attribute	*petime = NULL;
	resc_resv	*presv = NULL;
	int		rc = 0;
	int		state = 0;
	int		sub = 0;
	int		resv_count = 0;
	int		is_degraded = 0;
	long		next_retry_time = 0;
	char		*execvnodes = NULL;
	char		*next_execvnode = NULL;
	char		**short_xc = NULL;
	char		**tofree = NULL;
	char		*str_time = NULL;
	extern char	server_host[];
	int		is_being_altered = 0;
	char		*tmp_buf = NULL;
	size_t		tmp_buf_size = 0;

	if ((preq->rq_perm & (ATR_DFLAG_MGWR | ATR_DFLAG_OPWR)) == 0) {
		req_reject(PBSE_PERM, 0, preq);
		return;
	}

	presv = find_resv(preq->rq_ind.rq_run.rq_jid);
	if (presv == NULL) {
		req_reject(PBSE_UNKRESVID, 0, preq);
		return;
	}
	is_degraded = presv->ri_qs.ri_substate == RESV_DEGRADED ? 1 : 0;
	is_being_altered = presv->ri_alter_flags;

	if (preq->rq_extend == NULL) {
		req_reject(PBSE_resvFail, 0, preq);
		return;
	}

	/* If the reservation was degraded and it could not be reconfirmed by the
	 * scheduler, then the retry time for that reservation is reset to the half-
	 * time between now and the time to reservation start or, if the retry time
	 * is invalid, set it to some time after the soonest occurrence is to start
	 */
	if (strcmp(preq->rq_extend, PBS_RESV_CONFIRM_FAIL) == 0) {
		if (is_degraded && !is_being_altered) {
			long degraded_time = presv->ri_degraded_time;
			DBPRT(("degraded_time of %s is %s", presv->ri_qs.ri_resvID, ctime(&degraded_time)));
			next_retry_time = time_now + ((degraded_time - time_now)/2);
			/* If reservation is still degraded, and time of degraded resv to start
			 * is over cutoff from now, then set a time to try again.
			 */
			if (next_retry_time <= (degraded_time - reserve_retry_cutoff)) {

				set_resv_retry(presv, next_retry_time);

				str_time = ctime(&(presv->ri_wattr[RESV_ATR_retry].at_val.at_long));
				if (str_time != NULL) {
					str_time[strlen(str_time)-1] = '\0';
					(void)snprintf(log_buffer, sizeof(log_buffer), "Next attempt to reconfirm reservation will be made on %s", str_time);
					log_event(PBSEVENT_DEBUG2, PBS_EVENTCLASS_RESV, LOG_NOTICE, presv->ri_qs.ri_resvID, log_buffer);
				}
			}
			else {
				/* reached a retry attempt that falls within the cutoff
				 * When processing an advance reservation, unset retry attribute
				 */
				if (presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long == 0) {
					unset_resv_retry(presv);
				}
				else {
					/* When processing a standing reservation, set a retry time
					 * past the end time of the soonest occurrence.
					 */
					set_resv_retry(presv, presv->ri_wattr[RESV_ATR_end].at_val.at_long + RESV_RETRY_DELAY);
				}
			}
		}
		else {
			if (!is_being_altered)
				log_event(PBS_EVENTCLASS_RESV, PBS_EVENTCLASS_RESV,
					LOG_INFO, presv->ri_qs.ri_resvID,
					"Reservation denied");

			/* Clients waiting on an interactive request must be
			 * notified of the failure to confirm
			 */
			if ((presv->ri_brp != NULL) &&
				(presv->ri_wattr[RESV_ATR_interactive].at_flags &
				ATR_VFLAG_SET)) {
				presv->ri_wattr[RESV_ATR_interactive].at_flags &= ~ATR_VFLAG_SET;
				snprintf(buf, sizeof(buf), "%s DENIED",
					presv->ri_qs.ri_resvID);
				(void)reply_text(presv->ri_brp,
					PBSE_NONE, buf);
				presv->ri_brp = NULL;
			}
			if (!is_being_altered) {
				(void)snprintf(log_buffer, sizeof(log_buffer),
					"requestor=%s@%s", msg_daemonname, server_host);
				account_recordResv(PBS_ACCT_DRss, presv, log_buffer);
				log_event(PBSEVENT_DEBUG, PBS_EVENTCLASS_RESV,
					LOG_NOTICE, presv->ri_qs.ri_resvID,
					"reservation deleted");
				resv_purge(presv);
			}
		}
		if (presv->ri_qs.ri_state == RESV_BEING_ALTERED) {
			resv_revert_alter_times(presv);
			log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO,
				  presv->ri_qs.ri_resvID, "Reservation alter denied");
		}
		reply_ack(preq);
		return;
	}

#ifdef NAS /* localmod 122 */
	/* If an advance reservation has already been confirmed there's no
	 * work to be done.
	 */
	if (presv->ri_qs.ri_state == RESV_CONFIRMED &&
		!presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long) {
		reply_ack(preq);
		return;
	}
#endif /* localmod 122 */

	/* Do not alter a reservation that started running when the reconfirmation
	 * message was received. If a standing reservation, then set a retry time
	 * past the end of this occurrence.
	 */
	if (presv->ri_qs.ri_state == RESV_RUNNING) {
		if (presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long)
			set_resv_retry(presv, presv->ri_wattr[RESV_ATR_end].at_val.at_long + 10);
		req_reject(PBSE_TOOLATE, 0, preq);
		return;
	}

	petime = &presv->ri_wattr[RESV_ATR_end];

	/* if passed in the confirmation, set a new start time */
	if ((newstart = (time_t)preq->rq_ind.rq_run.rq_resch) != 0) {
		presv->ri_qs.ri_stime = newstart;
		presv->ri_wattr[RESV_ATR_start].at_val.at_long = newstart;
		presv->ri_wattr[RESV_ATR_start].at_flags
		|= ATR_VFLAG_SET | ATR_VFLAG_MODIFY | ATR_VFLAG_MODCACHE;

		presv->ri_qs.ri_etime = newstart + presv->ri_qs.ri_duration;
		petime->at_val.at_long = presv->ri_qs.ri_etime;
		petime->at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODIFY | ATR_VFLAG_MODCACHE;
	}

	/* The main difference between an advance reservation and a standing
	 * reservation is the format of the execvnodes returned by "rq_destin":
	 * An advance reservation has a single execvnode while a standing reservation
	 * has a sting with the  particular format:
	 *    <num_resv>#<execvnode1>[<range>]<exevnode2>[...
	 * describing the execvnodes associated to each occurrence.
	 */
	if (presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long) {

		/* The number of occurrences in the standing reservation and index are parsed
		 * from the execvnode string which is of the form:
		 *     <num_occurrences>#<vnode1>[range1]<vnode2>[range2]...
		 */
		resv_count = get_execvnodes_count(preq->rq_ind.rq_run.rq_destin);
		if (resv_count == 0) {
			req_reject(PBSE_INTERNAL, 0, preq);
			return;
		}

		execvnodes = strdup(preq->rq_ind.rq_run.rq_destin);
		if (execvnodes == NULL) {
			req_reject(PBSE_SYSTEM, 0, preq);
			return;
		}
		DBPRT(("stdg_resv conf: execvnodes_seq is %s\n", execvnodes));

		/* execvnodes is of the form:
		 *       <num_resv>#<(execvnode1)>[<range>]<(exevnode2)>[...
		 * this "condensed" string is unrolled into a pointer array of
		 * execvnodes per occurrence, e.g. short_xc[0] are the execvnodes
		 * for 1st occurrence, short_xc[1] for the 2nd etc...
		 * If something goes wrong during unrolling then NULL is returned.
		 * which causes the confirmation message to be rejected
		 */
		short_xc = unroll_execvnode_seq(execvnodes, &tofree);
		if (short_xc == NULL) {
			free(execvnodes);
			req_reject(PBSE_SYSTEM, 0, preq);
			return;
		}
		/* The execvnode of the soonest (i.e., next) occurrence */
		next_execvnode = strdup(short_xc[0]);
		if (next_execvnode == NULL) {
			free(short_xc);
			free_execvnode_seq(tofree);
			free(execvnodes);
			req_reject(PBSE_SYSTEM, 0, preq);
			return;
		}
		/* Release the now obsolete allocations used to manipulate the
		 * unrolled string */
		free(short_xc);
		free_execvnode_seq(tofree);
		free(execvnodes);

		/* When confirming for the first time, set the index and count */
		if (!is_degraded) {

			/* Add first occurrence's end date on timed task list */
			if (presv->ri_wattr[RESV_ATR_start].at_val.at_long
				!= PBS_RESV_FUTURE_SCH) {
				if (gen_task_EndResvWindow(presv)) {
					free(next_execvnode);
					req_reject(PBSE_SYSTEM, 0, preq);
					return;
				}
			}
			if (!is_being_altered) {
				presv->ri_wattr[RESV_ATR_resv_count].at_val.at_long = resv_count;
				presv->ri_wattr[RESV_ATR_resv_count].at_flags |= ATR_VFLAG_SET
					| ATR_VFLAG_MODIFY | ATR_VFLAG_MODCACHE;
			}

			/* Set first occurrence to index 1
			 * (rather than 0 because it gets displayed in pbs_rstat -f) */
			presv->ri_wattr[RESV_ATR_resv_idx].at_val.at_long = 1;
			presv->ri_wattr[RESV_ATR_resv_idx].at_flags |= ATR_VFLAG_SET
				| ATR_VFLAG_MODIFY | ATR_VFLAG_MODCACHE;
		}

		/* Skip setting the execvnodes sequence when reconfirming the last
		 * occurrence or when altering a reservation.
		 */
		if (!is_being_altered) {
			if (presv->ri_wattr[RESV_ATR_resv_idx].at_val.at_long
				< presv->ri_wattr[RESV_ATR_resv_count].at_val.at_long) {

				/* now assign the execvnodes sequence attribute */
				(void) resv_attr_def[(int)RESV_ATR_resv_execvnodes].at_free(
					&presv->ri_wattr[(int)RESV_ATR_resv_execvnodes]);

				(void) resv_attr_def[(int)RESV_ATR_resv_execvnodes].at_decode(
					&presv->ri_wattr[(int)RESV_ATR_resv_execvnodes],
					NULL,
					NULL,
					preq->rq_ind.rq_run.rq_destin);
			}
		}
	}
	else { /* Advance reservation */
		next_execvnode = strdup(preq->rq_ind.rq_run.rq_destin);
		if (next_execvnode == NULL) {
			req_reject(PBSE_SYSTEM, 0, preq);
			return;
		}
	}

	/* Is reservation still a viable reservation? */
	if ((rc = chk_resvReq_viable(presv)) != 0) {
		free(next_execvnode);
		req_reject(PBSE_BADTSPEC, 0, preq);
		return;
	}

	/* When reconfirming a degraded reservation, first free the nodes linked
	 * to the reservation and unset all attributes relating to retry attempts
	 */
	if (is_degraded) {
		free_resvNodes(presv);
		/* Reset retry time */
		unset_resv_retry(presv);
		/* reset vnodes_down counter to 0 */
		presv->ri_vnodes_down = 0;
	}

	if (is_being_altered & RESV_END_TIME_MODIFIED) {
		if (gen_task_EndResvWindow(presv)) {
			free(next_execvnode);
			req_reject(PBSE_SYSTEM, 0, preq);
			return;
		}
	}

	/*
	 * Assign the allocated resources to the reservation
	 * and the reservation to the associated vnodes.
	 */
	if (is_being_altered)
		free_resvNodes(presv);
	rc = assign_resv_resc(presv, next_execvnode);

	if (rc != PBSE_NONE) {
		free(next_execvnode);
		req_reject(rc, 0, preq);
		return;
	}

	/* place "Time4resv" task on "task_list_timed" only if this is a
	 * confirmation but not the reconfirmation of a degraded reservation as
	 * in this case, the reservation had already been confirmed and added to
	 * the task list before
	 */
	if (!is_degraded && (is_being_altered != RESV_END_TIME_MODIFIED) &&
		(rc = gen_task_Time4resv(presv)) != 0) {
		free(next_execvnode);
		req_reject(rc, 0, preq);
		return;
	}

	/*
	 * compute new values for state and substate
	 * and update the resc_resv object with these
	 * newly computed values
	 */
	eval_resvState(presv, RESVSTATE_gen_task_Time4resv, 0, &state, &sub);
	(void)resv_setResvState(presv, state, sub);
	cmp_resvStateRelated_attrs((void *)presv,
		presv->ri_qs.ri_type);
	Update_Resvstate_if_resv(presv->ri_jbp);

	if (presv->ri_modified)
		(void)job_or_resv_save((void *)presv, SAVERESV_FULL, RESC_RESV_OBJECT);

	log_buffer[0] = '\0';

	/*
	 * Notify all interested parties that the reservation
	 * is moving from state UNCONFIRMED to CONFIRMED
	 */
	if (presv->ri_brp) {
		presv = find_resv(presv->ri_qs.ri_resvID);
		if (presv->ri_wattr[(int)RESV_ATR_convert].at_val.at_str != NULL) {
			rc = cnvrt_qmove(presv);
			if (rc != 0) {
				snprintf(buf, sizeof(buf), "%.240s FAILED",  presv->ri_qs.ri_resvID);
			} else {
				snprintf(buf, sizeof(buf), "%.240s CONFIRMED",  presv->ri_qs.ri_resvID);
			}
		} else {
			snprintf(buf, sizeof(buf), "%.240s CONFIRMED",  presv->ri_qs.ri_resvID);
		}

		rc = reply_text(presv->ri_brp, PBSE_NONE, buf);
		presv->ri_brp = NULL;
	}

	svr_mailownerResv(presv, MAIL_CONFIRM, MAIL_NORMAL, log_buffer);
	presv->ri_wattr[RESV_ATR_interactive].at_flags &= ~ATR_VFLAG_SET;

	if (is_being_altered) {
		/*
		 * If the reservation is currently running and its start time is being
		 * altered after the current time, It is going back to the confirmed state.
		 * We need to stop the reservation queue as it would have been started at
		 * the original start time.
		 * This will prevent any jobs - that are submitted after the
		 * reservation's start time is changed - from running.
		 * The reservation went to CO from RN while being altered, that means the reservation
		 * had resources assigned. We should decrement their usages until it starts running
		 * again, where the resources will be accounted again.
		 */
		if (presv->ri_qs.ri_state == RESV_CONFIRMED && presv->ri_alter_state == RESV_RUNNING) {
			change_enableORstart(presv, Q_CHNG_START, "FALSE");
			if (presv->ri_giveback) {
				set_resc_assigned((void *)presv, 1, DECR);
				presv->ri_giveback = 0;
			}
		}
		/*
		 * Reset only the flags and end time backup here, as we will need
		 * the start time backup in Time4occurrenceFinish for a standing
		 * reservation. Reset it for an advanced reservation.
		 */
		if (!(presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long)) {
		    presv->ri_alter_stime = 0;
		}
		presv->ri_alter_etime = 0;

		presv->ri_alter_flags = 0;

		log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO,
			  presv->ri_qs.ri_resvID, "Reservation alter confirmed");
	} else {
		log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO,
			  presv->ri_qs.ri_resvID, "Reservation confirmed");
	}

	if (!is_degraded) {
		/* 100 extra bytes for field names, times, and count */
		tmp_buf_size = 100 + strlen(preq->rq_user) + strlen(preq->rq_host) + strlen(next_execvnode);
		if (tmp_buf_size > sizeof(buf)) {
			tmp_buf = malloc(tmp_buf_size);
			if (tmp_buf == NULL) {
				snprintf(log_buffer, LOG_BUF_SIZE-1, "malloc failure (errno %d)", errno);
				log_err(PBSE_SYSTEM, __func__, log_buffer);
				free(next_execvnode);
				reply_ack(preq);
				return;
			}
		} else {
			tmp_buf = buf;
			tmp_buf_size = sizeof(buf);
		}

		if (presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long) {
			(void)snprintf(tmp_buf, tmp_buf_size, "requestor=%s@%s start=%ld end=%ld nodes=%s count=%ld",
				preq->rq_user, preq->rq_host,
				presv->ri_qs.ri_stime, presv->ri_qs.ri_etime,
				next_execvnode,
				presv->ri_wattr[RESV_ATR_resv_count].at_val.at_long);
		} else {
			(void)snprintf(tmp_buf, tmp_buf_size, "requestor=%s@%s start=%ld end=%ld nodes=%s",
				preq->rq_user, preq->rq_host,
				presv->ri_qs.ri_stime, presv->ri_qs.ri_etime,
				next_execvnode);
		}
		account_recordResv(PBS_ACCT_CR, presv, tmp_buf);
		if (tmp_buf != buf) {
			free(tmp_buf);
			tmp_buf_size = 0;
		}
	}

	free(next_execvnode);
	reply_ack(preq);

	return;
}