perror generating unexpected errno value - c

I am experiencing an unexpected value of errno when using perror with glibc. When an non-existent file is specified as arg[1] it prints Error: 2 ( which isENOENT) as expected. However when the perror line below is uncommented it throws error 22 (EINVAL) no matter what I pass it. Can anyone please explain why this is getting set?
EDIT: Looks like this is some sort of Eclipse bug. The IDE seems to be causing perror to throw some sort of error, the program works perfectly on the command line, and works perfectly when a correct file is specified in the argument list in Eclipse. It fails incorrectly when run inside of Eclipse.
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(int argc, char *argv[]) {
FILE *input_file;
input_file = fopen(argv[argc - 1], "r");
if (!input_file) {
// perror(argv[argc-1]);
fprintf(stderr, "Error: %d\n", errno);
return (EXIT_FAILURE);
}
else {
fclose(input_file);
}
return (EXIT_SUCCESS);
}

You can't rely on the value of errno after calling into other library functions, in other words your call to perror() itself may be modifying the value of errno You need to save it in a temporary variable if you want to be able to use it after calls into other library procedures.
if (!input_file) {
int err = errno;
perror(argv[argc-1]);
fprintf(stderr, "Error: %d\n", err);
return (EXIT_FAILURE);
}

Your program works as expected for me here:
$ ./app fkjhsf
Error: 2
and with the perror() call uncommented:
$ ./app asdkfljh
asdkfljh: No such file or directory
Error: 2
Maybe the perror() call is changing your errno for some reason? What operating system/compiler/library versions are you using?

He's likely running the program without any arguments.
If so, "argv[argc - 1]" will evaluate to garbage.
There should be code to make sure that "argc-1" is within a valid range.

Related

Segmentation fault (core dumped) when creating directory

I have this simple code:
int read_data(int GrNr) {
//many lines of code
fprintf(fdatagroup, "%i", Ngroups);
return 0;
}
int main(int argc, char **argv) {
for(NUM=NUM_MIN;NUM<=NUM_MAX;NUM++) {
sprintf(groupfile,"../output/profiles/properties_%03d.txt", NUM);
fdatagroup = fopen(groupfile,"w");
GROUP=0;
accept=0;
do {
check=read_data(GROUP);
printf("check = %d \n", check);
accept++;
FOF_GROUP++;
}
while (accept<=n_of_halos);
fclose(fdatagroup);
}
printf("Everything done.\n");
return 0;
}
If I don't create manually the folder called "profiles" inside my output directory i get
the error: Segmentation fault (core dumped)
If the folder is there, everything works fine.
What can I do to be able to create the directory from inside the code?
I am using gcc in linux.
Thanks.
Just as some background, when fopen attempts to open a file that does not exist, instead of failing, it simply returns NULL. The seg fault then occurs when you try to read/write data to a null pointer.
The creation and destruction of directories lies within the realm of sys/dir.h
#include <sys/dir.h>
...
mkdir(path_str);
On Linux:
#include <sys/stat.h>
#include <sys/types.h>
mkdir("/path/to/dir", 0777); // second argument is new file mode for directory (as in chmod)
You should also always check your functions for failure. fopen returns NULL and sets errno if it fails to open the file; mkdir (and most other system calls returning int) returns -1 and sets errno. You can use perror to print out a message containing the error string:
#include <errno.h>
if(mkdir("/path", 0777) < 0 && errno != EEXIST) { // we check for EEXIST since maybe the directory is already there
perror("mkdir failed");
exit(-1); // or some other error handling code
}

Why does fopen("any_path_name",'r') not give NULL as return?

