After seeing your boot script, and duplicating exactly what you present above I experienced the joys of infinite sh#
prompts.
Your problem is that you're entering an infinite loop. To explain what's happening, we follow the logic in your script.
When you invoke the shell with the --login
option, it reads /etc/profile
. This has a line reading:
ENV=$HOME/.shinit; export ENV
which, at the end of processing the profile is sourced.
This file contains the line: setsid cttyhack sh
This launches a new copy of sh
, which has been pre-armed with an ENV
variable, which causes it to issue setsid cttyhack sh
… repeat until your screen is covered in shell prompts and you're scratching your head.
The solution is even simpler than you think. Rather than getting the ENV file to load that cttyhack, move it into the init
script, i.e. at the bottom of the init script, instead of just sh
do:
exec setsid cttyhack sh --login
Don't add the line to the .shinit
with the setsid cttyhack sh
, and you don't end up with an infinite loop.
TLDR - Below is for loading /etc/profile
initially
You pretty much answered the issue in your question, when you mentioned:
By the way, my shell doesn't ask for loging(no login shell)
So I'm guessing that you're launching it with something like: busybox ash
, without any arguments.
There are two modes for launching a shell - as a 'login' type shell and as a 'non-login' type shell. This governs the launch behavior.
When you invoke a login-type shell, it will read the /etc/profile
file and the ~/.profile
files. This can be seen in the source -
behavior on isloginsh
:
if (argv[0] && argv[0][0] == '-')
isloginsh = 1;
if (isloginsh) {
const char *hp;
state = 1;
read_profile("/etc/profile");
state1:
state = 2;
hp = lookupvar("HOME");
if (hp)
read_profile("$HOME/.profile");
}
The detection of isloginsh
can also be set by passing in the -l
or --login
options, where the argument parser checks if the -l
or --login
options are passed:
} else if (cmdline && (c == 'l')) { /* -l or +l == --login */
isloginsh = 1;