Esempio n. 1
0
File: spec.c Progetto: goodwinos/pcp
/*
 * Parse the attributes component of a PCP connection string.
 * Optionally, an initial attribute:value pair can be passed
 * in as well to add to the parsed set.
 */
static int
parseAttributeSpec(
    const char *spec,           /* the original, complete string to parse */
    char **position,            /* parse from here onward and update at end */
    int attribute,
    char *value,
    __pmHashCtl *attributes,
    char **errmsg)
{
    char *s, *start, *v = NULL;
    char buffer[32];	/* must be large enough to hold largest attr name */
    int buflen, attr, len, sts;

    if (attribute != PCP_ATTR_NONE)
	if ((sts = __pmHashAdd(attribute, (void *)value, attributes)) < 0)
	    return sts;

    for (s = start = *position; s != NULL; s++) {
	/* parse: foo=bar&moo&goo=blah ... go! */
	if (*s == '\0' || *s == '/' || *s == '&') {
	    if ((*s == '\0' || *s == '/') && s == start)
		break;
	    len = v ? (v - start - 1) : (s - start);
	    buflen = (len < sizeof(buffer)-1) ? len : sizeof(buffer)-1;
	    strncpy(buffer, start, buflen);
	    buffer[buflen] = '\0';
	    attr = __pmLookupAttrKey(buffer, buflen+1);
	    if (attr != PCP_ATTR_NONE) {
		char *val = NULL;

		if (v && (val = strndup(v, s - v)) == NULL) {
		    sts = -ENOMEM;
		    goto fail;
		}
		if ((sts = __pmHashAdd(attr, (void *)val, attributes)) < 0) {
		    free(val);
		    goto fail;
		}
	    }
	    v = NULL;
	    if (*s == '\0' || *s == '/')
		break;
	    start = s + 1;	/* start of attribute name */
	    continue;
	}
	if (*s == '=') {
	   v = s + 1;	/* start of attribute value */
	}
    }

    *position = s;
    return 0;

fail:
    if (attribute != PCP_ATTR_NONE)	/* avoid double free in caller */
	__pmHashDel(attribute, (void *)value, attributes);
    __pmFreeAttrsSpec(attributes);
    return sts;
}
Esempio n. 2
0
File: dopdu.c Progetto: aeppert/pcp
/* Delete every instance of a given metric from the data structure.
 * The pmid is deleted from the pmidlist of every task containing an instance.
 * Return a pointer to the first pmDesc found (the only thing salvaged from the
 * smoking ruins), or nil if no instances were found.
 */
static pmDesc *
del_insts(pmID pmid)
{
    optreq_t	*rqp;
    __pmHashNode	*hp;
    task_t	*tp;
    pmDesc	*dp = NULL;
    int		i, sts, keep;

    for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; ) {
	/* Do that BEFORE we nuke the node */
    	__pmHashNode * nextnode = hp->next;

	if (pmid == (pmID)hp->key) {
	    rqp = (optreq_t *)hp->data;
	    tp = (task_t *)rqp->r_fetch->f_aux;
	    if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0)
		die("del_insts: __pmOptFetchDel", sts);
	    if ((sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0)
		die("del_insts: __pmHashDel", sts);

	    /* save the first pmDesc pointer for return and subsequent
	     *  re-use, but free all the others
	     */
	    if (dp != NULL)
		free(rqp->r_desc);
	    else
		dp = rqp->r_desc;

	    if (rqp->r_numinst)
		free(rqp->r_instlist);
	    free(rqp);

	    /* remove pmid from the task's pmid list */
	    for (i = 0; i < tp->t_numpmid; i++)
		if (tp->t_pmidlist[i] == pmid)
		    break;
	    keep = (tp->t_numpmid - 1 - i) * sizeof(tp->t_pmidlist[0]);
	    if (keep) {
		memmove(&tp->t_pmidlist[i], &tp->t_pmidlist[i+1], keep);
		memmove(&tp->t_desclist[i], &tp->t_desclist[i+1], keep);
		memmove(&tp->t_namelist[i], &tp->t_namelist[i+1], keep);
	    }

	    /* don't bother shrinking the pmidlist */
	    tp->t_numpmid--;
	    if (tp->t_numpmid == 0) {
		/* TODO: nuke the task if that was the last pmID */
	    }
	}
	hp = nextnode;
    }

    return dp;
}
Esempio n. 3
0
File: check.c Progetto: jujis008/pcp
static void
undo(task_t *tp, optreq_t *rqp, int inst)
{
    int 	j;
    int		k;
    int		sts;

    if (rqp->r_numinst >= 1) {
	/* remove instance from list of instance */
	for (k =0, j = 0; j < rqp->r_numinst; j++) {
	    if (rqp->r_instlist[j] != inst)
		rqp->r_instlist[k++] = rqp->r_instlist[j];
	}
	rqp->r_numinst = k;
	if ((sts =  __pmOptFetchDel(&tp->t_fetch, rqp)) < 0)
	    die("undo: __pmOptFetchDel", sts);

	if (rqp->r_numinst == 0) {
	    /* no more instances, remove specification */
	    if (tp->t_fetch == NULL) {
		/* no more specifications, remove task */
		task_t	*xtp;
		task_t	*ltp = NULL;
		for (xtp = tasklist; xtp != NULL; xtp = xtp->t_next) {
		    if (xtp == tp) {
			if (ltp == NULL)
			    tasklist = tp->t_next;
			else
			    ltp->t_next = tp->t_next;
			break;
		    }
		    ltp = xtp;
		}
	    }
	    __pmHashDel(rqp->r_desc->pmid, (void *)rqp, &pm_hash);
	    free(rqp);
	}
	else
	    /* re-insert modified specification */
	    __pmOptFetchAdd(&tp->t_fetch, rqp);
    }
    else {
	/*
	 * TODO ... current specification is for all instances,
	 * need to remove this instance from the set ...
	 * this requires some enhancement to optFetch
	 *
	 * pro tem, this metric-instance pair may continue to get
	 * logged, even though the logging state is recorded as
	 * OFF (this is the worst thing that can happen here)
	 */
    }
}
Esempio n. 4
0
File: dopdu.c Progetto: aeppert/pcp
/* Delete an optreq_t from its task, free it and remove it from the hash list.
 */
