17fe8924f2
wordexp p is now initialized to {0} to prevent a segfault on wordfree in the failure case. File paths with single quotes and double quotes are now supported. The quote can either be wrapped in the other quote or escaped with three backslashes. Additionally to make passing file paths with double quotes to swaybg easier, instead of enclosing the path given to swaybg in quotes, all spaces, single quotes, and double quotes in the resulting path are now escaped with a single backslash.
167 lines
4.3 KiB
C
167 lines
4.3 KiB
C
#define _POSIX_C_SOURCE 200809
|
|
#include <libgen.h>
|
|
#include <strings.h>
|
|
#include <unistd.h>
|
|
#include <wordexp.h>
|
|
#include <errno.h>
|
|
#include "sway/commands.h"
|
|
#include "sway/config.h"
|
|
#include "sway/swaynag.h"
|
|
#include "log.h"
|
|
#include "stringop.h"
|
|
|
|
static const char *bg_options[] = {
|
|
"stretch",
|
|
"center",
|
|
"fill",
|
|
"fit",
|
|
"tile",
|
|
};
|
|
|
|
struct cmd_results *output_cmd_background(int argc, char **argv) {
|
|
if (!config->handler_context.output_config) {
|
|
return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
|
|
}
|
|
if (!argc) {
|
|
return cmd_results_new(CMD_INVALID, "output",
|
|
"Missing background file or color specification.");
|
|
}
|
|
if (argc < 2) {
|
|
return cmd_results_new(CMD_INVALID, "output",
|
|
"Missing background scaling mode or `solid_color`.");
|
|
}
|
|
|
|
struct output_config *output = config->handler_context.output_config;
|
|
|
|
if (strcasecmp(argv[1], "solid_color") == 0) {
|
|
output->background = calloc(1, strlen(argv[0]) + 3);
|
|
snprintf(output->background, strlen(argv[0]) + 3, "\"%s\"", argv[0]);
|
|
output->background_option = strdup("solid_color");
|
|
output->background_fallback = NULL;
|
|
argc -= 2; argv += 2;
|
|
} else {
|
|
bool valid = false;
|
|
char *mode;
|
|
size_t j;
|
|
for (j = 0; j < (size_t)argc; ++j) {
|
|
mode = argv[j];
|
|
size_t n = sizeof(bg_options) / sizeof(char *);
|
|
for (size_t k = 0; k < n; ++k) {
|
|
if (strcasecmp(mode, bg_options[k]) == 0) {
|
|
valid = true;
|
|
break;
|
|
}
|
|
}
|
|
if (valid) {
|
|
break;
|
|
}
|
|
}
|
|
if (!valid) {
|
|
return cmd_results_new(CMD_INVALID, "output",
|
|
"Missing background scaling mode.");
|
|
}
|
|
|
|
wordexp_t p = {0};
|
|
char *src = join_args(argv, j);
|
|
while (strstr(src, " ")) {
|
|
src = realloc(src, strlen(src) + 2);
|
|
char *ptr = strstr(src, " ") + 1;
|
|
memmove(ptr + 1, ptr, strlen(ptr) + 1);
|
|
*ptr = '\\';
|
|
}
|
|
if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
|
|
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID, "output",
|
|
"Invalid syntax (%s)", src);
|
|
free(src);
|
|
wordfree(&p);
|
|
return cmd_res;
|
|
}
|
|
free(src);
|
|
src = join_args(p.we_wordv, p.we_wordc);
|
|
wordfree(&p);
|
|
if (!src) {
|
|
wlr_log(WLR_ERROR, "Failed to duplicate string");
|
|
return cmd_results_new(CMD_FAILURE, "output",
|
|
"Unable to allocate resource");
|
|
}
|
|
|
|
if (config->reading && *src != '/') {
|
|
// src file is inside configuration dir
|
|
|
|
char *conf = strdup(config->current_config_path);
|
|
if (!conf) {
|
|
wlr_log(WLR_ERROR, "Failed to duplicate string");
|
|
free(src);
|
|
return cmd_results_new(CMD_FAILURE, "output",
|
|
"Unable to allocate resources");
|
|
}
|
|
|
|
char *conf_path = dirname(conf);
|
|
char *rel_path = src;
|
|
src = malloc(strlen(conf_path) + strlen(src) + 2);
|
|
if (!src) {
|
|
free(rel_path);
|
|
free(conf);
|
|
wlr_log(WLR_ERROR, "Unable to allocate memory");
|
|
return cmd_results_new(CMD_FAILURE, "output",
|
|
"Unable to allocate resources");
|
|
}
|
|
|
|
sprintf(src, "%s/%s", conf_path, rel_path);
|
|
free(rel_path);
|
|
free(conf);
|
|
}
|
|
|
|
bool can_access = access(src, F_OK) != -1;
|
|
if (!can_access) {
|
|
wlr_log(WLR_ERROR, "Unable to access background file '%s': %s",
|
|
src, strerror(errno));
|
|
if (config->reading && !config->validating) {
|
|
swaynag_log(config->swaynag_command,
|
|
&config->swaynag_config_errors,
|
|
"Unable to access background file '%s'", src);
|
|
}
|
|
free(src);
|
|
} else {
|
|
// Escape spaces and quotes in the final path for swaybg
|
|
for (size_t i = 0; i < strlen(src); i++) {
|
|
switch (src[i]) {
|
|
case ' ':
|
|
case '\'':
|
|
case '\"':
|
|
src = realloc(src, strlen(src) + 2);
|
|
memmove(src + i + 1, src + i, strlen(src + i) + 1);
|
|
*(src + i) = '\\';
|
|
i++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
output->background = src;
|
|
output->background_option = strdup(mode);
|
|
}
|
|
argc -= j + 1; argv += j + 1;
|
|
|
|
output->background_fallback = NULL;
|
|
if (argc && *argv[0] == '#') {
|
|
output->background_fallback = calloc(1, strlen(argv[0]) + 3);
|
|
snprintf(output->background_fallback, strlen(argv[0]) + 3,
|
|
"\"%s\"", argv[0]);
|
|
argc--; argv++;
|
|
|
|
if (!can_access) {
|
|
output->background = output->background_fallback;
|
|
output->background_option = strdup("solid_color");
|
|
output->background_fallback = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
config->handler_context.leftovers.argc = argc;
|
|
config->handler_context.leftovers.argv = argv;
|
|
return NULL;
|
|
}
|
|
|