]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/pty-session.c
2 * This is pseudo-terminal container for child process where parent creates a
3 * proxy between the current std{in,out,etrr} and the child's pty. Advantages:
5 * - child has no access to parent's terminal (e.g. su --pty)
6 * - parent can log all traffic between user and child's terminal (e.g. script(1))
7 * - it's possible to start commands on terminal although parent has no terminal
9 * This code is in the public domain; do with it what you wish.
11 * Written by Karel Zak <kzak@redhat.com> in Jul 2019
17 #include <sys/signalfd.h>
19 #include <sys/types.h>
26 #include "pty-session.h"
27 #include "monotonic.h"
30 static UL_DEBUG_DEFINE_MASK(ulpty
);
31 UL_DEBUG_DEFINE_MASKNAMES(ulpty
) = UL_DEBUG_EMPTY_MASKNAMES
;
33 #define ULPTY_DEBUG_INIT (1 << 1)
34 #define ULPTY_DEBUG_SETUP (1 << 2)
35 #define ULPTY_DEBUG_SIG (1 << 3)
36 #define ULPTY_DEBUG_IO (1 << 4)
37 #define ULPTY_DEBUG_DONE (1 << 5)
38 #define ULPTY_DEBUG_ALL 0xFFFF
40 #define DBG(m, x) __UL_DBG(ulpty, ULPTY_DEBUG_, m, x)
41 #define ON_DBG(m, x) __UL_DBG_CALL(ulpty, ULPTY_DEBUG_, m, x)
43 #define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpty)
46 void ul_pty_init_debug(int mask
)
50 __UL_INIT_DEBUG_FROM_ENV(ulpty
, ULPTY_DEBUG_
, mask
, ULPTY_DEBUG
);
53 struct ul_pty
*ul_new_pty(int is_stdin_tty
)
55 struct ul_pty
*pty
= calloc(1, sizeof(*pty
));
60 DBG(SETUP
, ul_debugobj(pty
, "alloc handler"));
61 pty
->isterm
= is_stdin_tty
;
65 pty
->child
= (pid_t
) -1;
70 void ul_free_pty(struct ul_pty
*pty
)
72 struct ul_pty_child_buffer
*hd
;
74 while ((hd
= pty
->child_buffer_head
)) {
75 pty
->child_buffer_head
= hd
->next
;
79 while ((hd
= pty
->free_buffers
)) {
80 pty
->free_buffers
= hd
->next
;
86 void ul_pty_slave_echo(struct ul_pty
*pty
, int enable
)
89 pty
->slave_echo
= enable
? 1 : 0;
92 int ul_pty_get_delivered_signal(struct ul_pty
*pty
)
95 return pty
->delivered_signal
;
98 struct ul_pty_callbacks
*ul_pty_get_callbacks(struct ul_pty
*pty
)
101 return &pty
->callbacks
;
104 void ul_pty_set_callback_data(struct ul_pty
*pty
, void *data
)
107 pty
->callback_data
= data
;
110 void ul_pty_set_child(struct ul_pty
*pty
, pid_t child
)
116 int ul_pty_get_childfd(struct ul_pty
*pty
)
122 pid_t
ul_pty_get_child(struct ul_pty
*pty
)
128 /* it's active when signals are redirected to sigfd */
129 int ul_pty_is_running(struct ul_pty
*pty
)
132 return pty
->sigfd
>= 0;
135 void ul_pty_set_mainloop_time(struct ul_pty
*pty
, struct timeval
*tv
)
139 DBG(IO
, ul_debugobj(pty
, "mainloop time: clear"));
140 timerclear(&pty
->next_callback_time
);
142 pty
->next_callback_time
.tv_sec
= tv
->tv_sec
;
143 pty
->next_callback_time
.tv_usec
= tv
->tv_usec
;
144 DBG(IO
, ul_debugobj(pty
, "mainloop time: %"PRId64
".%06"PRId64
,
145 (int64_t) tv
->tv_sec
, (int64_t) tv
->tv_usec
));
149 static void pty_signals_cleanup(struct ul_pty
*pty
)
151 if (pty
->sigfd
!= -1)
155 /* restore original setting */
156 sigprocmask(SIG_SETMASK
, &pty
->orgsig
, NULL
);
159 /* call me before fork() */
160 int ul_pty_setup(struct ul_pty
*pty
)
162 struct termios attrs
;
165 assert(pty
->sigfd
== -1);
167 /* save the current signals setting (to make ul_pty_cleanup() usable,
168 * otherwise see ul_pty_signals_setup() */
169 sigprocmask(0, NULL
, &pty
->orgsig
);
172 DBG(SETUP
, ul_debugobj(pty
, "create for terminal"));
174 /* original setting of the current terminal */
175 if (tcgetattr(STDIN_FILENO
, &pty
->stdin_attrs
) != 0) {
180 attrs
= pty
->stdin_attrs
;
182 attrs
.c_lflag
|= ECHO
;
184 attrs
.c_lflag
&= ~ECHO
;
186 ioctl(STDIN_FILENO
, TIOCGWINSZ
, (char *)&pty
->win
);
187 /* create master+slave */
188 rc
= openpty(&pty
->master
, &pty
->slave
, NULL
, &attrs
, &pty
->win
);
192 /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */
194 tcsetattr(STDIN_FILENO
, TCSANOW
, &attrs
);
196 DBG(SETUP
, ul_debugobj(pty
, "create for non-terminal"));
198 rc
= openpty(&pty
->master
, &pty
->slave
, NULL
, NULL
, NULL
);
202 tcgetattr(pty
->slave
, &attrs
);
205 attrs
.c_lflag
|= ECHO
;
207 attrs
.c_lflag
&= ~ECHO
;
209 tcsetattr(pty
->slave
, TCSANOW
, &attrs
);
212 fcntl(pty
->master
, F_SETFL
, O_NONBLOCK
);
218 DBG(SETUP
, ul_debugobj(pty
, "pty setup done [master=%d, slave=%d, rc=%d]",
219 pty
->master
, pty
->slave
, rc
));
223 /* call me before fork() */
224 int ul_pty_signals_setup(struct ul_pty
*pty
)
229 assert(pty
->sigfd
== -1);
231 /* save the current signals setting */
232 sigprocmask(0, NULL
, &pty
->orgsig
);
235 if (sigprocmask(SIG_BLOCK
, &ourset
, NULL
)) {
240 sigemptyset(&ourset
);
241 sigaddset(&ourset
, SIGCHLD
);
242 sigaddset(&ourset
, SIGWINCH
);
243 sigaddset(&ourset
, SIGALRM
);
244 sigaddset(&ourset
, SIGTERM
);
245 sigaddset(&ourset
, SIGINT
);
246 sigaddset(&ourset
, SIGQUIT
);
248 if (pty
->callbacks
.flush_logs
)
249 sigaddset(&ourset
, SIGUSR1
);
251 if ((pty
->sigfd
= signalfd(-1, &ourset
, SFD_CLOEXEC
)) < 0)
257 DBG(SETUP
, ul_debugobj(pty
, "pty signals setup done [rc=%d]", rc
));
261 /* cleanup in parent process */
262 void ul_pty_cleanup(struct ul_pty
*pty
)
266 pty_signals_cleanup(pty
);
268 if (pty
->master
== -1 || !pty
->isterm
)
271 DBG(DONE
, ul_debugobj(pty
, "cleanup"));
272 rtt
= pty
->stdin_attrs
;
273 tcsetattr(STDIN_FILENO
, TCSADRAIN
, &rtt
);
276 int ul_pty_chownmod_slave(struct ul_pty
*pty
, uid_t uid
, gid_t gid
, mode_t mode
)
278 if (fchown(pty
->slave
, uid
, gid
))
280 if (fchmod(pty
->slave
, mode
))
285 /* call me in child process */
286 void ul_pty_init_slave(struct ul_pty
*pty
)
288 DBG(SETUP
, ul_debugobj(pty
, "initialize slave"));
292 ioctl(pty
->slave
, TIOCSCTTY
, 1);
295 dup2(pty
->slave
, STDIN_FILENO
);
296 dup2(pty
->slave
, STDOUT_FILENO
);
297 dup2(pty
->slave
, STDERR_FILENO
);
308 sigprocmask(SIG_SETMASK
, &pty
->orgsig
, NULL
);
310 DBG(SETUP
, ul_debugobj(pty
, "... initialize slave done"));
313 static int write_output(char *obuf
, ssize_t bytes
)
315 DBG(IO
, ul_debug(" writing output"));
317 if (write_all(STDOUT_FILENO
, obuf
, bytes
)) {
318 DBG(IO
, ul_debug(" writing output *failed*"));
325 static int schedule_child_write(struct ul_pty
*pty
, char *buf
, size_t bufsz
, int final
)
327 struct ul_pty_child_buffer
*stash
;
329 if (pty
->free_buffers
) {
330 stash
= pty
->free_buffers
;
331 pty
->free_buffers
= stash
->next
;
332 memset(stash
, 0, sizeof(*stash
));
334 stash
= calloc(1, sizeof(*stash
));
338 assert(bufsz
<= sizeof(stash
->buf
));
340 memcpy(stash
->buf
, buf
, bufsz
);
342 stash
->final_input
= final
? 1 : 0;
344 if (pty
->child_buffer_head
)
345 pty
->child_buffer_tail
= pty
->child_buffer_tail
->next
= stash
;
347 pty
->child_buffer_head
= pty
->child_buffer_tail
= stash
;
352 * The pty is usually faster than shell, so it's a good idea to wait until
353 * the previous message has been already read by shell from slave before we
354 * write to master. This is necessary especially for EOF situation when we can
355 * send EOF to master before shell is fully initialized, to workaround this
356 * problem we wait until slave is empty. For example:
358 * echo "date" | su --pty
360 * Unfortunately, the child (usually shell) can ignore stdin at all, so we
361 * don't wait forever to avoid dead locks...
363 * Note that su --pty is primarily designed for interactive sessions as it
364 * maintains master+slave tty stuff within the session. Use pipe to write to
365 * pty and assume non-interactive (tee-like) behavior is NOT well supported.
367 static void drain_child_buffers(struct ul_pty
*pty
)
369 unsigned int tries
= 0;
370 struct pollfd fd
= { .fd
= pty
->slave
, .events
= POLLIN
};
372 DBG(IO
, ul_debugobj(pty
, " waiting for empty slave"));
373 while (poll(&fd
, 1, 10) == 1 && tries
< 8) {
374 DBG(IO
, ul_debugobj(pty
, " slave is not empty"));
379 DBG(IO
, ul_debugobj(pty
, " slave is empty now"));
381 DBG(IO
, ul_debugobj(pty
, " sending EOF to master"));
384 static int flush_child_buffers(struct ul_pty
*pty
, int *anything
)
388 while (pty
->child_buffer_head
) {
389 struct ul_pty_child_buffer
*hd
= pty
->child_buffer_head
;
393 drain_child_buffers(pty
);
395 DBG(IO
, ul_debugobj(hd
, " stdin --> master trying %zu bytes", hd
->size
- hd
->cursor
));
397 ret
= write(pty
->master
, hd
->buf
+ hd
->cursor
, hd
->size
- hd
->cursor
);
399 DBG(IO
, ul_debugobj(hd
, " EAGAIN"));
400 if (!(errno
== EINTR
|| errno
== EAGAIN
))
404 DBG(IO
, ul_debugobj(hd
, " wrote %zd", ret
));
408 if (hd
->cursor
== hd
->size
) {
409 pty
->child_buffer_head
= hd
->next
;
411 pty
->child_buffer_tail
= NULL
;
413 hd
->next
= pty
->free_buffers
;
414 pty
->free_buffers
= hd
;
418 /* without sync write_output() will write both input &
419 * shell output that looks like double echoing */
421 fdatasync(pty
->master
);
428 void ul_pty_write_eof_to_child(struct ul_pty
*pty
)
431 schedule_child_write(pty
, &c
, sizeof(char), 1);
434 static int mainloop_callback(struct ul_pty
*pty
)
438 if (!pty
->callbacks
.mainloop
)
441 DBG(IO
, ul_debugobj(pty
, "calling mainloop callback"));
442 rc
= pty
->callbacks
.mainloop(pty
->callback_data
);
444 DBG(IO
, ul_debugobj(pty
, " callback done [rc=%d]", rc
));
448 static int handle_io(struct ul_pty
*pty
, int fd
, int *eof
)
455 DBG(IO
, ul_debugobj(pty
, " handle I/O on fd=%d", fd
));
459 sigaddset(&set
, SIGTTIN
);
460 sigprocmask(SIG_UNBLOCK
, &set
, NULL
);
461 /* read from active FD */
462 bytes
= read(fd
, buf
, sizeof(buf
));
463 sigprocmask(SIG_BLOCK
, &set
, NULL
);
465 if (errno
== EAGAIN
|| errno
== EINTR
)
475 /* from stdin (user) to command */
476 if (fd
== STDIN_FILENO
) {
477 DBG(IO
, ul_debugobj(pty
, " stdin --> master %zd bytes queued", bytes
));
479 if (schedule_child_write(pty
, buf
, bytes
, 0))
482 /* from command (master) to stdout */
483 } else if (fd
== pty
->master
) {
484 DBG(IO
, ul_debugobj(pty
, " master --> stdout %zd bytes", bytes
));
485 write_output(buf
, bytes
);
488 if (pty
->callbacks
.log_stream_activity
)
489 rc
= pty
->callbacks
.log_stream_activity(
490 pty
->callback_data
, fd
, buf
, bytes
);
495 void ul_pty_wait_for_child(struct ul_pty
*pty
)
501 if (pty
->child
== (pid_t
) -1)
504 DBG(SIG
, ul_debug("waiting for child [child=%d]", (int) pty
->child
));
506 if (ul_pty_is_running(pty
)) {
507 /* wait for specific child */
510 pid
= waitpid(pty
->child
, &status
, options
);
511 DBG(SIG
, ul_debug(" waitpid done [rc=%d]", (int) pid
));
512 if (pid
!= (pid_t
) - 1) {
513 if (pty
->callbacks
.child_die
)
514 pty
->callbacks
.child_die(
517 ul_pty_set_child(pty
, (pid_t
) -1);
523 while ((pid
= waitpid(-1, &status
, options
)) > 0) {
524 DBG(SIG
, ul_debug(" waitpid done [rc=%d]", (int) pid
));
525 if (pid
== pty
->child
) {
526 if (pty
->callbacks
.child_die
)
527 pty
->callbacks
.child_die(
530 ul_pty_set_child(pty
, (pid_t
) -1);
536 static int handle_signal(struct ul_pty
*pty
, int fd
)
538 struct signalfd_siginfo info
;
542 DBG(SIG
, ul_debugobj(pty
, " handle signal on fd=%d", fd
));
544 bytes
= read(fd
, &info
, sizeof(info
));
545 if (bytes
!= sizeof(info
)) {
546 if (bytes
< 0 && (errno
== EAGAIN
|| errno
== EINTR
))
551 switch (info
.ssi_signo
) {
553 DBG(SIG
, ul_debugobj(pty
, " get signal SIGCHLD"));
555 if (info
.ssi_code
== CLD_EXITED
556 || info
.ssi_code
== CLD_KILLED
557 || info
.ssi_code
== CLD_DUMPED
) {
559 if (pty
->callbacks
.child_wait
)
560 pty
->callbacks
.child_wait(pty
->callback_data
,
563 ul_pty_wait_for_child(pty
);
565 } else if (info
.ssi_status
== SIGSTOP
&& pty
->child
> 0) {
566 pty
->callbacks
.child_sigstop(pty
->callback_data
,
570 if (pty
->child
<= 0) {
571 DBG(SIG
, ul_debugobj(pty
, " no child, setting leaving timeout"));
572 pty
->poll_timeout
= 10;
573 timerclear(&pty
->next_callback_time
);
577 DBG(SIG
, ul_debugobj(pty
, " get signal SIGWINCH"));
579 ioctl(STDIN_FILENO
, TIOCGWINSZ
, (char *)&pty
->win
);
580 ioctl(pty
->slave
, TIOCSWINSZ
, (char *)&pty
->win
);
582 if (pty
->callbacks
.log_signal
)
583 rc
= pty
->callbacks
.log_signal(pty
->callback_data
,
584 &info
, (void *) &pty
->win
);
592 DBG(SIG
, ul_debugobj(pty
, " get signal SIG{TERM,INT,QUIT}"));
593 pty
->delivered_signal
= info
.ssi_signo
;
594 /* Child termination is going to generate SIGCHLD (see above) */
596 kill(pty
->child
, SIGTERM
);
598 if (pty
->callbacks
.log_signal
)
599 rc
= pty
->callbacks
.log_signal(pty
->callback_data
,
600 &info
, (void *) &pty
->win
);
603 DBG(SIG
, ul_debugobj(pty
, " get signal SIGUSR1"));
604 if (pty
->callbacks
.flush_logs
)
605 rc
= pty
->callbacks
.flush_logs(pty
->callback_data
);
615 int ul_pty_proxy_master(struct ul_pty
*pty
)
617 int rc
= 0, ret
, eof
= 0;
624 struct pollfd pfd
[] = {
625 [POLLFD_SIGNAL
] = { .fd
= -1, .events
= POLLIN
| POLLERR
| POLLHUP
},
626 [POLLFD_MASTER
] = { .fd
= pty
->master
, .events
= POLLIN
| POLLERR
| POLLHUP
},
627 [POLLFD_STDIN
] = { .fd
= STDIN_FILENO
, .events
= POLLIN
| POLLERR
| POLLHUP
}
630 /* We use signalfd, and standard signals by handlers are completely blocked */
631 assert(pty
->sigfd
>= 0);
633 pfd
[POLLFD_SIGNAL
].fd
= pty
->sigfd
;
634 pty
->poll_timeout
= -1;
636 while (!pty
->delivered_signal
) {
640 DBG(IO
, ul_debugobj(pty
, "--poll() loop--"));
642 /* note, callback usually updates @next_callback_time */
643 if (timerisset(&pty
->next_callback_time
)) {
646 DBG(IO
, ul_debugobj(pty
, " callback requested"));
647 gettime_monotonic(&now
);
648 if (timercmp(&now
, &pty
->next_callback_time
, >)) {
649 rc
= mainloop_callback(pty
);
656 if (timerisset(&pty
->next_callback_time
)) {
657 struct timeval now
, rest
;
659 gettime_monotonic(&now
);
660 timersub(&pty
->next_callback_time
, &now
, &rest
);
661 timeout
= (rest
.tv_sec
* 1000) + (rest
.tv_usec
/ 1000);
663 timeout
= pty
->poll_timeout
;
665 /* use POLLOUT (aka "writing is now possible") if data queued */
666 if (pty
->child_buffer_head
)
667 pfd
[POLLFD_MASTER
].events
|= POLLOUT
;
669 pfd
[POLLFD_MASTER
].events
&= ~POLLOUT
;
671 /* wait for input, signal or timeout */
672 DBG(IO
, ul_debugobj(pty
, "calling poll() [timeout=%dms]", timeout
));
673 ret
= poll(pfd
, ARRAY_SIZE(pfd
), timeout
);
676 DBG(IO
, ul_debugobj(pty
, "poll() rc=%d", ret
));
688 if (timerisset(&pty
->next_callback_time
)) {
689 rc
= mainloop_callback(pty
);
696 DBG(IO
, ul_debugobj(pty
, "leaving poll() loop [timeout=%d, rc=%d]", timeout
, rc
));
700 for (i
= 0; i
< ARRAY_SIZE(pfd
); i
++) {
701 if (pfd
[i
].revents
== 0)
704 DBG(IO
, ul_debugobj(pty
, " active pfd[%s].fd=%d %s %s %s %s %s",
705 i
== POLLFD_STDIN
? "stdin" :
706 i
== POLLFD_MASTER
? "master" :
707 i
== POLLFD_SIGNAL
? "signal" : "???",
709 pfd
[i
].revents
& POLLIN
? "POLLIN" : "",
710 pfd
[i
].revents
& POLLOUT
? "POLLOUT" : "",
711 pfd
[i
].revents
& POLLHUP
? "POLLHUP" : "",
712 pfd
[i
].revents
& POLLERR
? "POLLERR" : "",
713 pfd
[i
].revents
& POLLNVAL
? "POLLNVAL" : ""));
715 if (i
== POLLFD_SIGNAL
)
716 rc
= handle_signal(pty
, pfd
[i
].fd
);
718 if (pfd
[i
].revents
& POLLIN
)
719 rc
= handle_io(pty
, pfd
[i
].fd
, &eof
); /* data */
720 if (pfd
[i
].revents
& POLLOUT
) /* i == POLLFD_MASTER */
721 rc
= flush_child_buffers(pty
, NULL
);
727 ul_pty_write_eof_to_child(pty
);
728 for (anything
= 1; anything
;)
729 flush_child_buffers(pty
, &anything
);
733 if (i
== POLLFD_SIGNAL
)
736 /* EOF maybe detected in two ways; they are as follows:
737 * A) poll() return POLLHUP event after close()
738 * B) read() returns 0 (no data)
740 * POLLNVAL means that fd is closed.
742 if ((pfd
[i
].revents
& POLLHUP
) || (pfd
[i
].revents
& POLLNVAL
) || eof
) {
743 DBG(IO
, ul_debugobj(pty
, " ignore FD"));
744 if (i
== POLLFD_STDIN
) {
746 ul_pty_write_eof_to_child(pty
);
747 } else /* i == POLLFD_MASTER */
748 pfd
[i
].revents
&= ~POLLIN
;
755 if (rc
&& pty
->child
&& pty
->child
!= (pid_t
) -1 && !pty
->delivered_signal
) {
756 kill(pty
->child
, SIGTERM
);
758 kill(pty
->child
, SIGKILL
);
761 pty_signals_cleanup(pty
);
763 DBG(IO
, ul_debug("poll() done [signal=%d, rc=%d]", pty
->delivered_signal
, rc
));
767 #ifdef TEST_PROGRAM_PTY
772 * ... and see for example tty(1) or "ps afu"
774 static void child_sigstop(void *data
__attribute__((__unused__
)), pid_t child
)
776 kill(getpid(), SIGSTOP
);
777 kill(child
, SIGCONT
);
780 int main(int argc
, char *argv
[])
782 struct ul_pty_callbacks
*cb
;
783 const char *shell
, *command
= NULL
, *shname
= NULL
;
784 int caught_signal
= 0;
788 shell
= getenv("SHELL");
790 shell
= _PATH_BSHELL
;
794 ul_pty_init_debug(0);
796 pty
= ul_new_pty(isatty(STDIN_FILENO
));
798 err(EXIT_FAILURE
, "failed to allocate PTY handler");
800 cb
= ul_pty_get_callbacks(pty
);
801 cb
->child_sigstop
= child_sigstop
;
803 if (ul_pty_setup(pty
))
804 err(EXIT_FAILURE
, "failed to create pseudo-terminal");
805 if (ul_pty_signals_setup(pty
))
806 err(EXIT_FAILURE
, "failed to initialize signals handler");
808 fflush(stdout
); /* ??? */
810 switch ((int) (child
= fork())) {
813 err(EXIT_FAILURE
, "cannot create child process");
817 ul_pty_init_slave(pty
);
819 signal(SIGTERM
, SIG_DFL
); /* because /etc/csh.login */
821 shname
= strrchr(shell
, '/');
822 shname
= shname
? shname
+ 1 : shell
;
825 execl(shell
, shname
, "-c", command
, (char *)NULL
);
827 execl(shell
, shname
, "-i", (char *)NULL
);
828 err(EXIT_FAILURE
, "failed to execute %s", shell
);
836 ul_pty_set_child(pty
, child
);
838 /* this is the main loop */
839 ul_pty_proxy_master(pty
);
841 /* all done; cleanup and kill */
842 caught_signal
= ul_pty_get_delivered_signal(pty
);
844 if (!caught_signal
&& ul_pty_get_child(pty
) != (pid_t
)-1)
845 ul_pty_wait_for_child(pty
); /* final wait */
847 if (caught_signal
&& ul_pty_get_child(pty
) != (pid_t
)-1) {
848 fprintf(stderr
, "\nSession terminated, killing shell...");
849 kill(child
, SIGTERM
);
851 kill(child
, SIGKILL
);
852 fprintf(stderr
, " ...killed.\n");
860 #endif /* TEST_PROGRAM */