예제 #1
0
static int
ping_pmcd(int ctx)
{
    /*
     * We're going to leveraging an existing host context, just make sure
     * pmcd is still alive at the other end ... we don't have a "ping"
     * pdu, but sending a pmDesc request for PM_ID_NULL is pretty much
     * the same thing ... expect a PM_ERR_PMID error PDU back.
     * The code here is based on pmLookupDesc() with some short cuts
     * because we know it is a host context and we already hold the
     * __pmLock_libpcp lock
     */
    __pmContext	*ctxp = contexts[ctx];
    int		sts;

    PM_LOCK(ctxp->c_pmcd->pc_lock);
    if ((sts = __pmSendDescReq(ctxp->c_pmcd->pc_fd, ctx, PM_ID_NULL)) >= 0) {
	int	pinpdu;
	__pmPDU	*pb;
	pinpdu = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE,
				    ctxp->c_pmcd->pc_tout_sec, &pb);
	if (pinpdu == PDU_ERROR)
	    __pmDecodeError(pb, &sts);
	if (pinpdu > 0)
	    __pmUnpinPDUBuf(pb);
    }
    PM_UNLOCK(ctxp->c_pmcd->pc_lock);

    if (sts != PM_ERR_PMID) {
	/* pmcd is not well on this context ... */
	return 0;
    }
    return 1;
}
예제 #2
0
파일: p_label.c 프로젝트: goodwinos/pcp
int
__pmRecvLabel(int fd, __pmContext *ctxp, int timeout,
	 	int *ident, int *type, pmLabelSet **sets, int *nsets)
{
    __pmPDU	*pb;
    int		oident = *ident;
    int		otype = *type;
    int		pinpdu;
    int		sts;

    sts = pinpdu = __pmGetPDU(fd, ANY_SIZE, timeout, &pb);
    if (sts == PDU_LABEL) {
	sts = __pmDecodeLabel(pb, ident, type, sets, nsets);
	if (sts >= 0) {
	    /* verify response is for a matching request */
	    if (oident != *ident || otype != *type)
		sts = PM_ERR_IPC;
	}
    }
    else if (sts == PDU_ERROR)
	__pmDecodeError(pb, &sts);
    else if (sts != PM_ERR_TIMEOUT)
	sts = PM_ERR_IPC;

    if (pinpdu > 0)
	__pmUnpinPDUBuf(pb);

    return sts;
}
예제 #3
0
파일: p_creds.c 프로젝트: goodwinos/pcp
int
__pmSendCreds(int fd, int from, int credcount, const __pmCred *credlist)
{
    size_t	need;
    creds_t	*pp;
    int		i;
    int		sts;

    if (credcount <= 0 || credcount > LIMIT_CREDS || credlist == NULL)
	return PM_ERR_IPC;

    need = sizeof(creds_t) + ((credcount-1) * sizeof(__pmCred));
    if ((pp = (creds_t *)__pmFindPDUBuf((int)need)) == NULL)
	return -oserror();
    pp->hdr.len = (int)need;
    pp->hdr.type = PDU_CREDS;
    pp->hdr.from = from;
    pp->numcreds = htonl(credcount);
    if (pmDebugOptions.context)
	for (i = 0; i < credcount; i++)
	    fprintf(stderr, "__pmSendCreds: #%d = %x\n", i, *(unsigned int*)&(credlist[i]));
    /* swab and fix bitfield order */
    for (i = 0; i < credcount; i++)
	pp->credlist[i] = __htonpmCred(credlist[i]);

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #4
0
파일: p_label.c 프로젝트: goodwinos/pcp
int
__pmSendLabelReq(int fd, int from, int ident, int type)
{
    label_req_t	*pp;
    int		sts;
    int		nid;

    if (type & PM_LABEL_CONTEXT)
	nid = htonl(PM_ID_NULL);
    else if (type & PM_LABEL_DOMAIN)
	nid = htonl(ident);
    else if (type & PM_LABEL_INDOM)
	nid = __htonpmInDom((pmInDom)ident);
    else if (type & (PM_LABEL_CLUSTER|PM_LABEL_ITEM|PM_LABEL_INSTANCES))
	nid = __htonpmID((pmID)ident);
    else
	return -EINVAL;

    if ((pp = (label_req_t *)__pmFindPDUBuf(sizeof(label_req_t))) == NULL)
	return -oserror();
    pp->hdr.len = sizeof(label_req_t);
    pp->hdr.type = PDU_LABEL_REQ;
    pp->hdr.from = from;
    pp->ident = nid;
    pp->type = htonl(type);

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #5
0
파일: dopdu.c 프로젝트: aeppert/pcp
/*
 * Service a request from the pmlogger client.
 * Return non-zero if the client has closed the connection.
 */
int
client_req(void)
{
    int		sts;
    __pmPDU	*pb;
    __pmPDUHdr	*php;
    int		pinpdu;

    if ((pinpdu = sts = __pmGetPDU(clientfd, ANY_SIZE, TIMEOUT_DEFAULT, &pb)) <= 0) {
	if (sts != 0)
	    fprintf(stderr, "client_req: %s\n", pmErrStr(sts));
	return 1;
    }
    if (qa_case == QA_SLEEPY) {
	/* error injection - delay before processing and responding */
	sleep(5);
    }
    php = (__pmPDUHdr *)pb;
    sts = 0;

    switch (php->type) {
	case PDU_CREDS:		/* version 2 PDU */
	    sts = do_creds(pb);
	    break;
	case PDU_LOG_REQUEST:	/* version 2 PDU */
	    sts = do_request(pb);
	    break;
	case PDU_LOG_CONTROL:	/* version 2 PDU */
	    sts = do_control(pb);
	    break;
	default:		/*  unknown PDU  */
	    fprintf(stderr, "client_req: bad PDU type 0x%x\n", php->type);
	    sts = PM_ERR_IPC;
	    break;
    }
    if (pinpdu > 0)
	__pmUnpinPDUBuf(pb);
    
    if (sts >= 0)
	return 0;
    else {
	/* the client isn't playing by the rules */
	__pmSendError(clientfd, FROM_ANON, sts);
	return 1;
    }
}
예제 #6
0
파일: p_instance.c 프로젝트: ColeJackes/pcp
int
__pmSendInstanceReq(int fd, int from, const __pmTimeval *when, pmInDom indom, 
		    int inst, const char *name)
{
    instance_req_t	*pp;
    int			need;
    int			sts;

    need = sizeof(instance_req_t) - sizeof(int);
    if (name != NULL)
	need += PM_PDU_SIZE_BYTES(strlen(name));
    if ((pp = (instance_req_t *)__pmFindPDUBuf(need)) == NULL)
	return -oserror();
    pp->hdr.len = need;
    pp->hdr.type = PDU_INSTANCE_REQ;
    pp->hdr.from = from;
    pp->when.tv_sec = htonl((__int32_t)when->tv_sec);
    pp->when.tv_usec = htonl((__int32_t)when->tv_usec);
    pp->indom = __htonpmInDom(indom);
    pp->inst = htonl(inst);
    if (name == NULL)
	pp->namelen = 0;
    else {
	pp->namelen = (int)strlen(name);
	memcpy((void *)pp->name, (void *)name, pp->namelen);
	if ((pp->namelen % sizeof(__pmPDU)) != 0) {
            /* clear the padding bytes, lest they contain garbage */
	    int	pad;
	    char	*padp = pp->name + pp->namelen;

	    for (pad = sizeof(__pmPDU) - 1; pad >= (pp->namelen % sizeof(__pmPDU)); pad--)
		*padp++ = '~';	/* buffer end */
	}
	pp->namelen = htonl(pp->namelen);
    }

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #7
0
파일: p_attr.c 프로젝트: ColeJackes/pcp
int
__pmSendAttr(int fd, int from, int attr, const char *value, int length)
{
    size_t	need;
    attr_t	*pp;
    int		i;
    int		sts;

    if (length < 0 || length >= LIMIT_ATTR_PDU)
	return PM_ERR_IPC;

    need = (sizeof(*pp) - sizeof(pp->value)) + length;
    if ((pp = (attr_t *)__pmFindPDUBuf((int)need)) == NULL)
	return -oserror();
    pp->hdr.len = (int)need;
    pp->hdr.type = PDU_ATTR;
    pp->hdr.from = from;
    pp->attr = htonl(attr);
    memcpy(&pp->value, value, length);

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_ATTR) {
	char buffer[LIMIT_ATTR_PDU];
	for (i = 0; i < length; i++)
	    buffer[i] = isprint((int)value[i]) ? value[i] : '.';
	buffer[length] = buffer[LIMIT_ATTR_PDU-1] = '\0';
	if (attr)
	    fprintf(stderr, "__pmSendAttr [len=%d]: attr=0x%x value=\"%s\"\n",
			    length, attr, buffer);
	else
	    fprintf(stderr, "__pmSendAttr [len=%d]: payload=\"%s\"\n",
			    length, buffer);
    }
#endif

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #8
0
파일: p_desc.c 프로젝트: goodwinos/pcp
int
__pmSendDesc(int fd, int ctx, pmDesc *desc)
{
    desc_t	*pp;
    int		sts;

    if ((pp = (desc_t *)__pmFindPDUBuf(sizeof(desc_t))) == NULL)
	return -oserror();

    pp->hdr.len = sizeof(desc_t);
    pp->hdr.type = PDU_DESC;
    pp->hdr.from = ctx;
    pp->desc.type = htonl(desc->type);
    pp->desc.sem = htonl(desc->sem);
    pp->desc.indom = __htonpmInDom(desc->indom);
    pp->desc.units = __htonpmUnits(desc->units);
    pp->desc.pmid = __htonpmID(desc->pmid);

    sts =__pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #9
0
파일: p_text.c 프로젝트: goodwinos/pcp
int
__pmSendTextReq(int fd, int from, int ident, int type)
{
    text_req_t	*pp;
    int		sts;

    if ((pp = (text_req_t *)__pmFindPDUBuf(sizeof(text_req_t))) == NULL)
	return -oserror();
    pp->hdr.len = sizeof(text_req_t);
    pp->hdr.type = PDU_TEXT_REQ;
    pp->hdr.from = from;

    if (type & PM_TEXT_PMID)
	pp->ident = __htonpmID((pmID)ident);
    else /* (type & PM_TEXT_INDOM) */
	pp->ident = __htonpmInDom((pmInDom)ident);

    type &= ~PM_TEXT_DIRECT;
    pp->type = htonl(type);

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #10
0
파일: p_desc.c 프로젝트: goodwinos/pcp
int
__pmSendDescReq(int fd, int from, pmID pmid)
{
    desc_req_t	*pp;
    int		sts;

    if ((pp = (desc_req_t *)__pmFindPDUBuf(sizeof(desc_req_t))) == NULL)
	return -oserror();
    pp->hdr.len = sizeof(desc_req_t);
    pp->hdr.type = PDU_DESC_REQ;
    pp->hdr.from = from;
    pp->pmid = __htonpmID(pmid);

#ifdef DESPERATE
    {
	char	strbuf[20];
	fprintf(stderr, "__pmSendDescReq: converted 0x%08x (%s) to 0x%08x\n", pmid, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), pp->pmid);
    }
#endif

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #11
0
파일: p_text.c 프로젝트: goodwinos/pcp
int
__pmSendText(int fd, int ctx, int ident, const char *buffer)
{
    text_t	*pp;
    size_t	need;
    size_t	len = strlen(buffer);
    int		sts;

    need = sizeof(text_t) - sizeof(pp->buffer) + PM_PDU_SIZE_BYTES(len);
    if ((pp = (text_t *)__pmFindPDUBuf((int)need)) == NULL)
	return -oserror();
    pp->hdr.len = (int)need;
    pp->hdr.type = PDU_TEXT;
    pp->hdr.from = ctx;
    /*
     * Note: ident argument must already be in network byte order.
     * The caller has to do this because the type of ident is not
     * part of the transmitted PDU_TEXT pdu; ident may be either
     * a pmID or pmInDom, and so the caller must use either
     * __htonpmID or __htonpmInDom (respectively).
     */
    pp->ident = ident;
    pp->buflen = htonl(len);
    memcpy((void *)pp->buffer, (void *)buffer, len);
    if (len % sizeof(__pmPDU) != 0) {
	/* clear the padding bytes, lest they contain garbage */
	int	pad;
	char	*padp = pp->buffer + len;
	for (pad = sizeof(__pmPDU) - 1; pad >= (len % sizeof(__pmPDU)); pad--)
	    *padp++ = '~';	/* buffer end */
    }

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #12
0
파일: p_label.c 프로젝트: goodwinos/pcp
int
__pmSendLabel(int fd, int from, int ident, int type, pmLabelSet *sets, int nsets)
{
    size_t	labels_offset;
    size_t	labels_need;
    size_t	json_offset;
    size_t	json_need;
    labelset_t	*lsp;
    labels_t	*pp;
    pmLabel	*lp;
    int		sts;
    int		i, j;

    if (nsets < 0)
	return -EINVAL;
    labels_need = sizeof(labels_t) + (sizeof(labelset_t) * (nsets - 1));
    json_need = 0;
    for (i = 0; i < nsets; i++) {
	json_need += sets[i].jsonlen;
	if (sets[i].nlabels > 0)
	    labels_need += sets[i].nlabels * sizeof(pmLabel);
    }

    if ((pp = (labels_t *)__pmFindPDUBuf((int)labels_need + json_need)) == NULL)
	return -oserror();

    pp->hdr.len = (int)(labels_need + json_need);
    pp->hdr.type = PDU_LABEL;
    pp->hdr.from = from;

    if (type & PM_LABEL_DOMAIN)
	pp->ident = htonl(ident);
    else if (type & (PM_LABEL_CLUSTER | PM_LABEL_ITEM | PM_LABEL_INSTANCES))
	pp->ident = __htonpmID((pmID)ident);
    else if (type & PM_LABEL_INDOM)
	pp->ident = __htonpmInDom((pmInDom)ident);
    else
	pp->ident = htonl(PM_ID_NULL);

    pp->type = htonl(type);
    pp->padding = 0;
    pp->nsets = htonl(nsets);

    labels_offset = (char *)&pp->sets[0] - (char *)pp;
    json_offset = labels_need;	/* JSONB immediately follows labelsets */

    for (i = 0; i < nsets; i++) {
	lsp = (labelset_t *)((char *)pp + labels_offset);
	lsp->inst = htonl(sets[i].inst);
	lsp->nlabels = htonl(sets[i].nlabels);
	lsp->json = htonl(json_offset);
	lsp->jsonlen = htonl(sets[i].jsonlen);

	if (sets[i].nlabels > 0) {
	    for (j = 0; j < sets[i].nlabels; j++) {
		lp = &lsp->labels[j];
		lp->name = htons(sets[i].labels[j].name);
		lp->namelen = sets[i].labels[j].namelen;	/* byte copy */
		lp->flags = sets[i].labels[j].flags;		/* byte copy */
		lp->value = htons(sets[i].labels[j].value);
		lp->valuelen = htons(sets[i].labels[j].valuelen);
	    }
	    labels_offset += sets[i].nlabels * sizeof(pmLabel);
	}
	labels_offset += sizeof(labelset_t);

	if (sets[i].jsonlen) {
	    memcpy((char *)pp + json_offset, sets[i].json, sets[i].jsonlen);
	    json_offset += sets[i].jsonlen;
	}
    }

    if (pmDebugOptions.labels)
	DumpLabelSets("__pmSendLabel", ident, type, sets, nsets);

    sts = __pmXmitPDU(fd, (__pmPDU *)pp);
    __pmUnpinPDUBuf(pp);
    return sts;
}
예제 #13
0
파일: pdu.c 프로젝트: rwongone/pcp
/* result is pinned on successful return */
int
__pmGetPDU(int fd, int mode, int timeout, __pmPDU **result)
{
    int			need;
    int			len;
    static int		maxsize = PDU_CHUNK;
    char		*handle;
    __pmPDU		*pdubuf;
    __pmPDU		*pdubuf_prev;
    __pmPDUHdr		*php;

    if ((pdubuf = __pmFindPDUBuf(maxsize)) == NULL)
	return -oserror();

    /* First read - try to read the header */
    len = pduread(fd, (void *)pdubuf, sizeof(__pmPDUHdr), HEADER, timeout);
    php = (__pmPDUHdr *)pdubuf;

    if (len < (int)sizeof(__pmPDUHdr)) {
	if (len == -1) {
	    if (__pmSocketClosed()) {
		len = 0;
	    } else {
		char	errmsg[PM_MAXERRMSGLEN];
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg)));
	    }
	}
	else if (len >= (int)sizeof(php->len)) {
	    /*
	     * Have part of a PDU header.  Enough for the "len"
	     * field to be valid, but not yet all of it - save
	     * what we have received and try to read some more.
	     * Note this can only happen once per PDU, so the
	     * ntohl() below will _only_ be done once per PDU.
	     */
	    goto check_read_len;	/* continue, do not return */
	}
	else if (len == PM_ERR_TIMEOUT) {
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_TIMEOUT;
	}
	else if (len < 0) {
	    char	errmsg[PM_MAXERRMSGLEN];
	    __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(len, errmsg, sizeof(errmsg)));
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}
	else if (len > 0) {
	    __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: bad len=%d", fd, len);
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}

	/*
	 * end-of-file with no data
	 */
	__pmUnpinPDUBuf(pdubuf);
	return 0;
    }

check_read_len:
    php->len = ntohl(php->len);
    if (php->len < (int)sizeof(__pmPDUHdr)) {
	/*
	 * PDU length indicates insufficient bytes for a PDU header
	 * ... looks like DOS attack like PV 935490
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU len=%d in hdr", fd, php->len);
	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_IPC;
    }
    else if (mode == LIMIT_SIZE && php->len > ceiling) {
	/*
	 * Guard against denial of service attack ... don't accept PDUs
	 * from clients that are larger than 64 Kbytes (ceiling)
	 * (note, pmcd and pmdas have to be able to _send_ large PDUs,
	 * e.g. for a pmResult or instance domain enquiry)
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d bad PDU len=%d in hdr exceeds maximum client PDU size (%d)",
		      fd, php->len, ceiling);

	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_TOOBIG;
    }

    if (len < php->len) {
	/*
	 * need to read more ...
	 */
	int		tmpsize;
	int		have = len;

	PM_INIT_LOCKS();
	PM_LOCK(__pmLock_libpcp);
	if (php->len > maxsize) {
	    tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK);
	    maxsize = tmpsize;
	}
	else
	    tmpsize = maxsize;
	PM_UNLOCK(__pmLock_libpcp);

	pdubuf_prev = pdubuf;
	if ((pdubuf = __pmFindPDUBuf(tmpsize)) == NULL) {
	    __pmUnpinPDUBuf(pdubuf_prev);
	    return -oserror();
	}

	memmove((void *)pdubuf, (void *)php, len);
	__pmUnpinPDUBuf(pdubuf_prev);

	php = (__pmPDUHdr *)pdubuf;
	need = php->len - have;
	handle = (char *)pdubuf;
	/* block until all of the PDU is received this time */
	len = pduread(fd, (void *)&handle[len], need, BODY, timeout);
	if (len != need) {
	    if (len == PM_ERR_TIMEOUT) {
		__pmUnpinPDUBuf(pdubuf);
		return PM_ERR_TIMEOUT;
	    }
	    else if (len < 0) {
		char	errmsg[PM_MAXERRMSGLEN];
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg)));
	    }
	    else
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: have %d, want %d, got %d", fd, have, need, len);
	    /*
	     * only report header fields if you've read enough bytes
	     */
	    if (len > 0)
		have += len;
	    if (have >= (int)(sizeof(php->len)+sizeof(php->type)+sizeof(php->from)))
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x from=0x%x", php->len, (unsigned)ntohl(php->type), (unsigned)ntohl(php->from));
	    else if (have >= (int)(sizeof(php->len)+sizeof(php->type)))
		__pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x", php->len, (unsigned)ntohl(php->type));
	    __pmUnpinPDUBuf(pdubuf);
	    return PM_ERR_IPC;
	}
    }

    *result = (__pmPDU *)php;
    php->type = ntohl((unsigned int)php->type);
    if (php->type < 0) {
	/*
	 * PDU type is bad ... could be a possible mem leak attack like
	 * https://bugzilla.redhat.com/show_bug.cgi?id=841319
	 */
	__pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU type=%d in hdr", fd, php->type);
	__pmUnpinPDUBuf(pdubuf);
	return PM_ERR_IPC;
    }
    php->from = ntohl((unsigned int)php->from);
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_PDU) {
	int	j;
	char	*p;
	int	jend = PM_PDU_SIZE(php->len);
	char	strbuf[20];

        /* clear the padding bytes, lest they contain garbage */
	p = (char *)*result + php->len;
	while (p < (char *)*result + jend*sizeof(__pmPDU))
	    *p++ = '~';	/* buffer end */

	if (mypid == -1)
	    mypid = (int)getpid();
	fprintf(stderr, "[%d]pmGetPDU: %s fd=%d len=%d from=%d",
		mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len, php->from);
	for (j = 0; j < jend; j++) {
	    if ((j % 8) == 0)
		fprintf(stderr, "\n%03d: ", j);
	    fprintf(stderr, "%8x ", (*result)[j]);
	}
	putc('\n', stderr);
    }
