Example #1
0
void
req_stat_resv(struct batch_request * preq)
{
	char		   *name;
	struct batch_reply *preply;
	resc_resv	   *presv = NULL;
	int		    rc   = 0;
	int		    type = 0;

	/*
	 * first, validate the name sent in the request.
	 * This is either the ID of a specific reservation
	 * or a '\0' or "@..." for all reservations.
	 */

	name = preq->rq_ind.rq_status.rq_id;

	if ((*name == '\0') || (*name =='@'))
		type = 1;
	else {
		presv = find_resv(name);
		if (presv == NULL) {
			req_reject(PBSE_UNKRESVID, 0, preq);
			return;
		}
	}

	preply = &preq->rq_reply;
	preply->brp_choice = BATCH_REPLY_CHOICE_Status;
	CLEAR_HEAD(preply->brp_un.brp_status);

	if (type == 0) {
		/* get status of the specifically named reservation */
		rc = status_resv(presv, preq, &preply->brp_un.brp_status);

	} else {
		/* get status of all the reservations */

		presv = (resc_resv *)GET_NEXT(svr_allresvs);
		while (presv) {
			rc = status_resv(presv, preq, &preply->brp_un.brp_status);
			if (rc == PBSE_PERM)
				rc = 0;
			if (rc)
				break;
			presv = (resc_resv *)GET_NEXT(presv->ri_allresvs);
		}
	}

	if (rc == 0)
		(void)reply_send(preq);
	else
		req_reject(rc, bad, preq);
}
Example #2
0
resc_resv  *
chk_rescResv_request(char *resvID, struct batch_request *preq)
{
	resc_resv	*presv;

	if ((presv = find_resv(resvID)) == NULL) {
		log_event(PBSEVENT_DEBUG, PBS_EVENTCLASS_RESV, LOG_INFO,
			resvID, msg_unkresvID);
		req_reject(PBSE_UNKRESVID, 0, preq);
		return NULL;
	}

	if (svr_authorize_resvReq(preq, presv) == -1) {
		(void)sprintf(log_buffer, msg_permlog, preq->rq_type,
			"RESCRESV", presv->ri_qs.ri_resvID,
			preq->rq_user, preq->rq_host);
		log_event(PBSEVENT_SECURITY, PBS_EVENTCLASS_RESV, LOG_INFO,
			presv->ri_qs.ri_resvID, log_buffer);
		req_reject(PBSE_PERM, 0, preq);
		return NULL;
	}

	return (presv);
}
Example #3
0
/**
 * @brief Service the Modify Reservation Request from client such as pbs_ralter.
 *
 *	This request atomically modifies one or more of a reservation's attributes.
 *	An error is returned to the client if the user does not have permission
 *	to perform the modification, the attribute is read-only, the reservation is
 *	running and the attribute is only modifiable when the reservation is not
 *	running or is empty.
 *
 * @param[in] preq - pointer to batch request from client
 */
