From f395f29918210e50308341c221ac2c62107bf75c Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Fri, 14 Aug 2026 02:48:49 +0900 Subject: [PATCH] ibus: complete setup before publication --- ibus.c | 55 +++++++++++++++++++++++++-------- tests/ibus_test.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++ tests/test.h | 1 + tests/unit_test.c | 1 + 4 files changed, 123 insertions(+), 13 deletions(-) diff --git a/ibus.c b/ibus.c index 1ff062b..31320a0 100644 --- a/ibus.c +++ b/ibus.c @@ -182,14 +182,15 @@ writeaddr(char *path, char *addr) fd = -1; if(fprintf(fp, "IBUS_ADDRESS=%s\n", addr) < 0 || fprintf(fp, "IBUS_DAEMON_PID=%d\n", (int)getpid()) < 0 || - fflush(fp) < 0 || fsync(fileno(fp)) < 0) + fflush(fp) < 0 || fsync(fileno(fp)) < 0 || + fstat(fileno(fp), &st) < 0) goto out; if(fclose(fp) < 0){ fp = nil; goto out; } fp = nil; - if(rename(tmp, path) < 0 || lstat(path, &st) < 0) + if(rename(tmp, path) < 0) goto out; addrdev = st.st_dev; addrino = st.st_ino; @@ -695,11 +696,19 @@ newconn(DBusServer *s, DBusConnection *c, void *_) USED(_); if(nconns >= Maxconns) return; - dbus_connection_ref(c); - dbus_connection_set_watch_functions(c, addwatch, removewatch, togglewatch, nil, nil); + if(!dbus_connection_set_watch_functions(c, addwatch, removewatch, + togglewatch, nil, nil)){ + fprintf(stderr, "strans: ibus: cannot watch client connection\n"); + return; + } memset(&vt, 0, sizeof(vt)); vt.message_function = onmsg; - dbus_connection_register_fallback(c, "/", &vt, nil); + if(!dbus_connection_register_fallback(c, "/", &vt, nil)){ + fprintf(stderr, "strans: ibus: cannot register client handler\n"); + dbus_connection_set_watch_functions(c, nil, nil, nil, nil, nil); + return; + } + dbus_connection_ref(c); conns[nconns++] = c; } @@ -726,7 +735,10 @@ ibusinit(void) DBusError err; char addr[128]; char *full; + int cleanupregistered; + full = nil; + cleanupregistered = 0; if(buildaddrpath(addrfile, sizeof(addrfile)) < 0){ fprintf(stderr, "strans: ibus: cannot build address path\n"); return -1; @@ -745,20 +757,37 @@ ibusinit(void) return -1; } dbus_server_set_new_connection_function(srv, newconn, nil, nil); - dbus_server_set_watch_functions(srv, addwatch, removewatch, togglewatch, nil, nil); + if(!dbus_server_set_watch_functions(srv, addwatch, removewatch, + togglewatch, nil, nil)){ + fprintf(stderr, "strans: ibus: cannot watch server\n"); + goto fail; + } full = dbus_server_get_address(srv); + if(full == nil){ + fprintf(stderr, "strans: ibus: cannot get server address\n"); + goto fail; + } + if(!atexit(unlinkaddr)){ + fprintf(stderr, "strans: ibus: cannot register address cleanup\n"); + goto fail; + } + cleanupregistered = 1; if(writeaddr(addrfile, full) < 0){ fprintf(stderr, "strans: ibus: cannot write %s\n", addrfile); - dbus_free(full); - dbus_server_disconnect(srv); - dbus_server_unref(srv); - srv = nil; - addrfile[0] = '\0'; - return -1; + goto fail; } dbus_free(full); - atexit(unlinkaddr); return 0; +fail: + if(cleanupregistered) + atexitdont(unlinkaddr); + if(full != nil) + dbus_free(full); + dbus_server_disconnect(srv); + dbus_server_unref(srv); + srv = nil; + addrfile[0] = '\0'; + return -1; } void diff --git a/tests/ibus_test.c b/tests/ibus_test.c index 5871783..d950fc7 100644 --- a/tests/ibus_test.c +++ b/tests/ibus_test.c @@ -1,6 +1,8 @@ #include "../ibus.c" #include "../cutest/cutest.h" +#include + void testengineinit(int); void testenginehandle(Keyreq*); void* testengineowner(void); @@ -67,6 +69,83 @@ cleanup: CT_CHECK(t, rmdir(root) == 0); } +void +ibus_startup_requires_ownership(struct ct *t) +{ + char root[] = "/tmp/strans-ibus-startup.XXXXXX"; + char busdir[128], ibusdir[128], path[512], *old, *saved; + struct stat st; + int i, made, rv; + + made = 0; + busdir[0] = '\0'; + ibusdir[0] = '\0'; + path[0] = '\0'; + old = getenv("XDG_CONFIG_HOME"); + saved = old == nil ? nil : strdup(old); + if(old != nil && !CT_CHECK(t, saved != nil)) + return; + if(!CT_CHECK(t, mkdtemp(root) != nil)) + goto cleanup; + made = 1; + if(!CT_CHECK(t, snprintf(busdir, sizeof busdir, "%s/ibus/bus", root) + < (int)sizeof busdir) || + !CT_CHECK(t, snprintf(ibusdir, sizeof ibusdir, "%s/ibus", root) + < (int)sizeof ibusdir) || + !CT_CHECK(t, setenv("XDG_CONFIG_HOME", root, 1) == 0) || + !CT_CHECK(t, buildaddrpath(path, sizeof path) == 0)) + goto cleanup; + + memset(watches, 0, sizeof watches); + for(i = 0; i < nelem(watches); i++) + watches[i] = (DBusWatch*)1; + nwatches = nelem(watches); + rv = ibusinit(); + CT_EQ_INT(t, -1, rv); + CT_EQ_PTR(t, nil, srv); + CT_CHECK(t, lstat(path, &st) < 0 && errno == ENOENT); + if(rv == 0){ + dbus_server_disconnect(srv); + dbus_server_unref(srv); + srv = nil; + unlinkaddr(); + atexitdont(unlinkaddr); + } + + memset(watches, 0, sizeof watches); + nwatches = 0; + while(atexit(unlinkaddr)) + continue; + CT_EQ_INT(t, -1, ibusinit()); + CT_EQ_PTR(t, nil, srv); + CT_CHECK(t, lstat(path, &st) < 0 && errno == ENOENT); +cleanup: + if(srv != nil){ + dbus_server_disconnect(srv); + dbus_server_unref(srv); + srv = nil; + } + unlinkaddr(); + atexitdont(unlinkaddr); + memset(watches, 0, sizeof watches); + nwatches = 0; + addrfile[0] = '\0'; + if(saved != nil){ + setenv("XDG_CONFIG_HOME", saved, 1); + free(saved); + }else + unsetenv("XDG_CONFIG_HOME"); + if(made){ + if(path[0] != '\0') + unlink(path); + if(busdir[0] != '\0') + CT_CHECK(t, rmdir(busdir) == 0 || errno == ENOENT); + if(ibusdir[0] != '\0') + CT_CHECK(t, rmdir(ibusdir) == 0 || errno == ENOENT); + CT_CHECK(t, rmdir(root) == 0); + } +} + static void enginepump(void *arg) { diff --git a/tests/test.h b/tests/test.h index 1cdfce2..1d1d7a4 100644 --- a/tests/test.h +++ b/tests/test.h @@ -72,5 +72,6 @@ void ipc_response_fragmented_and_truncated(struct ct*); void ipc_broken_peer_send(struct ct*); void server_connection_ownership(struct ct*); void ibus_machine_id_fallback(struct ct*); +void ibus_startup_requires_ownership(struct ct*); void ibus_context_lifecycle(struct ct*); void ibus_active_release_lifecycle(struct ct*); diff --git a/tests/unit_test.c b/tests/unit_test.c index 80258ab..49f718b 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -126,6 +126,7 @@ static const struct ct_test tests[] = { { "ipc/broken-peer-send", ipc_broken_peer_send }, { "server/connection-ownership", server_connection_ownership }, { "ibus/machine-id-fallback", ibus_machine_id_fallback }, + { "ibus/startup-requires-ownership", ibus_startup_requires_ownership }, { "ibus/context-lifecycle", ibus_context_lifecycle }, { "ibus/active-release-lifecycle", ibus_active_release_lifecycle }, };