~sircmpwn/himitsu-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH himitsu v2] hiq: use himitsu::client to run queries

Details
Message ID
<20230513140430.8738-1-sam@samnystrom.dev>
DKIM signature
missing
Download raw message
Patch: +66 -87
Replace manual usage of the himitsud Unix socket with calls to the
himitsu::client library.
---
Since v1:
- free the key items and query
- improve a few error messages

 cmd/hiq/main.ha | 153 +++++++++++++++++++++---------------------------
 1 file changed, 66 insertions(+), 87 deletions(-)

diff --git a/cmd/hiq/main.ha b/cmd/hiq/main.ha
index ad0460e..7960ec6 100644
--- a/cmd/hiq/main.ha
+++ b/cmd/hiq/main.ha
@@ -15,32 +15,6 @@ use strings;
use strio;
use unix::tty;

type flag = enum uint {
	ONE = 1 << 0,
	DECRYPT = 1 << 1,
};

fn write_item(
	out: io::handle,
	items: str,
	field: str
) (void | io::error) = {
	if (field == "") {
		fmt::fprintln(out, items)!;
		return;
	};
	let items = shlex::split(items)!;
	defer strings::freeall(items);
	let query = query::parse_items(items)!;
	for (let i = 0z; i < len(query.items); i += 1) {
		let item = query.items[i];
		if (item.key != field) {
			continue;
		};
		fmt::fprintln(out, item.value)?;
	};
};

export fn main() void = {
	let usage: [_]getopt::help = [
		"secure key store client",
@@ -56,15 +30,17 @@ export fn main() void = {
	defer getopt::finish(&cmd);

	let op = client::operation::QUERY;
	let flags: flag = 0, field = "";
	let flags: client::flags = 0;
	let field: (str | void) = void;
	let one = false;
	for (let i = 0z; i < len(cmd.opts); i += 1) {
		switch (cmd.opts[i].0) {
		case '1' =>
			flags |= flag::ONE;
			one = true;
		case 'a' =>
			op = client::operation::ADD;
		case 'd' =>
			flags |= flag::DECRYPT;
			flags |= client::flags::DECRYPT;
		case 'D' =>
			op = client::operation::DEL;
		case 'F' =>
@@ -74,16 +50,20 @@ export fn main() void = {
		};
	};

	let buf = path::init();
	// TODO: Bubble up dirs::runtime errors
	const sockpath = path::set(&buf, dirs::runtime()!, "himitsu")!;
	let conn = match (unix::connect(sockpath)) {
	let conn = match (client::connect()) {
	case let s: net::socket =>
		yield s;
	case errors::noentry =>
		fmt::fatal("error: himitsud connection failed (is it running?)");
	case let e: client::hierror =>
		fmt::fatal(e);
	case let e: io::error =>
		fmt::fatal("error:", io::strerror(e));
	case let e: net::error =>
		fmt::fatal("error:", net::strerror(e));
		match (e) {
		case errors::noentry =>
			fmt::fatal("error: himitsud connection failed (is it running?)");
		case =>
			fmt::fatal("error:", net::strerror(e));
		};
	};
	defer io::close(conn)!;

@@ -97,77 +77,76 @@ export fn main() void = {
			case let line: []u8 =>
				// NB. Can't defer free(line), causes a
				// use-after-free in fmt::fatal
				const line = strings::fromutf8(line)!;
				const query = match (shlex::split(line)) {
				case let q: []str =>
				const query = bufio::fixed(line, io::mode::READ);
				const query = match (query::parse(&query)) {
				case let q: query::query =>
					yield q;
				case =>
					fmt::fatal("Invalid query:", line);
				case query::invalid =>
					fmt::fatal("Invalid query:", strings::fromutf8(line)!);
				case let err: io::error =>
					abort(); // reading from a fixed buffer shouldn't fail
				};
				defer strings::freeall(query);
				defer query::finish(&query);
				free(line);

				send(conn, client::operation::ADD, flags, field, query);
				send(conn, client::operation::ADD, &query, flags, field, one);
			};
		};
	} else {
		let query = alloc(cmd.args...);
		defer free(query);
		if (flags & flag::DECRYPT != 0) {
			insert(query[0], "-d");
		const query = match (query::parse_items(cmd.args)) {
		case let q: query::query =>
			yield q;
		case query::invalid =>
			fmt::fatal("Invalid query");
		};
		send(conn, op, flags, field, query);
		defer query::finish(&query);
		send(conn, op, &query, flags, field, one);
	};
};

fn send(
	conn: io::file,
	conn: net::socket,
	op: client::operation,
	flags: flag,
	field: str,
	query: []str,
	query: *query::query,
	flags: client::flags,
	field: (str | void),
	one: bool,
) void = {
	fmt::fprint(conn, switch (op) {
	case client::operation::QUERY =>
		yield "query";
	case client::operation::ADD =>
		yield "add";
	case client::operation::DEL =>
		yield "del";
	case client::operation::QUIT =>
		yield "quit";
	})!;
	for (let i = 0z; i < len(query); i += 1) {
		fmt::fprint(conn, " ")!;
		shlex::quote(conn, query[i])!;
	const keys = match (client::query(conn, op, query, flags)) {
	case let k: client::keyiter =>
		yield k;
	case let err: client::error =>
		fmt::fatal("Error executing query:", client::strerror(err));
	};
	fmt::fprintln(conn)!;

	let buf = strio::dynamic();
	defer io::close(&buf)!;

	for (let n = 0; true; n += 1) match (bufio::scanline(conn)!) {
	case io::EOF => break;
	case let line: []u8 =>
		// NB. Can't defer free(line), causes a use-after-free in
		// fmt::fatal
		let resp = strings::fromutf8(line)!;
		let resp = strings::cut(resp, " ");
		switch (resp.0) {
		case "key" =>
			if (flags & flag::ONE != 0 && n > 0) {
				fmt::fatal("error: Ambiguous match");
	for (let i = 0; true; i += 1) {
		let key = match (client::next(&keys)) {
		case let k: const str =>
			if (one && i > 0) {
				fmt::fatal("Error: ambiguous match");
			};
			write_item(&buf, resp.1, field)!;
		case "error" =>
			fmt::fatal("error:", resp.1);
		case "end" =>
			free(line);
			break;
		case =>
			break;
			yield k;
		case let err: client::error =>
			fmt::fatal("Error executing query:", client::strerror(err));
		case void => break;
		};
		match (field) {
		case let field: str =>
			const items = shlex::split(key)!;
			defer strings::freeall(items);
			const query = query::parse_items(items)!;
			defer query::finish(&query);
			for (let i = 0z; i < len(query.items); i += 1) {
				let item = query.items[i];
				if (item.key == field) {
					fmt::fprintln(&buf, item.value)!;
				};
			};
		case void =>
			fmt::fprintln(&buf, key)!;
		};
		free(line);
	};

	fmt::print(strio::string(&buf))!;
-- 
2.40.1
Details
Message ID
<CSX0WFV9SATH.13GBXOIE8CPHL@framework>
In-Reply-To
<20230513140430.8738-1-sam@samnystrom.dev> (view parent)
DKIM signature
missing
Download raw message
Applied to master. Thanks!
Reply to thread Export thread (mbox)