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