#endif
    if (php->type >= PDU_START && php->type <= PDU_FINISH)
	__pmPDUCntIn[php->type-PDU_START]++;

    /*
     * Note php points into the PDU buffer pdubuf that remains pinned
     * and php is returned via the result parameter ... see the
     * thread-safe comments above
     */
    return php->type;
}
예제 #14
0
파일: pmlogreduce.c 프로젝트: tongfw/pcp
int
main(int argc, char **argv)
{
    int		sts;
    char	*msg;
    pmResult	*irp;		/* input pmResult */
    pmResult	*orp;		/* output pmResult */
    __pmPDU	*pb;		/* pdu buffer */
    struct timeval	unused;
    unsigned long	peek_offset;

    /* process cmd line args */
    if (parseargs(argc, argv) < 0) {
	pmUsageMessage(&opts);
	exit(1);
    }

    /* input  archive name is argv[opts.optind] */
    /* output archive name is argv[argc-1]) */

    /* output archive */
    oname = argv[argc-1];

    /* input archive */
    iname = argv[opts.optind];

    /*
     * This is the interp mode context
     */
    if ((ictx_a = pmNewContext(PM_CONTEXT_ARCHIVE, iname)) < 0) {
	fprintf(stderr, "%s: Error: cannot open archive \"%s\" (ctx_a): %s\n",
		pmProgname, iname, pmErrStr(ictx_a));
	exit(1);
    }

    if ((sts = pmGetArchiveLabel(&ilabel)) < 0) {
	fprintf(stderr, "%s: Error: cannot get archive label record (%s): %s\n", pmProgname, iname, pmErrStr(sts));
	exit(1);
    }

    /* start time */
    logstart_tval.tv_sec = ilabel.ll_start.tv_sec;
    logstart_tval.tv_usec = ilabel.ll_start.tv_usec;

    /* end time */
    if ((sts = pmGetArchiveEnd(&logend_tval)) < 0) {
	fprintf(stderr, "%s: Error: cannot get end of archive (%s): %s\n",
		pmProgname, iname, pmErrStr(sts));
	exit(1);
    }

    if (zarg) {
	/* use TZ from metrics source (input-archive) */
	if ((sts = pmNewZone(ilabel.ll_tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set context timezone: %s\n",
		    pmProgname, pmErrStr(sts));
            exit(1);
	}
	printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", ilabel.ll_hostname);
    }
    else if (tz != NULL) {
	/* use TZ as specified by user */
	if ((sts = pmNewZone(tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n",
		    pmProgname, tz, pmErrStr(sts));
	    exit(1);
	}
	printf("Note: timezone set to \"TZ=%s\"\n\n", tz);
    }
    else {
	char	*tz;
        tz = __pmTimezone();
	/* use TZ from local host */
	if ((sts = pmNewZone(tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set local host's timezone: %s\n",
		    pmProgname, pmErrStr(sts));
	    exit(1);
	}
    }

    /* set winstart and winend timevals */
    sts = pmParseTimeWindow(Sarg, Targ, Aarg, Oarg,
			    &logstart_tval, &logend_tval,
			    &winstart_tval, &winend_tval, &unused, &msg);
    if (sts < 0) {
	fprintf(stderr, "%s: Invalid time window specified: %s\n",
		pmProgname, msg);
	exit(1);
    }
#if PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL0) {
	char	buf[26];
	pmCtime((const time_t *)&winstart_tval.tv_sec, buf);
	fprintf(stderr, "Start time: %s", buf);
	pmCtime((const time_t *)&winend_tval.tv_sec, buf);
	fprintf(stderr, "End time: %s", buf);
    }
#endif

    if ((sts = pmSetMode(PM_MODE_INTERP | PM_XTB_SET(PM_TIME_SEC),
                         &winstart_tval, (int)targ)) < 0) {
	fprintf(stderr, "%s: pmSetMode(PM_MODE_INTERP ...) failed: %s\n",
		pmProgname, pmErrStr(sts));
	exit(1);
    }

    /* create output log - must be done before writing label */
    if ((sts = __pmLogCreate("", oname, PM_LOG_VERS02, &logctl)) < 0) {
	fprintf(stderr, "%s: Error: __pmLogCreate: %s\n",
		pmProgname, pmErrStr(sts));
	exit(1);
    }

    /* This must be done after log is created:
     *		- checks that archive version, host, and timezone are ok
     *		- set archive version, host, and timezone of output archive
     *		- set start time
     *		- write labels
     */
    newlabel();
    current.tv_sec = logctl.l_label.ill_start.tv_sec = winstart_tval.tv_sec;
    current.tv_usec = logctl.l_label.ill_start.tv_usec = winstart_tval.tv_usec;
    /* write label record */
    writelabel();
    /*
     * Supress any automatic label creation in libpcp at the first
     * pmResult write.
     */
    logctl.l_state = PM_LOG_STATE_INIT;

    /*
     * Traverse the PMNS to get all the metrics and their metadata
     */
    if ((sts = pmTraversePMNS ("", dometric)) < 0) {
	fprintf(stderr, "%s: Error traversing namespace ... %s\n",
		pmProgname, pmErrStr(sts));
	goto cleanup;
    }

    /*
     * All the initial metadata has been generated, add timestamp
     */
    fflush(logctl.l_mdfp);
    __pmLogPutIndex(&logctl, &current);

    written = 0;

    /*
     * main loop
     */
    while (sarg == -1 || written < sarg) {
	/*
	 * do stuff
	 */
	if ((sts = pmUseContext(ictx_a)) < 0) {
	    fprintf(stderr, "%s: Error: cannot use context (%s): %s\n",
		    pmProgname, iname, pmErrStr(sts));
	    goto cleanup;
	}
	if ((sts = pmFetch(numpmid, pmidlist, &irp)) < 0) {
	    if (sts == PM_ERR_EOL)
		break;
	    fprintf(stderr,
		"%s: Error: pmFetch failed: %s\n", pmProgname, pmErrStr(sts));
	    exit(1);
	}
	if (irp->timestamp.tv_sec > winend_tval.tv_sec ||
	    (irp->timestamp.tv_sec == winend_tval.tv_sec &&
	     irp->timestamp.tv_usec > winend_tval.tv_usec)) {
	    /* past end time as per -T */
	    break;
	}
#if PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "input record ...\n");
	    __pmDumpResult(stderr, irp);
	}
#endif

	/*
	 * traverse the interval, looking at every archive record ...
	 * we are particularly interested in:
	 * 	- metric-values that are interpolated but not present in
	 * 	  this interval
	 * 	- counter wraps
	 *	- mark records
	 */
	doscan(&irp->timestamp);

	if ((sts = pmUseContext(ictx_a)) < 0) {
	    fprintf(stderr, "%s: Error: cannot use context (%s): %s\n",
		    pmProgname, iname, pmErrStr(sts));
	    goto cleanup;
	}

	orp = rewrite(irp);
#if PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    if (orp == NULL)
		fprintf(stderr, "output record ... none!\n");
	    else {
		fprintf(stderr, "output record ...\n");
		__pmDumpResult(stderr, orp);
	    }
	}
#endif
	if (orp == NULL)
	    goto next;

	/*
	 * convert log record to a PDU, and enforce V2 encoding semantics,
	 * then write it out
	 */
	sts = __pmEncodeResult(PDU_OVERRIDE2, orp, &pb);
	if (sts < 0) {
	    fprintf(stderr, "%s: Error: __pmEncodeResult: %s\n",
		    pmProgname, pmErrStr(sts));
	    goto cleanup;
	}

	/* switch volumes if required */
	if (varg > 0) {
	    if (written > 0 && (written % varg) == 0) {
		__pmTimeval	next_stamp;
		next_stamp.tv_sec = irp->timestamp.tv_sec;
		next_stamp.tv_usec = irp->timestamp.tv_usec;
		newvolume(oname, &next_stamp);
	    }
	}
	/*
	 * Even without a -v option, we may need to switch volumes
	 * if the data file exceeds 2^31-1 bytes
	 */
	peek_offset = ftell(logctl.l_mfp);
	peek_offset += ((__pmPDUHdr *)pb)->len - sizeof(__pmPDUHdr) + 2*sizeof(int);
	if (peek_offset > 0x7fffffff) {
	    __pmTimeval	next_stamp;
	    next_stamp.tv_sec = irp->timestamp.tv_sec;
	    next_stamp.tv_usec = irp->timestamp.tv_usec;
	    newvolume(oname, &next_stamp);
	}

	current.tv_sec = orp->timestamp.tv_sec;
	current.tv_usec = orp->timestamp.tv_usec;

	doindom(orp);

	/* write out log record */
	sts = __pmLogPutResult2(&logctl, pb);
	__pmUnpinPDUBuf(pb);
	if (sts < 0) {
	    fprintf(stderr, "%s: Error: __pmLogPutResult2: log data: %s\n",
		    pmProgname, pmErrStr(sts));
	    goto cleanup;
	}
	written++;

	rewrite_free();

next:
	pmFreeResult(irp);
    }

    /* write the last time stamp */
    fflush(logctl.l_mfp);
    fflush(logctl.l_mdfp);
    __pmLogPutIndex(&logctl, &current);

    exit(exit_status);

cleanup:
    {
	char    fname[MAXNAMELEN];
	fprintf(stderr, "Archive \"%s\" not created.\n", oname);
	snprintf(fname, sizeof(fname), "%s.0", oname);
	unlink(fname);
	snprintf(fname, sizeof(fname), "%s.meta", oname);
	unlink(fname);
	snprintf(fname, sizeof(fname), "%s.index", oname);
	unlink(fname);
	exit(1);
    }
}
예제 #15
0
파일: fetch.c 프로젝트: Aconex/pcp
int
pmFetch(int numpmid, pmID pmidlist[], pmResult **result)
{
    int		n;

    if (numpmid < 1) {
	n = PM_ERR_TOOSMALL;
	goto done;
    }

    if ((n = pmWhichContext()) >= 0) {
	__pmContext	*ctxp = __pmHandleToPtr(n);
	int		newcnt;
	pmID		*newlist = NULL;
	int		have_dm;

	if (ctxp == NULL) {
	    n = PM_ERR_NOCONTEXT;
	    goto done;
	}
	if (ctxp->c_type == PM_CONTEXT_LOCAL && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) {
	    /* Local context requires single-threaded applications */
	    n = PM_ERR_THREAD;
	    PM_UNLOCK(ctxp->c_lock);
	    goto done;
	}

	/* for derived metrics, may need to rewrite the pmidlist */
	have_dm = newcnt = __pmPrepareFetch(ctxp, numpmid, pmidlist, &newlist);
	if (newcnt > numpmid) {
	    /* replace args passed into pmFetch */
	    numpmid = newcnt;
	    pmidlist = newlist;
	}

	if (ctxp->c_type == PM_CONTEXT_HOST) {
	    /*
	     * Thread-safe note
	     *
	     * Need to be careful here, because the PMCD changed protocol
	     * may mean several PDUs are returned, but __pmDecodeResult()
	     * may request more info from PMCD if pmDebug is set.
	     *
	     * So unlock ctxp->c_pmcd->pc_lock as soon as possible.
	     */
	    PM_LOCK(ctxp->c_pmcd->pc_lock);
	    if ((n = request_fetch(n, ctxp, numpmid, pmidlist)) >= 0) {
		int changed = 0;
		do {
		    __pmPDU	*pb;
		    int		pinpdu;

		    pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE,
					    ctxp->c_pmcd->pc_tout_sec, &pb);
		    if (n == PDU_RESULT) {
			PM_UNLOCK(ctxp->c_pmcd->pc_lock);
			n = __pmDecodeResult(pb, result);
		    }
		    else if (n == PDU_ERROR) {
			__pmDecodeError(pb, &n);
			if (n > 0)
			    /* PMCD state change protocol */
			    changed = n;
			else
			    PM_UNLOCK(ctxp->c_pmcd->pc_lock);
		    }
		    else {
			PM_UNLOCK(ctxp->c_pmcd->pc_lock);
			if (n != PM_ERR_TIMEOUT)
			    n = PM_ERR_IPC;
		    }
		    if (pinpdu > 0)
			__pmUnpinPDUBuf(pb);
		} while (n > 0);

		if (n == 0)
		    n |= changed;
	    }
	    else
		PM_UNLOCK(ctxp->c_pmcd->pc_lock);
	}
	else if (ctxp->c_type == PM_CONTEXT_LOCAL) {
	    n = __pmFetchLocal(ctxp, numpmid, pmidlist, result);
	}
	else {
	    /* assume PM_CONTEXT_ARCHIVE */
	    n = __pmLogFetch(ctxp, numpmid, pmidlist, result);
	    if (n >= 0 && (ctxp->c_mode & __PM_MODE_MASK) != PM_MODE_INTERP) {
		ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec;
		ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec;
	    }
	}

	/* process derived metrics, if any */
	if (have_dm) {
	    __pmFinishResult(ctxp, n, result);
	    if (newlist != NULL)
		free(newlist);
	}
	PM_UNLOCK(ctxp->c_lock);
    }

done:
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_FETCH) {
	fprintf(stderr, "pmFetch returns ...\n");
	if (n > 0) {
	    fprintf(stderr, "PMCD state changes: agent(s)");
	    if (n & PMCD_ADD_AGENT) fprintf(stderr, " added");
	    if (n & PMCD_RESTART_AGENT) fprintf(stderr, " restarted");
	    if (n & PMCD_DROP_AGENT) fprintf(stderr, " dropped");
	    fputc('\n', stderr);
	}
	if (n >= 0)
	    __pmDumpResult(stderr, *result);
	else {
	    char	errmsg[PM_MAXERRMSGLEN];
	    fprintf(stderr, "Error: %s\n", pmErrStr_r(n, errmsg, sizeof(errmsg)));
	}
    }
#endif

    return n;
}
예제 #16
0
파일: connect.c 프로젝트: tongfw/pcp
/*
 * client connects to pmcd handshake
 */
static int
__pmConnectHandshake(int fd, const char *hostname, int ctxflags, __pmHashCtl *attrs)
{
    __pmPDU	*pb;
    int		ok;
    int		version;
    int		challenge;
    int		sts;
    int		pinpdu;

    /* Expect an error PDU back from PMCD: ACK/NACK for connection */
    pinpdu = sts = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb);
    if (sts == PDU_ERROR) {
	/*
	 * See comments in pmcd ... we actually get an extended error PDU
	 * from pmcd, of the form
	 *
	 *  :----------:-----------:
	 *  |  status  | challenge |
	 *  :----------:-----------:
	 *
	 *   For a good connection, status is 0, else a PCP error code;
	 *   challenge contains server-side info (e.g. enabled features)
	 */
	version = __pmDecodeXtendError(pb, &sts, &challenge);
	if (version < 0) {
	    __pmUnpinPDUBuf(pb);
	    return version;
	}
	if (sts < 0) {
	    __pmUnpinPDUBuf(pb);
	    return sts;
	}

	if (version == PDU_VERSION2) {
	    __pmPDUInfo		pduinfo;
	    __pmVersionCred	handshake;
	    int			pduflags = 0;

	    pduinfo = __ntohpmPDUInfo(*(__pmPDUInfo *)&challenge);

	    if (pduinfo.features & PDU_FLAG_CREDS_REQD)
		/*
		 * This is a mandatory connection feature - pmcd must be
		 * sent user credential information one way or another -
		 * i.e. via SASL2 authentication, or AF_UNIX peer creds.
		 */
		pduflags |= PDU_FLAG_CREDS_REQD;

	    if (ctxflags) {
		/*
		 * If an optional connection feature (e.g. encryption) is
		 * desired, the pmcd that we're talking to must advertise
		 * support for the feature.  And if it did, the client in
		 * turn must request it be enabled (now, via pduflags).
		 */
		if (ctxflags & (PM_CTXFLAG_SECURE|PM_CTXFLAG_RELAXED)) {
		    if (pduinfo.features & PDU_FLAG_SECURE) {
			pduflags |= PDU_FLAG_SECURE;
			/*
			 * Determine whether the server can send an ACK for a
			 * secure connection request. We can still connect
			 * whether it does or not, but we need to know the
			 * protocol.
			 */
			if (pduinfo.features & PDU_FLAG_SECURE_ACK)
			    pduflags |= PDU_FLAG_SECURE_ACK;
		    } else if (ctxflags & PM_CTXFLAG_SECURE) {
			__pmUnpinPDUBuf(pb);
			return -EOPNOTSUPP;
		    }
		}
		if (ctxflags & PM_CTXFLAG_COMPRESS) {
		    if (pduinfo.features & PDU_FLAG_COMPRESS)
			pduflags |= PDU_FLAG_COMPRESS;
		    else {
			__pmUnpinPDUBuf(pb);
			return -EOPNOTSUPP;
		    }
		}
		if (ctxflags & PM_CTXFLAG_AUTH) {
		    if (pduinfo.features & PDU_FLAG_AUTH)
			pduflags |= PDU_FLAG_AUTH;
		    else {
			__pmUnpinPDUBuf(pb);
			return -EOPNOTSUPP;
		    }
		}
	    }

	    /*
	     * Negotiate connection version and features (via creds PDU)
	     */
	    if ((ok = __pmSetVersionIPC(fd, version)) < 0) {
		__pmUnpinPDUBuf(pb);
		return ok;
	    }

	    memset(&handshake, 0, sizeof(handshake));
	    handshake.c_type = CVERSION;
	    handshake.c_version = PDU_VERSION;
	    handshake.c_flags = pduflags;

	    sts = __pmSendCreds(fd, (int)getpid(), 1, (__pmCred *)&handshake);

	    /*
	     * At this point we know caller wants to set channel options and
	     * pmcd supports them so go ahead and update the socket now (this
	     * completes the SSL handshake in encrypting mode, authentication
	     * via SASL, and/or enabling compression in NSS).
	     */
	    if (sts >= 0 && pduflags)
		sts = __pmSecureClientHandshake(fd, pduflags, hostname, attrs);
	}
	else
	    sts = PM_ERR_IPC;
    }
    else if (sts != PM_ERR_TIMEOUT)
	sts = PM_ERR_IPC;

    if (pinpdu > 0)
	__pmUnpinPDUBuf(pb);

    return sts;
}
예제 #17
0
파일: pmcd.c 프로젝트: andyvand/cygpcpfans
/*
 * Determine which clients (if any) have sent data to the server and handle it
 * as required.
 */
