Home > other >  Using ncurses with custom pseudoterminal file descriptor
Using ncurses with custom pseudoterminal file descriptor

Time:08-13

I am trying to write a single-process, multi-threaded terminal application (not a multi-process, individually single-threaded terminal application as seems to be far more common). I want it to be single-process so that the different terminal sessions can interact more richly and so that shared libraries are only opened once.

The basic architecture at the moment is that a terminal creates a pseudoterminal in a "master process", with the slave end handled in a main process. (By "master process", I mean this in the sense that it is the master end of the psuedoterminal, and there is one master process per terminal, but it doesn't run any of the logic of the terminal application - this is the (one and only) multithreaded long-lived "main" process).

When a new session "connects", the "master process" sets up the master PTY, and then sends the slave PTY name over a socket to the main process. The master process is then just simply relaying I/O from STDIN/OUT to the PTY master file descriptor. The main process receives the slave name and then opens it, which allows I/O to pass through. If the master process gets a SIGWINCH, it sends the new terminal size over the socket (it can't forward the SIGWINCH using ioctl, since the main process wouldn't know which psuedoterminal it's for).

Basic input and output actually seem to work fine, e.g. if the corresponding slave thread on the main process prints something to the slave fd, it prints out on the actual terminal. However, if I try to use something more complicated like ncurses, funny things start to happen. I think this is because ncurses is setup to use standard input/output by default, and this needs to be overridden, since STDIN/STDOUT of the main process has nothing to do with the user's actual terminal (either nothing at all, if the process is run as a daemon, or just a log console).

I have been trying to use the setupterm function as discussed here: https://web.cs.wpi.edu/~claypool/courses/525-S01/projects/proj3/ncurses-intro.html

This routine is called to initialize a terminal's description, without setting up the curses screen structures or changing the tty-driver mode bits. term is the character string representing the name of the terminal being used. filenum is the UNIX file descriptor of the terminal to be used for output.

However, when I actually use this in my program, it doesn't seem to have any effect. As soon as I try to set up a menu, the program behaves as if it should be interacting with its STDIN/STDOUT, as opposed to the PTY slave file descriptor, which is the only fd it should be using for I/O. Really, that's the only way that multiple PTYs could be handled in a multi-threaded program anyways.

setupterm("vt100", fd, &errret);
initscr();
start_color();
/* etc... */

errret is 1 per the man page, so setupterm isn't encountering any errors.

Here, fd refers to the file descriptor corresponding to the slave end of the PTY.

Despite the description, all my debug logs show that ncurses is trying to use STDIN/STDOUT of the main process, rather than the PTY fd that I told it to use. I haven't found any other ncurses functions to set the fd used. How can I get ncurses to communicate with my pseudoterminal instead of STDIN/STDOUT?

CodePudding user response:

It's not so much that ncurses uses stdin and stdout by default. Rather, the call initscr initializes the input and output devices to stdin and stdout, respectively.

If you want to use different devices, initialise with newterm instead of initscr. The prototype is:

SCREEN *newterm(char *type, FILE *outfd, FILE *infd);

type is the name of the terminal type; if you pass NULL, newstr will try to use the current value of the environment variable TERM (which is what initscr uses). Since it expects FILE* rather than unix file descriptors, you'll need to use fdopen to construct stdio FILE objects. (See man initscr for more details.)

  • Related