Possible reasons of linux open call returning EINVAL - c

I am trying to make a system call in my source code as follows.
int file;
file = open(argv[index], O_RDONLY);
Where the command line arguement is a path to a binary file in my filesystem. But this call throws me an EINVAL error. I have checked the existence of file and the required permissions to access it.
Any suggestions on what circumstances the EINVAL error will be thrown out.

The official documentation suggests that this is because your implementation of open() does not support synchronized IO for the file you are trying to open.

Cause of failure:
There were two processes say (process-1 and process-2) that were executing in close sequel and was trying to open this binary file. Since my system (embedded device) will crash after this open call, the debugs splitted out weren't proper and it made me to suspect the process-1. But the actual culprit is process-2 who was opening the binary with O_RDWR flag. But my file system (network mount) was mounted as "read only file system".
Points to be taken care:
Refining the perror prints it should be the right cause of the problem as "Read Only File System". So my initial perror description must be a uncleared value of any of the previous erroneous call. One learning here is to use perror with care, so as avoid analysing misleading error message.
Possible circumstances the EINVAL error will be thrown out:
The open call will show an EINVAL if we use O_SYNC (or) related flags for the file which we are not supposed to use. I conclude this based on the documentation as previously mentioned by Rafe.

If you are sure that argv[index] actually contains the filename and that O_RDONLY hasn't been overridden somehow (O_RDONLY should equal 0), check your system log via the dmesg command and make sure that nothing funky has happened in-kernel.

Related

Character Device Driver Read/Write in Linux

I've written a character device driver that, I believe, should work.
I want to test the read/write functions. On another stack overflow question, apparently this can be done by writing to the device file in /dev and echoing the output.
I don't understand how this works:
When I load up my device driver by allocating a major number and calling mknod to create the file, is the file "open"? If it isn't open, then reading/writing shouldn't work like that from the command line, or so I thought?
What state is the device driver in when it has been initialized in /proc/devices and a file created in /dev?
Does this initialization need to happen before attempting to open the device file in a c program?
These answer are extremely difficult to find online, and many resources are outdated. Thanks
One good resource is Linux device driver. A shorter and simpler explanation can be found here.
When you create a file driver, you will implement some functions among file operations (fops):
open
close
read
write
seek
...
Not all function have to be implemented. If write is not implemented for instance, your device won't support writting.
When I load up my device driver by allocating a major number and calling mknod to create the file, is the file "open"?
When the /dev file is created, your module is only inited. A function like init_module is called
When the file is removed, your module is deinited. A function like module_cleanup is called.
What state is the device driver in when it has been initialized in /proc/devices and a file created in /dev?
In that case, the module is inited, the file are not open.
If it isn't open, then reading/writing shouldn't work like that from the command line, or so I thought?
When you read a file from command line, the file is open, read then closed, as a user, you don't have to care to open/close file explicitly.
Things are different if you are a C programmer, in that case, you explicitly have to open, read, close the files.
You can check that adding traces in your kernel code (using printk to print some info to kernel console, reading it with dmesg) or using strace that will trace the system calls.
Does this initialization need to happen before attempting to open the device file in a c program?
Let's resume:
The first function called will be module_init before it's called, the file doesnot exist in /dev
The last function called will be module_cleanup after it's called, the file doesnot exist in /dev
between init and cleanup, you can call the different open, close, read and write function.
Generally read/write are called between open and close.

getcwd error when $HOME

