Release 1.3.0

- Add IPC
This commit is contained in:
Cagebreak Signing Key 1 2020-05-25 23:06:29 +02:00
commit 0c185eef09
14 changed files with 503 additions and 116 deletions

View file

@ -94,6 +94,6 @@ difficult to reproduce.
* github issue number : N/A
* Fixed: 1.2.1
Our fuzzing framework up to and including release 1.2.0 does not the limit line
Our fuzzing framework up to and including release 1.2.0 does not limit line
lengths. This can crash the fuzzing framework with a segfault due to running
out of memory.

View file

@ -139,6 +139,9 @@ Release checklist
* [ ] Update signature of the binary
* [ ] Signature
* [ ] Branching Strategy
* [ ] git archive --prefix=cagebreak/ -o release_version.tar.gz tags/version .
* [ ] gpg --detach-sign -u keyid release_version.tar.gz
* [ ] upload build assets
### Signing Key
@ -180,6 +183,11 @@ ninja -C build
For every release after 1.0.5, hashes will be provided.
1.3.0
* sha 256: aecc5292f56f7250d777110cee1f11a92018a9eb2117d7d37cd51d7d3a5cbae0
* sha 512: 1d2d220f44787a97359a32f305e33185f0369551e61a9d7066023bfa43de50849eba5bcbb0083d2dc563ac993b8d51dd733afa0adb2a823ef50ecfee5624bbc0
1.2.1
* sha 256: 803f7667dc4997062f9ec95afcdca0cac68c82a7cf057cef83fe1ccfee33b8bc
@ -256,6 +264,10 @@ Unifies commands and actions. See Issue 4 in Bugs.md.
Adds output configuration as described in the man pages.
### Release 1.3.0
Adds IPC as described in the man pages.
## License
Please see [LICENSE](https://github.com/project-repo/cagebreak/blob/master/LICENSE)

View file

@ -47,6 +47,7 @@
#endif
#include "idle_inhibit_v1.h"
#include "ipc_server.h"
#include "keybinding.h"
#include "message.h"
#include "output.h"
@ -189,16 +190,19 @@ set_configuration(struct cg_server *server,
config_file_path);
return -1;
}
size_t max_line_size = 256;
char line[max_line_size * sizeof(char)];
char line[MAX_LINE_SIZE * sizeof(char)];
for(unsigned int line_num = 1;
fgets(line, max_line_size, config_file) != NULL; ++line_num) {
fgets(line, MAX_LINE_SIZE, config_file) != NULL; ++line_num) {
line[strcspn(line, "\n")] = '\0';
if(*line != '\0' && *line != '#') {
if(parse_rc_line(server, line) != 0) {
char *errstr;
if(parse_rc_line(server, line, &errstr) != 0) {
wlr_log(WLR_ERROR, "Error in config file \"%s\", line %d\n",
config_file_path, line_num);
fclose(config_file);
if(errstr != NULL) {
free(errstr);
}
return -1;
}
}
@ -289,7 +293,7 @@ main(int argc, char *argv[]) {
if(server.modes[0] == NULL || server.modes[1] == NULL ||
server.modes[2] == NULL) {
wlr_log(WLR_ERROR, "Error allocating default modes");
goto end;
return 1;
}
server.nws = 1;
@ -512,6 +516,12 @@ main(int argc, char *argv[]) {
wlr_xwayland_set_seat(xwayland, server.seat->seat);
#endif
if(ipc_init(&server) != 0) {
wlr_log(WLR_ERROR, "Failed to initialize IPC");
ret = 1;
goto end;
}
{ // config_file should only be visible as long as it is valid
char *config_file = get_config_file();
if(config_file == NULL) {
@ -534,7 +544,7 @@ main(int argc, char *argv[]) {
}
}
/* Place the cursor to the topl left of the output layout. */
/* Place the cursor to the top left of the output layout. */
wlr_cursor_warp(server.seat->cursor, NULL, 0, 0);
wl_display_run(server.wl_display);

View file

@ -406,7 +406,11 @@ set_configuration(struct cg_server *server, char *content) {
(line = strtok_r(NULL, "\n", &content)) != NULL; ++line_num) {
line[strcspn(line, "\n")] = '\0';
if(*line != '\0' && *line != '#') {
if(parse_rc_line(server, line) != 0) {
char *errstr;
if(parse_rc_line(server, line, &errstr) != 0) {
if(errstr != NULL) {
free(errstr);
}
return -1;
}
}

277
ipc_server.c Normal file
View file

@ -0,0 +1,277 @@
/*
* Cagebreak: A Wayland tiling compositor.
*
* Copyright (C) 2020 The Cagebreak Authors
* Copyright (C) 2018-2020 Jente Hidskes
*
* See the LICENSE file accompanying this file.
*/
#define _POSIX_C_SOURCE 200112L
#include "ipc_server.h"
#include "message.h"
#include "parse.h"
#include "server.h"
#include <fcntl.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <wlr/util/log.h>
static void
handle_display_destroy(struct wl_listener *listener, void *data) {
struct cg_ipc_handle *ipc = wl_container_of(listener, ipc, display_destroy);
if(ipc->event_source != NULL) {
wl_event_source_remove(ipc->event_source);
}
close(ipc->socket);
unlink(ipc->sockaddr->sun_path);
struct cg_ipc_client *tmp_client, *client;
wl_list_for_each_safe(client, tmp_client, &ipc->client_list, link) {
ipc_client_disconnect(client);
}
free(ipc->sockaddr);
wl_list_remove(&ipc->display_destroy.link);
}
int
ipc_init(struct cg_server *server) {
struct cg_ipc_handle *ipc = &server->ipc;
ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0);
if(ipc->socket == -1) {
wlr_log(WLR_ERROR, "Unable to create IPC socket");
return -1;
}
if(fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) {
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC socket");
return -1;
}
if(fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) {
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC socket");
return -1;
}
ipc->sockaddr = malloc(sizeof(struct sockaddr_un));
if(ipc->sockaddr == NULL) {
wlr_log(WLR_ERROR, "Unable to allocate socket address");
return -1;
}
ipc->sockaddr->sun_family = AF_UNIX;
int max_path_size = sizeof(ipc->sockaddr->sun_path);
const char *sockdir = getenv("XDG_RUNTIME_DIR");
if(sockdir == NULL) {
sockdir = "/tmp";
}
if(max_path_size <= snprintf(ipc->sockaddr->sun_path, max_path_size,
"%s/cagebreak-ipc.%i.%i.sock", sockdir,
getuid(), getpid())) {
wlr_log(WLR_ERROR, "Unable to write socket path to "
"ipc->sockaddr->sun_path. Path too long");
free(ipc->sockaddr);
return -1;
}
unlink(ipc->sockaddr->sun_path);
if(bind(ipc->socket, (struct sockaddr *)ipc->sockaddr,
sizeof(*ipc->sockaddr)) == -1) {
wlr_log(WLR_ERROR, "Unable to bind IPC socket");
free(ipc->sockaddr);
return -1;
}
if(listen(ipc->socket, 3) == -1) {
wlr_log(WLR_ERROR, "Unable to listen on IPC socket");
free(ipc->sockaddr);
return -1;
}
setenv("CAGEBREAK_SOCKET", ipc->sockaddr->sun_path, 1);
wl_list_init(&ipc->client_list);
ipc->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(server->wl_display, &ipc->display_destroy);
ipc->event_source =
wl_event_loop_add_fd(server->event_loop, ipc->socket, WL_EVENT_READABLE,
ipc_handle_connection, server);
return 0;
}
int
ipc_handle_connection(int fd, uint32_t mask, void *data) {
(void)fd;
struct cg_server *server = data;
struct cg_ipc_handle *ipc = &server->ipc;
if(mask != WL_EVENT_READABLE) {
wlr_log(WLR_ERROR, "Expected to receive a WL_EVENT_READABLE");
return 0;
}
int client_fd = accept(ipc->socket, NULL, NULL);
if(client_fd == -1) {
wlr_log(WLR_ERROR, "Unable to accept IPC client connection");
return 0;
}
int flags;
if((flags = fcntl(client_fd, F_GETFD)) == -1 ||
fcntl(client_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
wlr_log(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket");
close(client_fd);
return 0;
}
if((flags = fcntl(client_fd, F_GETFL)) == -1 ||
fcntl(client_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
wlr_log(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket");
close(client_fd);
return 0;
}
struct cg_ipc_client *client = malloc(sizeof(struct cg_ipc_client));
if(!client) {
wlr_log(WLR_ERROR, "Unable to allocate ipc client");
close(client_fd);
return 0;
}
// +1 for \n and +1 for \0
client->read_buffer = malloc(sizeof(char) * (MAX_LINE_SIZE + 2));
client->read_buf_len = 0;
client->read_discard = 0;
client->server = server;
client->fd = client_fd;
client->event_source =
wl_event_loop_add_fd(server->event_loop, client_fd, WL_EVENT_READABLE,
ipc_client_handle_readable, client);
client->writable_event_source = NULL;
client->write_buffer_size = 128;
client->write_buffer_len = 0;
client->write_buffer = malloc(client->write_buffer_size);
if(!client->write_buffer) {
wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer");
close(client_fd);
return 0;
}
wl_list_insert(&ipc->client_list, &client->link);
return 0;
}
int
ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
struct cg_ipc_client *client = data;
if(mask & WL_EVENT_ERROR) {
wlr_log(WLR_ERROR, "IPC Client socket error, removing client");
ipc_client_disconnect(client);
return 0;
}
if(mask & WL_EVENT_HANGUP) {
ipc_client_disconnect(client);
return 0;
}
int read_available;
if(ioctl(client_fd, FIONREAD, &read_available) < 0) {
wlr_log(WLR_ERROR, "Unable to read IPC socket buffer size");
ipc_client_disconnect(client);
return 0;
}
int read_size = read_available < MAX_LINE_SIZE + 1 - client->read_buf_len
? read_available
: MAX_LINE_SIZE + 1 - client->read_buf_len;
// Append to buffer
ssize_t received = recv(
client_fd, client->read_buffer + client->read_buf_len, read_size, 0);
if(received == -1) {
wlr_log(WLR_ERROR, "Unable to receive data from IPC client");
ipc_client_disconnect(client);
return 0;
}
client->read_buf_len += received;
ipc_client_handle_command(client);
return 0;
}
void
ipc_client_disconnect(struct cg_ipc_client *client) {
if(client == NULL) {
wlr_log(WLR_ERROR,
"Client \"NULL\" was passed to ipc_client_disconnect");
return;
}
shutdown(client->fd, SHUT_RDWR);
wl_event_source_remove(client->event_source);
if(client->writable_event_source) {
wl_event_source_remove(client->writable_event_source);
}
wl_list_remove(&client->link);
free(client->write_buffer);
free(client->read_buffer);
close(client->fd);
free(client);
}
void
ipc_client_handle_command(struct cg_ipc_client *client) {
if(client == NULL) {
wlr_log(WLR_ERROR,
"Client \"NULL\" was passed to ipc_client_handle_command");
return;
}
client->read_buffer[client->read_buf_len] = '\0';
char *nl_pos;
uint32_t offset = 0;
while((nl_pos = strchr(client->read_buffer + offset, '\n')) != NULL) {
if(client->read_discard) {
client->read_discard = 0;
} else {
*nl_pos = '\0';
char *line = client->read_buffer + offset;
if(*line != '\0' && *line != '#') {
message_clear(client->server->curr_output);
char *errstr;
if(parse_rc_line(client->server, line, &errstr) != 0) {
if(errstr != NULL) {
message_printf(client->server->curr_output, "%s",
errstr);
wlr_log(WLR_ERROR, "%s", errstr);
free(errstr);
}
wlr_log(WLR_ERROR, "Error parsing input from IPC socket");
}
}
}
offset = (nl_pos - client->read_buffer) + 1;
}
if(offset == 0) {
wlr_log(WLR_ERROR, "Line received was longer that %d, discarding it",
MAX_LINE_SIZE);
client->read_buf_len = 0;
client->read_discard = 1;
return;
}
if(offset < client->read_buf_len) {
memmove(client->read_buffer, client->read_buffer + offset,
client->read_buf_len - offset);
}
client->read_buf_len -= offset;
}

50
ipc_server.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef CG_IPC_SERVER_H
#define CG_IPC_SERVER_H
#include "config.h"
#include <inttypes.h>
#include <sys/types.h>
#include <wayland-server-core.h>
struct cg_server;
struct cg_ipc_client {
struct wl_event_source *event_source;
struct wl_event_source *writable_event_source;
struct cg_server *server;
struct wl_list link;
int fd;
uint32_t security_policy;
size_t write_buffer_len;
size_t write_buffer_size;
char *write_buffer;
// The following is for storing data between event_loop calls
uint16_t read_buf_len;
uint8_t read_discard; // 1 if the current line is to be discarded
char *read_buffer;
};
struct cg_ipc_handle {
int socket;
struct wl_event_source *event_source;
struct wl_list client_list;
struct wl_listener display_destroy;
struct sockaddr_un *sockaddr;
};
int
ipc_init(struct cg_server *server);
int
ipc_handle_connection(int fd, uint32_t mask, void *data);
int
ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
// int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
void
ipc_client_disconnect(struct cg_ipc_client *client);
void
ipc_client_handle_command(struct cg_ipc_client *client);
// bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t
// payload_length);
#endif

View file

@ -1,4 +1,4 @@
% CAGEBREAK-CONFIG(1) Version 1.2.1 | Cagebreak Manual
% CAGEBREAK-CONFIG(1) Version 1.3.0 | Cagebreak Manual
# NAME

View file

@ -1,4 +1,4 @@
% CAGEBREAK(1) Version 1.2.1 | Cagebreak Manual
% CAGEBREAK(1) Version 1.3.0 | Cagebreak Manual
# NAME
@ -18,10 +18,19 @@ in contrast to the original `ratpoison`, has native support for
multi-workspace operation.
All interactions between the user and `cagebreak` are done via
the keyboard. Configuration of this behaviour is specified
in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**).
the keyboard.
## OPTIONS
Configuration of this behaviour is specified in the
**\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**).
Scripting support is provided through the IPC
socket specified in the environment variable **\$CAGEBREAK_SOCKET**.
The syntax accepted through this socket is identical to
that of the configuration file (see **cagebreak-config(5)**).
Errors which occur during interaction over IPC channel
are displayed in a message box at the top right of the screen.
# OPTIONS
-h
@ -37,6 +46,11 @@ in the **\$XDG_CONFIG_PATH/cagebreak/config** file (See **cagebreak-config(5)**)
# ENVIRONMENT
`CAGEBREAK_SOCKET`
: The IPC unix domain socket address accepting
commands as specified in **cagebreak-config(5)**
`XKB_DEFAULT_LAYOUT`
: The keyboard layout to be used (See **xkeyboard-config(7)**)

View file

@ -1,5 +1,5 @@
project('cagebreak', 'c',
version: '1.2.1',
version: '1.3.0',
license: 'MIT',
default_options: [
'c_std=c11',
@ -123,6 +123,7 @@ conf_data.set_quoted('CG_VERSION', version)
cagebreak_main_file = [ 'cagebreak.c', ]
cagebreak_source_strings = [
'idle_inhibit_v1.c',
'ipc_server.c',
'keybinding.c',
'workspace.c',
'output.c',
@ -139,6 +140,7 @@ cagebreak_source_strings = [
cagebreak_header_strings = [
'idle_inhibit_v1.h',
'ipc_server.h',
'keybinding.h',
'workspace.h',
'output.h',

215
parse.c
View file

@ -11,12 +11,35 @@
#include "server.h"
#include "workspace.h"
char *
malloc_vsprintf(const char *fmt, va_list ap) {
va_list ap2;
va_copy(ap2, ap);
int len = vsnprintf(NULL, 0, fmt, ap);
char *ret = malloc(sizeof(char) * (len + 1));
vsnprintf(ret, len + 1, fmt, ap2);
va_end(ap2);
return ret;
}
char *
log_error(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *ret = malloc_vsprintf(fmt, args);
if(ret != NULL) {
wlr_log(WLR_ERROR, "%s", ret);
}
va_end(args);
return ret;
}
/* parses a key definition (e.g. "S-Tab") and sets key and modifiers in
* keybinding respectivly */
int
parse_key(struct keybinding *keybinding, const char *key_def) {
parse_key(struct keybinding *keybinding, const char *key_def, char **errstr) {
if(key_def == NULL) {
wlr_log(WLR_ERROR, "Expected key definition, got nothing.");
*errstr = log_error("Expected key definition, got nothing.");
return -1;
}
keybinding->modifiers = 0;
@ -44,14 +67,14 @@ parse_key(struct keybinding *keybinding, const char *key_def) {
keybinding->modifiers |= WLR_MODIFIER_MOD5;
break;
default:
wlr_log(WLR_ERROR, "Unknown modifier \"%c\"", key_def[0]);
*errstr = log_error("Unknown modifier \"%c\"", key_def[0]);
return -1;
}
key_def += 2;
}
xkb_keysym_t keysym = xkb_keysym_from_name(key_def, XKB_KEYSYM_NO_FLAGS);
if(keysym == XKB_KEY_NoSymbol) {
wlr_log(WLR_ERROR, "Could not convert key \"%s\" to keysym.", key_def);
*errstr = log_error("Could not convert key \"%s\" to keysym.", key_def);
return -1;
}
keybinding->key = keysym;
@ -60,25 +83,25 @@ parse_key(struct keybinding *keybinding, const char *key_def) {
int
parse_command(struct cg_server *server, struct keybinding *keybinding,
char *saveptr);
char *saveptr, char **errstr);
/* Parse a keybinding definition and return it if successful, else return NULL
*/
struct keybinding *
parse_keybinding(struct cg_server *server, char **saveptr) {
parse_keybinding(struct cg_server *server, char **saveptr, char **errstr) {
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
if(keybinding == NULL) {
wlr_log(WLR_ERROR,
"Failed to allocate memory for keybinding in parse_keybinding");
*errstr = log_error(
"Failed to allocate memory for keybinding in parse_keybinding");
return NULL;
}
char *key = strtok_r(NULL, " ", saveptr);
if(parse_key(keybinding, key) != 0) {
if(parse_key(keybinding, key, errstr) != 0) {
wlr_log(WLR_ERROR, "Could not parse key definition \"%s\"", key);
free(keybinding);
return NULL;
}
if(parse_command(server, keybinding, *saveptr) != 0) {
if(parse_command(server, keybinding, *saveptr, errstr) != 0) {
free(keybinding);
return NULL;
}
@ -86,8 +109,8 @@ parse_keybinding(struct cg_server *server, char **saveptr) {
}
struct keybinding *
parse_bind(struct cg_server *server, char **saveptr) {
struct keybinding *keybinding = parse_keybinding(server, saveptr);
parse_bind(struct cg_server *server, char **saveptr, char **errstr) {
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
if(keybinding == NULL) {
wlr_log(WLR_ERROR, "Could not parse keybinding for \"bind\".");
return NULL;
@ -97,18 +120,19 @@ parse_bind(struct cg_server *server, char **saveptr) {
}
struct keybinding *
parse_definekey(struct cg_server *server, char **saveptr) {
parse_definekey(struct cg_server *server, char **saveptr, char **errstr) {
char *mode = strtok_r(NULL, " ", saveptr);
if(mode == NULL) {
wlr_log(WLR_ERROR, "Too few arguments to \"definekey\". Expected mode");
*errstr =
log_error("Too few arguments to \"definekey\". Expected mode");
return NULL;
}
int mode_idx = get_mode_index_from_name(server->modes, mode);
if(mode_idx == -1) {
wlr_log(WLR_ERROR, "Unknown mode \"%s\"", mode);
*errstr = log_error("Unknown mode \"%s\"", mode);
return NULL;
}
struct keybinding *keybinding = parse_keybinding(server, saveptr);
struct keybinding *keybinding = parse_keybinding(server, saveptr, errstr);
if(keybinding == NULL) {
wlr_log(WLR_ERROR, "Could not parse keybinding for \"definekey\"");
return NULL;
@ -118,16 +142,16 @@ parse_definekey(struct cg_server *server, char **saveptr) {
}
int
parse_background(struct cg_server *server, float *color, char **saveptr) {
parse_background(struct cg_server *server, float *color, char **saveptr,
char **errstr) {
/* Read rgb numbers */
for(unsigned int i = 0; i < 3; ++i) {
char *nstr = strtok_r(NULL, " \n", saveptr);
int nstrlen;
if(nstr == NULL || (nstrlen = strlen(nstr)) == 0) {
wlr_log(WLR_ERROR,
"Expected three space-separated numbers (rgb) for "
"background color setting. Got %d.",
i);
*errstr = log_error("Expected three space-separated numbers (rgb) "
"for background color setting. Got %d.",
i);
return -1;
}
if(nstr[nstrlen - 1] == '\n') {
@ -137,17 +161,15 @@ parse_background(struct cg_server *server, float *color, char **saveptr) {
char *endptr = NULL;
float nval = strtof(nstr, &endptr);
if(endptr != nstr + nstrlen) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Could not parse number \"%s\" for background color setting.",
nstr);
return -1;
}
if(nval < 0 || nval > 1) {
wlr_log(WLR_ERROR,
"Expected a number between 0 and 1 for setting of "
"background color. Got %f.",
nval);
*errstr = log_error("Expected a number between 0 and 1 for setting "
"of background color. Got %f.",
nval);
return -1;
}
color[i] = nval;
@ -156,15 +178,15 @@ parse_background(struct cg_server *server, float *color, char **saveptr) {
}
struct keybinding *
parse_escape(char **saveptr) {
parse_escape(char **saveptr, char **errstr) {
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
if(keybinding == NULL) {
wlr_log(WLR_ERROR,
"Failed to allocate memory for keybinding in parse_escape");
*errstr = log_error(
"Failed to allocate memory for keybinding in parse_escape");
return NULL;
}
char *key = strtok_r(NULL, " ", saveptr);
if(parse_key(keybinding, key) != 0) {
if(parse_key(keybinding, key, errstr) != 0) {
wlr_log(WLR_ERROR,
"Could not parse key definition \"%s\" for \"escape\"", key);
free(keybinding);
@ -177,27 +199,27 @@ parse_escape(char **saveptr) {
}
char *
parse_definemode(char **saveptr) {
parse_definemode(char **saveptr, char **errstr) {
char *mode = strtok_r(NULL, " ", saveptr);
if(mode == NULL) {
wlr_log(WLR_ERROR, "Expected mode to succeed \"definemode\" keyword.");
*errstr = log_error("Expected mode to succeed \"definemode\" keyword.");
return NULL;
}
return strdup(mode);
}
int
parse_workspaces(char **saveptr) {
parse_workspaces(char **saveptr, char **errstr) {
char *nws_str = strtok_r(NULL, " ", saveptr);
if(nws_str == NULL) {
wlr_log(WLR_ERROR,
"Expected argument for \"workspaces\" command, got none.");
*errstr = log_error(
"Expected argument for \"workspaces\" command, got none.");
return -1;
}
long nws = strtol(nws_str, NULL, 10);
if(!(1 <= nws && nws <= 30)) {
wlr_log(WLR_ERROR,
"More than 30 workspaces are not supported. Received %li", nws);
*errstr = log_error(
"More than 30 workspaces are not supported. Received %li", nws);
return -1;
}
return nws;
@ -240,23 +262,23 @@ parse_float(char **saveptr, const char *delim) {
}
int
parse_output_config(struct wl_list *config_list, char **saveptr) {
parse_output_config(struct wl_list *config_list, char **saveptr,
char **errstr) {
struct cg_output_config *cfg = malloc(sizeof(struct cg_output_config));
if(cfg == NULL) {
wlr_log(WLR_ERROR,
"Failed to allocate memory for output configuration");
*errstr =
log_error("Failed to allocate memory for output configuration");
goto error;
}
char *name = strtok_r(NULL, " ", saveptr);
if(name == NULL) {
wlr_log(WLR_ERROR,
"Expected name of output to be configured, got none");
*errstr =
log_error("Expected name of output to be configured, got none");
goto error;
}
char *pos_str = strtok_r(NULL, " ", saveptr);
if(pos_str == NULL || strcmp(pos_str, "pos") != 0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Expected keyword \"pos\" in output configuration for output %s",
name);
goto error;
@ -264,8 +286,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
cfg->pos.x = parse_uint(saveptr, " ");
if(cfg->pos.x < 0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Error parsing x coordinate of output configuration for output %s",
name);
goto error;
@ -273,8 +294,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
cfg->pos.y = parse_uint(saveptr, " ");
if(cfg->pos.y < 0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Error parsing y coordinate of output configuration for output %s",
name);
goto error;
@ -282,8 +302,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
char *res_str = strtok_r(NULL, " ", saveptr);
if(res_str == NULL || strcmp(res_str, "res") != 0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Expected keyword \"res\" in output configuration for output %s",
name);
goto error;
@ -291,26 +310,23 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
cfg->pos.width = parse_uint(saveptr, "x");
if(cfg->pos.width <= 0) {
wlr_log(WLR_ERROR,
"Error parsing width of output configuration for output %s "
"(hint: width must be larger than 0)",
name);
*errstr = log_error("Error parsing width of output configuration for "
"output %s (hint: width must be larger than 0)",
name);
goto error;
}
cfg->pos.height = parse_uint(saveptr, " ");
if(cfg->pos.height <= 0) {
wlr_log(WLR_ERROR,
"Error parsing height of output configuration for output %s "
"(hint: height must e larger than 0)",
name);
*errstr = log_error("Error parsing height of output configuration for "
"output %s (hint: height must e larger than 0)",
name);
goto error;
}
char *rate_str = strtok_r(NULL, " ", saveptr);
if(rate_str == NULL || strcmp(rate_str, "rate") != 0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Expected keyword \"rate\" in output configuration for output %s",
name);
goto error;
@ -318,8 +334,7 @@ parse_output_config(struct wl_list *config_list, char **saveptr) {
cfg->refresh_rate = parse_float(saveptr, " ");
if(cfg->refresh_rate <= 0.0) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Error parsing refresh rate of output configuration for output %s",
name);
goto error;
@ -346,10 +361,10 @@ error:
int
parse_command(struct cg_server *server, struct keybinding *keybinding,
char *saveptr) {
char *saveptr, char **errstr) {
char *action = strtok_r(NULL, " ", &saveptr);
if(action == NULL) {
wlr_log(WLR_ERROR, "Expected an action to parse, got none.");
*errstr = log_error("Expexted an action to parse, got none.");
return -1;
}
keybinding->data = (union keybinding_params){.c = NULL};
@ -386,8 +401,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
} else if(strcmp(action, "exec") == 0) {
keybinding->action = KEYBINDING_RUN_COMMAND;
if(saveptr == NULL) {
wlr_log(WLR_ERROR, "Not enough paramaters to \"exec\". Expected "
"string to execute.");
*errstr = log_error("Not enough paramaters to \"exec\". Expected "
"string to execute.");
return -1;
}
keybinding->data.c = strdup(saveptr);
@ -407,17 +422,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_SWITCH_WORKSPACE;
char *nws_str = strtok_r(NULL, " ", &saveptr);
if(nws_str == NULL) {
wlr_log(WLR_ERROR,
"Expected argument for \"workspace\" action, got none.");
*errstr = log_error(
"Expected argument for \"workspace\" action, got none.");
return -1;
}
long ws = strtol(nws_str, NULL, 10);
if(ws < 1) {
wlr_log(WLR_ERROR,
"Workspace number must be a integer number larger or equal "
"to 1. Got %ld",
ws);
*errstr = log_error("Workspace number must be an integer number "
"larger or equal to 1. Got %ld",
ws);
return -1;
}
keybinding->data.u = ws - 1;
@ -425,17 +439,16 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_MOVE_VIEW_TO_WORKSPACE;
char *nws_str = strtok_r(NULL, " ", &saveptr);
if(nws_str == NULL) {
wlr_log(WLR_ERROR,
"Expected argument for \"workspace\" action, got none.");
*errstr = log_error(
"Expected argument for \"workspace\" action, got none.");
return -1;
}
long ws = strtol(nws_str, NULL, 10);
if(ws < 1) {
wlr_log(WLR_ERROR,
"Workspace number must be an integer larger or equal to 1. "
"Got %ld",
ws);
*errstr = log_error("Workspace number must be an integer larger or "
"equal to 1. Got %ld",
ws);
return -1;
}
keybinding->data.u = ws - 1;
@ -461,8 +474,8 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_CHANGE_TTY;
char *ntty = strtok_r(NULL, " ", &saveptr);
if(ntty == NULL) {
wlr_log(WLR_ERROR,
"Expected argument for \"switchvt\" command, got none.");
*errstr = log_error(
"Expected argument for \"switchvt\" command, got none.");
return -1;
}
long tty = strtol(ntty, NULL, 10);
@ -471,13 +484,13 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_SWITCH_MODE;
char *mode = strtok_r(NULL, " ", &saveptr);
if(mode == NULL) {
wlr_log(WLR_ERROR,
"Expected mode after \"switch_mode\". Got nothing.");
*errstr =
log_error("Expected mode after \"switch_mode\". Got nothing.");
return -1;
}
int mode_idx = get_mode_index_from_name(server->modes, mode);
if(mode_idx == -1) {
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_mode", mode);
*errstr = log_error("Unknown mode \"%s\" for switch_mode", mode);
return -1;
}
keybinding->data.u = (unsigned int)mode_idx;
@ -485,78 +498,78 @@ parse_command(struct cg_server *server, struct keybinding *keybinding,
keybinding->action = KEYBINDING_SWITCH_DEFAULT_MODE;
char *mode = strtok_r(NULL, " ", &saveptr);
if(mode == NULL) {
wlr_log(
WLR_ERROR,
*errstr = log_error(
"Expected mode after \"switch_default_mode\". Got nothing.");
return -1;
}
int mode_idx = get_mode_index_from_name(server->modes, mode);
if(mode_idx == -1) {
wlr_log(WLR_ERROR, "Unknown mode \"%s\" for switch_default_mode",
mode);
*errstr =
log_error("Unknown mode \"%s\" for switch_default_mode", mode);
return -1;
}
keybinding->data.u = (unsigned int)mode_idx;
} else if(strcmp(action, "bind") == 0) {
keybinding->action = KEYBINDING_DEFINEKEY;
keybinding->data.kb = parse_bind(server, &saveptr);
keybinding->data.kb = parse_bind(server, &saveptr, errstr);
if(keybinding->data.kb == NULL) {
return -1;
}
} else if(strcmp(action, "definekey") == 0) {
keybinding->action = KEYBINDING_DEFINEKEY;
keybinding->data.kb = parse_definekey(server, &saveptr);
keybinding->data.kb = parse_definekey(server, &saveptr, errstr);
if(keybinding->data.kb == NULL) {
return -1;
}
} else if(strcmp(action, "background") == 0) {
keybinding->action = KEYBINDING_BACKGROUND;
if(parse_background(server, keybinding->data.color, &saveptr) != 0) {
if(parse_background(server, keybinding->data.color, &saveptr, errstr) !=
0) {
return -1;
}
} else if(strcmp(action, "escape") == 0) {
keybinding->action = KEYBINDING_DEFINEKEY;
keybinding->data.kb = parse_escape(&saveptr);
keybinding->data.kb = parse_escape(&saveptr, errstr);
if(keybinding->data.kb == NULL) {
return -1;
}
} else if(strcmp(action, "definemode") == 0) {
keybinding->action = KEYBINDING_DEFINEMODE;
keybinding->data.c = parse_definemode(&saveptr);
keybinding->data.c = parse_definemode(&saveptr, errstr);
if(keybinding->data.c == NULL) {
return -1;
}
} else if(strcmp(action, "workspaces") == 0) {
keybinding->action = KEYBINDING_WORKSPACES;
keybinding->data.i = parse_workspaces(&saveptr);
keybinding->data.i = parse_workspaces(&saveptr, errstr);
if(keybinding->data.i < 0) {
return -1;
}
} else if(strcmp(action, "output") == 0) {
if(parse_output_config(&server->output_config, &saveptr) != 0) {
if(parse_output_config(&server->output_config, &saveptr, errstr) != 0) {
return -1;
}
} else {
wlr_log(WLR_ERROR, "Error, unsupported action \"%s\".", action);
*errstr = log_error("Error, unsupported action \"%s\".", action);
return -1;
}
return 0;
}
int
parse_rc_line(struct cg_server *server, char *line) {
parse_rc_line(struct cg_server *server, char *line, char **errstr) {
char *saveptr = strdup(line); // Used internally by strtok_r
struct keybinding *keybinding = malloc(sizeof(struct keybinding));
if(keybinding == NULL) {
wlr_log(WLR_ERROR,
"Failed to allocate memory for temporary keybinding struct.");
*errstr = log_error(
"Failed to allocate memory for temporary keybinding struct.");
free(keybinding);
free(saveptr);
return -1;
}
if(parse_command(server, keybinding, saveptr) != 0) {
wlr_log(WLR_ERROR, "Error parsing config file.");
if(parse_command(server, keybinding, saveptr, errstr) != 0) {
wlr_log(WLR_ERROR, "Error parsing command.");
free(keybinding);
free(saveptr);
return -1;

View file

@ -2,9 +2,11 @@
#define PARSE_H
#define MAX_LINE_SIZE 256
struct cg_server;
int
parse_rc_line(struct cg_server *server, char *line);
parse_rc_line(struct cg_server *server, char *line, char **errstr);
#endif /* end of include guard PARSE_H */

View file

@ -2,6 +2,7 @@
#define CG_SERVER_H
#include "config.h"
#include "ipc_server.h"
#include <wayland-server-core.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
@ -40,6 +41,8 @@ struct cg_server {
enum wl_output_transform output_transform;
struct cg_ipc_handle ipc;
bool running;
char **modes;
uint16_t nws;

BIN
signatures/1.2.1.sig Normal file

Binary file not shown.

Binary file not shown.