Introduce the GET_CONFIG IPC request
This introduces memory usage by one copy of the config file, which is an acceptable trade-off for being able to easily revert data loss. The default config is 6KB, user configs will be in the same ballpark. fixes #2856
This commit is contained in:
@ -119,6 +119,43 @@ static yajl_callbacks reply_callbacks = {
|
||||
.yajl_end_map = reply_end_map_cb,
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* Config reply callbacks
|
||||
*******************************************************************************/
|
||||
|
||||
static char *config_last_key = NULL;
|
||||
|
||||
static int config_string_cb(void *params, const unsigned char *val, size_t len) {
|
||||
char *str = scalloc(len + 1, 1);
|
||||
strncpy(str, (const char *)val, len);
|
||||
if (strcmp(config_last_key, "config") == 0) {
|
||||
fprintf(stdout, "%s", str);
|
||||
}
|
||||
free(str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int config_start_map_cb(void *params) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int config_end_map_cb(void *params) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int config_map_key_cb(void *params, const unsigned char *keyVal, size_t keyLen) {
|
||||
config_last_key = scalloc(keyLen + 1, 1);
|
||||
strncpy(config_last_key, (const char *)keyVal, keyLen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static yajl_callbacks config_callbacks = {
|
||||
.yajl_string = config_string_cb,
|
||||
.yajl_start_map = config_start_map_cb,
|
||||
.yajl_map_key = config_map_key_cb,
|
||||
.yajl_end_map = config_end_map_cb,
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if defined(__OpenBSD__)
|
||||
if (pledge("stdio rpath unix", NULL) == -1)
|
||||
@ -150,25 +187,27 @@ int main(int argc, char *argv[]) {
|
||||
free(socket_path);
|
||||
socket_path = sstrdup(optarg);
|
||||
} else if (o == 't') {
|
||||
if (strcasecmp(optarg, "command") == 0)
|
||||
if (strcasecmp(optarg, "command") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_COMMAND;
|
||||
else if (strcasecmp(optarg, "get_workspaces") == 0)
|
||||
} else if (strcasecmp(optarg, "get_workspaces") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES;
|
||||
else if (strcasecmp(optarg, "get_outputs") == 0)
|
||||
} else if (strcasecmp(optarg, "get_outputs") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_OUTPUTS;
|
||||
else if (strcasecmp(optarg, "get_tree") == 0)
|
||||
} else if (strcasecmp(optarg, "get_tree") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_TREE;
|
||||
else if (strcasecmp(optarg, "get_marks") == 0)
|
||||
} else if (strcasecmp(optarg, "get_marks") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_MARKS;
|
||||
else if (strcasecmp(optarg, "get_bar_config") == 0)
|
||||
} else if (strcasecmp(optarg, "get_bar_config") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_BAR_CONFIG;
|
||||
else if (strcasecmp(optarg, "get_binding_modes") == 0)
|
||||
} else if (strcasecmp(optarg, "get_binding_modes") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_BINDING_MODES;
|
||||
else if (strcasecmp(optarg, "get_version") == 0)
|
||||
} else if (strcasecmp(optarg, "get_version") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_VERSION;
|
||||
else {
|
||||
} else if (strcasecmp(optarg, "get_config") == 0) {
|
||||
message_type = I3_IPC_MESSAGE_TYPE_GET_CONFIG;
|
||||
} else {
|
||||
printf("Unknown message type\n");
|
||||
printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_binding_modes, get_version\n");
|
||||
printf("Known types: command, get_workspaces, get_outputs, get_tree, get_marks, get_bar_config, get_binding_modes, get_version, get_config\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (o == 'q') {
|
||||
@ -241,7 +280,7 @@ int main(int argc, char *argv[]) {
|
||||
errx(EXIT_FAILURE, "IPC: Received reply of type %d but expected %d", reply_type, message_type);
|
||||
/* For the reply of commands, have a look if that command was successful.
|
||||
* If not, nicely format the error message. */
|
||||
if (reply_type == I3_IPC_MESSAGE_TYPE_COMMAND) {
|
||||
if (reply_type == I3_IPC_REPLY_TYPE_COMMAND) {
|
||||
yajl_handle handle = yajl_alloc(&reply_callbacks, NULL, NULL);
|
||||
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
|
||||
yajl_free(handle);
|
||||
@ -256,8 +295,24 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
/* NB: We still fall-through and print the reply, because even if one
|
||||
* command failed, that doesn’t mean that all commands failed. */
|
||||
} else if (reply_type == I3_IPC_REPLY_TYPE_CONFIG) {
|
||||
yajl_handle handle = yajl_alloc(&config_callbacks, NULL, NULL);
|
||||
yajl_status state = yajl_parse(handle, (const unsigned char *)reply, reply_length);
|
||||
yajl_free(handle);
|
||||
|
||||
switch (state) {
|
||||
case yajl_status_ok:
|
||||
break;
|
||||
case yajl_status_client_canceled:
|
||||
case yajl_status_error:
|
||||
errx(EXIT_FAILURE, "IPC: Could not parse JSON reply.");
|
||||
}
|
||||
|
||||
goto exit;
|
||||
}
|
||||
printf("%.*s\n", reply_length, reply);
|
||||
|
||||
exit:
|
||||
free(reply);
|
||||
|
||||
close(sockfd);
|
||||
|
Reference in New Issue
Block a user