From ab6ed3df416bb25063e2a3530668519acecf9765 Mon Sep 17 00:00:00 2001 From: ptrcnull Date: Fri, 19 Nov 2021 16:22:29 +0100 Subject: [PATCH] feat: Add spotify-on-musl --- content/posts/spotify-on-musl.md | 178 ++++++++++++++++++ static/posts/spotify-on-musl/white_window.png | Bin 0 -> 6301 bytes 2 files changed, 178 insertions(+) create mode 100644 content/posts/spotify-on-musl.md create mode 100644 static/posts/spotify-on-musl/white_window.png diff --git a/content/posts/spotify-on-musl.md b/content/posts/spotify-on-musl.md new file mode 100644 index 0000000..f4e7473 --- /dev/null +++ b/content/posts/spotify-on-musl.md @@ -0,0 +1,178 @@ +--- +title: "WIP: Running Spotify on musl" +date: 2021-11-19T16:22:02+01:00 +draft: false +--- + +Note: this post is not finished yet (and might never be) - it's more of a collection of notes. + +When trying to run Spotify on Alpine, most answers on the internet pointed to [Flatpak](https://flatpak.org/). +And don't get me wrong - Flatpak is great and allows for running glibc-based apps +with minimal setup, but... I'd really like to get Spotify to run natively, mostly because containers a bit heavier in terms of disk space and interoperability is . + +Let's start by downloading Spotify's deb package from [the official repository](https://repository-origin.spotify.com/pool/non-free/s/spotify-client/) and unpacking it into downloads. +Most of the files are in `usr/share/spotify`, so we'll try to just go there and run it. + +``` +$ cd usr/share/spotify +$ ./spotify +zsh: no such file or directory: ./spotify +``` + +Oh right, it's missing some stuff. What stuff though? + +``` +$ ldd spotify +(114 lines skipped...) +Error relocating ./libcef.so: __libc_realloc: symbol not found +Error relocating ./libcef.so: __libc_free: symbol not found +Error relocating ./libcef.so: __fdelt_chk: symbol not found +Error relocating ./libcef.so: __fprintf_chk: symbol not found +Error relocating ./libcef.so: __sprintf_chk: symbol not found +Error relocating ./libcef.so: initstate_r: symbol not found +Error relocating ./libcef.so: random_r: symbol not found +Error relocating ./libcef.so: gnu_get_libc_version: symbol not found +Error relocating ./libcef.so: __register_atfork: symbol not found +Error relocating ./libcef.so: __longjmp_chk: symbol not found +Error relocating ./libcef.so: __libc_stack_end: symbol not found +Error relocating ./spotify: strtoll_l: symbol not found +Error relocating ./spotify: strtoull_l: symbol not found +Error relocating ./spotify: __isnanf: symbol not found +Error relocating ./spotify: __isinff: symbol not found +Error relocating ./spotify: __isnan: symbol not found +Error relocating ./spotify: __isinf: symbol not found +Error relocating ./spotify: __cxa_thread_atexit_impl: symbol not found +``` + +It seems that it uses a lot of glibc-specific stuff, but we can use Adelie Linux's [gcompat](https://git.adelielinux.org/adelie/gcompat) to make it work. + +``` +$ apk add gcompat +(1/3) Installing musl-obstack (1.2.2-r0) +(2/3) Installing libucontext (1.1-r0) +(3/3) Installing gcompat (1.0.0-r2) +OK: 11425 MiB in 1571 packages +$ patchelf --set-interpreter /lib/ld-musl-x86_64.so.1 spotify +$ patchelf --add-needed libgcompat.so.0 spotify +$ ldd spotify +(97 lines skipped...) +Error relocating ./libcef.so: __mbrlen: symbol not found +Error relocating ./libcef.so: __close: symbol not found +Error relocating ./libcef.so: initstate_r: symbol not found +Error relocating ./libcef.so: random_r: symbol not found +``` + +That's much better, but there are still a few things missing. `random_r` was added +[a few months ago](https://git.adelielinux.org/adelie/gcompat/-/commit/59e99e9e6db4fd4d33786fbe3ffd3fabf4a49dd7), +but `__mbrlen` and `__close` were still missing, so I cloned gcompat and [added them in](https://github.com/ptrcnull/gcompat). + +Note: gcompat seems to be temporarily no longer maintained as A. Wilcox has [retired](https://catfox.life/2020/10/21/leaving-the-linux-distribution-community/), +so I pushed my changed to a fork on GitHub instead of creating a merge request to the original repo. + +After recompiling gcompat and trying to run Spotify again, it still complains about missing glibc: + +``` +$ ./spotify +Error loading shared library ld-linux-x86-64.so.2: No such file or directory (needed by libcef.so) +``` + +Fortunately, another `patchelf`, this time to `libcef.so`, makes the error go away: + +``` +$ patchelf --remove-needed ld-linux-x86-64.so.2 libcef.so +$ ./spotify +``` + +Aaand... it crashes with `boost::filesystem::read_symlink: No such file or directory: "/proc/self/exe"`. +That's weird, `/proc/self/exe` should be present, `read_symlink` just calls +[https://github.com/steinwurf/boost/blob/1c73b071b4c458de71923072be2a7ee8e4c87799/libs/filesystem/src/operations.cpp#L1586](readlink), +and `readlink` [uses the syscall](https://github.com/bminor/musl/blob/cfdfd5ea3ce14c6abf7fb22a531f3d99518b5a1b/src/unistd/readlink.c#L5), right? + +Nope, gcompat [replaces](https://git.adelielinux.org/adelie/gcompat/-/blob/current/libgcompat/readlink.c) readlink with its own function to intercept `/proc/self/exe` (ugh), +but as we don't use the loader, we can remove it from the Makefile and build again. + +Another recompile of gcompat later, maybe now it would launch? + +``` +$ ./spotify +[1] 26559 segmentation fault (core dumped) ./spotify +``` + +Whoops, it doesn't look good... +After running `gdb spotify core`, it looks like it [segfaults](https://git.adelielinux.org/adelie/gcompat/-/issues/344) in `savestate_r () from /lib/libgcompat.so.0`. +We could try to fix this _or_ we can replace it with a [fair dice roll](https://xkcd.com/221/): + +```diff +diff --git a/libgcompat/random_r.c b/libgcompat/random_r.c +index 5bc7053..f6e7071 100644 +--- a/libgcompat/random_r.c ++++ b/libgcompat/random_r.c +@@ -141,4 +141,7 @@ int random_r(struct random_data *restrict buf, int32_t *restrict result) { + } + ++ *result = 4; ++ return 0; ++ + if (buf->n == 0) { + k = buf->x[0] = lcg31(buf->x[0]); +``` + +(and also add `return 0;` before first `savestate_r` in `initstate_r`) + +Aaand... it shows a window! + +![Empty white window on gray background, with title Spotify](/posts/spotify-on-musl/white_window.png) + +Sadly, after a while, the enthusiasm goes away - the window stays white and doesn't display any content. +Command line argument `--show-console` doesn't give us any helpful info either: + +``` +$ ./spotify --show-console +14:54:32.302 I [f:156 ] Access allowance changed from online: 0 stream: 0, sync: 0, persistent conn: 0 to online: 1 stream: 1, sync: 0, persistent conn: 1 +14:54:32.334 I [f:77 ] Connectivity policy is initially allow_all +14:54:32.334 I [f:79 ] Connection type is initially unknown +14:54:32.334 I [f:96 ] Enabling all persistent connections +14:54:32.353 I [f:150 ] D-Bus name 'org.freedesktop.NetworkManager' does not exist on system bus +``` + +Okay, but A. Wilcox [has the same issue](https://catfox.life/2020/07/06/live-from-adelie-streaming-spotify-on-musl/) - maybe we can use that? + +``` +$ ldd spotify + /lib/ld-musl-x86_64.so.1 (0x7f0b5dbf5000) + libgcompat.so.0 => /lib/libgcompat.so.0 (0x7f0b5dbe1000) + libm.so.6 => /lib/ld-musl-x86_64.so.1 (0x7f0b5dbf5000) + libdl.so.2 => /lib/ld-musl-x86_64.so.1 (0x7f0b5dbf5000) + libasound.so.2 => /usr/lib/libasound.so.2 (0x7f0b5daf6000) + libatomic.so.1 => /usr/lib/libatomic.so.1 (0x7f0b5daed000) + libcurl-gnutls.so.4 => /usr/lib/libcurl-gnutls.so.4 (0x7f0b5da73000) + libcef.so => ./libcef.so (0x7f0b52887000) +(86 lines skipped...) +``` + +It seems to match (libm/libdl before libcef), so let's try removing them and see what happens: + +``` +$ patchelf --remove-needed libm.so.6 libcef.so +$ patchelf --remove-needed libdl.so.2 libcef.so +$ ./spotify --show-console +15:02:04.445 I [f:156 ] Access allowance changed from online: 0 stream: 0, sync: 0, persistent conn: 0 to online: 1 stream: 1, sync: 0, persistent conn: 1 +15:02:04.491 I [f:77 ] Connectivity policy is initially allow_all +15:02:04.491 I [f:79 ] Connection type is initially unknown +15:02:04.492 I [f:96 ] Enabling all persistent connections +15:02:04.500 I [f:150 ] D-Bus name 'org.freedesktop.NetworkManager' does not exist on system bus +``` + +Unfortunately, it still shows the white window and `strace` reveals that it still segfaults: + +``` +28567 +++ killed by SIGSEGV (core dumped) +++ +28566 +++ killed by SIGSEGV (core dumped) +++ +28565 +++ killed by SIGSEGV (core dumped) +++ +28564 +++ killed by SIGSEGV (core dumped) +++ +28563 +++ killed by SIGSEGV (core dumped) +++ +``` + +This is where the post ends, at least for now (2021-11-19). + +If you manage to make it further than I did, please DM me on [Telegram](https://t.me/ptrcnull) or send an [e-mail](mailto:hello@ptrcnull.me). diff --git a/static/posts/spotify-on-musl/white_window.png b/static/posts/spotify-on-musl/white_window.png new file mode 100644 index 0000000000000000000000000000000000000000..9cd456833e8fa6f96ffaecbe22e6102a887a861f GIT binary patch literal 6301 zcmeHLX;4$=8a^y)Y6Q81fS?kPiI49YzXt%ZTM$ujWisufEdYpwV@*tK%uP&`d@tkNv0fMe z*c(rb*GE4$+F9#-(!#V*@`}`@dK=3ADA`M|;oCBd^JMJ(4^&P=$y)zZL&RS5tf`5s zEx1l9p-IxNDb0!W4-I9H>{eaUP%n+*zN>&uaP&ESBF0tCT7{mX?f9N=Rr_7{JcVy` zenmPut#adP^L{t0goMeR&b&$P45G1w-X_plc%51c+(+v*ZTWRipHf<1sYL7I3m4nO z)BS$^mu@4_{CfYK23#r>0oBv=$~`&t!o~Gbd(H7pC7JpEsEbl5$URwo3tQY6NGh?V z6?f{-Lrrvun7eE(vs=%0Co3HdzXm_P_xZ6zTgo=5T6bLVT%;odg@|xaJ#cw{x~N1k zd(-lD=3D#u{08?EdnLu4b`HC3gK$J+$O8n}5vu|5Nkg$SK|Rj-Vw(4}-*nrvAlrZ2 zh@kb5i#IuN02AvQUX3)?12xvvvqgF0N!ji64MCmcs$Axpy77xJUb-r%jwY`m6b~*Ajj|uxVQ;#ZfUw{5GpOHg)HBj zAO4V0gLxgGBdZdITI!+2LQ5>=BT5m0=mb0y}eG) z?0Uvs&Kb|iu~D+^cKta~_Pv#OF4Xm~T^P#2D2CiCfoZ&hx6ks?^P(Ks-0YouR9w2t zE?yMjQY;U1EswI2+LA8ny)92(sb+t2+11^|YqP&pRg~;;Q%Tn=BN!Cw(wUG`nl_{*H|f1QC&MQIH;{~pKNP4w-?6@3@TL<0iNA0rfCr5PY*)t z_(kK)khxZa4h>04wdN~#^h&fVSr~`I=Q#pooMK{+ZD_#2xqFSBbjO~{{Y}JEaj9Hf z(#(#ai3zJ^b+<*#2d78Y>7w9QMo1Z_m|}R-eUl%BL7azXob85lH%n0iNA4k8?8=usGS#bwk?*%dhbt)u(mYE(zvXl}GML zD~Ff*2p*s5Mfx|Us!LE2vH+0UOg6{EsV#?k6zoHFN6(ooxKsFb`XjV3YyLtso0Qhu z={fQ-(zPMxw)?UN9?zqi=49ob(UROzHO2{14j)oUdKAzw8F^R{*9{}3yy#bLFp^My z&9PS`rF=`E&N2-6`Tf7x(OE4E$-}U_a-@_kp}vlgjQNpPjDNIqY>SoR?a-;Ymt+QX zHEs?H-S!V!1Kj<_lAuGDMfO}0Q!Z{_JsQibT+BHGXOm-*gkpR{ES+7w!+0biLC4#O zcOk_~yZv?0bbB3UaIuJQ^}b6#YuNU~u7J7l2?2z6N=!gc#ExS2yN)BCE?$MOl?hk&UJ^6VX1nym>8k{oxO3ZD9p+ zvDsVUjph^a$k~@3f}$&gAq5do6oUzV*|P(KGEa*aByr3H|I?3IBoB9|%)!Y=<+rp$ ze#)VacmKG|mpbSdT&A_mCdGMpk_dy$`e+n!bk=&nu$gh`BhnM@tmoC@ydoV3U8g&N zO?e`LXI~-iRw0&aSa#2A3T7QQJdS}SP!z{IgU7_)?95v@2YHXmba|C_!<-k_+=3qM zdpgma8M26ch%>Anw6g@|RG;eO%uOt(b*E~wW_8}U3$TL*a$u%e)jX-jAJ*(tymQ5x z{-MCYQQETOX#r`N-dD|r74r1#b^RtWSQwo_Y|NxI#IzZd^F0kK1%nv3ENaYzPnYim z%W?YxmK&TVku>2e`ggnsx z-8L4lh*{jdQ@gF#EW!_gdsp9Yp!NfmstJ~z_B>zZq@*^OoOeh_2dr4fTiLGAKC2lmS){~ZD6f>R2&hKo`4eDv#fSp$_TQ|vFosla ztO*=G3;vDYo8Wq@`lCUuwZ8wiR`oZU+wZPvr5%1wBor66=I?|e?bSUC&xNfqe?}K3 zWNEMYJE6F+HGlUvg!<`j?Q;tHuM%Wk*jH9h}Q}rKH of{;^j-BkUzS>t~+Rg^Y{NPQQ@f-d{<1xOE=n_8i0#^