Bug 274280 - Incompatible default shell configuration
Summary: Incompatible default shell configuration
Status: New
Alias: None
Product: Base System
Classification: Unclassified
Component: conf (show other bugs)
Version: Unspecified
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2023-10-05 17:00 UTC by mirabilos
Modified: 2023-11-03 11:37 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description mirabilos 2023-10-05 17:00:07 UTC
I’m upstream for mksh (shells/mksh in ports), and I’ve had a user report problems on FreeBSD, which I was able to track down.

dot.shrc¹ contains commands specific to FreeBSD sh which are not POSIX conformant nor compatible with mksh; specifically, the bind commands in lines 34ff, although the PS1 is also nōn-standard.

The problem is exacerbated by dot.profile² exporting ENV, which makes mksh look at .shrc in the first place, which it normally would not.

Just like PS1, exporting ENV is something that should not be done. For ENV however, there’s the option of writing the designated file in a way that is compatible with all shells that read it (which is not an option for PS1).

My preference would be for FreeBSD to not export ENV. I understand this is most likely too much; therefore, please add the following lines…

if test -n "$KSH_VERSION"; then
	test -e ~/.mkshrc || return 0
	. ~/.mkshrc
	return
fi

… between the comment end on line 8 and the comment beginning on line 11 to fix this problem and MFC that to the active stable branches.

The change will defer from .shrc to .mkshrc if it exists (and if so, return its exit status up the chain), and just return true if it doesn’t exist.

The change will make it so that, when mksh (or pdksh, oksh or AT&T ksh93, incidentally, but the stock dot.mkshrc has a whitelist for mksh/lksh and just returns true for all other shells) is run, the remainder of the FreeBSD .shrc is ignored and the mksh one is used instead.

It might be useful to defer to different files, depending on what shells are ported however this will raise complexity.

Looking at your ports tree, I’m surprised to see that 1999 pdksh is even still present. But that can be mostly lumped together with oksh. A more complete solution would thus be:

if test -n "${KSH_VERSION:-}"; then
	# mksh/lksh? (shells/mksh port)
	case $KSH_VERSION in
	*LEGACY\ KSH*|*MIRBSD\ KSH*)
		test -e ~/.mkshrc || return 0
		. ~/.mkshrc
		return
		;;
	esac
	# AT&T ksh93? (shells/ast-ksh, shells/ksh, shells/ksh93)
	if (eval 'x=${.sh.version}') >/dev/null 2>&1; then
		test -e ~/.ksh93rc || return 0
		. ~/.ksh93rc
		return
	fi
	# other pdksh variants (shells/oksh, shells/pdksh)
	test -e ~/.kshrc || return 0
	. ~/.kshrc
	return
fi

This is assuming users of these shells would create the corresponding dotfiles. There’s historic evidence for ~/.kshrc, mostly by pdksh/oksh users; there’s none for ~/.ksh93rc TTBOMK (some, but few, seem to be using ~/.kshrc).

This leaves out GNU bash, AT&T ksh88, yash, zsh (if any of these honour $ENV).

From my shell detection utility³, they can easily be detected by:

if test -n "${BASH_VERSION:-}"; then
	…
fi

case ${YASH_VERSION:-} in
*.*)
	…
	;;
esac

case ${ZSH_VERSION:-} in
*[0-9]*)
	…
	;;
esac

case ${VERSION:-} in
zsh*)
	…
	;;
esac

(the last one is for old versions of zsh and may not be necessary any more)

This leaves out AT&T ksh88, which is sensible as it’s binary-only and only present on old Unicēs, and other sh variants like NetBSD sh, ash/dash, etc.

There *is* a dash port; dash does not support bind, and it does not set a shell parameter to detect it; dash does read $ENV. You’ll have broken dash users, but that’s probably not a big issue.

Unfortunately, FreeBSD /bin/sh doesn’t appear (I don’t have access to a FreeBSD system at the moment, only a MidnightBSD system, but it seems to share /bin/sh still) to set a variable to discern it either, so let’s just ignore dash for now.


Note: I don’t advocate for leaving out the bind commands from .shrc instead. Users of the other shells *will* want to be able to read their shells’ own startup files (especially considering mksh ships such a rich one predefined), so diverting to them is necessary.


① https://cgit.freebsd.org/src/tree/usr.bin/man/man.shhttps://cgit.freebsd.org/src/tree/share/skel/dot.profilehttp://www.mirbsd.org/cvs.cgi/contrib/code/Snippets/getshver?rev=HEAD
Comment 1 Jilles Tjoelker freebsd_committer freebsd_triage 2023-10-14 20:03:39 UTC
The reasoning for exporting ENV was to make sure interactive non-login shells have the user's settings such as aliases and shell options, while not extending the startup files from the POSIX standard. However, this indeed has the problem that the ENV file must be readable by all POSIX-style shells.

Perhaps the cleanest solution is to read, in interactive shells, a file with some hard-coded name from the user's home directory if ENV is not set. In an interactive login shell, this file would be read after .profile (if .profile did not set ENV). The standard dot.profile can then be changed to stop setting ENV.

The hard-coded name could be something like .shrc or something new like .freebsdshrc.

By the way, bash's decision to use the ENV file only when it is invoked as sh or in POSIX mode (in either case, only in interactive shells, as specified by POSIX) helps it here.
Comment 2 mirabilos 2023-10-14 23:12:33 UTC
> Perhaps the cleanest solution is to read, in interactive shells, a file with
> some hard-coded name from the user's home directory if ENV is not set. In an

That’s what mksh does: it expands "${ENV:-~/.mkshrc}".

I didn’t want to presume requesting for adding it to your sh, but if you’re in favour of that, it’d also solve the situation.

Otherwise, adding suitable lines sending other shells to their respective *rc files in the default $ENV are needed, yes.

Thanks!