]> git.ipfire.org Git - thirdparty/util-linux.git/blob - lib/pty-session.c
Merge branch 'fincore-block' of https://github.com/dancerj/util-linux
[thirdparty/util-linux.git] / lib / pty-session.c
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)
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
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>
21 #include <inttypes.h>
22
23 #include "c.h"
24 #include "all-io.h"
25 #include "ttyutils.h"
26 #include "pty-session.h"
27 #include "monotonic.h"
28 #include "debug.h"
29
30 static UL_DEBUG_DEFINE_MASK(ulpty);
31 UL_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
46 void 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
53 struct 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
70 void ul_free_pty(struct ul_pty *pty)
71 {
72 struct ul_pty_child_buffer *hd;
73
74 while ((hd = pty->child_buffer_head)) {
75 pty->child_buffer_head = hd->next;
76 free(hd);
77 }
78
79 while ((hd = pty->free_buffers)) {
80 pty->free_buffers = hd->next;
81 free(hd);
82 }
83 free(pty);
84 }
85
86 void ul_pty_slave_echo(struct ul_pty *pty, int enable)
87 {
88 assert(pty);
89 pty->slave_echo = enable ? 1 : 0;
90 }
91
92 int ul_pty_get_delivered_signal(struct ul_pty *pty)
93 {
94 assert(pty);
95 return pty->delivered_signal;
96 }
97
98 struct ul_pty_callbacks *ul_pty_get_callbacks(struct ul_pty *pty)
99 {
100 assert(pty);
101 return &pty->callbacks;
102 }
103
104 void ul_pty_set_callback_data(struct ul_pty *pty, void *data)
105 {
106 assert(pty);
107 pty->callback_data = data;
108 }
109
110 void ul_pty_set_child(struct ul_pty *pty, pid_t child)
111 {
112 assert(pty);
113 pty->child = child;
114 }
115
116 int ul_pty_get_childfd(struct ul_pty *pty)
117 {
118 assert(pty);
119 return pty->master;
120 }
121
122 pid_t ul_pty_get_child(struct ul_pty *pty)
123 {
124 assert(pty);
125 return pty->child;
126 }
127
128 /* it's active when signals are redirected to sigfd */
129 int ul_pty_is_running(struct ul_pty *pty)
130 {
131 assert(pty);
132 return pty->sigfd >= 0;
133 }
134
135 void 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;
144 DBG(IO, ul_debugobj(pty, "mainloop time: %"PRId64".%06"PRId64,
145 (int64_t) tv->tv_sec, (int64_t) tv->tv_usec));
146 }
147 }
148
149 static 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
159 /* call me before fork() */
160 int ul_pty_setup(struct ul_pty *pty)
161 {
162 struct termios attrs;
163 int rc = 0;
164
165 assert(pty->sigfd == -1);
166
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);
170
171 if (pty->isterm) {
172 DBG(SETUP, ul_debugobj(pty, "create for terminal"));
173
174 /* original setting of the current terminal */
175 if (tcgetattr(STDIN_FILENO, &pty->stdin_attrs) != 0) {
176 rc = -errno;
177 goto done;
178 }
179
180 attrs = pty->stdin_attrs;
181 if (pty->slave_echo)
182 attrs.c_lflag |= ECHO;
183 else
184 attrs.c_lflag &= ~ECHO;
185
186 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&pty->win);
187 /* create master+slave */
188 rc = openpty(&pty->master, &pty->slave, NULL, &attrs, &pty->win);
189 if (rc)
190 goto done;
191
192 /* set the current terminal to raw mode; pty_cleanup() reverses this change on exit */
193 cfmakeraw(&attrs);
194 tcsetattr(STDIN_FILENO, TCSANOW, &attrs);
195 } else {
196 DBG(SETUP, ul_debugobj(pty, "create for non-terminal"));
197
198 rc = openpty(&pty->master, &pty->slave, NULL, NULL, NULL);
199 if (rc)
200 goto done;
201
202 tcgetattr(pty->slave, &attrs);
203
204 if (pty->slave_echo)
205 attrs.c_lflag |= ECHO;
206 else
207 attrs.c_lflag &= ~ECHO;
208
209 tcsetattr(pty->slave, TCSANOW, &attrs);
210 }
211
212 fcntl(pty->master, F_SETFL, O_NONBLOCK);
213
214 done:
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() */
224 int 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
234 sigfillset(&ourset);
235 if (sigprocmask(SIG_BLOCK, &ourset, NULL)) {
236 rc = -errno;
237 goto done;
238 }
239
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
248 if (pty->callbacks.flush_logs)
249 sigaddset(&ourset, SIGUSR1);
250
251 if ((pty->sigfd = signalfd(-1, &ourset, SFD_CLOEXEC)) < 0)
252 rc = -errno;
253 done:
254 if (rc)
255 ul_pty_cleanup(pty);
256
257 DBG(SETUP, ul_debugobj(pty, "pty signals setup done [rc=%d]", rc));
258 return rc;
259 }
260
261 /* cleanup in parent process */
262 void ul_pty_cleanup(struct ul_pty *pty)
263 {
264 struct termios rtt;
265
266 pty_signals_cleanup(pty);
267
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
276 int 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
285 /* call me in child process */
286 void 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
313 static 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
325 static int schedule_child_write(struct ul_pty *pty, char *buf, size_t bufsz, int final)
326 {
327 struct ul_pty_child_buffer *stash;
328
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
338 assert(bufsz <= sizeof(stash->buf));
339
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;
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 */
367 static void drain_child_buffers(struct ul_pty *pty)
368 {
369 unsigned int tries = 0;
370 struct pollfd fd = { .fd = pty->slave, .events = POLLIN };
371
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"));
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"));
382 }
383
384 static int flush_child_buffers(struct ul_pty *pty, int *anything)
385 {
386 int rc = 0, any = 0;
387
388 while (pty->child_buffer_head) {
389 struct ul_pty_child_buffer *hd = pty->child_buffer_head;
390 ssize_t ret;
391
392 if (hd->final_input)
393 drain_child_buffers(pty);
394
395 DBG(IO, ul_debugobj(hd, " stdin --> master trying %zu bytes", hd->size - hd->cursor));
396
397 ret = write(pty->master, hd->buf + hd->cursor, hd->size - hd->cursor);
398 if (ret == -1) {
399 DBG(IO, ul_debugobj(hd, " EAGAIN"));
400 if (!(errno == EINTR || errno == EAGAIN))
401 rc = -errno;
402 goto out;
403 }
404 DBG(IO, ul_debugobj(hd, " wrote %zd", ret));
405 any = 1;
406 hd->cursor += ret;
407
408 if (hd->cursor == hd->size) {
409 pty->child_buffer_head = hd->next;
410 if (!hd->next)
411 pty->child_buffer_tail = NULL;
412
413 hd->next = pty->free_buffers;
414 pty->free_buffers = hd;
415 }
416 }
417 out:
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;
425 return rc;
426 }
427
428 void 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);
432 }
433
434 static int mainloop_callback(struct ul_pty *pty)
435 {
436 int rc;
437
438 if (!pty->callbacks.mainloop)
439 return 0;
440
441 DBG(IO, ul_debugobj(pty, "calling mainloop callback"));
442 rc = pty->callbacks.mainloop(pty->callback_data);
443
444 DBG(IO, ul_debugobj(pty, " callback done [rc=%d]", rc));
445 return rc;
446 }
447
448 static int handle_io(struct ul_pty *pty, int fd, int *eof)
449 {
450 char buf[BUFSIZ];
451 ssize_t bytes;
452 int rc = 0;
453 sigset_t set;
454
455 DBG(IO, ul_debugobj(pty, " handle I/O on fd=%d", fd));
456 *eof = 0;
457
458 sigemptyset(&set);
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);
464 if (bytes == -1) {
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) {
477 DBG(IO, ul_debugobj(pty, " stdin --> master %zd bytes queued", bytes));
478
479 if (schedule_child_write(pty, buf, bytes, 0))
480 return -errno;
481
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
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;
493 }
494
495 void 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
504 DBG(SIG, ul_debug("waiting for child [child=%d]", (int) pty->child));
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);
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(
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 */
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(
528 pty->callback_data,
529 pty->child, status);
530 ul_pty_set_child(pty, (pid_t) -1);
531 }
532 }
533 }
534 }
535
536 static int handle_signal(struct ul_pty *pty, int fd)
537 {
538 struct signalfd_siginfo info;
539 ssize_t bytes;
540 int rc = 0;
541
542 DBG(SIG, ul_debugobj(pty, " handle signal on fd=%d", fd));
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
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);
564
565 } else if (info.ssi_status == SIGSTOP && pty->child > 0) {
566 pty->callbacks.child_sigstop(pty->callback_data,
567 pty->child);
568 }
569
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);
574 }
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);
581
582 if (pty->callbacks.log_signal)
583 rc = pty->callbacks.log_signal(pty->callback_data,
584 &info, (void *) &pty->win);
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;
594 /* Child termination is going to generate SIGCHLD (see above) */
595 if (pty->child > 0)
596 kill(pty->child, SIGTERM);
597
598 if (pty->callbacks.log_signal)
599 rc = pty->callbacks.log_signal(pty->callback_data,
600 &info, (void *) &pty->win);
601 break;
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;
607 default:
608 abort();
609 }
610
611 return rc;
612 }
613
614 /* loop in parent */
615 int ul_pty_proxy_master(struct ul_pty *pty)
616 {
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
630 /* We use signalfd, and standard signals by handlers are completely blocked */
631 assert(pty->sigfd >= 0);
632
633 pfd[POLLFD_SIGNAL].fd = pty->sigfd;
634 pty->poll_timeout = -1;
635
636 while (!pty->delivered_signal) {
637 size_t i;
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;
664
665 /* use POLLOUT (aka "writing is now possible") if data queued */
666 if (pty->child_buffer_head)
667 pfd[POLLFD_MASTER].events |= POLLOUT;
668 else
669 pfd[POLLFD_MASTER].events &= ~POLLOUT;
670
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);
674
675 errsv = errno;
676 DBG(IO, ul_debugobj(pty, "poll() rc=%d", ret));
677
678 /* error */
679 if (ret < 0) {
680 if (errsv == EAGAIN)
681 continue;
682 rc = -errno;
683 break;
684 }
685
686 /* timeout */
687 if (ret == 0) {
688 if (timerisset(&pty->next_callback_time)) {
689 rc = mainloop_callback(pty);
690 if (rc == 0)
691 continue;
692 } else {
693 rc = 0;
694 }
695
696 DBG(IO, ul_debugobj(pty, "leaving poll() loop [timeout=%d, rc=%d]", timeout, rc));
697 break;
698 }
699 /* event */
700 for (i = 0; i < ARRAY_SIZE(pfd); i++) {
701 if (pfd[i].revents == 0)
702 continue;
703
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" : "???",
708 pfd[i].fd,
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" : ""));
714
715 if (i == POLLFD_SIGNAL)
716 rc = handle_signal(pty, pfd[i].fd);
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 }
723
724 if (rc) {
725 int anything = 1;
726
727 ul_pty_write_eof_to_child(pty);
728 for (anything = 1; anything;)
729 flush_child_buffers(pty, &anything);
730 break;
731 }
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"));
744 if (i == POLLFD_STDIN) {
745 pfd[i].fd = -1;
746 ul_pty_write_eof_to_child(pty);
747 } else /* i == POLLFD_MASTER */
748 pfd[i].revents &= ~POLLIN;
749 }
750 }
751 if (rc)
752 break;
753 }
754
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
761 pty_signals_cleanup(pty);
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 */
774 static void child_sigstop(void *data __attribute__((__unused__)), pid_t child)
775 {
776 kill(getpid(), SIGSTOP);
777 kill(child, SIGCONT);
778 }
779
780 int main(int argc, char *argv[])
781 {
782 struct ul_pty_callbacks *cb;
783 const char *shell, *command = NULL, *shname = NULL;
784 int caught_signal = 0;
785 pid_t child;
786 struct ul_pty *pty;
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
796 pty = ul_new_pty(isatty(STDIN_FILENO));
797 if (!pty)
798 err(EXIT_FAILURE, "failed to allocate PTY handler");
799
800 cb = ul_pty_get_callbacks(pty);
801 cb->child_sigstop = child_sigstop;
802
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");
807
808 fflush(stdout); /* ??? */
809
810 switch ((int) (child = fork())) {
811 case -1: /* error */
812 ul_pty_cleanup(pty);
813 err(EXIT_FAILURE, "cannot create child process");
814 break;
815
816 case 0: /* child */
817 ul_pty_init_slave(pty);
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)
825 execl(shell, shname, "-c", command, (char *)NULL);
826 else
827 execl(shell, shname, "-i", (char *)NULL);
828 err(EXIT_FAILURE, "failed to execute %s", shell);
829 break;
830
831 default:
832 break;
833 }
834
835 /* parent */
836 ul_pty_set_child(pty, child);
837
838 /* this is the main loop */
839 ul_pty_proxy_master(pty);
840
841 /* all done; cleanup and kill */
842 caught_signal = ul_pty_get_delivered_signal(pty);
843
844 if (!caught_signal && ul_pty_get_child(pty) != (pid_t)-1)
845 ul_pty_wait_for_child(pty); /* final wait */
846
847 if (caught_signal && ul_pty_get_child(pty) != (pid_t)-1) {
848 fprintf(stderr, "\nSession terminated, killing shell...");
849 kill(child, SIGTERM);
850 sleep(2);
851 kill(child, SIGKILL);
852 fprintf(stderr, " ...killed.\n");
853 }
854
855 ul_pty_cleanup(pty);
856 ul_free_pty(pty);
857 return EXIT_SUCCESS;
858 }
859
860 #endif /* TEST_PROGRAM */
861