void
HandleClientInput(__pmFdSet *fdsPtr)
{
    int		sts;
    int		i;
    __pmPDU	*pb;
    __pmPDUHdr	*php;
    ClientInfo	*cp;

    for (i = 0; i < nClients; i++) {
	int		pinpdu;
	if (!client[i].status.connected || !__pmFD_ISSET(client[i].fd, fdsPtr))
	    continue;

	cp = &client[i];
	this_client_id = i;

	pinpdu = sts = __pmGetPDU(cp->fd, LIMIT_SIZE, _pmcd_timeout, &pb);
	if (sts > 0) {
	    pmcd_trace(TR_RECV_PDU, cp->fd, sts, (int)((__psint_t)pb & 0xffffffff));
	} else {
	    CleanupClient(cp, sts);
	    continue;
	}

	php = (__pmPDUHdr *)pb;
	if (__pmVersionIPC(cp->fd) == UNKNOWN_VERSION && php->type != PDU_CREDS) {
	    /* old V1 client protocol, no longer supported */
	    sts = PM_ERR_IPC;
	    CleanupClient(cp, sts);
	    __pmUnpinPDUBuf(pb);
	    continue;
	}

	if (pmDebug & DBG_TRACE_APPL0)
	    ShowClients(stderr);

	switch (php->type) {
	    case PDU_PROFILE:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoProfile(cp, pb);
		break;

	    case PDU_FETCH:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoFetch(cp, pb);
		break;

	    case PDU_INSTANCE_REQ:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoInstance(cp, pb);
		break;

	    case PDU_DESC_REQ:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoDesc(cp, pb);
		break;

	    case PDU_TEXT_REQ:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoText(cp, pb);
		break;

	    case PDU_RESULT:
		sts = (cp->denyOps & PMCD_OP_STORE) ?
		      PM_ERR_PERMISSION : DoStore(cp, pb);
		break;

	    case PDU_PMNS_IDS:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoPMNSIDs(cp, pb);
		break;

	    case PDU_PMNS_NAMES:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoPMNSNames(cp, pb);
		break;

	    case PDU_PMNS_CHILD:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoPMNSChild(cp, pb);
		break;

	    case PDU_PMNS_TRAVERSE:
		sts = (cp->denyOps & PMCD_OP_FETCH) ?
		      PM_ERR_PERMISSION : DoPMNSTraverse(cp, pb);
		break;

	    case PDU_CREDS:
		sts = DoCreds(cp, pb);
		break;

	    default:
		sts = PM_ERR_IPC;
	}
	if (sts < 0) {
	    if (pmDebug & DBG_TRACE_APPL0)
		fprintf(stderr, "PDU:  %s client[%d]: %s\n",
		    __pmPDUTypeStr(php->type), i, pmErrStr(sts));
	    /* Make sure client still alive before sending. */
	    if (cp->status.connected) {
		pmcd_trace(TR_XMIT_PDU, cp->fd, PDU_ERROR, sts);
		sts = __pmSendError(cp->fd, FROM_ANON, sts);
		if (sts < 0)
		    __pmNotifyErr(LOG_ERR, "HandleClientInput: "
			"error sending Error PDU to client[%d] %s\n", i, pmErrStr(sts));
	    }
	}
	if (pinpdu > 0)
	    __pmUnpinPDUBuf(pb);
    }
}
예제 #18
0
파일: dofetch.c 프로젝트: jujis008/pcp
int
DoFetch(ClientInfo *cip, __pmPDU* pb)
{
    int			i, j;
    int 		sts;
    int			ctxnum;
    __pmTimeval		when;
    int			nPmids;
    pmID		*pmidList;
    static pmResult	*endResult = NULL;
    static int		maxnpmids = 0;	/* sizes endResult */
    DomPmidList		*dList;		/* NOTE: NOT indexed by agent index */
    static int		nDoms = 0;
    static pmResult	**results = NULL;
    static int		*resIndex = NULL;
    __pmFdSet		waitFds;
    __pmFdSet		readyFds;
    int			nWait;
    int			maxFd;
    struct timeval	timeout;

    if (nAgents > nDoms) {
	if (results != NULL)
	    free(results);
	if (resIndex != NULL)
	    free(resIndex);
	results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *));
	resIndex = (int *)malloc((nAgents + 1) * sizeof(int));
	if (results == NULL || resIndex == NULL) {
	    __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR);
	}
	nDoms = nAgents;
    }
    memset(results, 0, (nAgents + 1) * sizeof(results[0]));

    sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList);
    if (sts < 0)
	return sts;

    /* Check that a profile has been received from the specified context */
    if (ctxnum < 0 || ctxnum >= cip->szProfile ||
	cip->profile[ctxnum] == NULL) {
	__pmUnpinPDUBuf(pb);
	if (ctxnum < 0 || ctxnum >= cip->szProfile)
	    __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum);
	else
	    __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum);
	return PM_ERR_NOPROFILE;
    }

    if (nPmids > maxnpmids) {
	int		need;
	if (endResult != NULL)
	    free(endResult);
	need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *);
	if ((endResult = (pmResult *)malloc(need)) == NULL) {
	    __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR);
	}
	maxnpmids = nPmids;
    }

    dList = SplitPmidList(nPmids, pmidList);

    /* For each domain in the split pmidList, dispatch the per-domain subset
     * of pmIDs to the appropriate agent.  For DSO agents, the pmResult will
     * come back immediately.  If a request cannot be sent to an agent, a
     * suitable pmResult (containing metric not available values) will be
     * returned.
     */
    __pmFD_ZERO(&waitFds);
    nWait = 0;
    maxFd = -1;
    for (i = 0; dList[i].domain != -1; i++) {
	j = mapdom[dList[i].domain];
	results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum);
	if (results[j] == NULL) { /* Wait for agent's response */
	    int fd = agent[j].outFd;
	    agent[j].status.busy = 1;
	    __pmFD_SET(fd, &waitFds);
	    if (fd > maxFd)
		maxFd = fd;
	    nWait++;
	}
    }
    /* Construct pmResult for bad-pmID list */
    if (dList[i].listSize != 0)
	results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT);

    /* Wait for results to roll in from agents */
    while (nWait > 0) {
        __pmFD_COPY(&readyFds, &waitFds);
	if (nWait > 1) {
	    timeout.tv_sec = _pmcd_timeout;
	    timeout.tv_usec = 0;

            retry:
	    setoserror(0);
	    sts = __pmSelectRead(maxFd+1, &readyFds, &timeout);

	    if (sts == 0) {
		__pmNotifyErr(LOG_INFO, "DoFetch: select timeout");

		/* Timeout, terminate agents with undelivered results */
		for (i = 0; i < nAgents; i++) {
		    if (agent[i].status.busy) {
			/* Find entry in dList for this agent */
			for (j = 0; dList[j].domain != -1; j++)
			    if (dList[j].domain == agent[i].pmDomainId)
				break;
			results[i] = MakeBadResult(dList[j].listSize,
						   dList[j].list,
						   PM_ERR_NOAGENT);
			pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0);
			CleanupAgent(&agent[i], AT_COMM, agent[i].inFd);
		    }
		}
		break;
	    }
	    else if (sts < 0) {
		if (neterror() == EINTR)
		    goto retry;
		/* this is not expected to happen! */
		__pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n",
			netstrerror());
		Shutdown();
		exit(1);
	    }
	}

	/* Read results from agents that have them ready */
	for (i = 0; i < nAgents; i++) {
	    AgentInfo	*ap = &agent[i];
	    int		pinpdu;
	    if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds))
		continue;
	    ap->status.busy = 0;
	    __pmFD_CLR(ap->outFd, &waitFds);
	    nWait--;
	    pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb);
	    if (sts > 0)
		pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff));
	    if (sts == PDU_RESULT) {
		if ((sts = __pmDecodeResult(pb, &results[i])) >= 0)
		    if (results[i]->numpmid != aFreq[i]) {
			pmFreeResult(results[i]);
			sts = PM_ERR_IPC;
#ifdef PCP_DEBUG
			if (pmDebug & DBG_TRACE_APPL0)
			    __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n",
					 ap->pmDomainLabel, aFreq[i], results[i]->numpmid);
#endif
		    }
	    }
	    else {
		if (sts == PDU_ERROR) {
		    int s;
		    if ((s = __pmDecodeError(pb, &sts)) < 0)
			sts = s;
		    else if (sts >= 0)
			sts = PM_ERR_GENERIC;
		    pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts);
		}
		else if (sts >= 0) {
		    pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts);
		    sts = PM_ERR_IPC;
		}
	    }
	    if (pinpdu > 0)
		__pmUnpinPDUBuf(pb);

	    if (sts < 0) {
		/* Find entry in dList for this agent */
		for (j = 0; dList[j].domain != -1; j++)
		    if (dList[j].domain == agent[i].pmDomainId)
			break;
		results[i] = MakeBadResult(dList[j].listSize,
					   dList[j].list, sts);

		if (sts == PM_ERR_PMDANOTREADY) {
		    /* the agent is indicating it can't handle PDUs for now */
		    int k;
		    extern int CheckError(AgentInfo *ap, int sts);

		    for (k = 0; k < dList[j].listSize; k++)
			results[i]->vset[k]->numval = PM_ERR_AGAIN;
		    sts = CheckError(&agent[i], sts);
		}

#ifdef PCP_DEBUG
		if (pmDebug & DBG_TRACE_APPL0) {
		    fprintf(stderr, "RESULT error from \"%s\" agent : %s\n",
			    ap->pmDomainLabel, pmErrStr(sts));
		}
#endif
		if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT)
		    CleanupAgent(ap, AT_COMM, ap->outFd);
	    }
	}
    }

    endResult->numpmid = nPmids;
    __pmtimevalNow(&endResult->timestamp);
    /* The order of the pmIDs in the per-domain results is the same as in the
     * original request, but on a per-domain basis.  resIndex is an array of
     * indices (one per agent) of the next metric to be retrieved from each
     * per-domain result's vset.
     */
    memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0]));

    for (i = 0; i < nPmids; i++) {
	j = mapdom[((__pmID_int *)&pmidList[i])->domain];
	endResult->vset[i] = results[j]->vset[resIndex[j]++];
    }
    pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid);

    sts = 0;
    if (cip->status.changes) {
	/* notify client of PMCD state change */
	sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes);
	if (sts > 0)
	    sts = 0;
	cip->status.changes = 0;
    }
    if (sts == 0)
	sts = __pmSendResult(cip->fd, FROM_ANON, endResult);

    if (sts < 0) {
	pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts);
	CleanupClient(cip, sts);
    }

    /*
     * pmFreeResult() all the accumulated results.
     */
    for (i = 0; dList[i].domain != -1; i++) {
	j = mapdom[dList[i].domain];
	if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected &&
	    !agent[j].status.madeDsoResult)
	    /* Living DSO's manage their own pmResult skeleton unless
	     * MakeBadResult was called to create the result.  The value sets
	     * within the skeleton need to be freed though!
	     */
	    __pmFreeResultValues(results[j]);
	else
	    /* For others it is dynamically allocated in __pmDecodeResult or
	     * MakeBadResult
	     */
	    pmFreeResult(results[j]);
    }
    if (results[nAgents] != NULL)
	pmFreeResult(results[nAgents]);
    __pmUnpinPDUBuf(pmidList);
    return 0;
}
예제 #19
0
int
main(int argc, char **argv)
{
    int			c;
    int			sts;
    int			sep = __pmPathSeparator();
    int			use_localtime = 0;
    int			isdaemon = 0;
    char		*pmnsfile = PM_NS_DEFAULT;
    char		*username;
    char		*logfile = "pmlogger.log";
				    /* default log (not archive) file name */
    char		*endnum;
    int			i;
    task_t		*tp;
    optcost_t		ocp;
    __pmFdSet		readyfds;
    char		*p;
    char		*runtime = NULL;
    int	    		ctx;		/* handle corresponding to ctxp below */
    __pmContext  	*ctxp;		/* pmlogger has just this one context */
    int			niter;
    pid_t               target_pid = 0;

    __pmGetUsername(&username);

    /*
     * Warning:
     *		If any of the pmlogger options change, make sure the
     *		corresponding changes are made to pmnewlog when pmlogger
     *		options are passed through from the control file
     */
    while ((c = pmgetopt_r(argc, argv, &opts)) != EOF) {
	switch (c) {

	case 'c':		/* config file */
	    if (access(opts.optarg, F_OK) == 0)
		configfile = opts.optarg;
	    else {
		/* does not exist as given, try the standard place */
		char *sysconf = pmGetConfig("PCP_VAR_DIR");
		int sz = strlen(sysconf)+strlen("/config/pmlogger/")+strlen(opts.optarg)+1;
		if ((configfile = (char *)malloc(sz)) == NULL)
		    __pmNoMem("config file name", sz, PM_FATAL_ERR);
		snprintf(configfile, sz,
			"%s%c" "config%c" "pmlogger%c" "%s",
			sysconf, sep, sep, sep, opts.optarg);
		if (access(configfile, F_OK) != 0) {
		    /* still no good, error handling happens below */
		    free(configfile);
		    configfile = opts.optarg;
		}
	    }
	    break;

	case 'D':	/* debug flag */
	    sts = __pmParseDebug(opts.optarg);
	    if (sts < 0) {
		pmprintf("%s: unrecognized debug flag specification (%s)\n",
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else
		pmDebug |= sts;
	    break;

	case 'h':		/* hostname for PMCD to contact */
	    pmcd_host_conn = opts.optarg;
	    break;

	case 'l':		/* log file name */
	    logfile = opts.optarg;
	    break;

	case 'L':		/* linger if not primary logger */
	    linger = 1;
	    break;

	case 'm':		/* note for port map file */
	    note = opts.optarg;
	    isdaemon = ((strcmp(note, "pmlogger_check") == 0) ||
			(strcmp(note, "pmlogger_daily") == 0));
	    break;

	case 'n':		/* alternative name space file */
	    pmnsfile = opts.optarg;
	    break;

	case 'p':
	    target_pid = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0') {
		pmprintf("%s: invalid process identifier (%s)\n",
			 pmProgname, opts.optarg);
		opts.errors++;
	    } else if (!__pmProcessExists(target_pid)) {
		pmprintf("%s: PID error - no such process (%d)\n",
			 pmProgname, target_pid);
		opts.errors++;
	    }
	    break;

	case 'P':		/* this is the primary pmlogger */
	    primary = 1;
	    isdaemon = 1;
	    break;

	case 'r':		/* report sizes of pmResult records */
	    rflag = 1;
	    break;

	case 's':		/* exit size */
	    sts = ParseSize(opts.optarg, &exit_samples, &exit_bytes, &exit_time);
	    if (sts < 0) {
		pmprintf("%s: illegal size argument '%s' for exit size\n",
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else if (exit_time.tv_sec > 0) {
		__pmAFregister(&exit_time, NULL, run_done_callback);
	    }
	    break;

	case 'T':		/* end time */
	    runtime = opts.optarg;
            break;

	case 't':		/* change default logging interval */
	    if (pmParseInterval(opts.optarg, &delta, &p) < 0) {
		pmprintf("%s: illegal -t argument\n%s", pmProgname, p);
		free(p);
		opts.errors++;
	    }
	    break;

	case 'U':		/* run as named user */
	    username = opts.optarg;
	    isdaemon = 1;
	    break;

	case 'u':		/* flush output buffers after each fetch */
	    /*
	     * all archive write I/O is unbuffered now, so maintain -u
	     * for backwards compatibility only
	     */
	    break;

	case 'v':		/* volume switch after given size */
	    sts = ParseSize(opts.optarg, &vol_switch_samples, &vol_switch_bytes,
			    &vol_switch_time);
	    if (sts < 0) {
		pmprintf("%s: illegal size argument '%s' for volume size\n", 
			pmProgname, opts.optarg);
		opts.errors++;
	    }
	    else if (vol_switch_time.tv_sec > 0) {
		vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, 
						 vol_switch_callback);
            }
	    break;

        case 'V': 
	    archive_version = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0' || archive_version != PM_LOG_VERS02) {
		pmprintf("%s: -V requires a version number of %d\n",
			 pmProgname, PM_LOG_VERS02); 
		opts.errors++;
	    }
	    break;

	case 'x':		/* recording session control fd */
	    rsc_fd = (int)strtol(opts.optarg, &endnum, 10);
	    if (*endnum != '\0' || rsc_fd < 0) {
		pmprintf("%s: -x requires a non-negative numeric argument\n", pmProgname);
		opts.errors++;
	    }
	    else {
		time(&rsc_start);
	    }
	    break;

	case 'y':
	    use_localtime = 1;
	    break;

	case '?':
	default:
	    opts.errors++;
	    break;
	}
    }

    if (primary && pmcd_host != NULL) {
	pmprintf(
	    "%s: -P and -h are mutually exclusive; use -P only when running\n"
	    "%s on the same (local) host as the PMCD to which it connects.\n",
		pmProgname, pmProgname);
	opts.errors++;
    }

    if (!opts.errors && opts.optind != argc - 1) {
	pmprintf("%s: insufficient arguments\n", pmProgname);
	opts.errors++;
    }

    if (opts.errors) {
	pmUsageMessage(&opts);
	exit(1);
    }

    if (rsc_fd != -1 && note == NULL) {
	/* add default note to indicate running with -x */
	static char	xnote[10];
	snprintf(xnote, sizeof(xnote), "-x %d", rsc_fd);
	note = xnote;
    }

    /* if we are running as a daemon, change user early */
    if (isdaemon)
	__pmSetProcessIdentity(username);

    __pmOpenLog("pmlogger", logfile, stderr, &sts);
    if (sts != 1) {
	fprintf(stderr, "%s: Warning: log file (%s) creation failed\n", pmProgname, logfile);
	/* continue on ... writing to stderr */
    }

    /* base name for archive is here ... */
    archBase = argv[opts.optind];

    if (pmcd_host_conn == NULL)
	pmcd_host_conn = "local:";

    /* initialise access control */
    if (__pmAccAddOp(PM_OP_LOG_ADV) < 0 ||
	__pmAccAddOp(PM_OP_LOG_MAND) < 0 ||
	__pmAccAddOp(PM_OP_LOG_ENQ) < 0) {
	fprintf(stderr, "%s: access control initialisation failed\n", pmProgname);
	exit(1);
    }

    if (pmnsfile != PM_NS_DEFAULT) {
	if ((sts = pmLoadASCIINameSpace(pmnsfile, 1)) < 0) {
	    fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts));
	    exit(1);
	}
    }

    if ((ctx = pmNewContext(PM_CONTEXT_HOST, pmcd_host_conn)) < 0) {
	fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, pmcd_host_conn, pmErrStr(ctx));
	exit(1);
    }
    pmcd_host = (char *)pmGetContextHostName(ctx);
    if (strlen(pmcd_host) == 0) {
	fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n",
	    pmProgname, ctx);
	exit(1);
    }

    if (rsc_fd == -1) {
	/* no -x, so register client id with pmcd */
	__pmSetClientIdArgv(argc, argv);
    }

    /*
     * discover fd for comms channel to PMCD ... 
     */
    if ((ctxp = __pmHandleToPtr(ctx)) == NULL) {
	fprintf(stderr, "%s: botch: __pmHandleToPtr(%d) returns NULL!\n", pmProgname, ctx);
	exit(1);
    }
    pmcdfd = ctxp->c_pmcd->pc_fd;
    PM_UNLOCK(ctxp->c_lock);

    if (configfile != NULL) {
	if ((yyin = fopen(configfile, "r")) == NULL) {
	    fprintf(stderr, "%s: Cannot open config file \"%s\": %s\n",
		pmProgname, configfile, osstrerror());
	    exit(1);
	}
    }
    else {
	/* **ANY** Lex would read from stdin automagically */
	configfile = "<stdin>";
    }

    __pmOptFetchGetParams(&ocp);
    ocp.c_scope = 1;
    __pmOptFetchPutParams(&ocp);

    /* prevent early timer events ... */
    __pmAFblock();

    if (yyparse() != 0)
	exit(1);
    if (configfile != NULL)
	fclose(yyin);
    yyend();

