Also tried it on FreeBSD which doesnt change errno.
Stephen.
<Stephen...@cs.tcd.ie>
#include <stdio.h>
#include <netdb.h>
main()
{
struct hostent* hp;
perror("starting");
hp = gethostbyname("localhost"); //messes errno
//hp = gethostbyname("www.yahoo.com"); //works
perror("gethostbyname");
return 0;
}
>The following code sets errno to be 2(No such file or directory)
>even if gethostbyname succeeds! (returns nonzero) It happens
>for all names which refer to the local machine. I've tried it on three
>linux boxes all with the same result.
The value of errno holds no meaning unless there has been an error. Also,
gethostbyname() does not set errno to anything meaningful - you should
be looking at h_errno - as described in man gethostbyname.
errno gets changed because gethostbyname() internally e.g. opens files
and such, but you shouldn't care about that. I don't think there
are any specifications that say that gethostbyname() should leave errno
unchanged?
--
==============================================================================
Erwin Andreasen Herlev, Denmark <e...@dde.dk> UNIX System Programmer
<URL:http://www.andreasen.org> <*> (not speaking for) DDE
==============================================================================
>
> The following code sets errno to be 2(No such file or directory)
> even if gethostbyname succeeds! (returns nonzero) It happens
> for all names which refer to the local machine. I've tried it on three
> linux boxes all with the same result.
Appended is an excerpt from GNU Libc Manual. Hope this helps.
Bye,
__
Takeyasu Wakabayashi,
Faculty of Economics, Toyama University
########################################################################
If the name lookup by `gethostbyname' or `gethostbyaddr' fails, you
can find out the reason by looking at the value of the variable
`h_errno'. (It would be cleaner design for these functions to set
`errno', but use of `h_errno' is compatible with other systems.)
Before using `h_errno', you must declare it like this:
extern int h_errno;
Here are the error codes that you may find in `h_errno':
`HOST_NOT_FOUND'
No such host is known in the data base.
`TRY_AGAIN'
This condition happens when the name server could not be
contacted. If you try again later, you may succeed then.
`NO_RECOVERY'
A non-recoverable error occurred.
`NO_ADDRESS'
The host database contains an entry for the name, but it doesn't
have an associated Internet address.
Of course it does. errno is supposed to be zero unless there has been an
error.
My point is that even if gethostbyname() succeeds (h_errno is ok) it also
clobbers errno, which it shouldnt do.
>errno gets changed because gethostbyname() internally e.g. opens files
>and such, but you shouldn't care about that. I don't think there
>are any specifications that say that gethostbyname() should leave errno
>unchanged?
The _whole point_ of errno is that it is zero until an error occurs!
nowhere does it say that gethostbyname() changes errno so the following
gives a bogus error
open(file); // errno =0
blah = gethostbyname("localhost");
close(); // errno = 2 even though close succeeded!
Steve.
Not so - see for example man errno:
The integer errno is set by system calls (and some library
functions) to indicate what went wrong. Its value is sig-
nificant only when the call returned an error (usually
-1), and a library function that does succeed is allowed
to change errno.
>My point is that even if gethostbyname() succeeds (h_errno is ok) it also
>clobbers errno, which it shouldnt do.
Not according to the manual page - library functions are allowed to change
errno.
>The _whole point_ of errno is that it is zero until an error occurs!
>nowhere does it say that gethostbyname() changes errno so the following
>gives a bogus error
>
>open(file); // errno =0
>blah = gethostbyname("localhost");
>close(); // errno = 2 even though close succeeded!
If a call succeeds, the value of errno is undefined. You cannot trust
the value of errno to be anything useful unless you have just done
a system/library call AND it fails.
Your code rewritten:
if ((fd = open(...)) < 0) {
// errno defined
} else { // success, errno could be anything
if (!(blah = gethostbyname("localhost"))) {
// h_errno defined here
// errno allowed to have been changed by gethostbyname()
}
if (close(fd) < 0) {
// errno meaningful
} else {
// succeded, errno not defined
}
}
I don't have any POSIX standards around, but the Linux manual pages
are usually fairly good.
Looking at the FreeBSD manual page, they only mention how errno can change
in conjuction with system calls, but not library functions.
Yes, you are right, point taken. I didnt see the man page
for errno, just the pages for system/library calls.
It just seems a little naff, for lack of a better word.
I did an strace and found that, for example gethostbyname
sets errno even though no system call fails.
Ick! Ah well, you live and learn
Steve.
Does the C standard say this, or is this just your intuition about how
things should work? errno has no guaranteed state unless a function
which is specifically supposed to set errno on error has just returned
an error status. Checking whether errno is 0 or not is not a standard
way to check if an error has occured. errno is only for checking
*which* error occured after you know that some error has occured. If
you look at the documentation for standard C functions, you'll see
that it never says that errno will be 0 on success, it only says what
errno will be on error.
If you need to save the value of errno across other function calls,
you should explicitly do so, not expect every library function to save
and restore errno for you.
>
> >errno gets changed because gethostbyname() internally e.g. opens files
> >and such, but you shouldn't care about that. I don't think there
> >are any specifications that say that gethostbyname() should leave errno
> >unchanged?
>
>
> The _whole point_ of errno is that it is zero until an error occurs!
> nowhere does it say that gethostbyname() changes errno so the following
> gives a bogus error
>
> open(file); // errno =0
> blah = gethostbyname("localhost");
> close(); // errno = 2 even though close succeeded!
>
> Steve.
>
>
--
Adam P. Jenkins
ajen...@netway.com
>Yes, you are right, point taken. I didnt see the man page
>for errno, just the pages for system/library calls.
>It just seems a little naff, for lack of a better word.
>I did an strace and found that, for example gethostbyname
>sets errno even though no system call fails.
Well, at least one of the system calls called from within gethostbyname
failed, but gethostnamed handled that error and handled the error before
returning with success. You should expect the same papening with for
example fopen when it tries to determine if it is opening a terminal
device. This involves a system call which returns an error if the
device or file is not a terminal device.
Villy
Thats what I thought too until:
>>I did an strace and found that, for example gethostbyname
>>sets errno even though no system call fails.
If a system call failed and was handled I could understand it.
Its the fact that no sys call failed that made me think it was a bug.
But now I know better :)
Steve.
No, see
$ man errno
If there is no error, errno is irrelevant. Always.
If a function call indicated an error, errno says which unless a
different one (like h_errno) is used for some compatibility reason.
If a function call can't indicate an error, you should zero errno
yourself before calling the function, because a successful operation
leaves errno unaltered.
> >errno gets changed because gethostbyname() internally e.g. opens files
> >and such, but you shouldn't care about that. I don't think there
> >are any specifications that say that gethostbyname() should leave errno
> >unchanged?
>
> The _whole point_ of errno is that it is zero until an error occurs!
> nowhere does it say that gethostbyname() changes errno so the following
> gives a bogus error
Wrong! see
$ man errno
> open(file); // errno =0
> blah = gethostbyname("localhost");
> close(); // errno = 2 even though close succeeded!
This is wrong. You should do:
(almostcode...)
--------------------------------
extern int h_errno;
fd = open(filename, etc); /* errno could be anything */
if (fd==-1) { /* errno indicates which error */
perror( progname );
exit( EXIT_FAILURE );
}
blah = gethostbyname( "localhost" ); /* h_errno, and errno could be
anything */
if (blah==NULL) { /* h_errno indicates which error */
/* errno could be anything */
herror( progname ); /* ideally, errno would be used,
not h_errno */
exit( EXIT_FAILURE ); /* but it's done this way for
compatibility reasons */
}
err = close( fd ); /* errno could be anything */
if (err) { /* errno indicates which error */
perror( progname ); /* but only because close() said
there was one */
exit( EXIT_SOMETHING );
}
--------------------------------
The man page is your friend.
--
Tristan Wibberley