Skip to content

Commit 66d7b4b

Browse files
committed
OpenBSD doesn't have wordexp(), make it optional
- like done in swaywm/swaylock#325, provide an alternative for swayidle configuration file lookup - and provide a handrolled config line parser for 'timeout' commands, using strspn(), strchr() and asprintf() - the latter is in recent POSIX so move _POSIX_C_SOURCE 200809L definition within #if HAVE_WORDEXP - OpenBSD doesn't (and won't) have support for systemd/logind, so only care about timeout commands
1 parent 61d653f commit 66d7b4b

File tree

2 files changed

+133
-2
lines changed

2 files changed

+133
-2
lines changed

main.c

+131-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
#include "config.h"
2+
#if HAVE_WORDEXP
13
#define _POSIX_C_SOURCE 200809L
4+
#include <wordexp.h>
5+
#endif
26
#include <errno.h>
37
#include <fcntl.h>
48
#include <signal.h>
@@ -13,8 +17,6 @@
1317
#include <wayland-client.h>
1418
#include <wayland-server.h>
1519
#include <wayland-util.h>
16-
#include <wordexp.h>
17-
#include "config.h"
1820
#include "ext-idle-notify-v1-client-protocol.h"
1921
#include "log.h"
2022
#if HAVE_SYSTEMD
@@ -933,6 +935,7 @@ static int display_event(int fd, uint32_t mask, void *data) {
933935
}
934936

935937
static char *get_config_path(void) {
938+
#if HAVE_WORDEXP
936939
static char *config_paths[3] = {
937940
"$XDG_CONFIG_HOME/swayidle/config",
938941
"$HOME/.swayidle/config",
@@ -957,10 +960,117 @@ static char *get_config_path(void) {
957960
free(path);
958961
}
959962
}
963+
#else
964+
char *home = getenv("HOME");
965+
char *path;
966+
int n, len;
967+
if (home) {
968+
len = strlen(home) + strlen("/.swayidle/config") + 1;
969+
path = malloc(len);
970+
if (path == NULL)
971+
return NULL;
972+
n = snprintf(path, len, "%s/.swayidle/config", home);
973+
if (n < len && access(path, R_OK) == 0)
974+
return path;
975+
free(path);
976+
char *config_home = getenv("XDG_CONFIG_HOME");
977+
if (!config_home || config_home[0] == '\0') {
978+
len = strlen(home) + strlen("/.config/swayidle/config") + 1;
979+
path = malloc(len);
980+
if (path == NULL)
981+
return NULL;
982+
n = snprintf(path, len, "%s/.config/swayidle/config", home);
983+
if (n < len && access(path, R_OK) == 0)
984+
return path;
985+
free(path);
986+
} else {
987+
len = strlen(config_home) + strlen("/swayidle/config") + 1;
988+
path = malloc(len);
989+
if (path == NULL)
990+
return NULL;
991+
n = snprintf(path, len, "%s/swayidle/config", config_home);
992+
if (n < len && access(path, R_OK) == 0)
993+
return path;
994+
free(path);
995+
}
996+
}
997+
len = strlen(SYSCONFDIR "/swayidle/config") + 1;
998+
path = malloc(len);
999+
if (path == NULL)
1000+
return NULL;
1001+
n = snprintf(path, len, "%s/swayidle/config", SYSCONFDIR);
1002+
if (n < len && access(path, R_OK) == 0)
1003+
return path;
1004+
free(path);
1005+
1006+
#endif
9601007

9611008
return NULL;
9621009
}
9631010

