FFI, getutxent question

D

Daniel Berger

Hi

According to the man page, the prototypes for getutxent(), setutxent()
and endutxent() are as follows:

void endutxent(void);
struct utmpx * getutxent(void);
void setutxent(void);

So, I declared them like so:

require 'ffi'

class Info
extend FFI::Library

attach_function :setutxent, [], :void
attach_function :getutxent, [], :pointer
attach_function :endutxent, [], :void

def self.getstuff
begin
setutxent()
p getutxent() # NULL Pointer ???
ensure
endutxent()
end
end
end

Info.getstuff # Null Pointer object

However, the call to getutxent() returns a NULL pointer. I'm guessing I
have to tell it what kind of pointer to return, but I wasn't sure how to
do that. How do I do that?

Regards,

Dan
 
A

Andrea Fazzi

Daniel said:
Info.getstuff # Null Pointer object

Your script runs smoothly on my system (Ubuntu Linux) returning a proper
NativePointer object. It seems that the issue is related to your
environment rather then FFI.
However, the call to getutxent() returns a NULL pointer. I'm guessing I
have to tell it what kind of pointer to return, but I wasn't sure how to
do that. How do I do that?

You don't. Once you get a proper pointer object you'll use it to
instantiate the Utmpx class:

Utmpx.new(getutxent)

The Utmpx class will be a subclass of FFI::Struct that mirrors the
layout of the C counterpart. Moreover, as I can see from libc reference
manual[1], utmpx has nested structs within. The good news is that
Ruby-FFI has support for nested structs. The bad one is that you have to
define all the nested structs by hand:

class Pid < FFI::Struct
layout ...
end

...

class Utmpx < FFI::Struct
layout :ut_type, :short,
:ut_pid, Pid
...
end

Regards,
Andrea
 
D

Daniel Berger

Your script runs smoothly on my system (Ubuntu Linux) returning a proper
NativePointer object. It seems that the issue is related to your
environment rather then FFI.

Ah, yes. I was on OS X. I tried again on Linux.
However, the call to getutxent() returns a NULL pointer. I'm guessing I
have to tell it what kind of pointer to return, but I wasn't sure how t= o
do that. How do I do that?

You don't. Once you get a proper pointer object you'll use it to
instantiate the Utmpx class:

=A0 Utmpx.new(getutxent)

The Utmpx class will be a subclass of FFI::Struct that mirrors the
layout of the C counterpart. Moreover, as I can see from libc reference
manual[1], utmpx has nested structs within. The good news is that
Ruby-FFI has support for nested structs. The bad one is that you have to
define all the nested structs by hand:

=A0 class Pid < FFI::Struct
=A0 =A0 layout ...
=A0 end

Looks like FFI has a :pid_t type.

I tried this but I'm still having trouble. Part of the problem may be
that I'm not sure how to declare char[] struct members. The docs
indicate there's a :char_array type, but FFI doesn't seem to like it.

require 'ffi'

class Info
extend FFI::Library

BOOT_TIME =3D 2

attach_function :setutxent, [], :void
attach_function :getutxent, [], :pointer
attach_function :endutxent, [], :void

class Timeval < FFI::Struct
layout:)tv_sec, :long, :tv_usec, :long)
end

class Utmpx < FFI::Struct
layout(
:ut_user, :char, 32
:ut_id, :char, 4
:ut_line, :char, 32
:ut_pid, :pid_t,
:ut_type, :short,
:ut_tv, Timeval
)
end

def self.getstuff
time =3D nil

begin
setutxent()
while ent =3D Utmpx.new(getutxent())
if ent[:ut_type] =3D=3D BOOT_TIME
time =3D Time.new(ent[:ut_tv][:tv_sec], ent[:ut_tv]
[:tv_usec])
break
end
end
ensure
endutxent()
end

time
end
end

Info.getstuff

ruby boot_time.rb
boot_time.rb:33:in `[]': NULL Pointer access attempted
(FFI::NullPointerError)
from boot_time.rb:33:in `getstuff'
from boot_time.rb:46

Where line 33 is the ent[:ut_type] reference.

Any suggestions?

Regards,

Dan
 
A

Andrea Fazzi

Daniel said:
I tried this but I'm still having trouble. Part of the problem may be
that I'm not sure how to declare char[] struct members. The docs
indicate there's a :char_array type, but FFI doesn't seem to like it.

Yeah, the docs on the Kenai wiki are pretty out of date at the moment.
We'll fix them when we'll finish the migration on github. Basically, you
can declare array types in this way:

[type, num]

where type can be:

* a native type like :char, :int, :short, ...
* a subclass of FFI::Struct

and num is the number of the elements of the array.

I made some changes on your script and I pasted a working version here:

http://gist.github.com/164777

Keep in mind that the script is working on my system (Ubuntu 32bit) but
might not work on yours. Indeed, as you can see looking at the C header
file "/usr/include/bits/utmpx.h", there are a bunch of precompiler
conditional branches that made structs definitions platform-dependent.

Regards,
Andrea
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

ffi, struct pointer question 2
FFI, sysctl, pointer question 5
JRuby, ffi, bad file descriptor 8
FFI Memory Leak 4
ffi: How to use wchar_t strings? 3
[ANN] ffi 0.5.0 0
FFI and pointers 2
ruby-ffi problem 1

Members online

Forum statistics

Threads
474,470
Messages
2,571,807
Members
48,797
Latest member
PeterSimpson
Top