int send_kvvec(int sd, struct kvvec *kvv) { int ret; struct kvvec_buf *kvvb; /* * key=value, separated by nul bytes and two nul's * delimit one message from another. We need to cut * one from MSG_DELIM_LEN here though, since nul is * added unconditionally after each value as well * and we'd otherwise run into an off-by-one when * parsing the messages back into sensible order. */ kvvb = kvvec2buf(kvv, KV_SEP, PAIR_SEP, MSG_DELIM_LEN_SEND); if (!kvvb) { /* * XXX: do *something* sensible here to let the * master know we failed, although the most likely * reason is OOM, in which case the OOM-slayer will * probably kill us sooner or later. */ return 0; } /* use bufsize here, as it gets us the nul string delimiter */ ret = write(sd, kvvb->buf, kvvb->bufsize); free(kvvb->buf); free(kvvb); return ret; }
/* * Handles adding the command and macros to the kvvec, * as well as shipping the command off to a designated * worker */ static int wproc_run_job(struct wproc_job *job, nagios_macros *mac) { static struct kvvec kvv = KVVEC_INITIALIZER; struct kvvec_buf *kvvb; struct kvvec *env_kvvp = NULL; struct kvvec_buf *env_kvvb = NULL; struct wproc_worker *wp; int ret, result = OK; if (!job || !job->wp) return ERROR; wp = job->wp; if (!kvvec_init(&kvv, 4)) /* job_id, type, command and timeout */ return ERROR; kvvec_addkv(&kvv, "job_id", (char *)mkstr("%d", job->id)); kvvec_addkv(&kvv, "type", (char *)mkstr("%d", job->type)); kvvec_addkv(&kvv, "command", job->command); kvvec_addkv(&kvv, "timeout", (char *)mkstr("%u", job->timeout)); /* Add the macro environment variables */ if(mac) { env_kvvp = macros_to_kvv(mac); if(NULL != env_kvvp) { env_kvvb = kvvec2buf(env_kvvp, '=', '\n', 0); if(NULL == env_kvvb) { kvvec_destroy(env_kvvp, KVVEC_FREE_KEYS); } else { kvvec_addkv_wlen(&kvv, "env", strlen("env"), env_kvvb->buf, env_kvvb->buflen); } } } kvvb = build_kvvec_buf(&kvv); ret = write(wp->sd, kvvb->buf, kvvb->bufsize); if (ret != (int)kvvb->bufsize) { logit(NSLOG_RUNTIME_ERROR, TRUE, "wproc: '%s' seems to be choked. ret = %d; bufsize = %lu: errno = %d (%s)\n", wp->name, ret, kvvb->bufsize, errno, strerror(errno)); destroy_job(job); result = ERROR; } else { wp->jobs_running++; wp->jobs_started++; loadctl.jobs_running++; } if(NULL != env_kvvp) kvvec_destroy(env_kvvp, KVVEC_FREE_KEYS); if(NULL != env_kvvb) { free(env_kvvb->buf); free(env_kvvb); } free(kvvb->buf); free(kvvb); return result; }
struct kvvec_buf *build_kvvec_buf(struct kvvec *kvv) { struct kvvec_buf *kvvb; /* * key=value, separated by PAIR_SEP and messages * delimited by MSG_DELIM */ kvvb = kvvec2buf(kvv, KV_SEP, PAIR_SEP, MSG_DELIM_LEN); if (!kvvb) { return NULL; } memcpy(kvvb->buf + (kvvb->bufsize - MSG_DELIM_LEN), MSG_DELIM, MSG_DELIM_LEN); return kvvb; }
int main(int argc, char **argv) { int i, j; struct kvvec *kvv, *kvv2, *kvv3; struct kvvec_buf *kvvb, *kvvb2; struct kvvec k = KVVEC_INITIALIZER; t_set_colors(0); t_start("key/value vector tests"); kvv = kvvec_create(1); kvv2 = kvvec_create(1); kvv3 = kvvec_create(1); add_vars(kvv, test_data, 1239819); add_vars(kvv, (const char **)argv + 1, argc - 1); kvvec_sort(kvv); kvvec_foreach(kvv, NULL, walker); /* kvvec2buf -> buf2kvvec -> kvvec2buf -> buf2kvvec conversion */ kvvb = kvvec2buf(kvv, KVSEP, PAIRSEP, OVERALLOC); kvv3 = buf2kvvec(kvvb->buf, kvvb->buflen, KVSEP, PAIRSEP, KVVEC_COPY); kvvb2 = kvvec2buf(kvv3, KVSEP, PAIRSEP, OVERALLOC); buf2kvvec_prealloc(kvv2, kvvb->buf, kvvb->buflen, KVSEP, PAIRSEP, KVVEC_ASSIGN); kvvec_foreach(kvv2, kvv, walker); kvvb = kvvec2buf(kvv, KVSEP, PAIRSEP, OVERALLOC); test(kvv->kv_pairs == kvv2->kv_pairs, "pairs should be identical"); for (i = 0; i < kvv->kv_pairs; i++) { struct key_value *kv1, *kv2; kv1 = &kvv->kv[i]; if (i >= kvv2->kv_pairs) { t_fail("missing var %d in kvv2", i); printf("[%s=%s] (%d+%d)\n", kv1->key, kv1->value, kv1->key_len, kv1->value_len); continue; } kv2 = &kvv2->kv[i]; if (!test(!kv_compare(kv1, kv2), "kv pair %d must match", i)) { printf("%d failed: [%s=%s] (%d+%d) != [%s=%s (%d+%d)]\n", i, kv1->key, kv1->value, kv1->key_len, kv1->value_len, kv2->key, kv2->value, kv2->key_len, kv2->value_len); } } test(kvvb2->buflen == kvvb->buflen, "buflens must match"); test(kvvb2->bufsize == kvvb->bufsize, "bufsizes must match"); if (kvvb2->buflen == kvvb->buflen && kvvb2->bufsize == kvvb->bufsize && !memcmp(kvvb2->buf, kvvb->buf, kvvb->bufsize)) { t_pass("kvvec -> buf -> kvvec conversion works flawlessly"); } else { t_fail("kvvec -> buf -> kvvec conversion failed :'("); } free(kvvb->buf); free(kvvb); free(kvvb2->buf); free(kvvb2); kvvec_destroy(kvv, 1); kvvec_destroy(kvv3, KVVEC_FREE_ALL); for (j = 0; pair_term_missing[j]; j++) { buf2kvvec_prealloc(&k, strdup(pair_term_missing[j]), strlen(pair_term_missing[j]), '=', ';', KVVEC_COPY); for (i = 0; i < k.kv_pairs; i++) { struct key_value *kv = &k.kv[i]; test(kv->key_len == kv->value_len, "%d.%d; key_len=%d; value_len=%d (%s = %s)", j, i, kv->key_len, kv->value_len, kv->key, kv->value); test(kv->value_len == strlen(kv->value), "%d.%d; kv->value_len(%d) == strlen(%s)(%d)", j, i, kv->value_len, kv->value, (int)strlen(kv->value)); } } t_end(); return 0; }