I wrote my own find() function. When I do:
./myown $HOME/Documents test.txt
I get:
/Users/CJ/Documents/test/test.txt
/Users/CJ/Documents/test/test1/test.txt
/Users/CJ/Documents/test/test2/test.txt
However when I do:
./myown $HOME test.txt
I get:
getcwd error
My code for getcwd is here and it is in a helper function:
findit(*directory, *pattern){
...
if(getcwd(cwd, 2048+1) == NULL){
fprintf(stderr, "getcwd error\n");
exit(1);
}
...
}
How can I solve this issue?
EDIT: closedir() solve this issue but there is another issue now. Result is the same when I do : ./myown $HOME/Documents test.txt but when I do the other way I get : stat error
`
struct stat mode;
if(stat(entry->d_name, &mode) == -1){
fprintf(stderr, "stat error\n");
continue;
}`
I didn't use stat error anywhere else in the code.
This can be helpful too, this is how I used open
DIR *dir
dir = opendir(".");
The error is in readdir().
One suggested step in debugging was:
Since getcwd() sets errno when it fails, you should probably report errno, maybe with perror("getcwd"). Although I'm not keen on perror(), it is probably simplest here.
It turns out that the error set was EMFILE Too many open files.
So, now you know what the trouble is. The getcwd() is failing because you have opened a lot of files and not closed enough of them, and it needs some available file descriptors but you've not left it any that it can use.
And, when requested, I elaborated on that with:
You've opened files and/or directories (opening a directory with opendir() usually uses a file descriptor), and you've not closed them. Consequently, the system won't allow you to open any more files — and the getcwd() fails. It probably isn't immediate; your program has probably done some processing before that failure.
The OP observed:
I just saw that I haven't used fclose; give me a second and I will check it if that's it.
Making sure you've used fclose() and closedir() — and plain close() if you've used any file descriptors by calling open() directly — should help. If, however, the call to getcwd() is the very first thing your code is doing, it won't be because you've opened many files (you haven't).
If there are still problems after files have been closed, then you need to take a step back and review the larger context.
For example:
Why is stat() failing after readdir()?
stat() error 'No such file or directory' when file name is returned by readdir()

Basics questions regarding File and I/O System Calls in C (on Linux/UNIX)

I'm working on improving my C programming knowledge, but I am having trouble understanding the man pages for the following Unix system calls:
open
create
close
unlink
read
write
lseek
The man pages for each of these are, for lack of a better term, completely confusing and unintelligible. For example, here is the man page for open:
"Given a pathname for a file, open() returns a file descriptor, a small, nonnegative integer for use in subsequent system calls (read(2), write(2), lseek(2), fcntl(2), etc.). The file descriptor returned by a successful call will be the lowest-numbered file descriptor not currently open for the process.
By default, the new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described in fcntl(2) is initially disabled; the O_CLOEXEC flag, described below, can be used to change this default). The file offset is set to the beginning of the file (see lseek(2)).
A call to open() creates a new open file description, an entry in the system-wide table of open files. This entry records the file offset and the file status flags (modifiable via the fcntl(2) F_SETFL operation). A file descriptor is a reference to one of these entries; this reference is unaffected if pathname is subsequently removed or modified to refer to a different file. The new open file description is initially not shared with any other process, but sharing may arise via fork(2)."
I have no idea what this all means. From my understanding, if open returns a negative integer, an error occurred, and if it returns a positive integer, then that integer can be used in further system calls (???). That is, unfortunately, basically the extent of my knowledge and what I can attempt to parse from the man page. I need some help.
What does it mean that it "returns the lowest-numbered file descriptor not currently open for the process"? What process is it referring to? Why is it the lowest-numbered file descriptor, and why does this matter/how would I use this? I hate to sound like an idiot but I honestly have no clue what it's talking about.
Let's take an example. Let's say I wanted to create a new file in a directory, and open up a file from another directory, and copy the file I opened into the file I created, while checking for errors along the way. This is my attempt:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int XYZ = creat("XYZ.doc", 0 );
if (XYZ < 0)
printf("file creating error");
int file = open("/usr/.../xx.xx", 0);
if(file < 0)
printf("file opening error");
}
How would I copy the file that I opened into the file that I created? That should be easy. But what if I wanted to copy the file that I opened in reverse to the file that I created? (Maybe that example will illuminate how to use the file offset stuff mentioned in the man page, which I don't currently understand...)
I would like to edit this post to write a layman's terms description next to each of these system calls, thus creating a good online resource for people to study from. Also, if anyone has any good references for these system calls in C, that would be much appreciated as well.
Error checking left out for simplicity sake:
char data[1024]; /* size of this chosen more or less on a whim */
ssize_t n;
while ((n = read(file, data, sizeof(data))) > 0) {
write(XYZ, data, n);
}
close(file);
close(XYZ);

Why can't I open a file for reading if (theoretically) I should be allowed?

I have two projects in C:
The first:
include windows.h
include stdio.h
include tchar.h
int main()
{
HANDLE hFile = CreateFile("D:\\f.txt",
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
_tprintf("Error: CreateFile %d\n",GetLastError());
Sleep(5000);
return 0;
}
The Second:
include windows.h
include stdio.h
include tchar.h
int main()
{
HANDLE hFile = CreateFile("D:\\f.txt",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile == INVALID_HANDLE_VALUE)
_tprintf("Error: CreateFile %d\n",GetLastError());
return 0;
}
The first program is supposed to open the file for reading while allowing others to read from it.
The second is supposed to open the file for reading.
When I run the program, the second one give me error 32 (ERROR_SHARING_VIOLATION).
I thought the whole point of FILE_SHARE_READ was to allow other threads/processes to open a file just for reading regardless of whether it's already open or not.
Can anyone help me solve this problem?
P.S. If the file were a mailslot, would that make any difference?
Your CreateFile() call explicitly denies write sharing, you specified FILE_SHARE_READ. That cannot work, the first program already gained write access since it used GENERIC_WRITE. You cannot deny a right that was already acquired so the call will fail with a sharing violation error.
To make it work, the second call will have to specify FILE_SHARE_WRITE instead. And deal with the headache of trying to read from a file that's being written to at unpredictable times and places. This typically only comes to a good end when the 1st process only appends to the file and doesn't seek. And you properly dealing with sometimes only getting a part of the appended data because some of it is still stuck in a buffer or in the process of being written. Tricky stuff. Consider a pipe in message mode if that's a problem.
Reiterating from the comments, the sharing flags do not control what you can do, they control what another process can do with the file. What you want to do is specified in the 2nd argument. So the missing FILE_SHARE_WRITE is the problem since it prevents another process from writing to the file. But it already does.
You cannot request a sharing mode that conflicts with the access mode that is specified
in an existing request that has an open handle. CreateFile would fail and the
GetLastError function would return ERROR_SHARING_VIOLATION.
Here in the first program, you specify the third parameter (dwShareMode) as granting "read" permission to other processes and requests "write" access for itself in the second parameter (dwDesiredAccess).
Then in the second program, you ask for "read" access in the second parameter (which is fine) and grant only "read" permission to other processes in the third parameter, which conflicts with the access mode specified in the first program ("write"). The opening of the file by the first program is an "existing request that has an open handle".
In the first program, you are saying that "I can write to "f.txt". Other people can only read it." and in the second program you are saying that "I can read "f.txt". Other people can only read it.", which is a contradiction, as the first program is already writing to "f.txt".
As has already been mentioned, reading and writing to a file simultaneously by two different processes is a good recipe for data corruption.
I think the answer in CreateFile documentation:
You cannot request a sharing mode that conflicts with the access mode
that is specified in an existing request that has an open handle.
CreateFile would fail and the GetLastError function would return
ERROR_SHARING_VIOLATION.
i.e. you open file to write but you didn't indicate that this write can be shared.

How to determine in Windows whether file exists, does not exist or this can't be known (using c)

I have to clean up from a list of files the ones that do not exist any more. The ones whose status is indeterminable should be given a warning about but left on the list. Sounds simple enough. However, the c functions I tried to solve this with don't seem to give a reliable answer between whether the file really does not exist or it e.g. resides on a network share that is at the moment inaccessible (e.g. due to network problems).
stat function sets errno to ENOENT if the file can't be reached, so that is indistinguishable from the file not actually existing.
FindFirstFile in some cases sets last error (obtainable with GetLastError()) to ERROR_PATH_NOT_FOUND when the network share can't be reached.
Yes, I know FindFirstFile is for reading directories, but I thought I could deduce what I need to know by the error code it sets.
Also GetFileAttributes seems to in some cases set last error to ERROR_PATH_NOT_FOUND in case the network drive is unreachable.
CreateFile does set LastError to 0x35 (network path not found) if network share is not availiable and to 0x2 (system cannot find the path specified) if share is availiable, but file does not exist
if((f = fopen(file, "r")) == NULL){
//File does not exist or can not be read
}else{
//File exists
fclose(f);
}
Drawbacks:
You don't know if a file is nonexistent or just can't be read (privileges etc),
On the other hand, it is 100% portable.

Resources