Skip to content
This repository

Struct::Passwd#gecos #1930

Merged
merged 5 commits into from over 1 year ago

3 participants

Karol Hosiawa Ian Leitch Brian Shirai
Karol Hosiawa
Collaborator

Repro (current master in 1.8.7 mode):

require 'etc'
a = Etc.getpwent
a.gecos

NoMethodError: undefined method `gecos' on an instance of Struct::Passwd.

Ian Leitch
Collaborator

There are cross platform issues here. Etc is implement with FFI. @brixen @dbussink What's the recommended approach for dealing with this in Rubinius? Implement Etc in C?

Brian Shirai
Owner

What are the issues? You can deal with platform issues in either rakelib/platform.rake or in lib/etc.rb.ffi.

Ian Leitch
Collaborator

struct passwd differs. Mostly just extra members, though there are is one type difference MRI implements. I've not been able to find an example of detecting member presence with FFI (possible?). Conditionals on the platform are the recommended approach then?

Brian Shirai
Owner

Look at rakelib/platform.rake. We also have detection code in configure if it is needed.

Karol Hosiawa
Collaborator

I've added a spec for Struct::Passwd and the #gecos field to Struct::Passwd (needed to run Chef on rbx). The extra platform dependent members that MRI implements (change, quota, age, class, comment, expire)

https://github.com/ruby/ruby/blob/trunk/ext/etc/etc.c

aren't in MRI's official docs http://www.ruby-doc.org/stdlib-1.9.3/libdoc/etc/rdoc/Etc.html#method-c-getpwent

and I couldn't figure out how to make the detection code in configure work with ffi either nor how to write a spec for them (the detection code is in configure, it passes compile flags to rubinius but how do you get to them in mspec in a way that's implementation independent ?)

Brian Shirai brixen merged commit a27d1ff into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
19 lib/etc.rb.ffi
@@ -9,6 +9,7 @@ class Struct::Passwd < FFI::Struct
9 9 s.field :pw_passwd, :string
10 10 s.field :pw_uid, :uid_t
11 11 s.field :pw_gid, :gid_t
  12 + s.field :pw_gecos, :string
12 13 s.field :pw_dir, :string
13 14 s.field :pw_shell, :string
14 15 end
@@ -18,6 +19,7 @@ class Struct::Passwd < FFI::Struct
18 19 def passwd; self[:pw_passwd]; end
19 20 def uid; self[:pw_uid]; end
20 21 def gid; self[:pw_gid]; end
  22 + def gecos; self[:pw_gecos]; end
21 23 def dir; self[:pw_dir]; end
22 24 def shell; self[:pw_shell]; end
23 25 end
@@ -30,12 +32,29 @@ class Struct::Group < FFI::Struct
30 32
31 33 s.name "struct group"
32 34 s.field :gr_name, :string
  35 + s.field :gr_passwd, :string
33 36 s.field :gr_gid, :gid_t
  37 + s.field :gr_mem, :pointer
34 38 end
35 39 @@@
36 40
37 41 def name; self[:gr_name]; end
38 42 def gid; self[:gr_gid]; end
  43 + def passwd; self[:gr_passwd]; end
  44 + def mem
  45 + ptr = self[:gr_mem].read_pointer
  46 +
  47 + ary = []
  48 + i = 1
  49 +
  50 + while not ptr.null? do
  51 + ary << ptr.read_string
  52 + ptr = (self[:gr_mem] + i * FFI::Pointer.size).read_pointer
  53 + i += 1
  54 + end
  55 +
  56 + ary
  57 + end
39 58 end
40 59
41 60 module Etc
27 spec/ruby/library/etc/struct_group_spec.rb
... ... @@ -0,0 +1,27 @@
  1 +require File.expand_path('../../../spec_helper', __FILE__)
  2 +require 'etc'
  3 +
  4 +describe "Struct::Group" do
  5 + platform_is_not :windows do
  6 + before :all do
  7 + @g = Etc.getgrgid(`id -g`.strip.to_i)
  8 + end
  9 +
  10 + it "returns group name" do
  11 + @g.name.should == `id -gn`.strip
  12 + end
  13 +
  14 + it "returns group password" do
  15 + @g.passwd.is_a?(String).should == true
  16 + end
  17 +
  18 + it "returns group id" do
  19 + @g.gid.should == `id -g`.strip.to_i
  20 + end
  21 +
  22 + it "returns an array of users belonging to the group" do
  23 + @g.mem.is_a?(Array).should == true
  24 + end
  25 +
  26 + end
  27 +end
38 spec/ruby/library/etc/struct_passwd_spec.rb
... ... @@ -0,0 +1,38 @@
  1 +require File.expand_path('../../../spec_helper', __FILE__)
  2 +require 'etc'
  3 +
  4 +describe "Struct::Passwd" do
  5 + platform_is_not :windows do
  6 + before :all do
  7 + @pw = Etc.getpwuid(`id -u`.strip.to_i)
  8 + end
  9 +
  10 + it "returns user name" do
  11 + @pw.name.should == `id -un`.strip
  12 + end
  13 +
  14 + it "returns user password" do
  15 + @pw.passwd.is_a?(String).should == true
  16 + end
  17 +
  18 + it "returns user id" do
  19 + @pw.uid.should == `id -u`.strip.to_i
  20 + end
  21 +
  22 + it "returns user group id" do
  23 + @pw.gid.should == `id -g`.strip.to_i
  24 + end
  25 +
  26 + it "returns user personal information (gecos field)" do
  27 + @pw.gecos.is_a?(String).should == true
  28 + end
  29 +
  30 + it "returns user home directory" do
  31 + @pw.dir.is_a?(String).should == true
  32 + end
  33 +
  34 + it "returns user shell" do
  35 + @pw.shell.is_a?(String).should == true
  36 + end
  37 + end
  38 +end

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.