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