diff --git a/client.c b/client.c index c818c185..ecb850f6 100644 --- a/client.c +++ b/client.c @@ -29,27 +29,32 @@ static void print_usage(const char *prog_name) { printf("Usage: %s [OPTIONS]...\n", prog_name); + printf("Usage: %s [OPTIONS]... -- command\n", prog_name); printf("\n"); printf("Options:\n"); printf(" -t,--term=TERM value to set the environment variable TERM to (foot)\n" + " -s,--server-socket=PATH path to the server UNIX domain socket (default=XDG_RUNTIME_DIR/foot.sock)\n" " -v,--version show the version number and quit\n"); } int main(int argc, char *const *argv) { + log_init(LOG_FACILITY_USER); int ret = EXIT_FAILURE; const char *const prog_name = argv[0]; static const struct option longopts[] = { - {"term", required_argument, 0, 't'}, - {"version", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {NULL, no_argument, 0, 0}, + {"term", required_argument, 0, 't'}, + {"server-socket", required_argument, 0, 's'}, + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {NULL, no_argument, 0, 0}, }; const char *term = ""; + const char *server_socket_path = NULL; while (true) { int c = getopt_long(argc, argv, ":t:hv", longopts, NULL); @@ -59,6 +64,9 @@ main(int argc, char *const *argv) switch (c) { case 't': term = optarg; + + case 's': + server_socket_path = optarg; break; case 'v': @@ -88,23 +96,34 @@ main(int argc, char *const *argv) goto err; } - bool connected = false; struct sockaddr_un addr = {.sun_family = AF_UNIX}; - const char *xdg_runtime = getenv("XDG_RUNTIME_DIR"); - if (xdg_runtime != NULL) { - snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/foot.sock", xdg_runtime); - - if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) == 0) - connected = true; - } - - if (!connected) { - strncpy(addr.sun_path, "/tmp/foot.sock", sizeof(addr.sun_path) - 1); + if (server_socket_path != NULL) { + strncpy(addr.sun_path, server_socket_path, sizeof(addr.sun_path)); if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { - LOG_ERRNO("failed to connect (is 'foot --server' running?)"); + LOG_ERR("%s: failed to connect (is 'foot --server' running?)", server_socket_path); goto err; } + } else { + bool connected = false; + + const char *xdg_runtime = getenv("XDG_RUNTIME_DIR"); + if (xdg_runtime != NULL) { + snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/foot.sock", xdg_runtime); + + if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) == 0) + connected = true; + else + LOG_WARN("%s/foot.sock: failed to connect, will now try /tmp/foot.sock", xdg_runtime); + } + + if (!connected) { + strncpy(addr.sun_path, "/tmp/foot.sock", sizeof(addr.sun_path) - 1); + if (connect(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) { + LOG_ERRNO("failed to connect (is 'foot --server' running?)"); + goto err; + } + } } const uint16_t term_len = strlen(term) + 1; @@ -172,5 +191,6 @@ main(int argc, char *const *argv) err: if (fd != -1) close(fd); + log_deinit(); return ret; } diff --git a/completions/zsh/_foot b/completions/zsh/_foot index cbb1237c..220f6ec6 100644 --- a/completions/zsh/_foot +++ b/completions/zsh/_foot @@ -3,9 +3,9 @@ _arguments \ -s \ '(-f --font)'{-f,--font}'[font name and style in fontconfig format (monospace)]:font:->fonts' \ - '(-t,--term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ + '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ '(-g --geometry)'{-g,--geometry}'[window WIDTHxHEIGHT, in pixels (84x24 cells)]' \ - '(-s --server)'{-s,--server}'[run as server; open terminals by running footclient]' \ + '(-s --server)'{-s,--server}'[run as server; open terminals by running footclient]:server:_files' \ '(-v --version)'{-v,--version}'[show the version number and quit]' \ '(-h --help)'{-h,--help}'[show help message and quit]' diff --git a/completions/zsh/_footclient b/completions/zsh/_footclient index 47a050cb..93b8c01e 100644 --- a/completions/zsh/_footclient +++ b/completions/zsh/_footclient @@ -2,7 +2,8 @@ _arguments \ -s \ - '(-t,--term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ + '(-t --term)'{-t,--term}'[value to set the environment variable TERM to (foot)]:term:->terms' \ + '(-s --server-socket)'{-s,--server-socket}'[override the default path to the foot server socket (XDG_RUNTIME_DIR/foot.sock)]' \ '(-v --version)'{-v,--version}'[show the version number and quit]' \ '(-h --help)'{-h,--help}'[show help message and quit]' diff --git a/config.c b/config.c index 6f2d0bf8..55e82b46 100644 --- a/config.c +++ b/config.c @@ -450,6 +450,18 @@ err: return false; } +static char * +get_server_socket_path(void) +{ + const char *xdg_runtime = getenv("XDG_RUNTIME_DIR"); + if (xdg_runtime == NULL) + return strdup("/tmp/foot.sock"); + + char *path = malloc(strlen(xdg_runtime) + 1 + strlen("foot.sock") + 1); + sprintf(path, "%s/foot.sock", xdg_runtime); + return path; +} + bool config_load(struct config *conf) { @@ -498,6 +510,7 @@ config_load(struct config *conf) }, .render_worker_count = sysconf(_SC_NPROCESSORS_ONLN), + .server_socket_path = get_server_socket_path(), }; char *path = get_config_path(); @@ -531,4 +544,5 @@ config_free(struct config conf) free(conf.term); free(conf.shell); tll_free_and_free(conf.fonts, free); + free(conf.server_socket_path); } diff --git a/config.h b/config.h index 0db130ad..4e7086d7 100644 --- a/config.h +++ b/config.h @@ -34,6 +34,8 @@ struct config { } cursor; size_t render_worker_count; + + char *server_socket_path; }; bool config_load(struct config *conf); diff --git a/doc/foot.1.scd b/doc/foot.1.scd index 5d52cb1c..1bf180d0 100644 --- a/doc/foot.1.scd +++ b/doc/foot.1.scd @@ -33,7 +33,7 @@ execute (instead of the shell). *-t*,*--term*=_TERM_ Value to set the environment variable _TERM_ to. Default: _foot_. -*-s*,*--server* +*-s*,*--server*[=_PATH_] Run as a server. In this mode, a single foot instance hosts multiple terminals (windows). Use *footclient*(1) to launch new terminals. @@ -45,7 +45,7 @@ execute (instead of the shell). loaded and parsed, and most importantly, fonts have already been loaded (and their glyph caches are likely to already have been populated). - + Each terminal will have its own rendering threads, but all Wayland communication, as well as input/output to the shell, is multiplexed in the main thread. Thus, this mode might result in @@ -54,6 +54,10 @@ execute (instead of the shell). Also be aware that should one terminal crash, it will take all the others with it. + + You may optionally override the default socket path, + _XDG\_RUNTIME\_DIR/foot.sock_. If you do so, you will need to use + the *--server-socket* option in *footclient*(1). *-v*,*--version* Show the version number and quit diff --git a/doc/footclient.1.scd b/doc/footclient.1.scd index 40ead1cd..78397544 100644 --- a/doc/footclient.1.scd +++ b/doc/footclient.1.scd @@ -15,6 +15,9 @@ execute (instead of the shell). *-t*,*--term*=_TERM_ Value to set the environment variable _TERM_ to. Default: _foot_. +*-s*,*--server-socket*=_PATH_ + Connect to _PATH_ instead of _XDG\_RUNTIME\_DIR/foot.sock_. + *-v*,*--version* Show the version number and quit diff --git a/main.c b/main.c index ed426d4b..938aa992 100644 --- a/main.c +++ b/main.c @@ -38,12 +38,14 @@ static void print_usage(const char *prog_name) { printf("Usage: %s [OPTIONS]...\n", prog_name); + printf("Usage: %s [OPTIONS]... -- command\n", prog_name); printf("\n"); printf("Options:\n"); printf(" -f,--font=FONT comma separated list of fonts in fontconfig format (monospace)\n" " -t,--term=TERM value to set the environment variable TERM to (foot)\n" " -g,--geometry=WIDTHxHEIGHT set initial width and height\n" - " -s,--server run as a server (use 'footclient' to start terminals)\n" + " -s,--server[=PATH] run as a server (use 'footclient' to start terminals).\n" + " Without PATH, XDG_RUNTIME_DIR/foot.sock will be used.\n" " -v,--version show the version number and quit\n"); } @@ -79,7 +81,7 @@ main(int argc, char *const *argv) {"term", required_argument, 0, 't'}, {"font", required_argument, 0, 'f'}, {"geometry", required_argument, 0, 'g'}, - {"server", no_argument, 0, 's'}, + {"server", optional_argument, 0, 's'}, {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {NULL, no_argument, 0, 0}, @@ -88,7 +90,7 @@ main(int argc, char *const *argv) bool as_server = false; while (true) { - int c = getopt_long(argc, argv, ":t:f:g:vh", longopts, NULL); + int c = getopt_long(argc, argv, ":t:f:g:s::vh", longopts, NULL); if (c == -1) break; @@ -135,6 +137,10 @@ main(int argc, char *const *argv) case 's': as_server = true; + if (optarg != NULL) { + free(conf.server_socket_path); + conf.server_socket_path = strdup(optarg); + } break; case 'v': diff --git a/server.c b/server.c index ae3f22b4..143af512 100644 --- a/server.c +++ b/server.c @@ -27,7 +27,7 @@ struct server { struct wayland *wayl; int fd; - char *sock_path; + const char *sock_path; tll(struct client *) clients; }; @@ -273,18 +273,6 @@ fdm_server(struct fdm *fdm, int fd, int events, void *data) return true; } -static char * -get_socket_path(void) -{ - const char *xdg_runtime = getenv("XDG_RUNTIME_DIR"); - if (xdg_runtime == NULL) - return strdup("/tmp/foot.sock"); - - char *path = malloc(strlen(xdg_runtime) + 1 + strlen("foot.sock") + 1); - sprintf(path, "%s/foot.sock", xdg_runtime); - return path; -} - enum connect_status {CONNECT_ERR, CONNECT_FAIL, CONNECT_SUCCESS}; static enum connect_status @@ -328,10 +316,7 @@ server_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl) } struct server *server = NULL; - char *sock_path = NULL; - - if ((sock_path = get_socket_path()) == NULL) - goto err; + const char *sock_path = conf->server_socket_path; switch (try_connect(sock_path)) { case CONNECT_FAIL: @@ -381,7 +366,6 @@ server_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl) err: free(server); - free(sock_path); if (fd != -1) close(fd); return NULL; @@ -406,6 +390,5 @@ server_destroy(struct server *server) fdm_del(server->fdm, server->fd); if (server->sock_path != NULL) unlink(server->sock_path); - free(server->sock_path); free(server); }