Subject: Re: bug#7362: dd strangeness

From: Pádraig Brady <[email-masked]>
Date: Wed, 02 Mar 2011 13:12:36 +0000

On 01/03/11 19:30, Paul Eggert wrote:
> On 03/01/2011 09:45 AM, Paul Eggert wrote:
>> By the way, the relationship between fullblock and ibs=N obs=N is
>> a curious one, one that I don't fully understand.  If you have
>> ibs=N obs=N, why would you need fullblock?  This should probably
>> be documented (preferably by someone who understands it :-).
> 
> In looking into this some more, I did find one difference
> (or at least, something that *should* be a difference).
> 
> POSIX says that when an input record has
> an odd size, conv=swab should output the last byte as-is.
> If dd obeyed POSIX, ibs=100 obs=100 conv=swab would differ
> from bs=100 iflag=fullblock conv=swab in that the latter would
> swap every pair of input bytes, regardless of how many bytes
> are returned by individual 'read' system calls, whereas the
> former would not swap the last byte of each input record that
> has an odd size.
> 
> Except -- GNU dd doesn't conform to POSIX here!  It swaps
> bytes in the ibs=100 obs=100 conv=swab case, even when an
> input record has an odd number of bytes and POSIX says the
> last byte shouldn't be swapped.
> 
> For example:
> 
> (echo ab; sleep 1; echo cd) | dd ibs=100 conv=swab 2>/dev/null
> 
> POSIX says the output should be:
> 
> ba
> dc
> 
> (and Solaris dd agrees with POSIX here).  But GNU dd outputs:
> 
> bac
> 
> 
> (with a blank line at the end).
> 
> I suspect that this incompatibility was put in before the fullblock
> flag was added, because of the need to be able to swap bytes reliably.
> However, this need is better served by the fullblock option, so we
> should remove the incompatibility.

Oh good spot.

One can use an odd block size to test directly:

[solaris-10]$ echo abcde | dd bs=3 conv=swab 2>/dev/null
baced
[solaris-10]$ printf "abcd\n" | dd bs=3 conv=swab 2>/dev/null
bac
[solaris-10]$ printf "abcd" | dd bs=3 conv=swab 2>/dev/null
bacSegmentation Fault (core dumped)

So solaris is not being POSIX compliant either :)

Seriously though, changing to output the trailing byte directly
might break existing scripts that are swapping from a pipe.
I suppose we could warn to use fullblock if
  (!input_seekable && C_SWAB && !ibs%2 && nread%2)
though that would warn for your example above.
So I'm not sure how to proceed here.

cheers,
Pádraig.