From 3eb4d872f7157b67691fb5a98e2cf53f716c5457 Mon Sep 17 00:00:00 2001 From: Kévin Le Gouguec Date: Sat, 18 Jan 2025 19:00:03 +0100 Subject: Resume gratuitous shuffling --- guides/sysadmin/apps.org | 186 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 guides/sysadmin/apps.org (limited to 'guides/sysadmin/apps.org') diff --git a/guides/sysadmin/apps.org b/guides/sysadmin/apps.org new file mode 100644 index 0000000..0ff0184 --- /dev/null +++ b/guides/sysadmin/apps.org @@ -0,0 +1,186 @@ +#+TITLE: Installing applications under =$HOME= + +One day I woke up and decided to stop letting ~make install~ put +programs under =/usr/local/=. Not every project provides an +=uninstall= target, so over time, as more and more applications get +lumped under that hierarchy, it becomes a clutter of stuff that I +cannot remove without… + +1. guesstimating what files belong to any given program using + timestamps, +2. weighing my odds of passing correctly crafted globs to the likes of + =sudo find -delete= and =sudo rm -r= without destroying my system. + +Instead I figured I would start ~./configure~'ing programs with +=--prefix=${HOME}/apps/${program}=, and teach whichever dotfiles +manage session environment variables to arrange for installed +resources to be found. + +How hard could it be? + +* =PATH= +The Correct Way™ to set environment variables seems to depend on + +1. the kind of session (TTY vs GUI), +2. the init system (e.g. [[https://www.freedesktop.org/software/systemd/man/environment.d.html][systemd user environment variables]]) +3. the desktop environment (e.g. [[https://userbase.kde.org/Session_Environment_Variables][Plasma session environment variables]]), +4. the display server, +5. the distro? + - e.g. Debian's SSDM [[https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=794419][used not to]] source =~/.profile=, + - and [[https://github.com/sddm/sddm/issues/448][developers said]] it should not anyway, + - except [[https://github.com/sddm/sddm/issues/1551][it has provisions to do so]]? +6. [[https://man7.org/linux/man-pages/man8/pam_env.8.html][PAM]]? + +Empirically with Plasma on both Tumbleweed (20230929) and Debian 12, +=~/.profile= seems to be run for both TTY and GUI sessions. Unclear +what arcane magic is causing that: probably the login manager - on +Tumbleweed =/usr/share/sddm/scripts/Xsession= seems to start a ~bash +--login~, but getting lost in the =/usr/etc/X11/xdm/= weeds trying to +track down who might source that =Xesssion= script. + +=~/.profile= it is, then 🤞 + +(For other DEs on X, my recollection was that =~/.xsessionrc= is the +way to go for GUI sessions? No clue about Wayland) + +* ~man~ pages +=manpath(5)= says: + +#+begin_quote +By default, man-db examines the user's =$PATH=. For each +=path_element= found there, it adds =manpath_element= to the search +path. + +If there is no =MANPATH_MAP= line in the configuration file for a +given =path_element=, then it adds all of =path_element/../man=, +=path_element/man=, =path_element/../share=man=, and +=path_element/shared/=man= that exist as directories to the search +path. +#+end_quote + +How convenient! Setting =PATH= automatically takes care of ~man~ +then… unless =MANPATH= is set, in which case that logic is bypassed. + +** openSUSE +=/usr/etc/profile.d/manpath.sh= [fn:: sourced by =/etc/profile=, +sourced by =/usr/etc/profile= and =~/.profile=.] plays a little danse +to (a) query ~manpath~, which runs the heuristic described above (b) +set the resulting value "in stone" by exporting =MANPATH=. + +This means that ~man~ will not consider any =PATH= element added by +the user after that profile fragment was sourced. + +Solutions: + +1. Unset =MANPATH= in =~/.profile=, after =/etc/profile= is read. + =~/.profile= is "read each time a login shell is strated. All + other interactive shells will only read .bashrc", so unclear + whether that will affect graphical sessions. +2. Extend =PATH= with apps /before/ those profile fragments are + loaded. Unclear how to accomplish that: + - [[https://wiki.archlinux.org/title/environment_variables#Per_user][systemd user environment variables]]? Seems to be limited to + =KEY=VALUE= directives; I would like to run a bit of logic that + will automatically add every =~/apps/*/bin= directory. + - [[https://userbase.kde.org/Session_Environment_Variables][Plasma session environment variables]]? Presumably will not affect + TTYs? +3. Embrace the distro's method: if =MANPATH= is set, extend it. + +Went with solution 1 because empirically =~/.profile= seems to be +sourced for GUI sessions (as noted in § =PATH=). + +* ~info~ pages +Similar to ~man~, ~info~ knows to work with =PATH=. The priority +[[https://git.savannah.gnu.org/cgit/texinfo.git/tree/info/infopath.c?h=texinfo-7.0.3#n41][seems to be]]: + +1. the =INFOPATH= environment variable, +2. the =INFODIR= build macro, /if =infopath-no-defaults= is not set/, +3. the =DEFAULT_INFOPATH= build macro, /if =INFOPATH= is unset or ends + with a trailing colon/. + +Any of these can contain the =PATH= literal, which means "iterate over +=${PATH}= and add nearby =share/info= & =info= directories". By +default, =DEFAULT_INFOPATH= contains =PATH= 🥳 but =INFODIR= has +priority and is set to something boring like =/usr/share/info= 😒 + +Solution: + +#+begin_src bash +cat < ~/.infokey +#var +# Disable INFODIR; fall back to DEFAULT_INFOPATH which prioritizes +# program PATH over /usr/share/info. +infopath-no-defaults=On +EOF +#+end_src + +* DONE systemd services +=systemd.unit(5)= § "User Unit Search Path" mentions a couple of +variables that we could append: + +- =$XDG_CONFIG_DIRS/systemd/user/*= +- =$XDG_DATA_DIRS/systemd/user/*= + +And: + +#+begin_quote +When the variable =$SYSTEMD_UNIT_PATH= is set, the contents of this +variable overrides the unit load path. If =$SYSTEMD_UNIT_PATH= ends +with an empty component (=:=), the usual unit load path will be +appended to the contents of the variable. +#+end_quote + +So we could either: + +1. find the directory 𝒟 where an app tucks =systemd/user= in its + installation tree, and append 𝒟 to one of the XDG variables, +2. find the directory where an app tucks its =.service= files, and + append that directory to =SYSTEMD_UNIT_PATH=, keeping a final + colon. + +(1) could feed multiple birds with one scone: in particular, +=XDG_DATA_DIRS= is used for other purposes (see § Desktop entry +files). Serendipitously, [[https://github.com/systemd/systemd/blob/1d87a00a951dca801c8ccd79c1460fa91efa7dce/src/basic/path-lookup.c#L147][the systemd sources]] suggest =DATA= over +=CONFIG= for our purposes: + +#+begin_src c + /* Implement the mechanisms defined in + * + * https://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html + * + * We look in both the config and the data dirs because we + * want to encourage that distributors ship their unit files + * as data, and allow overriding as configuration. + */ +#+end_src + +* DONE Desktop entry files +The Freedesktop [[https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html][Desktop Menu]] and [[https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html][Desktop Entry]] specs spell out how +=XDG_DATA_DIRS= will be searched for =applications/*.desktop= files. + +* TODO ~bash~ completions + +* Putting it all together +Presenting [[./apps-demo/activate][=~/apps/activate=]], to be sourced from =~/.profile=: + +#+INCLUDE: "apps-demo/activate" src sh + +* Resources +** [[https://nullprogram.com/blog/2017/06/19/][nullprogram.com]] — Building and Installing Software in $HOME +Explains how to set things up so that one can use =~/.local= as a +first-class citizen for applications, libraries and development +resources (headers, pkg-config, manpages). + +** [[https://specifications.freedesktop.org][specifications.freedesktop.org]] — Freedesktop.org Specifications +Hosts the specifications for the behavior and environment variables +most GNU/Linux distros (that I have experience with) adhere to, e.g. + +- the [[https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html][Base Directory spec]] :: defines the various + =XDG_*_@(HOME|DIR|DIRS)= variables referenced here; +- the [[https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html][Desktop Entry spec]] :: explains the significance of a desktop + file's filename with respect to its position within =XDG_DATA_DIRS=; +- the [[https://specifications.freedesktop.org/menu-spec/menu-spec-latest.html][Desktop Menu spec]] :: defines the expected file locations for + desktop files (and more) with respect to XDG base directories. + +** [[https://wiki.archlinux.org/title/Environment_variables#Per_user][wiki.archlinux.org]] — Environment variables § Per user - ArchWiki +A thorough overview of the myriad of ways users can amend environment +variables, as examined in § PATH. -- cgit v1.2.3