#ifdef PCP_DEBUG
    fprintf(stderr, "Config parsed\n");
#endif

    fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n",
            primary ? "primary " : "", pmcd_host, pmcd_host_conn);

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOG) {
	fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n",
		ocp.c_pmid, ocp.c_indom, ocp.c_fetch, ocp.c_scope);

	fprintf(stderr, "\nAfter loading config ...\n");
	for (tp = tasklist; tp != NULL; tp = tp->t_next) {
	    if (tp->t_numvalid == 0)
		continue;
	    fprintf(stderr, " state: %sin log, %savail, %s, %s",
		PMLC_GET_INLOG(tp->t_state) ? "" : "not ",
		PMLC_GET_AVAIL(tp->t_state) ? "" : "un",
		PMLC_GET_MAND(tp->t_state) ? "mand" : "adv",
		PMLC_GET_ON(tp->t_state) ? "on" : "off");
	    fprintf(stderr, " delta: %ld usec", 
			(long)1000 * tp->t_delta.tv_sec + tp->t_delta.tv_usec);
	    fprintf(stderr, " numpmid: %d\n", tp->t_numpmid);
	    for (i = 0; i < tp->t_numpmid; i++) {
		fprintf(stderr, "  %s (%s):\n", pmIDStr(tp->t_pmidlist[i]), tp->t_namelist[i]);
	    }
	    __pmOptFetchDump(stderr, tp->t_fetch);
	}
    }
