/*___INFO__MARK_BEGIN__*/ /************************************************************************* * * The Contents of this file are made available subject to the terms of * the Sun Industry Standards Source License Version 1.2 * * Sun Microsystems Inc., March, 2001 * * * Sun Industry Standards Source License Version 1.2 * ================================================= * The contents of this file are subject to the Sun Industry Standards * Source License Version 1.2 (the "License"); You may not use this file * except in compliance with the License. You may obtain a copy of the * License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html * * Software provided under this License is provided on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. * See the License for the specific provisions governing your rights and * obligations concerning the Software. * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2001 by Sun Microsystems, Inc. * * All Rights Reserved. * ************************************************************************/ /*___INFO__MARK_END__*/ #include #include #include #include #include #include "rmon/sgermon.h" #include "uti/sge_log.h" #include "uti/sge_stdlib.h" #include "uti/sge_string.h" #include "uti/sge_hostname.h" #include "uti/sge_parse_num_par.h" #include "gdi/sge_gdi.h" #include "sge_all_listsL.h" #include "sge_pe.h" #include "sge_qinstance_type.h" #include "sge_schedd_conf.h" #include "sge_userprj.h" #include "sge_userset.h" #include "sge_answer.h" #include "sge_range.h" #include "sge_object.h" #include "sge_centry.h" #include "sge_str.h" #include "sge_subordinate.h" #include "sge_utility.h" #include "cull_parse_util.h" #include "parse.h" #include "sge_eval_expression.h" #include "msg_common.h" #include "msg_sgeobjlib.h" #define OBJECT_LAYER BASIS_LAYER static lList *Master_Job_List = NULL; static lList *Master_Zombie_List = NULL; static lList *Master_Job_Schedd_Info_List = NULL; static lList *Master_CEntry_List = NULL; static lList *Master_HGroup_List = NULL; static lList *Master_Userset_List = NULL; static lList *Master_Project_List = NULL; static lList *Master_User_List = NULL; static lList *Master_CQueue_List = NULL; static lList *Master_Exechost_List = NULL; static lList *Master_Adminhost_List = NULL; static lList *Master_Submithost_List = NULL; static lList *Master_Calendar_List = NULL; static lList *Master_Ckpt_List = NULL; static lList *Master_Manager_List = NULL; static lList *Master_Operator_List = NULL; static lList *Master_Sharetree_List = NULL; static lList *Master_Pe_List = NULL; static lList *Master_SUser_List = NULL; static lList *Master_RQS_List = NULL; static lList *Master_AR_List = NULL; static lList *Master_SchedulerConfig_List = NULL; static lList *Master_Config_List = NULL; #ifndef __SGE_NO_USERMAPPING__ static lList *Master_Cuser_List = NULL; #endif /* One entry per event type */ static object_description object_base[SGE_TYPE_ALL] = { /* master list set function name descr key */ { &Master_Adminhost_List, NULL, "ADMINHOST", AH_Type, AH_name }, { &Master_Calendar_List, NULL, "CALENDAR", CAL_Type, CAL_name }, { &Master_Ckpt_List, NULL, "CKPT", CK_Type, CK_name }, { &Master_Config_List, NULL, "CONFIG", CONF_Type, CONF_name }, { NULL, NULL, "GLOBAL_CONFIG", NULL, NoName }, { &Master_Exechost_List, NULL, "EXECHOST", EH_Type, EH_name }, { NULL, NULL, "JATASK", JAT_Type, JAT_task_number }, { NULL, NULL, "PETASK", PET_Type, PET_id }, { &Master_Job_List, NULL, "JOB", JB_Type, JB_job_number }, { &Master_Job_Schedd_Info_List, NULL, "JOB_SCHEDD_INFO", SME_Type, NoName }, { &Master_Manager_List, NULL, "MANAGER", UM_Type, UM_name }, { &Master_Operator_List, NULL, "OPERATOR", UO_Type, UO_name }, { &Master_Sharetree_List, NULL, "SHARETREE", STN_Type, STN_name }, { &Master_Pe_List, NULL, "PE", PE_Type, PE_name }, { &Master_Project_List, NULL, "PROJECT", PR_Type, PR_name }, { &Master_CQueue_List, NULL, "CQUEUE", CQ_Type, CQ_name }, { NULL, NULL, "QINSTANCE", QU_Type, QU_qname }, { &Master_SchedulerConfig_List, sconf_validate_config_, "SCHEDD_CONF", SC_Type, NoName }, { NULL, NULL, "SCHEDD_MONITOR", NULL, NoName }, { NULL, NULL, "SHUTDOWN", NULL, NoName }, { NULL, NULL, "QMASTER_GOES_DOWN", NULL, NoName }, { &Master_Submithost_List, NULL, "SUBMITHOST", SH_Type, SH_name }, { &Master_User_List, NULL, "USER", UU_Type, UU_name }, { &Master_Userset_List, NULL, "USERSET", US_Type, US_name }, { &Master_HGroup_List, NULL, "HOSTGROUP", HGRP_Type, HGRP_name }, { &Master_CEntry_List, NULL, "COMPLEX_ENTRY", CE_Type, CE_name }, { &Master_Zombie_List, NULL, "ZOMBIE_JOBS", JB_Type, JB_job_number }, { &Master_SUser_List, NULL, "SUBMIT_USER", SU_Type, SU_name }, { &Master_RQS_List, NULL, "RQS", RQS_Type, RQS_name }, { &Master_AR_List, NULL, "AR", AR_Type, AR_id }, { NULL, NULL, "JOBSCRIPT", STU_Type, STU_name }, #ifndef __SGE_NO_USERMAPPING__ { &Master_Cuser_List, NULL, "USERMAPPING", CU_Type, CU_name } #endif }; /*-------------------------*/ /* multithreading support */ /*-------------------------*/ /* contains the information for the thread local structure. */ typedef struct { bool global; /* thrue means, that the global structure is referenced */ lList *lists[SGE_TYPE_ALL]; /* stores the list information */ object_description object_base[SGE_TYPE_ALL]; /* subscription handlers */ } obj_state_t; /* the key for the thread local memeory */ static pthread_key_t obj_state_key; static pthread_once_t obj_once = PTHREAD_ONCE_INIT; static void obj_state_destroy(void* st); static void obj_thread_local_once_init(void); static void obj_thread_local_once_init(void) { pthread_key_create(&obj_state_key, obj_state_destroy); } static bool object_parse_raw_field_from_string(lListElem *object, lList **answer_list, const int nm, const char *value); static const char * object_append_raw_field_to_dstring(const lListElem *object, lList **answer_list, dstring *buffer, const int nm, char string_quotes); /****** sge_object/obj_state_init() ******************************************** * NAME * obj_state_init() -- Inits the thread local memory none global * * SYNOPSIS * static void obj_state_init(obj_state_t *state) * * FUNCTION * Inits the thread local memory, by coping the static information and * setting the list pointers to NULL * * INPUTS * obj_state_t *state - the thread local memory * * NOTES * MT-NOTE: obj_state_init() is MT safe * * SEE ALSO * sge_object/obj_state_global_init * sge_object/obj_state_destroy * sge_object/obj_mt_init *******************************************************************************/ static void obj_state_init(obj_state_t *state) { int i; state->global = false; memcpy(state->object_base, object_base, sizeof(object_description) * SGE_TYPE_ALL); /* initialize mirroring data structures - only changeable fields */ for (i = 0; i < SGE_TYPE_ALL; i++) { state->lists[i] = NULL; state->object_base[i].list = &(state->lists[i]); /* master list */ } } /****** sge_object/obj_state_global_init() ************************************ * NAME * obj_state_global_init() -- Inits the thread local memory global * * SYNOPSIS * static void obj_state_global_init(obj_state_t *state) * * FUNCTION * Inits the thread local memory, by coping the static information and * setting the list pointers to NULL * * INPUTS * obj_state_t *state - the thread local memory * * NOTES * MT-NOTE: obj_state_global_init() is MT safe * * SEE ALSO * sge_object/obj_state_init * sge_object/obj_state_destroy * sge_object/obj_mt_init *******************************************************************************/ static void obj_state_global_init(obj_state_t* state) { int i; DENTER(TOP_LAYER, "obj_state_global_init"); state->global=true; if (state != NULL) { memcpy(state->object_base, object_base, sizeof(object_description) * SGE_TYPE_ALL); /* initialize mirroring data structures - only changeable fields */ for (i = 0; i < SGE_TYPE_ALL; i++) { state->lists[i] = NULL; state->object_base[i].list = object_base[i].list; } } else { /* SG: we need a error message */ abort(); } DEXIT; } /****** sge_object/obj_state_destroy() ***************************************** * NAME * obj_state_destroy() -- frees the thread local memory * * SYNOPSIS * static void obj_state_destroy(void* st) * * INPUTS * void* st - thread local memory * * NOTES * MT-NOTE: obj_state_destroy() is MT safe * * SEE ALSO * sge_object/obj_state_global_init * sge_object/obj_state_init * sge_object/obj_mt_init *******************************************************************************/ static void obj_state_destroy(void* st) { int i; obj_state_t *state = (obj_state_t*) st; for (i = 0; i < SGE_TYPE_ALL; i++) { lFreeList(&(state->lists[i])); } free(state); } /****** sge_object/obj_mt_init() *********************************************** * NAME * obj_mt_init() -- creats the pthread key * * SYNOPSIS * void obj_mt_init(void) * * FUNCTION * Creates the pthread key. Needs to be called when the daemon, clients * starts up * * NOTES * MT-NOTE: obj_mt_init() is not MT safe * * * SEE ALSO * sge_object/obj_state_global_init * sge_object/obj_state_init * sge_object/obj_state_destroy *******************************************************************************/ void obj_mt_init(void) { pthread_once(&obj_once, obj_thread_local_once_init); } void obj_init(bool is_global) { obj_state_t *state = NULL; int ret = 0; bool init = false; DENTER(TOP_LAYER, "obj_init"); if((state = pthread_getspecific(obj_state_key)) == NULL) { state = (obj_state_t*) malloc(sizeof(obj_state_t)); memset(state, 0 , sizeof(obj_state_t)); init = true; ret = pthread_setspecific(obj_state_key, (void*)state); if (ret != 0) { abort(); /* find a better way for this, use a return code */ } } if (init || (state->global != is_global)) { if (is_global) { if (!init) { int i; for (i = 0; i < SGE_TYPE_ALL; i++) { lFreeList(&(state->lists[i])); } } obj_state_global_init(state); } else { obj_state_init(state); } } DEXIT; } /****** sgeobj/object/object_has_type() *************************************** * NAME * object_has_type() -- has an object a certain type? * * SYNOPSIS * bool * object_has_type(const lListElem *object, const lDescr *descr) * * FUNCTION * Checks if an object has a certain type. * The check is done by looking up the primary key field in descr and * checking, if this key field is contained in the given object. * * INPUTS * const lListElem *object - object to check * const lDescr *descr - type to check against * * RESULT * bool - true, if the object has the given type, else false * * NOTES * As looking up the primary key of an object is only implemented * for selected types, this function also will work only for these * object types. * * SEE ALSO * sgeobj/object/object_get_primary_key() *******************************************************************************/ bool object_has_type(const lListElem *object, const lDescr *descr) { bool ret = false; /* * we assume that "object" is of the given type when the * primary key is contained in the element * * --> make sure that your object is handled in object_get_primary_key() */ if (object != NULL && descr != NULL && _lGetPosInDescr(object->descr, object_get_primary_key(descr)) != -1) { ret = true; } return ret; } /****** sgeobj/object/object_get_type() *************************************** * NAME * object_get_type() -- return type (descriptor) for object * * SYNOPSIS * const lDescr * object_get_type(const lListElem *object) * * FUNCTION * Returns the cull type (descriptor) for a certain object. * This descriptor can be different from the objects descriptor, * as the objects descriptor can come from an object created from * communication, can be a partial descriptor etc. * * INPUTS * const lListElem *object - the object to analyze * * RESULT * const lDescr * - the object type / descriptor * *******************************************************************************/ const lDescr * object_get_type(const lListElem *object) { const lDescr *ret = NULL; if (object_has_type(object, AH_Type)) { ret = AH_Type; } else if (object_has_type(object, CAL_Type)) { ret = CAL_Type; } else if (object_has_type(object, CK_Type)) { ret = CK_Type; } else if (object_has_type(object, EH_Type)) { ret = EH_Type; } else if (object_has_type(object, JAT_Type)) { ret = JAT_Type; } else if (object_has_type(object, JB_Type)) { ret = JB_Type; } else if (object_has_type(object, PE_Type)) { ret = PE_Type; } else if (object_has_type(object, PET_Type)) { ret = PET_Type; } else if (object_has_type(object, QU_Type)) { ret = QU_Type; } else if (object_has_type(object, QR_Type)) { ret = QR_Type; } else if (object_has_type(object, RN_Type)) { ret = RN_Type; } else if (object_has_type(object, SH_Type)) { ret = SH_Type; } else if (object_has_type(object, VA_Type)) { ret = VA_Type; } return ret; } /****** sgeobj/object/object_get_primary_key() ******************************** * NAME * object_get_primary_key() -- get primary key for object type * * SYNOPSIS * int object_get_primary_key(const lDescr *descr) * * FUNCTION * Returns the primary key field for a given object type. * * INPUTS * const lDescr *descr - the object type (descriptor) * * RESULT * int - name (nm) of the primary key field or * NoName (-1) on error. * * NOTES * Only implemented for selected object types. * It would be better to have the necessary data in the object * description, e.g. via a field property CULL_PRIMARY_KEY. * * Function interface breaks style guide - either we would have to * pass an object, or call it descr_get_primary_key. *******************************************************************************/ int object_get_primary_key(const lDescr *descr) { int ret = NoName; if (descr != NULL) { int i; for (i = 0; descr[i].nm != NoName; i++) { if (descr[i].mt & CULL_PRIMARY_KEY) { ret = descr[i].nm; break; } } } #if 0 ret = MR_user; /* JG: TODO: is this really the primary key? */ ret = PA_origin; /* JG: TODO: this is most probably no primary key! */ #endif return ret; } /****** sgeobj/object/object_get_name_prefix() ******************************** * NAME * object_get_name_prefix() -- get prefix of cull attribute name * * SYNOPSIS * const char * * object_get_name_prefix(const lDescr *descr, dstring *buffer) * * FUNCTION * Returns the prefix that is used in attribute names characterizing * the object type (e.g. "QU_" for the QU_Type). * * INPUTS * const lDescr *descr - object type to use * dstring *buffer - buffer that is used to return the result * * RESULT * const char * - the prefix or * NULL, if an error occured * * EXAMPLE * object_get_name_prefix(QU_Type, buffer) = "QU_" * object_get_name_prefix(JB_Type, buffer) = "JB_" * * NOTES * The function relies on object_get_primary_key. This function only * is implemented for some object types. * For types not handled in object_get_primary_key, NULL will be * returned. * * SEE ALSO * sgeobj/object/object_get_primary_key() *******************************************************************************/ const char * object_get_name_prefix(const lDescr *descr, dstring *buffer) { int nm; if (descr == NULL || buffer == NULL) { return NULL; } nm = descr[0].nm; if (nm != NoName) { const char *name = lNm2Str(nm); if (name != NULL) { char *underscore = strchr(name, '_'); if (underscore != NULL) { sge_dstring_sprintf(buffer, "%.*s", underscore - name + 1, name); return sge_dstring_get_string(buffer); } } } return NULL; } /****** sge_object/object_get_name() ******************************************* * NAME * object_get_name() -- get the object name by object descriptor * * SYNOPSIS * const char * * object_get_name(const lDescr *descr) * * FUNCTION * Returns the object name for a given descriptor. * If the descriptor doesn't match a descriptor in object_base, * return "unknown". * * INPUTS * const lDescr *descr - descriptor. * * RESULT * const char * - the object name * * EXAMPLE * object_get_name(JOB_Type) returns "JOB" * * NOTES * MT-NOTE: object_get_name() is MT safe *******************************************************************************/ const char * object_get_name(const lDescr *descr) { const char *name = "unknown"; if (descr != NULL) { int i; for (i = SGE_TYPE_ADMINHOST; i < SGE_TYPE_ALL; i++) { if (object_base[i].descr == descr) { name = object_base[i].type_name; break; } } } return name; } /****** sgeobj/object/object_append_field_to_dstring() ************************ * NAME * object_append_field_to_dstring() -- object field to string * * SYNOPSIS * const char * * object_append_field_to_dstring(const lListElem *object, * lList **answer_list, * dstring *buffer, const int nm, * char string_quotes) * * FUNCTION * Returns a string representation of a given object attribute. * If errors arrise they are returned in the given answer_list. * Data will be created in the given dynamic string buffer. * For some fields a special handling is implemented, e.g. mapping * bitfields to string lists. * * INPUTS * const lListElem *object - object to use * lList **answer_list - used to return error messages * dstring *buffer - buffer used to format the result * const int nm - attribute to output * char string_quotes - character to be used for string quoting * '\0' means no quoting * * RESULT * const char * - string representation of the attribute value * (pointer to the string in the dynamic string * buffer, or NULL if an error occured. * * NOTES * For sublists, subobjects and references NULL is returned. * * BUGS * For the handled special cases, the dstring is cleared, * the default handling appends to the dstring buffer. * * SEE ALSO * sgeobj/object/--GDI-object-Handling * sgeobj/object/object_parse_field_from_string() *******************************************************************************/ const char * object_append_field_to_dstring(const lListElem *object, lList **answer_list, dstring *buffer, const int nm, const char string_quotes) { const char *ret = NULL; dstring string = DSTRING_INIT; bool quote_special_case = false; DENTER(OBJECT_LAYER, "object_append_field_to_dstring"); SGE_CHECK_POINTER_NULL(object, answer_list); /* handle special cases * these special cases are for instance bitfields that shall be * output as readable strings. * Usually such special cases are evidence of bad data base design. * Example: QU_qtype is a bitfield of types (BATCH, PARALLEL, ...) * Instead, multiple boolean fields should be created: * QU_batch, QU_parallel, ... */ switch (nm) { case CE_valtype: ret = map_type2str(lGetUlong(object, nm)); quote_special_case = true; break; case CE_relop: ret = map_op2str(lGetUlong(object, nm)); quote_special_case = true; break; case CE_requestable: ret = map_req2str(lGetUlong(object, nm)); break; case CE_consumable: ret = map_consumable2str(lGetUlong(object, nm)); quote_special_case = true; break; case QU_qtype: qinstance_print_qtype_to_dstring(object, &string, false); ret = sge_dstring_get_string(&string); quote_special_case = true; break; case US_type: ret = userset_get_type_string(object, answer_list, &string); quote_special_case = true; break; case ASTRLIST_value: ret = str_list_append_to_dstring(lGetList(object, nm), &string, ' '); break; case AUSRLIST_value: ret = userset_list_append_to_dstring(lGetList(object, nm), &string); break; case APRJLIST_value: ret = prj_list_append_to_dstring(lGetList(object, nm), &string); break; case ACELIST_value: ret = centry_list_append_to_dstring(lGetList(object, nm), &string); break; case ASOLIST_value: ret = so_list_append_to_dstring(lGetList(object, nm), &string); break; case AQTLIST_value: ret = qtype_append_to_dstring(lGetUlong(object, nm), &string); break; } /* we had a special case - append to result dstring */ if (ret != NULL) { if (quote_special_case && string_quotes != '\0') { sge_dstring_append_char(buffer, string_quotes); sge_dstring_append(buffer, ret); ret = sge_dstring_append_char(buffer, string_quotes); } else { ret = sge_dstring_append(buffer, ret); } } else { ret = object_append_raw_field_to_dstring(object, answer_list, buffer, nm, string_quotes); } sge_dstring_free(&string); DRETURN(ret); } /****** sgeobj/object/object_append_raw_field_to_dstring() ********************* * NAME * object_append_raw_field_to_dstring() -- object field to string * * SYNOPSIS * const char * * object_append_raw_field_to_dstring(const lListElem *object, * lList **answer_list, * dstring *buffer, const int nm, * char string_quotes) * * FUNCTION * Returns a string representation of a given object attribute. * If errors arrise they are returned in the given answer_list. * Data will be created in the given dynamic string buffer. * For some fields a special handling is implemented, e.g. mapping * bitfields to string lists. * * INPUTS * const lListElem *object - object to use * lList **answer_list - used to return error messages * dstring *buffer - buffer used to format the result * const int nm - attribute to output * char string_quotes - character to be used for string quoting * '\0' means no quoting * * RESULT * const char * - string representation of the attribute value * (pointer to the string in the dynamic string * buffer, or NULL if an error occured. * * NOTES * For sublists, subobjects and references NULL is returned. * * BUGS * For the handled special cases, the dstring is cleared, * the default handling appends to the dstring buffer. * * SEE ALSO * sgeobj/object/--GDI-object-Handling * sgeobj/object/object_parse_field_from_string() *******************************************************************************/ static const char * object_append_raw_field_to_dstring(const lListElem *object, lList **answer_list, dstring *buffer, const int nm, char string_quotes) { const char *str; const char *result = NULL; int pos; DENTER(OBJECT_LAYER, "object_append_raw_field_to_dstring"); pos = lGetPosViaElem(object, nm, SGE_NO_ABORT); if (pos < 0) { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_NMNOTINELEMENT_S, lNm2Str(nm)); } else { const lDescr *descr; int type; descr = lGetElemDescr(object); type = lGetPosType(descr, pos); /* no special case: read and copy data from object */ switch (type) { case lFloatT: result = sge_dstring_sprintf_append(buffer, "%f", lGetPosFloat(object, pos)); break; case lDoubleT: result = sge_dstring_sprintf_append(buffer, "%lf", lGetPosDouble(object, pos)); break; case lUlongT: result = sge_dstring_sprintf_append(buffer, sge_U32CFormat, lGetPosUlong(object, pos)); break; case lLongT: result = sge_dstring_sprintf_append(buffer, "%ld", lGetPosLong(object, pos)); break; case lCharT: result = sge_dstring_sprintf_append(buffer, "%c", lGetPosChar(object, pos)); break; case lBoolT: result = sge_dstring_append(buffer, lGetPosBool(object, pos) ? TRUE_STR : FALSE_STR); break; case lIntT: result = sge_dstring_sprintf_append(buffer, "%d", lGetPosInt(object, pos)); break; case lStringT: str = lGetPosString(object, pos); if (string_quotes != '\0') { sge_dstring_append_char(buffer, string_quotes); sge_dstring_append(buffer, str != NULL ? str : NONE_STR); result = sge_dstring_append_char(buffer, string_quotes); } else { result = sge_dstring_append(buffer, str != NULL ? str : NONE_STR); } break; case lHostT: str = lGetPosHost(object, pos); if (string_quotes != '\0') { sge_dstring_append_char(buffer, string_quotes); sge_dstring_append(buffer, str != NULL ? str : NONE_STR); result = sge_dstring_append_char(buffer, string_quotes); } else { result = sge_dstring_append(buffer, str != NULL ? str : NONE_STR); } break; case lListT: case lObjectT: case lRefT: /* what do to here? */ break; default: answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_INVALIDCULLDATATYPE_D, type); break; } } DRETURN(result); } /****** sgeobj/object/object_parse_field_from_string() ************************ * NAME * object_parse_field_from_string() -- set object attr. from str * * SYNOPSIS * bool * object_parse_field_from_string(lListElem *object, * lList **answer_list, * const int nm, const char *value) * * FUNCTION * Sets a new value for a certain object attribute. * The new value is passed as parameter in string format. * For some fields a special handling is implemented, e.g. mapping * string lists to bitfields. * * INPUTS * lListElem *object - the object to change * lList **answer_list - used to return error messages * const int nm - the attribute to change * const char *value - the new value * * RESULT * bool - true on success, * false, on error, error description in answer_list * * NOTES * Sublists, subobjects and references cannot be set with this * function. * * SEE ALSO * sgeobj/object/--GDI-object-Handling * sgeobj/object/object_append_field_to_dstring() ******************************************************************************/ bool object_parse_field_from_string(lListElem *object, lList **answer_list, const int nm, const char *value) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_field_from_string"); SGE_CHECK_POINTER_FALSE(object, answer_list); /* handle special cases */ switch (nm) { case CE_valtype: { /* JG: TODO: we should better have a function map_str2type * and isn't there some sort of framework for mapping * strings to ints and vice versa? See QU_qtype implementation. */ u_long32 type = 0; int i; for (i=TYPE_FIRST; !type && i<=TYPE_CE_LAST; i++) { if (strcasecmp(value, map_type2str(i)) == 0) { type = i; } } if (type == 0) { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_SGETEXT_UNKNOWN_ATTR_TYPE_S, value); ret = false; } else { lSetUlong(object, nm, type); } } break; case CE_relop: { u_long32 op = 0; int i; for (i=TYPE_FIRST; !op && i<=TYPE_DOUBLE; i++) { if (!strcasecmp(value, map_op2str(i))) op = i; } if (op == 0) { /* error output necessary? Should be created by parsing function */ ret = false; } else { lSetUlong(object, nm, op); } } break; case CE_requestable: { u_long32 requestable = REQU_NO; if (strcasecmp(value, "y") == 0 || strcasecmp(value, "yes") == 0) { requestable = REQU_YES; } else if (strcasecmp(value, "n") == 0 || strcasecmp(value, "no") == 0) { requestable = REQU_NO; } else if (strcasecmp(value, "f") == 0 || strcasecmp(value, "forced") == 0) { requestable = REQU_FORCED; } else { ret = false; } if (ret) { lSetUlong(object, nm, requestable); } } break; case CE_consumable: { u_long32 cond = CONSUMABLE_NO; if (strcasecmp(value, "y") == 0 || strcasecmp(value, "yes") == 0) { cond = CONSUMABLE_YES; } else if (strcasecmp(value, "n") == 0 || strcasecmp(value, "no") == 0) { cond = CONSUMABLE_NO; } else if (strcasecmp(value, "j") == 0 || strcasecmp(value, "job") == 0) { cond = CONSUMABLE_JOB; } else { ret = false; } lSetUlong(object, nm, cond); } break; case QU_qtype: ret = qinstance_parse_qtype_from_string(object, answer_list, value); break; case US_type: ret = userset_set_type_string(object, answer_list, value); break; case AMEM_value: ret = object_parse_mem_from_string(object, answer_list, nm, value); break; case ATIME_value: ret = object_parse_time_from_string(object, answer_list, nm, value); break; case AINTER_value: ret = object_parse_inter_from_string(object, answer_list, nm, value); break; case ASTRLIST_value: ret = object_parse_list_from_string(object, answer_list, nm, value, ST_Type, ST_name); break; case AUSRLIST_value: ret = object_parse_list_from_string(object, answer_list, nm, value, US_Type, US_name); break; case APRJLIST_value: ret = object_parse_list_from_string(object, answer_list, nm, value, PR_Type, PR_name); break; case ACELIST_value: ret = object_parse_celist_from_string(object, answer_list, nm, value); break; case ASOLIST_value: ret = object_parse_solist_from_string(object, answer_list, nm, value); break; case AQTLIST_value: ret = object_parse_qtlist_from_string(object, answer_list, nm, value); break; default: ret = object_parse_raw_field_from_string(object, answer_list, nm, value); break; } DRETURN(ret); } /****** sgeobj/object/object_parse_raw_field_from_string() ************************ * NAME * object_parse_raw_field_from_string() -- set object attr. from str * * SYNOPSIS * bool * object_parse_raw_field_from_string(lListElem *object, * lList **answer_list, * const int nm, const char *value) * * FUNCTION * Sets a new value for a certain object attribute. * The new value is passed as parameter in string format. * * INPUTS * lListElem *object - the object to change * lList **answer_list - used to return error messages * const int nm - the attribute to change * const char *value - the new value * * RESULT * bool - true on success, * false, on error, error description in answer_list * * NOTES * Sublists, subobjects and references cannot be set with this * function. * * SEE ALSO * sgeobj/object/--GDI-object-Handling * sgeobj/object/object_append_field_to_dstring() ******************************************************************************/ static bool object_parse_raw_field_from_string(lListElem *object, lList **answer_list, const int nm, const char *value) { bool ret = true; int pos; DENTER(OBJECT_LAYER, "object_parse_raw_field_from_string"); pos = lGetPosViaElem(object, nm, SGE_NO_ABORT); if (pos < 0) { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_NMNOTINELEMENT_S, lNm2Str(nm)); ret = false; } else { const lDescr *descr; int type; descr = lGetElemDescr(object); type = lGetPosType(descr, pos); /* read data */ switch (type) { case lFloatT: ret = object_parse_float_from_string(object, answer_list, nm, value); break; case lDoubleT: ret = object_parse_double_from_string(object, answer_list, nm, value); break; case lUlongT: ret = object_parse_ulong32_from_string(object, answer_list, nm, value); break; case lLongT: ret = object_parse_long_from_string(object, answer_list, nm, value); break; case lCharT: ret = object_parse_char_from_string(object, answer_list, nm, value); break; case lBoolT: ret = object_parse_bool_from_string(object, answer_list, nm, value); break; case lIntT: ret = object_parse_int_from_string(object, answer_list, nm, value); break; case lStringT: lSetPosString(object, pos, value); break; case lHostT: lSetPosHost(object, pos, value); break; case lListT: case lObjectT: case lRefT: /* what do to here? */ break; default: answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_INVALIDCULLDATATYPE_D, type); break; } } DRETURN(ret); } /****** sgeobj/object/object_delete_range_id() ******************************** * NAME * object_delete_range_id() -- del certain id from an range_list * * SYNOPSIS * void * object_delete_range_id(lListElem *object, lList **answer_list, * const int rnm, const u_long32 id) * * FUNCTION * Deletes a certain id from an objects sublist that is a range list. * * INPUTS * lListElem *object - the object to handle * lList **answer_list - error messages will be put here * const int rnm - attribute containing the range list * const u_long32 id - id to delete * *******************************************************************************/ void object_delete_range_id(lListElem *object, lList **answer_list, const int rnm, const u_long32 id) { lList *range_list = NULL; lXchgList(object, rnm, &range_list); range_list_remove_id(&range_list, answer_list, id); range_list_compress(range_list); lXchgList(object, rnm, &range_list); } /****** sgeobj/object/object_set_range_id() ********************************** * NAME * object_set_range_id() -- store the initial range ids in "job" * * SYNOPSIS * int object_set_range_id(lListElem *job, u_long32 start, * u_long32 end, u_long32 step) * * FUNCTION * The function stores the initial range id values ("start", "end" * and "step") in the range list of an object. It should only be used * in functions initializing objects range lists. * * INPUTS * lListElem *object - object to handle * const int rnm - attribute containing the range list * u_long32 start - first id * u_long32 end - last id * u_long32 step - step size * * RESULT * int - 0 -> OK * 1 -> no memory * * NOTES * MT-NOTE: object_set_range_id() is MT safe ******************************************************************************/ int object_set_range_id(lListElem *object, int rnm, u_long32 start, u_long32 end, u_long32 step) { lListElem *range_elem; /* RN_Type */ int ret = 0; range_elem = lFirst(lGetList(object, rnm)); if (range_elem == NULL) { lList *range_list; range_elem = lCreateElem(RN_Type); range_list = lCreateList("task_id_range", RN_Type); if (range_elem == NULL || range_list == NULL) { lFreeElem(&range_elem); lFreeList(&range_list); /* No memory */ ret = 1; } else { lAppendElem(range_list, range_elem); lSetList(object, rnm, range_list); } } if (range_elem != NULL) { lSetUlong(range_elem, RN_min, start); lSetUlong(range_elem, RN_max, end); lSetUlong(range_elem, RN_step, step); } return ret; } /****** sgeobj/object/object_type_get_master_list() ************************** * NAME * object_type_get_master_list() -- get master list for object type * * SYNOPSIS * lList** object_type_get_master_list(const sge_object_type type) * * FUNCTION * Returns a pointer to the master list holding objects of the * given type. * * INPUTS * const sge_object_type type - the object type * * RESULT * lList** - the corresponding master list, or NULL, if the object * type has no associated master list * * EXAMPLE * object_type_get_master_list(SGE_TYPE_JOB) will return a pointer * to the Master_Job_List. * * object_type_get_master_list(SGE_TYPE_SHUTDOWN) will return NULL, * as this object type has no associated master list. * * NOTES * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_name() * sgeobj/object/object_type_get_descr() * sgeobj/object/object_type_get_key_nm() *******************************************************************************/ lList **object_type_get_master_list(const sge_object_type type) { lList **ret = NULL; DENTER(OBJECT_LAYER, "object_type_get_master_list"); if (type >= 0 && type < SGE_TYPE_ALL) { GET_SPECIFIC(obj_state_t, obj_state, obj_state_global_init, obj_state_key, "object_type_get_master_list"); if (obj_state->object_base[type].list != NULL) { ret = obj_state->object_base[type].list; } else { ERROR((SGE_EVENT, MSG_OBJECT_NO_LIST_TO_MOD_TYPE_SI, SGE_FUNC, type)); } } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } /****** sgeobj/object/sge_master_list() ************************** * NAME * sge_master_list() -- get master list for object type * * SYNOPSIS * lList** sge_master_list(const object_description *object_base, * const sge_object_type type) * * FUNCTION * Returns a pointer to the master list holding objects of the * given type. * * INPUTS * const sge_object_type type - the object type * * RESULT * lList** - the corresponding master list, or NULL, if the object * type has no associated master list * * EXAMPLE * object_type_get_master_list(SGE_TYPE_JOB) will return a pointer * to the Master_Job_List. * * object_type_get_master_list(SGE_TYPE_SHUTDOWN) will return NULL, * as this object type has no associated master list. * * NOTES * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_name() * sgeobj/object/object_type_get_descr() * sgeobj/object/object_type_get_key_nm() *******************************************************************************/ lList **sge_master_list(const object_description *object_base, const sge_object_type type) { lList **ret = NULL; DENTER(OBJECT_LAYER, "sge_master_list"); if (type >= 0 && type < SGE_TYPE_ALL) { if (object_base[type].list != NULL) { ret = object_base[type].list; } else { ERROR((SGE_EVENT, MSG_OBJECT_NO_LIST_TO_MOD_TYPE_SI, SGE_FUNC, type)); } } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } /****** sge_object/object_type_get_object_description() ************************ * NAME * object_type_get_object_description() -- gets the master list table * * SYNOPSIS * object_description* object_type_get_object_description() * * FUNCTION * ??? * * RESULT * object_description* - the table with all master lists and its information * * NOTES * MT-NOTE: object_type_get_object_description() is MT safe * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_name() * sgeobj/object/object_type_get_descr() * sgeobj/object/object_type_get_key_nm() *******************************************************************************/ object_description *object_type_get_object_description(void) { object_description *ret = NULL; DENTER(OBJECT_LAYER, "object_type_get_object_description"); { GET_SPECIFIC(obj_state_t, obj_state, obj_state_global_init, obj_state_key, "object_type_get_object_description"); ret = obj_state->object_base; } DRETURN(ret); } /****** sge_object/object_type_get_global_object_description() ***************** * NAME * object_type_get_global_object_description() -- grands access to the global * master lists * * SYNOPSIS * object_description* object_type_get_global_object_description(void) * * RESULT * object_description* - the global object description / master lists * * NOTES * MT-NOTE: object_type_get_global_object_description() is MT safe * * SEE ALSO * sge_object/object_type_get_global_object_description() * *******************************************************************************/ object_description *object_type_get_global_object_description(void) { object_description *ret = NULL; DENTER(OBJECT_LAYER, "object_type_get_object_description"); ret = object_base; DRETURN(ret); } bool object_type_commit_master_list(const sge_object_type type, lList **answer_list) { bool ret = true; DENTER(OBJECT_LAYER, "object_type_set_master_list"); if (type >= 0 && type < SGE_TYPE_ALL) { if (object_base[type].commitMasterList) { ret = object_base[type].commitMasterList(answer_list); } } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); ret = false; } DRETURN(ret); } /****** sgeobj/object/object_type_free_master_list() *************************** * NAME * object_type_free_master_list() -- free the master list * * SYNOPSIS * bool * object_type_free_master_list(const sge_object_type type) * * FUNCTION * Frees the masterlist for a certain type of objects. * * INPUTS * const sge_object_type type - the object type * * RESULT * bool - true, if the list existed and could be freed, else false * * NOTES * * SEE ALSO * sgeobj/object/--object-Typedefs *******************************************************************************/ bool object_type_free_master_list(const sge_object_type type) { bool ret = false; DENTER(OBJECT_LAYER, "object_type_free_master_list"); if (type >= 0 && type < SGE_TYPE_ALL) { GET_SPECIFIC(obj_state_t, obj_state, obj_state_global_init, obj_state_key, SGE_FUNC); if (obj_state->object_base[type].list) { lFreeList(obj_state->object_base[type].list); ret = true; } } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } /****** sgeobj/object/object_type_get_name() ********************************* * NAME * object_type_get_name() -- get a printable name for event type * * SYNOPSIS * const char* object_type_get_name(const sge_object_type type) * * FUNCTION * Returns a printable name for an event type. * * INPUTS * const sge_object_type type - the event type * * RESULT * const char* - string describing the type * * EXAMPLE * object_type_get_name(SGE_TYPE_JOB) will return "JOB" * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_descr() * sgeobj/object/object_type_get_key_nm() *******************************************************************************/ const char *object_type_get_name(const sge_object_type type) { const char *ret = "unknown"; DENTER(OBJECT_LAYER, "object_type_get_name"); if (type >= 0 && type < SGE_TYPE_ALL) { ret = object_base[type].type_name; } else if (type == SGE_TYPE_ALL) { ret = "default"; } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } /****** sgeobj/object/object_name_get_type() ********************************** * NAME * object_name_get_type() -- Return type id of a certain object * * SYNOPSIS * sge_object_type object_name_get_type(const char *name) * * FUNCTION * returns the type id a an object given by "name" * We allow to pass in names in the form :, e.g. * USERSET:deadlineusers. * * INPUTS * const char *name - object name * * RESULT * sge_object_type - type of the object * * NOTES * MT-NOTE: object_name_get_type() is MT safe *******************************************************************************/ sge_object_type object_name_get_type(const char *name) { sge_object_type ret = SGE_TYPE_ALL; sge_object_type i; char *type_name; char *colon; DENTER(OBJECT_LAYER, "object_name_get_type"); type_name = strdup(name); colon = strchr(type_name, ':'); if (colon != NULL) { *colon = '\0'; } for (i = SGE_TYPE_ADMINHOST; i < SGE_TYPE_ALL; i++) { if (strcasecmp(object_base[i].type_name, type_name) == 0) { ret = i; break; } } FREE(type_name); DRETURN(ret); } /****** sgeobj/object/object_type_get_descr() ******************************** * NAME * object_type_get_descr() -- get the descriptor for an event type * * SYNOPSIS * const lDescr* object_type_get_descr(const sge_object_type type) * * FUNCTION * Returns the CULL element descriptor for the object type * associated with the given event. * * INPUTS * const sge_object_type type - the event type * * RESULT * const lDescr* - the descriptor, or NULL, if no descriptor is * associated with the type * * EXAMPLE * object_type_get_descr(SGE_TYPE_JOB) will return the descriptor * JB_Type, * object_type_get_descr(SGE_TYPE_SHUTDOWN) will return NULL * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_name() * sgeobj/object/object_type_get_key_nm() *******************************************************************************/ const lDescr *object_type_get_descr(const sge_object_type type) { const lDescr *ret = NULL; DENTER(OBJECT_LAYER, "object_type_get_descr"); if (type >= 0 && type < SGE_TYPE_ALL) { ret = object_base[type].descr; } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } /****** sgeobj/object/object_type_get_key_nm() ******************************* * NAME * object_type_get_key_nm() -- get the primary key attribute for type * * SYNOPSIS * int object_type_get_key_nm(const sge_object_type type) * * FUNCTION * Returns the primary key attribute for the object type associated * with the given event type. * * INPUTS * const sge_object_type type - event type * * RESULT * int - the key number (struct element nm of the descriptor), or * -1, if no object type is associated with the event type * * EXAMPLE * object_type_get_key_nm(SGE_TYPE_JOB) will return JB_job_number * object_type_get_key_nm(SGE_TYPE_SHUTDOWN) will return -1 * * SEE ALSO * sgeobj/object/object_type_get_master_list() * sgeobj/object/object_type_get_name() * sgeobj/object/object_type_get_descr() *******************************************************************************/ int object_type_get_key_nm(const sge_object_type type) { int ret = NoName; DENTER(OBJECT_LAYER, "object_type_get_key_nm"); if (type >= 0 && type < SGE_TYPE_ALL) { ret = object_base[type].key_nm; } else { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_OBJECT_TYPE_SI, SGE_FUNC, type)); } DRETURN(ret); } bool object_parse_bool_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_bool_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (!strcasecmp(string, "true") || !strcasecmp(string, "t") || !strcmp(string, "1") || !strcasecmp(string, "yes") || !strcasecmp(string, "y")) { lSetPosBool(this_elem, pos, true); } else if (!strcasecmp(string, "false") || !strcasecmp(string, "f") || !strcmp(string, "0") || !strcasecmp(string, "no") || !strcasecmp(string, "n")) { lSetPosBool(this_elem, pos, false); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_time_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_time_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (parse_ulong_val(NULL, NULL, TYPE_TIM, string, NULL, 0)) { lSetPosString(this_elem, pos, string); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_inter_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_inter_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (parse_ulong_val(NULL, NULL, TYPE_TIM, string, NULL, 0)) { lSetPosString(this_elem, pos, string); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_list_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string, const lDescr *descr, int nm) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_strlist_from_string"); if (this_elem != NULL && string != NULL) { lList *tmp_list = NULL; int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); lString2List(string, &tmp_list, descr, nm, "\t \v\r,"); if (tmp_list != NULL) { lListElem *first_elem = lFirst(tmp_list); const char *first_string = lGetString(first_elem, nm); if (strcasecmp(NONE_STR, first_string)) { lSetPosList(this_elem, pos, tmp_list); } else { lFreeList(&tmp_list); } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_celist_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { static int rule[] = {CE_name, CE_stringval, 0}; bool ret = true; DENTER(TOP_LAYER, "object_parse_celist_from_string"); if (this_elem != NULL && string != NULL) { lList *tmp_list = NULL; int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (!cull_parse_definition_list((char *)string, &tmp_list, "", CE_Type, rule)) { lSetPosList(this_elem, pos, tmp_list); } else { lFreeList(&tmp_list); answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_solist_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_solist_from_string"); if (this_elem != NULL && string != NULL) { lList *tmp_list = NULL; lListElem *tmp_elem = NULL; struct saved_vars_s *last = NULL; char *slots_text = NULL; int pos = -1; pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); /* * The queue wise subordinate is defined like this: * subordinate_list A.q=3,B.q=4 * The slotwise subordinate is defined like this: * subordinate_list slots=4(A.q:1:lr, B.q:2:sr) * If the value of the "subordinate_list" key begins with * "slots=", it's slotwise subordinate, otherwise it's * queue wise subordinate. * * TODO: HP: This parser could be improved, now a queue wise subordinate * that begins with a queue called "slots" will be interpreted as * slotwise subordinate and therefore lead to an error. */ slots_text = sge_strtok_r(string, "=", &last); if (strncasecmp("slots", slots_text, 5) == 0) { /* * slot-wise suspend on subordinate */ char *sub_queues_text = NULL; char *slots_sum_text = NULL; char *endptr = NULL; lUlong slots_sum_value = 0; /* * format of string: slots=8(queue1.q:3:sr, queue2.q:2:lr) */ /* the "slots=" was already skipped in the first sge_strtok_r() */ /* parse the "8" in our example above */ slots_sum_text = sge_strtok_r(NULL, "(", &last); slots_sum_value = strtol(slots_sum_text, &endptr, 10); if (*endptr != '\0') { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } /* point the "sub_queues_text" to the start of the sub queue list */ sub_queues_text = sge_strtok_r(NULL, ")", &last); /* split up the original string from the first subordinated queue on */ lString2List(sub_queues_text, &tmp_list, SO_Type, SO_name, ",) \t"); for_each(tmp_elem, tmp_list) { const char *queue_value = lGetString(tmp_elem, SO_name); char *queuename = sge_strtok(queue_value, ":"); char *value_str = sge_strtok(NULL, ":"); char *action_str = sge_strtok(NULL, ":"); sge_strip_blanks(queuename); sge_strip_blanks(value_str); sge_strip_blanks(action_str); if (queuename != NULL) { lSetString(tmp_elem, SO_name, queuename); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); lFreeList(&tmp_list); ret = false; break; } if (slots_sum_value > 0) { lSetUlong(tmp_elem, SO_slots_sum, slots_sum_value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); lFreeList(&tmp_list); ret = false; break; } if (value_str != NULL) { char *endptr = NULL; u_long32 value = strtol(value_str, &endptr, 10); if (*endptr == '\0') { lSetUlong(tmp_elem, SO_seq_no, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); lFreeList(&tmp_list); ret = false; break; } } else { lSetUlong(tmp_elem, SO_seq_no, 0); } if (action_str != NULL) { if (strcmp(action_str, "lr") == 0) { lSetUlong(tmp_elem, SO_action, SO_ACTION_LR); } else if (strcmp(action_str, "sr") == 0) { lSetUlong(tmp_elem, SO_action, SO_ACTION_SR); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); lFreeList(&tmp_list); ret = false; break; } } else { /* default is "sr" */ lSetUlong(tmp_elem, SO_action, SO_ACTION_SR); } } if (ret) { lSetPosList(this_elem, pos, tmp_list); } } else { lString2List(string, &tmp_list, SO_Type, SO_name, ", \t"); if (tmp_list != NULL) { if (!strcasecmp("NONE", lGetString(lFirst(tmp_list), SO_name))) { lFreeList(&tmp_list); } else { /* * queue instance-wise suspend on subordinate */ for_each(tmp_elem, tmp_list) { const char *queue_value = lGetString(tmp_elem, SO_name); const char *queuename = sge_strtok(queue_value, ":="); const char *value_str = sge_strtok(NULL, ":="); lSetString(tmp_elem, SO_name, queuename); if (value_str != NULL) { char *endptr = NULL; u_long32 value = strtol(value_str, &endptr, 10); if (*endptr == '\0') { lSetUlong(tmp_elem, SO_threshold, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); lFreeList(&tmp_list); ret = false; break; } } else { /* * No value is explicitely allowed */ } } if (ret) { lSetPosList(this_elem, pos, tmp_list); } } } } sge_free_saved_vars(last); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_qtlist_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(TOP_LAYER, "object_parse_qtlist_from_string"); if (this_elem != NULL && string != NULL) { u_long32 value; int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (sge_parse_bitfield_str(string, queue_types, &value, "", answer_list, true)) { lSetPosUlong(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_QTYPE_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_mem_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_mem_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (parse_ulong_val(NULL, NULL, TYPE_MEM, string, NULL, 0)) { lSetPosString(this_elem, pos, string); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_ulong32_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_ulong32_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); if (strlen(string) == 0) { /* * Empty string will be parsed as '0' */ lSetPosUlong(this_elem, pos, (u_long32)0); } else { const double epsilon = 1.0E-12; char *end_ptr = NULL; double dbl_value; u_long32 ulng_value; dbl_value = strtod(string, &end_ptr); ulng_value = dbl_value; if (dbl_value < 0 || dbl_value - ulng_value > epsilon) { /* * value to big for u_long32 variable */ answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_OBJECT_VALUENOTULONG_S, string); ret = false; } else if (end_ptr != NULL && *end_ptr == '\0') { lSetPosUlong(this_elem, pos, ulng_value); } else { /* * Not a number or * garbage after number */ answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ULONG_INCORRECTSTRING, string); ret = false; } } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_int_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_int_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); int value; if (sscanf(string, "%d", &value) == 1) { lSetPosInt(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_INT_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_char_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_char_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); char value; if (sscanf(string, "%c", &value) == 1) { lSetPosChar(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_CHAR_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_long_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_long_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); long value; if (sscanf(string, "%ld", &value) == 1) { lSetPosLong(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_LONG_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_double_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_double_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); double value; if (sscanf(string, "%lf", &value) == 1) { lSetPosDouble(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_DOUBLE_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_parse_float_from_string(lListElem *this_elem, lList **answer_list, int name, const char *string) { bool ret = true; DENTER(OBJECT_LAYER, "object_parse_float_from_string"); if (this_elem != NULL && string != NULL) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); float value; if (sscanf(string, "%f", &value) == 1) { lSetPosFloat(this_elem, pos, value); } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_FLOAT_INCORRECTSTRING, string); ret = false; } } else { answer_list_add_sprintf(answer_list, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR, MSG_ERRORPARSINGVALUEFORNM_S, ""); ret = false; } DRETURN(ret); } bool object_set_any_type(lListElem *this_elem, int name, void *value) { int cull_ret = 0; int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); int type = lGetPosType(lGetElemDescr(this_elem), pos); DENTER(OBJECT_LAYER, "object_set_any_type"); if (type == lStringT) { cull_ret = lSetPosString(this_elem, pos, *((const char **)value)); } else if (type == lHostT) { cull_ret = lSetPosHost(this_elem, pos, *((const char **)value)); } else if (type == lUlongT) { cull_ret = lSetPosUlong(this_elem, pos, *((lUlong*)value)); } else if (type == lDoubleT) { cull_ret = lSetPosDouble(this_elem, pos, *((lDouble*)value)); } else if (type == lFloatT) { cull_ret = lSetPosFloat(this_elem, pos, *((lFloat*)value)); } else if (type == lLongT) { cull_ret = lSetPosLong(this_elem, pos, *((lLong*)value)); } else if (type == lCharT) { cull_ret = lSetPosChar(this_elem, pos, *((lChar*)value)); } else if (type == lBoolT) { cull_ret = lSetPosBool(this_elem, pos, *((bool*)value)); } else if (type == lIntT) { cull_ret = lSetPosInt(this_elem, pos, *((int*)value)); } else if (type == lObjectT) { cull_ret = lSetPosObject(this_elem, pos, *((lListElem **)value)); } else if (type == lRefT) { cull_ret = lSetPosRef(this_elem, pos, *((lRef*)value)); } else if (type == lListT) { cull_ret = lSetPosList(this_elem, pos, lCopyList("", *((lList **)value))); } else { /* not possible */ cull_ret = -1; } DRETURN(cull_ret == 0 ? true : false); } bool object_replace_any_type(lListElem *this_elem, int name, lListElem *org_elem) { int cull_ret = 0; int out_pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); int in_pos = lGetPosViaElem(org_elem, name, SGE_NO_ABORT); int type = lGetPosType(lGetElemDescr(this_elem), out_pos); DENTER(OBJECT_LAYER, "object_replace_any_type"); if (type == lStringT) { const char *value = lGetPosString(org_elem, in_pos); cull_ret = lSetPosString(this_elem, out_pos, value); } else if (type == lHostT) { const char *value = lGetPosHost(org_elem, in_pos); cull_ret = lSetPosHost(this_elem, out_pos, value); } else if (type == lUlongT) { u_long32 value = lGetPosUlong(org_elem, in_pos); cull_ret = lSetPosUlong(this_elem, out_pos, value); } else if (type == lDoubleT) { double value = lGetPosDouble(org_elem, in_pos); cull_ret = lSetPosDouble(this_elem, out_pos, value); } else if (type == lFloatT) { float value = lGetPosFloat(org_elem, in_pos); cull_ret = lSetPosFloat(this_elem, out_pos, value); } else if (type == lLongT) { int value = lGetPosLong(org_elem, in_pos); cull_ret = lSetPosLong(this_elem, out_pos, value); } else if (type == lCharT) { char value = lGetPosChar(org_elem, in_pos); cull_ret = lSetPosChar(this_elem, out_pos, value); } else if (type == lBoolT) { bool value = lGetPosBool(org_elem, in_pos) ? true : false; cull_ret = lSetPosBool(this_elem, out_pos, value); } else if (type == lIntT) { int value = lGetPosInt(org_elem, in_pos); cull_ret = lSetPosInt(this_elem, out_pos, value); } else if (type == lObjectT) { lListElem *value = lGetPosObject(org_elem, in_pos); cull_ret = lSetPosObject(this_elem, out_pos, value); } else if (type == lRefT) { void *value = lGetPosRef(org_elem, in_pos); cull_ret = lSetPosRef(this_elem, out_pos, value); } else { /* not possible */ cull_ret = -1; } DRETURN(cull_ret == 0 ? true : false); } void object_get_any_type(lListElem *this_elem, int name, void *value) { int pos = lGetPosViaElem(this_elem, name, SGE_NO_ABORT); int type = lGetPosType(lGetElemDescr(this_elem), pos); DENTER(OBJECT_LAYER, "object_get_any_type"); if (value != NULL) { if (type == lStringT) { *((const char **)value) = lGetPosString(this_elem, pos); } else if (type == lHostT) { *((const char **)value) = lGetPosHost(this_elem, pos); } else if (type == lUlongT) { *((lUlong*)value) = lGetPosUlong(this_elem, pos); } else if (type == lDoubleT) { *((lDouble*)value) = lGetPosDouble(this_elem, pos); } else if (type == lFloatT) { *((lFloat*)value) = lGetPosFloat(this_elem, pos); } else if (type == lLongT) { *((lLong*)value) = lGetPosLong(this_elem, pos); } else if (type == lCharT) { *((lChar*)value) = lGetPosChar(this_elem, pos); } else if (type == lBoolT) { *((bool*)value) = lGetPosBool(this_elem, pos) ? true : false; } else if (type == lIntT) { *((int*)value) = lGetPosInt(this_elem, pos); } else if (type == lObjectT) { *((lListElem **)value) = lGetPosObject(this_elem, pos); } else if (type == lRefT) { *((lRef *)value) = lGetPosRef(this_elem, pos); } else if (type == lListT) { *((lList **)value) = lGetPosList(this_elem, pos); } else { DTRACE; /* not possible */ } } DRETURN_VOID; } bool object_has_differences(const lListElem *this_elem, lList **answer_list, const lListElem *old_elem, bool modify_changed_flag) { bool ret = false; DENTER(TOP_LAYER, "object_has_differences"); if (this_elem != NULL && old_elem != NULL) { lDescr *this_elem_descr = this_elem->descr; lDescr *old_elem_descr = old_elem->descr; lDescr *tmp_decr1 = NULL; lDescr *tmp_decr2 = NULL; /* * Compare each attribute of the given elements */ for (tmp_decr1 = this_elem_descr, tmp_decr2 = old_elem_descr; tmp_decr1->nm != NoName && tmp_decr2->nm != NoName; tmp_decr1++, tmp_decr2++) { int pos = tmp_decr1 - this_elem_descr; int type1 = this_elem_descr[pos].mt; int type2 = old_elem_descr[pos].mt; bool equiv = false; /* * Compare name and type */ if (tmp_decr1->nm != tmp_decr2->nm || mt_get_type(type1) != mt_get_type(type2)) { DPRINTF(("Attribute "SFQ" of type "SFQ" cannot be compared with" "attribute "SFQ" of type "SFQ".\n", lNm2Str(tmp_decr1->nm), multitypes[mt_get_type(type1)], lNm2Str(tmp_decr2->nm), multitypes[mt_get_type(type2)])); ret = true; break; } /* * Compare value of attributes */ switch (mt_get_type(type1)) { case lFloatT: equiv = (lGetPosFloat(this_elem, pos) == lGetPosFloat(old_elem, pos)) ? true : false; break; case lDoubleT: equiv = (lGetPosDouble(this_elem, pos) == lGetPosDouble(old_elem, pos)) ? true : false; break; case lUlongT: equiv = (lGetPosUlong(this_elem, pos) == lGetPosUlong(old_elem, pos)) ? true : false; break; case lLongT: equiv = (lGetPosLong(this_elem, pos) == lGetPosLong(old_elem, pos)) ? true : false; break; case lCharT: equiv = (lGetPosChar(this_elem, pos) == lGetPosChar(old_elem, pos)) ? true : false; break; case lBoolT: equiv = (lGetPosBool(this_elem, pos) == lGetPosBool(old_elem, pos)) ? true : false; break; case lIntT: equiv = (lGetPosInt(this_elem, pos) == lGetPosInt(old_elem, pos)) ? true : false; break; case lStringT: { const char *new_str = lGetPosString(this_elem, pos); const char *old_str = lGetPosString(old_elem, pos); if ((new_str == NULL && old_str != NULL) || (new_str != NULL && old_str == NULL)) { equiv = false; } else if (new_str == old_str) { equiv = true; } else { equiv = (strcmp(new_str, old_str) == 0) ? true : false; } } break; case lHostT: { const char *new_str = lGetPosHost(this_elem, pos); const char *old_str = lGetPosHost(old_elem, pos); if ((new_str == NULL && old_str != NULL) || (new_str != NULL && old_str == NULL)) { equiv = false; } else if (new_str == old_str) { equiv = true; } else { equiv = (sge_hostcmp(new_str, old_str) == 0) ? true : false; } } break; case lRefT: equiv = (lGetPosRef(this_elem, pos) == lGetPosRef(old_elem, pos)) ? true : false; break; case lObjectT: { lListElem *new_obj = lGetPosObject(this_elem, pos); lListElem *old_obj = lGetPosObject(old_elem, pos); equiv = object_has_differences(new_obj, answer_list, old_obj, modify_changed_flag)? false : true; } break; case lListT: { lList *new_list = lGetPosList(this_elem, pos); lList *old_list = lGetPosList(old_elem, pos); if (object_list_has_differences(new_list, answer_list, old_list, modify_changed_flag)) { equiv = false; } else { equiv = true; } } break; default: DTRACE; equiv = false; break; } if (!equiv) { DPRINTF(("Attributes "SFQ" of type "SFQ" are not equivalent.\n", lNm2Str(tmp_decr1->nm), multitypes[mt_get_type(type1)])); DTRACE; ret = true; } } /* * Compare number of attributes within each element */ if (tmp_decr1->nm != tmp_decr2->nm) { DPRINTF(("Descriptor size is not equivalent\n")); ret = true; } } else if (this_elem != NULL || old_elem != NULL) { /* One of both elems is not NULL */ ret = true; } DRETURN(ret); } bool object_list_has_differences(const lList *this_list, lList **answer_list, const lList *old_list, bool modify_changed_flag) { bool ret = false; DENTER(BASIS_LAYER, "object_list_has_differences"); if (this_list == NULL && old_list == NULL) { ret = false; } else if (lGetNumberOfElem(this_list) == lGetNumberOfElem(old_list)) { lListElem *new_elem; lListElem *old_elem; for(new_elem = lFirst(this_list), old_elem = lFirst(old_list); new_elem != NULL && old_elem != NULL; new_elem = lNext(new_elem), old_elem = lNext(old_elem)) { ret = object_has_differences(new_elem, answer_list, old_elem, modify_changed_flag); if (ret) { break; } } } else { DTRACE; ret = true; } DRETURN(ret); } /****** sge_object/object_list_verify_cull() *********************************** * NAME * object_list_verify_cull() -- verify cull list structure * * SYNOPSIS * bool * object_list_verify_cull(const lList *lp, const lDescr *descr) * * FUNCTION * Verifies that a cull list, including all its objects and sublists, * is a valid object of a defined type. * * There are cases, where the type of a list cannot be verified, when the * type of a sublist is set to CULL_ANY_SUBTYPE in the cull list definition. * In this case, the list descriptor is not checked, but still all list * objects and there sublists are verified. * * INPUTS * const lList *lp - list to verify * const lDescr *descr - expected descriptor (or NULL, see above) * * RESULT * bool - true, if the object is OK, else false * * NOTES * MT-NOTE: object_list_verify_cull() is MT safe * * SEE ALSO * sge_object/object_verify_cull() * cull/list/lCompListDescr() *******************************************************************************/ bool object_list_verify_cull(const lList *lp, const lDescr *descr) { bool ret = true; /* * valid input parameters? * descr may be NULL, if sublist is defined as CULL_ANY_SUBTYPE */ if (lp == NULL) { ret = false; } /* does list descriptor match expected descriptor? */ if (ret) { if (descr != NULL) { if (lCompListDescr(lp->descr, descr) != 0) { ret = false; } } } /* recursively check sublists and subobjects */ if (ret) { const lListElem *ep; for_each (ep, lp) { if (!object_verify_cull(ep, NULL)) { ret = false; break; } } } return ret; } /****** sge_object/object_verify_cull() **************************************** * NAME * object_verify_cull() -- verify cull object structure * * SYNOPSIS * bool * object_verify_cull(const lListElem *ep, const lDescr *descr) * * FUNCTION * Verifies that a cull object, including all its sublists and subobjects, * is a valid object of a defined type. * * The type (descr) argument may be zero in two cases: * - the descriptor has already been checked. This is the case when called * from object_list_verify_cull(). * - we don't know the type of a subobject (if it is defined as * CULL_ANY_SUBTYPE in the cull object definition * * INPUTS * const lListElem *ep - the object to verify * const lDescr *descr - expected object type, or NULL (see above) * * RESULT * bool - true on success, else false * * NOTES * MT-NOTE: object_verify_cull() is MT safe * * SEE ALSO * sge_object/object_verify_cull() * cull/list/lCompListDescr() *******************************************************************************/ bool object_verify_cull(const lListElem *ep, const lDescr *descr) { bool ret = true; /* * valid input parameters? * descr may be NULL, if subobject is defined as CULL_ANY_SUBTYPE */ if (ep == NULL) { ret = false; } /* does object descriptor match expected descriptor? */ if (ret) { if (descr != NULL) { if (lCompListDescr(ep->descr, descr) != 0) { ret = false; } } } /* check contents of subobject */ if (ret) { int i = 0; while (ep->descr[i].nm != NoName) { int type = mt_get_type(ep->descr[i].mt); if (type == lListT) { lList *lp = lGetList(ep, ep->descr[i].nm); if (lp != NULL) { const lDescr *subdescr = object_get_subtype(ep->descr[i].nm); if (!object_list_verify_cull(lp, subdescr)) { ret = false; break; } } } else if (type == lObjectT) { lListElem *sub_ep = lGetObject(ep, ep->descr[i].nm); if (sub_ep != NULL) { const lDescr *subdescr = object_get_subtype(ep->descr[i].nm); if (!object_verify_cull(sub_ep, subdescr)) { ret = false; break; } } } i++; } } return ret; } /****** sge_object/object_verify_ulong_not_null() ****************************** * NAME * object_verify_ulong_not_null() -- verify ulong attribute not null * * SYNOPSIS * bool * object_verify_ulong_not_null(const lListElem *ep, lList **answer_list, * int nm) * * FUNCTION * Verify that a certain ulong attribute in an object is not 0 * * INPUTS * const lListElem *ep - object to verify * lList **answer_list - answer list to pass back error messages * int nm - the attribute to verify * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: object_verify_ulong_not_null() is MT safe * * SEE ALSO * sge_object/object_verify_string_not_null() *******************************************************************************/ bool object_verify_ulong_not_null(const lListElem *ep, lList **answer_list, int nm) { bool ret = true; if (lGetUlong(ep, nm) == 0) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_ULONG_NOT_NULL, lNm2Str(nm)); ret = false; } return ret; } /****** sge_object/object_verify_ulong_null() ****************************** * NAME * object_verify_ulong_null() -- verify ulong attribute null * * SYNOPSIS * bool * object_verify_ulong_null(const lListElem *ep, lList **answer_list, * int nm) * * FUNCTION * Verify that a certain ulong attribute in an object is 0 * * INPUTS * const lListElem *ep - object to verify * lList **answer_list - answer list to pass back error messages * int nm - the attribute to verify * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: object_verify_ulong_null() is MT safe * * SEE ALSO * sge_object/object_verify_string_not_null() *******************************************************************************/ bool object_verify_ulong_null(const lListElem *ep, lList **answer_list, int nm) { bool ret = true; if (lGetUlong(ep, nm) != 0) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_ULONG_NULL, lNm2Str(nm)); ret = false; } return ret; } /****** sge_object/object_verify_ulong_null() ****************************** * NAME * object_verify_double_null() -- verify double attribute null * * SYNOPSIS * bool * object_verify_ulong_null(const lListElem *ep, lList **answer_list, * int nm) * * FUNCTION * Verify that a certain double attribute in an object is 0 * * INPUTS * const lListElem *ep - object to verify * lList **answer_list - answer list to pass back error messages * int nm - the attribute to verify * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: object_verify_double_null() is MT safe * * SEE ALSO * sge_object/object_verify_string_not_null() *******************************************************************************/ bool object_verify_double_null(const lListElem *ep, lList **answer_list, int nm) { bool ret = true; if (lGetDouble(ep, nm) != 0.0) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_DOUBLE_NULL, lNm2Str(nm)); ret = false; } return ret; } /****** sge_object/object_verify_string_not_null() ***************************** * NAME * object_verify_string_not_null() -- verify string attribute not null * * SYNOPSIS * bool * object_verify_string_not_null(const lListElem *ep, lList **answer_list, * int nm) * * FUNCTION * Verifies that a string attribute of a certain object is not NULL. * * INPUTS * const lListElem *ep - the object to verify * lList **answer_list - answer list to pass back error messages * int nm - the attribute to verify * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: object_verify_string_not_null() is MT safe * * SEE ALSO * sge_object/object_verify_ulong_not_null() *******************************************************************************/ bool object_verify_string_not_null(const lListElem *ep, lList **answer_list, int nm) { bool ret = true; if (lGetString(ep, nm) == NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_STRING_NOT_NULL, lNm2Str(nm)); ret = false; } return ret; } /****** sge_object/object_verify_expression_syntax() ***************************** * NAME * object_verify_expression_syntax() -- verify string attribute expression syntax * * SYNOPSIS * bool * object_verify_expression_syntax(const lListElem *ep, lList **answer_list) * * FUNCTION * Verifies that a string is expression in correct format. * * INPUTS * const lListElem *ep - the object to verify * lList **answer_list - answer list to pass back error messages * * RESULT * bool - true on success, * false on error with error message in answer_list * * NOTES * MT-NOTE: object_verify_expression_syntax() is MT safe * * SEE ALSO *******************************************************************************/ bool object_verify_expression_syntax(const lListElem *elem, lList **answer_list) { bool ret = true; const char *expr; lUlong type; type = lGetUlong(elem, CE_valtype); switch(type){ case TYPE_STR: case TYPE_CSTR: case TYPE_RESTR: case TYPE_HOST: expr = lGetString(elem, CE_stringval); if (sge_eval_expression(type,expr,"*",answer_list)==-1) { ret = false; } break; } return ret; } /****** sge_object/object_verify_name() ***************************************** * NAME * object_verify_name() - verifies object name * * SYNOPSIS * int object_verify_name(const lListElem *object, lList **alpp, int name, object_descr) * * FUNCTION * These checks are done for the attribute JB_object_name of 'object': * #1 reject object name if it starts with a digit * A detailed problem description is added to the answer list. * * INPUTS * const lListElem *object - JB_Type elemente * lList **alpp - the answer list * int name - object name * char *object_descr - used for the text in the answer list * * RESULT * int - returns != 0 if there is a problem with the object name * * MT-NOTE: sge_resolve_host() is MT safe * ******************************************************************************/ int object_verify_name(const lListElem *object, lList **answer_list, int name, const char *object_descr) { const char *object_name = lGetString(object, name); int ret = 0; DENTER(TOP_LAYER, "object_verify_name"); if (object_name != NULL) { if (isdigit(object_name[0])) { ERROR((SGE_EVENT, MSG_OBJECT_INVALID_NAME_S, object_name)); answer_list_add(answer_list, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); ret = STATUS_EUNKNOWN; } else { if (verify_str_key( answer_list, object_name, MAX_VERIFY_STRING, lNm2Str(name), QSUB_TABLE) != STATUS_OK) { ret = STATUS_EUNKNOWN; } } } DRETURN(ret); } /****** sge_object/object_verify_pe_range() ********************************** * NAME * object_verify_pe_range() -- Verify validness of a jobs PE range request * * SYNOPSIS * int object_verify_pe_range(lList **alpp, const char *pe_name, * lList *pe_range) * * FUNCTION * Verifies a jobs PE range is valid. Currently the following is done * - make PE range list normalized and ascending * - ensure PE range min/max not 0 * - in case multiple PEs match the PE request in GEEE ensure * the urgency slots setting is non-ambiguous * * INPUTS * lList **alpp - Returns answer list with error context. * const char *pe_name - PE request * lList *pe_range - PE range to be verified * const char *object_descr - object description for user messages * * RESULT * static int - STATUS_OK on success * * NOTES * *******************************************************************************/ int object_verify_pe_range(lList **alpp, const char *pe_name, lList *pe_range, const char *object_descr) { lListElem *relem = NULL; unsigned long pe_range_max; unsigned long pe_range_min; DENTER(TOP_LAYER, "object_verify_pe_range"); /* ensure jobs PE range list request is normalized and ascending */ range_list_sort_uniq_compress(pe_range, NULL, true); for_each(relem, pe_range) { pe_range_min = lGetUlong(relem, RN_min); pe_range_max = lGetUlong(relem, RN_max); DPRINTF(("pe max = %ld, pe min = %ld\n", pe_range_max, pe_range_min)); if ( pe_range_max == 0 || pe_range_min == 0 ) { ERROR((SGE_EVENT, MSG_OBJECT_PERANGEMUSTBEGRZERO_S, object_descr )); answer_list_add(alpp, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); DRETURN(STATUS_EUNKNOWN); } } /* PE slot ranges used in conjunction with wildcards can cause number of slots finally being used for urgency value computation be ambiguous. We reject such jobs */ if (range_list_get_number_of_ids(pe_range)>1) { lList *master_pe_list = *object_type_get_master_list(SGE_TYPE_PE); const lListElem *reference_pe = pe_list_find_matching(master_pe_list, pe_name); lListElem *pe; int nslots = pe_urgency_slots(reference_pe, lGetString(reference_pe, PE_urgency_slots), pe_range); for_each(pe, master_pe_list) { if (pe_is_matching(pe, pe_name) && nslots != pe_urgency_slots(pe, lGetString(pe, PE_urgency_slots), pe_range)) { ERROR((SGE_EVENT, MSG_OBJECT_WILD_RANGE_AMBIGUOUS_S, object_descr)); answer_list_add(alpp, SGE_EVENT, STATUS_EUNKNOWN, ANSWER_QUALITY_ERROR); DRETURN(STATUS_EUNKNOWN); } } } DRETURN(STATUS_OK); } /****** sge_objectcompress_ressources() ********************************** * NAME * compress_ressources() -- remove multiple requests for one resource * * SYNOPSIS * int compress_ressources(lList **alpp, lList *rl, const char *object_descr ) * * FUNCTION * remove multiple requests for one resource * this can't be done fully in clients without having complex definitions * -l arch=linux -l a=sun4 * * INPUTS * lList **alpp - Returns answer list with error context. * lList *rl - object description for user messages * const char *object_descr - object description * * RESULT * static int - 0 on success * * NOTES * *******************************************************************************/ int compress_ressources(lList **alpp, lList *rl, const char *object_descr) { lListElem *ep, *prev, *rm_ep; const char *attr_name; DENTER(TOP_LAYER, "compress_ressources"); for_each_rev (ep, rl) { attr_name = lGetString(ep, CE_name); /* ensure 'slots' is not requested explicitly */ if (!strcmp(attr_name, "slots")) { ERROR((SGE_EVENT, MSG_OBJECT_NODIRECTSLOTS_S, object_descr)); answer_list_add(alpp, SGE_EVENT, STATUS_EEXIST, ANSWER_QUALITY_ERROR); DRETURN(-1); } /* remove all previous requests with the same name */ prev = lPrev(ep); while ((rm_ep=prev)) { prev = lPrev(rm_ep); if (!strcmp(lGetString(rm_ep, CE_name), attr_name)) { DPRINTF(("resource request -l "SFN"="SFN" overrides previous -l "SFN"="SFN"\n", attr_name, lGetString(ep, CE_stringval), attr_name, lGetString(rm_ep, CE_stringval))); lRemoveElem(rl, &rm_ep); } } } DRETURN(0); } /****** sge_object/object_unpack_elem_verify() ********************************* * NAME * object_unpack_elem_verify() -- unpack and verify an object * * SYNOPSIS * bool * object_unpack_elem_verify(lList **answer_list, sge_pack_buffer *pb, * lListElem **epp, const lDescr *descr) * * FUNCTION * Unpacks the given packbuffer. * If unpacking was successfull, verifies the object * against the given descriptor. * * INPUTS * lList **answer_list - answer list to report errors * sge_pack_buffer *pb - the packbuffer containing the object * lListElem **epp - element pointer to pass back the unpacked object * const lDescr *descr - the expected object type * * RESULT * bool - true on success, else false * * NOTES * MT-NOTE: object_unpack_elem_verify() is MT safe * * SEE ALSO * sge_object/object_verify_cull() *******************************************************************************/ bool object_unpack_elem_verify(lList **answer_list, sge_pack_buffer *pb, lListElem **epp, const lDescr *descr) { bool ret = true; DENTER(TOP_LAYER, "object_unpack_elem_verify"); if (pb == NULL || epp == NULL || descr == NULL) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_NULLELEMENTPASSEDTO_S, "object_unpack_elem_verify"); ret = false; } if (ret) { if (cull_unpack_elem(pb, epp, NULL) != 0) { answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_COM_UNPACKOBJ_S, object_get_name(descr)); ret = false; } } if (ret) { if (!object_verify_cull(*epp, descr)) { lFreeElem(epp); answer_list_add_sprintf(answer_list, STATUS_ESYNTAX, ANSWER_QUALITY_ERROR, MSG_OBJECT_STRUCTURE_ERROR); ret = false; } } DRETURN(ret); }