/* Copyright Red Hat, Inc. 2004 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include void res_build_name(char *buf, size_t buflen, resource_t * res) { snprintf(buf, buflen, "%s:%s", res->r_rule->rr_type, res->r_attrs[0].ra_value); } /** Find and determine an attribute's value. @param res Resource node to look examine @param attrname Attribute to retrieve. @return value of attribute or NULL if not found */ char * res_attr_value(resource_t * res, const char *attrname) { resource_attr_t *ra; int x; for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) { if (strcmp(attrname, res->r_attrs[x].ra_name)) continue; ra = &res->r_attrs[x]; if (ra->ra_flags & RA_INHERIT) /* Can't check inherited resources */ return NULL; return ra->ra_value; } return NULL; } /** Find and determine an attribute's value. Takes into account inherited attribute flag, and append attribute flag, which isn't implemented yet. @param node Resource tree node to look examine @param attrname Attribute to retrieve. @param ptype Resource type to look for (if inheritance) @return value of attribute or NULL if not found */ static char * _attr_value(resource_node_t * node, const char *attrname, const char *ptype) { resource_t *res; resource_attr_t *ra; char *c, p_type[32]; ssize_t len; int x; if (!node) return NULL; res = node->rn_resource; /* Go up the tree if it's not the right parent type */ if (ptype && strcmp(res->r_rule->rr_type, ptype)) return _attr_value(node->rn_parent, attrname, ptype); for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) { if (strcmp(attrname, res->r_attrs[x].ra_name)) continue; ra = &res->r_attrs[x]; if (!(ra->ra_flags & RA_INHERIT)) return ra->ra_value; /* Handle resource_type%field to be more precise, so we don't have to worry about this being a child of an unexpected type. E.g. lots of things have the "name" attribute. */ c = strchr(ra->ra_value, '%'); if (!c) { /* Someone doesn't care or uses older semantics on inheritance */ return _attr_value(node->rn_parent, ra->ra_value, NULL); } len = (c - ra->ra_value); memset(p_type, 0, sizeof(p_type)); memcpy(p_type, ra->ra_value, len); /* Skip the "%" and recurse */ return _attr_value(node->rn_parent, ++c, p_type); } return NULL; } char * attr_value(resource_node_t * node, const char *attrname) { return _attr_value(node, attrname, NULL); } char * primary_attr_value(resource_t * res) { int x; resource_attr_t *ra; for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) { ra = &res->r_attrs[x]; if (!(ra->ra_flags & RA_PRIMARY)) continue; return ra->ra_value; } return NULL; } /** Find a resource given its reference. A reference is the value of the primary attribute. @param reslist List of resources to traverse. @param type Type of resource to look for. @param ref Reference @return Resource matching type/ref or NULL if none. */ resource_t * find_resource_by_ref(resource_t ** reslist, char *type, char *ref) { resource_t *curr; int x; list_do(reslist, curr) { if (strcmp(curr->r_rule->rr_type, type)) continue; /* This should be one operation - the primary attr is generally at the head of the array. */ for (x = 0; curr->r_attrs && curr->r_attrs[x].ra_name; x++) { if (!(curr->r_attrs[x].ra_flags & RA_PRIMARY)) continue; if (strcmp(ref, curr->r_attrs[x].ra_value)) continue; return curr; } } while (!list_done(reslist, curr)) ; return NULL; } /** Store a resource in the resource list if it's legal to do so. Otherwise, don't store it. Note: This function needs to be rewritten; it's way too long and way too indented. @param reslist Resource list to store the new resource. @param newres Resource to store @return 0 on succes; nonzero on failure. */ int store_resource(resource_t ** reslist, resource_t * newres) { resource_t *curr; int x, y; if (!*reslist) { /* first resource */ list_insert(reslist, newres); return 0; } list_do(reslist, curr) { if (strcmp(curr->r_rule->rr_type, newres->r_rule->rr_type)) continue; for (x = 0; newres->r_attrs && newres->r_attrs[x].ra_name; x++) { /* Look for conflicting primary/unique keys */ if (!(newres->r_attrs[x].ra_flags & (RA_PRIMARY | RA_UNIQUE))) continue; for (y = 0; curr->r_attrs[y].ra_name; y++) { if (curr->r_attrs[y].ra_flags & RA_INHERIT) continue; if (strcmp(curr->r_attrs[y].ra_name, newres->r_attrs[x].ra_name)) continue; if (!strcmp(curr->r_attrs[y].ra_value, newres->r_attrs[x].ra_value)) { /* Unique/primary is not unique */ fprintf(stderr, "%s attribute collision. " "type=%s attr=%s value=%s\n", (newres->r_attrs[x].ra_flags & RA_PRIMARY) ? "Primary" : "Unique", newres->r_rule->rr_type, newres->r_attrs[x].ra_name, newres->r_attrs[x].ra_value); return -1; } break; } } } while (!list_done(reslist, curr)) ; list_insert(reslist, newres); return 0; } /** Obliterate a resource_t structure. @param res Resource to free. */ void destroy_resource(resource_t * res) { int x; if (res->r_name) free(res->r_name); if (res->r_attrs) { for (x = 0; res->r_attrs && res->r_attrs[x].ra_name; x++) { free(res->r_attrs[x].ra_name); free(res->r_attrs[x].ra_value); } free(res->r_attrs); } if (res->r_actions) { /* Don't free the strings; they're part of the rule */ free(res->r_actions); } free(res); } /** Obliterate a resource_t list. @param list Resource list to free. */ void destroy_resources(resource_t ** list) { resource_t *res; while ((res = *list)) { list_remove(list, res); destroy_resource(res); } } void * act_dup(resource_act_t * acts) { int x; resource_act_t *newacts; for (x = 0; acts[x].ra_name; x++) ; ++x; x *= sizeof(resource_act_t); newacts = malloc(x); if (!newacts) return NULL; memcpy(newacts, acts, x); return newacts; } /* Copied from resrules.c -- _get_actions */ static void _get_actions_ccs(const char *base, resource_t * res) { char xpath[256]; int idx = 0; char *act, *ret; int interval, timeout, depth; do { /* setting these to -1 prevents overwriting with 0 */ interval = -1; depth = -1; act = NULL; timeout = -1; snprintf(xpath, sizeof(xpath), "%s/action[%d]/@name", base, ++idx); if (conf_get(xpath, &act) != 0) break; snprintf(xpath, sizeof(xpath), "%s/action[%d]/@timeout", base, idx); if (conf_get(xpath, &ret) == 0 && ret) { timeout = expand_time(ret); if (timeout < 0) timeout = 0; free(ret); } snprintf(xpath, sizeof(xpath), "%s/action[%d]/@interval", base, idx); if (conf_get(xpath, &ret) == 0 && ret) { interval = expand_time(ret); if (interval < 0) interval = 0; free(ret); } if (!strcmp(act, "status") || !strcmp(act, "monitor")) { snprintf(xpath, sizeof(xpath), "%s/action[%d]/@depth", base, idx); if (conf_get(xpath, &ret) == 0 && ret) { depth = atoi(ret); if (depth < 0) depth = 0; /* */ if (ret[0] == '*') depth = -1; free(ret); } } if (store_action(&res->r_actions, act, depth, timeout, interval) != 0) free(act); } while (1); } /** Try to load all the attributes in our rule set. If none are found, or an error occurs, return NULL and move on to the next one. @param rule Resource rule set to use when looking for data @param base Base XPath path to start with. @return New resource if legal or NULL on failure/error */ resource_t * load_resource(resource_rule_t * rule, const char *base) { resource_t *res; char ccspath[1024]; char *attrname, *attr; int x, found = 0, flags; res = malloc(sizeof(*res)); if (!res) { fprintf(stderr, "Out of memory\n"); return NULL; } memset(res, 0, sizeof(*res)); res->r_rule = rule; for (x = 0; res->r_rule->rr_attrs && res->r_rule->rr_attrs[x].ra_name; x++) { flags = rule->rr_attrs[x].ra_flags; attrname = strdup(rule->rr_attrs[x].ra_name); if (!attrname) { destroy_resource(res); return NULL; } /* Ask CCS for the respective attribute */ attr = NULL; snprintf(ccspath, sizeof(ccspath), "%s/@%s", base, attrname); if (conf_get(ccspath, &attr) != 0) { if (flags & (RA_REQUIRED | RA_PRIMARY)) { /* Missing required attribute. We're done. */ free(attrname); destroy_resource(res); return NULL; } if (!(flags & RA_INHERIT)) { /* If we don't have the inherit flag, see if we have a value anyway. If we do, this value is the default value, and should be used. */ if (!rule->rr_attrs[x].ra_value) { free(attrname); continue; } /* Copy default value from resource rule */ attr = strdup(rule->rr_attrs[x].ra_value); } } found = 1; /* If we are supposed to inherit and we don't have an instance of the specified attribute in CCS, then we keep the inherit flag and use it as the attribute. However, if we _do_ have the attribute for this instance, we drop the inherit flag and use the attribute. */ if (flags & RA_INHERIT) { if (attr) { flags &= ~RA_INHERIT; } else { attr = strdup(rule->rr_attrs[x].ra_value); if (!attr) { destroy_resource(res); free(attrname); return NULL; } } } /* Store the attribute. We'll ensure all required attributes are present soon. */ if (attrname && attr) store_attribute(&res->r_attrs, attrname, attr, flags); } if (!found) { destroy_resource(res); return NULL; } res->r_actions = act_dup(rule->rr_actions); _get_actions_ccs(base, res); return res; } /** Read all resources in the resource manager block in CCS. @param reslist Empty list to fill with resources. @param rulelist List of rules to use when searching CCS. @return 0 on success, nonzero on failure. */ int load_resources(resource_t ** reslist, resource_rule_t ** rulelist) { int resID = 0; resource_t *newres; resource_rule_t *currule; char tok[256]; list_do(rulelist, currule) { for (resID = 1;; resID++) { snprintf(tok, sizeof(tok), RESOURCE_BASE "/%s[%d]", currule->rr_type, resID); newres = load_resource(currule, tok); if (!newres) break; if (store_resource(reslist, newres) != 0) { fprintf(stderr, "Error storing %s resource\n", newres->r_rule->rr_type); destroy_resource(newres); } /* Just information */ newres->r_flags = RF_DEFINED; } } while (!list_done(rulelist, currule)) ; return 0; }