|
Home > Archive > Unix Programming > April 2004 > detecting symbolic links in c
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
detecting symbolic links in c
|
|
|
| I am writing a simple c program which checks its command-line arguments
and classifies them according to whether they are directories, regular
files, symbolic links or other. (If one of the arguments is not a path to
any kind of file or directory, an error message is emitted.)
The problem is that my program incorrectly reports symbolic links as
regular files.
What is a/the proper way to portably detect symbolic links in a unix-like
environment? I am using linux, but it seems like it should be possible to
do this portably.
For example, how portable are readlink() and lstat()?
Here is my current code. It is supposed to print the file or directory
name followed by an 'L' for symlinks, a 'D' for directories, an 'R' for
regular file, and an 'O' for any other file or directory which can be
stat()ed. Anything which cannot be stat()ed will produce an error message
of some kind.
/********* begin code **********************/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main (int argc, char **argv)
{
int result, i;
struct stat buf;
extern int errno;
for(i = 1; i < argc; i++)
{
errno = 0;
result = stat(argv[i], &buf);
if (result == -1)
printf("%s: %s\n", *argv, strerror(errno));
else
{
if (S_ISLNK(buf.st_mode))
printf("%s L\n", argv[i]);
else if (S_ISREG(buf.st_mode))
printf("%s R\n", argv[i]);
else if (S_ISDIR(buf.st_mode))
printf("%s D\n", argv[i]);
else printf("%s O\n", argv[i]);
}
}
return 0;
}
/****************end of code **********************/
Thanks for taking a look at it.
--Mac
| |
| Rich Teer 2004-04-18, 10:42 am |
| On Fri, 16 Apr 2004, Mac wrote:
> For example, how portable are readlink() and lstat()?
They're both standard, and are the answer you're looking for.
Replace your call to stat() with a call to lstat().
HTH,
> extern int errno;
Don't do this; #include <errno.h> instead.
HTH,
--
Rich Teer, SCNA, SCSA
President,
Rite Online Inc.
Voice: +1 (250) 979-1638
URL: http://www.rite-online.net
| |
|
| On Sat, 17 Apr 2004 07:05:32 +0000, Rich Teer wrote:
> On Fri, 16 Apr 2004, Mac wrote:
>
>
> They're both standard, and are the answer you're looking for.
> Replace your call to stat() with a call to lstat().
>
> HTH,
Yes, thanks very much.
>
>
> Don't do this; #include <errno.h> instead.
I did both. I guess I don't see the harm in what I did. But I certainly
admit that it isn't necessary. To me it is just a way of emphasizing that
errno comes from somewhere else.
>
> HTH,
Yes, thanks.
--Mac
| |
| Måns Rullgård 2004-04-18, 10:42 am |
| "Mac" <foo@bar.net> writes:
>
> I did both. I guess I don't see the harm in what I did. But I certainly
> admit that it isn't necessary. To me it is just a way of emphasizing that
> errno comes from somewhere else.
Often errno is declared in some special way, such as having one copy
per thread. Just declaring it as 'extern' will break things in those
cases.
--
Måns Rullgård
mru@kth.se
| |
| Casper H.S. Dik 2004-04-18, 10:42 am |
| =?iso-8859-1?q?M=E5ns_Rullg=E5rd?= <mru@kth.se> writes:
>"Mac" <foo@bar.net> writes:
[vbcol=seagreen]
>Often errno is declared in some special way, such as having one copy
>per thread. Just declaring it as 'extern' will break things in those
>cases.
Not nessarily:
#define errno (*(___errno()))
makes this just work fine:
extern int errno;
Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.
| |
| Rich Teer 2004-04-18, 3:34 pm |
| On Sat, 17 Apr 2004, Mac wrote:
> Yes, thanks very much.
My pleasure.
> I did both. I guess I don't see the harm in what I did. But I certainly
No harm (that I can think of), but not necessary, and might mask
errors.
> admit that it isn't necessary. To me it is just a way of emphasizing that
> errno comes from somewhere else.
An experienced programmer will know this, and if you're going to do it,
then to be consistent you should do the same for all the other externals
in your program, like printf, lstat, etc. (And no, I'm not suggesting
even for an attosecond that you actually do this!)
--
Rich Teer, SCNA, SCSA
President,
Rite Online Inc.
Voice: +1 (250) 979-1638
URL: http://www.rite-online.net
| |
|
| On Sun, 18 Apr 2004 12:55:38 +0200, Måns Rullgård wrote:
> "Mac" <foo@bar.net> writes:
>
>
> Often errno is declared in some special way, such as having one copy
> per thread. Just declaring it as 'extern' will break things in those
> cases.
Interesting. I don't have any real experience with threads, but it is
clear that "errno" is something that would need to be dealt with specially
in a threaded environment.
Without threads, I believe "extern int errno" HAS to work. I'll study up
on threads before I use them. ;-)
regards,
Mac
| |
|
| On Sun, 18 Apr 2004 19:10:00 +0000, Rich Teer wrote:
> On Sat, 17 Apr 2004, Mac wrote:
>
>
> My pleasure.
>
>
> No harm (that I can think of), but not necessary, and might mask
> errors.
>
>
> An experienced programmer will know this, and if you're going to do it,
> then to be consistent you should do the same for all the other externals
> in your program, like printf, lstat, etc. (And no, I'm not suggesting
> even for an attosecond that you actually do this!)
I agree with all your arguments except this last one. Errno isn't a
function, so different rules apply. But anyway, in the future I'll just
use it (after inclcuding errno.h).
Thanks again.
--Mac
| |
| Brian Raiter 2004-04-19, 6:34 pm |
| > I agree with all your arguments except this last one. Errno isn't a
> function, so different rules apply.
On what do you base that assertion? How do you know errno can never be
a macro encapsulating a function? For that matter, how do you know
errno can never be a short? Or a long? Or unsigned, for that matter?
Unless memory fails me, I don't believe ANSI or POSIX makes any promise
other than that "errno" is some kind of object that can be compared
with positive integral values. I'm not even sure it requires that
errno be "non-const".
b
| |
| Geoff Clare 2004-04-20, 12:35 pm |
| "Brian Raiter" <blr@drizzle.com> wrote, on Mon, 19 Apr 2004:
> Unless memory fails me, I don't believe ANSI or POSIX makes any promise
> other than that "errno" is some kind of object that can be compared
> with positive integral values. I'm not even sure it requires that
> errno be "non-const".
The current POSIX standard says the following things about how
errno is defined (these are not literal quotes):
errno is an lvalue with type int, defined in <errno.h> either
as a macro or as an identifier with external linkage.
The only valid way for applications to obtain the definition
of errno is by including <errno.h>.
If errno is a macro and an application suppresses the macro then
the behaviour is undefined.
I think what this means for the following code mentioned earlier in
the thread:
#include <errno.h>
extern int errno;
is that it will either fail to compile, or will compile and run
exactly the same as it would if the second line had not been there.
--
Geoff Clare <nospam@gclare.org.uk>
| |
|
| On Mon, 19 Apr 2004 22:17:49 +0000, Brian Raiter wrote:
>
> On what do you base that assertion? How do you know errno can never be
> a macro encapsulating a function? For that matter, how do you know
> errno can never be a short? Or a long? Or unsigned, for that matter?
>
> Unless memory fails me, I don't believe ANSI or POSIX makes any promise
> other than that "errno" is some kind of object that can be compared
> with positive integral values. I'm not even sure it requires that
> errno be "non-const".
>
> b
From the standard:
The header <errno.h> defines several macros, [...] and
errno
which expands to a modifiable lvalue/83/ that has type int , the value
of which is set to a positive error number by several library
functions. It is unspecified whether errno is a macro or an
identifier declared with external linkage. If a macro definition is
suppressed in order to access an actual object, or a program defines
an external identifier with the name errno, the behavior is
undefined.
--------------end of quote-----------------------
So, I guess it is not a good idea for me to declare it, after all. Doing
so could result in a syntax error if errno is a macro. But it is clearly
intended to have integer-like behavior, since it is modifiable lvalue of
type int.
And of course, "extern int errno" is not technically a definition, so it
doesn't explicitly violate the text above.
I don't know what posix says about errno, but from now on I won't be
declaring it in any functions I write.
--Mac
| |
|
| On Tue, 20 Apr 2004 13:46:32 +0100, Geoff Clare wrote:
> "Brian Raiter" <blr@drizzle.com> wrote, on Mon, 19 Apr 2004:
>
>
> The current POSIX standard says the following things about how
> errno is defined (these are not literal quotes):
>
> errno is an lvalue with type int, defined in <errno.h> either
> as a macro or as an identifier with external linkage.
>
> The only valid way for applications to obtain the definition
> of errno is by including <errno.h>.
>
> If errno is a macro and an application suppresses the macro then
> the behaviour is undefined.
>
> I think what this means for the following code mentioned earlier in
> the thread:
>
> #include <errno.h>
> extern int errno;
>
> is that it will either fail to compile, or will compile and run
> exactly the same as it would if the second line had not been there.
I think I agree with you. Just two nitpicks: 1) "extern int errno;"
appeared inside main, and 2) "extern int errno;" is not a definition
because it does not reserve storage.
Still, if errno is a macro, the declaration could be a syntax error after
pre-processing. So from now on I won't bother with the declaration.
Thanks,
Mac
| |
| Rich Teer 2004-04-22, 1:35 am |
| On Wed, 21 Apr 2004, Mac wrote:
> From the standard:
[...]
> I don't know what posix says about errno, but from now on I won't be
Umm, POSIX (aka, the Single UNIX Specification) *is* the standard. :-)
> declaring it in any functions I write.
Good idea! Solaris is one of those OSes that declares errno
to be an int in a single threaded program, but it's a macro
which calls a function to return the thread-cpecific errno
in a multithreaded program.
--
Rich Teer, SCNA, SCSA
President,
Rite Online Inc.
Voice: +1 (250) 979-1638
URL: http://www.rite-online.net
| |
| Villy Kruse 2004-04-22, 4:34 am |
| On Thu, 22 Apr 2004 05:35:45 GMT,
Rich Teer <rich.teer@rite-group.com> wrote:
> On Wed, 21 Apr 2004, Mac wrote:
>
>
> [...]
>
>
> Umm, POSIX (aka, the Single UNIX Specification) *is* the standard. :-)
>
>
> Good idea! Solaris is one of those OSes that declares errno
> to be an int in a single threaded program, but it's a macro
> which calls a function to return the thread-cpecific errno
> in a multithreaded program.
>
If this is controlled by _REENTRANT or _THREAD_SAFE then you get
bad results if you ever mix object modules where some modules are
compiled in thread safe mode and other modules are compiled in single
threaded mode. This also applies to libraries where you sometime have
a single threaded version and a threaded version.
Villy
|
|
|
|
|