Python 3.8 adds a shiny new toy - a binding to posix_spawn(). I figured I'd try it as a more robust way of creating a child process attached to a terminal. While I happened to use Python, this is really about NetBSD (and even apply to other code bases such as GLIBC). Forgive my pseudo Python/C ...
I'm trying to mimic something like: pty, tty = openpty() pid = fork() if pid is child: close stray fd's by magic, or set them CLOEXEC login_tty(tty) as in: setsid() ioctl(tty, TIOCSCTTY, NULL) redirect stdin, stdout, stderr, to tty and close tty exec ... close tty In a program that has lots of threads and forks .... The first problem I hit was with openpty(3) and "close stray fd's by magic, or set them CLOEXEC": openpty() returns descriptors that aren't CLOEXEC. This means that, even if my program was somehow 100% perfect and opened everything CLOEXEC (Python seems to be trying to do this), I still need some sort of "close stray FD's magic" so that a parallel fork() doesn't inherit the pty/tty. The magic I used was to wrap the openpty() call in a lock and then force CLOEXEC on the FDs ..... Is there, or should there be, something better? The remaining problems are with emulating login_tty(): - posix_spawn() does setpgid(), not setsid(); at least not officially Apparently setsid() both creates a new Session ID and then sets the process group; while setpgid() only sets the process group. Since setsid() has been "the new and preferred method for programs to lose their controlling terminal" (tty(4)TIOCNOTTY) since the early 90's and GLIBC does support it I filed a bug suggesting it be added. - posix_spawn() doesn't do ioctl(tty, TIOCSCTTY, NULL) at all Per above, setsid() looses the old controlling terminal, and then this call makes tty the new one. But is this really needed, i.e., if it is missing what breaks? I'm guessing that sub-shells trying to do job control would fail, but since I'm not doing that I'm not going to see problems .... Should this be added as an extension to posix_spawn() as well? Andrew