module/i3: replace asserts with real error checks

This commit is contained in:
Daniel Eklöf 2018-12-26 11:31:28 +01:00
parent 30332670aa
commit b2121070f8

View file

@ -51,23 +51,55 @@ struct private {
} workspaces; } workspaces;
}; };
static struct workspace static bool
workspace_from_json(const struct json_object *json) workspace_from_json(const struct json_object *json, struct workspace *ws)
{ {
assert(json_object_is_type(json, json_type_object)); assert(json_object_is_type(json, json_type_object));
if (!json_object_is_type(json, json_type_object)) {
LOG_ERR("'workspace' object is not of type 'object'");
return false;
}
struct json_object *name = json_object_object_get(json, "name"); struct json_object *name = json_object_object_get(json, "name");
struct json_object *output = json_object_object_get(json, "output"); struct json_object *output = json_object_object_get(json, "output");
const struct json_object *visible = json_object_object_get(json, "visible"); const struct json_object *visible = json_object_object_get(json, "visible");
const struct json_object *focused = json_object_object_get(json, "focused"); const struct json_object *focused = json_object_object_get(json, "focused");
const struct json_object *urgent = json_object_object_get(json, "urgent"); const struct json_object *urgent = json_object_object_get(json, "urgent");
return (struct workspace) { if (name == NULL || !json_object_is_type(name, json_type_string)) {
LOG_ERR("'workspace' object has no 'name' string value");
return false;
}
if (output == NULL || !json_object_is_type(output, json_type_string)) {
LOG_ERR("'workspace' object has no 'output' string value");
return false;
}
if (visible != NULL && !json_object_is_type(visible, json_type_boolean)) {
LOG_ERR("'workspace' object's 'visible' value is not a boolean");
return false;
}
if (focused != NULL && !json_object_is_type(focused, json_type_boolean)) {
LOG_ERR("'workspace' object's 'focused' value is not a boolean");
return false;
}
if (urgent != NULL && !json_object_is_type(urgent, json_type_boolean)) {
LOG_ERR("'workspace' object's 'urgent' value is not a boolean");
return false;
}
*ws = (struct workspace) {
.name = strdup(json_object_get_string(name)), .name = strdup(json_object_get_string(name)),
.output = strdup(json_object_get_string(output)), .output = strdup(json_object_get_string(output)),
.visible = json_object_get_boolean(visible), .visible = json_object_get_boolean(visible),
.focused = json_object_get_boolean(focused), .focused = json_object_get_boolean(focused),
.urgent = json_object_get_boolean(urgent), .urgent = json_object_get_boolean(urgent),
}; };
return true;
} }
static void static void
@ -154,12 +186,18 @@ send_pkg(int sock, int cmd, char *data)
static bool static bool
handle_get_version_reply(struct private *m, const struct json_object *json) handle_get_version_reply(struct private *m, const struct json_object *json)
{ {
assert(json_object_is_type(json, json_type_object)); if (!json_object_is_type(json, json_type_object)) {
LOG_ERR("'version' reply is not of type 'object'");
return false;
}
struct json_object *version = json_object_object_get(json, "human_readable"); struct json_object *version = json_object_object_get(json, "human_readable");
assert(version != NULL); if (version == NULL || !json_object_is_type(version, json_type_string)) {
assert(json_object_is_type(version, json_type_string)); LOG_ERR("'version' reply did not contain a 'human_readable' string value");
return false;
}
LOG_INFO("connected to i3: %s", json_object_get_string(version)); LOG_INFO("connected to i3: %s", json_object_get_string(version));
return true; return true;
} }
@ -167,21 +205,33 @@ handle_get_version_reply(struct private *m, const struct json_object *json)
static bool static bool
handle_subscribe_reply(struct private *m, const struct json_object *json) handle_subscribe_reply(struct private *m, const struct json_object *json)
{ {
assert(json_object_is_type(json, json_type_object)); if (!json_object_is_type(json, json_type_object)) {
LOG_ERR("'subscribe' reply is not of type 'object'");
return false;
}
const struct json_object *success = json_object_object_get(json, "success"); const struct json_object *success = json_object_object_get(json, "success");
assert(success != NULL); if (success == NULL || !json_object_is_type(success, json_type_boolean)) {
assert(json_object_is_type(success, json_type_boolean)); LOG_ERR("'subscribe' reply did not contain a 'success' boolean value");
assert(json_object_get_boolean(success)); return false;
}
return json_object_get_boolean(success); if (!json_object_get_boolean(success)) {
LOG_ERR("failed to subscribe");
return false;
}
return true;
} }
static bool static bool
handle_get_workspaces_reply(struct private *m, const struct json_object *json) handle_get_workspaces_reply(struct private *m, const struct json_object *json)
{ {
assert(json_object_is_type(json, json_type_array)); if (!json_object_is_type(json, json_type_array)) {
LOG_ERR("'workspaces' reply is not of type 'array'");
return false;
}
workspaces_free(m); workspaces_free(m);
@ -190,7 +240,12 @@ handle_get_workspaces_reply(struct private *m, const struct json_object *json)
m->workspaces.v = malloc(count * sizeof(m->workspaces.v[0])); m->workspaces.v = malloc(count * sizeof(m->workspaces.v[0]));
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
m->workspaces.v[i] = workspace_from_json(json_object_array_get_idx(json, i)); if (!workspace_from_json(
json_object_array_get_idx(json, i), &m->workspaces.v[i])) {
workspaces_free(m);
return false;
}
LOG_DBG("#%zu: %s", i, m->workspaces.v[i].name); LOG_DBG("#%zu: %s", i, m->workspaces.v[i].name);
} }
@ -200,30 +255,64 @@ handle_get_workspaces_reply(struct private *m, const struct json_object *json)
static bool static bool
handle_workspace_event(struct private *m, const struct json_object *json) handle_workspace_event(struct private *m, const struct json_object *json)
{ {
assert(json_object_is_type(json, json_type_object)); if (!json_object_is_type(json, json_type_object)) {
LOG_ERR("'workspace' event is not of type 'object'");
return false;
}
struct json_object *change = json_object_object_get(json, "change"); struct json_object *change = json_object_object_get(json, "change");
const struct json_object *current = json_object_object_get(json, "current"); const struct json_object *current = json_object_object_get(json, "current");
const struct json_object *old = json_object_object_get(json, "old"); const struct json_object *old = json_object_object_get(json, "old");
if (change == NULL || !json_object_is_type(change, json_type_string)) {
LOG_ERR("'workspace' event did not contain a 'change' string value");
return false;
}
if (current == NULL || !json_object_is_type(current, json_type_object)) {
LOG_ERR("'workspace' event did not contain a 'current' object value");
return false;
}
struct json_object *current_name = json_object_object_get(current, "name");
if (current_name == NULL || !json_object_is_type(current_name, json_type_string)) {
LOG_ERR("'workspace' event's 'current' object did not "
"contain a 'name' string value");
return false;
}
const char *change_str = json_object_get_string(change); const char *change_str = json_object_get_string(change);
if (strcmp(change_str, "init") == 0) { if (strcmp(change_str, "init") == 0) {
struct json_object *current_name = json_object_object_get(current, "name");
assert(workspace_lookup(m, json_object_get_string(current_name)) == NULL); assert(workspace_lookup(m, json_object_get_string(current_name)) == NULL);
struct workspace ws = workspace_from_json(current); struct workspace ws;
if (!workspace_from_json(current, &ws))
return false;
workspace_add(m, ws); workspace_add(m, ws);
} }
else if (strcmp(change_str, "empty") == 0) { else if (strcmp(change_str, "empty") == 0) {
struct json_object *current_name = json_object_object_get(current, "name");
assert(workspace_lookup(m, json_object_get_string(current_name)) != NULL); assert(workspace_lookup(m, json_object_get_string(current_name)) != NULL);
workspace_del(m, json_object_get_string(current_name)); workspace_del(m, json_object_get_string(current_name));
} }
else if (strcmp(change_str, "focus") == 0) { else if (strcmp(change_str, "focus") == 0) {
struct json_object *current_name = json_object_object_get(current, "name"); if (old == NULL || !json_object_is_type(old, json_type_object)) {
struct workspace *w = workspace_lookup(m, json_object_get_string(current_name)); LOG_ERR("'workspace' event did not contain a 'old' object value");
return false;
}
struct json_object *old_name = json_object_object_get(old, "name");
if (old_name == NULL || !json_object_is_type(old_name, json_type_string)) {
LOG_ERR("'workspace' event's 'old' object did not "
"contain a 'name' string value");
return false;
}
struct workspace *w = workspace_lookup(
m, json_object_get_string(current_name));
assert(w != NULL); assert(w != NULL);
/* Mark all workspaces on current's output invisible */ /* Mark all workspaces on current's output invisible */
@ -234,13 +323,19 @@ handle_workspace_event(struct private *m, const struct json_object *json)
} }
const struct json_object *urgent = json_object_object_get(current, "urgent"); const struct json_object *urgent = json_object_object_get(current, "urgent");
if (urgent == NULL || !json_object_is_type(urgent, json_type_boolean)) {
LOG_ERR("'workspace' event's 'current' object did not "
"contain a 'urgent' boolean value");
return false;
}
w->urgent = json_object_get_boolean(urgent); w->urgent = json_object_get_boolean(urgent);
w->focused = true; w->focused = true;
w->visible = true; w->visible = true;
/* Old workspace is no longer focused */ /* Old workspace is no longer focused */
struct json_object *old_name = json_object_object_get(old, "name"); struct workspace *old_w = workspace_lookup(
struct workspace *old_w = workspace_lookup(m, json_object_get_string(old_name)); m, json_object_get_string(old_name));
if (old_w != NULL) if (old_w != NULL)
old_w->focused = false; old_w->focused = false;
} }
@ -261,7 +356,11 @@ run(struct module_run_context *ctx)
char sock_path[1024]; char sock_path[1024];
{ {
FILE *out = popen("i3 --get-socketpath", "r"); FILE *out = popen("i3 --get-socketpath", "r");
assert(out != NULL); if (out == NULL) {
LOG_ERRNO("failed to execute 'i3 --get-socketpath'");
module_signal_ready(ctx);
return 1;
}
fgets(sock_path, sizeof(sock_path), out); fgets(sock_path, sizeof(sock_path), out);
pclose(out); pclose(out);
@ -273,13 +372,22 @@ run(struct module_run_context *ctx)
} }
int sock = socket(AF_UNIX, SOCK_STREAM, 0); int sock = socket(AF_UNIX, SOCK_STREAM, 0);
assert(sock != -1); if (sock == -1) {
LOG_ERRNO("failed to create UNIX socket");
module_signal_ready(ctx);
return 1;
}
struct sockaddr_un addr = {.sun_family = AF_UNIX}; struct sockaddr_un addr = {.sun_family = AF_UNIX};
strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1); strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
int r = connect(sock, (const struct sockaddr *)&addr, sizeof(addr)); int r = connect(sock, (const struct sockaddr *)&addr, sizeof(addr));
assert(r != -1); if (r == -1) {
LOG_ERRNO("failed to connect to i3 socket");
close(sock);
module_signal_ready(ctx);
return 1;
}
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL); send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL);
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
@ -297,7 +405,10 @@ run(struct module_run_context *ctx)
}; };
int res = poll(fds, 2, -1); int res = poll(fds, 2, -1);
assert(res > 0); if (res <= 0) {
LOG_ERRNO("failed to poll()");
break;
}
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
break; break;
@ -306,14 +417,25 @@ run(struct module_run_context *ctx)
assert(sizeof(buf) > buf_idx); assert(sizeof(buf) > buf_idx);
ssize_t bytes = read(sock, &buf[buf_idx], sizeof(buf) - buf_idx); ssize_t bytes = read(sock, &buf[buf_idx], sizeof(buf) - buf_idx);
if (bytes < 0) if (bytes < 0) {
LOG_ERRNO("failed to read from i3's socket");
break; break;
}
buf_idx += bytes; buf_idx += bytes;
while (buf_idx >= sizeof(i3_ipc_header_t)) { bool err = false;
while (!err && buf_idx >= sizeof(i3_ipc_header_t)) {
const i3_ipc_header_t *hdr = (const i3_ipc_header_t *)buf; const i3_ipc_header_t *hdr = (const i3_ipc_header_t *)buf;
assert(strncmp(hdr->magic, I3_IPC_MAGIC, sizeof(hdr->magic)) == 0); if (strncmp(hdr->magic, I3_IPC_MAGIC, sizeof(hdr->magic)) != 0) {
LOG_ERR(
"i3 IPC header magic mismatch: expected \"%.*s\", got \"%.*s\"",
(int)sizeof(hdr->magic), I3_IPC_MAGIC,
(int)sizeof(hdr->magic), hdr->magic);
err = true;
break;
}
size_t total_size = sizeof(i3_ipc_header_t) + hdr->size; size_t total_size = sizeof(i3_ipc_header_t) + hdr->size;
@ -328,7 +450,11 @@ run(struct module_run_context *ctx)
json_tokener *tokener = json_tokener_new(); json_tokener *tokener = json_tokener_new();
struct json_object *json = json_tokener_parse(json_str); struct json_object *json = json_tokener_parse(json_str);
assert(json != NULL); if (json == NULL) {
LOG_ERR("failed to parse json");
err = true;
break;
}
mtx_lock(&ctx->module->lock); mtx_lock(&ctx->module->lock);
@ -371,6 +497,9 @@ run(struct module_run_context *ctx)
memmove(buf, &buf[total_size], buf_idx - total_size); memmove(buf, &buf[total_size], buf_idx - total_size);
buf_idx -= total_size; buf_idx -= total_size;
} }
if (err)
break;
} }
close(sock); close(sock);