void
req_modifyReservation(struct batch_request *preq)
{
	char		*rid = NULL;
	svrattrl	*psatl = NULL;
	attribute_def	*pdef = NULL;
	int		rc = 0;
	int		bad = 0;
	char		buf[PBS_MAXUSER + PBS_MAXHOSTNAME + 32] = {0};
	int		sock;
	int		resc_access_perm_save = 0;
	int		send_to_scheduler = 0;
	int		log_len = 0;
	char		*fmt = "%a %b %d %H:%M:%S %Y";
	int		is_standing = 0;
	int		next_occr_start = 0;
	extern char	*msg_stdg_resv_occr_conflict;
	resc_resv	*presv;

	if (preq == NULL)
		return;

	sock = preq->rq_conn;

	presv = chk_rescResv_request(preq->rq_ind.rq_modify.rq_objname, preq);
	/* Note: on failure, chk_rescResv_request invokes req_reject
	 * appropriate reply is sent and batch_request is freed.
	 */
	if (presv == NULL)
		return;

	rid = preq->rq_ind.rq_modify.rq_objname;
	if ((presv = find_resv(rid)) == NULL) {
		/* Not on "all_resvs" list try "new_resvs" list */
		presv = (resc_resv *)GET_NEXT(svr_newresvs);
		while (presv) {
			if (!strcmp(presv->ri_qs.ri_resvID, rid))
				break;
			presv = (resc_resv *)GET_NEXT(presv->ri_allresvs);
		}
	}

	if (presv == NULL) {
		req_reject(PBSE_UNKRESVID, 0, preq);
		return;
	}

	is_standing = presv->ri_wattr[RESV_ATR_resv_standing].at_val.at_long;
	if (is_standing)
		next_occr_start = get_occurrence(presv->ri_wattr[RESV_ATR_resv_rrule].at_val.at_str,
					presv->ri_wattr[RESV_ATR_start].at_val.at_long,
					presv->ri_wattr[RESV_ATR_resv_timezone].at_val.at_str, 2);

	resc_access_perm_save = resc_access_perm;
	psatl = (svrattrl *)GET_NEXT(preq->rq_ind.rq_modify.rq_attr);
	presv->ri_alter_flags = 0;
	while (psatl) {
		long temp = 0;
		char *end = NULL;
		int index;

		/* identify the attribute by name */
		index = find_attr(resv_attr_def, psatl->al_name, RESV_ATR_LAST);
		if (index < 0) {
			/* didn`t recognize the name */
			reply_badattr(PBSE_NOATTR, 1, psatl, preq);
			return;
		}
		pdef = &resv_attr_def[index];

		/* Does attribute's definition flags indicate that
		 * we have sufficient permission to write the attribute?
		 */

		resc_access_perm = resc_access_perm_save; /* reset */
		if (psatl->al_flags & ATR_VFLAG_HOOK) {
			resc_access_perm = ATR_DFLAG_USWR | \
					    ATR_DFLAG_OPWR | \
					    ATR_DFLAG_MGWR | \
				            ATR_DFLAG_SvWR | \
					    ATR_DFLAG_Creat;
		}
		if ((pdef->at_flags & resc_access_perm) == 0) {
			reply_badattr(PBSE_ATTRRO, 1, psatl, preq);
			return;
		}

		switch (index) {
			case RESV_ATR_start:
				if ((presv->ri_wattr[RESV_ATR_state].at_val.at_long != RESV_RUNNING) ||
					!(presv->ri_qp->qu_numjobs)) {
					temp = strtol(psatl->al_value, &end, 10);
					if ((temp > time(NULL)) &&
						(temp != presv->ri_wattr[RESV_ATR_start].at_val.at_long)) {
						if (!is_standing || (temp < next_occr_start)) {
							send_to_scheduler = RESV_START_TIME_MODIFIED;
							presv->ri_alter_stime = presv->ri_wattr[RESV_ATR_start].at_val.at_long;
							presv->ri_alter_flags |= RESV_START_TIME_MODIFIED;
						} else {
							snprintf(log_buffer, sizeof(log_buffer), "%s", msg_stdg_resv_occr_conflict);
							log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO,
								preq->rq_ind.rq_modify.rq_objname, log_buffer);
							req_reject(PBSE_STDG_RESV_OCCR_CONFLICT, 0, preq);
							return;
						}
					} else {
						req_reject(PBSE_BADTSPEC, 0, preq);
						return;
					}
				} else {
					if (presv->ri_qp->qu_numjobs)
						req_reject(PBSE_RESV_NOT_EMPTY, 0, preq);
					else
						req_reject(PBSE_BADTSPEC, 0, preq);
					return;
				}
				break;
			case RESV_ATR_end:
				temp = strtol(psatl->al_value, &end, 10);
				if (temp == presv->ri_wattr[RESV_ATR_end].at_val.at_long) {
					req_reject(PBSE_BADTSPEC, 0, preq);
					return;
				}
				if (!is_standing || temp < next_occr_start) {
					send_to_scheduler = RESV_END_TIME_MODIFIED;
					presv->ri_alter_etime = presv->ri_wattr[RESV_ATR_end].at_val.at_long;
					presv->ri_alter_flags |= RESV_END_TIME_MODIFIED;
				} else {
					snprintf(log_buffer, sizeof(log_buffer), "%s", msg_stdg_resv_occr_conflict);
					log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO,
						preq->rq_ind.rq_modify.rq_objname, log_buffer);
					req_reject(PBSE_STDG_RESV_OCCR_CONFLICT, 0, preq);
					return;
				}
				break;
			default:
				break;
		}

		/* decode attribute */
		rc = pdef->at_decode(&presv->ri_wattr[index],
			psatl->al_name, psatl->al_resc, psatl->al_value);

		if (rc != 0) {
			reply_badattr(rc, 1, psatl, preq);
			return;
		}

		psatl = (svrattrl *)GET_NEXT(psatl->al_link);
	}
	resc_access_perm = resc_access_perm_save; /* restore perm */

	if (send_to_scheduler) {
		presv->ri_alter_state = presv->ri_wattr[RESV_ATR_state].at_val.at_long;
		resv_setResvState(presv, RESV_BEING_ALTERED, presv->ri_qs.ri_substate);
		/*"start", "end","duration", and "wall"; derive and check */
		if (start_end_dur_wall(presv, RESC_RESV_OBJECT)) {
			req_reject(PBSE_BADTSPEC, 0, preq);
			resv_revert_alter_times(presv);
			return;
		}
		presv->ri_wattr[RESV_ATR_resource].at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODIFY | ATR_VFLAG_MODCACHE;
	}
	bad = 0;
	psatl = (svrattrl *)GET_NEXT(preq->rq_ind.rq_modify.rq_attr);
	if (psatl)
		rc = modify_resv_attr(presv, psatl, preq->rq_perm, &bad);

	if (send_to_scheduler)
		set_scheduler_flag(SCH_SCHEDULE_RESV_RECONFIRM, dflt_scheduler);

	(void)sprintf(log_buffer, "Attempting to modify reservation");
	if (presv->ri_alter_flags & RESV_START_TIME_MODIFIED) {
		strftime(buf, sizeof(buf), fmt, localtime((time_t *) &presv->ri_wattr[RESV_ATR_start].at_val.at_long));
		log_len = strlen(log_buffer);
		snprintf(log_buffer + log_len, sizeof(log_buffer) - log_len," start=%s", buf);
	}
	if (presv->ri_alter_flags & RESV_END_TIME_MODIFIED) {
		strftime(buf, sizeof(buf), fmt, localtime((time_t *) &presv->ri_wattr[RESV_ATR_end].at_val.at_long));
		log_len = strlen(log_buffer);
		snprintf(log_buffer + log_len, sizeof(log_buffer) - log_len," end=%s", buf);
	}
	log_event(PBSEVENT_RESV, PBS_EVENTCLASS_RESV, LOG_INFO, preq->rq_ind.rq_modify.rq_objname, log_buffer);

	if ((presv->ri_wattr[RESV_ATR_interactive].at_flags &
		ATR_VFLAG_SET) == 0) {
		char buf1[PBS_MAXUSER + PBS_MAXHOSTNAME + 32] = {0};
		/*Not "interactive" so don't wait on scheduler, reply now*/

		sprintf(buf, "%s ALTER REQUESTED",  presv->ri_qs.ri_resvID);
		sprintf(buf1, "requestor=%s@%s", preq->rq_user, preq->rq_host);

		if ((rc = reply_text(preq, PBSE_NONE, buf))) {
			/* reply failed,  close connection; DON'T purge resv */
			close_client(sock);
			return;
		}
	} else {
		/*Don't reply back until scheduler decides*/
		long dt;
		presv->ri_brp = preq;
		dt = presv->ri_wattr[RESV_ATR_interactive].at_val.at_long;
		/*reply with id and state no decision in +dt secs*/
		(void)gen_future_reply(presv, dt);
		(void)snprintf(buf, sizeof(buf), "requestor=%s@%s Interactive=%ld",
			preq->rq_user, preq->rq_host, dt);
	}
}
Example #4
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;
}