5

I use nethack with ttyrec to archive my funny deaths. My only issue is that nethack uses as much screen space as possible to print log massages.

I would like to limit it to only work with 80x24 terminal size. To fool nethack that it has access to only 80x24 tty.

I tried tmux, and even such abominations as script -q -c "trap '' WINCH; stty rows 24 cols 80; exec nethack" and even tput cols showed 80, but it always breaks when I resize my window.

New contributor
jptrzy is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

1 Answer 1

8

That's script that actively updates the tty size upon receiving the SIGWINCH signal (as sent by the terminal line discipline when the host terminal emulator tells it its new size¹) which in turn causes a SIGWINCH to be delivered to the foreground process group of the slave pty, and nethack in that process group queries that new size upon reception of that signal like full-screen TUI applications typically do.

On the system I try it on, script (from util-linux) installs that handler² on SIGWINCH even when SIGWINCH was ignored on startup, so doing something like (trap '' WINCH && script...) won't work.

You could use something else that doesn't have that feature though such as socat:

socat stdio,raw,echo=0 \
      'system:"stty rows 24 cols 80; exec nethack",pty,setsid,ctty,stderr'

That's doing the same as what script does except for that SIGWINCH handling and the saving of the data into a typescript file (though socat has some options to save the exchanged traffic):

  • puts the host terminal in raw mode with echo disabled
  • forks a process, starts new session (setsid), with new pty, gets control of the slave side there (ctty) and runs a shell in there (which will be the session leader) to interpret that shell code with stdin, stdout and stderr connected to that slave side.
  • then reads from the host terminal (for what you type) and forward to slave via master side while at the same time, read from master (from what the shell and the applications it runs output) and send that to the host terminal for display.

Another option is to run script or your ttyrec in a new session. Then it won't get the SIGWINCH when the host tty is resized since it's no longer controlled by that terminal (so a fortiori not in its foreground process group).

setsid -w ttyrec -e 'stty cols 80 rows 24; exec nethack'

In the ps output, you'll see that ttyrec no longer has a controlling terminal:

$ ps -jp 467606
    PID    PGID     SID TTY          TIME CMD
 467606  467606  467606 ?        00:00:00 ttyrec

Though its stdin/stdout/stderr still go to the host terminal:

$ readlink /proc/467606/fd/[0-2]
/dev/pts/15
/dev/pts/15
/dev/pts/15

¹ Via a TIOCSWINSZ ioctl() on the master side of the pseudo-terminal. That terminal size changing kernel API with those ioctls and the SIGWINCH signal was apparently first added in BSDs in late 1984; I wonder what sort of terminal from the time could be resized. It might have been for the VT220 which came out in late 1983 and could switch between 80 and 132 columns.

² Technically, in current versions at least, not a traditional signal() handler, as it uses a signalfd() instead, which is processed as part of the pty handling event loop, but the effect is the same.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.