dev_t is *not* necessarily the same as 'unsigned int', and pretending it is breaks on ARM.
[firstname.lastname@example.org: Change error handling slightly]
Instead of using readlink, stat() the child's file descriptors and compare the result to the device in /proc/$pid/stat and /dev/tty. This lets us properly attach a 'less' that is taking input from a pipe.
The explicit CONT on attach is needed in order for wait() to work on older kernels, and the STOP/CONT after attach is better at making bash notice the process is running again.
i386 has an mmap(), but mmap2() is the one we want with the right calling convention.
This causes bash to notice that the process is backgrounded, which prevents it from sending a SIGTERM when the original shell exits.
If the target /doesn't/ properly initialize the terminal after a SIGTSTP/continue (I'm looking at you, emacs), we need to be sure to grab the terminal state before we suspend it and the shell resets the terminal to cooked mode.
waitid() seems to return EINVAL sometimes, for reasons I don't understand.
This should both cause the target process to redraw / reinitialize the terminal (since it thinks it's been backgrounded and restarted), and should give you back the old terminal, since it sees the process now running in the "background".
These are actually easier -- we just need to TIOCNOTTY, instead of playing games with a dummy child and setsid.
sizeof(sigset_t) is something ludicrous like 0x80 in userspace. Just hard-code it at 8, since all the userspace definitions seem to be lies.
We were letting the child return from fork() and run to the next syscall. This happened to work on my system with 'less', but segfaulted on mutt. Instead, we need to reset the child to before the syscall point, so that none of its code is ever run.