Show swaynag on config errors

This commit is contained in:
Brian Ashworth 2018-08-01 23:54:40 -04:00
parent 3e2bf7f3a5
commit f9a6407111
6 changed files with 118 additions and 20 deletions

View file

@ -308,6 +308,7 @@ enum focus_wrapping_mode {
* The configuration struct. The result of loading a config file. * The configuration struct. The result of loading a config file.
*/ */
struct sway_config { struct sway_config {
pid_t swaynag_pid;
list_t *symbols; list_t *symbols;
list_t *modes; list_t *modes;
list_t *bars; list_t *bars;
@ -403,17 +404,18 @@ struct sway_config {
* Loads the main config from the given path. is_active should be true when * Loads the main config from the given path. is_active should be true when
* reloading the config. * reloading the config.
*/ */
bool load_main_config(const char *path, bool is_active); bool load_main_config(const char *path, bool is_active, char **errors);
/** /**
* Loads an included config. Can only be used after load_main_config. * Loads an included config. Can only be used after load_main_config.
*/ */
bool load_include_configs(const char *path, struct sway_config *config); bool load_include_configs(const char *path, struct sway_config *config,
char **errors);
/** /**
* Reads the config from the given FILE. * Reads the config from the given FILE.
*/ */
bool read_config(FILE *file, struct sway_config *config); bool read_config(FILE *file, struct sway_config *config, char **errors);
/** /**
* Free config struct * Free config struct
@ -422,6 +424,8 @@ void free_config(struct sway_config *config);
void free_sway_variable(struct sway_variable *var); void free_sway_variable(struct sway_variable *var);
void spawn_swaynag_config_errors(struct sway_config *config, char *errors);
/** /**
* Does variable replacement for a string based on the config's currently loaded variables. * Does variable replacement for a string based on the config's currently loaded variables.
*/ */

View file

@ -511,11 +511,14 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
results->input = NULL; results->input = NULL;
} }
if (format) { if (format) {
char *error = malloc(256);
va_list args; va_list args;
va_start(args, format); va_start(args, format);
size_t length = vsnprintf(NULL, 0, format, args) + 1;
char *error = malloc(length);
va_end(args);
va_start(args, format);
if (error) { if (error) {
vsnprintf(error, 256, format, args); vsnprintf(error, length, format, args);
} }
va_end(args); va_end(args);
results->error = error; results->error = error;

View file

@ -7,8 +7,19 @@ struct cmd_results *cmd_include(int argc, char **argv) {
return error; return error;
} }
if (!load_include_configs(argv[0], config)) { char *errors = NULL;
return cmd_results_new(CMD_INVALID, "include", "Failed to include sub configuration file: %s", argv[0]); if (!load_include_configs(argv[0], config, &errors)) {
struct cmd_results *result = cmd_results_new(CMD_INVALID, "include",
"Failed to include sub configuration file: %s", argv[0]);
free(errors);
return result;
}
if (errors) {
struct cmd_results *result = cmd_results_new(CMD_INVALID, "include",
"There are errors in the included config\n%s", errors);
free(errors);
return result;
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);

View file

@ -1,4 +1,5 @@
#define _XOPEN_SOURCE 500 #define _XOPEN_SOURCE 500
#include <signal.h>
#include <string.h> #include <string.h>
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
@ -19,8 +20,11 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
list_add(bar_ids, strdup(bar->id)); list_add(bar_ids, strdup(bar->id));
} }
if (!load_main_config(config->current_config_path, true)) { char *errors = NULL;
return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); if (!load_main_config(config->current_config_path, true, &errors)) {
free(errors);
return cmd_results_new(CMD_FAILURE, "reload",
"Error(s) reloading config.");
} }
ipc_event_workspace(NULL, NULL, "reload"); ipc_event_workspace(NULL, NULL, "reload");
@ -42,5 +46,16 @@ struct cmd_results *cmd_reload(int argc, char **argv) {
list_free(bar_ids); list_free(bar_ids);
arrange_windows(&root_container); arrange_windows(&root_container);
if (config->swaynag_pid > 0) {
kill(config->swaynag_pid, SIGTERM);
config->swaynag_pid = -1;
}
if (errors) {
spawn_swaynag_config_errors(config, errors);
free(errors);
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL); return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} }

View file

@ -158,6 +158,7 @@ static void set_color(float dest[static 4], uint32_t color) {
} }
static void config_defaults(struct sway_config *config) { static void config_defaults(struct sway_config *config) {
config->swaynag_pid = -1;
if (!(config->symbols = create_list())) goto cleanup; if (!(config->symbols = create_list())) goto cleanup;
if (!(config->modes = create_list())) goto cleanup; if (!(config->modes = create_list())) goto cleanup;
if (!(config->bars = create_list())) goto cleanup; if (!(config->bars = create_list())) goto cleanup;
@ -319,7 +320,8 @@ static char *get_config_path(void) {
return NULL; // Not reached return NULL; // Not reached
} }
static bool load_config(const char *path, struct sway_config *config) { static bool load_config(const char *path, struct sway_config *config,
char **errors) {
if (path == NULL) { if (path == NULL) {
wlr_log(WLR_ERROR, "Unable to find a config file!"); wlr_log(WLR_ERROR, "Unable to find a config file!");
return false; return false;
@ -338,7 +340,7 @@ static bool load_config(const char *path, struct sway_config *config) {
return false; return false;
} }
bool config_load_success = read_config(f, config); bool config_load_success = read_config(f, config, errors);
fclose(f); fclose(f);
if (!config_load_success) { if (!config_load_success) {
@ -348,7 +350,7 @@ static bool load_config(const char *path, struct sway_config *config) {
return true; return true;
} }
bool load_main_config(const char *file, bool is_active) { bool load_main_config(const char *file, bool is_active, char **errors) {
char *path; char *path;
if (file != NULL) { if (file != NULL) {
path = strdup(file); path = strdup(file);
@ -365,6 +367,7 @@ bool load_main_config(const char *file, bool is_active) {
config_defaults(config); config_defaults(config);
if (is_active) { if (is_active) {
wlr_log(WLR_DEBUG, "Performing configuration file reload"); wlr_log(WLR_DEBUG, "Performing configuration file reload");
config->swaynag_pid = old_config->swaynag_pid;
config->reloading = true; config->reloading = true;
config->active = true; config->active = true;
create_default_output_configs(); create_default_output_configs();
@ -423,7 +426,7 @@ bool load_main_config(const char *file, bool is_active) {
} }
*/ */
success = success && load_config(path, config); success = success && load_config(path, config, errors);
if (is_active) { if (is_active) {
for (int i = 0; i < config->output_configs->length; i++) { for (int i = 0; i < config->output_configs->length; i++) {
@ -441,7 +444,7 @@ bool load_main_config(const char *file, bool is_active) {
} }
static bool load_include_config(const char *path, const char *parent_dir, static bool load_include_config(const char *path, const char *parent_dir,
struct sway_config *config) { struct sway_config *config, char **errors) {
// save parent config // save parent config
const char *parent_config = config->current_config_path; const char *parent_config = config->current_config_path;
@ -485,7 +488,7 @@ static bool load_include_config(const char *path, const char *parent_dir,
list_add(config->config_chain, real_path); list_add(config->config_chain, real_path);
int index = config->config_chain->length - 1; int index = config->config_chain->length - 1;
if (!load_config(real_path, config)) { if (!load_config(real_path, config, errors)) {
free(real_path); free(real_path);
config->current_config_path = parent_config; config->current_config_path = parent_config;
list_del(config->config_chain, index); list_del(config->config_chain, index);
@ -497,7 +500,8 @@ static bool load_include_config(const char *path, const char *parent_dir,
return true; return true;
} }
bool load_include_configs(const char *path, struct sway_config *config) { bool load_include_configs(const char *path, struct sway_config *config,
char **errors) {
char *wd = getcwd(NULL, 0); char *wd = getcwd(NULL, 0);
char *parent_path = strdup(config->current_config_path); char *parent_path = strdup(config->current_config_path);
const char *parent_dir = dirname(parent_path); const char *parent_dir = dirname(parent_path);
@ -519,7 +523,7 @@ bool load_include_configs(const char *path, struct sway_config *config) {
char **w = p.we_wordv; char **w = p.we_wordv;
size_t i; size_t i;
for (i = 0; i < p.we_wordc; ++i) { for (i = 0; i < p.we_wordc; ++i) {
load_include_config(w[i], parent_dir, config); load_include_config(w[i], parent_dir, config, errors);
} }
free(parent_path); free(parent_path);
wordfree(&p); wordfree(&p);
@ -575,7 +579,26 @@ static char *expand_line(const char *block, const char *line, bool add_brace) {
return expanded; return expanded;
} }
bool read_config(FILE *file, struct sway_config *config) { static void log_error(char **errors, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args);
int offset = *errors ? strlen(*errors) : 0;
char *temp = realloc(*errors, offset + length + 1);
if (!temp) {
wlr_log(WLR_ERROR, "Failed to realloc error log");
return;
}
*errors = temp;
va_start(args, fmt);
vsnprintf(*errors + offset, length, fmt, args);
va_end(args);
}
bool read_config(FILE *file, struct sway_config *config, char **errors) {
bool reading_main_config = false; bool reading_main_config = false;
char *this_config = NULL; char *this_config = NULL;
size_t config_size = 0; size_t config_size = 0;
@ -665,6 +688,8 @@ bool read_config(FILE *file, struct sway_config *config) {
case CMD_INVALID: case CMD_INVALID:
wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number, wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number,
line, res->error, config->current_config_path); line, res->error, config->current_config_path);
log_error(errors, "Error on line %i (%s) '%s': %s\n", line_number,
config->current_config_path, line, res->error);
success = false; success = false;
break; break;
@ -713,6 +738,38 @@ bool read_config(FILE *file, struct sway_config *config) {
return success; return success;
} }
void spawn_swaynag_config_errors(struct sway_config *config, char *errors) {
char *command = "swaynag "
"--type error "
"--message 'There are errors in your config file' "
"--detailed-message "
"--button 'Exit sway' 'swaymsg exit' "
"--button 'Reload sway' 'swaymsg reload'";
int fd[2];
if (pipe(fd) != 0) {
wlr_log(WLR_ERROR, "Failed to create pipe for swaynag");
return;
}
pid_t pid;
if ((pid = fork()) == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
execl("/bin/sh", "/bin/sh", "-c", command, NULL);
_exit(0);
} else if (pid < 0) {
wlr_log(WLR_ERROR, "Failed to create fork for swaynag");
}
close(fd[0]);
write(fd[1], errors, strlen(errors));
close(fd[1]);
config->swaynag_pid = pid;
}
char *do_var_replacement(char *str) { char *do_var_replacement(char *str) {
int i; int i;
char *find = str; char *find = str;

View file

@ -415,12 +415,14 @@ int main(int argc, char **argv) {
ipc_init(&server); ipc_init(&server);
log_env(); log_env();
char *errors = NULL;
if (validate) { if (validate) {
bool valid = load_main_config(config_path, false); bool valid = load_main_config(config_path, false, &errors);
free(errors);
return valid ? 0 : 1; return valid ? 0 : 1;
} }
if (!load_main_config(config_path, false)) { if (!load_main_config(config_path, false, &errors)) {
sway_terminate(EXIT_FAILURE); sway_terminate(EXIT_FAILURE);
} }
@ -433,6 +435,7 @@ int main(int argc, char **argv) {
setenv("WAYLAND_DISPLAY", server.socket, true); setenv("WAYLAND_DISPLAY", server.socket, true);
if (!terminate_request) { if (!terminate_request) {
if (!server_start_backend(&server)) { if (!server_start_backend(&server)) {
free(errors);
sway_terminate(EXIT_FAILURE); sway_terminate(EXIT_FAILURE);
} }
} }
@ -452,6 +455,11 @@ int main(int argc, char **argv) {
} }
transaction_commit_dirty(); transaction_commit_dirty();
if (errors) {
spawn_swaynag_config_errors(config, errors);
free(errors);
}
if (!terminate_request) { if (!terminate_request) {
server_run(&server); server_run(&server);
} }