tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

shipping processes between ttys



Somebody mentioned reptyr (https://github.com/nelhage/reptyr) in chat
tonight, and so I was thinking about how one might do it properly;
this is a topic I've looked at in the past from time to time, so I
think I have a viable plan for it. Which I'm going to post, both for
feedback and in the hope that I can trick someone into implementing it
for me. :-)

(1) It seems clear that the unit of transfer should be a whole process
group (or "job"); if you want to move your mailreader, it makes sense
for the editor it spawned to go with it, and so on.

(2) It also seems desirable as part of the same machinery to be able
to reconnect to jobs that have been lost because of a disconnect. For
that and some technical reasons I think moving a job should have two
parts: first detaching it from one tty and then attaching it to
another. It follows from Occam's razor that a job that's been detached
but not yet reattached should be in the same state as a background job
that's been hung up on; formally, an orphaned process group.

(3) Therefore, there are two actions. At the shell level, this should
look something like

   % detach %1
   [1]    Detached (pid 12345)         mutt
   % jobs
   % 

and

   % attach 12345
   [1]  + Suspended                    mutt
   % 

(4) At the syscall level, we add two ioctls: TIOCDETACH and
TIOCATTACH. Both are called on one's controlling tty and take a
process group id as the argument.

TIOCDETACH does the following:
   - checks that the target process group is in the session of the
     TIOCDETACH caller;
   - for any process in the process group whose parent pid is outside
     the process group, sets the parent pid to 1;
   - creates a new session with no session leader;
   - moves the process group into the new session and out of its old
     session;
   - for every process in the process group, goes through the
     process's file table and collects a list of the unique open files
     connected to the old session's controlling tty;
   - for each of these clones the open file, except connects the open
     file to a dummy tty device established for the purpose;
   - goes through the process file tables again and replaces the old
     open files with the corresponding new ones;
   - sends SIGCONT to the process group.

TIOCATTACH does the following:
   - checks that the caller is a session leader (maybe not necessary);
   - checks that the target process group is in a session with no
     session leader;
   - checks that either the caller has euid 0, or at least one of the
     uids of every process in the process group matches the caller's
     euid (*);
   - for any process in the process group whose parent pid is 1,
     changes it to the caller's pid;
   - moves the target process group into the caller's session;
   - disposes of the target process group's old session if it's now
     empty;
   - for every process in the process group, goes through the
     process's file table and for every open file attached to the
     dummy tty device, reconnects it to the new session's controlling
     tty instead;
   - sends SIGTSTP to the process group.

(*) This security check is sufficient but not necessary; it e.g.
prohibits moving sessions that contain su instances. It would probably
be better to attach credentials to process groups and check those
instead; but that's a bigger departure from standard behavior and
should probably be done separately. (But until then, it's probably a
good idea to disallow detaching process groups that can't be
reattached.)

Also, we'll change the hangup-time behavior so it also does the dummy
tty device step, so orphaned process groups that have been hung up on
are the same as process groups that have been explicitly detached.
(Another way to do this is to keep the same hangup behavior we have
now and have TIOCDETACH mimic it; however, then it becomes harder to
identify which open files need to be reconnected to the new tty at
attach time.)

The dummy tty device is basically a copy of /dev/null that accepts tty
ioctls.

To implement detach, the shell calls TIOCDETACH and forgets about the
job it detached. To implement attach, the shell calls TIOCATTACH and
adds the necessary goop to its own data structures so that it doesn't
get confused when that job starts reporting status to it.

It might be necessary for TIOCATTACH to provide a list of pids
attached, or at least pids attached that have been reparented to the
caller, in order for shells to be able to do this properly. Or maybe
provide a separate call to get this information.

It should not be necessary to touch wait(), which is good because that
code in netbsd is a maze.

Have I forgotten anything necessary to make this work? (At least from
at semantic level; I'm sure there are a pile of implementation
issues.)

-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index