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