Chan Kim
Chan Kim

Reputation: 5999

How to set commands that should be automatically executed in busybox ash?

I want a command to be excuted after busybox ash starts.
I saw here that busybox ash is debian ash variant, and after seeing here, tried setting

ENV=$HOME/.shinit; export ENV

in file /etc/profile, and adding (BTW, this is to make Ctrl-C work in the shell)

setsid cttyhack sh

in file /.shinit.
But when I entered the shell, the 'ENV' variable is not set. (echo $ENV shows nothing).
How should I do it? By the way, my shell doesn't ask for loging(no login shell).

ADD :
This is my /init script.

#!/bin/sh
echo "### INIT SCRIPT ###"
mkdir /proc /sys /tmp
mount -t proc none /proc
mount -t sysfs none /sys
mount -t tmpfs none /tmp
echo -e "\nThis boot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
mknod /dev/virtual_buffer c 125 0

#ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
#route add default gw 10.0.2.2
echo "### calling /bin/sh ###"
exec /bin/sh

Upvotes: 1

Views: 1000

Answers (1)

Anya Shenanigans
Anya Shenanigans

Reputation: 94849

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;

Upvotes: 0

Related Questions