# EnvShim EnvShim is a symlink shim to load executables with user-defined environment variables. Refer next section for more details on what this means. **Status:** This project is active and a 1.0 release is planned. It currently has all the features I personally expect from it and is of beta quality. However, it will be in 0.x version for a while to identify any bugs or essentially needed features. Not a lot of features will be added, since that may slow down program and delay the loading of the final application. ## EnvShim in detail **The problem:** A big issue on a GNU/Linux desktop is that there are so many incompatible ways to define environment variables. A cursory search indicates `/etc/profile.d/`, `.bashrc`, `~/.profile`, `~/.xprofile`, `~/.config/environment.d/envvars.conf`, `/etc/environment` and numerous other locations. There is no reliable method to define all the variables in one place and have all the applications pick them up. There are also surprising ways in which desktop managers like SDDM and GDM process these variables. Some desktop environments like Gnome and KDE force a standard way of defining users' environment variables. However, it's still an issue on window managers like sway or awesome. **The solution:** EnvShim aims to provide a way for users to define their variables in a single source of truth (`~/.config/envshim/script` file) and ensure that the desired applications pick it up. The way EnvShim solves this is by acting as a loader shim for the desired target applications. For this, symlinks to the `envshim` executable is with the same name as the target application is placed in directory that has precedence over the actual target application in the $PATH variable. Consider an example using the sway executable: ```sh _# printenv PATH /usr/local/sbin:/usr/local/bin:/usr/bin _# which sway /usr/bin/sway _# which envshim /usr/local/bin/envshim _# ln -sr /usr/local/bin/envshim /usr/local/bin/sway _# rehash _# which sway /usr/local/bin/sway ``` In the above case, `/usr/local/bin` has a higher precedence than `/usr/bin`. Therefore, when we try to execute sway, `envshim` will be invoked via the symlink in `/usr/local/bin` instead of `/usr/bin/sway`. Envshim then takes care of initializing the variables and then invoking the target (`/usr/bin/sway`). **User settings:** The second requirement for this to work is a file where the variables are declared. This has to created by the user in their home directory under `$XDG_CONFIG_HOME/envshim/script`. If `$XDG_CONFIG_HOME` is undefined, the default location is assumed - `~/.config/envshim/script`. The `script` file is a shell script written for a shell (like `sh` or `bash`) of user's choice. At the time of shim loading, `envshim` invokes that shell as a subprocess and feeds the content of the script to it. Envshim then reads the result of the script execution and uses it to define the environment for the target application. Envshim then `exec`s into the target application, replacing itself with the target application in the process. ## Building Clone this repository and cd into it. Then issue the normal `cargo` command to build it. Copy the executable to the desired location afterwards. ```sh git clone https://git.sr.ht/~gokuldas/envshim cd envshim cargo build --release sudo cp target/release/envshim /usr/local/bin ``` ## Configuration There are two steps in the configuration process: **1. Script file:** The user has to create a script file at `$XDG_CONFIG_HOME/envshim/script`. It doesn't need an executable permission. The first line is a *shebang* line indicating the shell to use and configured to accept input from stdin. The following are some options: - `#!/usr/bin/sh -s` - `#!/usr/bin/bash -s` - `#!/usr/bin/zsh -s` Fill the script file to *print* the necessary variables in a `VAR=value` format, one variable per line. This can be done using `echo`, for example. If it's desired to print out all the environment variables at once, `printenv` command does the job. Just remember to `export` the variables before using `printenv`. For example: ```sh export PATH=$HOME/.local/bin:$PATH printenv echo 'ENVSHIM_MARKER=envshim' ``` A sample of this file is provided as `assets/script` in this repo. **2. Create shims:** Shims are symlinks with the same name as the target and pointing to `envshim` executable. The important matter here is to ensure that the **shims come first in $PATH before the target executable**. For example, if `PATH=/usr/local/bin:/usr/bin` and the target application is `/usr/bin/sway`, then `/usr/local/bin/sway` is reasonable choice for the shim. Another matter to note is that PATH variable mentioned here is what you get before shim loading. Don't depend on paths defined in the script file. Have a look at the example given in 'EnvShim in detail' section. Which applications should be chosen for shim loading? There are two guidelines that can help decide. 1. Any application for which you want to ensure the correct variables 2. Any application that is the parent process of most other applications Shim loading adds a delay time to the loading of the target application, since a shell has to be run before it. The second guideline helps to reduce such delays by doing shim loading fewer times and then passing on the result to as many other processes as possible. Here are some possible candidate for shim loading: - Shells (like bash or zsh) - Window managers (like sway or awesome) ## Troubleshooting Envshim is designed to run the target application in any of the cases where the target is available. This means that the target will run even if the shell or the script fails or is missing. However, the environment variables that the target receives may not be what you expect. It's designed like this to avoid making the target application inaccessible in case of any other error. You wouldn't want your shell or window manager to be inaccessible because of a missing or misconfigured script. If you suspect such a fail-safe shim load, you should try running the application from a command shell. EnvShell prints error messages on stderr if it encounters any problem. ## Contributing Suggestions and contributions are welcome through the [mailing list](mailto:~gokuldas/projects@lists.sr.ht). Refer to the [Contributor Guidelines](https://git.sr.ht/~gokuldas/free-software/tree/master/CONTRIBUTING.md) and [Project Policies](https://git.sr.ht/~gokuldas/free-software/tree/master/policies.md) page of my free software index for details on how to contribute. Meanwhile, the following additional guidelines apply: 1. Format your code with `rustfmt` before submission - The text width for markdown documents is 100 2. The patches must be signed-off (`git commit -s`) 3. Set up the cloned local repository with the following configuration: ```sh git config format.to "~gokuldas/projects@lists.sr.ht" git config format.subjectPrefix "PATCH EnvShim" git config format.coverLetter auto git config format.useAutoBase true git config format.signOff true ``` ## License **envshim**: Symlink shim to load executables with user-defined environment variables Copyright (C) 2023 Gokul Das B SPDX-License-Identifier: **GPL-3.0-or-later** This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see .