FFI, getutxent question

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

Daniel Berger wrote:

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

···

--
Posted via http://www.ruby-forum.com/\.

Daniel Berger wrote:
> 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.

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 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

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 = 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 = nil

      begin
         setutxent()
         while ent = Utmpx.new(getutxent())
            if ent[:ut_type] == BOOT_TIME
               time = 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

···

On Aug 9, 2:54 am, Andrea Fazzi <andrea.fa...@alcacoop.it> wrote:

Daniel Berger wrote:

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:

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

···

--
Posted via http://www.ruby-forum.com/\.