Hi all,

Busybox's ash built-in commands -e.g. echo, printf, cd- returns an error
if the stdout/stderr device is not available. In particular, I reached
this behavior while debugging a Debian initramfs, where ash built-in
commands are run during boot, before the console is available.

For example, Debian initramfs-tools handles this type of error on
printf:
https://salsa.debian.org/kernel-team/initramfs-tools/-/blob/master/scripts/functions#L8

```
_log_msg()
{
    if [ "${quiet?}" = "y" ]; then return; fi
    # shellcheck disable=SC2059
    printf "$@"
    return 0 # Prevents error carry over in case of unavailable console
}
```

* As I'm not sure if this is really a bug or not, I'm sending this as an
RFC. So, the question of this RFC is: should this be considered a bug
and get fixed properly?

Note that running other commands from ash won't fail. Although I haven't
checked the source code, that's probably due to the forking process
handling stdout/stderr differently.

The following straces were run from inside and initramfs, when the
console device was still unavailable.

Failing case,`cd /` runs silently, but `cd -` tries to print to stdout:

```
strace sh -c "cd / ; cd -"
[...]
chdir("/")                              = 0
wait4(-1, 0x7fff4d5351bc, WNOHANG, NULL) = -1 ECHILD (No child processes)
chdir("/")                              = 0
newfstatat(1, "", {st_mode=S_IFCHR|0600, st_rdev=makedev(0x5, 0x1),
...}, AT_EMPTY_PATH) = 0
ioctl(1, TCGETS, 0x7fff4d534880)        = -1 EIO (Input/output error)
write(1, "/\n", 2)                      = -1 EIO (Input/output error)
getpid()                                = 223
exit_group(1)                           = ?
+++ exited with 1 +++
```

Success case, redirecting `cd -` stdout to /dev/null:

```
strace sh -c "cd / ; cd - >> /dev/null"
[...]
chdir("/")                              = 0
openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fcntl(1, F_DUPFD_CLOEXEC, 10)           = 10
dup2(3, 1)                              = 1
close(3)                                = 0
wait4(-1, 0x7ffc316043cc, WNOHANG, NULL) = -1 ECHILD (No child processes)
chdir("/")                              = 0
newfstatat(1, "", {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1, 0x3),
...}, AT_EMPTY_PATH) = 0
ioctl(1, TCGETS, 0x7ffc31603a90)        = -1 ENOTTY (Inappropriate ioctl
for device)
write(1, "/\n", 2)                      = 2
dup2(10, 1)                             = 1
close(10)                               = 0
getpid()                                = 219
exit_group(0)                           = ?
+++ exited with 0 +++
```

>From Busybox ash source code, it can be seen that the *lone-dash* case
`cd -` tries to print to stdout. The other cd cases with the target
directory explicitly set don't fail as they don't try to open the output
device, which is unavailable at that point.

>From https://git.busybox.net/busybox/tree/shell/ash.c#n2980:

```
static int FAST_FUNC
cdcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
{
[...]
        else if (LONE_DASH(dest)) {
                dest = bltinlookup("OLDPWD");
                flags |= CD_PRINT;
        }
[...]
 out:
        if (flags & CD_PRINT)
                out1fmt("%s\n", curdir);
        return 0;
}
```

Regards,
Ariel D'Alessandro
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to