i am writing a driver code, to read some register values from x86., when i ran my user space application i got the below error.
ioctl:Inappropriate ioctl for device
here is the code sniff..
fd = open_drvfile();
if(ioctl(fd, IOCTL_MSR_CMDS, (long long)msr_start) == -1 ) {
perror("ioctl:");
exit (0);
}
and open_drvfile() just open(create and open) the char file as below
fd = open("/dev/" DEV_NAME, O_RDWR|O_CREAT);
if (fd == -1) {
perror("Failed to open /dev/" DEV_NAME);
}
return fd;
can some one point where i made mistake on this?
A char device implies that it shall be created with mknod(), and not with O_CREAT under open() flags (which will create a regular file, not a char device).
(see question comments).
Related
I have a USB serial port module and I want to use it in my C application. The problem is the open system call doesn't return!
int serialDevice = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY); // doesn't return
I added my user to dialout group and I can access the port without root access using minicom in terminal. So it's not permission problem. Even if it is, it should return instantly and give permission error. But open function doesn't return at all.
What should I do? Do you have any idea?
Thanks
I believe this can happen if the device is busy, etc..
You need to add the flag O_NONBLOCK:
O_NONBLOCK
When opening a FIFO with O_RDONLY or O_WRONLY set:
*
If O_NONBLOCK is set, an open() for reading-only shall return without delay. An open() for writing-only shall return an error if no
process currently has the file open for reading.
*
If O_NONBLOCK is clear, an open() for reading-only shall block the calling thread until a thread opens the file for writing. An open()
for writing-only shall block the calling thread until a thread opens
the file for reading.
When opening a block special or character special file that supports
non-blocking opens:
*
If O_NONBLOCK is set, the open() function shall return without blocking for the device to be ready or available. Subsequent behavior
of the device is device-specific.
*
If O_NONBLOCK is clear, the open() function shall block the calling thread until the device is ready or available before
returning.
Otherwise, the behavior of O_NONBLOCK is unspecified.
int serialDevice = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY);
In addition to #darune's answer and O_NONBLOCK, you might consider O_SYNC too. Also see How to open, read, and write from serial port in C?
You might also consider making the file descriptor exclusive so another program like Modem Manager does not open the device and muck with your state. Exclusive is fine because of O_RDWR. Also see How to make /dev/ttyACM0 (and friends) exclusive? on the Kernel Newbies mailing list.
To make the file descriptor exclusive you need to use ioctl and TIOCEXCL. O_EXCL does not work as expected because it is not honored for character devices (and the kernel folks say -ENOPATCH).
int term_config(int fd, int speed)
{
struct termios tty;
memset(&tty, 0, sizeof(tty));
if (tcgetattr(fd, &tty) != 0) {
log_error("term_config: tcgetattr: %s\n", strerror(errno));
return -1;
}
cfmakeraw(&tty);
tty.c_cflag |= CLOCAL; /* ignore status lines */
tty.c_cflag |= CRTSCTS; /* hardware flow control */
cfsetospeed(&tty,(speed_t)speed);
cfsetispeed(&tty,(speed_t)speed);
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
log_error("term_config: tcsetattr: %s\n", strerror(errno));
return -1;
}
if (ioctl(fd, TIOCEXCL, NULL) != 0) {
log_error("term_config: ioctl_tty: %s\n", strerror(errno));
return -1;
}
return 0;
}
You would call term_config something like:
int serialDevice = open("/dev/ttyUSB0", ...);
if (serialDevice == -1) { /* error */ }
int result = term_config(serialDevice, B115200);
if (result != 0) { /* error */ }
I wrote a program to get the details of hard disk drive using HDIO_ ioctl calls.
For writing program, I'm referring Documentation/ioctl/hdio.txt in kernel source(2.6.32).
Here is my main part of code:
unsigned char driveid[512];
fd = open("/dev/sda", O_RDONLY); // validated fd.
retval = ioctl(fd, HDIO_GET_IDENTITY, &driveid);
if(retval < 0) {
perror("ioctl(HDIO_GET_IDENTITY)");
exit(3);
}
When I run(as root) the above code, I got below error:
ioctl(HDIO_GET_IDENTITY): Invalid argument
What is the wrong in the program?
Why I'm getting error?
Additional Info: OS: CentOS-6.5, kernel version: 2.6.32, IA:x86_64 (running on VMware).
the HDIO_GET_IDENTITY ioctl() doesn`t take a raw character buffer as its 3rd argument.
it uses a struct defined in linux/hdreg.h.
struct hd_driveid driveid;
fd = open("/dev/sda", O_RDONLY); // validated fd.
retval = ioctl(fd, HDIO_GET_IDENTITY, &driveid);
if(retval < 0) {
perror("ioctl(HDIO_GET_IDENTITY)");
exit(3);
}
this way it should work. Be aware that it only works for IDE/SATA drives, SCSI is not supported.
has
if you are wondering on how to get the information after the command ioctl() has returned succesfully, I suggest going through
http://lxr.free-electrons.com/source/include/linux/hdreg.h?v=2.6.36
I have 10 processes which try open the same file more or less at the same time using open(O_CREAT) call, then delete it. Is there any robust way to find out which process actually did create the file and which did open already create file, for instance, if I want to accurately count how many times that file was opened in such scenario.
I guess I could put a global mutex on file open operation, and do a sequence of open() calls using O_CREAT and O_EXCL flags, but that doesn't fit my definition of "robust".
Use O_EXCL flag with O_CREAT. This will fail if the file exists and errno will be set to EEXIST. If it does fail
then attempt open again without O_CREAT and without O_EXCL modes.
e.g.
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
if ((fd == -1) && (EEXIST == errno))
{
/* open the existing file with write flag */
fd = open(path, O_WRONLY);
}
Based roughly on your comments, you want something along the lines of this function:
/* return the fd or negative on error (check errno);
how is 1 if created, or 0 if opened */
int create_or_open (const char *path, int create_flags, int open_flags,
int *how) {
int fd;
create_flags |= (O_CREAT|O_EXCL);
open_flags &= ~(O_CREAT|O_EXCL);
for (;;) {
*how = 1;
fd = open(path, create_flags);
if (fd >= 0) break;
if (errno != EEXIST) break;
*how = 0;
fd = open(path, open_flags);
if (fd >= 0) break;
if (errno != ENOENT) break;
}
return fd;
}
This solution is not bullet proof. There may be cases (symbolic links maybe?) that would cause it to loop forever. Also, it may live-lock in certain concurrency scenarios. I'll leave resolving such issues as an exercise. :-)
In your edited question, you pose:
I have 10 processes which try open the same file more or less at the same time using open(O_CREAT) call, then delete it.
A hack-ish, but more bullet proof, solution would be to give each process a different user ID. Then, just use the regular open(path, O_CREAT|...) call. You can then query the file with fstat() on the file descriptor, and check the st_uid field of the stat structure. If the field equals the processes' user ID, then it was the creator. Otherwise, it was an opener. This works since each process deletes the file after opening.
I am working on a pseudo terminal library. The code is implemented in C code and the code is used by a web based terminal. The code works as long as I do not use sudo or login.
This is the error I get when I run the server on a Mac:
sh-3.2$ sudo ls
Password:
[1]+ Stopped(SIGTTOU)
sh-3.2$
The above works on Linux:
$ sudo ls
readme.txt
However, I get the following on Linux with sudo bash:
$ sudo bash
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
]0;root#ubuntu: /tmproot#ubuntu:/tmp#
Note: the above works, but I have no job control.
I have probably forgot to set some controlling bits on the terminal, but Google has not been very helpful in finding this.
Also, do you know of any good books that explains Pseudo terminal management in great detail.
I have the setsid call, but I am not using openpty. I use the following code when opening the pty:
static int createPty(lua_State* L, char* ttyName, int* pty)
{
*pty = getpt();
if (*pty < 0 || grantpt(*pty) < 0 || unlockpt(*pty) < 0)
return lDoErr(L,"Cannot open PTY: %s",strerror(errno));
if(ptsname_r(*pty, ttyName, PTY_NAME_SIZE-1))
return lDoErr(L,"ptsname_r: %s",strerror(errno));
return 0;
}
I have edited the code below and this code works. The reason my first version did not work was that I tried to create two PTY channels. I wanted to be able to differentiate between stdout and stderr, but the Linux kernel does not allow multiple TIOCSCTTY calls.
static int
childOpenTTY(const char* ttyName)
{
struct termios termbuf;
int fd=open(ttyName, O_RDWR);
if(fd < 0)
doClientError("open %s: %s",ttyName, strerror(errno));
tcsetpgrp(fd, getpid());
ioctl(fd,TIOCSCTTY,NULL);
tcgetattr(fd, &termbuf);
cfmakeraw(&termbuf); /* turn off NL to CR/NL mapping on output. */
tcsetattr(fd, TCSANOW, &termbuf);
return fd;
}
if( (ret = createPty(L, ttyName, &te->pty)) != 0)
return ret;
if ((te->pid = zzbafork()) < 0)
return lDoErr(L,"fork: %s",strerror(errno));
if(te->pid == 0)
{ /* Child process */
static const char efmt[]={"Cannot set '%s' (dup2 err)"};
int fd;
if(setsid() < 0) /* make new process group */
doClientError("setsid: %s",strerror(errno));
fd=childOpenTTY(ttyName);
if(dup2(fd, STDIN_FILENO) != STDIN_FILENO)
doClientError(efmt,"stdin");
if(dup2(fd, STDOUT_FILENO) != STDOUT_FILENO)
doClientError(efmt,"stdout");
if(dup2(fd, STDERR_FILENO) != STDERR_FILENO)
doClientError(efmt,"stderr");
if(fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
close(fd);
execve(cmd, (char**)cmdArgv, environ);
/* execve should not return, unless error exec cmd */
doClientError("Executing %s failed: %s",cmd,strerror(errno));
}
It's hard to be sure since there's no actual code shown here, but I suspect you're running into POSIX-style "session" management. You need to execute a setsid call, then open the pty (slave side) such that it becomes the controlling terminal. The openpty and login_tty routines do the low level grunge work for you; are you using those?
From what I have been reading on The Open Group website on fcntl, open, read, and write, I get the impression that whether O_NONBLOCK is set on a file descriptor, and hence whether non-blocking I/O is used with the descriptor, should be a property of that file descriptor rather than the underlying file. Being a property of the file descriptor means, for example, that if I duplicate a file descriptor or open another descriptor to the same file, then I can use blocking I/O with one and non-blocking I/O with the other.
Experimenting with a FIFO, however, it appears that it is not possible to have a blocking I/O descriptor and non-blocking I/O descriptor to the FIFO simultaneously (so whether O_NONBLOCK is set is a property of the underlying file [the FIFO]):
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int fds[2];
if (pipe(fds) == -1) {
fprintf(stderr, "`pipe` failed.\n");
return EXIT_FAILURE;
}
int fd0_dup = dup(fds[0]);
if (fd0_dup <= STDERR_FILENO) {
fprintf(stderr, "Failed to duplicate the read end\n");
return EXIT_FAILURE;
}
if (fds[0] == fd0_dup) {
fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n");
return EXIT_FAILURE;
}
if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n");
return EXIT_FAILURE;
}
if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) {
fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n");
return EXIT_FAILURE;
}
if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) {
fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n");
return EXIT_FAILURE; // RETURNS HERE
}
char buf[1];
if (read(fd0_dup, buf, 1) != -1) {
fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n");
return EXIT_FAILURE;
}
else if (errno != EAGAIN) {
fprintf(stderr, "Expected `errno` to be `EAGAIN`\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
This leaves me thinking: is it ever possible to have a non-blocking I/O descriptor and blocking I/O descriptor to the same file and if so, does it depend on the type of file (regular file, FIFO, block special file, character special file, socket, etc.)?
O_NONBLOCK is a property of the open file description, not of the file descriptor, nor of the underlying file.
Yes, you could have separate file descriptors open for the same file, one of which is blocking and the other of which is non-blocking.
You need to distinguish between a FIFO (created using mkfifo()) and a pipe (created using pipe()).
Note that the blocking status is a property of the 'open file description', but in the simplest cases, there is a one-to-one mapping between file descriptors and open file descriptions. The open() function call creates a new open file description and a new file descriptor that refers to the open file description.
When you use dup(), you have two file descriptors sharing one open file description, and the properties belong to the open file description. The description of fcntl() says that F_SETFL affects the open file description associated with the file descriptor. Note that lseek() adjusts the file position of the open file description associated with the file descriptor - so it affects other file descriptors duplicated from the original one.
Removing the error handling from your code to reduce it, you have:
int fds[2];
pipe(fds);
int fd0_dup = dup(fds[0]);
fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK);
Now both fd0_dup and fds[0] refer to the same open file description (because of the dup()), so the fcntl() operation affected both file descriptors.
if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... }
Hence the observed behaviour here is required by POSIX.