diff --git a/include/config.h b/include/config.h index 0c790bf2..22b0c472 100644 --- a/include/config.h +++ b/include/config.h @@ -126,9 +126,11 @@ struct Config { /** * This function resolves ~ in pathnames. + * It may resolve wildcards in the first part of the path, but if no match + * or multiple matches are found, it just returns a copy of path as given. * */ -char *glob_path(const char *path); +char *resolve_tilde(const char *path); /** * Checks if the given path exists by calling stat(). diff --git a/src/config.c b/src/config.c index 972e376c..fa4a6042 100644 --- a/src/config.c +++ b/src/config.c @@ -18,7 +18,6 @@ #include #include #include -#include #include /* We need Xlib for XStringToKeysym */ @@ -39,26 +38,32 @@ struct modes_head modes; /* * This function resolves ~ in pathnames. + * It may resolve wildcards in the first part of the path, but if no match + * or multiple matches are found, it just returns a copy of path as given. * */ -char *glob_path(const char *path) { +char *resolve_tilde(const char *path) { static glob_t globbuf; - if (glob(path, GLOB_NOCHECK | GLOB_TILDE, NULL, &globbuf) < 0) - die("glob() failed"); - char *result = sstrdup(globbuf.gl_pathc > 0 ? globbuf.gl_pathv[0] : path); - globfree(&globbuf); + char *head, *tail, *result; - /* If the file does not exist yet, we still may need to resolve tilde, - * so call wordexp */ - if (strcmp(result, path) == 0) { - wordexp_t we; - wordexp(path, &we, WRDE_NOCMD); - if (we.we_wordc > 0) { - free(result); - result = sstrdup(we.we_wordv[0]); - } - wordfree(&we); + tail = strchr(path, '/'); + head = strndup(path, tail ? tail - path : strlen(path)); + + int res = glob(head, GLOB_TILDE, NULL, &globbuf); + free(head); + /* no match, or many wildcard matches are bad */ + if(res == GLOB_NOMATCH || globbuf.gl_pathc != 1) + result = sstrdup(path); + else if (res != 0) { + die("glob() failed"); } + else { + head = globbuf.gl_pathv[0]; + result = smalloc(strlen(head) + (tail ? strlen(tail) : 0) + 1); + strncpy(result, head, strlen(head)); + strncat(result, tail, strlen(tail)); + } + globfree(&globbuf); return result; } @@ -239,7 +244,7 @@ static char *get_config_path() { if ((xdg_config_home = getenv("XDG_CONFIG_HOME")) == NULL) xdg_config_home = "~/.config"; - xdg_config_home = glob_path(xdg_config_home); + xdg_config_home = resolve_tilde(xdg_config_home); if (asprintf(&config_path, "%s/i3/config", xdg_config_home) == -1) die("asprintf() failed"); free(xdg_config_home); @@ -255,7 +260,7 @@ static char *get_config_path() { char *buf = strdup(xdg_config_dirs); char *tok = strtok(buf, ":"); while (tok != NULL) { - tok = glob_path(tok); + tok = resolve_tilde(tok); if (asprintf(&config_path, "%s/i3/config", tok) == -1) die("asprintf() failed"); free(tok); @@ -269,7 +274,7 @@ static char *get_config_path() { free(buf); /* 3: check traditional paths */ - config_path = glob_path("~/.i3/config"); + config_path = resolve_tilde("~/.i3/config"); if (path_exists(config_path)) return config_path; diff --git a/src/ipc.c b/src/ipc.c index 3dd95653..fcda355e 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -502,20 +502,20 @@ void ipc_new_client(EV_P_ struct ev_io *w, int revents) { int ipc_create_socket(const char *filename) { int sockfd; - char *globbed = glob_path(filename); - DLOG("Creating IPC-socket at %s\n", globbed); - char *copy = sstrdup(globbed); + char *resolved = resolve_tilde(filename); + DLOG("Creating IPC-socket at %s\n", resolved); + char *copy = sstrdup(resolved); const char *dir = dirname(copy); if (!path_exists(dir)) mkdirp(dir); free(copy); /* Unlink the unix domain socket before */ - unlink(globbed); + unlink(resolved); if ((sockfd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { perror("socket()"); - free(globbed); + free(resolved); return -1; } @@ -524,14 +524,14 @@ int ipc_create_socket(const char *filename) { struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_LOCAL; - strcpy(addr.sun_path, globbed); + strncpy(addr.sun_path, resolved, sizeof(addr.sun_path) - 1); if (bind(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0) { perror("bind()"); - free(globbed); + free(resolved); return -1; } - free(globbed); + free(resolved); set_nonblock(sockfd); if (listen(sockfd, 5) < 0) {