It seems that a simple shell redirect from /dev/ptmx
gets me a new pseudo-terminal.
$ ls /dev/pts; ls /dev/pts </dev/ptmx
0 1 2 ptmx
0 1 2 3 ptmx
It disappears as soon as the process that owns the fd claim on /dev/ptmx
quits, but it is simple enough to retain it:
$ PS1='<$(ls -1 "$@" /dev/pts/*|uniq -u)> $ ' \
exec 3<>/dev/ptmx "$0" -si -- /dev/pts/*
</dev/pts/3> $ ls /dev/pts; exec 3>&-
0 1 2 3 ptmx
<> $ ls /dev/pts; exec 3<>/dev/ptmx
0 1 2 ptmx
</dev/pts/3> $ exit
So it looks like the simple open()
on /dev/ptmx
is enough to get a pseudo-terminal. I guess that would make the shell – (or the process for which it does the redirect) – the owner of the master side of the pty.
But how do I assign the slave side – or can I assign the slave side? And if I can – what can I do with it? Can I affect its read/write/flush timings w/ stty
? Will a slave side process link through to my new pty when referencing /dev/tty
?
Best Answer
So, as @muru points out in the comments, there doesn't seem to be a simple way to interface the pty created for you with just the shell. I managed all of it but the
unlockpt()
part. According to something I read here it may be there are some compile-time options in the kernel for disabling newly created pty locking, but I didn't want to do that. So, I did something else.I didn't need
grantpt()
actually. According to the description found here all it does is change the UID/GID for/dev/pts/[num]
device file. But according toman mount
there are easier ways to handle that. Here are somedevpts
mount options:uid=value
andgid=value
gid=5
will cause newly created PTYs to belong to the tty group.That was already the case on my system by default. But after reading that I realized I might want to make a change after all. The very next section reads:
ptmxmode=value
devpts
filesystem.devpts
(seenewinstance
option above), each instance has a private ptmx node in the root of thedevpts
filesystem (typically/dev/pts/ptmx
).0000
.ptmxmode=value
specifies a more useful mode for the ptmx node and is highly recommended when thenewinstance
option is specified.While it would have worked without doing so, I liked the idea and set that to
0640
as recommended in the kernel documentation. The kernel doc link, by the way, elaborates on thenewinstance
mount option - which is pretty cool and basically enables you get a separately name-spaced group of ptys per/dev/ptmx
mount.Anyway, so the something else amounted mostly to:
...as the kernel docs recommend - see the link about why. I also made the effect of the above commands permanent by adding a couple of lines to my
/etc/fstab
.And...
Which just compiles a tiny little C program that attempts to call
unlockpt()
on its stdin and if successful prints the name of the newly created and unlocked pty tostdout
or else silently returns 2.Once that was done I could create my own screened processes like:
...to get the master-side fd in the current shell then...
That gets an interactive shell running on the other end of the pseudo-terminal in the background. It will interpret anything printed to
>&3
as user input.Which basically nets me a backgrounded, logged, interactive interpreter (or anything else I might care to run on these) ala
screen
without so much overhead and on any file descriptor I choose.The master-side fd owned by my current shell is the only means of serving the slave-side input and is only writable by my current shell process (and its children). I can communicate with the other end by writing to
>&3
and I can either read from same or from a log file as I wish.And
stty
does work on the terminal after all: