]> git.ipfire.org Git - thirdparty/util-linux.git/blob - term-utils/script.c
Merge branch 'help-description' of https://github.com/rudimeier/util-linux
[thirdparty/util-linux.git] / term-utils / script.c
1 /*
2 * Copyright (c) 1980 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
36 * - added Native Language Support
37 *
38 * 2000-07-30 Per Andreas Buer <per@linpro.no> - added "q"-option
39 *
40 * 2014-05-30 Csaba Kos <csaba.kos@gmail.com>
41 * - fixed a rare deadlock after child termination
42 */
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <paths.h>
47 #include <time.h>
48 #include <sys/stat.h>
49 #include <termios.h>
50 #include <sys/ioctl.h>
51 #include <sys/time.h>
52 #include <signal.h>
53 #include <errno.h>
54 #include <string.h>
55 #include <getopt.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <limits.h>
59 #include <locale.h>
60 #include <stddef.h>
61 #include <sys/wait.h>
62 #include <poll.h>
63 #include <sys/signalfd.h>
64 #include <assert.h>
65 #include <inttypes.h>
66
67 #include "closestream.h"
68 #include "nls.h"
69 #include "c.h"
70 #include "ttyutils.h"
71 #include "all-io.h"
72 #include "monotonic.h"
73 #include "timeutils.h"
74
75 #include "debug.h"
76
77 static UL_DEBUG_DEFINE_MASK(script);
78 UL_DEBUG_DEFINE_MASKNAMES(script) = UL_DEBUG_EMPTY_MASKNAMES;
79
80 #define SCRIPT_DEBUG_INIT (1 << 1)
81 #define SCRIPT_DEBUG_POLL (1 << 2)
82 #define SCRIPT_DEBUG_SIGNAL (1 << 3)
83 #define SCRIPT_DEBUG_IO (1 << 4)
84 #define SCRIPT_DEBUG_MISC (1 << 5)
85 #define SCRIPT_DEBUG_ALL 0xFFFF
86
87 #define DBG(m, x) __UL_DBG(script, SCRIPT_DEBUG_, m, x)
88 #define ON_DBG(m, x) __UL_DBG_CALL(script, SCRIPT_DEBUG_, m, x)
89
90 #if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
91 # include <pty.h>
92 #endif
93
94 #ifdef HAVE_LIBUTEMPTER
95 # include <utempter.h>
96 #endif
97
98 #define DEFAULT_TYPESCRIPT_FILENAME "typescript"
99
100 struct script_control {
101 char *shell; /* shell to be executed */
102 char *command; /* command to be executed */
103 char *fname; /* output file path */
104 FILE *typescriptfp; /* output file pointer */
105 char *tname; /* timing file path */
106 FILE *timingfp; /* timing file pointer */
107 struct timeval oldtime; /* previous write or command start time */
108 int master; /* pseudoterminal master file descriptor */
109 int slave; /* pseudoterminal slave file descriptor */
110 int poll_timeout; /* poll() timeout, used in end of execution */
111 pid_t child; /* child pid */
112 int childstatus; /* child process exit value */
113 struct termios attrs; /* slave terminal runtime attributes */
114 struct winsize win; /* terminal window size */
115 #if !HAVE_LIBUTIL || !HAVE_PTY_H
116 char *line; /* terminal line */
117 #endif
118 unsigned int
119 append:1, /* append output */
120 rc_wanted:1, /* return child exit value */
121 flush:1, /* flush after each write */
122 quiet:1, /* suppress most output */
123 timing:1, /* include timing file */
124 force:1, /* write output to links */
125 isterm:1, /* is child process running as terminal */
126 die:1; /* terminate program */
127
128 sigset_t sigset; /* catch SIGCHLD and SIGWINCH with signalfd() */
129 sigset_t sigorg; /* original signal mask */
130 int sigfd; /* file descriptor for signalfd() */
131 };
132
133 static void script_init_debug(void)
134 {
135 __UL_INIT_DEBUG(script, SCRIPT_DEBUG_, 0, SCRIPT_DEBUG);
136 }
137
138 /*
139 * For tests we want to be able to control time output
140 */
141 #ifdef TEST_SCRIPT
142 static inline time_t script_time(time_t *t)
143 {
144 const char *str = getenv("SCRIPT_TEST_SECOND_SINCE_EPOCH");
145 int64_t sec;
146
147 if (!str || sscanf(str, "%"SCNi64, &sec) != 1)
148 return time(t);
149 if (t)
150 *t = (time_t)sec;
151 return (time_t)sec;
152 }
153 #else /* !TEST_SCRIPT */
154 # define script_time(x) time(x)
155 #endif
156
157 static void __attribute__((__noreturn__)) usage(void)
158 {
159 FILE *out = stdout;
160 fputs(USAGE_HEADER, out);
161 fprintf(out, _(" %s [options] [file]\n"), program_invocation_short_name);
162
163 fputs(USAGE_SEPARATOR, out);
164 fputs(_("Make a typescript of a terminal session.\n"), out);
165
166 fputs(USAGE_OPTIONS, out);
167 fputs(_(" -a, --append append the output\n"
168 " -c, --command <command> run command rather than interactive shell\n"
169 " -e, --return return exit code of the child process\n"
170 " -f, --flush run flush after each write\n"
171 " --force use output file even when it is a link\n"
172 " -q, --quiet be quiet\n"
173 " -t, --timing[=<file>] output timing data to stderr (or to FILE)\n"
174 ), out);
175 print_usage_help_options(25);
176
177 fprintf(out, USAGE_MAN_TAIL("script(1)"));
178 exit(EXIT_SUCCESS);
179 }
180
181 static void die_if_link(const struct script_control *ctl)
182 {
183 struct stat s;
184
185 if (ctl->force)
186 return;
187 if (lstat(ctl->fname, &s) == 0 && (S_ISLNK(s.st_mode) || s.st_nlink > 1))
188 errx(EXIT_FAILURE,
189 _("output file `%s' is a link\n"
190 "Use --force if you really want to use it.\n"
191 "Program not started."), ctl->fname);
192 }
193
194 static void restore_tty(struct script_control *ctl, int mode)
195 {
196 struct termios rtt;
197
198 if (!ctl->isterm)
199 return;
200
201 rtt = ctl->attrs;
202 tcsetattr(STDIN_FILENO, mode, &rtt);
203 }
204
205 static void enable_rawmode_tty(struct script_control *ctl)
206 {
207 struct termios rtt;
208
209 if (!ctl->isterm)
210 return;
211
212 rtt = ctl->attrs;
213 cfmakeraw(&rtt);
214 rtt.c_lflag &= ~ECHO;
215 tcsetattr(STDIN_FILENO, TCSANOW, &rtt);
216 }
217
218 static void __attribute__((__noreturn__)) done(struct script_control *ctl)
219 {
220 DBG(MISC, ul_debug("done!"));
221
222 restore_tty(ctl, TCSADRAIN);
223
224 if (!ctl->quiet && ctl->typescriptfp)
225 printf(_("Script done, file is %s\n"), ctl->fname);
226 #ifdef HAVE_LIBUTEMPTER
227 if (ctl->master >= 0)
228 utempter_remove_record(ctl->master);
229 #endif
230 kill(ctl->child, SIGTERM); /* make sure we don't create orphans */
231
232 if (ctl->timingfp && close_stream(ctl->timingfp) != 0)
233 err(EXIT_FAILURE, "write failed: %s", ctl->tname);
234 if (ctl->typescriptfp && close_stream(ctl->typescriptfp) != 0)
235 err(EXIT_FAILURE, "write failed: %s", ctl->fname);
236
237 if (ctl->rc_wanted) {
238 if (WIFSIGNALED(ctl->childstatus))
239 exit(WTERMSIG(ctl->childstatus) + 0x80);
240 else
241 exit(WEXITSTATUS(ctl->childstatus));
242 }
243 exit(EXIT_SUCCESS);
244 }
245
246 static void __attribute__((__noreturn__)) fail(struct script_control *ctl)
247 {
248 DBG(MISC, ul_debug("fail!"));
249 kill(0, SIGTERM);
250 done(ctl);
251 }
252
253 static void wait_for_child(struct script_control *ctl, int wait)
254 {
255 int status;
256 pid_t pid;
257 int options = wait ? 0 : WNOHANG;
258
259 DBG(MISC, ul_debug("waiting for child"));
260
261 while ((pid = wait3(&status, options, NULL)) > 0)
262 if (pid == ctl->child)
263 ctl->childstatus = status;
264 }
265
266 static void write_output(struct script_control *ctl, char *obuf,
267 ssize_t bytes)
268 {
269 DBG(IO, ul_debug(" writing output"));
270
271 if (ctl->timing && ctl->timingfp) {
272 struct timeval now, delta;
273
274 DBG(IO, ul_debug(" writing timing info"));
275
276 gettime_monotonic(&now);
277 timersub(&now, &ctl->oldtime, &delta);
278 fprintf(ctl->timingfp, "%ld.%06ld %zd\n",
279 (long)delta.tv_sec, (long)delta.tv_usec, bytes);
280 if (ctl->flush)
281 fflush(ctl->timingfp);
282 ctl->oldtime = now;
283 }
284
285 DBG(IO, ul_debug(" writing to script file"));
286
287 if (fwrite_all(obuf, 1, bytes, ctl->typescriptfp)) {
288 warn(_("cannot write script file"));
289 fail(ctl);
290 }
291 if (ctl->flush)
292 fflush(ctl->typescriptfp);
293
294 DBG(IO, ul_debug(" writing to output"));
295
296 if (write_all(STDOUT_FILENO, obuf, bytes)) {
297 DBG(IO, ul_debug(" writing output *failed*"));
298 warn(_("write failed"));
299 fail(ctl);
300 }
301
302 DBG(IO, ul_debug(" writing output *done*"));
303 }
304
305 static int write_to_shell(struct script_control *ctl,
306 char *buf, size_t bufsz)
307 {
308 return write_all(ctl->master, buf, bufsz);
309 }
310
311 /*
312 * The script(1) is usually faster than shell, so it's a good idea to wait until
313 * the previous message has been already read by shell from slave before we
314 * write to master. This is necessary especially for EOF situation when we can
315 * send EOF to master before shell is fully initialized, to workaround this
316 * problem we wait until slave is empty. For example:
317 *
318 * echo "date" | script
319 *
320 * Unfortunately, the child (usually shell) can ignore stdin at all, so we
321 * don't wait forever to avoid dead locks...
322 *
323 * Note that script is primarily designed for interactive sessions as it
324 * maintains master+slave tty stuff within the session. Use pipe to write to
325 * script(1) and assume non-interactive (tee-like) behavior is NOT well
326 * supported.
327 */
328 static void write_eof_to_shell(struct script_control *ctl)
329 {
330 unsigned int tries = 0;
331 struct pollfd fds[] = {
332 { .fd = ctl->slave, .events = POLLIN }
333 };
334 char c = DEF_EOF;
335
336 DBG(IO, ul_debug(" waiting for empty slave"));
337 while (poll(fds, 1, 10) == 1 && tries < 8) {
338 DBG(IO, ul_debug(" slave is not empty"));
339 xusleep(250000);
340 tries++;
341 }
342 if (tries < 8)
343 DBG(IO, ul_debug(" slave is empty now"));
344
345 DBG(IO, ul_debug(" sending EOF to master"));
346 write_to_shell(ctl, &c, sizeof(char));
347 }
348
349 static void handle_io(struct script_control *ctl, int fd, int *eof)
350 {
351 char buf[BUFSIZ];
352 ssize_t bytes;
353
354 DBG(IO, ul_debug("%d FD active", fd));
355 *eof = 0;
356
357 /* read from active FD */
358 bytes = read(fd, buf, sizeof(buf));
359 if (bytes < 0) {
360 if (errno == EAGAIN || errno == EINTR)
361 return;
362 fail(ctl);
363 }
364
365 if (bytes == 0) {
366 *eof = 1;
367 return;
368 }
369
370 /* from stdin (user) to command */
371 if (fd == STDIN_FILENO) {
372 DBG(IO, ul_debug(" stdin --> master %zd bytes", bytes));
373
374 if (write_to_shell(ctl, buf, bytes)) {
375 warn(_("write failed"));
376 fail(ctl);
377 }
378 /* without sync write_output() will write both input &
379 * shell output that looks like double echoing */
380 fdatasync(ctl->master);
381
382 /* from command (master) to stdout */
383 } else if (fd == ctl->master) {
384 DBG(IO, ul_debug(" master --> stdout %zd bytes", bytes));
385 write_output(ctl, buf, bytes);
386 }
387 }
388
389 static void handle_signal(struct script_control *ctl, int fd)
390 {
391 struct signalfd_siginfo info;
392 ssize_t bytes;
393
394 DBG(SIGNAL, ul_debug("signal FD %d active", fd));
395
396 bytes = read(fd, &info, sizeof(info));
397 if (bytes != sizeof(info)) {
398 if (bytes < 0 && (errno == EAGAIN || errno == EINTR))
399 return;
400 fail(ctl);
401 }
402
403 switch (info.ssi_signo) {
404 case SIGCHLD:
405 DBG(SIGNAL, ul_debug(" get signal SIGCHLD"));
406 wait_for_child(ctl, 0);
407 ctl->poll_timeout = 10;
408 return;
409 case SIGWINCH:
410 DBG(SIGNAL, ul_debug(" get signal SIGWINCH"));
411 if (ctl->isterm) {
412 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
413 ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
414 }
415 break;
416 case SIGTERM:
417 /* fallthrough */
418 case SIGINT:
419 /* fallthrough */
420 case SIGQUIT:
421 DBG(SIGNAL, ul_debug(" get signal SIG{TERM,INT,QUIT}"));
422 fprintf(stderr, _("\nSession terminated.\n"));
423 /* Child termination is going to generate SIGCHILD (see above) */
424 kill(ctl->child, SIGTERM);
425 return;
426 default:
427 abort();
428 }
429 }
430
431 static void do_io(struct script_control *ctl)
432 {
433 int ret, ignore_stdin = 0, eof = 0;
434 time_t tvec = script_time((time_t *)NULL);
435 char buf[128];
436 enum {
437 POLLFD_SIGNAL = 0,
438 POLLFD_MASTER,
439 POLLFD_STDIN /* optional; keep it last, see ignore_stdin */
440
441 };
442 struct pollfd pfd[] = {
443 [POLLFD_SIGNAL] = { .fd = ctl->sigfd, .events = POLLIN | POLLERR | POLLHUP },
444 [POLLFD_MASTER] = { .fd = ctl->master, .events = POLLIN | POLLERR | POLLHUP },
445 [POLLFD_STDIN] = { .fd = STDIN_FILENO, .events = POLLIN | POLLERR | POLLHUP }
446 };
447
448
449 if ((ctl->typescriptfp =
450 fopen(ctl->fname, ctl->append ? "a" UL_CLOEXECSTR : "w" UL_CLOEXECSTR)) == NULL) {
451
452 restore_tty(ctl, TCSANOW);
453 warn(_("cannot open %s"), ctl->fname);
454 fail(ctl);
455 }
456 if (ctl->timing) {
457 const char *tname = ctl->tname ? ctl->tname : "/dev/stderr";
458
459 if (!(ctl->timingfp = fopen(tname, "w" UL_CLOEXECSTR))) {
460 restore_tty(ctl, TCSANOW);
461 warn(_("cannot open %s"), tname);
462 fail(ctl);
463 }
464 }
465
466
467 if (ctl->typescriptfp) {
468 strtime_iso(&tvec, ISO_8601_DATE | ISO_8601_TIME |
469 ISO_8601_TIMEZONE | ISO_8601_SPACE,
470 buf, sizeof(buf));
471 fprintf(ctl->typescriptfp, _("Script started on %s\n"), buf);
472 }
473 gettime_monotonic(&ctl->oldtime);
474
475 while (!ctl->die) {
476 size_t i;
477 int errsv;
478
479 DBG(POLL, ul_debug("calling poll()"));
480
481 /* wait for input or signal */
482 ret = poll(pfd, ARRAY_SIZE(pfd) - ignore_stdin, ctl->poll_timeout);
483 errsv = errno;
484 DBG(POLL, ul_debug("poll() rc=%d", ret));
485
486 if (ret < 0) {
487 if (errsv == EAGAIN)
488 continue;
489 warn(_("poll failed"));
490 fail(ctl);
491 }
492 if (ret == 0) {
493 DBG(POLL, ul_debug("setting die=1"));
494 ctl->die = 1;
495 break;
496 }
497
498 for (i = 0; i < ARRAY_SIZE(pfd) - ignore_stdin; i++) {
499 if (pfd[i].revents == 0)
500 continue;
501
502 DBG(POLL, ul_debug(" active pfd[%s].fd=%d %s %s %s",
503 i == POLLFD_STDIN ? "stdin" :
504 i == POLLFD_MASTER ? "master" :
505 i == POLLFD_SIGNAL ? "signal" : "???",
506 pfd[i].fd,
507 pfd[i].revents & POLLIN ? "POLLIN" : "",
508 pfd[i].revents & POLLHUP ? "POLLHUP" : "",
509 pfd[i].revents & POLLERR ? "POLLERR" : ""));
510 switch (i) {
511 case POLLFD_STDIN:
512 case POLLFD_MASTER:
513 /* data */
514 if (pfd[i].revents & POLLIN)
515 handle_io(ctl, pfd[i].fd, &eof);
516 /* EOF maybe detected by two ways:
517 * A) poll() return POLLHUP event after close()
518 * B) read() returns 0 (no data) */
519 if ((pfd[i].revents & POLLHUP) || eof) {
520 DBG(POLL, ul_debug(" ignore FD"));
521 pfd[i].fd = -1;
522 /* according to man poll() set FD to -1 can't be used to ignore
523 * STDIN, so let's remove the FD from pool at all */
524 if (i == POLLFD_STDIN) {
525 ignore_stdin = 1;
526 write_eof_to_shell(ctl);
527 DBG(POLL, ul_debug(" ignore STDIN"));
528 }
529 }
530 continue;
531 case POLLFD_SIGNAL:
532 handle_signal(ctl, pfd[i].fd);
533 break;
534 }
535 }
536 }
537
538 DBG(POLL, ul_debug("poll() done"));
539
540 if (!ctl->die)
541 wait_for_child(ctl, 1);
542
543 if (ctl->typescriptfp) {
544 tvec = script_time((time_t *)NULL);
545 strtime_iso(&tvec, ISO_8601_DATE | ISO_8601_TIME |
546 ISO_8601_TIMEZONE | ISO_8601_SPACE,
547 buf, sizeof(buf));
548 fprintf(ctl->typescriptfp, _("\nScript done on %s\n"), buf);
549 }
550 done(ctl);
551 }
552
553 static void getslave(struct script_control *ctl)
554 {
555 #ifndef HAVE_LIBUTIL
556 ctl->line[strlen("/dev/")] = 't';
557 ctl->slave = open(ctl->line, O_RDWR | O_CLOEXEC);
558 if (ctl->slave < 0) {
559 warn(_("cannot open %s"), ctl->line);
560 fail(ctl);
561 }
562 if (ctl->isterm) {
563 tcsetattr(ctl->slave, TCSANOW, &ctl->attrs);
564 ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
565 }
566 #endif
567 setsid();
568 ioctl(ctl->slave, TIOCSCTTY, 0);
569 }
570
571 /* don't use DBG() stuff here otherwise it will be in the typescript file */
572 static void __attribute__((__noreturn__)) do_shell(struct script_control *ctl)
573 {
574 char *shname;
575
576 getslave(ctl);
577
578 /* close things irrelevant for this process */
579 close(ctl->master);
580 close(ctl->sigfd);
581
582 dup2(ctl->slave, STDIN_FILENO);
583 dup2(ctl->slave, STDOUT_FILENO);
584 dup2(ctl->slave, STDERR_FILENO);
585 close(ctl->slave);
586
587 ctl->master = -1;
588
589 shname = strrchr(ctl->shell, '/');
590 if (shname)
591 shname++;
592 else
593 shname = ctl->shell;
594
595 sigprocmask(SIG_SETMASK, &ctl->sigorg, NULL);
596
597 /*
598 * When invoked from within /etc/csh.login, script spawns a csh shell
599 * that spawns programs that cannot be killed with a SIGTERM. This is
600 * because csh has a documented behavior wherein it disables all
601 * signals when processing the /etc/csh.* files.
602 *
603 * Let's restore the default behavior.
604 */
605 signal(SIGTERM, SIG_DFL);
606
607 if (access(ctl->shell, X_OK) == 0) {
608 if (ctl->command)
609 execl(ctl->shell, shname, "-c", ctl->command, NULL);
610 else
611 execl(ctl->shell, shname, "-i", NULL);
612 } else {
613 if (ctl->command)
614 execlp(shname, "-c", ctl->command, NULL);
615 else
616 execlp(shname, "-i", NULL);
617 }
618 warn(_("failed to execute %s"), ctl->shell);
619 fail(ctl);
620 }
621
622
623 static void getmaster(struct script_control *ctl)
624 {
625 #if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
626 int rc;
627
628 ctl->isterm = isatty(STDIN_FILENO);
629
630 if (ctl->isterm) {
631 if (tcgetattr(STDIN_FILENO, &ctl->attrs) != 0)
632 err(EXIT_FAILURE, _("failed to get terminal attributes"));
633 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
634 rc = openpty(&ctl->master, &ctl->slave, NULL, &ctl->attrs, &ctl->win);
635 } else
636 rc = openpty(&ctl->master, &ctl->slave, NULL, NULL, NULL);
637
638 if (rc < 0) {
639 warn(_("openpty failed"));
640 fail(ctl);
641 }
642 #else
643 char *pty, *bank, *cp;
644
645 ctl->isterm = isatty(STDIN_FILENO);
646
647 pty = &ctl->line[strlen("/dev/ptyp")];
648 for (bank = "pqrs"; *bank; bank++) {
649 ctl->line[strlen("/dev/pty")] = *bank;
650 *pty = '0';
651 if (access(ctl->line, F_OK) != 0)
652 break;
653 for (cp = "0123456789abcdef"; *cp; cp++) {
654 *pty = *cp;
655 ctl->master = open(ctl->line, O_RDWR | O_CLOEXEC);
656 if (ctl->master >= 0) {
657 char *tp = &ctl->line[strlen("/dev/")];
658 int ok;
659
660 /* verify slave side is usable */
661 *tp = 't';
662 ok = access(ctl->line, R_OK | W_OK) == 0;
663 *tp = 'p';
664 if (ok) {
665 if (ctl->isterm) {
666 tcgetattr(STDIN_FILENO, &ctl->attrs);
667 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
668 }
669 return;
670 }
671 close(ctl->master);
672 ctl->master = -1;
673 }
674 }
675 }
676 ctl->master = -1;
677 warn(_("out of pty's"));
678 fail(ctl);
679 #endif /* not HAVE_LIBUTIL */
680
681 DBG(IO, ul_debug("master fd: %d", ctl->master));
682 }
683
684 int main(int argc, char **argv)
685 {
686 struct script_control ctl = {
687 #if !HAVE_LIBUTIL || !HAVE_PTY_H
688 .line = "/dev/ptyXX",
689 #endif
690 .master = -1,
691 .poll_timeout = -1,
692 0
693 };
694 int ch;
695
696 enum { FORCE_OPTION = CHAR_MAX + 1 };
697
698 static const struct option longopts[] = {
699 {"append", no_argument, NULL, 'a'},
700 {"command", required_argument, NULL, 'c'},
701 {"return", no_argument, NULL, 'e'},
702 {"flush", no_argument, NULL, 'f'},
703 {"force", no_argument, NULL, FORCE_OPTION,},
704 {"quiet", no_argument, NULL, 'q'},
705 {"timing", optional_argument, NULL, 't'},
706 {"version", no_argument, NULL, 'V'},
707 {"help", no_argument, NULL, 'h'},
708 {NULL, 0, NULL, 0}
709 };
710
711 setlocale(LC_ALL, "");
712 /*
713 * script -t prints time delays as floating point numbers. The example
714 * program (scriptreplay) that we provide to handle this timing output
715 * is a perl script, and does not handle numbers in locale format (not
716 * even when "use locale;" is added). So, since these numbers are not
717 * for human consumption, it seems easiest to set LC_NUMERIC here.
718 */
719 setlocale(LC_NUMERIC, "C");
720 bindtextdomain(PACKAGE, LOCALEDIR);
721 textdomain(PACKAGE);
722 atexit(close_stdout);
723
724 script_init_debug();
725
726 while ((ch = getopt_long(argc, argv, "ac:efqt::Vh", longopts, NULL)) != -1)
727 switch (ch) {
728 case 'a':
729 ctl.append = 1;
730 break;
731 case 'c':
732 ctl.command = optarg;
733 break;
734 case 'e':
735 ctl.rc_wanted = 1;
736 break;
737 case 'f':
738 ctl.flush = 1;
739 break;
740 case FORCE_OPTION:
741 ctl.force = 1;
742 break;
743 case 'q':
744 ctl.quiet = 1;
745 break;
746 case 't':
747 if (optarg)
748 ctl.tname = optarg;
749 ctl.timing = 1;
750 break;
751 case 'V':
752 printf(UTIL_LINUX_VERSION);
753 exit(EXIT_SUCCESS);
754 break;
755 case 'h':
756 usage();
757 break;
758 default:
759 errtryhelp(EXIT_FAILURE);
760 }
761 argc -= optind;
762 argv += optind;
763
764 if (argc > 0)
765 ctl.fname = argv[0];
766 else {
767 ctl.fname = DEFAULT_TYPESCRIPT_FILENAME;
768 die_if_link(&ctl);
769 }
770
771 ctl.shell = getenv("SHELL");
772 if (ctl.shell == NULL)
773 ctl.shell = _PATH_BSHELL;
774
775 getmaster(&ctl);
776 if (!ctl.quiet)
777 printf(_("Script started, file is %s\n"), ctl.fname);
778 enable_rawmode_tty(&ctl);
779
780 #ifdef HAVE_LIBUTEMPTER
781 utempter_add_record(ctl.master, NULL);
782 #endif
783 /* setup signal handler */
784 sigemptyset(&ctl.sigset);
785 sigaddset(&ctl.sigset, SIGCHLD);
786 sigaddset(&ctl.sigset, SIGWINCH);
787 sigaddset(&ctl.sigset, SIGTERM);
788 sigaddset(&ctl.sigset, SIGINT);
789 sigaddset(&ctl.sigset, SIGQUIT);
790
791 /* block signals used for signalfd() to prevent the signals being
792 * handled according to their default dispositions */
793 sigprocmask(SIG_BLOCK, &ctl.sigset, &ctl.sigorg);
794
795 if ((ctl.sigfd = signalfd(-1, &ctl.sigset, SFD_CLOEXEC)) < 0)
796 err(EXIT_FAILURE, _("cannot set signal handler"));
797
798 DBG(SIGNAL, ul_debug("signal fd=%d", ctl.sigfd));
799
800 fflush(stdout);
801 ctl.child = fork();
802
803 switch (ctl.child) {
804 case -1: /* error */
805 warn(_("fork failed"));
806 fail(&ctl);
807 break;
808 case 0: /* child */
809 do_shell(&ctl);
810 break;
811 default: /* parent */
812 do_io(&ctl);
813 break;
814 }
815
816 /* should not happen, all used functions are non-return */
817 return EXIT_FAILURE;
818 }