/* * release_job - releases the hold on job j * @param j - the job to modify * @return 0 if successful, a PBS error on failure */ int release_job( struct batch_request *preq, /* I */ void *j) /* I/O */ { long old_hold; int rc = 0; int newstate; int newsub; char *pset; job *pjob = (job *)j; char log_buf[LOCAL_LOG_BUF_SIZE]; pbs_attribute temphold; /* cannot do anything until we decode the holds to be set */ if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset, &temphold)) != 0) { return(rc); } /* if other than HOLD_u is being released, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { return(rc); } /* unset the hold */ old_hold = pjob->ji_wattr[JOB_ATR_hold].at_val.at_long; if ((rc = job_attr_def[JOB_ATR_hold].at_set(&pjob->ji_wattr[JOB_ATR_hold], &temphold, DECR))) { return(rc); } /* everything went well, if holds changed, update the job state */ if (old_hold != pjob->ji_wattr[JOB_ATR_hold].at_val.at_long) { pjob->ji_modified = 1; /* indicates attributes changed */ svr_evaljobstate(pjob, &newstate, &newsub, 0); svr_setjobstate(pjob, newstate, newsub, FALSE); /* saves job */ } sprintf(log_buf, msg_jobholdrel, pset, preq->rq_user, preq->rq_host); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buf); return(rc); } /* END release_job() */
int modify_job_attr( job *pjob, /* I (modified) */ svrattrl *plist, /* I */ int perm, int *bad) /* O */ { int allow_unkn = -1; long i; pbs_attribute newattr[JOB_ATR_LAST]; pbs_attribute *pattr; int rc; char log_buf[LOCAL_LOG_BUF_SIZE]; pbs_queue *pque; if ((pque = get_jobs_queue(&pjob)) != NULL) { if (pque->qu_qs.qu_type != QTYPE_Execution) allow_unkn = JOB_ATR_UNKN; unlock_queue(pque, __func__, NULL, LOGLEVEL); } else if (pjob->ji_parent_job != NULL) { allow_unkn = JOB_ATR_UNKN; } else { log_err(PBSE_JOBNOTFOUND, __func__, "Job lost while acquiring queue 5"); return(PBSE_JOBNOTFOUND); } pattr = pjob->ji_wattr; /* call attr_atomic_set to decode and set a copy of the attributes */ rc = attr_atomic_set( plist, /* I */ pattr, /* I */ newattr, /* O */ job_attr_def, /* I */ JOB_ATR_LAST, allow_unkn, /* I */ perm, /* I */ bad); /* O */ /* if resource limits are being changed ... */ if ((rc == 0) && (newattr[JOB_ATR_resource].at_flags & ATR_VFLAG_SET)) { if ((perm & (ATR_DFLAG_MGWR | ATR_DFLAG_OPWR)) == 0) { /* If job is running, only manager/operator can raise limits */ if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) { long lim = TRUE; int comp_resc_lt; get_svr_attr_l(SRV_ATR_QCQLimits, &lim); comp_resc_lt = comp_resc2(&pjob->ji_wattr[JOB_ATR_resource], &newattr[JOB_ATR_resource], lim, NULL, LESS); if (comp_resc_lt != 0) { rc = PBSE_PERM; } } /* Also check against queue and system limits */ if (rc == 0) { if ((pque = get_jobs_queue(&pjob)) != NULL) { rc = chk_resc_limits( &newattr[JOB_ATR_resource], pque, NULL); unlock_queue(pque, __func__, NULL, LOGLEVEL); } else if (pjob == NULL) { log_err(PBSE_JOBNOTFOUND, __func__, "Job lost while acquiring queue 6"); return(PBSE_JOBNOTFOUND); } else rc = PBSE_QUENOTAVAILABLE; } } } /* END if ((rc == 0) && ...) */ /* special check on permissions for hold */ if ((rc == 0) && (newattr[JOB_ATR_hold].at_flags & ATR_VFLAG_MODIFY)) { i = newattr[JOB_ATR_hold].at_val.at_long ^ (pattr + JOB_ATR_hold)->at_val.at_long; rc = chk_hold_priv(i, perm); } if (rc == 0) { for (i = 0;i < JOB_ATR_LAST;i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { if (job_attr_def[i].at_action) { rc = job_attr_def[i].at_action( &newattr[i], pjob, ATR_ACTION_ALTER); if (rc) break; } } } /* END for (i) */ if ((rc == 0) && ((newattr[JOB_ATR_userlst].at_flags & ATR_VFLAG_MODIFY) || (newattr[JOB_ATR_grouplst].at_flags & ATR_VFLAG_MODIFY))) { /* need to reset execution uid and gid */ rc = set_jobexid(pjob, newattr, NULL); } if ((rc == 0) && (newattr[JOB_ATR_outpath].at_flags & ATR_VFLAG_MODIFY)) { /* need to recheck if JOB_ATR_outpath is a special case of host only */ if (newattr[JOB_ATR_outpath].at_val.at_str[strlen(newattr[JOB_ATR_outpath].at_val.at_str) - 1] == ':') { dynamic_string *ds = get_dynamic_string(-1, NULL); newattr[JOB_ATR_outpath].at_val.at_str = prefix_std_file(pjob, ds, (int)'o'); /* don't call free_dynamic_string() */ free(ds); } /* * if the output path was specified and ends with a '/' * then append the standard file name */ else if (newattr[JOB_ATR_outpath].at_val.at_str[strlen(newattr[JOB_ATR_outpath].at_val.at_str) - 1] == '/') { dynamic_string *ds = get_dynamic_string(-1, NULL); newattr[JOB_ATR_outpath].at_val.at_str[strlen(newattr[JOB_ATR_outpath].at_val.at_str) - 1] = '\0'; replace_attr_string(&newattr[JOB_ATR_outpath], (add_std_filename(pjob, newattr[JOB_ATR_outpath].at_val.at_str, (int)'o', ds))); /* don't call free_dynamic_string because() we still want to use the allocated string */ free(ds); } } if ((rc == 0) && (newattr[JOB_ATR_errpath].at_flags & ATR_VFLAG_MODIFY)) { /* need to recheck if JOB_ATR_errpath is a special case of host only */ if (newattr[JOB_ATR_errpath].at_val.at_str[strlen(newattr[JOB_ATR_errpath].at_val.at_str) - 1] == ':') { dynamic_string *ds = get_dynamic_string(-1, NULL); newattr[JOB_ATR_errpath].at_val.at_str = prefix_std_file(pjob, ds, (int)'e'); /* don't call free_dynamic_string() */ free(ds); } /* * if the error path was specified and ends with a '/' * then append the standard file name */ else if (newattr[JOB_ATR_errpath].at_val.at_str[strlen(newattr[JOB_ATR_errpath].at_val.at_str) - 1] == '/') { dynamic_string *ds = get_dynamic_string(-1, NULL); newattr[JOB_ATR_errpath].at_val.at_str[strlen(newattr[JOB_ATR_errpath].at_val.at_str) - 1] = '\0'; replace_attr_string(&newattr[JOB_ATR_errpath], (add_std_filename(pjob, newattr[JOB_ATR_errpath].at_val.at_str,(int)'e', ds))); /* don't call free_dynamic_string() */ free(ds); } } } /* END if (rc == 0) */ if (rc != 0) { for (i = 0;i < JOB_ATR_LAST;i++) job_attr_def[i].at_free(newattr + i); /* FAILURE */ return(rc); } /* END if (rc != 0) */ /* OK, now copy the new values into the job attribute array */ for (i = 0;i < JOB_ATR_LAST;i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { if (LOGLEVEL >= 7) { sprintf(log_buf, "attr %s modified", job_attr_def[i].at_name); log_event(PBSEVENT_JOB,PBS_EVENTCLASS_JOB,pjob->ji_qs.ji_jobid,log_buf); } job_attr_def[i].at_free(pattr + i); if ((newattr[i].at_type == ATR_TYPE_LIST) || (newattr[i].at_type == ATR_TYPE_RESC)) { list_move( &newattr[i].at_val.at_list, &(pattr + i)->at_val.at_list); } else { *(pattr + i) = newattr[i]; } (pattr + i)->at_flags = newattr[i].at_flags; } } /* END for (i) */ /* note, the newattr[] attributes are on the stack, they go away automatically */ pjob->ji_modified = 1; return(0); } /* END modify_job_attr() */
/** * @brief * modify_job_attr - modify the attributes of a job automatically * Used by req_modifyjob() to alter the job attributes and by * stat_update() [see req_stat.c] to update with latest from MOM * * @param[in,out] pjob - job structure * @param[in,out] plist - Pointer to list of attributes * @param[in] perm - Permissions of the caller requesting the operation * @param[out] bad - Pointer to the attribute index in case of a failed */ int modify_job_attr(job *pjob, svrattrl *plist, int perm, int *bad) { int changed_resc; int allow_unkn; long i; int modified = 0; attribute *newattr; attribute *pre_copy; attribute *attr_save; attribute *pattr; resource *prc; int rc; int newstate = -1; int newsubstate = -1; long newaccruetype = -1; if (pjob->ji_qhdr->qu_qs.qu_type == QTYPE_Execution) allow_unkn = -1; else allow_unkn = (int)JOB_ATR_UNKN; pattr = pjob->ji_wattr; /* call attr_atomic_set to decode and set a copy of the attributes. * We need 2 copies: 1 for copying to pattr and 1 for calling the action functions * We can't use the same copy for the action functions because copying to pattr * is a shallow copy and array pointers will be cleared during the copy. */ newattr = calloc(JOB_ATR_LAST, sizeof(attribute)); if (newattr == NULL) return PBSE_SYSTEM; rc = attr_atomic_set(plist, pattr, newattr, job_attr_def, JOB_ATR_LAST, allow_unkn, perm, bad); if (rc) { attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST); return rc; } pre_copy = calloc(JOB_ATR_LAST, sizeof(attribute)); if(pre_copy == NULL) { attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST); return PBSE_SYSTEM; } attr_atomic_copy(pre_copy, newattr, job_attr_def, JOB_ATR_LAST); attr_save = calloc(JOB_ATR_LAST, sizeof(attribute)); if (attr_save == NULL) { attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST); attr_atomic_kill(pre_copy, job_attr_def, JOB_ATR_LAST); return PBSE_SYSTEM; } attr_atomic_copy(attr_save, pattr, job_attr_def, JOB_ATR_LAST); /* If resource limits are being changed ... */ changed_resc = newattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET; if ((rc == 0) && (changed_resc != 0)) { /* first, remove ATR_VFLAG_DEFLT from any value which was set */ /* it can no longer be a "default" as it explicitly changed */ prc = (resource *)GET_NEXT(newattr[(int)JOB_ATR_resource].at_val.at_list); while (prc) { if ((prc->rs_value.at_flags & (ATR_VFLAG_MODIFY|ATR_VFLAG_DEFLT)) == (ATR_VFLAG_MODIFY|ATR_VFLAG_DEFLT)) prc->rs_value.at_flags &= ~ATR_VFLAG_DEFLT; if ((prc->rs_value.at_flags & (ATR_VFLAG_MODIFY|ATR_VFLAG_SET)) == (ATR_VFLAG_MODIFY|ATR_VFLAG_SET)) { /* if being changed at all, see if "select" */ if (prc->rs_defin == pseldef) { /* select is modified, recalc chunk sums */ rc = set_chunk_sum(&prc->rs_value, &newattr[(int)JOB_ATR_resource]); if (rc) break; } } prc = (resource *)GET_NEXT(prc->rs_link); } /* Manager/Operator can modify job just about any old way */ /* So, the following checks are made only if not the Op/Admin */ if ((perm & (ATR_DFLAG_MGWR | ATR_DFLAG_OPWR)) == 0) { if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) { /* regular user cannot raise the limits of a running job */ if ((comp_resc(&pjob->ji_wattr[(int)JOB_ATR_resource], &newattr[(int)JOB_ATR_resource]) == -1) || comp_resc_lt) rc = PBSE_PERM; } /* Also check against queue, system and entity limits */ if (rc == 0) { rc = chk_resc_limits(&newattr[(int)JOB_ATR_resource], pjob->ji_qhdr); } if (rc == 0) { rc = check_entity_resc_limit_max(pjob, pjob->ji_qhdr, &newattr[(int)JOB_ATR_resource]); if (rc == 0) { rc = check_entity_resc_limit_queued(pjob, pjob->ji_qhdr, &newattr[(int)JOB_ATR_resource]); if (rc == 0) { rc = check_entity_resc_limit_max(pjob, NULL, &newattr[(int)JOB_ATR_resource]); if (rc == 0) rc = check_entity_resc_limit_queued(pjob, NULL, &newattr[(int)JOB_ATR_resource]); } } } } } /* special check on permissions for hold */ if ((rc == 0) && (newattr[(int)JOB_ATR_hold].at_flags & ATR_VFLAG_MODIFY)) { svrattrl *hold_e = find_name_in_svrattrl(plist, ATTR_h); /* don't perform permission check if Hold_Types attribute */ /* was set in a hook script (special privilege) */ if ((hold_e == NULL) || ((hold_e->al_flags & ATR_VFLAG_HOOK) == 0)) { i = newattr[(int)JOB_ATR_hold].at_val.at_long ^ (pattr+(int)JOB_ATR_hold)->at_val.at_long; rc = chk_hold_priv(i, perm); } } if ((rc == 0) && ((newattr[(int)JOB_ATR_userlst].at_flags & ATR_VFLAG_MODIFY) || (newattr[(int)JOB_ATR_grouplst].at_flags & ATR_VFLAG_MODIFY))) { /* Need to reset execution uid and gid */ rc = set_objexid((void *)pjob, JOB_OBJECT, newattr); } if (rc) { attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST); attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST); attr_atomic_kill(pre_copy, job_attr_def, JOB_ATR_LAST); return (rc); } /* OK, if resources changed, reset entity sums */ if (changed_resc) { account_entity_limit_usages(pjob, NULL, &newattr[(int)JOB_ATR_resource], INCR, ETLIM_ACC_ALL_RES); account_entity_limit_usages(pjob, pjob->ji_qhdr, &newattr[(int)JOB_ATR_resource], INCR, ETLIM_ACC_ALL_RES); } /* Now copy the new values into the job attribute array for the purposes of running the action functions */ for (i = 0; i < JOB_ATR_LAST; i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { /* * The function update_eligible_time() expects it is the only one setting accrue_type. * If we set it here, it will get confused. There is no action function for accrue_type, * so pre-setting it for the action function calls isn't required. */ if (i == JOB_ATR_accrue_type) continue; job_attr_def[i].at_free(&pattr[i]); if ((pre_copy[i].at_type == ATR_TYPE_LIST) || (pre_copy[i].at_type == ATR_TYPE_RESC)) { list_move(&pre_copy[i].at_val.at_list, &pattr[i].at_val.at_list); } else { pattr[i] = pre_copy[i]; } /* ATR_VFLAG_MODCACHE will be included if set */ pattr[i].at_flags = pre_copy[i].at_flags; } } for (i = 0; i < JOB_ATR_LAST; i++) { /* Check newattr instead of pattr for modify. It is possible that * the attribute already has the modify flag before we added the new attributes to it. * We only want to call the action functions for attributes which are being modified by this function. */ if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { if ((job_attr_def[i].at_flags & ATR_DFLAG_NOSAVM) == 0) modified = 1; /* full save to disk for job */ if (job_attr_def[i].at_action) { rc = job_attr_def[i].at_action(&newattr[i], pjob, ATR_ACTION_ALTER); if (rc) { *bad = i; break; } } } } if (rc) { attr_atomic_copy(pjob->ji_wattr, attr_save, job_attr_def, JOB_ATR_LAST); free(pre_copy); attr_atomic_kill(newattr, job_attr_def, JOB_ATR_LAST); attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST); return (rc); } /* The action functions may have modified the attributes, need to set them to newattr2 */ for (i = 0; i < JOB_ATR_LAST; i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { job_attr_def[i].at_free(&pattr[i]); switch (i) { case JOB_ATR_state: newstate = state_char2int(newattr[i].at_val.at_char); break; case JOB_ATR_substate: newsubstate = newattr[i].at_val.at_long; break; case JOB_ATR_accrue_type: newaccruetype = newattr[i].at_val.at_long; break; default: if ((newattr[i].at_type == ATR_TYPE_LIST) || (newattr[i].at_type == ATR_TYPE_RESC)) { list_move(&newattr[i].at_val.at_list, &pattr[i].at_val.at_list); } else { pattr[i] = newattr[i]; } } /* ATR_VFLAG_MODCACHE will be included if set */ pattr[i].at_flags = newattr[i].at_flags; } } if (newstate != -1 && newsubstate != -1) { svr_setjobstate(pjob, newstate, newsubstate); } if (newaccruetype != -1) update_eligible_time(newaccruetype, pjob); if (modified) pjob->ji_modified = 1; /* an attr was modified, do full save */ free(newattr); free(pre_copy); attr_atomic_kill(attr_save, job_attr_def, JOB_ATR_LAST); return (0); }
/* * release_job - releases the hold on job j * @param j - the job to modify * @param pa - a pointer to an array whose mutex we hold - always this job's array * @return 0 if successful, a PBS error on failure */ int release_job( struct batch_request *preq, /* I */ void *j, /* I/O */ job_array *pa) /* I */ { long old_hold; int rc = PBSE_NONE; int newstate; int newsub; char *pset; job *pjob = (job *)j; char log_buf[LOCAL_LOG_BUF_SIZE]; pbs_attribute temphold; // this function is meaningless for jobs in exiting or completed if (pjob->ji_qs.ji_state > JOB_STATE_RUNNING) return(PBSE_NONE); /* cannot do anything until we decode the holds to be set */ if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, (const char **)&pset, &temphold)) != 0) { return(rc); } /* if other than HOLD_u is being released, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { return(rc); } /* unset the hold */ old_hold = pjob->ji_wattr[JOB_ATR_hold].at_val.at_long; if ((rc = job_attr_def[JOB_ATR_hold].at_set(&pjob->ji_wattr[JOB_ATR_hold], &temphold, DECR))) { return(rc); } if (pjob->ji_arraystructid[0] != '\0') { // Make sure our slot limit counts are correct check_array_slot_limits(pjob, pa); } /* everything went well, if holds changed, update the job state */ if (old_hold != pjob->ji_wattr[JOB_ATR_hold].at_val.at_long) { pjob->ji_modified = 1; /* indicates attributes changed */ svr_evaljobstate(*pjob, newstate, newsub, 0); svr_setjobstate(pjob, newstate, newsub, FALSE); /* saves job */ } sprintf(log_buf, msg_jobholdrel, pset, preq->rq_user, preq->rq_host); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buf); return(rc); } /* END release_job() */
int req_holdjob( batch_request *vp) /* I */ { long *hold_val; int newstate; int newsub; long old_hold; job *pjob; char *pset; int rc; pbs_attribute temphold; pbs_attribute *pattr; batch_request *preq = (struct batch_request *)vp; char log_buf[LOCAL_LOG_BUF_SIZE]; batch_request *dup_req = NULL; pjob = chk_job_request(preq->rq_ind.rq_hold.rq_orig.rq_objname, preq); if (pjob == NULL) { return(PBSE_NONE); } mutex_mgr job_mutex(pjob->ji_mutex, true); /* cannot do anything until we decode the holds to be set */ if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, (const char **)&pset, &temphold)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return(PBSE_NONE); } /* if other than HOLD_u is being set, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return(PBSE_NONE); } hold_val = &pjob->ji_wattr[JOB_ATR_hold].at_val.at_long; old_hold = *hold_val; *hold_val |= temphold.at_val.at_long; pjob->ji_wattr[JOB_ATR_hold].at_flags |= ATR_VFLAG_SET; sprintf(log_buf, msg_jobholdset, pset, preq->rq_user, preq->rq_host); pattr = &pjob->ji_wattr[JOB_ATR_checkpoint]; if ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) && ((pattr->at_flags & ATR_VFLAG_SET) && ((csv_find_string(pattr->at_val.at_str, "s") != NULL) || (csv_find_string(pattr->at_val.at_str, "c") != NULL) || (csv_find_string(pattr->at_val.at_str, "enabled") != NULL)))) { /* have MOM attempt checkpointing */ /* ** The jobid in the request always have the server suffix attached ** which is dropped when the server attribute ** 'display_job_server_suffix' is FALSE and so will in the MOM's. ** Therefore, it must be passed as the server to the MOM so she can ** find it to hold. */ if (strncmp(pjob->ji_qs.ji_jobid, preq->rq_ind.rq_hold.rq_orig.rq_objname, PBS_MAXSVRJOBID)) snprintf(preq->rq_ind.rq_hold.rq_orig.rq_objname, sizeof(preq->rq_ind.rq_hold.rq_orig.rq_objname), "%s", pjob->ji_qs.ji_jobid); if ((dup_req = duplicate_request(preq)) == NULL) { req_reject(rc, 0, preq, NULL, "memory allocation failure"); } /* The dup_req is freed in relay_to_mom (failure) * or in issue_Drequest (success) */ else if ((rc = relay_to_mom(&pjob, dup_req, NULL)) != PBSE_NONE) { free_br(dup_req); *hold_val = old_hold; /* reset to the old value */ req_reject(rc, 0, preq, NULL, "relay to mom failed"); if (pjob == NULL) job_mutex.set_unlock_on_exit(false); } else { if (pjob != NULL) { pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHECKPOINT_FILE; job_save(pjob, SAVEJOB_QUICK, 0); /* fill in log_buf again, since relay_to_mom changed it */ sprintf(log_buf, msg_jobholdset, pset, preq->rq_user, preq->rq_host); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buf); unlock_ji_mutex(pjob, __func__, "3", LOGLEVEL); pjob = NULL; reply_ack(preq); } else job_mutex.set_unlock_on_exit(false); process_hold_reply(dup_req); } } #ifdef ENABLE_BLCR else if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) { /* * This system is configured with BLCR checkpointing to be used, * but this Running job does not have checkpointing enabled, * so we reject the request */ log_event(PBSEVENT_JOB,PBS_EVENTCLASS_JOB,pjob->ji_qs.ji_jobid,log_buf); req_reject(PBSE_IVALREQ, 0, preq, NULL, "job not held since checkpointing is expected but not enabled for job"); } #endif else { /* everything went well, may need to update the job state */ log_event(PBSEVENT_JOB,PBS_EVENTCLASS_JOB,pjob->ji_qs.ji_jobid,log_buf); if (old_hold != *hold_val) { /* indicate attributes changed */ pjob->ji_modified = 1; svr_evaljobstate(*pjob, newstate, newsub, 0); svr_setjobstate(pjob, newstate, newsub, FALSE); } reply_ack(preq); } return(PBSE_NONE); } /* END req_holdjob() */
void req_holdarray(struct batch_request *preq) { int i; char *pset; char *range_str; int rc; attribute temphold; char owner[PBS_MAXUSER + 1]; job_array *pa; /* batch_request *preq_tmp; */ pa = get_array(preq->rq_ind.rq_hold.rq_orig.rq_objname); if (pa == NULL) { /* this shouldn't happen since we verify that this is a valid array just prior to calling this function */ req_reject(PBSE_UNKARRAYID, 0, preq, NULL, "unable to find array"); } get_jobowner(pa->ai_qs.owner, owner); if (svr_authorize_req(preq, owner, pa->ai_qs.submit_host) == -1) { sprintf(log_buffer, msg_permlog, preq->rq_type, "Array", preq->rq_ind.rq_delete.rq_objname, preq->rq_user, preq->rq_host); log_event( PBSEVENT_SECURITY, PBS_EVENTCLASS_JOB, preq->rq_ind.rq_delete.rq_objname, log_buffer); req_reject(PBSE_PERM, 0, preq, NULL, "operation not permitted"); return; } if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset, &temphold)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } /* if other than HOLD_u is being set, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } /* get the range of jobs to iterate over */ range_str = preq->rq_extend; if ((range_str != NULL) && (strstr(range_str,ARRAY_RANGE) != NULL)) { if ((rc = hold_array_range(pa,range_str,&temphold)) != 0) { req_reject(rc,0,preq,NULL, "Error in specified array range"); } } else { /* do the entire array */ for (i = 0;i < pa->ai_qs.array_size;i++) { if (pa->jobs[i] == NULL) continue; hold_job(&temphold,pa->jobs[i]); } } reply_ack(preq); }
int req_holdarray( void *vp) /* I */ { int i; struct batch_request *preq = (struct batch_request *)vp; char *pset; char *range_str; int rc; pbs_attribute temphold; char owner[PBS_MAXUSER + 1]; job_array *pa; job *pjob; char log_buf[LOCAL_LOG_BUF_SIZE]; pa = get_array(preq->rq_ind.rq_hold.rq_orig.rq_objname); if (pa == NULL) { /* this shouldn't happen since we verify that this is a valid array just prior to calling this function */ req_reject(PBSE_UNKARRAYID, 0, preq, NULL, "unable to find array"); return(PBSE_NONE); } get_jobowner(pa->ai_qs.owner, owner); if (svr_authorize_req(preq, owner, pa->ai_qs.submit_host) == -1) { sprintf(log_buf, msg_permlog, preq->rq_type, "Array", preq->rq_ind.rq_delete.rq_objname, preq->rq_user, preq->rq_host); log_event(PBSEVENT_SECURITY, PBS_EVENTCLASS_JOB, preq->rq_ind.rq_delete.rq_objname, log_buf); if (LOGLEVEL >= 7) { sprintf(log_buf, "%s: unlocking ai_mutex", __func__); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pa->ai_qs.parent_id, log_buf); } pthread_mutex_unlock(pa->ai_mutex); req_reject(PBSE_PERM, 0, preq, NULL, "operation not permitted"); return(PBSE_NONE); } if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset, &temphold)) != 0) { if (LOGLEVEL >= 7) { sprintf(log_buf, "%s: unlocking ai_mutex", __func__); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pa->ai_qs.parent_id, log_buf); } pthread_mutex_unlock(pa->ai_mutex); req_reject(rc, 0, preq, NULL, NULL); return(PBSE_NONE); } /* if other than HOLD_u is being set, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { if (LOGLEVEL >= 7) { sprintf(log_buf, "%s: unlocking ai_mutex", __func__); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pa->ai_qs.parent_id, log_buf); } pthread_mutex_unlock(pa->ai_mutex); req_reject(rc, 0, preq, NULL, NULL); return(PBSE_NONE); } /* get the range of jobs to iterate over */ range_str = preq->rq_extend; if ((range_str != NULL) && (strstr(range_str,ARRAY_RANGE) != NULL)) { if ((rc = hold_array_range(pa,range_str,&temphold)) != 0) { pthread_mutex_unlock(pa->ai_mutex); req_reject(rc,0,preq,NULL, "Error in specified array range"); return(PBSE_NONE); } } else { /* do the entire array */ for (i = 0;i < pa->ai_qs.array_size;i++) { if (pa->job_ids[i] == NULL) continue; if ((pjob = svr_find_job(pa->job_ids[i], FALSE)) == NULL) { free(pa->job_ids[i]); pa->job_ids[i] = NULL; } else { hold_job(&temphold,pjob); if (LOGLEVEL >= 7) { sprintf(log_buf, "%s: unlocking ai_mutex", __func__); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pa->ai_qs.parent_id, log_buf); } unlock_ji_mutex(pjob, __func__, "1", LOGLEVEL); } } } if (LOGLEVEL >= 7) { sprintf(log_buf, "%s: unlocking ai_mutex", __func__); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pa->ai_qs.parent_id, log_buf); } pthread_mutex_unlock(pa->ai_mutex); reply_ack(preq); return(PBSE_NONE); } /* END req_holdarray() */
void req_releasejob(struct batch_request *preq) { int jt; /* job type */ int newstate; int newsub; long old_hold; job *pjob; char *pset; int rc; pjob = chk_job_request(preq->rq_ind.rq_release.rq_objname, preq, &jt); if (pjob == (job *)0) return; if ((jt != IS_ARRAY_NO) && (jt != IS_ARRAY_ArrayJob)) { req_reject(PBSE_IVALREQ, 0, preq); return; } /* cannot do anything until we decode the holds to be set */ if ((rc=get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset)) != 0) { req_reject(rc, 0, preq); return; } /* if other than HOLD_u is being released, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq); return; } /* all ok so far, unset the hold */ old_hold = pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long; rc = job_attr_def[(int)JOB_ATR_hold]. at_set(&pjob->ji_wattr[(int)JOB_ATR_hold], &temphold, DECR); if (rc) { req_reject(rc, 0, preq); return; } /* every thing went well, if holds changed, update the job state */ #ifndef NAS /* localmod 105 Always reset etime on release */ if (old_hold != pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long) { #endif /* localmod 105 */ #ifdef NAS /* localmod 105 */ { attribute *etime = &pjob->ji_wattr[(int)JOB_ATR_etime]; etime->at_val.at_long = time_now; etime->at_flags |= ATR_VFLAG_SET|ATR_VFLAG_MODCACHE; #endif /* localmod 105 */ pjob->ji_modified = 1; /* indicates attributes changed */ svr_evaljobstate(pjob, &newstate, &newsub, 0); (void)svr_setjobstate(pjob, newstate, newsub); /* saves job */ } if (pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long == 0) job_attr_def[(int)JOB_ATR_Comment].at_free(&pjob->ji_wattr[(int)JOB_ATR_Comment]); (void)sprintf(log_buffer, msg_jobholdrel, pset, preq->rq_user, preq->rq_host); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, LOG_INFO, pjob->ji_qs.ji_jobid, log_buffer); reply_ack(preq); } /** * @brief * get_hold - search a list of attributes (svrattrl) for the hold-types * attribute. This is used by the Hold Job and Release Job request, * therefore it is an error if the hold-types attribute is not present, * or there is more than one. * * Decode the hold attribute into temphold. * * @param[in] phead - pbs list head. * @param[out] phead - RETURN - ptr to hold value * * @return error code */ static int get_hold(pbs_list_head *phead, char **pset) { int have_one = 0; struct svrattrl *holdattr = (struct svrattrl*)0; struct svrattrl *pal; pal = (struct svrattrl *)GET_NEXT((*phead)); while (pal) { if (!strcasecmp(pal->al_name, job_attr_def[(int)JOB_ATR_hold].at_name)) { holdattr = pal; *pset = pal->al_value; have_one++; } else { return (PBSE_IVALREQ); } pal = (struct svrattrl *)GET_NEXT(pal->al_link); } if (have_one != 1) return (PBSE_IVALREQ); /* decode into temporary attribute structure */ clear_attr(&temphold, &job_attr_def[(int)JOB_ATR_hold]); return (job_attr_def[(int)JOB_ATR_hold].at_decode( &temphold, holdattr->al_name, (char *)0, holdattr->al_value)); }
void req_holdjob(struct batch_request *preq) { long *hold_val; int jt; /* job type */ int newstate; int newsub; long old_hold; job *pjob; char *pset; int rc; char date[32]; time_t now; pjob = chk_job_request(preq->rq_ind.rq_hold.rq_orig.rq_objname, preq, &jt); if (pjob == (job *)0) return; if ((jt != IS_ARRAY_NO) && (jt != IS_ARRAY_ArrayJob)) { req_reject(PBSE_IVALREQ, 0, preq); return; } if ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) && (pjob->ji_qs.ji_substate == JOB_SUBSTATE_PROVISION)) { req_reject(PBSE_BADSTATE, 0, preq); return; } /* cannot do anything until we decode the holds to be set */ if ((rc=get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset)) != 0) { req_reject(rc, 0, preq); return; } /* if other than HOLD_u is being set, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq); return; } /* HOLD_bad_password can only be done by root or admin */ #ifdef WIN32 if ( (temphold.at_val.at_long & HOLD_bad_password) && \ !isAdminPrivilege(preq->rq_user) ) #else if ( (temphold.at_val.at_long & HOLD_bad_password) && \ strcasecmp(preq->rq_user, PBS_DEFAULT_ADMIN) != 0 ) #endif { req_reject(PBSE_PERM, 0, preq); return; } hold_val = &pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long; old_hold = *hold_val; *hold_val |= temphold.at_val.at_long; pjob->ji_wattr[(int)JOB_ATR_hold].at_flags |= ATR_VFLAG_SET | ATR_VFLAG_MODCACHE; /* Note the hold time in the job comment. */ now = time(NULL); (void)strncpy(date, (const char *)ctime(&now), 24); date[24] = '\0'; (void)sprintf(log_buffer, "Job held by %s on %s", preq->rq_user, date); job_attr_def[(int)JOB_ATR_Comment].at_decode(&pjob->ji_wattr[(int)JOB_ATR_Comment], (char *)0, (char *)0, log_buffer); (void)sprintf(log_buffer, msg_jobholdset, pset, preq->rq_user, preq->rq_host); if ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) && (pjob->ji_qs.ji_substate != JOB_SUBSTATE_PRERUN) && (pjob->ji_wattr[(int)JOB_ATR_chkpnt].at_val.at_str) && (*pjob->ji_wattr[(int)JOB_ATR_chkpnt].at_val.at_str != 'n')) { /* have MOM attempt checkpointing */ if ((rc = relay_to_mom(pjob, preq, post_hold)) != 0) { *hold_val = old_hold; /* reset to the old value */ req_reject(rc, 0, preq); } else { pjob->ji_qs.ji_substate = JOB_SUBSTATE_RERUN; pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHKPT; (void)job_save(pjob, SAVEJOB_QUICK); log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, LOG_INFO, pjob->ji_qs.ji_jobid, log_buffer); } } else { /* every thing went well, may need to update the job state */ log_event(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, LOG_INFO, pjob->ji_qs.ji_jobid, log_buffer); if (old_hold != *hold_val) { /* indicate attributes changed */ pjob->ji_modified = 1; svr_evaljobstate(pjob, &newstate, &newsub, 0); (void)svr_setjobstate(pjob, newstate, newsub); } reply_ack(preq); } }
void req_releasejob( struct batch_request *preq) /* ptr to the decoded request */ { int newstate; int newsub; long old_hold; job *pjob; char *pset; int rc; attribute temphold; pjob = chk_job_request(preq->rq_ind.rq_release.rq_objname, preq); if (pjob == NULL) { return; } /* cannot do anything until we decode the holds to be set */ if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset, &temphold)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } /* if other than HOLD_u is being released, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } /* all ok so far, unset the hold */ old_hold = pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long; if ((rc = job_attr_def[(int)JOB_ATR_hold].at_set(&pjob->ji_wattr[(int)JOB_ATR_hold], &temphold, DECR))) { req_reject(rc, 0, preq, NULL, NULL); return; } /* everything went well, if holds changed, update the job state */ if (old_hold != pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long) { pjob->ji_modified = 1; /* indicates attributes changed */ svr_evaljobstate(pjob, &newstate, &newsub, 0); svr_setjobstate(pjob, newstate, newsub); /* saves job */ } sprintf(log_buffer, msg_jobholdrel, pset, preq->rq_user, preq->rq_host); LOG_EVENT(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buffer); reply_ack(preq); return; } /* END req_releasejob() */
void req_holdjob( struct batch_request *preq) { long *hold_val; int newstate; int newsub; long old_hold; job *pjob; char *pset; int rc; attribute temphold; attribute *pattr; pjob = chk_job_request(preq->rq_ind.rq_hold.rq_orig.rq_objname, preq); if (pjob == NULL) { return; } if (is_cloud_job(pjob)) { req_reject(PBSE_CLOUD_REQUEST,0,preq,NULL,NULL); } /* cannot do anything until we decode the holds to be set */ if ((rc = get_hold(&preq->rq_ind.rq_hold.rq_orig.rq_attr, &pset, &temphold)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } /* if other than HOLD_u is being set, must have privil */ if ((rc = chk_hold_priv(temphold.at_val.at_long, preq->rq_perm)) != 0) { req_reject(rc, 0, preq, NULL, NULL); return; } hold_val = &pjob->ji_wattr[(int)JOB_ATR_hold].at_val.at_long; old_hold = *hold_val; *hold_val |= temphold.at_val.at_long; pjob->ji_wattr[(int)JOB_ATR_hold].at_flags |= ATR_VFLAG_SET; sprintf(log_buffer, msg_jobholdset, pset, preq->rq_user, preq->rq_host); pattr = &pjob->ji_wattr[(int)JOB_ATR_checkpoint]; if ((pjob->ji_qs.ji_state == JOB_STATE_RUNNING) && ((pattr->at_flags & ATR_VFLAG_SET) && ((csv_find_string(pattr->at_val.at_str, "s") != NULL) || (csv_find_string(pattr->at_val.at_str, "c") != NULL) || (csv_find_string(pattr->at_val.at_str, "enabled") != NULL)))) { /* have MOM attempt checkpointing */ if ((rc = relay_to_mom(pjob->ji_qs.ji_un.ji_exect.ji_momaddr, preq, process_hold_reply)) != 0) { *hold_val = old_hold; /* reset to the old value */ req_reject(rc, 0, preq, NULL, NULL); } else { pjob->ji_qs.ji_svrflags |= JOB_SVFLG_HASRUN | JOB_SVFLG_CHECKPOINT_FILE; job_save(pjob, SAVEJOB_QUICK); /* fill in log_buffer again, since relay_to_mom changed it */ sprintf(log_buffer, msg_jobholdset, pset, preq->rq_user, preq->rq_host); LOG_EVENT(PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buffer); } } #ifdef ENABLE_BLCR else if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) { /* * This system is configured with BLCR checkpointing to be used, * but this Running job does not have checkpointing enabled, * so we reject the request */ LOG_EVENT( PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buffer); req_reject(PBSE_IVALREQ, 0, preq, NULL, "job not held since checkpointing is expected but not enabled for job"); } #endif else { /* everything went well, may need to update the job state */ LOG_EVENT( PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buffer); if (old_hold != *hold_val) { /* indicate attributes changed */ pjob->ji_modified = 1; svr_evaljobstate(pjob, &newstate, &newsub, 0); svr_setjobstate(pjob, newstate, newsub); } reply_ack(preq); } } /* END req_holdjob() */
int modify_job_attr( job *pjob, /* I (modified) */ svrattrl *plist, /* I */ int perm, int *bad) /* O */ { int allow_unkn; long i; attribute newattr[(int)JOB_ATR_LAST]; attribute *pattr; int rc; if (pjob->ji_qhdr->qu_qs.qu_type == QTYPE_Execution) allow_unkn = -1; else allow_unkn = (int)JOB_ATR_UNKN; pattr = pjob->ji_wattr; /* call attr_atomic_set to decode and set a copy of the attributes */ rc = attr_atomic_set( plist, /* I */ pattr, /* I */ newattr, /* O */ job_attr_def, /* I */ JOB_ATR_LAST, allow_unkn, /* I */ perm, /* I */ bad); /* O */ /* if resource limits are being changed ... */ if ((rc == 0) && (newattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET)) { if ((perm & (ATR_DFLAG_MGWR | ATR_DFLAG_OPWR)) == 0) { /* If job is running, only manager/operator can raise limits */ if (pjob->ji_qs.ji_state == JOB_STATE_RUNNING) { if ((comp_resc2( &pjob->ji_wattr[(int)JOB_ATR_resource], &newattr[(int)JOB_ATR_resource], server.sv_attr[(int)SRV_ATR_QCQLimits].at_val.at_long, NULL) == -1) || (comp_resc_lt != 0)) { rc = PBSE_PERM; } } /* Also check against queue and system limits */ if (rc == 0) { rc = chk_resc_limits( &newattr[(int)JOB_ATR_resource], pjob->ji_qhdr, NULL); } } } /* END if ((rc == 0) && ...) */ /* special check on permissions for hold */ if ((rc == 0) && (newattr[(int)JOB_ATR_hold].at_flags & ATR_VFLAG_MODIFY)) { i = newattr[(int)JOB_ATR_hold].at_val.at_long ^ (pattr + (int)JOB_ATR_hold)->at_val.at_long; rc = chk_hold_priv(i, perm); } if (rc == 0) { for (i = 0;i < JOB_ATR_LAST;i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { if (job_attr_def[i].at_action) { rc = job_attr_def[i].at_action( &newattr[i], pjob, ATR_ACTION_ALTER); if (rc) break; } } } /* END for (i) */ if ((rc == 0) && ((newattr[(int)JOB_ATR_userlst].at_flags & ATR_VFLAG_MODIFY) || (newattr[(int)JOB_ATR_grouplst].at_flags & ATR_VFLAG_MODIFY))) { /* need to reset execution uid and gid */ rc = set_jobexid(pjob, newattr, NULL); } if ((rc == 0) && (newattr[(int)JOB_ATR_outpath].at_flags & ATR_VFLAG_MODIFY)) { /* need to recheck if JOB_ATR_outpath is a special case of host only */ if (newattr[(int)JOB_ATR_outpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_outpath].at_val.at_str) - 1] == ':') { newattr[(int)JOB_ATR_outpath].at_val.at_str = prefix_std_file(pjob, (int)'o'); } /* * if the output path was specified and ends with a '/' * then append the standard file name */ else if (newattr[(int)JOB_ATR_outpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_outpath].at_val.at_str) - 1] == '/') { newattr[(int)JOB_ATR_outpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_outpath].at_val.at_str) - 1] = '\0'; replace_attr_string(&newattr[(int)JOB_ATR_outpath], (add_std_filename(pjob, newattr[(int)JOB_ATR_outpath].at_val.at_str, (int)'o'))); } } if ((rc == 0) && (newattr[(int)JOB_ATR_errpath].at_flags & ATR_VFLAG_MODIFY)) { /* need to recheck if JOB_ATR_errpath is a special case of host only */ if (newattr[(int)JOB_ATR_errpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_errpath].at_val.at_str) - 1] == ':') { newattr[(int)JOB_ATR_errpath].at_val.at_str = prefix_std_file(pjob, (int)'e'); } /* * if the error path was specified and ends with a '/' * then append the standard file name */ else if (newattr[(int)JOB_ATR_errpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_errpath].at_val.at_str) - 1] == '/') { newattr[(int)JOB_ATR_errpath].at_val.at_str[strlen(newattr[(int)JOB_ATR_errpath].at_val.at_str) - 1] = '\0'; replace_attr_string(&newattr[(int)JOB_ATR_errpath], (add_std_filename(pjob, newattr[(int)JOB_ATR_errpath].at_val.at_str, (int)'e'))); } } } /* END if (rc == 0) */ if (rc != 0) { for (i = 0;i < JOB_ATR_LAST;i++) job_attr_def[i].at_free(newattr + i); /* FAILURE */ return(rc); } /* END if (rc != 0) */ /* OK, now copy the new values into the job attribute array */ for (i = 0;i < JOB_ATR_LAST;i++) { if (newattr[i].at_flags & ATR_VFLAG_MODIFY) { if (LOGLEVEL >= 7) { sprintf(log_buffer, "attr %s modified", job_attr_def[i].at_name); LOG_EVENT( PBSEVENT_JOB, PBS_EVENTCLASS_JOB, pjob->ji_qs.ji_jobid, log_buffer); } job_attr_def[i].at_free(pattr + i); if ((newattr[i].at_type == ATR_TYPE_LIST) || (newattr[i].at_type == ATR_TYPE_RESC)) { list_move( &newattr[i].at_val.at_list, &(pattr + i)->at_val.at_list); } else { *(pattr + i) = newattr[i]; } (pattr + i)->at_flags = newattr[i].at_flags; } } /* END for (i) */ /* note, the newattr[] attributes are on the stack, they go away automatically */ pjob->ji_modified = 1; return(0); } /* END modify_job_attr() */