I am migrating the c application from Solaris 9 SPARC to RHEL 5.x
x86_64 platform.
Here are the platform details:
-------------------------------------------
1. OS: Red Hat Linux 5.x, kernel 2.6.x
2. gcc compiler : 4.1.2.x V
ioctl() call on Linux returning errno as EFAULT (Bad Address). I have
simulated the problem with below sample program. Can I know what is
going wrong on Linux with this program.
--------------
/* Sample program to test the ioctl() call which sets the read mode to
message-nondiscard mode.
* For some reason this sample is not working on Linux x84_64, gcc :
4.1.x V and Red Hat 5.x.
* However this code works on Solaris SPARC.
*/
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <errno.h>
# include <stropts.h> / macros I_SRDOPT and RMSGN are defined */
int
main(){
int fd[2];
int fd_read;
int fd_write;
fd_read= fd_write = -1; /* Initila value */
/* Create unnamed socket pairs */
if ( socketpair(AF_UNIX, SOCK_STREAM,0,fd) == -1 ){
fprintf(stdout, "socketpair call failed with errno: %d
\n", errno);
exit(1);
}
fd_read = fd[0];
fd_write = fd[1];
/* fcntl code comes here to set non blocking read */
if ( ioctl(fd_read, I_SRDOPT, RMSGN ) == -1 ){ /* set read
mode to message -nondiscard mode */
fprintf(stdout, "ioctl call failed with below error:
\n" );
if ( errno == EBADF )
fprintf(stdout, "EBADF:The fildes argument is
not a valid open file descriptor. errno: %d\n", errno );
if ( errno == EFAULT )
fprintf(stdout, "EFAULT:The argp is
referencing an inaccessible memory area.errno: %d\n", errno );
if ( errno == EAGAIN )
fprintf(stdout, "EAGAIN:Unable to allocate
buffers for the acknowledgement message. errno: %d\n", errno );
if ( errno == EINTR )
fprintf(stdout, "EINTR:A signal was caught
during the ioctl() operation. errno: %d\n", errno );
if ( errno == EINVAL )
fprintf(stdout, "EINVAL:The request or arg
argument is not valid for this device. errno: %d\n", errno );
if ( errno == EIO )
fprintf(stdout, "EIO:Some physical I/O error
has occurred.errno: %d\n", errno );
if ( errno == ENOTTY )
fprintf(stdout, "ENOTTY:The fildes argument
is not associated with a STREAMS device that accepts control
functions. errno: %d\n", errno );
if ( errno == ENXIO )
fprintf(stdout, "ENXIO: The request and arg arguments are valid
for this device driver, but the service requested cannot be performed
on this particu- lar sub-device. errno: %d\n", errno );
if ( errno == ENODEV )
fprintf(stdout, "ENODEV:The fildes argument
refers to a valid STREAMS device, but the corresponding device
driver does not support the ioctl() func- tion. errno: %d\n", errno);
exit(1);
}else
fprintf(stdout, "ioctl works!\n");
return 0;
}// main() ends
Thanks in Advance.
> Hello,
>
> I am migrating the c application from Solaris 9 SPARC to RHEL 5.x
> x86_64 platform.
>
> Here are the platform details:
> -------------------------------------------
> 1. OS: Red Hat Linux 5.x, kernel 2.6.x
> 2. gcc compiler : 4.1.2.x V
>
> ioctl() call on Linux returning errno as EFAULT (Bad Address). I have
> simulated the problem with below sample program. Can I know what is
> going wrong on Linux with this program.
Your program call printf() before checking the value of errno. Printf()
can modify errno, so you're printing the value that printf() set it to,
not what ioctl() set it to.
BTW, you seem to be going to a lot of work to reinvent perror(), which
prints the error message associated with errno.
--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***
It's more precise than that. The Linux ioctl(2) man page says:
ERRORS
EBADF d is not a valid descriptor.
EFAULT argp references an inaccessible memory area.
EINVAL Request or argp is not valid.
...
here it means 'argp references an inaccessible memory area'.
> I have
> simulated the problem with below sample program. Can I know what is
> going wrong on Linux with this program.
>
> --------------
> /* Sample program to test the ioctl() call which sets the read mode to
> message-nondiscard mode.
> * For some reason this sample is not working on Linux x84_64, gcc :
> 4.1.x V and Red Hat 5.x.
> * However this code works on Solaris SPARC.
> */
>
> # include <stdio.h>
> # include <stdlib.h>
> # include <unistd.h>
> # include <fcntl.h>
> # include <sys/ioctl.h>
> # include <sys/socket.h>
> # include <sys/types.h>
> # include <errno.h>
> # include <stropts.h> / macros I_SRDOPT and RMSGN are defined */
^^^^^^^
Hm -- apparently you haven't tried to compile this program. But that
seemed to be the only error.
>
>
> int
> main(){
>
> int fd[2];
>
> int fd_read;
> int fd_write;
>
> fd_read= fd_write = -1; /* Initila value */
>
> /* Create unnamed socket pairs */
> if ( socketpair(AF_UNIX, SOCK_STREAM,0,fd) == -1 ){
> fprintf(stdout, "socketpair call failed with errno: %d
> \n", errno);
> exit(1);
> }
>
> fd_read = fd[0];
> fd_write = fd[1];
>
> /* fcntl code comes here to set non blocking read */
>
> if ( ioctl(fd_read, I_SRDOPT, RMSGN ) == -1 ){ /* set read mode to message -nondiscard mode */
> fprintf(stdout, "ioctl call failed with below error:\n" );
And as mr Magol wrote, there's perror() and strerror() for printing
errnos. (You don't even have to do that -- it's easier to run the
program under strace(1) and have it explain everything.)
> }else
> fprintf(stdout, "ioctl works!\n");
>
>
> return 0;
> }// main() ends
^^^^^^^^^^^^^^
Removing that to make it compile as C89.
>
> Thanks in Advance.
I_SRDOPT seems to be related to STREAMS. I cannot find it documented
in Stevens' "Unix network programming" books, and I have never used
STREAMS myself. But I know the Linux people generally dislike it, and
last time I heard it was /not/ part of Linux except as a kernel patch.
It is most likely /not/ in RedHat's kernel.
But the question is: if this is indeed STREAMS, and you don't have
that, then why are the ioctls defined in the header files? Perhaps
there are good reasons, but it's better when code that cannot possibly
work doesn't compile ...
Also, normally I expect 'gcc -std=c89 -Wall -W -pedantic ...' not to
compile unless I say "I want BSD APIs" or "I want POSIX this and
that". See features.h. But for these things, there was *no*
protection. That's surely a bug in the headers.
Someone else has to answer, but it seems to me you have a problem
here. The program you try to port uses Solaris-specific APIs. (OK,
some other Unices in the past may have had STREAMS too, but neither of
the healthy Unices -- Linux and the BSDs -- have it).
By the way, running the program under valgrind(1) is also enlightening.
Syscall param ioctl(CDROMREADTOCENTRY (cdte_format, char)) points to
unaddressable byte(s)
and so on.
/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Barry Margolin,
As you said, i changed the code to use perror() call instead of
fprintf() . I am getting "Bad Address" error message associated with
errno set by ioctl and not by fprintf().
let me know why ioctl() call is failing on Linux with the above
parameters. This program works fine on Solaris.
Thanks in advance.
Jorgen,
thanks for pointers.
> Hm -- apparently you haven't tried to compile this program. But that
> seemed to be the only error.
Here is the modified program:
/* Sample program to test the ioctl() call which sets the read mode to
message-nondiscard mode.
* For some reason this sample is not working on Linux x84_64, gcc :
4.1.x V and Red Hat 5.x.
* However this code works on Solaris SPARC.
*/
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <sys/ioctl.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <errno.h>
# include <stropts.h> /* macros I_SRDOPT and RMSGN are defined */
int
main(){
int fd[2];
int fd_read;
int fd_write;
fd_read= fd_write = -1; /* Initila value */
/* Create unnamed socket pairs */
if ( socketpair(AF_UNIX, SOCK_STREAM,0,fd) == -1 ){
perror("socketpair");
exit(1);
}
fd_read = fd[0];
fd_write = fd[1];
/* fcntl code comes here to set non blocking read */
/* set read mode to message -nondiscard mode */
if ( ioctl(fd_read, I_SRDOPT, RMSGN ) )
perror("ioctl");
return 0;
}/* main() ends */
I compiled this with "gcc -std=c89 -Wall -W -pedantic"
> program under strace(1) and have it explain everything.)
Here is the output of strace:
execve("./a.out", ["./a.out"], [/* 23 vars */]) = 0
uname({sys="Linux", node="smt-linux2", ...}) = 0
brk(0) = 0x8b18000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=71234, ...}) = 0
old_mmap(NULL, 71234, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7f21000
close(3) = 0
open("/lib/tls/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\320\36h
\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1529136, ...}) = 0
old_mmap(0x66d000, 1227964, PROT_READ|PROT_EXEC, MAP_PRIVATE|
MAP_DENYWRITE, 3, 0) = 0x66d000
old_mmap(0x793000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|
MAP_DENYWRITE, 3, 0x125000) = 0x793000
old_mmap(0x797000, 7356, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|
MAP_ANONYMOUS, -1, 0) = 0x797000
close(3) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS,
-1, 0) = 0xb7f20000
mprotect(0x793000, 8192, PROT_READ) = 0
mprotect(0x669000, 4096, PROT_READ) = 0
set_thread_area({entry_number:-1 -> 6, base_addr:0xb7f20940, limit:
1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1,
seg_not_present:0, useable:1}) = 0
munmap(0xb7f21000, 71234) = 0
socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0
ioctl(3, CDROMREADTOCENTRY, 0x2) = -1 EFAULT (Bad address)
dup(2) = 5
fcntl64(5, F_GETFL) = 0x8002 (flags O_RDWR|
O_LARGEFILE)
brk(0) = 0x8b18000
brk(0x8b39000) = 0x8b39000
fstat64(5, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0xb7f32000
_llseek(5, 0, 0xbfe58830, SEEK_CUR) = -1 ESPIPE (Illegal seek)
write(5, "ioctl: Bad address\n", 19ioctl: Bad address
) = 19
close(5) = 0
munmap(0xb7f32000, 4096) = 0
exit_group(0) = ?
I hope this extra details help you and others to understand the
problem.
Let me know if you have any suggestions to replace ioctl()
functionality (set the read to message-nondiscard mode) with other
APIs.
Thanks,
Prakash
...
>> > � � � � /* Create unnamed socket pairs */
>> > � � � � if ( socketpair(AF_UNIX, SOCK_STREAM,0,fd) == -1 ){
>> > � � � � � � � � fprintf(stdout, "socketpair call failed with errno: %d
>> > \n", errno);
>> > � � � � � � � � exit(1);
>> > � � � � }
>>
>> > � � � � fd_read = fd[0];
>> > � � � � fd_write = fd[1];
>>
>> > � � � � /* fcntl code comes here �to set non blocking read */
>>
>> > � � � � if ( ioctl(fd_read, I_SRDOPT, RMSGN �) == -1 ){ �/* set read mode to message -nondiscard mode */
>> > � � � � � � � � fprintf(stdout, "ioctl call failed with below error:\n" );
...
>> I_SRDOPT seems to be related to STREAMS. I cannot find it documented
>> in Stevens' "Unixnetwork programming" books, and I have never used
>> STREAMS myself. �But I know the Linux people generally dislike it, and
>> last time I heard it was /not/ part of Linux except as a kernel patch.
>> It is most likely /not/ in RedHat's kernel.
>>
>> But the question is: if this is indeed STREAMS, and you don't have
>> that, then why are the ioctls defined in theheader files? �Perhaps
>> there are good reasons, but it's better when code that cannot possibly
>> work doesn't compile ...
>>
>> Also, normally I expect 'gcc -std=c89 -Wall -W -pedantic ...' not to
>> compile unless I say "I want BSD APIs" or "I want POSIX this and
>> that". See features.h. But for these things, there was *no*
>> protection. That's surely a bug in the headers.
>>
>> Someone else has to answer, but it seems to me you have a problem
>> here. The program you try to port uses Solaris-specific APIs. (OK,
>> some other Unices in the past may have had STREAMS too, but neither of
>> the healthy Unices -- Linux and the BSDs -- have it).
> Here is the output of strace:
...
> socketpair(PF_FILE, SOCK_STREAM, 0, [3, 4]) = 0
> ioctl(3, CDROMREADTOCENTRY, 0x2) = -1 EFAULT (Bad address)
...
> I hope this extra details help you and others to understand the
> problem.
I already understand enough to be happy. You try to use STREAMS, and
Linux doesn't have STREAMS. And some glibc quirk makes this invisible
until you run the program.
> Let me know if you have any suggestions to replace ioctl()
> functionality (set the read to message-nondiscard mode) with other
> APIs.
As I wrote, I know nothing about STREAMS, so I cannot even understand
what "message-nondiscard mode" means, and cannot suggest alternatives.
If noone else here answers, and Google doesn't help, perhaps you can
ask on a Solaris newsgroup. comp.unix.solaris seems fairly active.
> If noone else here answers, and Google doesn't help, perhaps you can
> ask on a Solaris newsgroup. comp.unix.solaris seems fairly active.
Shouldn't he ask on a Linux newsgroup?
I don't see what this has to do with TCP/IP at all, since he's using
Unix domain sockets.
--
Barry Margolin, bar...@alum.mit.edu
The Solaris people are more likely to understand STREAMS, understand
what his code is supposed to do, and know the portable alternatives.
(They are less unlikely to know the Linux-specific alternatives if
there are any, so crossposting to some Linux group might be a good
idea after all.)
> I don't see what this has to do with TCP/IP at all, since he's using
> Unix domain sockets.
Neither do I, but pointing him in the right direction seemed like a
good idea anyway.
Thank you...I will post it in other Linux groups.
Thanks,
Prakash