While debugging some code I got something like below:
#include<stdio.h>
int main()
{
FILE *fb = fopen("/home/jeegar/","r");
if(NULL == fb)
printf("it is null");
else
printf("working");
}
Here in fopen I gave a somewhat valid path name but not a filename. Shouldn't fopen return NULL then? But it does not return null!
Edit:
If I give path of valid directory in fopen then it will print working:
If I give path of invalid directory in fopen then it will print it is null
Edit:
spec says
Upon successful completion, fopen() shall return a pointer to the object
controlling the stream. Otherwise, a null pointer shall be returned.
so here whether error code set or not, it MUST return NULL
And error code setting is an extansion to ISO C standard standard.
ERROR IS ALSO NOT GOING TO SET HERE
#include<stdio.h>
#include <errno.h>
int main()
{
errno = 0;
FILE *fb = fopen("/home/jeegar/","r");
if(fb==NULL)
printf("its null");
else
printf("working");
printf("Error %d \n", errno);
}
OUTPUT IS
workingError 0
I think that in Unix everything (directories included) is considered to be file so fopen should work on them.
The posix man page man 3p fopen says, in the section ERRORS:
The fopen() function shall fail if:
[...]
EISDIR The named file is a directory and mode requires write access.
(Emphasis mine). Since you are not requesting write access, and chances are that the path you use is a directory, the function does not fail.
About what can you use with a FILE* that refers to a directory, I have no idea.
As you might be very well aware that pretty much everything on Linux system is a file, if not a file then its a process (corrections & remarks welcome :) ) Directory is treated like a file which lists other files (Reference from TLDP); so opening to read a directory as a file is a valid operation and thus you do not get any error. Although trying to write to it is not allowed, so if you open directory in write or append mode, the fopen operation will fail (this has been very well mentioned is other responses & link to fopen documentation). Most of the file operation like read & write operations on this file stream will fail with the error stating that its a directory. Only use which could be found was finding the size of the file (directory in this case) using fseek to SEEK_END & ftell (which will most likely give a result of 4096).
Regarding using errno to get meaningful messages, you can use perror which is in stdio.h & pass message which will be added before the error message or strerror which is in string.h & pass errno which is in errno.h
Hope this helps!
How to check that errno?
You can check errno for example:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
errno = 0;
fp = fopen("file.txt", "r");
if ( errno != 0 )
{
// Here you can check your error types:
perror("Error %d \n", errno);
exit(1);
}
}
Error types you can find at http://pubs.opengroup.org/onlinepubs/009695399/functions/fopen.html Error section.

SImple C Program opening a file

I'm trying to make a program to open a file, called "write.txt".
#include <stdio.h>
main() {
FILE *fp;
fp = fopen("write.txt", "w");
return 0;
}
Should this work? Because it returns nothing.
Other than an old variant of main, there's not really much wrong with that code. It should, barring errors, create the file.
However, since you're not checking the return value from fopen, you may get an error of some sort and not know about it.
I'd start with:
#include <stdio.h>
#include <errno.h>
int main (void) {
FILE *fp;
fp = fopen ("write.txt","w");
if (fp == NULL) {
printf ("File not created okay, errno = %d\n", errno);
return 1;
}
//fprintf (fp, "Hello, there.\n"); // if you want something in the file.
fclose (fp);
printf ("File created okay\n");
return 0;
}
If you're adamant that the file isn't being created but the above code says it is, then you may be a victim of the dreaded "IDE is working in a different directory from what you think" syndrome :-)
Some IDEs (such as Visual Studio) will actually run your code while they're in a directory like <solution-name>\bin or <solution-name>\debug. You can find out by putting:
system ("cd"); // for Windows
system ("pwd") // for UNIXy systems
in to your code to see where it's running. That's where a file will be created if you specify a relative path line "write.txt". Otherwise, you can specify an absolute path to ensure it tries to create it at a specific point in the file system.
What did you expect it to 'return' - it opens a file, on most platforms creating one if it doesn't exist.
You should probably fclose(fp) the file at the end.
I think you want to print the contents of file write.txt. (Assume it contains characters).
#include <stdio.h>
int main()
{
FILE *fp,char ch;
fp=fopen("write.txt","r");
if(fp==NULL)
{
printf("Some problem in opening the file");
exit(0);
}
else
{
while((ch=fgetc(fp))!=EOF)
{
printf("%c",ch);
}
}
fclose(fp);
return 0;
}
I think you should study some more fundamentals in C before you start attempting to work with files. A return means some data is passed back to the calling code from the called function.In this case you return 0 at the end of your program. You did not do anything with your FILE pointer except cause a new file to be created...

Segmentation fault while using ferror() in a simple program. Why?

Why is the following code giving segmentation fault?
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file;
file = fopen("text","r");
if (file == NULL) printf("Error READING FILE");
if (ferror(file)) printf("error reading file"); //line 9
return 0;
}
Doing backtrace in gdb gives:-
> #0 0x00007ffff7ad9d30 in ferror () from /lib/libc.so.6
> #1 0x00000000004005fa in main () at test.c:9
file is NULL. You're not seeing the first printf because the program crashes before stdout is flushed.
If fopen returns NULL, then the file isn't open; you're passing NULL in to ferror, which is invalid. You don't have an open file to pass in; that's what NULL means, that it couldn't give you a file pointer. ferror is for getting errors related to reading and writing the file, once it has actually been opened and you have the file to work with.
If fopen fails, and you want to get more information about why, you need to check the errno global variable, defined in errno.h.
#include <errno.h>
// ...snip...
if (file == NULL)
printf("Error READING FILE: %s\n", strerror(errno));
This example shows how to fetch a string describing the error; you could also compare the value in errno against one of the possible values it could have, and do something different depending on what the error is. See the fopen man page, or the POSIX spec, for a list of possible errors to compare against. Here's how you could check against various possible errors:
if (file == NULL) {
int error = errno; // copy it so other calls like printf don't modify it
printf("Error READING FILE: %s\n", strerror(error));
switch (error) {
case EACCESS:
// access was denied
break;
case ENOENT:
// the file or one of its ancestors doesn't exist
break;
// etc...
}
}
(this is an expansion of something I originally wrote in a comment on another answer)
If file is equal to NULL on line 9, then the Seg Fault will occur during the ferror() call.
If there the file is NULL (as determined on line 8), then you shouldn't perform line 9.
Your line 8 code should be changed as such:
if (file == NULL)
{
printf("Error READING FILE");
return 1;
}
NB: i could be very wrong about this, it's been a while since i've done C/C++

