Call to fdopendir() corrupts file descriptor - c

I stumbled upon a problem in a program I was working on. The following reproduces my issue:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
int fd, ret_fd;
DIR *dirp;
fd = open("./", O_RDONLY);
#if 1
if ((dirp = fdopendir(fd)) == NULL) {
perror("dirp");
return 1;
}
closedir(dirp);
#endif
ret_fd = openat(fd, "Makefile", O_RDONLY);
if (ret_fd == -1) {
perror("ret_fd");
return 1;
}
return 0;
}
Basically, the call to openat(), which has been preceeded by fdopendir(), fails with: Bad file descriptor. However, this does not happen if fdopendir() is omitted.
I know that fdopendir() makes internal use of the file descriptor, but shouldn't it revert any changes to it after calling closedir()?
What can I do to prevent openat() from failing in this case?

The POSIX description of fdopendir() says:
Upon calling closedir() the file descriptor shall be closed.
So the descriptor is likely to be closed by the time you call openat().
And this is from a typical Linux man page for fdopendir():
After a successful call to fdopendir(), fd is used internally by the
implementation, and should not otherwise be used by the application.

Related

open file linux eclipse c error after getchld

im just trying to open a file.
i have done it for 100 times, and then I sent SIGCHLD signal to other processes and i think right after that i couldn't open that file anymore.
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#define FLAGS IPC_CREAT | 0644
int main() {
int res =open("results.txt",FLAGS);
if(res== -1) { printf("error!!")} //prints it every time
return 0;}
..it suddenly just happened.. help ???
You're doing something strange with the flags. I think your intention is as per below code:
#define FLAGS O_CREAT
#define MODE 0644
int main()
{
int res =open("results.txt",FLAGS,MODE);
if(res== -1) { printf("error!!");} //prints it every time
return 0;
}
the following code:
cleanly compiles
properly calls the open() function
properly displays the error message
does not #include header files that are not used
consistently indents the code
follows the axiom: `only one statement per line and (at most) one variable declaration per statement.
separates code blocks (for, if ,else, while, do...while, switch, case, default) via a blank line
uses a proper signature for the main() function (the empty parens in the posted code means that any number of parameters, including 0 parameters, are allowed
code should not return 0 success when an error occurs so using exit( EXIT_FAILURE )
And now the code:
#include <stdio.h> // perror()
#include <stdlib.h> // exit(), EXIT_FAILURE
#include <unistd.h> // open()
#include <fcntl.h> // O_CREAT
#define FLAGS O_CREAT
#define MODE 0644
int main( void )
{
int res =open("results.txt", FLAGS, MODE);
if(res== -1)
{
perror( "open for results.txt failed" );
exit( EXIT_FAILURE );
}
return 0;
}

Setting Immutable Flag using ioctl() in C

I have attempted to make a script that creates a file and then sets it as immutable similar to the chattr +i command for linux. The script compiles (with gcc), runs and the file is created. However the file itself is not immutable and can be removed with a simple rm -f. I have attempted to stacktrace where chattr is called and I found a function called ioctl. I then used what little information I could gather and came up with what I have below. I narrowed it down from ext2_fs.h but it just doesn't seem to work. I've clearly overlooked something.
Updates to previous entry: Compiles but returns -1 on ioctl() function. Bad address shown with perror().
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
fp = fopen("/shovel.txt", "w+");
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
fclose(fp);
}
Any help appreciated.
You are using the right ioctl command, but you're passing it the wrong arguments.
The manpage for ioctl_list(2) shows that FS_IOC_SETFLAGS expects to receive a pointer to int (an int *), yet you're passing it an integer literal (hence the Bad Address error).
The fact that you don't to any error checking whatsoever is also not helping.
The correct flag to pass to FS_IOC_SETFLAGS is a pointer holding the value EXT2_IMMUTABLE_FL, which is defined in ext2fs/ext2_fs.h (some older / different Linux distributions seem to have it under linux/ext2_fs.h), so you'll need to #include <ext2fs/etx2_fs.h>. Make sure to install e2fslibs-dev (and probably you'll need linux-headers too).
This code is working:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = EXT2_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
Remember to run this as root.
UPDATE:
As Giuseppe Guerrini suggests in his answer, you might want to use FS_IMMUTABLE_FL instead, and you won't need to include ext2_fs.h:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = FS_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
The main problem is that the ioctl wants a pointer to the mask, not a direct constant. You have to define a int variable, store the mask (0x10) in it and pass its address as third argument of ioctl.
Also, I'd add some hints:
other programs to change attributes are used to use low-level I/O directly (open, close...). Also, the file is usually opened with O_RDONLY.
Use FS_IMMUTABLE_FL istead the raw constant.
Get the current attribute mask first (FS_IOC_SETFLAGS) and mask it with the new flag, so other settings are not lost by the service.

open() function error when flags are a char string pointer instead of an int

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
int i=1;
for(i=1;i<argc;++i)
{
char temp;
fd=open(argv[i],"O_RDWR");
if (fd==-1)
perror("file:");
while (read(fd,&temp,1)!=EOF)
{
putchar(temp);
}
}
}
I execute ./a.out a b. a and b are files in my directory. I get an error saying File exists.
The line open(argv[i],"O_RDWR") is not opening the file.
It is returning -1 since the file exists . How then should i open the file using the open system call?
fd=open(argv[i],"O_RDWR");
^ ^
You're passing a char * instead of an integer constant. Drop the ", it should be just:
fd = open(argv[i], O_RDWR);
Interestingly but likely off-topic, open must have thought you passed O_CREAT | O_EXCL, that's why it complained about the file already existing.
So what i have wriiten is right then???But the code is going into an
infinite look printing nothin
The function read(2) doesn't return EOF at and of input but rather 0.

Existence of a file given its path

Given the path, is there a way to find out whether the file exists without opening the file?
Thanks
The most efficient way is access with the F_OK flag.
stat also works but it's much heavier weight since it has to read the inode contents, not just the directory.
You can use the stat system call. Make sure though that you check errno for the correct error because stat may return -1 for a number of other reasons/Failures.
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat BUF;
if(stat("/Filepath/FileName",&BUF)==0)
{
printf("File exists\n");
}
}
Another way is by using the access function.
#include <unistd.h>
main()
{
if(access("/Filepath/FileName", F_OK) != -1 )
{
printf("File exists\n");
}
else
{
printf("File does not exist\n");
}
}
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
int rc;
struct stat mystat;
rc = stat(path, &mystat);
Now check rc and (maybe) errno.
EDIT 2011-09-18 addendum:
Both access() and stat() return 0 if the path points to a non-file (directory, fifo,symlink, whatever)
In the stat() case, this can be tested with "((st_mode & S_IFREG) == S_IFREG)".
Best way still is to just try to open the file with open() or fopen().
Try to remove it (unlink()). If successful, it doesn't exist anymore. If unsuccessful,
interpret errno to see if it exists :)

Distinguishing a pipe from a file in Unix

Given a FILE*, is it possible to determine the underlying type? That is, is there a function that will tell me if the FILE* is a pipe or a socket or a regular on-disk file?
There's a fstat(2) function.
NAME
stat, fstat, lstat - get file status
SYNOPSIS
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int fstat(int fd, struct stat *buf);
You can get the fd by calling fileno(3).
Then you can call S_ISFIFO(buf) to figure it out.
Use the fstat() function. However, you'll need to use the fileno() macro to get the file descriptor from file FILE struct.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
FILE *fp = fopen(path, "r");
int fd = fileno(fp);
struct stat statbuf;
fstat(fd, &statbuf);
/* a decoding case statement would be good here */
printf("%s is file type %08o\n", path, (statbuf.st_mode & 0777000);

Resources