12045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle/*
22045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Copyright (C) 2010 The Android Open Source Project
32045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *
42045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Licensed under the Apache License, Version 2.0 (the "License");
52045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * you may not use this file except in compliance with the License.
62045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * You may obtain a copy of the License at
72045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *
82045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *      http://www.apache.org/licenses/LICENSE-2.0
92045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle *
102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * Unless required by applicable law or agreed to in writing, software
112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * distributed under the License is distributed on an "AS IS" BASIS,
122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * See the License for the specific language governing permissions and
142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle * limitations under the License.
152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle */
162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <assert.h>
182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <errno.h>
192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <fcntl.h>
202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <linux/ublock.h>
212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdint.h>
222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdio.h>
232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <stdlib.h>
242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <sys/types.h>
252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#include <ublock/ublock.h>
262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CONTROL_FILE "/dev/ublockctl"
282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestruct ublock_ctx {
302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_ops *ops;
312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	uint32_t index;
332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	uint64_t size;
342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	uint32_t max_buf;
352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	char *in_buf;
372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	char *out_buf;
382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int flags;
402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int fd;
412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int fails;
422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle};
432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_INITED  0x1
452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_READY   0x2
462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define CTX_RUNNING 0x4
472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define MAX_BUF 65536
492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define MAX_FAILURES 10
512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic inline void ublock_succeed(struct ublock_ctx *ub_ctx)
532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->fails = 0;
572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic void ublock_fail(struct ublock_ctx *ub_ctx)
602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->fails++;
642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (ub_ctx->fails > MAX_FAILURES)
652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		ublock_stop(ub_ctx);
662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_init(struct ublock_ctx *ub_ctx,
692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                              const void *in, size_t in_len,
702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                              void *out, size_t *out_len)
712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const struct ublock_init_in *in_h;
732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_init_out *out_h;
742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in);
772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out);
782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len != sizeof(*in_h))
802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_h = (const struct ublock_init_in *)in;
832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_h->version != UBLOCK_VERSION)
852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h = (struct ublock_init_out *)out;
882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->version = UBLOCK_VERSION;
892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->size = ub_ctx->size;
902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_h->max_buf < MAX_BUF)
912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		ub_ctx->max_buf = in_h->max_buf;
922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	else
932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		ub_ctx->max_buf = MAX_BUF;
942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->max_buf = ub_ctx->max_buf;
952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	*out_len = sizeof(*out_h);
972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->index = in_h->index;
992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->flags |= CTX_INITED;
1002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
1022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
1032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_ready(struct ublock_ctx *ub_ctx,
1052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                               const void *in, size_t in_len,
1062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                               void *out, size_t *out_len)
1072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
1082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_ready_out *out_h;
1092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
1112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in);
1122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out);
1132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len != sizeof(struct ublock_ready_in))
1152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
1162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	*out_len = sizeof(struct ublock_ready_out);
1182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->flags |= CTX_READY;
1202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
1222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
1232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_read(struct ublock_ctx *ub_ctx,
1252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                              const void *in, size_t in_len,
1262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                              void *out, size_t *out_len)
1272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
1282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const struct ublock_read_in *in_h;
1292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_read_out *out_h;
1302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	char *out_buf;
1312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
1332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in);
1342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out);
1352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len != sizeof(*in_h))
1372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
1382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_h = (const struct ublock_read_in *)in;
1402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h = (struct ublock_read_out *)out;
1422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_buf = (char *)(out_h + 1);
1432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->status = (ub_ctx->ops->read)(out_buf, in_h->length, in_h->offset);
1452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (out_h->status >= 0)
1472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		*out_len = sizeof(*out_h) + in_h->length;
1482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	else
1492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		*out_len = sizeof(*out_h);
1502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
1522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
1532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_write(struct ublock_ctx *ub_ctx,
1552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                               const void *in, size_t in_len,
1562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                               void *out, size_t *out_len)
1572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
1582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const struct ublock_write_in *in_h;
1592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const char *in_buf;
1602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_write_out *out_h;
1612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
1632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in);
1642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out);
1652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len < sizeof(*in_h))
1672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
1682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_h = (const struct ublock_write_in *)in;
1702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf = (const char*)(in_h + 1);
1712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h = (struct ublock_write_out *)out;
1732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	*out_len = sizeof(*out_h);
1742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->status = (ub_ctx->ops->write)(in_buf, in_h->length, in_h->offset);
1762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
1782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
1792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_handle_request(struct ublock_ctx *ub_ctx,
1812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                                 const void *in, size_t in_len,
1822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle                                 void *out, size_t *out_len)
1832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
1842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const struct ublock_in_header *in_h;
1852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	const void *in_buf;
1862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t in_buf_len;
1872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_out_header *out_h;
1892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	void *out_buf;
1902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t out_buf_len;
1912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int result;
1932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int (*handle_fn)(struct ublock_ctx *, const void *, size_t, void *, size_t *);
1942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
1962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in);
1972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out);
1982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
1992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len < sizeof(*in_h))
2002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
2012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_h = (const struct ublock_in_header *)in;
2032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf = in_h + 1;
2042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf_len = in_len - sizeof(*in_h);
2052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h = (struct ublock_out_header *)out;
2072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_buf = out_h + 1;
2082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	switch (in_h->opcode) {
2102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	case UBLOCK_INIT_IN:
2112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		out_h->opcode = UBLOCK_INIT_OUT;
2122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		handle_fn = &ublock_handle_init;
2132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		break;
2142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	case UBLOCK_READY_IN:
2152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		out_h->opcode = UBLOCK_READY_OUT;
2162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		handle_fn = &ublock_handle_ready;
2172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		break;
2182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	case UBLOCK_READ_IN:
2192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		out_h->opcode = UBLOCK_READ_OUT;
2202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		handle_fn = &ublock_handle_read;
2212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		break;
2222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	case UBLOCK_WRITE_IN:
2232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		out_h->opcode = UBLOCK_WRITE_OUT;
2242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		handle_fn = &ublock_handle_write;
2252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		break;
2262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	default:
2272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
2282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
2292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_h->seq = in_h->seq;
2312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	result = (handle_fn)(ub_ctx, in_buf, in_buf_len, out_buf, &out_buf_len);
2322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	*out_len = sizeof(*out_h) + out_buf_len;
2332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return result;
2352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
2362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_do_request(struct ublock_ctx *ub_ctx,
2382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			     void *in_buf, size_t in_size,
2392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			     void *out_buf, size_t out_size)
2402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
2412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t out_len;
2422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ssize_t in_len, out_wrote;
2432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int result;
2442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(ub_ctx);
2462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(in_buf);
2472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out_buf);
2482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_len = read(ub_ctx->fd, in_buf, in_size);
2502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_len < 0)
2512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
2522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	result = ublock_handle_request(ub_ctx, in_buf, in_len, out_buf, &out_len);
2542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	assert(out_len <= out_size);
2562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_wrote = write(ub_ctx->fd, out_buf, out_len);
2582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (out_wrote < out_len)
2602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EPROTO;
2612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (result)
2632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		ublock_fail(ub_ctx);
2642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	else
2652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		ublock_succeed(ub_ctx);
2662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return result;
2682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
2692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_READY 1
2712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_STOPPED 2
2722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle#define EXIT_FAIL 4
2732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic int ublock_loop(struct ublock_ctx *ub_ctx, int exit_cond)
2752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
2762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t in_len, out_len;
2772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int result;
2782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	result = 0;
2802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	while (((exit_cond & EXIT_READY) && (!(ub_ctx->flags & CTX_READY))) ||
2812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	       ((exit_cond & EXIT_STOPPED) && (ub_ctx->flags & CTX_RUNNING)) ||
2822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	       ((exit_cond & EXIT_FAIL) && (result))) {
2832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = ublock_do_request(ub_ctx,
2842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		                           ub_ctx->in_buf, ub_ctx->max_buf,
2852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		                           ub_ctx->out_buf, ub_ctx->max_buf);
2862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		if (result)
2872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			return result;
2882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
2892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
2912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
2922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_run(struct ublock_ctx *ub_ctx)
2942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
2952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx)
2962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EFAULT;
2972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
2982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!(ub_ctx->flags & CTX_INITED))
2992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EINVAL;
3002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->flags |= CTX_RUNNING;
3022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ublock_loop(ub_ctx, EXIT_STOPPED);
3032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
3052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
3062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlevoid ublock_stop(struct ublock_ctx *ub_ctx)
3082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
3092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx)
3102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return;
3112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!(ub_ctx->flags & CTX_INITED))
3132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return;
3142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->flags &= ~CTX_RUNNING;
3162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
3172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_index(struct ublock_ctx *ub_ctx)
3192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
3202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx)
3212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EFAULT;
3222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!(ub_ctx->flags & CTX_INITED))
3242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EINVAL;
3252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return ub_ctx->index;
3272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
3282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlestatic inline size_t ublock_init_buf_size(void)
3302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
3312045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t in_size = sizeof(struct ublock_in_header) +
3322045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			 sizeof(struct ublock_init_in);
3332045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t out_size = sizeof(struct ublock_out_header) +
3342045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			  sizeof(struct ublock_init_out);
3352045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3362045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return (in_size > out_size) ? in_size : out_size;
3372045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
3382045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3392045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleint ublock_init(struct ublock_ctx **ub_ctx_out, struct ublock_ops *ops,
3402045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		uint64_t dev_size)
3412045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
3422045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	struct ublock_ctx *ub_ctx;
3432045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	char *in_buf, *out_buf;
3442045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size_t size;
3452045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	int result;
3462045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3472045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx_out || !ops)
3482045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return -EFAULT;
3492045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3502045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf = out_buf = NULL;
3512045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3522045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx = malloc(sizeof(struct ublock_ctx));
3532045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx) {
3542045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -ENOMEM;
3552045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3562045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3572045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3582045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	size = ublock_init_buf_size();
3592045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf = malloc(size);
3602045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_buf = malloc(size);
3612045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!(in_buf && out_buf)) {
3622045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -ENOMEM;
3632045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3642045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3652045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3662045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->ops = ops;
3672045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->size = dev_size;
3682045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->max_buf = 0;
3692045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->flags = 0;
3702045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3712045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->fd = open(CONTROL_FILE, O_RDWR);
3722045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (ub_ctx->fd < 0) {
3732045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -ENOENT;
3742045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3752045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3762045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3772045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	result = ublock_do_request(ub_ctx, in_buf, size, out_buf, size);
3782045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (result) {
3792045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -EPROTO;
3802045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3812045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3822045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx->flags & CTX_INITED) {
3832045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -EPROTO;
3842045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3852045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3862045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3872045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	free(in_buf);
3882045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	in_buf = NULL;
3892045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	free(out_buf);
3902045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	out_buf = NULL;
3912045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3922045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->in_buf = malloc(ub_ctx->max_buf);
3932045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ub_ctx->out_buf = malloc(ub_ctx->max_buf);
3942045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!(ub_ctx->in_buf && ub_ctx->out_buf)) {
3952045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		result = -ENOMEM;
3962045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		goto error;
3972045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
3982045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
3992045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	ublock_loop(ub_ctx, EXIT_READY);
4002045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4012045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	*ub_ctx_out = ub_ctx;
4022045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4032045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return 0;
4042045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4052045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttleerror:
4062045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (ub_ctx) {
4072045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		if (ub_ctx->in_buf)
4082045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			free(ub_ctx->in_buf);
4092045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		if (ub_ctx->out_buf)
4102045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			free(ub_ctx->out_buf);
4112045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		if (ub_ctx->fd)
4122045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle			close(ub_ctx->fd);
4132045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		free(ub_ctx);
4142045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	}
4152045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (in_buf)
4162045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		free(in_buf);
4172045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (out_buf)
4182045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		free(out_buf);
4192045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4202045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	return result;
4212045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
4222045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4232045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttlevoid ublock_destroy(struct ublock_ctx *ub_ctx)
4242045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle{
4252045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	if (!ub_ctx)
4262045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle		return;
4272045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle
4282045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	close(ub_ctx->fd);
4292045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle	free(ub_ctx);
4302045e6e39d6dbfed1e46c333c2910c66e788cd36Thomas Tuttle}
431