#endif

    if (!primary && tasklist == NULL && !linger) {
	fprintf(stderr, "Nothing to log, and not the primary logger instance ... good-bye\n");
	exit(1);
    }

    if ((sts = __pmLogCreate(pmcd_host, archBase, archive_version, &logctl)) < 0) {
	fprintf(stderr, "__pmLogCreate: %s\n", pmErrStr(sts));
	exit(1);
    }
    else {
	/*
	 * try and establish $TZ from the remote PMCD ...
	 * Note the label record has been set up, but not written yet
	 */
	char		*name = "pmcd.timezone";
	pmID		pmid;
	pmResult	*resp;

	__pmtimevalNow(&epoch);
	sts = pmUseContext(ctx);

	if (sts >= 0)
	    sts = pmLookupName(1, &name, &pmid);
	if (sts >= 0)
	    sts = pmFetch(1, &pmid, &resp);
	if (sts >= 0) {
	    if (resp->vset[0]->numval > 0) { /* pmcd.timezone present */
		strcpy(logctl.l_label.ill_tz, resp->vset[0]->vlist[0].value.pval->vbuf);
		/* prefer to use remote time to avoid clock drift problems */
		epoch = resp->timestamp;		/* struct assignment */
		if (! use_localtime)
		    pmNewZone(logctl.l_label.ill_tz);
	    }
#ifdef PCP_DEBUG
	    else if (pmDebug & DBG_TRACE_LOG) {
		fprintf(stderr,
			"main: Could not get timezone from host %s\n",
			pmcd_host);
	    }
#endif
	    pmFreeResult(resp);
	}
    }

    /* do ParseTimeWindow stuff for -T */
    if (runtime) {
        struct timeval res_end;    /* time window end */
        struct timeval start;
        struct timeval end;
        struct timeval last_delta;
        char *err_msg;             /* parsing error message */
        time_t now;
        struct timeval now_tv;

        time(&now);
        now_tv.tv_sec = now;
        now_tv.tv_usec = 0; 

        start = now_tv;
        end.tv_sec = INT_MAX;
        end.tv_usec = INT_MAX;
        sts = __pmParseTime(runtime, &start, &end, &res_end, &err_msg);
        if (sts < 0) {
	    fprintf(stderr, "%s: illegal -T argument\n%s", pmProgname, err_msg);
            exit(1);
        }

        last_delta = res_end;
        tsub(&last_delta, &now_tv);
	__pmAFregister(&last_delta, NULL, run_done_callback);

        last_stamp = res_end;
    }

    fprintf(stderr, "Archive basename: %s\n", archBase);

#ifndef IS_MINGW
    /* detach yourself from the launching process */
    if (isdaemon)
        setpgid(getpid(), 0);
#endif

    /* set up control port */
    init_ports();
    __pmFD_ZERO(&fds);
    for (i = 0; i < CFD_NUM; ++i) {
	if (ctlfds[i] >= 0)
	    __pmFD_SET(ctlfds[i], &fds);
    }
#ifndef IS_MINGW
    __pmFD_SET(pmcdfd, &fds);
