Closed p5pRT closed 15 years ago
Hi\, There's a problem with readlink().
print readlink("/proc/13917/exe"); results in: /usr/sbin/squidr.pyo (deleted)
While it should be '/usr/sbin/squid'. Actually there are \0's in the resulting string:
00000000 2f 75 73 72 2f 73 62 69 6e 2f 73 71 75 69 64 00 |/usr/sbin/squid.| 00000010 72 2e 70 79 6f 00 00 00 00 00 00 00 00 00 00 00 |r.pyo...........| 00000020 20 28 64 65 6c 65 74 65 64 29 | (deleted)|
As far as I understand\, C's readlink() and shell's readlink(1) work fine 'cause they see \0 termination\, while Perl doesn't use it.
The problem has appeared today\, yesterday the code worked fine.
Hello\,
Denis Melnikov wrote:
There's a problem with readlink().
I was bitten by the same thing in a program I wrote at $work. AFAIK\,
it's a Linux only thing.
print readlink("/proc/13917/exe"); results in: /usr/sbin/squidr.pyo (deleted)
While it should be '/usr/sbin/squid'. Actually there are \0's in the resulting string:
00000000 2f 75 73 72 2f 73 62 69 6e 2f 73 71 75 69 64 00 |/usr/ sbin/squid.| 00000010 72 2e 70 79 6f 00 00 00 00 00 00 00 00 00 00 00 | r.pyo...........| 00000020 20 28 64 65 6c 65 74 65 64 29 |
(deleted)|As far as I understand\, C's readlink() and shell's readlink(1) work fine 'cause they see \0 termination\, while Perl doesn't use it.
The problem has appeared today\, yesterday the code worked fine.
Read the full string: it only appears when the target file has been
deleted. IIRC\, the buffer contains the target path\, a fixed number of
bytes (I don't know their meaning)\, then the string "(deleted)". I
think it's used by utilities like lsof.
Note that Perl simply uses the C readlink(2) function\, so any C
program will show the same thing. Except you usually won't see it
because if you printf("%s\n"\, buf) (where buf has been filled by
readlink(2))\, you'll only see the target path because printf(3) will
stop at the first \0. In Perl\, you see everything because Perl
strings don't end at \0.
It can be demonstrated (on Linux) with a short C program. I don't
have by hand the one I wrote when I discovered this\, but I think it
was something like this:
$ cat myreadlink.c #include \<stdio.h> #include \<unistd.h>
#define BUF_SIZE 128
int main(int argc\, char *argv[]) { char buf[BUF_SIZE]; int n\, i;
n = readlink(argv[1]\, buf\, BUF_SIZE); printf("readlink() returned %d\n"\, n); printf(" buf=\"%s\"\n"\, buf); printf(" buf: ");
for (i=0; i\<=BUF_SIZE; i++) { printf("%02hhx "\, buf[i]); }
puts("");
return 0; }
Compile it\, then call it with "myreadlink /proc/13917/exe". IIRC\,
readlink(2) on Linux returns the total number of bytes it put in the
buffer\, up to and including the "(deleted)" string\, which Perl uses
as the length of the string.
If we consider this a bug\, the following (untested) patch should
solve it:
Sébastien Aperghis-Tramoni
Close the world\, txEn eht nepO.
The RT System itself - Status changed from 'new' to 'open'
On May 16\, 2008\, at 7:28 PM\, Sébastien Aperghis-Tramoni wrote:
Hello\,
Denis Melnikov wrote:
There's a problem with readlink().
I was bitten by the same thing in a program I wrote at $work.
AFAIK\, it's a Linux only thing.
It is a "trick" that procfs uses which assumes anyone using readlink
on a link in procfs will stop at the NULL.
print readlink("/proc/13917/exe"); results in: /usr/sbin/squidr.pyo (deleted)
While it should be '/usr/sbin/squid'. Actually there are \0's in the resulting string:
00000000 2f 75 73 72 2f 73 62 69 6e 2f 73 71 75 69 64 00 |/usr/ sbin/squid.| 00000010 72 2e 70 79 6f 00 00 00 00 00 00 00 00 00 00 00 | r.pyo...........| 00000020 20 28 64 65 6c 65 74 65 64 29 |
(deleted)|As far as I understand\, C's readlink() and shell's readlink(1) work fine 'cause they see \0 termination\, while Perl doesn't use it.
The problem has appeared today\, yesterday the code worked fine.
Read the full string: it only appears when the target file has been
deleted. IIRC\, the buffer contains the target path\, a fixed number
of bytes (I don't know their meaning)\, then the string "(deleted)".
I think it's used by utilities like lsof.If we consider this a bug\, the following (untested) patch should
solve it:
I do not consider it a bug. With the patch below anyone attempting to
write utilities to use that information cannot.
Graham.
--- pp_sys.c.old 2008-04-30 13:51:55.000000000 +0200 +++ pp_sys.c 2008-05-17 02:25:59.000000000 +0200 @@ -3586\,7 +3586\,8 @@ EXTEND(SP\, 1); if (len \< 0) RETPUSHUNDEF; - PUSHp(buf\, len); + buf[len] = '\0'; + PUSHp(buf\, strlen(buf)); RETURN; #else EXTEND(SP\, 1);
-- Sébastien Aperghis-Tramoni
Close the world\, txEn eht nepO.
On Sat\, May 17\, 2008 at 06:24:16AM -0500\, Graham Barr wrote:
On May 16\, 2008\, at 7:28 PM\, Sébastien Aperghis-Tramoni wrote:
Read the full string: it only appears when the target file has been
deleted. IIRC\, the buffer contains the target path\, a fixed number
of bytes (I don't know their meaning)\, then the string "(deleted)".
I think it's used by utilities like lsof.If we consider this a bug\, the following (untested) patch should
solve it:I do not consider it a bug. With the patch below anyone attempting to
write utilities to use that information cannot.
My view too. readlink is working as documented.
I'm curious whether this feature of the Linux proc filing system is documented. :-)
Nicholas Clark
Nicholas Clark wrote:
On Sat\, May 17\, 2008 at 06:24:16AM -0500\, Graham Barr wrote:
On May 16\, 2008\, at 7:28 PM\, Sébastien Aperghis-Tramoni wrote:
Read the full string: it only appears when the target file has been deleted. IIRC\, the buffer contains the target path\, a fixed number of bytes (I don't know their meaning)\, then the string "(deleted)". I think it's used by utilities like lsof.
If we consider this a bug\, the following (untested) patch should solve it:
I do not consider it a bug. With the patch below anyone attempting to write utilities to use that information cannot.
My view too. readlink is working as documented.
If you allow me to be a little pedant\, it's not exactly working as
documented:
readlink EXPR
readlink
Returns the value of a symbolic link\, if symbolic
links are
implemented. If not\, gives a fatal error. If there
is some
system error\, returns the undefined value and sets $!
(errno).
If EXPR is omitted\, uses $_.
i.e.\, it should return the target of the symbolic link\, and it's what
it does on all systems\, including Linux. It's only when the target
file doesn't exist that it returns this additional\, undocumented\,
information\, which doesn't exist on other systems. On OSX\, readlink
(2) on a broken link just returns the content of the symbolic link.
So\, one could argue that Perl could/should return consistent value
across operating systems.
Personally\, I can live with it as it is\, given it's just a matter of
s/\0//. Another solution is to add a POSIX::readlink() that DWIM and
only returns the target.
I'm curious whether this feature of the Linux proc filing system is documented. :-)
IIRC\, I had searched a little back then\, but didn't find anything.
Googling a little more today didn't end with more results. The man
page for proc(5) doesn't indicate this:
» http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html
-- Sébastien Aperghis-Tramoni
Close the world\, txEn eht nepO.
On May 17\, 2008\, at 7:36 PM\, Sébastien Aperghis-Tramoni wrote:
Nicholas Clark wrote:
On Sat\, May 17\, 2008 at 06:24:16AM -0500\, Graham Barr wrote:
On May 16\, 2008\, at 7:28 PM\, Sébastien Aperghis-Tramoni wrote:
Read the full string: it only appears when the target file has been deleted. IIRC\, the buffer contains the target path\, a fixed number of bytes (I don't know their meaning)\, then the string "(deleted)". I think it's used by utilities like lsof.
If we consider this a bug\, the following (untested) patch should solve it:
I do not consider it a bug. With the patch below anyone
attempting to write utilities to use that information cannot.My view too. readlink is working as documented.
If you allow me to be a little pedant\, it's not exactly working as
documented:readlink EXPR readlink Returns the value of a symbolic link\, if symbolic
links are implemented. If not\, gives a fatal error. If there
is some system error\, returns the undefined value and sets
$! (errno). If EXPR is omitted\, uses $_.i.e.\, it should return the target of the symbolic link\, and it's
what it does on all systems\, including Linux. It's only when the
target file doesn't exist that it returns this additional\,
undocumented\, information\, which doesn't exist on other systems. On
OSX\, readlink(2) on a broken link just returns the content of the
symbolic link. So\, one could argue that Perl could/should return
consistent value across operating systems.
Allow me to be pedant
SYNOPSIS #include \<unistd.h>
int readlink(const char *path\, char *buf\, int bufsiz);
DESCRIPTION
Readlink() places the contents of the symbolic link path in the
buffer
buf\, which has size bufsiz. Readlink does not append a NUL
character to
buf.
RETURN VALUES
The call returns the count of characters placed in the buffer
if it suc-
ceeds\, or a -1 if an error occurs\, placing the error code in
the global
variable errno.
As the man page states\, the system call does not append a nul
character\, but returns the number of characters placed into the
buffer. If your code is treating any embedded nul character as the
end of the link\, then I would suggest that your program is broken.
Personally\, I can live with it as it is\, given it's just a matter
of s/\0//. Another solution is to add a POSIX::readlink() that DWIM
and only returns the target.
It already does what it is supposed to do.
Graham.
@smpeters - Status changed from 'open' to 'resolved'
Migrated from rt.perl.org#54198 (status was 'resolved')
Searchable as RT54198$