static void
del_optreq(optreq_t *rqp)
{
    int		sts;
    task_t	*tp = (task_t *)rqp->r_fetch->f_aux;

    if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0)
	die("del_optreq: __pmOptFetchDel", sts);
    if ((sts = __pmHashDel(rqp->r_desc->pmid, (void *)rqp, &pm_hash)) < 0)
	die("del_optreq: __pmHashDel", sts);
    free(rqp->r_desc);
    if (rqp->r_numinst)
	free(rqp->r_instlist);
    free(rqp);
    /* TODO: remove pmid from task if that was the last optreq_t for it */
    /* TODO: remove task if last pmid removed */
}
Esempio n. 5
0
File: dopdu.c Progetto: aeppert/pcp
/* Update an existing metric (given a pmValueSet) adding it to the specified
 * task. Allocate and return a new task_t if the specified task pointer is nil.
 */
static int
update_metric(pmValueSet *vsp, int reqstate, int mflags, task_t **result)
{
    pmID	pmid = vsp->pmid;
    task_t	*ntp = *result;		/* pointer to new task */
    task_t	*ctp;			/* pointer to current task */
    optreq_t	*rqp;
    pmDesc	*dp;
    int		i, j, inst;
    int		sts, need = 0;
    int		addpmid = 0;
    int		freedp;

    /* allocate a new task if null task pointer passed in */
    if (ntp == NULL) {
	ntp = calloc(1, sizeof(task_t));
	if (ntp == NULL) {
	    __pmNoMem("update_metric: new task calloc", sizeof(task_t),
		     PM_FATAL_ERR);
	}
	*result = ntp;
    }

    if ((mflags & MF_HAS_INDOM) == 0) {
	rqp = findoptreq(pmid, 0);
	ctp = (task_t *)(rqp->r_fetch->f_aux);
	if (!update_ok(ctp->t_state, reqstate))
	    return 1;

	/* if the new state is advisory off, just remove the metric */
	if ((PMLC_GET_MAYBE(reqstate)) ||
	    (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0))
	    del_optreq(rqp);
	else {
	    /* update the optreq.  For single valued metrics there are no
	     * instances involved so the sole optreq can just be re-used.
	     */
	    if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0)
		die("update_metric: 1 metric __pmOptFetchDel", sts);
	    __pmOptFetchAdd(&ntp->t_fetch, rqp);
	    linkback(ntp);
	    addpmid = 1;
	}
    }
    else {
	/* metric has an instance domain */
	if (vsp->numval > 0) {
	    /* tricky: since optFetch can't handle instance profiles of the
	     * form "all except these specific instances", and managing it
	     * manually is just too hard, reject requests for specific
	     * metric instances if "all instances" of the metric are already
	     * being logged.
	     * Note: advisory off "all instances" is excepted since ANY request
	     * overrides and advisory off.  E.g. "advisory off all" followed by
	     * "advisory on someinsts" turns on advisory logging for
	     * "someinsts".  mflags will be zero for "advisory off" metrics.
	     */
	    if (mflags & MF_HAS_ALL)
		return 1;		/* can't turn "all" into specific insts */

	    for (i = 0; i < vsp->numval; i++) {
		dp = NULL;
		freedp = 0;
		inst = vsp->vlist[i].inst;
		rqp = findoptreq(pmid, inst);
		if (rqp != NULL) {
		    dp = rqp->r_desc;
		    ctp = (task_t *)(rqp->r_fetch->f_aux);
		    /* no work required if new task and current are the same */
		    if (ntp == ctp)
			continue;
		    if (!update_ok(ctp->t_state, reqstate))
			continue;

		    /* remove inst's group from current task */
		    if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0)
			die("update_metric: instance add __pmOptFetchDel", sts);

		    /* put group back if there are any instances left */
		    if (rqp->r_numinst > 1) {
			/* remove inst from group */
			for (j = 0; j < rqp->r_numinst; j++)
			    if (inst == rqp->r_instlist[j])
				break;
			/* don't call memmove to move zero bytes */
			if (j < rqp->r_numinst - 1)
			    memmove(&rqp->r_instlist[j], &rqp->r_instlist[j+1],
				    (rqp->r_numinst - 1 - j) *
				    sizeof(rqp->r_instlist[0]));
			rqp->r_numinst--;
			/* (don't bother realloc-ing the instlist to a smaller size) */

			__pmOptFetchAdd(&ctp->t_fetch, rqp);
			linkback(ctp);
			/* no need to update hash list, rqp already there */
		    }
		    /* if that was the last instance, free the group */
		    else {
			if (( sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0)
			    die("update_metric: instance __pmHashDel", sts);
			freedp = 1;
			free(rqp->r_instlist);
			free(rqp);
		    }
		}

		/* advisory off (mandatory maybe) metrics don't get put into
		 * the data structure
		 */
		if (PMLC_GET_MAYBE(reqstate) ||
		    (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) {
		    if (freedp)
			free(dp);
		    continue;
		}
		addpmid = 1;

		/* try to find an existing optreq_t for the instance */
		rqp = find_instoptreq(ntp, pmid);
		if (rqp != NULL) {
		    if ((sts = __pmOptFetchDel(&ntp->t_fetch, rqp)) < 0)
			die("update_metric: instance add __pmOptFetchDel", sts);
		}
		/* no existing optreq_t found, allocate & populate a new one */
		else {
		    rqp = (optreq_t *)calloc(1, sizeof(optreq_t));
		    if (rqp == NULL) {
			__pmNoMem("update_metric: optreq calloc",
				 sizeof(optreq_t), PM_FATAL_ERR);
		    }
		    /* if the metric existed but the instance didn't, we don't
		     * have a valid pmDesc (dp), so find one.
		     */
		    if (dp == NULL)  {
			/* find metric and associated pmDesc */
			__pmHashNode	*hp;

			for (hp = __pmHashSearch(pmid, &pm_hash);
			     hp != NULL; hp = hp->next) {
			    if (pmid == (pmID)hp->key)
				break;
			}
			assert(hp != NULL);
			dp = ((optreq_t *)hp->data)->r_desc;
		    }
		    /* recycle pmDesc from the old group, if possible */
		    if (freedp) {
			rqp->r_desc = dp;
			freedp = 0;
		    }
		    /* otherwise allocate & copy a new pmDesc via dp */
		    else {
			need = sizeof(pmDesc);
			rqp->r_desc = (pmDesc *)malloc(need);
			if (rqp->r_desc == NULL) {
			    __pmNoMem("update_metric: new inst pmDesc malloc",
				     need, PM_FATAL_ERR);
			}
			memcpy(rqp->r_desc, dp, need);
		    }
		    if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0)
			die("update_metric: __pmHashAdd", sts);
		}
		    
		need = (rqp->r_numinst + 1) * sizeof(rqp->r_instlist[0]);
		rqp->r_instlist = (int *)realloc(rqp->r_instlist, need);
		if (rqp->r_instlist == NULL) {
		    __pmNoMem("update_metric: inst list resize", need,
			     PM_FATAL_ERR);
		}
		rqp->r_instlist[rqp->r_numinst++] = inst;
		__pmOptFetchAdd(&ntp->t_fetch, rqp);
		linkback(ntp);
		if (freedp)
		    free(dp);
	    }
	}
	/* the vset has numval == 0, a request for "all instances" */
	else {
	    /* if the metric is a singular instance that has mandatory logging
	     * or has at least one instance with mandatory logging on, a
	     * request for advisory logging cannot be honoured
	     */
	    if ((mflags & MF_HAS_MAND) &&
		PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_MAYBE(reqstate) == 0)
		return 1;

	    if (mflags & MF_HAS_ALL) {
		/* if there is an "all instances" for the metric, it will be
		 * the only optreq_t for the metric
		 */
		rqp = findoptreq(pmid, 0);
		ctp = (task_t *)rqp->r_fetch->f_aux;

		/* if the metric is "advisory on, all instances"  and the
		 * request is for "mandatory maybe, all instances" the current
		 * advisory logging state of the metric is retained
		 */
		if (PMLC_GET_MAND(ctp->t_state) == 0 && PMLC_GET_MAYBE(reqstate))
		    return 0;

		/* advisory off & mandatory maybe metrics don't get put into
		 * the data structure
		 */
		if (PMLC_GET_MAYBE(reqstate) ||
		    (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) {
		    del_optreq(rqp);
		    return 0;
		}

		addpmid = 1;
		if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0)
		    die("update_metric: all inst __pmOptFetchDel", sts);
		/* don't delete from hash list, rqp re-used */
		__pmOptFetchAdd(&ntp->t_fetch, rqp);
		linkback(ntp);
	    }
	    else {
		/* there are one or more specific instances for the metric.
		 * The metric cannot have an "all instances" at the same time.
		 *
		 * if the request is for "mandatory maybe, all instances" and
		 * the only instances of the metric all have advisory logging
		 * on, retain the current advisory semantics.
		 */
		if (PMLC_GET_MAYBE(reqstate) &&
		    (mflags & MF_HAS_INST) && !(mflags & MF_HAS_MAND))
		    return 0;

		dp = del_insts(pmid);

		/* advisory off (mandatory maybe) metrics don't get put into
		 * the data structure
		 */
		if (PMLC_GET_MAYBE(reqstate) ||
		    (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) {
		    free(dp);
		    return 0;
		}

		addpmid = 1;
		rqp = (optreq_t *)calloc(1, sizeof(optreq_t));
		if (rqp == NULL) {
		    __pmNoMem("update_metric: all inst calloc",
			     sizeof(optreq_t), PM_FATAL_ERR);
		}
		rqp->r_desc = dp;
		__pmOptFetchAdd(&ntp->t_fetch, rqp);
		linkback(ntp);
		if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0)
		    die("update_metric: all inst __pmHashAdd", sts);
	    }
	}
    }

    if (!addpmid)
	return 0;

    /* add pmid to new task if not already there */
    for (i = 0; i < ntp->t_numpmid; i++)
	if (pmid == ntp->t_pmidlist[i])
	    break;
    if (i >= ntp->t_numpmid) {
	pmDesc	desc;
	char	*name;
	int	need;

	if ((sts = pmLookupDesc(pmid, &desc)) < 0)
	    die("update_metric: cannot lookup desc", sts);
	if ((sts = pmNameID(pmid, &name)) < 0)
	    die("update_metric: cannot lookup name", sts);

	need = (ntp->t_numpmid + 1) * sizeof(pmID);
	if (!(ntp->t_pmidlist = (pmID *)realloc(ntp->t_pmidlist, need)))
	    __pmNoMem("update_metric: grow task pmidlist", need, PM_FATAL_ERR);
	need = (ntp->t_numpmid + 1) * sizeof(char *);
	if (!(ntp->t_namelist = (char **)realloc(ntp->t_namelist, need)))
	    __pmNoMem("update_metric: grow task namelist", need, PM_FATAL_ERR);
	need = (ntp->t_numpmid + 1) * sizeof(pmDesc);
	if (!(ntp->t_desclist = (pmDesc *)realloc(ntp->t_desclist, need)))
	    __pmNoMem("update_metric: grow task desclist", need, PM_FATAL_ERR);
	i = ntp->t_numpmid;
	ntp->t_pmidlist[i] = pmid;
	ntp->t_namelist[i] = name;
	ntp->t_desclist[i] = desc;
	ntp->t_numpmid++;
    }
    return 0;
}