detecting loops in symbolic links (c programming)

I'm looking to detect loops in symbolic links in a C program:
$ ln -s self self
$ ln -s a b
$ ln -s b a
Here's what I've got so far:
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct stat buffer;
int status;
if (argc != 2) {
fprintf(stderr, "error: file name required\n");
return 0;
}
errno = 0;
status = lstat(argv[1], &buffer);
if (errno == ELOOP) {
fprintf(stderr, "loop found");
}
return 1;
}
I'm running my program like this:
$ findloops self
$ findloops a
Any idea what I'm doing wrong?
This is NOT homework.
This is where I got the idea from.
The trouble is that 'lstat()' looks at the symlink and its properties, and the symlinks actually exist.
If you replace the call with 'stat()', then you will get the ELOOP error. This tries to get the information at the far end of the symlink, and that cannot be found because of the ELOOP condition.
You should only test errno after you have verified that status indicates a failure. With a genuine system call, it is unlikely that errno would be set when the call succeeds, but with library functions, you can find errno is set even though the call succeeds. For example, with some standard I/O library implementations, you can have errno == ENOTTY even after a successful function call; the code checks whether the file descriptor represents a terminal and errno is set to indicate that it isn't, but since the function succeeded, it is not legitimate to check errno.
I would take a look at the buffer returned. According to the documentation of lstat the buffer contains two items that would be relevant:
st_ino - The inode for the file (note that this number is unique to each distinct file and all directories on a Linux file system, but the same inode number can appear in different file systems).
st_dev - The device that the file currently resides on.
If you create a list containing these two items per element+the directory where the link is located as the previously visited elements, you could detect loops. Also don't forget to pop them off when you leave the directory that they were created in.
I'm not convinced that ELOOP is the value that you think it is. According to this, it identifies the maximum links tolerated in the class path, but it won't tell you which link looped first.
The documentation on the page claimed this: "ELOOP: Too many symbolic links were encountered in translating the pathname. "
ELOOP doesn't have to mean that there is a loop. It can also mean that there are too many symbolic links from source to target, as in
a -> b -> c -> d -> e ... -> z
do this enough times and the OS kernel (particularily for some cases on linux) will give up trying to follow the links, even if they are all valid and non-cyclic.
You may also be interested in man 2 readlink.
After some playing with code, it looks like you've found either a feature or a bug with lstat(2). According to the man page on lstat, which is also stat and fstat, the difference between stat and lstat is:
stat() stats the file pointed to by
path and fills in buf.
lstat() is identical to stat(), except
that if path is a symbolic link, then
the link itself is stat-ed, not the
file that it refers to
I took your program and played with it a little. I used lstat, stat, and fopen to check the link. Code is below. The bottom line is that both stat and fopen detected the link properly, while lstat failed. I have no explanation for this.
The program below, executed on file bar created as 'ln -s bar bar', gave the following output:
./foo ./bar
Errno as returned from lstat = 0
Errno as returned from stat = 92
loop found
Errno as returned from fopen = 92
loop found
Code:
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int
main(int argc, char *argv[])
{
struct stat buffer;
int status;
int savedErrno1;
int savedErrno2;
int savedErrno3;
FILE *theFile;
if (argc != 2) {
printf("error: file name required\n");
return 0;
}
errno = 0;
status = lstat(argv[1], &buffer);
savedErrno1 = errno;
printf("Errno as returned from lstat = %d\n", savedErrno1);
if (savedErrno1 == ELOOP) {
printf("loop found\n");
}
errno = 0;
status = stat(argv[1], &buffer);
savedErrno2 = errno;
printf("Errno as returned from stat = %d\n", savedErrno2);
if (savedErrno2 == ELOOP) {
printf("loop found\n");
}
errno = 0;
theFile = fopen(argv[1], "w");
savedErrno3 = errno;
printf("Errno as returned from fopen = %d\n", savedErrno3);
if (savedErrno3 == ELOOP) {
printf("loop found\n");
}
return 1;
}

Resources