New scriptreplay is out-of-sync (longish)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Reproduction steps:

1. Run "script -t 2>timing".
2. When the prompt comes up, hit return.
3. New prompt. Wait several seconds, then type "true" and hit return.
4. Repeat (3) as desired, then exit scripted shell.
5. Run "scriptreplay timing".

You'll find on the replay that, rather than waiting several seconds
between the prompt and true, the wait will actually occur after the
first "t" of true.

- -= explanation =-

One way of looking at this is that this functionality was broken by the
reimplementation in C.

Another position, at least as equally viable, is that
script/scriptreplay was never really quite working right in the first place.

The source of the issue is that the C scriptreplay is expecting script
to behave in a common-sense way, as it is documented to do, when in fact
it has never behaved in such a way.

If you look carefully at the dooutput() function in script.c, you'll see
 that the following pseudocode sums up the situation, as far as timing goes:

oldtime = now() // via time()
do:
    newtime = now() // via gettimeofday()
    bytes_read = do_nonblocking_read()
    fprintf(timingfile, "%f %d\n", newtime - oldtime, bytes_read)
    print read-block to output
while (read was successful)

You'll notice, perhaps, that both newtime and oldtime will have been
sampled before the first actual read, which would normally yield a value
very close to zero; but it can actually be as great as a second, due to
the fact that oldtime was stored with time() and newtime was taken from
gettimeofday(). It's not until the next iteration of the loop that the
time taken to do a read has factored in any way, into the calculation of
a delay in the timing file.

The Perl-based scriptreplay had code like this (only a comment was removed):

my $block;
my $oldblock='';
while (<TIMING>) {
        my ($delay, $blocksize)=split ' ', $_, 2;
        if ($delay / $divisor > 0.0001) {
                select(undef, undef, undef, $delay / $divisor - 0.0001);
        }

        read(TYPESCRIPT, $block, $blocksize)
                or die "read failure on typescript: $!";
        print $oldblock;
        $oldblock=$block;
}

Note that two delay lines are read, and executed, before a single byte
has been written to the terminal. This makes sense since the first delay
value is in actuality a completely spurious number (less than 1).
scriptreplay.pl just read the number of bytes it was supposed to, but
held off on printing it out until the next delay.

The current C-based scriptreplay program doesn't do this, but does what
anyone would otherwise assume it should: read a delay and number of
bytes, do the delay, and read/write the number of bytes.

- -= what can be done =-

- From a Correctness POV, the right way to deal with this is to fix
script.c, not scriptreplay.c. The simple act of moving the newtime
calculation to below the read, rather than before it (and, perhaps,
calculating oldtime using gettimeofday, so we don't introduce a spurious
~half-second delay) will have things working better than they ever did,
and result in a much more straightforward way to process the timing file
(i.e., the way scriptreplay does it now).

- From a Pragmatism POV, though, there's the fact that, if we simply
kludge scriptreplay.c to behave as the original did, then the timing
files from all versions of script, new and old, will work with the
current scriptreplay. If we fix script.c instead, then everyone has to
be careful not to mix versions of script.

- -= ouch, my head =-

The reason I ran into this, is I'm currently nearing completion on a
program to break down typescripts into human-readable form. The program
is GNU Teseq, and a preview version can be had from
http://micah.cowan.name/projects/teseq/ (note to archive-readers: that
link won't be good for long; if you can't find it there, look around at
http://www.gnu.org/software/teseq/ (which isn't up yet at the time of
this writing)).

It takes input like:

     ^[[1mHi^[[m there, world^H^H^H^H^Hearth

And spits out something like:

     : Esc [ 1 m
     & SGR: SELECT GRAPHIC RENDITION
     " Set bold text.
     |Hi|
     : Esc [ 0 m
     & SGR: SELECT GRAPHIC RENDITION
     " Clear graphic rendition to defaults.
     | there, world|
     . BS/^H BS/^H BS/^H BS/^H BS/^H
     |earth|.

I just added support for timing files, so that you could include the
timing information, make edits (whatever's needed to debug a pesky
terminal issue), and the timings would all still be in the correct
place. These timings are inserted into the output as "delay lines", e.g.:

     @ 3.14159    <--- seconds to wait

Teseq currently behaves similar to scriptreplay.pl: skips over the first
(timestamp) line, processes _two_ timing-file lines, then processes the
number of bytes from the first of those lines.

Where it gets... interesting... is that there's a companion program,
reseq, which can turn this format back into a script-style
typescript-and-timings-file. In order to do that, it actually has to
read up to the _third_ delay line, before it can write a single byte out
to the timings file, since the seconds field for the first two lines of
the timing file will come from the first two delay lines of the Teseq
file; but the number-of-bytes field for the first line of the timing
file can't be determined until we see how many bytes follow them, up to
the next (third) delay line. Ick!

That may be a good case for the fix-script.c POV; but OTOH even if you
fix that I'm still going to have to support all the folks with less than
spanking-new versions of script. That means my choices are: (1) just
yell at them to get a version of script that works, or (2) include an
option to handle outputs from buggy versions of script. In the case of
(1), my code will be significantly cleaner, but I'll probably have mild
support headaches to look forward to.

.

If I had to choose, fixing script is the solution that appeals to me
most; but given that it's been like that for forever, and people may be
depending on its current idiosyncracies somewhere, and fixing it could
confuse people who try to share typescripts, it's not insane to consider
just "breaking" scriptreplay properly instead. ;)

- --
Micah J. Cowan
Programmer, musician, typesetting enthusiast, gamer.
GNU Maintainer: wget, screen, teseq
http://micah.cowan.name/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFIjb4f7M8hyUobTrERAk7LAJ95uJFk63LaEuqzhhhNKWUgvJj9vgCeO6g6
L9Iazqf7QexvfJG6k/c8kIo=
=u5Fi
-----END PGP SIGNATURE-----
--
To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux