]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/pty-session.c
Merge branch 'timestamp' of https://github.com/t-8ch/util-linux
[thirdparty/util-linux.git] / lib / pty-session.c
CommitLineData
6954895c
KZ
1/*
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:
4 *
5 * - child has no access to parent's terminal (e.g. su --pty)
86139a70 6 * - parent can log all traffic between user and child's terminal (e.g. script(1))
6954895c
KZ
7 * - it's possible to start commands on terminal although parent has no terminal
8 *
9 * This code is in the public domain; do with it what you wish.
10 *
11 * Written by Karel Zak <kzak@redhat.com> in Jul 2019
12 */
13#include <stdio.h>
14#include <stdlib.h>
15#include <pty.h>
16#include <poll.h>
17#include <sys/signalfd.h>
18#include <paths.h>
19#include <sys/types.h>
20#include <sys/wait.h>
f02286fd 21#include <inttypes.h>
6954895c
KZ
22
23#include "c.h"
24#include "all-io.h"
25#include "ttyutils.h"
26#include "pty-session.h"
4d5b2fed 27#include "monotonic.h"
6954895c
KZ
28#include "debug.h"
29
30static UL_DEBUG_DEFINE_MASK(ulpty);
31UL_DEBUG_DEFINE_MASKNAMES(ulpty) = UL_DEBUG_EMPTY_MASKNAMES;
32
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
39
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)
42
43#define UL_DEBUG_CURRENT_MASK UL_DEBUG_MASK(ulpty)
44#include "debugobj.h"
45
46void ul_pty_init_debug(int mask)
47{
48 if (ulpty_debug_mask)
49 return;
50 __UL_INIT_DEBUG_FROM_ENV(ulpty, ULPTY_DEBUG_, mask, ULPTY_DEBUG);
51}
52
53struct ul_pty *ul_new_pty(int is_stdin_tty)
54{
55 struct ul_pty *pty = calloc(1, sizeof(*pty));
56
57 if (!pty)
58 return NULL;
59
60 DBG(SETUP, ul_debugobj(pty, "alloc handler"));
61 pty->isterm = is_stdin_tty;
62 pty->master = -1;
63 pty->slave = -1;
64 pty->sigfd = -1;
65 pty->child = (pid_t) -1;
66
67 return pty;
68}
69
ab61a038 70void ul_free_pty(struct ul_pty *pty)
6954895c 71{
2a6d1768 72 struct ul_pty_child_buffer *hd;
fd5698ff
KZ
73
74 while ((hd = pty->child_buffer_head)) {
2a6d1768 75 pty->child_buffer_head = hd->next;
76 free(hd);
77 }
fd5698ff
KZ
78
79 while ((hd = pty->free_buffers)) {
2a6d1768 80 pty->free_buffers = hd->next;
81 free(hd);
82 }
ab61a038 83 free(pty);
6954895c
KZ
84}
85
1eee1acb 86void ul_pty_slave_echo(struct ul_pty *pty, int enable)
4169bcb7
KZ
87{
88 assert(pty);
1eee1acb 89 pty->slave_echo = enable ? 1 : 0;
4169bcb7 90}
ab61a038 91
6954895c
KZ
92int ul_pty_get_delivered_signal(struct ul_pty *pty)
93{
94 assert(pty);
95 return pty->delivered_signal;
96}
97
98struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty)
99{
100 assert(pty);
101 return &pty->callbacks;
102}
103
104void ul_pty_set_callback_data(struct ul_pty *pty, void *data)
105{
106 assert(pty);
107 pty->callback_data = data;
108}
109
110void ul_pty_set_child(struct ul_pty *pty, pid_t child)
111{
112 assert(pty);
113 pty->child = child;
114}
115
4d5b2fed
KZ
116int ul_pty_get_childfd(struct ul_pty *pty)
117{
118 assert(pty);
119 return pty->master;
120}
121
bdd43357
KZ
122pid_t ul_pty_get_child(struct ul_pty *pty)
123{
124 assert(pty);
125 return pty->child;
126}
127
c556dc59 128/* it's active when signals are redirected to sigfd */
6954895c
KZ
129int ul_pty_is_running(struct ul_pty *pty)
130{
131 assert(pty);
132 return pty->sigfd >= 0;
133}
134
4d5b2fed
KZ
135void ul_pty_set_mainloop_time(struct ul_pty *pty, struct timeval *tv)
136{
137 assert(pty);
138 if (!tv) {
139 DBG(IO, ul_debugobj(pty, "mainloop time: clear"));
140 timerclear(&pty->next_callback_time);
141 } else {
142 pty->next_callback_time.tv_sec = tv->tv_sec;
143 pty->next_callback_time.tv_usec = tv->tv_usec;
f02286fd
KZ
144 DBG(IO, ul_debugobj(pty, "mainloop time: %"PRId64".%06"PRId64,
145 (int64_t) tv->tv_sec, (int64_t) tv->tv_usec));
4d5b2fed
KZ
146 }
147}
148
b1154c4e
KZ
149static void pty_signals_cleanup(struct ul_pty *pty)
150{
151 if (pty->sigfd != -1)
152 close(pty->sigfd);
153 pty->sigfd = -1;
154
155 /* restore original setting */
156 sigprocmask(SIG_SETMASK, &pty->orgsig, NULL);
157}
158
6954895c
KZ
159/* call me before fork() */
160int ul_pty_setup(struct ul_pty *pty)
161{
75ccd75a 162 struct termios attrs;
b1154c4e
KZ
163 int rc = 0;
164
165 assert(pty->sigfd == -1);
6954895c 166
4681d88b
KZ
167 /* save the current signals setting (to make ul_pty_cleanup() usable,
168 * otherwise see ul_pty_signals_setup() */
ab61a038
KZ
169 sigprocmask(0, NULL, &pty->orgsig);
170
6954895c
KZ
171 if (pty->isterm) {
172 DBG(SETUP, ul_debugobj(pty, "create for terminal"));
173
174 /* original setting of the current terminal */
b1154c4e
KZ
175 if (tcgetattr(STDIN_FILENO, &pty->stdin_attrs) != 0) {
176 rc = -errno;
177 goto done;
178 }
75ccd75a
SG
179
180 attrs = pty->stdin_attrs;
181 if (pty->slave_echo)
182 attrs.c_lflag |= ECHO;
183 else
184 attrs.c_lflag &= ~ECHO;
185
6954895c
KZ
186 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win);
187 /* create master+slave */
75ccd75a 188 rc = openpty(&pty->master, &pty->slave, NULL, &attrs, &pty->win);
b1154c4e
KZ
189 if (rc)
190 goto done;
6954895c
KZ
191
192 /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */
75ccd75a
SG
193 cfmakeraw(&attrs);
194 tcsetattr(STDIN_FILENO, TCSANOW, &attrs);
6954895c 195 } else {
2a6d1768 196 DBG(SETUP, ul_debugobj(pty, "create for non-terminal"));
6954895c 197
1eee1acb
KZ
198 rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL);
199 if (rc)
b1154c4e 200 goto done;
1eee1acb 201
75ccd75a 202 tcgetattr(pty->slave, &attrs);
1eee1acb
KZ
203
204 if (pty->slave_echo)
75ccd75a 205 attrs.c_lflag |= ECHO;
1eee1acb 206 else
75ccd75a 207 attrs.c_lflag &= ~ECHO;
1eee1acb 208
75ccd75a 209 tcsetattr(pty->slave, TCSANOW, &attrs);
b1154c4e
KZ
210 }
211
2a6d1768 212 fcntl(pty->master, F_SETFL, O_NONBLOCK);
213
4681d88b
KZ
214done:
215 if (rc)
216 ul_pty_cleanup(pty);
217
218 DBG(SETUP, ul_debugobj(pty, "pty setup done [master=%d, slave=%d, rc=%d]",
219 pty->master, pty->slave, rc));
220 return rc;
221}
222
223/* call me before fork() */
224int ul_pty_signals_setup(struct ul_pty *pty)
225{
226 sigset_t ourset;
227 int rc = 0;
228
229 assert(pty->sigfd == -1);
230
231 /* save the current signals setting */
232 sigprocmask(0, NULL, &pty->orgsig);
233
b1154c4e
KZ
234 sigfillset(&ourset);
235 if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
236 rc = -errno;
237 goto done;
6954895c
KZ
238 }
239
b1154c4e
KZ
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);
247
7727be1a
KZ
248 if (pty->callbacks.flush_logs)
249 sigaddset(&ourset, SIGUSR1);
250
b1154c4e
KZ
251 if ((pty->sigfd = signalfd(-1, &ourset, SFD_CLOEXEC)) < 0)
252 rc = -errno;
253done:
254 if (rc)
255 ul_pty_cleanup(pty);
256
4681d88b 257 DBG(SETUP, ul_debugobj(pty, "pty signals setup done [rc=%d]", rc));
6954895c
KZ
258 return rc;
259}
260
261/* cleanup in parent process */
262void ul_pty_cleanup(struct ul_pty *pty)
263{
264 struct termios rtt;
265
b1154c4e
KZ
266 pty_signals_cleanup(pty);
267
6954895c
KZ
268 if (pty->master == -1 || !pty->isterm)
269 return;
270
271 DBG(DONE, ul_debugobj(pty, "cleanup"));
272 rtt = pty->stdin_attrs;
273 tcsetattr(STDIN_FILENO, TCSADRAIN, &rtt);
274}
275
17d5b264
KZ
276int ul_pty_chownmod_slave(struct ul_pty *pty, uid_t uid, gid_t gid, mode_t mode)
277{
278 if (fchown(pty->slave, uid, gid))
279 return -errno;
280 if (fchmod(pty->slave, mode))
281 return -errno;
282 return 0;
283}
284
6954895c
KZ
285/* call me in child process */
286void ul_pty_init_slave(struct ul_pty *pty)
287{
288 DBG(SETUP, ul_debugobj(pty, "initialize slave"));
289
290 setsid();
291
292 ioctl(pty->slave, TIOCSCTTY, 1);
293 close(pty->master);
294
295 dup2(pty->slave, STDIN_FILENO);
296 dup2(pty->slave, STDOUT_FILENO);
297 dup2(pty->slave, STDERR_FILENO);
298
299 close(pty->slave);
300
301 if (pty->sigfd >= 0)
302 close(pty->sigfd);
303
304 pty->slave = -1;
305 pty->master = -1;
306 pty->sigfd = -1;
307
308 sigprocmask(SIG_SETMASK, &pty->orgsig, NULL);
309
310 DBG(SETUP, ul_debugobj(pty, "... initialize slave done"));
311}
312
313static int write_output(char *obuf, ssize_t bytes)
314{
315 DBG(IO, ul_debug(" writing output"));
316
317 if (write_all(STDOUT_FILENO, obuf, bytes)) {
318 DBG(IO, ul_debug(" writing output *failed*"));
319 return -errno;
320 }
321
322 return 0;
323}
324
2a6d1768 325static int schedule_child_write(struct ul_pty *pty, char *buf, size_t bufsz, int final)
6954895c 326{
2a6d1768 327 struct ul_pty_child_buffer *stash;
fd5698ff 328
2a6d1768 329 if (pty->free_buffers) {
330 stash = pty->free_buffers;
331 pty->free_buffers = stash->next;
332 memset(stash, 0, sizeof(*stash));
333 } else
334 stash = calloc(1, sizeof(*stash));
335 if (!stash)
336 return -1;
337
fd5698ff
KZ
338 assert(bufsz <= sizeof(stash->buf));
339
2a6d1768 340 memcpy(stash->buf, buf, bufsz);
341 stash->size = bufsz;
342 stash->final_input = final ? 1 : 0;
343
344 if (pty->child_buffer_head)
345 pty->child_buffer_tail = pty->child_buffer_tail->next = stash;
346 else
347 pty->child_buffer_head = pty->child_buffer_tail = stash;
348 return 0;
6954895c
KZ
349}
350
351/*
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:
357 *
358 * echo "date" | su --pty
359 *
360 * Unfortunately, the child (usually shell) can ignore stdin at all, so we
361 * don't wait forever to avoid dead locks...
362 *
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.
366 */
2a6d1768 367static void drain_child_buffers(struct ul_pty *pty)
6954895c
KZ
368{
369 unsigned int tries = 0;
2a6d1768 370 struct pollfd fd = { .fd = pty->slave, .events = POLLIN };
6954895c
KZ
371
372 DBG(IO, ul_debugobj(pty, " waiting for empty slave"));
2a6d1768 373 while (poll(&fd, 1, 10) == 1 && tries < 8) {
6954895c
KZ
374 DBG(IO, ul_debugobj(pty, " slave is not empty"));
375 xusleep(250000);
376 tries++;
377 }
378 if (tries < 8)
379 DBG(IO, ul_debugobj(pty, " slave is empty now"));
380
381 DBG(IO, ul_debugobj(pty, " sending EOF to master"));
2a6d1768 382}
383
384static int flush_child_buffers(struct ul_pty *pty, int *anything)
385{
fd5698ff
KZ
386 int rc = 0, any = 0;
387
2a6d1768 388 while (pty->child_buffer_head) {
389 struct ul_pty_child_buffer *hd = pty->child_buffer_head;
fd5698ff 390 ssize_t ret;
2a6d1768 391
fd5698ff 392 if (hd->final_input)
2a6d1768 393 drain_child_buffers(pty);
394
395 DBG(IO, ul_debugobj(hd, " stdin --> master trying %zu bytes", hd->size - hd->cursor));
fd5698ff
KZ
396
397 ret = write(pty->master, hd->buf + hd->cursor, hd->size - hd->cursor);
2a6d1768 398 if (ret == -1) {
399 DBG(IO, ul_debugobj(hd, " EAGAIN"));
400 if (!(errno == EINTR || errno == EAGAIN))
fd5698ff 401 rc = -errno;
2a6d1768 402 goto out;
403 }
404 DBG(IO, ul_debugobj(hd, " wrote %zd", ret));
405 any = 1;
406 hd->cursor += ret;
fd5698ff 407
2a6d1768 408 if (hd->cursor == hd->size) {
409 pty->child_buffer_head = hd->next;
fd5698ff 410 if (!hd->next)
2a6d1768 411 pty->child_buffer_tail = NULL;
412
413 hd->next = pty->free_buffers;
414 pty->free_buffers = hd;
415 }
416 }
2a6d1768 417out:
418 /* without sync write_output() will write both input &
419 * shell output that looks like double echoing */
420 if (any)
421 fdatasync(pty->master);
422
423 if (anything)
424 *anything = any;
fd5698ff 425 return rc;
2a6d1768 426}
427
428void ul_pty_write_eof_to_child(struct ul_pty *pty)
429{
430 char c = DEF_EOF;
431 schedule_child_write(pty, &c, sizeof(char), 1);
6954895c
KZ
432}
433
4d5b2fed
KZ
434static int mainloop_callback(struct ul_pty *pty)
435{
f896aef3
KZ
436 int rc;
437
4d5b2fed
KZ
438 if (!pty->callbacks.mainloop)
439 return 0;
440
441 DBG(IO, ul_debugobj(pty, "calling mainloop callback"));
f896aef3
KZ
442 rc = pty->callbacks.mainloop(pty->callback_data);
443
444 DBG(IO, ul_debugobj(pty, " callback done [rc=%d]", rc));
445 return rc;
4d5b2fed
KZ
446}
447
6954895c
KZ
448static int handle_io(struct ul_pty *pty, int fd, int *eof)
449{
450 char buf[BUFSIZ];
451 ssize_t bytes;
4f7f723b 452 int rc = 0;
5c6903b1 453 sigset_t set;
6954895c 454
c4bacbd1 455 DBG(IO, ul_debugobj(pty, " handle I/O on fd=%d", fd));
6954895c
KZ
456 *eof = 0;
457
5c6903b1
SG
458 sigemptyset(&set);
459 sigaddset(&set, SIGTTIN);
460 sigprocmask(SIG_UNBLOCK, &set, NULL);
6954895c
KZ
461 /* read from active FD */
462 bytes = read(fd, buf, sizeof(buf));
5c6903b1 463 sigprocmask(SIG_BLOCK, &set, NULL);
2a6d1768 464 if (bytes == -1) {
6954895c
KZ
465 if (errno == EAGAIN || errno == EINTR)
466 return 0;
467 return -errno;
468 }
469
470 if (bytes == 0) {
471 *eof = 1;
472 return 0;
473 }
474
475 /* from stdin (user) to command */
476 if (fd == STDIN_FILENO) {
2a6d1768 477 DBG(IO, ul_debugobj(pty, " stdin --> master %zd bytes queued", bytes));
6954895c 478
2a6d1768 479 if (schedule_child_write(pty, buf, bytes, 0))
6954895c
KZ
480 return -errno;
481
6954895c
KZ
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);
486 }
487
4f7f723b
KZ
488 if (pty->callbacks.log_stream_activity)
489 rc = pty->callbacks.log_stream_activity(
490 pty->callback_data, fd, buf, bytes);
491
492 return rc;
6954895c
KZ
493}
494
bdd43357
KZ
495void ul_pty_wait_for_child(struct ul_pty *pty)
496{
497 int status;
498 pid_t pid;
499 int options = 0;
500
501 if (pty->child == (pid_t) -1)
502 return;
503
125314c0 504 DBG(SIG, ul_debug("waiting for child [child=%d]", (int) pty->child));
bdd43357
KZ
505
506 if (ul_pty_is_running(pty)) {
507 /* wait for specific child */
508 options = WNOHANG;
509 for (;;) {
510 pid = waitpid(pty->child, &status, options);
125314c0 511 DBG(SIG, ul_debug(" waitpid done [rc=%d]", (int) pid));
bdd43357
KZ
512 if (pid != (pid_t) - 1) {
513 if (pty->callbacks.child_die)
514 pty->callbacks.child_die(
515 pty->callback_data,
516 pty->child, status);
517 ul_pty_set_child(pty, (pid_t) -1);
518 } else
519 break;
520 }
521 } else {
522 /* final wait */
5c6903b1
SG
523 while ((pid = waitpid(-1, &status, options)) > 0) {
524 DBG(SIG, ul_debug(" waitpid done [rc=%d]", (int) pid));
bdd43357
KZ
525 if (pid == pty->child) {
526 if (pty->callbacks.child_die)
527 pty->callbacks.child_die(
528 pty->callback_data,
529 pty->child, status);
530 ul_pty_set_child(pty, (pid_t) -1);
531 }
532 }
533 }
534}
535
6954895c
KZ
536static int handle_signal(struct ul_pty *pty, int fd)
537{
538 struct signalfd_siginfo info;
539 ssize_t bytes;
4f7f723b 540 int rc = 0;
6954895c 541
c4bacbd1 542 DBG(SIG, ul_debugobj(pty, " handle signal on fd=%d", fd));
6954895c
KZ
543
544 bytes = read(fd, &info, sizeof(info));
545 if (bytes != sizeof(info)) {
546 if (bytes < 0 && (errno == EAGAIN || errno == EINTR))
547 return 0;
548 return -errno;
549 }
550
551 switch (info.ssi_signo) {
552 case SIGCHLD:
553 DBG(SIG, ul_debugobj(pty, " get signal SIGCHLD"));
554
555 if (info.ssi_code == CLD_EXITED
556 || info.ssi_code == CLD_KILLED
bdd43357
KZ
557 || info.ssi_code == CLD_DUMPED) {
558
559 if (pty->callbacks.child_wait)
560 pty->callbacks.child_wait(pty->callback_data,
561 pty->child);
562 else
563 ul_pty_wait_for_child(pty);
6954895c 564
5c6903b1 565 } else if (info.ssi_status == SIGSTOP && pty->child > 0) {
bdd43357
KZ
566 pty->callbacks.child_sigstop(pty->callback_data,
567 pty->child);
5c6903b1 568 }
6954895c 569
984082fa 570 if (pty->child <= 0) {
125314c0 571 DBG(SIG, ul_debugobj(pty, " no child, setting leaving timeout"));
6954895c 572 pty->poll_timeout = 10;
984082fa
KZ
573 timerclear(&pty->next_callback_time);
574 }
6954895c
KZ
575 return 0;
576 case SIGWINCH:
577 DBG(SIG, ul_debugobj(pty, " get signal SIGWINCH"));
578 if (pty->isterm) {
579 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win);
580 ioctl(pty->slave, TIOCSWINSZ, (char *)&pty->win);
4f7f723b
KZ
581
582 if (pty->callbacks.log_signal)
583 rc = pty->callbacks.log_signal(pty->callback_data,
584 &info, (void *) &pty->win);
6954895c
KZ
585 }
586 break;
587 case SIGTERM:
588 /* fallthrough */
589 case SIGINT:
590 /* fallthrough */
591 case SIGQUIT:
592 DBG(SIG, ul_debugobj(pty, " get signal SIG{TERM,INT,QUIT}"));
593 pty->delivered_signal = info.ssi_signo;
c556dc59 594 /* Child termination is going to generate SIGCHLD (see above) */
6954895c
KZ
595 if (pty->child > 0)
596 kill(pty->child, SIGTERM);
4f7f723b
KZ
597
598 if (pty->callbacks.log_signal)
599 rc = pty->callbacks.log_signal(pty->callback_data,
600 &info, (void *) &pty->win);
6954895c 601 break;
7727be1a
KZ
602 case SIGUSR1:
603 DBG(SIG, ul_debugobj(pty, " get signal SIGUSR1"));
604 if (pty->callbacks.flush_logs)
605 rc = pty->callbacks.flush_logs(pty->callback_data);
606 break;
6954895c
KZ
607 default:
608 abort();
609 }
610
4f7f723b 611 return rc;
6954895c
KZ
612}
613
614/* loop in parent */
615int ul_pty_proxy_master(struct ul_pty *pty)
616{
6954895c
KZ
617 int rc = 0, ret, eof = 0;
618 enum {
619 POLLFD_SIGNAL = 0,
620 POLLFD_MASTER,
621 POLLFD_STDIN
622
623 };
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 }
628 };
629
c556dc59 630 /* We use signalfd, and standard signals by handlers are completely blocked */
b1154c4e 631 assert(pty->sigfd >= 0);
6954895c
KZ
632
633 pfd[POLLFD_SIGNAL].fd = pty->sigfd;
634 pty->poll_timeout = -1;
635
636 while (!pty->delivered_signal) {
637 size_t i;
4d5b2fed
KZ
638 int errsv, timeout;
639
640 DBG(IO, ul_debugobj(pty, "--poll() loop--"));
641
642 /* note, callback usually updates @next_callback_time */
643 if (timerisset(&pty->next_callback_time)) {
644 struct timeval now;
645
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);
650 if (rc)
651 break;
652 }
653 }
654
655 /* set timeout */
656 if (timerisset(&pty->next_callback_time)) {
657 struct timeval now, rest;
658
659 gettime_monotonic(&now);
660 timersub(&pty->next_callback_time, &now, &rest);
661 timeout = (rest.tv_sec * 1000) + (rest.tv_usec / 1000);
662 } else
663 timeout = pty->poll_timeout;
6954895c 664
fd5698ff 665 /* use POLLOUT (aka "writing is now possible") if data queued */
2a6d1768 666 if (pty->child_buffer_head)
667 pfd[POLLFD_MASTER].events |= POLLOUT;
668 else
669 pfd[POLLFD_MASTER].events &= ~POLLOUT;
670
4d5b2fed
KZ
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);
6954895c 674
6954895c
KZ
675 errsv = errno;
676 DBG(IO, ul_debugobj(pty, "poll() rc=%d", ret));
677
4d5b2fed 678 /* error */
6954895c
KZ
679 if (ret < 0) {
680 if (errsv == EAGAIN)
681 continue;
682 rc = -errno;
683 break;
684 }
4d5b2fed
KZ
685
686 /* timeout */
6954895c 687 if (ret == 0) {
4d5b2fed
KZ
688 if (timerisset(&pty->next_callback_time)) {
689 rc = mainloop_callback(pty);
690 if (rc == 0)
691 continue;
5c6903b1 692 } else {
4d5b2fed 693 rc = 0;
5c6903b1 694 }
4d5b2fed 695
984082fa 696 DBG(IO, ul_debugobj(pty, "leaving poll() loop [timeout=%d, rc=%d]", timeout, rc));
6954895c
KZ
697 break;
698 }
4d5b2fed 699 /* event */
6954895c 700 for (i = 0; i < ARRAY_SIZE(pfd); i++) {
6954895c
KZ
701 if (pfd[i].revents == 0)
702 continue;
703
2a6d1768 704 DBG(IO, ul_debugobj(pty, " active pfd[%s].fd=%d %s %s %s %s %s",
6954895c
KZ
705 i == POLLFD_STDIN ? "stdin" :
706 i == POLLFD_MASTER ? "master" :
707 i == POLLFD_SIGNAL ? "signal" : "???",
708 pfd[i].fd,
709 pfd[i].revents & POLLIN ? "POLLIN" : "",
2a6d1768 710 pfd[i].revents & POLLOUT ? "POLLOUT" : "",
6954895c 711 pfd[i].revents & POLLHUP ? "POLLHUP" : "",
f896aef3
KZ
712 pfd[i].revents & POLLERR ? "POLLERR" : "",
713 pfd[i].revents & POLLNVAL ? "POLLNVAL" : ""));
714
5c6903b1 715 if (i == POLLFD_SIGNAL)
6954895c 716 rc = handle_signal(pty, pfd[i].fd);
2a6d1768 717 else {
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);
722 }
5c6903b1
SG
723
724 if (rc) {
fd5698ff
KZ
725 int anything = 1;
726
5c6903b1 727 ul_pty_write_eof_to_child(pty);
fd5698ff 728 for (anything = 1; anything;)
2a6d1768 729 flush_child_buffers(pty, &anything);
6954895c
KZ
730 break;
731 }
5c6903b1
SG
732
733 if (i == POLLFD_SIGNAL)
734 continue;
735
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)
739 *
740 * POLLNVAL means that fd is closed.
741 */
742 if ((pfd[i].revents & POLLHUP) || (pfd[i].revents & POLLNVAL) || eof) {
743 DBG(IO, ul_debugobj(pty, " ignore FD"));
5c6903b1 744 if (i == POLLFD_STDIN) {
2a6d1768 745 pfd[i].fd = -1;
5c6903b1 746 ul_pty_write_eof_to_child(pty);
2a6d1768 747 } else /* i == POLLFD_MASTER */
748 pfd[i].revents &= ~POLLIN;
5c6903b1 749 }
6954895c 750 }
5c6903b1
SG
751 if (rc)
752 break;
6954895c
KZ
753 }
754
8deb45fc
KZ
755 if (rc && pty->child && pty->child != (pid_t) -1 && !pty->delivered_signal) {
756 kill(pty->child, SIGTERM);
757 sleep(2);
758 kill(pty->child, SIGKILL);
759 }
760
b1154c4e 761 pty_signals_cleanup(pty);
6954895c
KZ
762
763 DBG(IO, ul_debug("poll() done [signal=%d, rc=%d]", pty->delivered_signal, rc));
764 return rc;
765}
766
767#ifdef TEST_PROGRAM_PTY
768/*
769 * $ make test_pty
770 * $ ./test_pty
771 *
772 * ... and see for example tty(1) or "ps afu"
773 */
bdd43357 774static void child_sigstop(void *data __attribute__((__unused__)), pid_t child)
6954895c 775{
6954895c 776 kill(getpid(), SIGSTOP);
bdd43357 777 kill(child, SIGCONT);
6954895c
KZ
778}
779
780int main(int argc, char *argv[])
781{
6954895c
KZ
782 struct ul_pty_callbacks *cb;
783 const char *shell, *command = NULL, *shname = NULL;
784 int caught_signal = 0;
bdd43357 785 pid_t child;
8cf448e9 786 struct ul_pty *pty;
6954895c
KZ
787
788 shell = getenv("SHELL");
789 if (shell == NULL)
790 shell = _PATH_BSHELL;
791 if (argc == 2)
792 command = argv[1];
793
794 ul_pty_init_debug(0);
795
8cf448e9
KZ
796 pty = ul_new_pty(isatty(STDIN_FILENO));
797 if (!pty)
6954895c
KZ
798 err(EXIT_FAILURE, "failed to allocate PTY handler");
799
8cf448e9 800 cb = ul_pty_get_callbacks(pty);
6954895c
KZ
801 cb->child_sigstop = child_sigstop;
802
8cf448e9 803 if (ul_pty_setup(pty))
6954895c 804 err(EXIT_FAILURE, "failed to create pseudo-terminal");
4681d88b
KZ
805 if (ul_pty_signals_setup(pty))
806 err(EXIT_FAILURE, "failed to initialize signals handler");
6954895c
KZ
807
808 fflush(stdout); /* ??? */
809
bdd43357 810 switch ((int) (child = fork())) {
6954895c 811 case -1: /* error */
8cf448e9 812 ul_pty_cleanup(pty);
6954895c
KZ
813 err(EXIT_FAILURE, "cannot create child process");
814 break;
815
816 case 0: /* child */
8cf448e9 817 ul_pty_init_slave(pty);
6954895c
KZ
818
819 signal(SIGTERM, SIG_DFL); /* because /etc/csh.login */
820
821 shname = strrchr(shell, '/');
822 shname = shname ? shname + 1 : shell;
823
824 if (command)
1b10fa0e 825 execl(shell, shname, "-c", command, (char *)NULL);
6954895c 826 else
1b10fa0e 827 execl(shell, shname, "-i", (char *)NULL);
6954895c
KZ
828 err(EXIT_FAILURE, "failed to execute %s", shell);
829 break;
830
831 default:
832 break;
833 }
834
835 /* parent */
8cf448e9 836 ul_pty_set_child(pty, child);
6954895c
KZ
837
838 /* this is the main loop */
8cf448e9 839 ul_pty_proxy_master(pty);
6954895c
KZ
840
841 /* all done; cleanup and kill */
8cf448e9 842 caught_signal = ul_pty_get_delivered_signal(pty);
6954895c 843
8cf448e9
KZ
844 if (!caught_signal && ul_pty_get_child(pty) != (pid_t)-1)
845 ul_pty_wait_for_child(pty); /* final wait */
6954895c 846
8cf448e9 847 if (caught_signal && ul_pty_get_child(pty) != (pid_t)-1) {
6954895c 848 fprintf(stderr, "\nSession terminated, killing shell...");
bdd43357 849 kill(child, SIGTERM);
6954895c 850 sleep(2);
bdd43357 851 kill(child, SIGKILL);
6954895c
KZ
852 fprintf(stderr, " ...killed.\n");
853 }
854
8cf448e9
KZ
855 ul_pty_cleanup(pty);
856 ul_free_pty(pty);
6954895c
KZ
857 return EXIT_SUCCESS;
858}
859
860#endif /* TEST_PROGRAM */
861