From c07936d91b38863f4e404a73aebe8a02820e4dfc Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 26 Nov 2017 16:41:59 +0100 Subject: [PATCH 1/3] no-op refactoring: make ipc_connect find socket path --- i3-config-wizard/main.c | 9 +-------- i3-input/main.c | 9 +-------- i3-msg/main.c | 30 +++--------------------------- libi3/ipc_connect.c | 25 ++++++++++++++++++++++--- src/display_version.c | 18 +----------------- 5 files changed, 28 insertions(+), 63 deletions(-) diff --git a/i3-config-wizard/main.c b/i3-config-wizard/main.c index dd58fd12..97c2a602 100644 --- a/i3-config-wizard/main.c +++ b/i3-config-wizard/main.c @@ -94,7 +94,7 @@ static xcb_get_modifier_mapping_reply_t *modmap_reply; static i3Font font; static i3Font bold_font; static int char_width; -static char *socket_path; +static char *socket_path = NULL; static xcb_window_t win; static surface_t surface; static xcb_key_symbols_t *symbols; @@ -744,7 +744,6 @@ static void finish() { int main(int argc, char *argv[]) { char *xdg_config_home; - socket_path = getenv("I3SOCK"); char *pattern = "pango:monospace 8"; char *patternbold = "pango:monospace bold 8"; int o, option_index = 0; @@ -824,12 +823,6 @@ int main(int argc, char *argv[]) { &xkb_base_error) != 1) errx(EXIT_FAILURE, "Could not setup XKB extension."); - if (socket_path == NULL) - socket_path = root_atom_contents("I3_SOCKET_PATH", conn, screen); - - if (socket_path == NULL) - socket_path = "/tmp/i3-ipc.sock"; - keysyms = xcb_key_symbols_alloc(conn); xcb_get_modifier_mapping_cookie_t modmap_cookie; modmap_cookie = xcb_get_modifier_mapping(conn); diff --git a/i3-input/main.c b/i3-input/main.c index 785a133f..efb7b20c 100644 --- a/i3-input/main.c +++ b/i3-input/main.c @@ -41,7 +41,6 @@ * the command will be sent to i3 */ static char *format; -static char *socket_path; static int sockfd; static xcb_key_symbols_t *symbols; static bool modeswitch_active = false; @@ -374,7 +373,7 @@ free_resources: int main(int argc, char *argv[]) { format = sstrdup("%s"); - socket_path = getenv("I3SOCK"); + char *socket_path = NULL; char *pattern = sstrdup("pango:monospace 8"); int o, option_index = 0; @@ -438,12 +437,6 @@ int main(int argc, char *argv[]) { if (!conn || xcb_connection_has_error(conn)) die("Cannot open display\n"); - if (socket_path == NULL) - socket_path = root_atom_contents("I3_SOCKET_PATH", conn, screen); - - if (socket_path == NULL) - socket_path = "/tmp/i3-ipc.sock"; - sockfd = ipc_connect(socket_path); root_screen = xcb_aux_get_screen(conn, screen); diff --git a/i3-msg/main.c b/i3-msg/main.c index a4f94850..91a714e5 100644 --- a/i3-msg/main.c +++ b/i3-msg/main.c @@ -38,8 +38,6 @@ #include -static char *socket_path; - /* * Having verboselog() and errorlog() is necessary when using libi3. * @@ -161,11 +159,7 @@ int main(int argc, char *argv[]) { if (pledge("stdio rpath unix", NULL) == -1) err(EXIT_FAILURE, "pledge"); #endif - char *env_socket_path = getenv("I3SOCK"); - if (env_socket_path) - socket_path = sstrdup(env_socket_path); - else - socket_path = NULL; + char *socket_path = NULL; int o, option_index = 0; uint32_t message_type = I3_IPC_MESSAGE_TYPE_RUN_COMMAND; char *payload = NULL; @@ -183,8 +177,7 @@ int main(int argc, char *argv[]) { while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) { if (o == 's') { - if (socket_path != NULL) - free(socket_path); + free(socket_path); socket_path = sstrdup(optarg); } else if (o == 't') { if (strcasecmp(optarg, "command") == 0) { @@ -228,13 +221,6 @@ int main(int argc, char *argv[]) { } } - if (socket_path == NULL) - socket_path = root_atom_contents("I3_SOCKET_PATH", NULL, 0); - - /* Fall back to the default socket path */ - if (socket_path == NULL) - socket_path = sstrdup("/tmp/i3-ipc.sock"); - /* Use all arguments, separated by whitespace, as payload. * This way, you don’t have to do i3-msg 'mark foo', you can use * i3-msg mark foo */ @@ -253,17 +239,7 @@ int main(int argc, char *argv[]) { if (!payload) payload = sstrdup(""); - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) - err(EXIT_FAILURE, "Could not create socket"); - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_LOCAL; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); - if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) - err(EXIT_FAILURE, "Could not connect to i3 on socket \"%s\"", socket_path); - + int sockfd = ipc_connect(socket_path); if (ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t *)payload) == -1) err(EXIT_FAILURE, "IPC: write()"); free(payload); diff --git a/libi3/ipc_connect.c b/libi3/ipc_connect.c index 2e628342..f659a1a4 100644 --- a/libi3/ipc_connect.c +++ b/libi3/ipc_connect.c @@ -22,6 +22,25 @@ * */ int ipc_connect(const char *socket_path) { + char *path = NULL; + if (socket_path != NULL) { + path = sstrdup(socket_path); + } + + if (path == NULL) { + if ((path = getenv("I3SOCK")) != NULL) { + path = sstrdup(path); + } + } + + if (path == NULL) { + path = root_atom_contents("I3_SOCKET_PATH", NULL, 0); + } + + if (path == NULL) { + path = sstrdup("/tmp/i3-ipc.sock"); + } + int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); if (sockfd == -1) err(EXIT_FAILURE, "Could not create socket"); @@ -31,9 +50,9 @@ int ipc_connect(const char *socket_path) { struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); addr.sun_family = AF_LOCAL; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) - err(EXIT_FAILURE, "Could not connect to i3"); - + err(EXIT_FAILURE, "Could not connect to i3 on socket %s", path); + free(path); return sockfd; } diff --git a/src/display_version.c b/src/display_version.c index 764ee753..2e05cafa 100644 --- a/src/display_version.c +++ b/src/display_version.c @@ -55,10 +55,6 @@ static yajl_callbacks version_callbacks = { * */ void display_running_version(void) { - char *socket_path = root_atom_contents("I3_SOCKET_PATH", conn, conn_screen); - if (socket_path == NULL) - exit(EXIT_SUCCESS); - char *pid_from_atom = root_atom_contents("I3_PID", conn, conn_screen); if (pid_from_atom == NULL) { /* If I3_PID is not set, the running version is older than 4.2-200. */ @@ -71,18 +67,7 @@ void display_running_version(void) { printf("(Getting version from running i3, press ctrl-c to abort…)"); fflush(stdout); - /* TODO: refactor this with the code for sending commands */ - int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0); - if (sockfd == -1) - err(EXIT_FAILURE, "Could not create socket"); - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(struct sockaddr_un)); - addr.sun_family = AF_LOCAL; - strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1); - if (connect(sockfd, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) - err(EXIT_FAILURE, "Could not connect to i3"); - + int sockfd = ipc_connect(NULL); if (ipc_send_message(sockfd, 0, I3_IPC_MESSAGE_TYPE_GET_VERSION, (uint8_t *)"") == -1) err(EXIT_FAILURE, "IPC: write()"); @@ -184,5 +169,4 @@ void display_running_version(void) { yajl_free(handle); free(reply); free(pid_from_atom); - free(socket_path); } From 1facb450c0088d662c4c76ee97f0b0151f746288 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 26 Nov 2017 17:26:40 +0100 Subject: [PATCH 2/3] i3-dump-log: enable shmlog on demand fixes #3055 --- i3-dump-log/main.c | 92 +++++++++++++++++++++++++++++++++------- testcases/t/207-shmlog.t | 2 +- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/i3-dump-log/main.c b/i3-dump-log/main.c index 478af310..e9901f8e 100644 --- a/i3-dump-log/main.c +++ b/i3-dump-log/main.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "libi3.h" #include "shmlog.h" @@ -38,6 +39,29 @@ static uint32_t wrap_count; static i3_shmlog_header *header; static char *logbuffer, *walk; +static int ipcfd = -1; + +static volatile bool interrupted = false; + +static void sighandler(int signal) { + interrupted = true; +} + +static void disable_shmlog(void) { + const char *disablecmd = "debuglog off; shmlog off"; + if (ipc_send_message(ipcfd, strlen(disablecmd), + I3_IPC_MESSAGE_TYPE_COMMAND, (uint8_t *)disablecmd) != 0) + err(EXIT_FAILURE, "IPC send"); + + /* Ensure the command was sent by waiting for the reply: */ + uint32_t reply_length = 0; + uint8_t *reply = NULL; + if (ipc_recv_message(ipcfd, I3_IPC_REPLY_TYPE_COMMAND, + &reply_length, &reply) != 0) { + err(EXIT_FAILURE, "IPC recv"); + } + free(reply); +} static int check_for_wrap(void) { if (wrap_count == header->wrap_count) @@ -59,6 +83,14 @@ static void print_till_end(void) { walk += len; } +void errorlog(char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); +} + int main(int argc, char *argv[]) { int o, option_index = 0; bool verbose = false; @@ -123,15 +155,35 @@ int main(int argc, char *argv[]) { exit(1); } if (root_atom_contents("I3_CONFIG_PATH", conn, screen) != NULL) { - fprintf(stderr, "i3-dump-log: ERROR: i3 is running, but SHM logging is not enabled.\n\n"); - if (!is_debug_build()) { + fprintf(stderr, "i3-dump-log: ERROR: i3 is running, but SHM logging is not enabled. Enabling SHM log until cancelled\n\n"); + ipcfd = ipc_connect(NULL); + const char *enablecmd = "debuglog on; shmlog 5242880"; + if (ipc_send_message(ipcfd, strlen(enablecmd), + I3_IPC_MESSAGE_TYPE_COMMAND, (uint8_t *)enablecmd) != 0) + err(EXIT_FAILURE, "IPC send"); + /* By the time we receive a reply, I3_SHMLOG_PATH is set: */ + uint32_t reply_length = 0; + uint8_t *reply = NULL; + if (ipc_recv_message(ipcfd, I3_IPC_REPLY_TYPE_COMMAND, + &reply_length, &reply) != 0) { + err(EXIT_FAILURE, "IPC recv"); + } + free(reply); + + atexit(disable_shmlog); + + /* Retry: */ + shmname = root_atom_contents("I3_SHMLOG_PATH", NULL, 0); + if (shmname == NULL && !is_debug_build()) { fprintf(stderr, "You seem to be using a release version of i3:\n %s\n\n", I3_VERSION); fprintf(stderr, "Release versions do not use SHM logging by default,\ntherefore i3-dump-log does not work.\n\n"); fprintf(stderr, "Please follow this guide instead:\nhttps://i3wm.org/docs/debugging-release-version.html\n"); exit(1); } } - errx(EXIT_FAILURE, "Cannot get I3_SHMLOG_PATH atom contents. Is i3 running on this display?"); + if (shmname == NULL) { + errx(EXIT_FAILURE, "Cannot get I3_SHMLOG_PATH atom contents. Is i3 running on this display?"); + } } if (*shmname == '\0') @@ -182,22 +234,32 @@ int main(int argc, char *argv[]) { print_till_end(); #if !defined(__OpenBSD__) - if (follow) { - /* Since pthread_cond_wait() expects a mutex, we need to provide one. + if (!follow) { + return 0; + } + + /* Handle SIGINT gracefully to invoke atexit handlers, if any. */ + struct sigaction action; + action.sa_handler = sighandler; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + sigaction(SIGINT, &action, NULL); + + /* Since pthread_cond_wait() expects a mutex, we need to provide one. * To not lock i3 (that’s bad, mhkay?) we just define one outside of * the shared memory. */ - pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_lock(&dummy_mutex); - while (1) { - pthread_cond_wait(&(header->condvar), &dummy_mutex); - /* If this was not a spurious wakeup, print the new lines. */ - if (header->offset_next_write != offset_next_write) { - offset_next_write = header->offset_next_write; - print_till_end(); - } + pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&dummy_mutex); + while (!interrupted) { + pthread_cond_wait(&(header->condvar), &dummy_mutex); + /* If this was not a spurious wakeup, print the new lines. */ + if (header->offset_next_write != offset_next_write) { + offset_next_write = header->offset_next_write; + print_till_end(); } } -#endif +#endif + exit(0); return 0; } diff --git a/testcases/t/207-shmlog.t b/testcases/t/207-shmlog.t index 1351d568..c2b2ebaa 100644 --- a/testcases/t/207-shmlog.t +++ b/testcases/t/207-shmlog.t @@ -54,7 +54,7 @@ like($stderr, qr#^$#, 'stderr empty'); # 3: change size of the shared memory log buffer and verify old content is gone ################################################################################ -cmd 'shmlog ' . (23 * 1024 * 1024); +cmd 'shmlog ' . (1 * 1024 * 1024); run [ 'i3-dump-log' ], '>', \$stdout, From 02b237b14dffd42bbafca34a5acaff8ebff88141 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 26 Nov 2017 18:07:13 +0100 Subject: [PATCH 3/3] shmlog: remote atom when disabled --- src/x.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/x.c b/src/x.c index 09a60493..7829079b 100644 --- a/src/x.c +++ b/src/x.c @@ -1227,9 +1227,13 @@ void x_set_name(Con *con, const char *name) { * */ void update_shmlog_atom() { - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, - A_I3_SHMLOG_PATH, A_UTF8_STRING, 8, - strlen(shmlogname), shmlogname); + if (*shmlogname == '\0') { + xcb_delete_property(conn, root, A_I3_SHMLOG_PATH); + } else { + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, + A_I3_SHMLOG_PATH, A_UTF8_STRING, 8, + strlen(shmlogname), shmlogname); + } } /*