]> git.ipfire.org Git - thirdparty/util-linux.git/blame - term-utils/script.c
script: allow to use the same log for more streams
[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"
aefe9893 74#include "strutils.h"
596f4202 75#include "xalloc.h"
6dbe3af9 76
a2b4dec5
KZ
77#include "debug.h"
78
2ba641e5 79static UL_DEBUG_DEFINE_MASK(script);
a2b4dec5
KZ
80UL_DEBUG_DEFINE_MASKNAMES(script) = UL_DEBUG_EMPTY_MASKNAMES;
81
82#define SCRIPT_DEBUG_INIT (1 << 1)
83#define SCRIPT_DEBUG_POLL (1 << 2)
84#define SCRIPT_DEBUG_SIGNAL (1 << 3)
85#define SCRIPT_DEBUG_IO (1 << 4)
86#define SCRIPT_DEBUG_MISC (1 << 5)
87#define SCRIPT_DEBUG_ALL 0xFFFF
88
89#define DBG(m, x) __UL_DBG(script, SCRIPT_DEBUG_, m, x)
90#define ON_DBG(m, x) __UL_DBG_CALL(script, SCRIPT_DEBUG_, m, x)
91
e11a5e63
SK
92#if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
93# include <pty.h>
5c36a0eb
KZ
94#endif
95
f0bc3fa0 96#ifdef HAVE_LIBUTEMPTER
e11a5e63 97# include <utempter.h>
f0bc3fa0
KZ
98#endif
99
7e5796c9 100#define DEFAULT_TYPESCRIPT_FILENAME "typescript"
05644dab 101
596f4202
KZ
102enum {
103 SCRIPT_FMT_RAW = 1, /* raw slave/master data */
104 SCRIPT_FMT_TIMING_SIMPLE, /* timing info in classic "<time> <delta>" format */
105};
106
107struct script_log {
108 FILE *fp; /* file pointer (handler) */
109 int format; /* SCRIPT_FMT_* */
110 char *filename; /* on command line specified name */
111 struct timeval oldtime; /* previous entry log time */
112};
113
114struct script_stream {
115 struct timeval oldtime; /* last update */
9f822648 116 struct script_log **logs; /* logs where to write data from stream */
596f4202
KZ
117 size_t nlogs; /* number of logs */
118};
119
edc7e420
SK
120struct script_control {
121 char *shell; /* shell to be executed */
3f19b85f 122 char *command; /* command to be executed */
596f4202
KZ
123 uint64_t outsz; /* current output files size */
124 uint64_t maxsz; /* maximum output files size */
125
edc7e420
SK
126 int master; /* pseudoterminal master file descriptor */
127 int slave; /* pseudoterminal slave file descriptor */
596f4202
KZ
128
129 struct script_stream out; /* output */
130 struct script_stream in; /* input */
131
89a859d4 132 int poll_timeout; /* poll() timeout, used in end of execution */
edc7e420 133 pid_t child; /* child pid */
edc7e420 134 int childstatus; /* child process exit value */
3f19b85f 135 struct termios attrs; /* slave terminal runtime attributes */
edc7e420 136 struct winsize win; /* terminal window size */
9779651e 137#if !HAVE_LIBUTIL || !HAVE_PTY_H
8d6fdd2f 138 char *line; /* terminal line */
5c36a0eb 139#endif
edc7e420 140 unsigned int
3f19b85f 141 append:1, /* append output */
7e5796c9 142 rc_wanted:1, /* return child exit value */
3f19b85f
KZ
143 flush:1, /* flush after each write */
144 quiet:1, /* suppress most output */
3f19b85f 145 force:1, /* write output to links */
edc7e420 146 isterm:1, /* is child process running as terminal */
edc7e420 147 die:1; /* terminate program */
7e5796c9 148
cc1a88fb 149 sigset_t sigset; /* catch SIGCHLD and SIGWINCH with signalfd() */
d35ffe80 150 sigset_t sigorg; /* original signal mask */
cc1a88fb 151 int sigfd; /* file descriptor for signalfd() */
edc7e420 152};
1f58c445 153
596f4202
KZ
154static void restore_tty(struct script_control *ctl, int mode);
155static void __attribute__((__noreturn__)) fail(struct script_control *ctl);
156
a2b4dec5
KZ
157static void script_init_debug(void)
158{
a15dca2f 159 __UL_INIT_DEBUG_FROM_ENV(script, SCRIPT_DEBUG_, 0, SCRIPT_DEBUG);
a2b4dec5
KZ
160}
161
6a40c65f
SK
162/*
163 * For tests we want to be able to control time output
164 */
165#ifdef TEST_SCRIPT
166static inline time_t script_time(time_t *t)
167{
168 const char *str = getenv("SCRIPT_TEST_SECOND_SINCE_EPOCH");
345208a5 169 int64_t sec;
6a40c65f 170
c2f03da9 171 if (!str || sscanf(str, "%"SCNi64, &sec) != 1)
345208a5
ID
172 return time(t);
173 if (t)
174 *t = (time_t)sec;
175 return (time_t)sec;
6a40c65f
SK
176}
177#else /* !TEST_SCRIPT */
178# define script_time(x) time(x)
179#endif
180
86be6a32 181static void __attribute__((__noreturn__)) usage(void)
3ff52639 182{
86be6a32 183 FILE *out = stdout;
db433bf7 184 fputs(USAGE_HEADER, out);
edc7e420 185 fprintf(out, _(" %s [options] [file]\n"), program_invocation_short_name);
87d6050b 186
451dbcfa
BS
187 fputs(USAGE_SEPARATOR, out);
188 fputs(_("Make a typescript of a terminal session.\n"), out);
189
db433bf7 190 fputs(USAGE_OPTIONS, out);
3cf274c9
AO
191 fputs(_(" -a, --append append the output\n"
192 " -c, --command <command> run command rather than interactive shell\n"
193 " -e, --return return exit code of the child process\n"
194 " -f, --flush run flush after each write\n"
195 " --force use output file even when it is a link\n"
aefe9893 196 " -o, --output-limit <size> terminate if output files exceed size\n"
3cf274c9
AO
197 " -q, --quiet be quiet\n"
198 " -t[<file>], --timing[=<file>] output timing data to stderr or to FILE\n"
b3054454 199 ), out);
3cf274c9 200 printf(USAGE_HELP_OPTIONS(31));
3ff52639 201
f45f3ec3 202 printf(USAGE_MAN_TAIL("script(1)"));
86be6a32 203 exit(EXIT_SUCCESS);
3ff52639
SK
204}
205
596f4202
KZ
206static struct script_log *get_log_by_name(struct script_stream *stream,
207 const char *name)
4d9b788d 208{
596f4202 209 size_t i;
4d9b788d 210
596f4202 211 for (i = 0; i < stream->nlogs; i++) {
9f822648
KZ
212 struct script_log *log = stream->logs[i];
213 if (strcmp(log->filename, name) == 0)
596f4202
KZ
214 return log;
215 }
216 return NULL;
217}
4d9b788d 218
596f4202
KZ
219static struct script_log *log_associate(struct script_control *ctl,
220 struct script_stream *stream,
221 const char *filename, int format)
222{
223 struct script_log *log;
224
9f822648
KZ
225 assert(ctl);
226 assert(filename);
227 assert(stream);
228
229 log = get_log_by_name(stream, filename);
230 if (log)
231 return log; /* already defined */
232
233 log = get_log_by_name(stream == &ctl->out ? &ctl->in : &ctl->out, filename);
596f4202
KZ
234 if (!log) {
235 /* create a new log */
9f822648
KZ
236 log = xcalloc(1, sizeof(*log));
237 log->filename = xstrdup(filename);
596f4202
KZ
238 log->format = format;
239 }
4d9b788d 240
9f822648
KZ
241 /* add log to the stream */
242 stream->logs = xrealloc(stream->logs,
243 (stream->nlogs + 1) * sizeof(log));
244 stream->logs[stream->nlogs] = log;
245 stream->nlogs++;
246
596f4202
KZ
247 return log;
248}
4d9b788d 249
d805688a 250static void log_close(struct script_control *ctl __attribute__((unused)),
596f4202
KZ
251 struct script_log *log,
252 const char *msg,
253 int status)
254{
255 DBG(MISC, ul_debug("closing %s", log->filename));
4d9b788d 256
596f4202
KZ
257 switch (log->format) {
258 case SCRIPT_FMT_RAW:
259 {
260 char buf[FORMAT_TIMESTAMP_MAX];
261 time_t tvec = script_time((time_t *)NULL);
4d9b788d 262
596f4202
KZ
263 strtime_iso(&tvec, ISO_TIMESTAMP, buf, sizeof(buf));
264 if (msg)
265 fprintf(log->fp, _("\nScript done on %s [<%s>]\n"), buf, msg);
266 else
267 fprintf(log->fp, _("\nScript done on %s [COMMAND_EXIT_CODE=\"%d\"]\n"), buf, status);
596f4202
KZ
268 break;
269 }
270 case SCRIPT_FMT_TIMING_SIMPLE:
271 break;
272 }
273
274 if (close_stream(log->fp) != 0)
275 err(EXIT_FAILURE, "write failed: %s", log->filename);
4d9b788d 276
596f4202 277 log->fp = NULL;
4d9b788d
KZ
278}
279
596f4202
KZ
280static void log_start(struct script_control *ctl,
281 struct script_log *log)
6343ee8c 282{
6343ee8c 283
596f4202 284 assert(log->fp == NULL);
6343ee8c 285
596f4202 286 DBG(MISC, ul_debug("opening %s", log->filename));
6343ee8c 287
596f4202
KZ
288 /* open the log */
289 log->fp = fopen(log->filename,
290 ctl->append && log->format == SCRIPT_FMT_RAW ?
291 "a" UL_CLOEXECSTR :
292 "w" UL_CLOEXECSTR);
293 if (!log->fp) {
294 restore_tty(ctl, TCSANOW);
295 warn(_("cannot open %s"), log->filename);
296 fail(ctl);
297 }
6343ee8c 298
596f4202
KZ
299 /* write header, etc. */
300 switch (log->format) {
301 case SCRIPT_FMT_RAW:
302 {
303 char buf[FORMAT_TIMESTAMP_MAX];
304 time_t tvec = script_time((time_t *)NULL);
305
306 strtime_iso(&tvec, ISO_TIMESTAMP, buf, sizeof(buf));
307 fprintf(log->fp, _("Script started on %s ["), buf);
308
309 if (ctl->isterm) {
310 int cols = 0, lines = 0;
311 const char *tty = NULL, *term = NULL;
312
313 get_terminal_dimension(&cols, &lines);
314 get_terminal_name(&tty, NULL, NULL);
315 get_terminal_type(&term);
316
317 if (term)
318 fprintf(log->fp, "TERM=\"%s\" ", term);
319 if (tty)
320 fprintf(log->fp, "TTY=\"%s\" ", tty);
321
322 fprintf(log->fp, "COLUMNS=\"%d\" LINES=\"%d\"", cols, lines);
323 } else
324 fprintf(log->fp, _("<not executed on terminal>"));
325
326 fputs("]\n", log->fp);
327 break;
328 }
329 case SCRIPT_FMT_TIMING_SIMPLE:
330 gettime_monotonic(&log->oldtime);
331 break;
332 }
333}
334
335static size_t log_write(struct script_control *ctl,
336 struct script_log *log,
337 char *obuf, size_t bytes)
338{
339 if (!log->fp)
340 return 0;
341
342 DBG(IO, ul_debug(" writining %s", log->filename));
343
344 switch (log->format) {
345 case SCRIPT_FMT_RAW:
346 if (fwrite_all(obuf, 1, bytes, log->fp)) {
347 warn(_("cannot write %s"), log->filename);
348 fail(ctl);
349 }
350 break;
351 case SCRIPT_FMT_TIMING_SIMPLE:
352 {
353 struct timeval now, delta;
354 int sz;
355
356 DBG(IO, ul_debug(" writing timing info"));
357
358 gettime_monotonic(&now);
359 timersub(&now, &log->oldtime, &delta);
360 sz = fprintf(log->fp, "%ld.%06ld %zd\n",
361 (long)delta.tv_sec, (long)delta.tv_usec, bytes);
362 log->oldtime = now;
363 bytes = sz > 0 ? sz : 0;
364 break;
365 }
366 default:
367 break;
368 }
369
370 if (ctl->flush)
371 fflush(log->fp);
372
373 return bytes;
6343ee8c
KZ
374}
375
596f4202
KZ
376static uint64_t log_stream_activity(
377 struct script_control *ctl,
378 struct script_stream *stream,
379 char *buf, size_t bytes)
380{
381 size_t i;
382 uint64_t outsz = 0;
383
384 for (i = 0; i < stream->nlogs; i++)
9f822648 385 outsz += log_write(ctl, stream->logs[i], buf, bytes);
596f4202
KZ
386
387 return outsz;
388}
389
390
391static void die_if_link(struct script_control *ctl, const char *filename)
93af8d8b
SK
392{
393 struct stat s;
6dbe3af9 394
3f19b85f 395 if (ctl->force)
93af8d8b 396 return;
596f4202 397 if (lstat(filename, &s) == 0 && (S_ISLNK(s.st_mode) || s.st_nlink > 1))
93af8d8b
SK
398 errx(EXIT_FAILURE,
399 _("output file `%s' is a link\n"
400 "Use --force if you really want to use it.\n"
596f4202 401 "Program not started."), filename);
93af8d8b 402}
fd4c1f63 403
8198052c
SK
404static void restore_tty(struct script_control *ctl, int mode)
405{
406 struct termios rtt;
407
408 if (!ctl->isterm)
409 return;
410
411 rtt = ctl->attrs;
412 tcsetattr(STDIN_FILENO, mode, &rtt);
413}
414
7fb65db1
KZ
415static void enable_rawmode_tty(struct script_control *ctl)
416{
417 struct termios rtt;
418
419 if (!ctl->isterm)
420 return;
421
422 rtt = ctl->attrs;
423 cfmakeraw(&rtt);
424 rtt.c_lflag &= ~ECHO;
425 tcsetattr(STDIN_FILENO, TCSANOW, &rtt);
426}
427
596f4202 428static void __attribute__((__noreturn__)) done_log(struct script_control *ctl, const char *msg)
93af8d8b 429{
596f4202
KZ
430 int status;
431 size_t i;
6343ee8c 432
a2b4dec5
KZ
433 DBG(MISC, ul_debug("done!"));
434
8198052c
SK
435 restore_tty(ctl, TCSADRAIN);
436
6343ee8c 437 if (WIFSIGNALED(ctl->childstatus))
596f4202 438 status = WTERMSIG(ctl->childstatus) + 0x80;
6343ee8c 439 else
596f4202
KZ
440 status = WEXITSTATUS(ctl->childstatus);
441
442
443 DBG(MISC, ul_debug(" status=%d", status));
444
445 /* close all output logs */
446 for (i = 0; i < ctl->out.nlogs; i++)
9f822648 447 log_close(ctl, ctl->out.logs[i], msg, status);
596f4202
KZ
448
449 /* close all input logs */
450 for (i = 0; i < ctl->in.nlogs; i++)
9f822648 451 log_close(ctl, ctl->in.logs[i], msg, status);
93df6a58 452
d805688a
KZ
453 if (!ctl->quiet)
454 printf(_("Script done.\n"));
455
f0bc3fa0 456#ifdef HAVE_LIBUTEMPTER
6ddf53a5
SK
457 if (ctl->master >= 0)
458 utempter_remove_record(ctl->master);
f0bc3fa0 459#endif
6ddf53a5 460 kill(ctl->child, SIGTERM); /* make sure we don't create orphans */
596f4202 461 exit(ctl->rc_wanted ? status : EXIT_SUCCESS);
6343ee8c
KZ
462}
463
464static void __attribute__((__noreturn__)) done(struct script_control *ctl)
465{
466 done_log(ctl, NULL);
93af8d8b 467}
5c36a0eb 468
2ddadb5e 469static void __attribute__((__noreturn__)) fail(struct script_control *ctl)
edc7e420 470{
a2b4dec5 471 DBG(MISC, ul_debug("fail!"));
93af8d8b 472 kill(0, SIGTERM);
edc7e420 473 done(ctl);
6dbe3af9
KZ
474}
475
5860c45e 476static void wait_for_child(struct script_control *ctl, int wait)
93af8d8b
SK
477{
478 int status;
479 pid_t pid;
93af8d8b
SK
480 int options = wait ? 0 : WNOHANG;
481
a2b4dec5
KZ
482 DBG(MISC, ul_debug("waiting for child"));
483
b09feab9 484 while ((pid = wait3(&status, options, NULL)) > 0)
89a859d4 485 if (pid == ctl->child)
edc7e420 486 ctl->childstatus = status;
93af8d8b
SK
487}
488
596f4202 489/* data from master to stdout */
cf470183 490static void write_output(struct script_control *ctl, char *obuf,
04639805 491 ssize_t bytes)
93af8d8b 492{
a2b4dec5
KZ
493 DBG(IO, ul_debug(" writing to output"));
494
cf470183 495 if (write_all(STDOUT_FILENO, obuf, bytes)) {
54c6611d 496 DBG(IO, ul_debug(" writing output *failed*"));
cf470183
SK
497 warn(_("write failed"));
498 fail(ctl);
499 }
54c6611d
KZ
500}
501
b2bff066
KZ
502static int write_to_shell(struct script_control *ctl,
503 char *buf, size_t bufsz)
54c6611d 504{
b2bff066 505 return write_all(ctl->master, buf, bufsz);
54c6611d
KZ
506}
507
508/*
23e35eca
RM
509 * The script(1) is usually faster than shell, so it's a good idea to wait until
510 * the previous message has been already read by shell from slave before we
511 * write to master. This is necessary especially for EOF situation when we can
54c6611d
KZ
512 * send EOF to master before shell is fully initialized, to workaround this
513 * problem we wait until slave is empty. For example:
514 *
515 * echo "date" | script
b2bff066
KZ
516 *
517 * Unfortunately, the child (usually shell) can ignore stdin at all, so we
518 * don't wait forever to avoid dead locks...
519 *
520 * Note that script is primarily designed for interactive sessions as it
521 * maintains master+slave tty stuff within the session. Use pipe to write to
522 * script(1) and assume non-interactive (tee-like) behavior is NOT well
523 * supported.
54c6611d 524 */
54c6611d
KZ
525static void write_eof_to_shell(struct script_control *ctl)
526{
b2bff066
KZ
527 unsigned int tries = 0;
528 struct pollfd fds[] = {
529 { .fd = ctl->slave, .events = POLLIN }
530 };
54c6611d
KZ
531 char c = DEF_EOF;
532
b2bff066
KZ
533 DBG(IO, ul_debug(" waiting for empty slave"));
534 while (poll(fds, 1, 10) == 1 && tries < 8) {
535 DBG(IO, ul_debug(" slave is not empty"));
536 xusleep(250000);
537 tries++;
538 }
539 if (tries < 8)
540 DBG(IO, ul_debug(" slave is empty now"));
541
54c6611d
KZ
542 DBG(IO, ul_debug(" sending EOF to master"));
543 write_to_shell(ctl, &c, sizeof(char));
364cda48
KZ
544}
545
54c6611d 546static void handle_io(struct script_control *ctl, int fd, int *eof)
93af8d8b 547{
6ddf53a5 548 char buf[BUFSIZ];
a8896ad5 549 ssize_t bytes;
a2b4dec5 550 DBG(IO, ul_debug("%d FD active", fd));
54c6611d 551 *eof = 0;
a2b4dec5 552
da26af4e 553 /* read from active FD */
a8896ad5
SK
554 bytes = read(fd, buf, sizeof(buf));
555 if (bytes < 0) {
54c6611d 556 if (errno == EAGAIN || errno == EINTR)
a8896ad5
SK
557 return;
558 fail(ctl);
559 }
da26af4e 560
54c6611d 561 if (bytes == 0) {
7dbcd80e 562 *eof = 1;
54c6611d
KZ
563 return;
564 }
565
da26af4e
KZ
566 /* from stdin (user) to command */
567 if (fd == STDIN_FILENO) {
2e9418b7 568 DBG(IO, ul_debug(" stdin --> master %zd bytes", bytes));
a2b4dec5 569
54c6611d 570 if (write_to_shell(ctl, buf, bytes)) {
a8896ad5
SK
571 warn(_("write failed"));
572 fail(ctl);
573 }
574 /* without sync write_output() will write both input &
575 * shell output that looks like double echoing */
576 fdatasync(ctl->master);
596f4202 577 ctl->outsz += log_stream_activity(ctl, &ctl->in, buf, (size_t) bytes);
da26af4e 578
aefe9893 579 /* from command (master) to stdout and log */
a2b4dec5 580 } else if (fd == ctl->master) {
2e9418b7 581 DBG(IO, ul_debug(" master --> stdout %zd bytes", bytes));
04639805 582 write_output(ctl, buf, bytes);
596f4202
KZ
583 ctl->outsz += log_stream_activity(ctl, &ctl->out, buf, (size_t) bytes);
584 }
aefe9893 585
596f4202
KZ
586 /* check output limit */
587 if (ctl->maxsz != 0 && ctl->outsz >= ctl->maxsz) {
588 if (!ctl->quiet)
589 printf(_("Script terminated, max output files size %"PRIu64" exceeded.\n"), ctl->maxsz);
590 DBG(IO, ul_debug("output size %"PRIu64", exceeded limit %"PRIu64, ctl->outsz, ctl->maxsz));
591 done_log(ctl, _("max output size exceeded"));
a2b4dec5 592 }
a8896ad5
SK
593}
594
595static void handle_signal(struct script_control *ctl, int fd)
596{
597 struct signalfd_siginfo info;
598 ssize_t bytes;
599
a2b4dec5
KZ
600 DBG(SIGNAL, ul_debug("signal FD %d active", fd));
601
a8896ad5 602 bytes = read(fd, &info, sizeof(info));
d35ffe80 603 if (bytes != sizeof(info)) {
7dbcd80e 604 if (bytes < 0 && (errno == EAGAIN || errno == EINTR))
d35ffe80
KZ
605 return;
606 fail(ctl);
607 }
da26af4e 608
a8896ad5
SK
609 switch (info.ssi_signo) {
610 case SIGCHLD:
27afe501
KZ
611 DBG(SIGNAL, ul_debug(" get signal SIGCHLD [ssi_code=%d, ssi_status=%d]",
612 info.ssi_code, info.ssi_status));
613 if (info.ssi_code == CLD_EXITED
614 || info.ssi_code == CLD_KILLED
615 || info.ssi_code == CLD_DUMPED) {
2e7a9227
KZ
616 wait_for_child(ctl, 0);
617 ctl->poll_timeout = 10;
27afe501
KZ
618
619 /* In case of ssi_code is CLD_TRAPPED, CLD_STOPPED, or CLD_CONTINUED */
2e7a9227
KZ
620 } else if (info.ssi_status == SIGSTOP && ctl->child) {
621 DBG(SIGNAL, ul_debug(" child stop by SIGSTOP -- stop parent too"));
622 kill(getpid(), SIGSTOP);
623 DBG(SIGNAL, ul_debug(" resume"));
624 kill(ctl->child, SIGCONT);
625 }
a8896ad5
SK
626 return;
627 case SIGWINCH:
b2bff066 628 DBG(SIGNAL, ul_debug(" get signal SIGWINCH"));
a8896ad5
SK
629 if (ctl->isterm) {
630 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
631 ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
632 }
633 break;
5860c45e
KZ
634 case SIGTERM:
635 /* fallthrough */
636 case SIGINT:
637 /* fallthrough */
638 case SIGQUIT:
b2bff066 639 DBG(SIGNAL, ul_debug(" get signal SIG{TERM,INT,QUIT}"));
5860c45e
KZ
640 fprintf(stderr, _("\nSession terminated.\n"));
641 /* Child termination is going to generate SIGCHILD (see above) */
642 kill(ctl->child, SIGTERM);
643 return;
a8896ad5
SK
644 default:
645 abort();
646 }
27afe501 647 DBG(SIGNAL, ul_debug("signal handle on FD %d done", fd));
a8896ad5
SK
648}
649
650static void do_io(struct script_control *ctl)
651{
d88b739f 652 int ret, eof = 0;
596f4202 653 size_t i;
da26af4e 654 enum {
54c6611d 655 POLLFD_SIGNAL = 0,
da26af4e 656 POLLFD_MASTER,
d88b739f 657 POLLFD_STDIN
54c6611d 658
da26af4e
KZ
659 };
660 struct pollfd pfd[] = {
0664d41d
SK
661 [POLLFD_SIGNAL] = { .fd = ctl->sigfd, .events = POLLIN | POLLERR | POLLHUP },
662 [POLLFD_MASTER] = { .fd = ctl->master, .events = POLLIN | POLLERR | POLLHUP },
663 [POLLFD_STDIN] = { .fd = STDIN_FILENO, .events = POLLIN | POLLERR | POLLHUP }
da26af4e
KZ
664 };
665
6dbe3af9 666
596f4202
KZ
667 /* start all output logs */
668 for (i = 0; i < ctl->out.nlogs; i++)
9f822648 669 log_start(ctl, ctl->out.logs[i]);
8198052c 670
596f4202
KZ
671 /* start all input logs */
672 for (i = 0; i < ctl->in.nlogs; i++)
9f822648 673 log_start(ctl, ctl->in.logs[i]);
a5a16c68 674
6ddf53a5 675 while (!ctl->die) {
da26af4e 676 size_t i;
7dbcd80e 677 int errsv;
da26af4e 678
a2b4dec5
KZ
679 DBG(POLL, ul_debug("calling poll()"));
680
cf470183 681 /* wait for input or signal */
d88b739f 682 ret = poll(pfd, ARRAY_SIZE(pfd), ctl->poll_timeout);
7dbcd80e 683 errsv = errno;
a2b4dec5
KZ
684 DBG(POLL, ul_debug("poll() rc=%d", ret));
685
cf470183 686 if (ret < 0) {
7dbcd80e 687 if (errsv == EAGAIN)
cf470183
SK
688 continue;
689 warn(_("poll failed"));
edc7e420 690 fail(ctl);
36c1d79b 691 }
a2b4dec5
KZ
692 if (ret == 0) {
693 DBG(POLL, ul_debug("setting die=1"));
89a859d4 694 ctl->die = 1;
5860c45e 695 break;
a2b4dec5 696 }
da26af4e 697
d88b739f 698 for (i = 0; i < ARRAY_SIZE(pfd); i++) {
cf470183
SK
699 if (pfd[i].revents == 0)
700 continue;
a2b4dec5 701
2e9418b7 702 DBG(POLL, ul_debug(" active pfd[%s].fd=%d %s %s %s",
54c6611d 703 i == POLLFD_STDIN ? "stdin" :
2e9418b7
KZ
704 i == POLLFD_MASTER ? "master" :
705 i == POLLFD_SIGNAL ? "signal" : "???",
706 pfd[i].fd,
54c6611d 707 pfd[i].revents & POLLIN ? "POLLIN" : "",
1200cfbf
KZ
708 pfd[i].revents & POLLHUP ? "POLLHUP" : "",
709 pfd[i].revents & POLLERR ? "POLLERR" : ""));
da26af4e
KZ
710 switch (i) {
711 case POLLFD_STDIN:
712 case POLLFD_MASTER:
54c6611d
KZ
713 /* data */
714 if (pfd[i].revents & POLLIN)
715 handle_io(ctl, pfd[i].fd, &eof);
716 /* EOF maybe detected by two ways:
717 * A) poll() return POLLHUP event after close()
7dbcd80e 718 * B) read() returns 0 (no data) */
54c6611d
KZ
719 if ((pfd[i].revents & POLLHUP) || eof) {
720 DBG(POLL, ul_debug(" ignore FD"));
721 pfd[i].fd = -1;
54c6611d 722 if (i == POLLFD_STDIN) {
54c6611d 723 write_eof_to_shell(ctl);
b2bff066 724 DBG(POLL, ul_debug(" ignore STDIN"));
54c6611d
KZ
725 }
726 }
cf470183 727 continue;
da26af4e 728 case POLLFD_SIGNAL:
a8896ad5 729 handle_signal(ctl, pfd[i].fd);
da26af4e 730 break;
cf470183 731 }
968e632c 732 }
cf470183 733 }
a2b4dec5
KZ
734
735 DBG(POLL, ul_debug("poll() done"));
736
6ddf53a5 737 if (!ctl->die)
5860c45e 738 wait_for_child(ctl, 1);
6f3c9c34 739
6ddf53a5 740 done(ctl);
6dbe3af9
KZ
741}
742
edc7e420 743static void getslave(struct script_control *ctl)
93af8d8b
SK
744{
745#ifndef HAVE_LIBUTIL
edc7e420 746 ctl->line[strlen("/dev/")] = 't';
760e5e68 747 ctl->slave = open(ctl->line, O_RDWR | O_CLOEXEC);
edc7e420
SK
748 if (ctl->slave < 0) {
749 warn(_("cannot open %s"), ctl->line);
750 fail(ctl);
93af8d8b 751 }
edc7e420 752 if (ctl->isterm) {
3f19b85f 753 tcsetattr(ctl->slave, TCSANOW, &ctl->attrs);
edc7e420 754 ioctl(ctl->slave, TIOCSWINSZ, (char *)&ctl->win);
93af8d8b
SK
755 }
756#endif
757 setsid();
edc7e420 758 ioctl(ctl->slave, TIOCSCTTY, 0);
93af8d8b
SK
759}
760
54c6611d 761/* don't use DBG() stuff here otherwise it will be in the typescript file */
d35ffe80 762static void __attribute__((__noreturn__)) do_shell(struct script_control *ctl)
93af8d8b 763{
df1dddf9
KZ
764 char *shname;
765
edc7e420 766 getslave(ctl);
4368e3e6
KZ
767
768 /* close things irrelevant for this process */
edc7e420 769 close(ctl->master);
d35ffe80 770 close(ctl->sigfd);
4368e3e6 771
edc7e420
SK
772 dup2(ctl->slave, STDIN_FILENO);
773 dup2(ctl->slave, STDOUT_FILENO);
774 dup2(ctl->slave, STDERR_FILENO);
775 close(ctl->slave);
df1dddf9 776
edc7e420 777 ctl->master = -1;
f0bc3fa0 778
edc7e420 779 shname = strrchr(ctl->shell, '/');
df1dddf9
KZ
780 if (shname)
781 shname++;
782 else
edc7e420 783 shname = ctl->shell;
df1dddf9 784
d35ffe80
KZ
785 sigprocmask(SIG_SETMASK, &ctl->sigorg, NULL);
786
a17f3264
KZ
787 /*
788 * When invoked from within /etc/csh.login, script spawns a csh shell
789 * that spawns programs that cannot be killed with a SIGTERM. This is
ee312c65 790 * because csh has a documented behavior wherein it disables all
a17f3264
KZ
791 * signals when processing the /etc/csh.* files.
792 *
793 * Let's restore the default behavior.
794 */
795 signal(SIGTERM, SIG_DFL);
796
edc7e420 797 if (access(ctl->shell, X_OK) == 0) {
3f19b85f
KZ
798 if (ctl->command)
799 execl(ctl->shell, shname, "-c", ctl->command, NULL);
b4ff2f54 800 else
edc7e420 801 execl(ctl->shell, shname, "-i", NULL);
b4ff2f54 802 } else {
3f19b85f
KZ
803 if (ctl->command)
804 execlp(shname, "-c", ctl->command, NULL);
b4ff2f54
SK
805 else
806 execlp(shname, "-i", NULL);
807 }
edc7e420
SK
808 warn(_("failed to execute %s"), ctl->shell);
809 fail(ctl);
6dbe3af9
KZ
810}
811
6dbe3af9 812
edc7e420 813static void getmaster(struct script_control *ctl)
93af8d8b 814{
e11a5e63 815#if defined(HAVE_LIBUTIL) && defined(HAVE_PTY_H)
3822032d
KZ
816 int rc;
817
edc7e420 818 ctl->isterm = isatty(STDIN_FILENO);
3822032d 819
edc7e420 820 if (ctl->isterm) {
3f19b85f 821 if (tcgetattr(STDIN_FILENO, &ctl->attrs) != 0)
3822032d 822 err(EXIT_FAILURE, _("failed to get terminal attributes"));
edc7e420 823 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
3f19b85f 824 rc = openpty(&ctl->master, &ctl->slave, NULL, &ctl->attrs, &ctl->win);
3822032d 825 } else
edc7e420 826 rc = openpty(&ctl->master, &ctl->slave, NULL, NULL, NULL);
3822032d
KZ
827
828 if (rc < 0) {
360d5005 829 warn(_("openpty failed"));
edc7e420 830 fail(ctl);
5c36a0eb
KZ
831 }
832#else
6dbe3af9 833 char *pty, *bank, *cp;
6dbe3af9 834
edc7e420 835 ctl->isterm = isatty(STDIN_FILENO);
3822032d 836
edc7e420 837 pty = &ctl->line[strlen("/dev/ptyp")];
6dbe3af9 838 for (bank = "pqrs"; *bank; bank++) {
edc7e420 839 ctl->line[strlen("/dev/pty")] = *bank;
6dbe3af9 840 *pty = '0';
a4aeb5bd 841 if (access(ctl->line, F_OK) != 0)
6dbe3af9
KZ
842 break;
843 for (cp = "0123456789abcdef"; *cp; cp++) {
844 *pty = *cp;
760e5e68 845 ctl->master = open(ctl->line, O_RDWR | O_CLOEXEC);
edc7e420
SK
846 if (ctl->master >= 0) {
847 char *tp = &ctl->line[strlen("/dev/")];
6dbe3af9
KZ
848 int ok;
849
850 /* verify slave side is usable */
851 *tp = 't';
edc7e420 852 ok = access(ctl->line, R_OK | W_OK) == 0;
6dbe3af9
KZ
853 *tp = 'p';
854 if (ok) {
edc7e420 855 if (ctl->isterm) {
3f19b85f 856 tcgetattr(STDIN_FILENO, &ctl->attrs);
edc7e420 857 ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ctl->win);
3822032d 858 }
6dbe3af9
KZ
859 return;
860 }
edc7e420
SK
861 close(ctl->master);
862 ctl->master = -1;
6dbe3af9
KZ
863 }
864 }
865 }
edc7e420 866 ctl->master = -1;
360d5005 867 warn(_("out of pty's"));
edc7e420
SK
868 fail(ctl);
869#endif /* not HAVE_LIBUTIL */
54c6611d
KZ
870
871 DBG(IO, ul_debug("master fd: %d", ctl->master));
6dbe3af9
KZ
872}
873
93af8d8b
SK
874int main(int argc, char **argv)
875{
edc7e420
SK
876 struct script_control ctl = {
877#if !HAVE_LIBUTIL || !HAVE_PTY_H
878 .line = "/dev/ptyXX",
879#endif
880 .master = -1,
596f4202
KZ
881 .slave = -1,
882
aefe9893 883 .poll_timeout = -1
edc7e420 884 };
93af8d8b 885 int ch;
596f4202 886 const char *typescript = DEFAULT_TYPESCRIPT_FILENAME;
d805688a 887 const char *timingfile = NULL;
93af8d8b
SK
888
889 enum { FORCE_OPTION = CHAR_MAX + 1 };
890
891 static const struct option longopts[] = {
edc7e420
SK
892 {"append", no_argument, NULL, 'a'},
893 {"command", required_argument, NULL, 'c'},
894 {"return", no_argument, NULL, 'e'},
895 {"flush", no_argument, NULL, 'f'},
896 {"force", no_argument, NULL, FORCE_OPTION,},
aefe9893 897 {"output-limit", required_argument, NULL, 'o'},
edc7e420
SK
898 {"quiet", no_argument, NULL, 'q'},
899 {"timing", optional_argument, NULL, 't'},
900 {"version", no_argument, NULL, 'V'},
901 {"help", no_argument, NULL, 'h'},
902 {NULL, 0, NULL, 0}
93af8d8b
SK
903 };
904
905 setlocale(LC_ALL, "");
b09feab9
SK
906 /*
907 * script -t prints time delays as floating point numbers. The example
908 * program (scriptreplay) that we provide to handle this timing output
909 * is a perl script, and does not handle numbers in locale format (not
910 * even when "use locale;" is added). So, since these numbers are not
911 * for human consumption, it seems easiest to set LC_NUMERIC here.
912 */
913 setlocale(LC_NUMERIC, "C");
93af8d8b
SK
914 bindtextdomain(PACKAGE, LOCALEDIR);
915 textdomain(PACKAGE);
2c308875 916 close_stdout_atexit();
93af8d8b 917
a2b4dec5
KZ
918 script_init_debug();
919
aefe9893 920 while ((ch = getopt_long(argc, argv, "ac:efo:qt::Vh", longopts, NULL)) != -1)
edc7e420 921 switch (ch) {
93af8d8b 922 case 'a':
3f19b85f 923 ctl.append = 1;
93af8d8b
SK
924 break;
925 case 'c':
3f19b85f 926 ctl.command = optarg;
93af8d8b
SK
927 break;
928 case 'e':
7e5796c9 929 ctl.rc_wanted = 1;
93af8d8b
SK
930 break;
931 case 'f':
3f19b85f 932 ctl.flush = 1;
93af8d8b
SK
933 break;
934 case FORCE_OPTION:
3f19b85f 935 ctl.force = 1;
93af8d8b 936 break;
aefe9893
FM
937 case 'o':
938 ctl.maxsz = strtosize_or_err(optarg, _("failed to parse output limit size"));
939 break;
93af8d8b 940 case 'q':
3f19b85f 941 ctl.quiet = 1;
93af8d8b
SK
942 break;
943 case 't':
4f7521d6
KZ
944 if (optarg && *optarg == '=')
945 optarg++;
596f4202
KZ
946 log_associate(&ctl, &ctl.out,
947 optarg ? optarg : "/dev/stderr",
948 SCRIPT_FMT_TIMING_SIMPLE);
d805688a
KZ
949 /* used for message only */
950 timingfile = optarg ? optarg : "stderr";
93af8d8b 951 break;
2c308875 952
93af8d8b 953 case 'V':
2c308875 954 print_version(EXIT_SUCCESS);
93af8d8b 955 case 'h':
86be6a32 956 usage();
93af8d8b 957 default:
677ec86c 958 errtryhelp(EXIT_FAILURE);
93af8d8b
SK
959 }
960 argc -= optind;
961 argv += optind;
962
963 if (argc > 0)
596f4202
KZ
964 typescript = argv[0];
965 else
966 die_if_link(&ctl, DEFAULT_TYPESCRIPT_FILENAME);
967
968 /* associate stdout with typescript file */
969 log_associate(&ctl, &ctl.out, typescript, SCRIPT_FMT_RAW);
93af8d8b 970
edc7e420
SK
971 ctl.shell = getenv("SHELL");
972 if (ctl.shell == NULL)
973 ctl.shell = _PATH_BSHELL;
93af8d8b 974
edc7e420 975 getmaster(&ctl);
d805688a
KZ
976 if (!ctl.quiet) {
977 if (!timingfile)
978 printf(_("Script started, log file is '%s'.\n"), typescript);
979 else
980 printf(_("Script started, log file is '%s', timing file is '%s'.\n"),
981 typescript, timingfile);
982 }
7fb65db1 983 enable_rawmode_tty(&ctl);
93af8d8b
SK
984
985#ifdef HAVE_LIBUTEMPTER
edc7e420 986 utempter_add_record(ctl.master, NULL);
5c36a0eb 987#endif
cc1a88fb 988 /* setup signal handler */
d35ffe80
KZ
989 sigemptyset(&ctl.sigset);
990 sigaddset(&ctl.sigset, SIGCHLD);
991 sigaddset(&ctl.sigset, SIGWINCH);
5860c45e
KZ
992 sigaddset(&ctl.sigset, SIGTERM);
993 sigaddset(&ctl.sigset, SIGINT);
994 sigaddset(&ctl.sigset, SIGQUIT);
d35ffe80
KZ
995
996 /* block signals used for signalfd() to prevent the signals being
997 * handled according to their default dispositions */
998 sigprocmask(SIG_BLOCK, &ctl.sigset, &ctl.sigorg);
a2b4dec5 999
760e5e68 1000 if ((ctl.sigfd = signalfd(-1, &ctl.sigset, SFD_CLOEXEC)) < 0)
cc1a88fb 1001 err(EXIT_FAILURE, _("cannot set signal handler"));
93af8d8b 1002
a2b4dec5
KZ
1003 DBG(SIGNAL, ul_debug("signal fd=%d", ctl.sigfd));
1004
93af8d8b 1005 fflush(stdout);
edc7e420 1006 ctl.child = fork();
93af8d8b 1007
d35ffe80
KZ
1008 switch (ctl.child) {
1009 case -1: /* error */
93af8d8b 1010 warn(_("fork failed"));
edc7e420 1011 fail(&ctl);
d35ffe80
KZ
1012 break;
1013 case 0: /* child */
1014 do_shell(&ctl);
1015 break;
1016 default: /* parent */
1017 do_io(&ctl);
1018 break;
93af8d8b 1019 }
d35ffe80
KZ
1020
1021 /* should not happen, all used functions are non-return */
b09feab9 1022 return EXIT_FAILURE;
6dbe3af9 1023}