summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bash-completion/script1
-rw-r--r--term-utils/script.113
-rw-r--r--term-utils/script.c33
-rw-r--r--tests/expected/script/options-size9
-rwxr-xr-xtests/ts/script/options7
-rwxr-xr-xtests/ts/script/race2
6 files changed, 58 insertions, 7 deletions
diff --git a/bash-completion/script b/bash-completion/script
index d7efd7e7c..57b91a9eb 100644
--- a/bash-completion/script
+++ b/bash-completion/script
@@ -25,6 +25,7 @@ _script_module()
--flush
--force
--quiet
+ --output-limit
--timing=
--version
--help"
diff --git a/term-utils/script.1 b/term-utils/script.1
index 6c50bc621..041b7620b 100644
--- a/term-utils/script.1
+++ b/term-utils/script.1
@@ -54,6 +54,10 @@ saves the dialogue in this
If no filename is given, the dialogue is saved in the file
.BR typescript .
.SH OPTIONS
+Below, the \fIsize\fR argument may be followed by the multiplicative
+suffixes KiB (=1024), MiB (=1024*1024), and so on for GiB, TiB, PiB, EiB, ZiB and YiB
+(the "iB" is optional, e.g. "K" has the same meaning as "KiB"), or the suffixes
+KB (=1000), MB (=1000*1000), and so on for GB, TB, PB, EB, ZB and YB.
.TP
\fB\-a\fR, \fB\-\-append\fR
Append the output to
@@ -82,6 +86,15 @@ being done using `cat foo'.
Allow the default output destination, i.e. the typescript file, to be a hard
or symbolic link. The command will follow a symbolic link.
.TP
+\fB\-o\fR, \fB\-\-output-limit\fR \fIsize\fR
+Limit the size of the typescript and timing files to
+.I size
+and stop the child process after this size is exceeded. The calculated
+file size does not include the start and done messages that the
+.B script
+command prepends and appends to the child process output.
+Due to buffering, the resulting output file might be larger than the specified value.
+.TP
\fB\-q\fR, \fB\-\-quiet\fR
Be quiet (do not write start and done messages to standard output).
.TP
diff --git a/term-utils/script.c b/term-utils/script.c
index d5ffa27f1..102f7ec32 100644
--- a/term-utils/script.c
+++ b/term-utils/script.c
@@ -71,6 +71,7 @@
#include "all-io.h"
#include "monotonic.h"
#include "timeutils.h"
+#include "strutils.h"
#include "debug.h"
@@ -104,6 +105,8 @@ struct script_control {
FILE *typescriptfp; /* output file pointer */
char *tname; /* timing file path */
FILE *timingfp; /* timing file pointer */
+ ssize_t outsz; /* current output file size */
+ ssize_t maxsz; /* maximum output file size */
struct timeval oldtime; /* previous write or command start time */
int master; /* pseudoterminal master file descriptor */
int slave; /* pseudoterminal slave file descriptor */
@@ -169,6 +172,7 @@ static void __attribute__((__noreturn__)) usage(void)
" -e, --return return exit code of the child process\n"
" -f, --flush run flush after each write\n"
" --force use output file even when it is a link\n"
+ " -o, --output-limit <size> terminate if output files exceed size\n"
" -q, --quiet be quiet\n"
" -t[<file>], --timing[=<file>] output timing data to stderr or to FILE\n"
), out);
@@ -266,6 +270,8 @@ static void wait_for_child(struct script_control *ctl, int wait)
static void write_output(struct script_control *ctl, char *obuf,
ssize_t bytes)
{
+ int timing_bytes = 0;
+
DBG(IO, ul_debug(" writing output"));
if (ctl->timing && ctl->timingfp) {
@@ -275,11 +281,13 @@ static void write_output(struct script_control *ctl, char *obuf,
gettime_monotonic(&now);
timersub(&now, &ctl->oldtime, &delta);
- fprintf(ctl->timingfp, "%ld.%06ld %zd\n",
+ timing_bytes = fprintf(ctl->timingfp, "%ld.%06ld %zd\n",
(long)delta.tv_sec, (long)delta.tv_usec, bytes);
if (ctl->flush)
fflush(ctl->timingfp);
ctl->oldtime = now;
+ if (timing_bytes < 0)
+ timing_bytes = 0;
}
DBG(IO, ul_debug(" writing to script file"));
@@ -299,6 +307,9 @@ static void write_output(struct script_control *ctl, char *obuf,
fail(ctl);
}
+ if (ctl->maxsz != 0)
+ ctl->outsz += bytes + timing_bytes;
+
DBG(IO, ul_debug(" writing output *done*"));
}
@@ -350,7 +361,6 @@ static void handle_io(struct script_control *ctl, int fd, int *eof)
{
char buf[BUFSIZ];
ssize_t bytes;
-
DBG(IO, ul_debug("%d FD active", fd));
*eof = 0;
@@ -379,10 +389,18 @@ static void handle_io(struct script_control *ctl, int fd, int *eof)
* shell output that looks like double echoing */
fdatasync(ctl->master);
- /* from command (master) to stdout */
+ /* from command (master) to stdout and log */
} else if (fd == ctl->master) {
DBG(IO, ul_debug(" master --> stdout %zd bytes", bytes));
write_output(ctl, buf, bytes);
+
+ /* check output limit */
+ if (ctl->maxsz != 0 && ctl->outsz >= ctl->maxsz) {
+ if (!ctl->quiet)
+ printf(_("Script terminated, max output file size %zd exceeded.\n"), ctl->maxsz);
+ DBG(IO, ul_debug("output size %zd, exceeded limit %zd", ctl->outsz, ctl->maxsz));
+ done(ctl);
+ }
}
}
@@ -688,8 +706,7 @@ int main(int argc, char **argv)
.line = "/dev/ptyXX",
#endif
.master = -1,
- .poll_timeout = -1,
- 0
+ .poll_timeout = -1
};
int ch;
@@ -701,6 +718,7 @@ int main(int argc, char **argv)
{"return", no_argument, NULL, 'e'},
{"flush", no_argument, NULL, 'f'},
{"force", no_argument, NULL, FORCE_OPTION,},
+ {"output-limit", required_argument, NULL, 'o'},
{"quiet", no_argument, NULL, 'q'},
{"timing", optional_argument, NULL, 't'},
{"version", no_argument, NULL, 'V'},
@@ -723,7 +741,7 @@ int main(int argc, char **argv)
script_init_debug();
- while ((ch = getopt_long(argc, argv, "ac:efqt::Vh", longopts, NULL)) != -1)
+ while ((ch = getopt_long(argc, argv, "ac:efo:qt::Vh", longopts, NULL)) != -1)
switch (ch) {
case 'a':
ctl.append = 1;
@@ -740,6 +758,9 @@ int main(int argc, char **argv)
case FORCE_OPTION:
ctl.force = 1;
break;
+ case 'o':
+ ctl.maxsz = strtosize_or_err(optarg, _("failed to parse output limit size"));
+ break;
case 'q':
ctl.quiet = 1;
break;
diff --git a/tests/expected/script/options-size b/tests/expected/script/options-size
new file mode 100644
index 000000000..6121181e2
--- /dev/null
+++ b/tests/expected/script/options-size
@@ -0,0 +1,9 @@
+Script started on 2015-05-24 17:43:18+00:00
+1:1234567890
+
+Script done on 2015-05-24 17:43:18+00:00
+Script started on 2015-05-24 17:43:18+00:00
+2:1234567890
+
+Script done on 2015-05-24 17:43:18+00:00
+0
diff --git a/tests/ts/script/options b/tests/ts/script/options
index 2656c4238..67a8b444d 100755
--- a/tests/ts/script/options
+++ b/tests/ts/script/options
@@ -57,4 +57,11 @@ $TS_HELPER_SCRIPT --return --append -c "exit 127" $TS_OUTPUT </dev/null >/dev/nu
echo $? >> $TS_OUTPUT
ts_finalize_subtest
+ts_init_subtest "size"
+$TS_HELPER_SCRIPT --output-limit 9 --command "echo 1:1234567890" $TS_OUTPUT </dev/null >/dev/null 2>&1
+$TS_HELPER_SCRIPT -a -o 9 --command "echo 2:1234567890" $TS_OUTPUT </dev/null >/dev/null 2>&1
+echo $? >> $TS_OUTPUT
+cp /home/fmora/u/src/util-linux/tests/output/script/options-size /tmp
+ts_finalize_subtest
+
ts_finalize
diff --git a/tests/ts/script/race b/tests/ts/script/race
index 86e383814..2c26b89fc 100755
--- a/tests/ts/script/race
+++ b/tests/ts/script/race
@@ -36,7 +36,7 @@ for i in `seq 1 $count`; do
done | grep -c Bingo >> $TS_OUTPUT
seen=$(<$TS_OUTPUT)
-if [ $seen = $count ]; then
+if [ "$seen" = "$count" ]; then
echo "all bingos seen" > $TS_OUTPUT
else
echo "only $seen of $count bingos seen" > $TS_OUTPUT