diff options
| -rw-r--r-- | Dockerfile | 10 | ||||
| -rw-r--r-- | clients/bokfweb.c | 26 | ||||
| -rw-r--r-- | deploy/cross-build.sh | 6 | ||||
| -rw-r--r-- | docs/DEPLOY.md | 4 | ||||
| -rw-r--r-- | docs/STATE.md | 6 |
5 files changed, 49 insertions, 3 deletions
@@ -23,7 +23,9 @@ RUN if [ -x .prebuilt/bokfd ]; then \ VERSION="$VERSION" \ && make test-core VERSION="$VERSION"; \ fi \ - && strip build/bokfd build/bokfctl build/bokftui build/bokfweb + && strip build/bokfd build/bokfctl build/bokftui build/bokfweb \ + && mkdir -p build/locale \ + && if [ -d .prebuilt/locale ]; then cp -a .prebuilt/locale/. build/locale/; fi # The web frontend (image bokf-web, `--target web`): Caddy for routing, the # bokfweb login gate, ttyd and bokftui in web mode. It reaches bokfd only @@ -36,9 +38,13 @@ RUN apk add --no-cache ca-certificates caddy ttyd ncurses-terminfo-base \ && addgroup -S bokfd \ && adduser -S -D -H -u 10001 -G bokfd -s /sbin/nologin bokfd COPY --from=build /src/build/bokftui /src/build/bokfweb /usr/local/bin/ +# glibc locale data for the cross-built static binaries (empty for a native +# musl build, which needs none); the check fails the build without UTF-8 +COPY --from=build /src/build/locale/ /usr/lib/locale/ COPY deploy/bokftui-web deploy/web-entrypoint.sh /usr/local/bin/ COPY deploy/Caddyfile /etc/caddy/Caddyfile -RUN chmod 0755 /usr/local/bin/bokftui-web /usr/local/bin/web-entrypoint.sh +RUN chmod 0755 /usr/local/bin/bokftui-web /usr/local/bin/web-entrypoint.sh \ + && LANG=C.UTF-8 bokfweb --check-locale ENV BOKFD_SOCKET=/run/bokfd/bokfd.sock \ TERM=xterm-256color \ LANG=C.UTF-8 diff --git a/clients/bokfweb.c b/clients/bokfweb.c index d04e2d6..cc19826 100644 --- a/clients/bokfweb.c +++ b/clients/bokfweb.c @@ -15,6 +15,7 @@ directly: only Caddy and the wrapper in the same container talk to it. */ #include <arpa/inet.h> #include <errno.h> +#include <locale.h> #include <netinet/in.h> #include <signal.h> #include <stdio.h> @@ -23,6 +24,7 @@ #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> +#include <wchar.h> #include "client.h" #include "log.h" @@ -446,8 +448,30 @@ static void serve(int cfd, struct gate *g) memset(buf, 0, n); /* the body may hold a password */ } -int main(void) +/* `bokfweb --check-locale`, run while the web image is built: bokftui in + the same image needs a UTF-8 locale for åäö, and a statically linked + glibc finds none unless its locale data is installed. Exits 1 without. */ +static int check_locale(void) { + const char *l = setlocale(LC_ALL, ""); + wchar_t w = 0; + mbstate_t st; + memset(&st, 0, sizeof st); + size_t n = mbrtowc(&w, "\xc3\xa5", 2, &st); /* å */ + if (!l || n != 2 || w != 0xE5) { + fprintf(stderr, "bokfweb: no UTF-8 locale (setlocale: %s); bokftui " + "would show no åäö\n", + l ? l : "failed"); + return 1; + } + printf("locale ok: %s\n", l); + return 0; +} + +int main(int argc, char **argv) +{ + if (argc > 1 && strcmp(argv[1], "--check-locale") == 0) + return check_locale(); signal(SIGPIPE, SIG_IGN); const char *lvl = getenv("BOKFWEB_LOG_LEVEL"); log_set_level(lvl ? log_level_from_name(lvl) : LOG_INFO); diff --git a/deploy/cross-build.sh b/deploy/cross-build.sh index 54a2929..75c181c 100644 --- a/deploy/cross-build.sh +++ b/deploy/cross-build.sh @@ -18,3 +18,9 @@ make -C /src -j"$(nproc)" BUILD=/tmp/build \ mkdir -p /out cp /tmp/build/bokfd /tmp/build/bokfctl /tmp/build/bokftui \ /tmp/build/bokfweb /out/ + +# A static glibc program loads its locale data from /usr/lib/locale, which +# the Alpine runtime does not have: without C.utf8 setlocale() fails and +# the TUI shows no åäö. Ship Debian's C.utf8 with the binaries. +mkdir -p /out/locale +cp -a /usr/lib/locale/C.utf8 /out/locale/ diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 99b7661..008093f 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -276,6 +276,10 @@ browser ──443──▶ host Caddy (TLS) ──▶ 127.0.0.1:8790 bokf-web c Port 443 is already forwarded for the other sites. The container publishes 8790 on the host's loopback only, so it is unreachable until that block exists. +- **UTF-8**: the cross-built binaries are static glibc, which needs its own + locale data; the image ships Debian's `C.utf8` in `/usr/lib/locale` and + the build runs `bokfweb --check-locale`, so an image whose TUI could not + show åäö fails to build instead of shipping. - `BOKF_WEB_MAX_SESSIONS` (default 20) caps concurrent terminals. `docker compose logs web` shows logins, logouts and failed attempts (never passwords). diff --git a/docs/STATE.md b/docs/STATE.md index c33d80e..10286fb 100644 --- a/docs/STATE.md +++ b/docs/STATE.md @@ -14,6 +14,12 @@ unit tests and the docs consistency check. ## Resume here (2026-09-23) +- **Web åäö fix (2026-09-23, `v0.1.70`)**: the web TUI showed no åäö on + the NAS: the cross-built static glibc bokftui found no locale data in + the Alpine image (setlocale failed, åäö were invalid bytes). The image + now ships Debian's `C.utf8` and the build checks it + (`bokfweb --check-locale`). Local amd64 tests missed it because the + native build uses musl. - **Web frontend (2026-09-23, live since `v0.1.69`: https://bokf.makandra.eu/web)**: image `bokf-web` (Caddy routing + `bokfweb` login gate + ttyd + bokftui in web mode) as compose service `web` on `127.0.0.1:8790`; see |
