Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

support for POSIX job control terminal management in zsh


I noticed that zsh does not implement POSIX.1 when it comes to
saving/restoring the terminal state of processes suspended with
SIGTSTP.  (The same applies to bash, btw, but not to ksh.)  Shells
like tcsh or ash/dash also do not implement it.

POSIX.1 asks that:

"When a foreground (not background) job stops, the shell must sample
and remember the current terminal settings so that it can restore them
later when it continues the stopped job in the foreground (via the
tcgetattr( ) and tcsetattr( ) functions)."

Consequently, a program such as the one attached below should not fail
any assertions.
However, it does not appear to work when run under zsh.

I've had an illuminating discussion with Chet Ramey, the author of
bash, regarding bash's behavior. He pointed out that applications
historically could never rely on the shell provided job control in a
manner that they could be oblivious to being suspended/resumed, and
therefore always had to handle the saving/restoring of the terminal
state upon suspend/restore themselves, rather than relying on the job
control shell as POSIX asks.

Still, at least one shell (ksh) does appear to implement it.

Hence my question, out of curiosity, is: why does zsh not follow
POSIX.1 semantics in this regard?


 - Godmar

// ts_test.c
/* Test that terminal state is properly restored when a process is
stopped and restored. */
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>

#define CTRL_D  4
#define CTRL_E  5

    int terminal_fd = open(ctermid(NULL), O_RDWR);
    assert (terminal_fd != -1);

    // Step 1. make a change to the terminal state:
    // change VEOF from Ctrl-D to Ctrl-E
    struct termios saved_tty_state;
    int rc = tcgetattr(terminal_fd, &saved_tty_state);
    assert (rc == 0);

    assert (saved_tty_state.c_cc[VEOF] == CTRL_D);       // ^D
    saved_tty_state.c_cc[VEOF] = CTRL_E;                 // ^E
    rc = tcsetattr(terminal_fd, TCSANOW, &saved_tty_state);
    assert (rc == 0);

    // Step 2.  Suspend and let user resume
    printf("This job should now stop, please run 'fg' to continue it\n");
    printf("Job now continuing...\n");

    // Step 3.
    // Expect that job control shell saved the terminal state
    rc = tcgetattr(terminal_fd, &saved_tty_state);
    assert (rc == 0);
    if (saved_tty_state.c_cc[VEOF] != CTRL_E) {
        printf("I expected a POSIX job control shell to preserve my
terminal settings\n");
        printf("VEOF was not saved, it is %d...\n", saved_tty_state.c_cc[VEOF]);

    assert (saved_tty_state.c_cc[VEOF] == CTRL_E);       // ^E

Messages sorted by: Reverse Date, Date, Thread, Author