1011+
#if !HAVE_WORDEXP
1012+
char ** parse_line_like_wordexp_does(const char* str, int* nargs) {
1013+
char **args = calloc (6, sizeof(char*));
1014+
char *q, *p = strchr(str, ' ');
1015+
char *junk = " \t";
1016+
int r, len = p - str;
1017+
size_t span;
1018+
if (args == NULL)
1019+
return NULL;
1020+
*nargs = 0;
1021+
/* consume leading spaces/tabs */
1022+
span = strspn(p, junk);
1023+
/* 'timeout' string */
1024+
r = asprintf(&args[0], "%.*s", len, str);
1025+
if (r == -1 || r != len)
1026+
return NULL;
1027+
q = strchr(p + span, ' ');
1028+
len = q - p - 1;
1029+
/* timeout value => no trailing \n! */
1030+
r = asprintf(&args[1], "%.*s", len, p + span);
1031+
if (r == -1 || r != len)
1032+
return NULL;
1033+
/* look for next quotes, should be the command */
1034+
p = strchr(q, '\'');
1035+
q = strchr(p + 1, '\'');
1036+
len = q - p - 1;
1037+
r = asprintf(&args[2], "%.*s", len, p + 1);
1038+
if (r == -1 || r != len)
1039+
return NULL;
1040+
q++;
1041+
/* have we reached the end of string ? */
1042+
if (*q == '\0') {
1043+
args[3] = NULL;
1044+
*nargs = 3;
1045+
} else {
1046+
/* consume eventual trailing spaces */
1047+
span = strspn(q, junk);
1048+
q += span;
1049+
if (*q == '\0') {
1050+
args[3] = NULL;
1051+
*nargs = 3;
1052+
} else {
1053+
p = strchr(q, ' ');
1054+
len = p - q;
1055+
/* 'resume' string */
1056+
r = asprintf(&args[3], "%.*s", len, q);
1057+
if (r == -1 || r != len)
1058+
return NULL;
1059+
/* look for next quotes, should be the resume command */
1060+
p = strchr(q, '\'');
1061+
q = strchr(p + 1, '\'');
1062+
len = q - p - 1;
1063+
r = asprintf(&args[4], "%.*s", len, p + 1);
1064+
if (r == -1 || r != len)
1065+
return NULL;
1066+
args[5] = NULL;
1067+
*nargs = 5;
1068+
}
1069+
}
1070+
return args;
1071+
}
1072+
#endif
1073+
9641074
static int load_config(const char *config_path) {
9651075
FILE *f = fopen(config_path, "r");
9661076
if (!f) {
@@ -986,6 +1096,7 @@ static int load_config(const char *config_path) {
9861096
i++;
9871097
}
9881098

1099+
#if HAVE_WORDEXP
9891100
wordexp_t p;
9901101
wordexp(line, &p, 0);
9911102
if (strncmp("timeout", line, i) == 0) {
@@ -1007,6 +1118,24 @@ static int load_config(const char *config_path) {
10071118
return -EINVAL;
10081119
}
10091120
wordfree(&p);
1121+
#else
1122+
if (strncmp("timeout", line, i) == 0) {
1123+
int nargs;
1124+
char **args = parse_line_like_wordexp_does(line, &nargs);
1125+
if (args)
1126+
parse_timeout(nargs, args);
1127+
else {
1128+
swayidle_log(LOG_ERROR, "failed parsing \"%s\" in line %zu", line, lineno);
1129+
free(line);
1130+
return -EINVAL;
1131+
}
1132+
} else {
1133+
line[i] = 0;
1134+
swayidle_log(LOG_ERROR, "Unexpected keyword \"%s\" in line %zu", line, lineno);
1135+
free(line);
1136+
return -EINVAL;
1137+
}
1138+
#endif
10101139
}
10111140
free(line);
10121141
fclose(f);

meson.build

+2
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ foreach xml : protos
5353
protos_src += wayland_scanner_client.process(xml)
5454
endforeach
5555

56+
cc = meson.get_compiler('c')
5657
conf_data = configuration_data()
5758
conf_data.set_quoted('SYSCONFDIR', get_option('prefix') / get_option('sysconfdir'))
5859
conf_data.set10('HAVE_SYSTEMD', false)
5960
conf_data.set10('HAVE_ELOGIND', false)
61+
conf_data.set10('HAVE_WORDEXP', cc.check_header('wordexp.h'))
6062

6163
if logind.found()
6264
conf_data.set10('HAVE_' + get_option('logind-provider').to_upper(), true)

0 commit comments

Comments
 (0)