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