Using less in environment without controlling tty

Harald Becker ralda at
Fri Jul 26 21:42:57 UTC 2013

Hi all,

sorry for the delays of my work on the sleep/timeout applets.
I'm currently really busy due to activities of craftsmen here
and some public authority duties ... and I'm got stuck with a
frustrating problem:

I tried to use less as a startup message viewer from an init
script and had massive problems to get that working, as less
uses /dev/tty, which is not available in environments without a
controlling tty.

The situation is as following:

In process pid 1:

#!/bin/busybox sh


  ... do startup code here
} | console_buffer

Where console_buffer is a little application to buffer console
messages in a circular memory buffer. Those messages are flushed
(and never displayed) if the startup code succeeds without
errors. In case there are errors, console_buffer forks a command
and pipes all messages from it's buffer to that command. As
command I tried to use less, but resulted in a display like cat.

It took me a long time until I found the reason for this. Busybox
less opens /dev/tty to display the messages and control message
view. The open call of /dev/tty fails and there seams to be no
possibility to work around this.

The relevant code part of less seams to be (from less_main):

        /* Another popular pager, most, detects when stdout
         * is not a tty and turns into cat. This makes sense. */
        if (!isatty(STDOUT_FILENO))
                return bb_cat(argv);

        if (!num_files) {
                if (isatty(STDIN_FILENO)) {
                        /* Just "less"? No args and no
        redirection? */ bb_error_msg("missing filename");
        } else {
                filename = xstrdup(files[0]);

        if (option_mask32 & FLAG_TILDE)
                empty_line_marker = "";

        kbd_fd = open(CURRENT_TTY, O_RDONLY);  <-- open /dev/tty
        if (kbd_fd < 0)
                return bb_cat(argv);

        tcgetattr(kbd_fd, &term_orig);
        term_less = term_orig;
        term_less.c_lflag &= ~(ICANON | ECHO);
        term_less.c_iflag &= ~(IXON | ICRNL);
        /*term_less.c_oflag &= ~ONLCR;*/
        term_less.c_cc[VMIN] = 1;
        term_less.c_cc[VTIME] = 0;

My current (temporary) fix for this is, to patch Busybox to use
fd #2 (stderr) als kbd_fd (kbd_fd = 2;) then it is possible to
redirect output of less to any location you like:

 ... | less 2<>/dev/ttyN

This works fine in all tested cases, but needs patching of
Busybox. So I really like to get a fix for this in main stream.

... or are there any other suggestions on how to use less in
such a situation?

If this is going to be accepted, I can send a patch, but as it is
unclear how we shall handle this situation, I decided to ask for
suggestions ahead.

... and no, I can't use cttyhack for this, as I do not like to
make any tty the controlling tty for process 1. Output of pid 1
is redirected entirely to the console_buffer. I just want to be
able to invoke less, pipe the messages and display on a specific
virtual tty, when the startup fails in any way.


More information about the busybox mailing list