llseek return ESPIPE when calling zcat all.tgz | ./cycletee
Question
I modified GNU tee
to cycletee
Source Code (You can download the binary from https://github.com/vls/cycletee/tree/master/bin)
What it does can be explained by the following example:
seq 10 | cycletee 1.txt 2.txt 3.txt
cat 1.txt // prints 1, 4, 7, 10
cat 2.txt // prints 2, 5, 8
cat 3.txt // prints 3, 6, 9
Then there is a all.tgz
(See Appendix for building script)
all.tgz
has three text file and totally 9000000 lines.
Everything is fine. Like:
seq 10000000 | ./cycletee 1.txt 2.txt 3.txt
zcat all.tgz | tee 1.txt > /dev/null
zcat all.tgz | tail // got 9000000 at the last line
except calling:
zcat all.tgz | ./cycletee 1.txt 2.txt 3.txt
when it reads the No.3000000 line, it exits.
strace it I got this message and it exited:
_llseek(2, 0, 0xffbec3d0, SEEK_CUR) = -1 ESPIPE (Illegal seek)
Question
Anyone can point out the problem of my source code?
Any debugging technique to figure out the problem will be appreciated. I don't know how to use
gdb
in this situation.
Appendix
all.tgz
can be built by this Python sciprt https://gist.github.com/1500742Environment: Ubuntu 10.04 32bit, CentOS 5.4 64bit
La solution
From the source:
read:
buffer[0] = '\0';
ptr = fgets(buffer, (int) sizeof buffer, stdin);
if(NULL == ptr) {
if(ferror(stdin)) {
error (0, errno, "%s", _("standard input"));
ok = false;
}
flag_break = true;
break;
}
bytes_read = strlen(buffer);
if (bytes_read < 0 && errno == EINTR)
{
flag_continue = true;
backup_i = i;
break;
}
if (bytes_read <= 0) {
flag_break = true;
break;
}
if (descriptors[0]
&& fwrite(buffer, bytes_read, 1, descriptors[0]) != 1)
{
error (0, errno, "%s", files[0]);
descriptors[0] = NULL;
ok = false;
}
...
I don't think this will work on binary input (input that contains NULs). [ Given the signedness of bytes_read, I have the strong suspicion that fread() has been replaced by fgets() + strlen(); ] This may or may not be the cause of the PIPE error, but it looks very wrong.
Autres conseils
You cannot call llseek
or ftell
on a pipe or socket, they are not seekable files.
You could use a debugger like gdb
(it is really worth learning to use it; and GDB is very well documented), and e.g. put a breakpoint on _llseek
You could also use strace
or ltrace