#endif
    if (rsc_fd != -1)
	__pmFD_SET(rsc_fd, &fds);
    numfds = maxfd() + 1;

    if ((sts = do_preamble()) < 0)
	fprintf(stderr, "Warning: problem writing archive preamble: %s\n",
	    pmErrStr(sts));

    sts = 0;		/* default exit status */

    parse_done = 1;	/* enable callback processing */
    __pmAFunblock();

    for ( ; ; ) {
	int		nready;

#ifdef PCP_DEBUG
	if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) {
	    fprintf(stderr, "before __pmSelectRead(%d,...): run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, run_done_alarm, vol_switch_alarm, log_alarm);
	}
#endif

	niter = 0;
	while (log_alarm && niter++ < 10) {
	    __pmAFblock();
	    log_alarm = 0;
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: log_alarm\n");
#endif
	    for (tp = tasklist; tp != NULL; tp = tp->t_next) {
		if (tp->t_alarm) {
		    tp->t_alarm = 0;
		    do_work(tp);
		}
	    }
	    __pmAFunblock();
	}

	if (vol_switch_alarm) {
	    __pmAFblock();
	    vol_switch_alarm = 0;
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: vol_switch_alarm\n");
#endif
	    newvolume(VOL_SW_TIME);
	    __pmAFunblock();
	}

	if (run_done_alarm) {
#ifdef PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL2)
		fprintf(stderr, "delayed callback: run_done_alarm\n");
#endif
	    run_done(0, NULL);
	    /*NOTREACHED*/
	}

	__pmFD_COPY(&readyfds, &fds);
	nready = __pmSelectRead(numfds, &readyfds, NULL);

#ifdef PCP_DEBUG
	if ((pmDebug & DBG_TRACE_APPL2) && (pmDebug & DBG_TRACE_DESPERATE)) {
	    fprintf(stderr, "__pmSelectRead(%d,...) done: nready=%d run_done_alarm=%d vol_switch_alarm=%d log_alarm=%d\n", numfds, nready, run_done_alarm, vol_switch_alarm, log_alarm);
	}
#endif

	__pmAFblock();
	if (nready > 0) {

	    /* handle request on control port */
	    for (i = 0; i < CFD_NUM; ++i) {
		if (ctlfds[i] >= 0 && __pmFD_ISSET(ctlfds[i], &readyfds)) {
		    if (control_req(ctlfds[i])) {
			/* new client has connected */
			__pmFD_SET(clientfd, &fds);
			if (clientfd >= numfds)
			    numfds = clientfd + 1;
		    }
		}
	    }
	    if (clientfd >= 0 && __pmFD_ISSET(clientfd, &readyfds)) {
		/* process request from client, save clientfd in case client
		 * closes connection, resetting clientfd to -1
		 */
		int	fd = clientfd;

		if (client_req()) {
		    /* client closed connection */
		    __pmFD_CLR(fd, &fds);
		    __pmCloseSocket(clientfd);
		    clientfd = -1;
		    numfds = maxfd() + 1;
		    qa_case = 0;
		}
	    }
#ifndef IS_MINGW
	    if (pmcdfd >= 0 && __pmFD_ISSET(pmcdfd, &readyfds)) {
		/*
		 * do not expect this, given synchronous commumication with the
		 * pmcd ... either pmcd has terminated, or bogus PDU ... or its
		 * Win32 and we are operating under the different conditions of
		 * our AF.c implementation there, which has to deal with a lack
		 * of signal support on Windows - race condition exists between
		 * this check and the async event timer callback.
		 */
		__pmPDU		*pb;
		__pmPDUHdr	*php;
		sts = __pmGetPDU(pmcdfd, ANY_SIZE, TIMEOUT_NEVER, &pb);
		if (sts <= 0) {
		    if (sts < 0)
			fprintf(stderr, "Error: __pmGetPDU: %s\n", pmErrStr(sts));
		    disconnect(sts);
		}
		else {
		    php = (__pmPDUHdr *)pb;
		    fprintf(stderr, "Error: Unsolicited %s PDU from PMCD\n",
			__pmPDUTypeStr(php->type));
		    disconnect(PM_ERR_IPC);
		}
		if (sts > 0)
		    __pmUnpinPDUBuf(pb);
	    }
#endif
	    if (rsc_fd >= 0 && __pmFD_ISSET(rsc_fd, &readyfds)) {
		/*
		 * some action on the recording session control fd
		 * end-of-file means launcher has quit, otherwise we
		 * expect one of these commands
		 *	V<number>\n	- version
		 *	F<folio>\n	- folio name
		 *	P<name>\n	- launcher's name
		 *	R\n		- launcher can replay
		 *	D\n		- detach from launcher
		 *	Q\n		- quit pmlogger
		 */
		char	rsc_buf[MAXPATHLEN];
		char	*rp = rsc_buf;
		char	myc;
		int	fake_x = 0;

		for (rp = rsc_buf; ; rp++) {
		    if (read(rsc_fd, &myc, 1) <= 0) {
#ifdef PCP_DEBUG
			if (pmDebug & DBG_TRACE_APPL2)
			    fprintf(stderr, "recording session control: eof\n");
#endif
			if (rp != rsc_buf) {
			    *rp = '\0';
			    fprintf(stderr, "Error: incomplete recording session control message: \"%s\"\n", rsc_buf);
			}
			fake_x = 1;
			break;
		    }
		    if (rp >= &rsc_buf[MAXPATHLEN]) {
			fprintf(stderr, "Error: absurd recording session control message: \"%100.100s ...\"\n", rsc_buf);
			fake_x = 1;
			break;
		    }
		    if (myc == '\n') {
			*rp = '\0';
			break;
		    }
		    *rp = myc;
		}

#ifdef PCP_DEBUG
		if (pmDebug & DBG_TRACE_APPL2) {
		    if (fake_x == 0)
			fprintf(stderr, "recording session control: \"%s\"\n", rsc_buf);
		}
#endif

		if (fake_x)
		    do_dialog('X');
		else if (strcmp(rsc_buf, "Q") == 0 ||
		         strcmp(rsc_buf, "D") == 0 ||
			 strcmp(rsc_buf, "?") == 0)
		    do_dialog(rsc_buf[0]);
		else if (rsc_buf[0] == 'F')
		    folio_name = strdup(&rsc_buf[1]);
		else if (rsc_buf[0] == 'P')
		    rsc_prog = strdup(&rsc_buf[1]);
		else if (strcmp(rsc_buf, "R") == 0)
		    rsc_replay = 1;
		else if (rsc_buf[0] == 'V' && rsc_buf[1] == '0') {
		    /*
		     * version 0 of the recording session control ...
		     * this is all we grok at the moment
		     */
		    ;
		}
		else {
		    fprintf(stderr, "Error: illegal recording session control message: \"%s\"\n", rsc_buf);
		    do_dialog('X');
		}
	    }
	}
	else if (vol_switch_flag) {
	    newvolume(VOL_SW_SIGHUP);
	    vol_switch_flag = 0;
	}
	else if (nready < 0 && neterror() != EINTR)
	    fprintf(stderr, "Error: select: %s\n", netstrerror());

	__pmAFunblock();

	if (target_pid && !__pmProcessExists(target_pid))
	    exit(EXIT_SUCCESS);

	if (exit_code)
	    break;
    }
    exit(exit_code);
}
예제 #20
0
파일: pmcd.c 프로젝트: andyvand/cygpcpfans
/* Process I/O on file descriptors from agents that were marked as not ready
 * to handle PDUs.
 */
static int
HandleReadyAgents(__pmFdSet *readyFds)
{
    int		i, s, sts;
    int		fd;
    int		reason;
    int		ready = 0;
    AgentInfo	*ap;
    __pmPDU	*pb;

    for (i = 0; i < nAgents; i++) {
	ap = &agent[i];
	if (ap->status.notReady) {
	    fd = ap->outFd;
	    if (__pmFD_ISSET(fd, readyFds)) {
		int		pinpdu;

		/* Expect an error PDU containing PM_ERR_PMDAREADY */
		reason = AT_COMM;	/* most errors are protocol failures */
		pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb);
		if (sts > 0)
		    pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff));
		if (sts == PDU_ERROR) {
		    s = __pmDecodeError(pb, &sts);
		    if (s < 0) {
			sts = s;
			pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_ERROR, sts);
		    }
		    else {
			/* sts is the status code from the error PDU */
			if (pmDebug & DBG_TRACE_APPL0)
			    __pmNotifyErr(LOG_INFO,
				 "%s agent (not ready) sent %s status(%d)\n",
				 ap->pmDomainLabel,
				 sts == PM_ERR_PMDAREADY ?
					     "ready" : "unknown", sts);
			if (sts == PM_ERR_PMDAREADY) {
			    ap->status.notReady = 0;
			    sts = 1;
			    ready++;
			}
			else {
			    pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_ERROR, sts);
			    sts = PM_ERR_IPC;
			}
		    }
		}
		else {
		    if (sts < 0)
			pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts);
		    else
			pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_ERROR, sts);
 		    sts = PM_ERR_IPC; /* Wrong PDU type */
		}
		if (pinpdu > 0)
		    __pmUnpinPDUBuf(pb);

		if (ap->ipcType != AGENT_DSO && sts <= 0)
		    CleanupAgent(ap, reason, fd);
	    }
	}
    }
    return ready;
}
예제 #21
0
파일: p_profile.c 프로젝트: Aconex/pcp
int
__pmSendProfile(int fd, int from, int ctxnum, __pmProfile *instprof)
{
    __pmInDomProfile	*prof, *p_end;
    profile_t		*pduProfile;
    instprof_t		*pduInstProf;
    __pmPDU		*p;
    size_t		need;
    __pmPDU		*pdubuf;
    int			sts;

    /* work out how much space we need and then alloc a pdu buf */
    need = sizeof(profile_t) + instprof->profile_len * sizeof(instprof_t);
    for (prof = instprof->profile, p_end = prof + instprof->profile_len;
	 prof < p_end;
	 prof++)
	need += prof->instances_len * sizeof(int);

    if ((pdubuf = __pmFindPDUBuf((int)need)) == NULL)
	return -oserror();

    p = (__pmPDU *)pdubuf;

    /* First the profile itself */
    pduProfile = (profile_t *)p;
    pduProfile->hdr.len = (int)need;
    pduProfile->hdr.type = PDU_PROFILE;
    /* 
     * note: context id may be sent twice due to protocol evolution and
     * backwards compatibility issues
     */
    pduProfile->hdr.from = from;
    pduProfile->ctxnum = htonl(ctxnum);
    pduProfile->g_state = htonl(instprof->state);
    pduProfile->numprof = htonl(instprof->profile_len);
    pduProfile->pad = 0;

    p += sizeof(profile_t) / sizeof(__pmPDU);

    if (instprof->profile_len) {
	/* Next all the profile entries (if any) in one block */
	for (prof = instprof->profile, p_end = prof + instprof->profile_len;
	     prof < p_end;
	     prof++) {
	    pduInstProf = (instprof_t *)p;
	    pduInstProf->indom = __htonpmInDom(prof->indom);
	    pduInstProf->state = htonl(prof->state);
	    pduInstProf->numinst = htonl(prof->instances_len);
	    pduInstProf->pad = 0;
	    p += sizeof(instprof_t) / sizeof(__pmPDU);
	}

	/* and then all the instances */
	for (prof = instprof->profile, p_end = prof+instprof->profile_len;
	     prof < p_end;
	     prof++) {
	    int j;

	    /* and then the instances themselves (if any) */
	    for (j = 0; j < prof->instances_len; j++, p++)
		*p = htonl(prof->instances[j]);
	}
    }
    sts = __pmXmitPDU(fd, pdubuf);
    __pmUnpinPDUBuf(pdubuf);
    return sts;
}
예제 #22
0
파일: pmproxy.c 프로젝트: aeppert/pcp
/* Determine which clients (if any) have sent data to the server and handle it
 * as required.
 */
void
HandleInput(__pmFdSet *fdsPtr)
{
    int		i, sts;
    __pmPDU	*pb;
    ClientInfo	*cp;

    /* input from clients */
    for (i = 0; i < nClients; i++) {
	if (!client[i].status.connected || !__pmFD_ISSET(client[i].fd, fdsPtr))
	    continue;

	cp = &client[i];

	sts = __pmGetPDU(cp->fd, LIMIT_SIZE, 0, &pb);
	if (sts <= 0) {
	    CleanupClient(cp, sts);
	    continue;
	}

	/* We *must* see a credentials PDU as the first PDU */
	if (!cp->status.allowed) {
	    sts = VerifyClient(cp, pb);
	    __pmUnpinPDUBuf(pb);
	    if (sts < 0) {
		CleanupClient(cp, sts);
		continue;
	    }
	    cp->status.allowed = 1;
	    continue;
	}

	sts = __pmXmitPDU(cp->pmcd_fd, pb);
	__pmUnpinPDUBuf(pb);
	if (sts <= 0) {
	    CleanupClient(cp, sts);
	    continue;
	}
    }

    /* input from pmcds */
    for (i = 0; i < nClients; i++) {
	if (!client[i].status.connected ||
	    !__pmFD_ISSET(client[i].pmcd_fd, fdsPtr))
	    continue;

	cp = &client[i];

	sts = __pmGetPDU(cp->pmcd_fd, ANY_SIZE, 0, &pb);
	if (sts <= 0) {
	    CleanupClient(cp, sts);
	    continue;
	}

	sts = __pmXmitPDU(cp->fd, pb);
	__pmUnpinPDUBuf(pb);
	if (sts <= 0) {
	    CleanupClient(cp, sts);
	    continue;
	}
    }
}
예제 #23
0
파일: preamble.c 프로젝트: Aconex/pcp
int
do_preamble(void)
{
    int		sts;
    int		i;
    int		j;
    pid_t	mypid = getpid();
    pmResult	*res;
    __pmPDU	*pb;
    pmAtomValue	atom;
    __pmTimeval	tmp;
    char	path[MAXPATHLEN];
    char	host[MAXHOSTNAMELEN];
    int		free_cp;

    /* start to build the pmResult */
    res = (pmResult *)malloc(sizeof(pmResult) + (n_metric - 1) * sizeof(pmValueSet *));
    if (res == NULL)
	return -oserror();

    res->numpmid = n_metric;
    last_stamp = res->timestamp = epoch;	/* struct assignment */
    tmp.tv_sec = (__int32_t)epoch.tv_sec;
    tmp.tv_usec = (__int32_t)epoch.tv_usec;

    for (i = 0; i < n_metric; i++)
	res->vset[i] = NULL;

    for (i = 0; i < n_metric; i++) {
	res->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet));
	if (res->vset[i] == NULL) {
	    sts = -oserror();
	    goto done;
	}
	res->vset[i]->pmid = desc[i].pmid;
	res->vset[i]->numval = 1;
	/* special case for each value 0 .. n_metric-1 */
	free_cp = 0;
	if (desc[i].pmid == PMID(2,3,3)) {
	    __pmHostEnt *servInfo;
	    /* my fully qualified hostname, cloned from the pmcd PMDA */
	    (void)gethostname(host, MAXHOSTNAMELEN);
	    host[MAXHOSTNAMELEN-1] = '\0';
	    if ((servInfo = __pmGetAddrInfo(host)) == NULL)
		atom.cp = host;
	    else {
		atom.cp = __pmHostEntGetName(servInfo);
		__pmHostEntFree(servInfo);
		if (atom.cp == NULL)
		    atom.cp = host;
		else
		    free_cp = 1;
	    }
	 }
	 else if (desc[i].pmid == PMID(2,3,0)) {
	    /* my control port number, from ports.c */
	    atom.l = ctlport;
	 }
	 else if (desc[i].pmid == PMID(2,3,2)) {
	    /*
	     * the full pathname to the base of the archive, cloned
	     * from GetPort() in ports.c
	     */
	    if (__pmAbsolutePath(archBase))
		atom.cp = archBase;
	    else {
		if (getcwd(path, MAXPATHLEN) == NULL)
		    atom.cp = archBase;
		else {
		    strcat(path, "/");
		    strcat(path, archBase);
		    atom.cp = path;
		}
	    }
	}

	sts = __pmStuffValue(&atom, &res->vset[i]->vlist[0], desc[i].type);
	if (free_cp)
	    free(atom.cp);
	if (sts < 0)
	    goto done;
	res->vset[i]->vlist[0].inst = (int)mypid;
	res->vset[i]->valfmt = sts;
    }

    if ((sts = __pmEncodeResult(fileno(logctl.l_mfp), res, &pb)) < 0)
	goto done;

    __pmOverrideLastFd(fileno(logctl.l_mfp));	/* force use of log version */
    /* and start some writing to the archive log files ... */
    sts = __pmLogPutResult2(&logctl, pb);
    __pmUnpinPDUBuf(pb);
    if (sts < 0)
	goto done;

    for (i = 0; i < n_metric; i++) {
	if ((sts = __pmLogPutDesc(&logctl, &desc[i], 1, &names[i])) < 0)
	    goto done;
	if (desc[i].indom == PM_INDOM_NULL)
	    continue;
	for (j = 0; j < i; j++) {
	    if (desc[i].indom == desc[j].indom)
		break;
	}
	if (j == i) {
	    /* need indom ... force one with my PID as the only instance */
	    int		*instid;
	    char	**instname;

	    if ((instid = (int *)malloc(sizeof(*instid))) == NULL) {
		sts = -oserror();
		goto done;
	    }
	    *instid = (int)mypid;
	    snprintf(path, sizeof(path), "%" FMT_PID, mypid);
	    if ((instname = (char **)malloc(sizeof(char *)+strlen(path)+1)) == NULL) {
		free(instid);
		sts = -oserror();
		goto done;
	    }
	    /*
	     * this _is_ correct ... instname[] is a one element array
	     * with the string value immediately following
	     */
	    instname[0] = (char *)&instname[1];
            strcpy(instname[0], path);
	    /*
	     * Note.	DO NOT free instid and instname ... they get hidden
	     *		away in addindom() below __pmLogPutInDom()
	     */
	    if ((sts = __pmLogPutInDom(&logctl, desc[i].indom, &tmp, 1, instid, instname)) < 0)
		goto done;
	}
    }

    /* fudge the temporal index */
    fseek(logctl.l_mfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET);
    fseek(logctl.l_mdfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET);
    __pmLogPutIndex(&logctl, &tmp);
    fseek(logctl.l_mfp, 0L, SEEK_END);
    fseek(logctl.l_mdfp, 0L, SEEK_END);
    sts = 0;

    /*
     * and now free stuff
     */
done:
    for (i = 0; i < n_metric; i++) {
	if (res->vset[i] != NULL)
	    free(res->vset[i]);
    }
    free(res);

    return sts;
}
예제 #24
0
static int
__pmAuthServerNegotiation(int fd, int ssf, __pmHashCtl *attrs)
{
    int sts, saslsts;
    int pinned, length, count;
    char *payload, *offset;
    sasl_conn_t *sasl_conn;
    __pmPDU *pb;

    if (pmDebugOptions.auth)
	fprintf(stderr, "__pmAuthServerNegotiation(fd=%d, ssf=%d)\n",
		fd, ssf);

    if ((sasl_conn = (sasl_conn_t *)__pmGetUserAuthData(fd)) == NULL)
        return -EINVAL;

    /* setup all the security properties for this connection */
    if ((sts = __pmAuthServerSetProperties(sasl_conn, ssf)) < 0)
	return sts;

    saslsts = sasl_listmech(sasl_conn,
			    NULL, NULL, " ", NULL,
                            (const char **)&payload,
                            (unsigned int *)&length,
                            &count);
    if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) {
	pmNotifyErr(LOG_ERR, "Generating client mechanism list: %s",
			sasl_errstring(saslsts, NULL, NULL));
	return __pmSecureSocketsError(saslsts);
    }
    if (pmDebugOptions.auth)
	fprintf(stderr, "__pmAuthServerNegotiation - sending mechanism list "
		"(%d items, %d bytes): \"%s\"\n", count, length, payload);

    if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0)
	return sts;

    if (pmDebugOptions.auth)
	fprintf(stderr, "__pmAuthServerNegotiation - wait for mechanism\n");

    sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb);
    if (sts == PDU_AUTH) {
        sts = __pmDecodeAuth(pb, &count, &payload, &length);
        if (sts >= 0) {
	    for (count = 0; count < length; count++) {
		if (payload[count] == '\0')
		    break;
	    }
	    if (count < length)	{  /* found an initial response */
		length = length - count - 1;
		offset = payload + count + 1;
	    } else {
		length = 0;
		offset = NULL;
	    }

	    saslsts = sasl_server_start(sasl_conn, payload,
				offset, length,
				(const char **)&payload,
				(unsigned int *)&length);
	    if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) {
		sts = __pmSecureSocketsError(saslsts);
		if (pmDebugOptions.auth)
		    fprintf(stderr, "sasl_server_start failed: %d (%s)\n",
				    saslsts, pmErrStr(sts));
	    } else {
		if (pmDebugOptions.auth)
		    fprintf(stderr, "sasl_server_start success: sts=%s\n",
			    saslsts == SASL_CONTINUE ? "continue" : "ok");
	    }
	}
    }
    else if (sts == PDU_ERROR)
	__pmDecodeError(pb, &sts);
    else if (sts != PM_ERR_TIMEOUT)
	sts = PM_ERR_IPC;

    if (pinned > 0)
	__pmUnpinPDUBuf(pb);
    if (sts < 0)
	return sts;

    if (pmDebugOptions.auth)
	fprintf(stderr, "__pmAuthServerNegotiation method negotiated\n");

    while (saslsts == SASL_CONTINUE) {
	if (!payload) {
	    pmNotifyErr(LOG_ERR, "No SASL data to send");
	    sts = -EINVAL;
	    break;
	}
	if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0)
	    break;

	if (pmDebugOptions.auth)
	    fprintf(stderr, "__pmAuthServerNegotiation awaiting response\n");

	sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb);
	if (sts == PDU_AUTH) {
	    sts = __pmDecodeAuth(pb, &count, &payload, &length);
	    if (sts >= 0) {
		sts = saslsts = sasl_server_step(sasl_conn, payload, length,
                                                 (const char **)&payload,
                                                 (unsigned int *)&length);
		if (sts != SASL_OK && sts != SASL_CONTINUE) {
		    sts = __pmSecureSocketsError(sts);
		    break;
		}
		if (pmDebugOptions.auth) {
		    fprintf(stderr, "__pmAuthServerNegotiation"
				    " step recv (%d bytes)\n", length);
		}
	    }
	}
	else if (sts == PDU_ERROR)
	    __pmDecodeError(pb, &sts);
	else if (sts != PM_ERR_TIMEOUT)
	    sts = PM_ERR_IPC;

	if (pinned > 0)
	    __pmUnpinPDUBuf(pb);
	if (sts < 0)
	    break;
    }

    if (sts < 0) {
	if (pmDebugOptions.auth)
	    fprintf(stderr, "__pmAuthServerNegotiation loop failed: %d\n", sts);
	return sts;
    }

    return __pmAuthServerSetAttributes(sasl_conn, attrs);
}
예제 #25
0
파일: p_instance.c 프로젝트: ColeJackes/pcp
int
__pmSendInstance(int fd, int from, __pmInResult *result)
{
    instance_t	*rp;
    instlist_t		*ip;
    int			need;
    int			i;
    int			j;
    int			sts;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_INDOM)
	__pmDumpInResult(stderr, result);
#endif

    need = sizeof(*rp) - sizeof(rp->rest);
    /* instlist_t + name rounded up to a __pmPDU boundary */
    for (i = 0; i < result->numinst; i++) {
	need += sizeof(*ip) - sizeof(ip->name);
	if (result->namelist != NULL)
	    need += PM_PDU_SIZE_BYTES(strlen(result->namelist[i]));
    }

    if ((rp = (instance_t *)__pmFindPDUBuf(need)) == NULL)
	return -oserror();
    rp->hdr.len = need;
    rp->hdr.type = PDU_INSTANCE;
    rp->hdr.from = from;
    rp->indom = __htonpmInDom(result->indom);
    rp->numinst = htonl(result->numinst);

    for (i = j = 0; i < result->numinst; i++) {
	ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)];
	if (result->instlist != NULL)
	    ip->inst = htonl(result->instlist[i]);
	else
	    /* weird, but this is going to be ignored at the other end */
	    ip->inst = htonl(PM_IN_NULL);
	if (result->namelist != NULL) {
	    ip->namelen = (int)strlen(result->namelist[i]);
	    memcpy((void *)ip->name, (void *)result->namelist[i], ip->namelen);
	    if ((ip->namelen % sizeof(__pmPDU)) != 0) {
                /* clear the padding bytes, lest they contain garbage */
		int	pad;
		char	*padp = ip->name + ip->namelen;
		for (pad = sizeof(__pmPDU) - 1; pad >= (ip->namelen % sizeof(__pmPDU)); pad--)
		    *padp++ = '~';	/* buffer end */
	    }
	    j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen);
	    ip->namelen = htonl(ip->namelen);
	}
	else {
	    ip->namelen = 0;
	    j += sizeof(*ip) - sizeof(ip->name);
	}
    }

    sts = __pmXmitPDU(fd, (__pmPDU *)rp);
    __pmUnpinPDUBuf(rp);
    return sts;
}