FS#68484 - [filesystem] [bash] [bash-completion] wrong init files order for interactive login shell

Attached to Project: Arch Linux
Opened by Alexandre Bouvier (doskoi) - Saturday, 31 October 2020, 06:09 GMT
Last edited by Sébastien Luttringer (seblu) - Tuesday, 07 December 2021, 01:19 GMT
Task Type Bug Report
Category Packages: Core
Status Closed
Assigned To Sébastien Luttringer (seblu)
Architecture All
Severity Low
Priority Normal
Reported Version
Due in Version Undecided
Due Date Undecided
Percent Complete 100%
Votes 0
Private No


The order in which init files are sourced is wrong for a interactive login shell. Apparently because of https://bugs.archlinux.org/task/15456.

Current order:

/etc/profile (sourced by bash)
/etc/bash.bashrc (sourced by /etc/profile)
/usr/share/bash-completion/bash_completion (sourced by /etc/bash.bashrc)
~/.bash_profile (sourced by bash)
~/.bashrc (sourced by ~/.bash_profile)

But /etc/bash.bashrc should be sourced in ~/.bash_profile instead (which makes all the tests of /etc/profile obsolete at the same time).
For example /usr/share/bash-completion/bash_completion (sourced in /etc/bash.bashrc) is sourced before user defined variables are set in ~/.profile, which prevents the use of the BASH_COMPLETION_USER_FILE variable (sourced at the end of /usr/share/bash-completion/bash_completion).
Correct order in which profile files are sourced before anything else:

/etc/profile (sourced by bash)
~/.bash_profile (sourced by bash)
/etc/bash.bashrc (sourced by ~/.bash_profile)
/usr/share/bash-completion/bash_completion (sourced by /etc/bash.bashrc)
~/.bashrc (sourced by ~/.bash_profile)

Other solutions are:
- defining BASH_COMPLETION_USER_FILE in /etc/profile (impossible for non-root user)
- sourcing /usr/share/bash-completion/bash_completion in ~/.bashrc (so after ~/.bash_profile) instead of /etc/bash.bashrc

What need to be removed in /etc/profile:

# Source global bash config, when interactive but not posix or sh mode
if test "$BASH" &&\
test "$PS1" &&\
test -z "$POSIXLY_CORRECT" &&\
test "${0#-}" != sh &&\
test -r /etc/bash.bashrc
. /etc/bash.bashrc

What need to be added at the top of /etc/skel/.bash_profile (and every existing user's ~/.bash_profile):

[[ -f /etc/bash.bashrc ]] && . /etc/bash.bashrc

New users will have nothing to do, but existing users will have to add the /etc/bash.bashrc sourcing in their ~/.bash_profile.
This task depends upon

Closed by  Sébastien Luttringer (seblu)
Tuesday, 07 December 2021, 01:19 GMT
Reason for closing:  Not a bug
Comment by Eli Schwartz (eschwartz) - Sunday, 01 November 2020, 01:40 GMT
I don't see a good reason to break this feature by default. If you don't like it, you can remove it from /etc/bash.bashrc -- it is a configuration file, pacman won't overwrite local modifications. Or you could even re-source /usr/share/bash-completion/bash_completion and it will do all work again, including sourcing the new value of your legacy completion file.

Anyway you should be using $BASH_COMPLETION_USER_DIR/cmd to complete `cmd <TAB>` (defaults to ~/.local/share/bash-completion/completions/ via $XDG_DATA_HOME) to lazy load completions via _completion_loader, which by virtue of being lazy loaded is both faster on startup and evaluated after ~/.bashrc and is therefore a win-win situation.
Comment by Alexandre Bouvier (doskoi) - Sunday, 01 November 2020, 09:37 GMT
It won't break anything. On the contrary it will makes things work correctly. BASH_COMPLETION_USER_FILE is a useless variable in the current situation (unless /usr/share/bash-completion/bash_completion is sourced a second time in ~/.bashrc).

Anyway, bash-completion was just an example to illustrate the wrong order. The problem is that any potentially user-defined (in ~/.bash_profile) variable used in /etc/bash.bashrc will be undefined when /etc/bash.bashrc is sourced.

~/.bashrc is already sourced in the default ~/.bash_profile, why not also adding /etc/bash.bashrc?
Comment by Eli Schwartz (eschwartz) - Sunday, 01 November 2020, 11:55 GMT
I don't quite comprehend how you think making bash-completion not work by default is "not breaking anything". I reiterate: if you don't believe it should ever be doing anything out of the box, you're free to remove it from /etc/bash.bashrc on your system.

We are definitely not going to completely remove the global bashrc from `bash` and require people to source it in their user bash_profile -- that is just plainly not how bash_profile works.
Comment by Alexandre Bouvier (doskoi) - Sunday, 01 November 2020, 13:45 GMT
But I want to make it work by default precisely!

Bash itself doesn't source ~/.bashrc for login shell. This is why you need to manually source it in ~/.bash_profile. And that is the default because this is written in /etc/skel/.bash_profile.

It's the same for the global bashrc, it needs to be sourced by someone. And I just think ~/.bash_profile is the right candidate.

The fact that it takes 4 tests before you can source /etc/bash.bashrc in /etc/profile indicates that this is not the right place to do it. None would be required in ~/.bash_profile.

And I know I can edit my own files, I already did, but it's my attempt to try to make things better for everyone else ;)

Example of other distros:

- Fedora and Mageia source the global bashrc in ~/.bashrc, which is weird because it's probably sourced twice for non-login shell.

- Gentoo does the same as Arch, but has an interesting comment in /etc/profile:

# Bash login shells run only /etc/profile
# Bash non-login shells run only /etc/bash/bashrc
# Since we want to run /etc/bash/bashrc regardless, we source it
# from here. It is unfortunate that there is no way to do
# this *after* the user's .bash_profile runs (without putting
# it in the user's dot-files), but it shouldn't make any
# difference.

But the fact is, there is a difference, as pointed in my first message.

And if the global bashrc is sourced in /etc/skel/.bash_profile, it becomes the new default ;)
Comment by Eli Schwartz (eschwartz) - Sunday, 01 November 2020, 14:06 GMT
It's entirely reasonable for *user .bashrc* to be sourced from *user .profile*, the same cannot be said for the global bashrc being sourced from user files.

What Fedora does is irrelevant, and if as you say it is sourced twice then you seem to be the one making a compelling argument that they're wrong...

This entire "correctness" argument is a red herring. Gentoo's comment is correct, there's no difference where you source bashrc -- only where you source bash-completion (and only then due to the odd choice to make this startup_configurable when it's easier to just source the file you want than to set an environment variable to source it for you). On technical correctness alone, it is wildly inappropriate to change how this works.

Going back to your original argument specific to bash-completion, this optional feature that Arch's package does not support out of the box is, once again, deprecated. Why do you need to override the startup completion file rather than overriding the lazy load directory?

I still don't see much reason to change how this works.