/* * Convert the given nv structure to network byte order and return ebuf * structure. */ struct ebuf * nv_hton(struct nv *nv) { struct nvhdr *nvh; unsigned char *ptr; size_t size; NV_CHECK(nv); PJDLOG_ASSERT(nv->nv_error == 0); ptr = ebuf_data(nv->nv_ebuf, &size); while (size > 0) { /* * Minimum size at this point is size of nvhdr structure, * one character long name plus terminating '\0'. */ PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); nvh = (struct nvhdr *)ptr; PJDLOG_ASSERT(NVH_SIZE(nvh) <= size); nv_swap(nvh, false); ptr += NVH_SIZE(nvh); size -= NVH_SIZE(nvh); } return (nv->nv_ebuf); }
int metadata_write(struct hast_resource *res) { struct ebuf *eb; struct nv *nv; unsigned char *buf, *ptr; size_t size; ssize_t done; int ret; buf = calloc(1, METADATA_SIZE); if (buf == NULL) { pjdlog_error("Unable to allocate %zu bytes for metadata.", (size_t)METADATA_SIZE); return (-1); } ret = -1; nv = nv_alloc(); nv_add_string(nv, res->hr_name, "resource"); nv_add_uint64(nv, (uint64_t)res->hr_datasize, "datasize"); nv_add_uint32(nv, (uint32_t)res->hr_extentsize, "extentsize"); nv_add_uint32(nv, (uint32_t)res->hr_keepdirty, "keepdirty"); nv_add_uint64(nv, (uint64_t)res->hr_localoff, "offset"); nv_add_uint64(nv, res->hr_resuid, "resuid"); if (res->hr_role == HAST_ROLE_PRIMARY || res->hr_role == HAST_ROLE_INIT) { nv_add_uint64(nv, res->hr_primary_localcnt, "localcnt"); nv_add_uint64(nv, res->hr_primary_remotecnt, "remotecnt"); } else /* if (res->hr_role == HAST_ROLE_SECONDARY) */ { PJDLOG_ASSERT(res->hr_role == HAST_ROLE_SECONDARY); nv_add_uint64(nv, res->hr_secondary_localcnt, "localcnt"); nv_add_uint64(nv, res->hr_secondary_remotecnt, "remotecnt"); } nv_add_string(nv, role2str(res->hr_role), "prevrole"); if (nv_error(nv) != 0) { pjdlog_error("Unable to create metadata."); goto end; } res->hr_previous_role = res->hr_role; eb = nv_hton(nv); PJDLOG_ASSERT(eb != NULL); ptr = ebuf_data(eb, &size); PJDLOG_ASSERT(ptr != NULL); PJDLOG_ASSERT(size < METADATA_SIZE); bcopy(ptr, buf, size); done = pwrite(res->hr_localfd, buf, METADATA_SIZE, 0); if (done == -1 || done != METADATA_SIZE) { pjdlog_errno(LOG_ERR, "Unable to write metadata"); goto end; } ret = 0; end: free(buf); nv_free(nv); return (ret); }
/* * Send the given nv structure via conn. * We keep headers in nv structure and pass data in separate argument. * There can be no data at all (data is NULL then). */ int hast_proto_send(const struct hast_resource *res, struct proto_conn *conn, struct nv *nv, const void *data, size_t size) { struct hast_main_header hdr; struct ebuf *eb; bool freedata; void *dptr, *hptr; size_t hsize; int ret; dptr = (void *)(uintptr_t)data; freedata = false; ret = -1; if (data != NULL) { unsigned int ii; for (ii = 0; ii < sizeof(pipeline) / sizeof(pipeline[0]); ii++) { (void)pipeline[ii].hps_send(res, nv, &dptr, &size, &freedata); } nv_add_uint32(nv, size, "size"); if (nv_error(nv) != 0) { errno = nv_error(nv); goto end; } } eb = nv_hton(nv); if (eb == NULL) goto end; hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION; hdr.size = htole32((uint32_t)ebuf_size(eb)); if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1) goto end; hptr = ebuf_data(eb, &hsize); if (proto_send(conn, hptr, hsize) == -1) goto end; if (data != NULL && proto_send(conn, dptr, size) == -1) goto end; ret = 0; end: if (freedata) free(dptr); return (ret); }
static struct nvhdr * nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap) { char name[255]; struct nvhdr *nvh; unsigned char *ptr; size_t size, namesize; if (nv == NULL) { errno = ENOMEM; return (NULL); } NV_CHECK(nv); namesize = vsnprintf(name, sizeof(name), namefmt, nameap); PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name)); namesize++; ptr = ebuf_data(nv->nv_ebuf, &size); while (size > 0) { PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); nvh = (struct nvhdr *)ptr; PJDLOG_ASSERT(size >= NVH_SIZE(nvh)); nv_swap(nvh, true); if (strcmp(nvh->nvh_name, name) == 0) { if (type != NV_TYPE_NONE && (nvh->nvh_type & NV_TYPE_MASK) != type) { errno = EINVAL; if (nv->nv_error == 0) nv->nv_error = EINVAL; return (NULL); } return (nvh); } ptr += NVH_SIZE(nvh); size -= NVH_SIZE(nvh); } errno = ENOENT; if (nv->nv_error == 0) nv->nv_error = ENOENT; return (NULL); }
int hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp) { struct hast_main_header hdr; struct nv *nv; struct ebuf *eb; void *hptr; eb = NULL; nv = NULL; if (proto_recv(conn, &hdr, sizeof(hdr)) == -1) goto fail; if (hdr.version > HAST_PROTO_VERSION) { errno = ERPCMISMATCH; goto fail; } hdr.size = le32toh(hdr.size); eb = ebuf_alloc(hdr.size); if (eb == NULL) goto fail; if (ebuf_add_tail(eb, NULL, hdr.size) == -1) goto fail; hptr = ebuf_data(eb, NULL); PJDLOG_ASSERT(hptr != NULL); if (proto_recv(conn, hptr, hdr.size) == -1) goto fail; nv = nv_ntoh(eb); if (nv == NULL) goto fail; *nvp = nv; return (0); fail: if (eb != NULL) ebuf_free(eb); return (-1); }
int metadata_read(struct hast_resource *res, bool openrw) { unsigned char *buf; struct ebuf *eb; struct nv *nv; ssize_t done; const char *str; int rerrno; bool opened_here; opened_here = false; rerrno = 0; /* * Is this first metadata_read() call for this resource? */ if (res->hr_localfd == -1) { if (provinfo(res, openrw) == -1) { rerrno = errno; goto fail; } opened_here = true; pjdlog_debug(1, "Obtained info about %s.", res->hr_localpath); if (openrw) { if (flock(res->hr_localfd, LOCK_EX | LOCK_NB) == -1) { rerrno = errno; if (errno == EOPNOTSUPP) { pjdlog_warning("Unable to lock %s (operation not supported), but continuing.", res->hr_localpath); } else { pjdlog_errno(LOG_ERR, "Unable to lock %s", res->hr_localpath); goto fail; } } pjdlog_debug(1, "Locked %s.", res->hr_localpath); } } eb = ebuf_alloc(METADATA_SIZE); if (eb == NULL) { rerrno = errno; pjdlog_errno(LOG_ERR, "Unable to allocate memory to read metadata"); goto fail; } if (ebuf_add_tail(eb, NULL, METADATA_SIZE) == -1) { rerrno = errno; pjdlog_errno(LOG_ERR, "Unable to allocate memory to read metadata"); ebuf_free(eb); goto fail; } buf = ebuf_data(eb, NULL); PJDLOG_ASSERT(buf != NULL); done = pread(res->hr_localfd, buf, METADATA_SIZE, 0); if (done == -1 || done != METADATA_SIZE) { rerrno = errno; pjdlog_errno(LOG_ERR, "Unable to read metadata"); ebuf_free(eb); goto fail; } nv = nv_ntoh(eb); if (nv == NULL) { rerrno = errno; pjdlog_errno(LOG_ERR, "Metadata read from %s is invalid", res->hr_localpath); ebuf_free(eb); goto fail; } str = nv_get_string(nv, "resource"); if (str != NULL && strcmp(str, res->hr_name) != 0) { pjdlog_error("Provider %s is not part of resource %s.", res->hr_localpath, res->hr_name); nv_free(nv); goto fail; } res->hr_datasize = nv_get_uint64(nv, "datasize"); res->hr_extentsize = (int)nv_get_uint32(nv, "extentsize"); res->hr_keepdirty = (int)nv_get_uint32(nv, "keepdirty"); res->hr_localoff = nv_get_uint64(nv, "offset"); res->hr_resuid = nv_get_uint64(nv, "resuid"); if (res->hr_role != HAST_ROLE_PRIMARY) { /* Secondary or init role. */ res->hr_secondary_localcnt = nv_get_uint64(nv, "localcnt"); res->hr_secondary_remotecnt = nv_get_uint64(nv, "remotecnt"); } if (res->hr_role != HAST_ROLE_SECONDARY) { /* Primary or init role. */ res->hr_primary_localcnt = nv_get_uint64(nv, "localcnt"); res->hr_primary_remotecnt = nv_get_uint64(nv, "remotecnt"); } str = nv_get_string(nv, "prevrole"); if (str != NULL) { if (strcmp(str, "primary") == 0) res->hr_previous_role = HAST_ROLE_PRIMARY; else if (strcmp(str, "secondary") == 0) res->hr_previous_role = HAST_ROLE_SECONDARY; } if (nv_error(nv) != 0) { errno = rerrno = nv_error(nv); pjdlog_errno(LOG_ERR, "Unable to read metadata from %s", res->hr_localpath); nv_free(nv); goto fail; } nv_free(nv); return (0); fail: if (opened_here) { close(res->hr_localfd); res->hr_localfd = -1; } errno = rerrno; return (-1); }
/* * Dump content of the nv structure. */ void nv_dump(struct nv *nv) { struct nvhdr *nvh; unsigned char *data, *ptr; size_t dsize, size; unsigned int ii; bool swap; if (nv_validate(nv, NULL) == -1) { printf("error: %d\n", errno); return; } NV_CHECK(nv); PJDLOG_ASSERT(nv->nv_error == 0); ptr = ebuf_data(nv->nv_ebuf, &size); while (size > 0) { PJDLOG_ASSERT(size >= sizeof(*nvh) + 2); nvh = (struct nvhdr *)ptr; PJDLOG_ASSERT(size >= NVH_SIZE(nvh)); swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK); dsize = NVH_DSIZE(nvh); data = NVH_DATA(nvh); printf(" %s", nvh->nvh_name); switch (nvh->nvh_type & NV_TYPE_MASK) { case NV_TYPE_INT8: printf("(int8): %jd", (intmax_t)(*(int8_t *)data)); break; case NV_TYPE_UINT8: printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data)); break; case NV_TYPE_INT16: printf("(int16): %jd", swap ? (intmax_t)le16toh(*(int16_t *)(void *)data) : (intmax_t)*(int16_t *)(void *)data); break; case NV_TYPE_UINT16: printf("(uint16): %ju", swap ? (uintmax_t)le16toh(*(uint16_t *)(void *)data) : (uintmax_t)*(uint16_t *)(void *)data); break; case NV_TYPE_INT32: printf("(int32): %jd", swap ? (intmax_t)le32toh(*(int32_t *)(void *)data) : (intmax_t)*(int32_t *)(void *)data); break; case NV_TYPE_UINT32: printf("(uint32): %ju", swap ? (uintmax_t)le32toh(*(uint32_t *)(void *)data) : (uintmax_t)*(uint32_t *)(void *)data); break; case NV_TYPE_INT64: printf("(int64): %jd", swap ? (intmax_t)le64toh(*(int64_t *)(void *)data) : (intmax_t)*(int64_t *)(void *)data); break; case NV_TYPE_UINT64: printf("(uint64): %ju", swap ? (uintmax_t)le64toh(*(uint64_t *)(void *)data) : (uintmax_t)*(uint64_t *)(void *)data); break; case NV_TYPE_INT8_ARRAY: printf("(int8 array):"); for (ii = 0; ii < dsize; ii++) printf(" %jd", (intmax_t)((int8_t *)data)[ii]); break; case NV_TYPE_UINT8_ARRAY: printf("(uint8 array):"); for (ii = 0; ii < dsize; ii++) printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]); break; case NV_TYPE_INT16_ARRAY: printf("(int16 array):"); for (ii = 0; ii < dsize / 2; ii++) { printf(" %jd", swap ? (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) : (intmax_t)((int16_t *)(void *)data)[ii]); } break; case NV_TYPE_UINT16_ARRAY: printf("(uint16 array):"); for (ii = 0; ii < dsize / 2; ii++) { printf(" %ju", swap ? (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) : (uintmax_t)((uint16_t *)(void *)data)[ii]); } break; case NV_TYPE_INT32_ARRAY: printf("(int32 array):"); for (ii = 0; ii < dsize / 4; ii++) { printf(" %jd", swap ? (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) : (intmax_t)((int32_t *)(void *)data)[ii]); } break; case NV_TYPE_UINT32_ARRAY: printf("(uint32 array):"); for (ii = 0; ii < dsize / 4; ii++) { printf(" %ju", swap ? (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) : (uintmax_t)((uint32_t *)(void *)data)[ii]); } break; case NV_TYPE_INT64_ARRAY: printf("(int64 array):"); for (ii = 0; ii < dsize / 8; ii++) { printf(" %ju", swap ? (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : (uintmax_t)((uint64_t *)(void *)data)[ii]); } break; case NV_TYPE_UINT64_ARRAY: printf("(uint64 array):"); for (ii = 0; ii < dsize / 8; ii++) { printf(" %ju", swap ? (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) : (uintmax_t)((uint64_t *)(void *)data)[ii]); } break; case NV_TYPE_STRING: printf("(string): %s", (char *)data); break; default: PJDLOG_ABORT("invalid condition"); } printf("\n"); ptr += NVH_SIZE(nvh); size -= NVH_SIZE(nvh); } }
/* * Validate correctness of the entire nv structure and all its elements. * If extrap is not NULL, store number of extra bytes at the end of the buffer. */ int nv_validate(struct nv *nv, size_t *extrap) { struct nvhdr *nvh; unsigned char *data, *ptr; size_t dsize, size, vsize; int error; if (nv == NULL) { errno = ENOMEM; return (-1); } NV_CHECK(nv); PJDLOG_ASSERT(nv->nv_error == 0); /* TODO: Check that names are unique? */ error = 0; ptr = ebuf_data(nv->nv_ebuf, &size); while (size > 0) { /* * Zeros at the end of the buffer are acceptable. */ if (ptr[0] == '\0') break; /* * Minimum size at this point is size of nvhdr structure, one * character long name plus terminating '\0'. */ if (size < sizeof(*nvh) + 2) { error = EINVAL; break; } nvh = (struct nvhdr *)ptr; if (size < NVH_HSIZE(nvh)) { error = EINVAL; break; } if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') { error = EINVAL; break; } if (strlen(nvh->nvh_name) != (size_t)(nvh->nvh_namesize - 1)) { error = EINVAL; break; } if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST || (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) { error = EINVAL; break; } dsize = NVH_DSIZE(nvh); if (dsize == 0) { error = EINVAL; break; } if (size < NVH_SIZE(nvh)) { error = EINVAL; break; } vsize = 0; switch (nvh->nvh_type & NV_TYPE_MASK) { case NV_TYPE_INT8: case NV_TYPE_UINT8: if (vsize == 0) vsize = 1; /* FALLTHROUGH */ case NV_TYPE_INT16: case NV_TYPE_UINT16: if (vsize == 0) vsize = 2; /* FALLTHROUGH */ case NV_TYPE_INT32: case NV_TYPE_UINT32: if (vsize == 0) vsize = 4; /* FALLTHROUGH */ case NV_TYPE_INT64: case NV_TYPE_UINT64: if (vsize == 0) vsize = 8; if (dsize != vsize) { error = EINVAL; break; } break; case NV_TYPE_INT8_ARRAY: case NV_TYPE_UINT8_ARRAY: break; case NV_TYPE_INT16_ARRAY: case NV_TYPE_UINT16_ARRAY: if (vsize == 0) vsize = 2; /* FALLTHROUGH */ case NV_TYPE_INT32_ARRAY: case NV_TYPE_UINT32_ARRAY: if (vsize == 0) vsize = 4; /* FALLTHROUGH */ case NV_TYPE_INT64_ARRAY: case NV_TYPE_UINT64_ARRAY: if (vsize == 0) vsize = 8; if ((dsize % vsize) != 0) { error = EINVAL; break; } break; case NV_TYPE_STRING: data = NVH_DATA(nvh); if (data[dsize - 1] != '\0') { error = EINVAL; break; } if (strlen((char *)data) != dsize - 1) { error = EINVAL; break; } break; default: PJDLOG_ABORT("invalid condition"); } if (error != 0) break; ptr += NVH_SIZE(nvh); size -= NVH_SIZE(nvh); } if (error != 0) { errno = error; if (nv->nv_error == 0) nv->nv_error = error; return (-1); } if (extrap != NULL) *extrap = size; return (0); }