solaris-utmpx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bea80841580cccc83697be3b85853852a04fc799
4
+ data.tar.gz: a23e1f074cd99fbe8b488827deddfbafaed497dc
5
+ SHA512:
6
+ metadata.gz: df97be060d9ced25a54d277008531a3912243d14147b85b93b8e6340b5cd64267359fa93b4ff744e5e6b97f5a2af3a05a7198d3af1a90baef89ae0a7afb2abdb
7
+ data.tar.gz: 506f30185ec4434791475c8af09a515e500e3851cc83915109f6bd6f78164cef1724f4e1a70405e14b7f79d3fff8c121a974ca34f5553d6ac64661e58244f34e
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright 2013 Martin Carpenter. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without modification, are
4
+ permitted provided that the following conditions are met:
5
+
6
+ 1. Redistributions of source code must retain the above copyright notice, this list of
7
+ conditions and the following disclaimer.
8
+
9
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list
10
+ of conditions and the following disclaimer in the documentation and/or other materials
11
+ provided with the distribution.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY Martin Carpenter ``AS IS'' AND ANY EXPRESS OR IMPLIED
14
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
15
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Martin Carpenter OR
16
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
17
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
21
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+
23
+ The views and conclusions contained in the software and documentation are those of the
24
+ authors and should not be interpreted as representing official policies, either expressed
25
+ or implied, of Martin Carpenter.
26
+
@@ -0,0 +1,34 @@
1
+
2
+ = solaris-utmpx
3
+
4
+ Author:: Martin Carpenter
5
+ Email:: mcarpenter@free.fr
6
+ Copyright:: Copyright (c) Martin Carpenter 2013
7
+
8
+ == About
9
+ The solaris-utmpx gem helps with the reading and writing of Solaris
10
+ binary utmpx(4) and wtmpx(4) files.
11
+
12
+ == Examples
13
+
14
+ === Read and display all records in wtmpx
15
+
16
+ require 'solaris/utmpx'
17
+
18
+ io = File.open('/var/adm/wtmpx', 'r')
19
+ reader = Solaris::Wtmpx.new(:endian => :little)
20
+ while !io.eof? do
21
+ puts reader.read(io)
22
+ end
23
+
24
+ === Filter all root entries from wtmpx
25
+
26
+ require 'solaris/utmpx'
27
+
28
+ io = File.open('/var/adm/wtmpx', 'r')
29
+ reader = Solaris::Wtmpx.new(:endian => :little)
30
+ while !io.eof? do
31
+ record = reader.read(io)
32
+ print record.to_binary_s unless record.ut_user == 'root'
33
+ end
34
+
@@ -0,0 +1,28 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rdoc/task'
5
+ require 'rubygems/package_task'
6
+
7
+ desc 'Default task (package)'
8
+ task :default => [:package]
9
+
10
+ Rake::TestTask.new( 'test' )
11
+
12
+ SPECFILE = 'solaris-utmpx.gemspec'
13
+ if File.exist?( SPECFILE )
14
+ spec = eval( File.read( SPECFILE ) )
15
+ Gem::PackageTask.new( spec ).define
16
+ end
17
+
18
+ RDoc::Task.new do |rdoc|
19
+ rdoc.rdoc_dir = 'rdoc'
20
+ rdoc.title = 'solaris-utmpx'
21
+ rdoc.options << '--charset' << 'utf-8'
22
+ rdoc.options << '--main' << 'README.rdoc'
23
+ rdoc.options << '--all'
24
+ rdoc.rdoc_files.include( 'README.rdoc' )
25
+ rdoc.rdoc_files.include( FileList[ 'lib/**/*.rb' ] )
26
+ rdoc.rdoc_files.include( FileList[ 'test/**/*.rb' ] )
27
+ end
28
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'solaris/utmpx'
4
+
5
+ io = File.open(ARGV[0], 'r')
6
+ reader = Solaris::Utmpx.new(:endian => :little)
7
+ while !io.eof? do
8
+ record = reader.read(io)
9
+ print record.to_binary_s unless record.ut_user == 'root'
10
+ end
11
+
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'solaris/utmpx'
4
+
5
+ io = File.open(ARGV[0], 'r')
6
+ reader = Solaris::Utmpx.new(:endian => :little)
7
+ while !io.eof? do
8
+ puts reader.read(io)
9
+ end
10
+
@@ -0,0 +1,7 @@
1
+
2
+ # Namespace for child classes.
3
+ module Solaris
4
+
5
+ require 'solaris/utmpx'
6
+
7
+ end
@@ -0,0 +1,113 @@
1
+
2
+ require 'bindata'
3
+
4
+ module Solaris
5
+
6
+ # See "struct futmpx" in /usr/include/utmpx.h:
7
+ #
8
+ # struct futmpx {
9
+ # char ut_user[32]; /* user login name */
10
+ # char ut_id[4]; /* inittab id */
11
+ # char ut_line[32]; /* device name (console, lnxx) */
12
+ # pid32_t ut_pid; /* process id */
13
+ # int16_t ut_type; /* type of entry */
14
+ # struct {
15
+ # int16_t e_termination; /* process termination status */
16
+ # int16_t e_exit; /* process exit status */
17
+ # } ut_exit; /* exit status of a process */
18
+ # struct timeval32 ut_tv; /* time entry was made */
19
+ # int32_t ut_session; /* session ID, user for windowing */
20
+ # int32_t pad[5]; /* reserved for future use */
21
+ # int16_t ut_syslen; /* significant length of ut_host */
22
+ # char ut_host[257]; /* remote host name */
23
+ # };
24
+ #
25
+ class Utmpx < BinData::Record
26
+
27
+ # The (anonymous) class of generated records.
28
+ attr_reader :record_class
29
+
30
+ # Length of a raw utmpx record in bytes.
31
+ RECORD_LENGTH = 372
32
+
33
+ # Create a new Utmpx factory object. Options are:
34
+ # * :endian -- mandatory, set to :big (SPARC) or :little (i386)
35
+ # * :trim_padding -- trim terminating nulls from read strings
36
+ # This will generate objects that are subclasses of BinData::Record.
37
+ def initialize(opts)
38
+
39
+ endianism = nil
40
+ trim_padding = true
41
+ opts.each do |key, value|
42
+ case key
43
+ when :endian
44
+ endianism = value
45
+ when :trim_padding
46
+ trim_padding = value
47
+ else
48
+ raise ArgumentError, "Unknown option #{key.inspect}"
49
+ end
50
+ end
51
+
52
+ @record_class = Class.new(BinData::Record) do
53
+
54
+ endian endianism
55
+
56
+ string :ut_user, :length => 32, :trim_padding => trim_padding
57
+ string :ut_id, :length => 4, :trim_padding => trim_padding
58
+ string :ut_line, :length => 32, :trim_padding => trim_padding
59
+ uint32 :ut_pid
60
+ uint16 :ut_type
61
+ string :pad_word1, :length => 2 # align to 4 byte words
62
+ uint16 :ut_termination
63
+ uint16 :ut_exit
64
+ uint32 :ut_tv_sec
65
+ uint32 :ut_tv_usec
66
+ uint32 :ut_session
67
+ uint32 :pad0
68
+ uint32 :pad1
69
+ uint32 :pad2
70
+ uint32 :pad3
71
+ uint32 :pad4
72
+ uint16 :ut_syslen
73
+ string :ut_host, :length => 257, :trim_padding => trim_padding
74
+ string :pad_word2, :length => 1 # align to 4 byte words
75
+
76
+ # Return the timestamp of this record as a Time object in the local TZ.
77
+ def localtime
78
+ Time.at(self.ut_tv_sec + self.ut_tv_usec / 1_000_000.0)
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ # Create a new record. Interesting option keys are:
86
+ # * :ut_user
87
+ # * :ut_id
88
+ # * :ut_line
89
+ # * :ut_pid
90
+ # * :ut_type
91
+ # * :ut_termination
92
+ # * :ut_exit
93
+ # * :ut_tv_sec
94
+ # * :ut_tv_usec
95
+ # * :ut_session
96
+ # * :ut_syslen
97
+ # * :ut_host
98
+ def create(opts={})
99
+ # BinData silently discards unknown fields so we check.
100
+ unknown_fields = opts.keys - self.record_class.fields.fields.map(&:name)
101
+ raise ArgumentError, "Unknown fields #{unknown_fields.inspect}" unless unknown_fields.empty?
102
+ @record_class.new(opts)
103
+ end
104
+
105
+ # Read a utmpx record from the given IO object.
106
+ def read(io)
107
+ @record_class.read(io)
108
+ end
109
+
110
+ end # Utmpx
111
+
112
+ end # Solaris
113
+
@@ -0,0 +1,45 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/utmpx'
4
+
5
+ class TestCreate < Test::Unit::TestCase #:nodoc:
6
+
7
+ def test_create
8
+ utmpx = Solaris::Utmpx.new(:endian => :big)
9
+ record = utmpx.create(
10
+ :ut_user => "root",
11
+ :ut_id => "co10",
12
+ :ut_line => "console",
13
+ :ut_pid => 1407,
14
+ :ut_type => 7,
15
+ :ut_termination => 0,
16
+ :ut_exit => 53726,
17
+ :ut_tv_sec => 1297338834,
18
+ :ut_tv_usec => 0,
19
+ :ut_session => 0,
20
+ :ut_syslen => 8,
21
+ :ut_host => "jupiter"
22
+ )
23
+ assert_equal("root", record.ut_user)
24
+ assert_equal("co10", record.ut_id)
25
+ assert_equal("console", record.ut_line)
26
+ assert_equal(1407, record.ut_pid)
27
+ assert_equal(7, record.ut_type)
28
+ assert_equal(0, record.ut_termination)
29
+ assert_equal(53726, record.ut_exit)
30
+ assert_equal(1297338834, record.ut_tv_sec)
31
+ assert_equal(0, record.ut_tv_usec)
32
+ assert_equal(0, record.ut_session)
33
+ assert_equal(8, record.ut_syslen)
34
+ assert_equal("jupiter", record.ut_host)
35
+ end
36
+
37
+ def test_create_invalid_fields
38
+ utmpx = Solaris::Utmpx.new(:endian => :big)
39
+ assert_raise(ArgumentError) do
40
+ utmpx.create(:quack => :boom)
41
+ end
42
+ end
43
+
44
+ end # TestCreate
45
+
@@ -0,0 +1,59 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/utmpx'
4
+
5
+ class TestUtmpxI386 < Test::Unit::TestCase #:nodoc:
6
+
7
+ def setup
8
+ @reader = Solaris::Utmpx.new(:endian => :little)
9
+ @io = File.open(File.join(File.dirname(__FILE__), 'wtmpx.i386'), 'r')
10
+ @records = []
11
+ 4.times { @records << @reader.read(@io) }
12
+ end
13
+
14
+ def teardown
15
+ @io.close
16
+ end
17
+
18
+ def test_read
19
+ assert_equal("root", @records[3].ut_user)
20
+ assert_equal("co10", @records[3].ut_id)
21
+ assert_equal("console", @records[3].ut_line)
22
+ assert_equal(1407, @records[3].ut_pid)
23
+ assert_equal(7, @records[3].ut_type)
24
+ assert_equal(0, @records[3].ut_termination)
25
+ assert_equal(53726, @records[3].ut_exit)
26
+ assert_equal(1297338834, @records[3].ut_tv_sec)
27
+ assert_equal(0, @records[3].ut_tv_usec)
28
+ assert_equal(0, @records[3].ut_session)
29
+ assert_equal(0, @records[3].ut_syslen)
30
+ assert_equal("", @records[3].ut_host)
31
+ end
32
+
33
+ def test_record_length
34
+ @records.each do |record|
35
+ assert_equal(Solaris::Utmpx::RECORD_LENGTH, record.to_binary_s.length)
36
+ end
37
+ end
38
+
39
+ def test_ut_syslen
40
+ @records.each do |record|
41
+ # +1 since ut_syslen includes terminating null but only when non-zero
42
+ if record.ut_syslen == 0
43
+ assert_equal(record.ut_syslen, record.ut_host.length, "#{record}")
44
+ else
45
+ assert_equal(record.ut_syslen, record.ut_host.length + 1, "#{record}")
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_to_binary_s
51
+ @io.rewind
52
+ @records.each do |record|
53
+ raw = @io.read(Solaris::Utmpx::RECORD_LENGTH)
54
+ assert_equal(raw, record.to_binary_s)
55
+ end
56
+ end
57
+
58
+ end # TestUtmpxI386
59
+
@@ -0,0 +1,59 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/utmpx'
4
+
5
+ class TestUtmpxSparc < Test::Unit::TestCase #:nodoc:
6
+
7
+ def setup
8
+ @reader = Solaris::Utmpx.new(:endian => :big)
9
+ @io = File.open(File.join(File.dirname(__FILE__), 'wtmpx.sparc'), 'r')
10
+ @records = []
11
+ 4.times { @records << @reader.read(@io) }
12
+ end
13
+
14
+ def teardown
15
+ @io.close
16
+ end
17
+
18
+ def test_read
19
+ assert_equal("root", @records[3].ut_user)
20
+ assert_equal("co10", @records[3].ut_id)
21
+ assert_equal("console", @records[3].ut_line)
22
+ assert_equal(3944, @records[3].ut_pid)
23
+ assert_equal(7, @records[3].ut_type)
24
+ assert_equal(0, @records[3].ut_termination)
25
+ assert_equal(0, @records[3].ut_exit)
26
+ assert_equal(1230681969, @records[3].ut_tv_sec)
27
+ assert_equal(0, @records[3].ut_tv_usec)
28
+ assert_equal(0, @records[3].ut_session)
29
+ assert_equal(0, @records[3].ut_syslen)
30
+ assert_equal("", @records[3].ut_host)
31
+ end
32
+
33
+ def test_record_length
34
+ @records.each do |record|
35
+ assert_equal(Solaris::Utmpx::RECORD_LENGTH, record.to_binary_s.length)
36
+ end
37
+ end
38
+
39
+ def test_ut_syslen
40
+ @records.each do |record|
41
+ # +1 since ut_syslen includes terminating null but only when non-zero
42
+ if record.ut_syslen == 0
43
+ assert_equal(record.ut_syslen, record.ut_host.length, "#{record}")
44
+ else
45
+ assert_equal(record.ut_syslen, record.ut_host.length + 1, "#{record}")
46
+ end
47
+ end
48
+ end
49
+
50
+ def test_to_binary_s
51
+ @io.rewind
52
+ @records.each do |record|
53
+ raw = @io.read(Solaris::Utmpx::RECORD_LENGTH)
54
+ assert_equal(raw, record.to_binary_s)
55
+ end
56
+ end
57
+
58
+ end # TestUtmpxSparc
59
+
Binary file
Binary file
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solaris-utmpx
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Martin Carpenter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bindata
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.5.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.5.0
27
+ description: Read and write Solaris utmpx and wtmpx files
28
+ email: mcarpenter@free.fr
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - Rakefile
34
+ - README.rdoc
35
+ files:
36
+ - examples/filter_root.rb
37
+ - examples/wtmpx.rb
38
+ - lib/solaris.rb
39
+ - lib/solaris/utmpx.rb
40
+ - test/test_create.rb
41
+ - test/test_utmpx_i386.rb
42
+ - test/test_utmpx_sparc.rb
43
+ - test/wtmpx.i386
44
+ - test/wtmpx.sparc
45
+ - LICENSE
46
+ - Rakefile
47
+ - README.rdoc
48
+ homepage: http://github.com/mcarpenter/solaris-utmpx
49
+ licenses:
50
+ - BSD
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.0.3
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Read and write Solaris utmpx and wtmpx files
72
+ test_files:
73
+ - test/test_create.rb
74
+ - test/test_utmpx_i386.rb
75
+ - test/test_utmpx_sparc.rb