solaris-lastlog 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0a32aafce3d78d5a27ccc119bda3f64a77bd6d84
4
+ data.tar.gz: 2e299e8826ecfbbb0267251b76a77225ffa6ace7
5
+ SHA512:
6
+ metadata.gz: 75c104e82828bed23b5b5be98fa5e7288ead6030167d56a79ce1c1f30fddd856af0610c9aad4a703b765bc7bd9196c8a4bc84a2bc068562c5d925045024f8036
7
+ data.tar.gz: 00a7158310efd66306124570cb405cc4d639c7eb198ac97af9b559dc72a83b2b9547167deb1e5a40aa4d6ceb813eccf1396637dfa27722d8a0d34ac4a70421f4
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,47 @@
1
+
2
+ = solaris-lastlog
3
+
4
+ Author:: Martin Carpenter
5
+ Email:: mcarpenter@free.fr
6
+ Copyright:: Copyright (c) Martin Carpenter 2013
7
+
8
+ == About
9
+ The solaris-lastlog gem helps with the reading and writing of Solaris
10
+ binary lastlog(4) files.
11
+
12
+ == Examples
13
+
14
+ See the examples subdirectory.
15
+
16
+ === Read and display all non-null entries in the lastlog
17
+
18
+ require 'solaris/lastlog'
19
+
20
+ io = File.open('/var/adm/lastlog', 'r')
21
+ reader = Solaris::Lastlog.new(:endian => :little)
22
+ uid = 0
23
+ while !io.eof? do
24
+ record = reader.read(io)
25
+ unless record.ll_time.zero?
26
+ time = Time.at(record.ll_time)
27
+ puts "%-5s %s %-16s %-8s" % [uid, time, record.ll_host, record.ll_line]
28
+ end
29
+ uid += 1
30
+ end
31
+
32
+ === Filter the lastlog and set root's last login time to the current time
33
+
34
+ require 'solaris/lastlog'
35
+
36
+ io = File.open('/var/adm/lastlog', 'r')
37
+ reader = Solaris::Lastlog.new(:endian => :little)
38
+ first_record = true
39
+ while !io.eof? do
40
+ record = reader.read(io)
41
+ if first_record
42
+ first_record = false
43
+ record.ll_time = Time.now.to_i
44
+ end
45
+ print record.to_binary_s
46
+ end
47
+
@@ -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-lastlog.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-lastlog'
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,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'solaris/lastlog'
4
+
5
+ io = File.open(ARGV[0], 'r')
6
+ reader = Solaris::Lastlog.new(:endian => :little)
7
+ uid = 0
8
+ while !io.eof? do
9
+ record = reader.read(io)
10
+ unless record.ll_time.zero?
11
+ time = Time.at(record.ll_time)
12
+ puts "%-5s %s %-16s %-8s" % [uid, time, record.ll_host, record.ll_line]
13
+ end
14
+ uid += 1
15
+ end
16
+
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'solaris/lastlog'
4
+
5
+ io = File.open(ARGV[0], 'r')
6
+ reader = Solaris::Lastlog.new(:endian => :little)
7
+ first_record = true
8
+ while !io.eof? do
9
+ record = reader.read(io)
10
+ if first_record
11
+ record.ll_time = Time.now.to_i
12
+ first_record = false
13
+ end
14
+ print record.to_binary_s
15
+ end
16
+
@@ -0,0 +1,7 @@
1
+
2
+ # Namespace for child classes.
3
+ module Solaris
4
+
5
+ require 'solaris/lastlog'
6
+
7
+ end
@@ -0,0 +1,82 @@
1
+
2
+ require 'bindata'
3
+
4
+ module Solaris
5
+
6
+ # See "struct lastlog" in /usr/include/lastlog.h:
7
+ #
8
+ # struct lastlog {
9
+ # #ifdef _LP64
10
+ # time32_t ll_time;
11
+ # #else
12
+ # time_t ll_time;
13
+ # #endif
14
+ # char ll_line[8];
15
+ # char ll_host[16]; /* same as in utmp */
16
+ # };
17
+ #
18
+ class Lastlog
19
+
20
+ # The (anonymous) class of generated records.
21
+ attr_reader :record_class
22
+
23
+ # Length of a raw lastlog record in bytes.
24
+ RECORD_LENGTH = 28
25
+
26
+ # Create a new Lastlog factory object. Options are:
27
+ # * :endian -- mandatory, set to :big (SPARC) or :little (i386)
28
+ # * :trim_padding -- trim terminating nulls from read strings
29
+ # This will generate objects of an anonymous class that is a subclass
30
+ # of BinData::Record.
31
+ def initialize(opts)
32
+
33
+ endianism = nil
34
+ trim_padding = true
35
+ opts.each do |key, value|
36
+ case key
37
+ when :endian
38
+ endianism = value
39
+ when :trim_padding
40
+ trim_padding = value
41
+ else
42
+ raise ArgumentError, "Unknown option #{key.inspect}"
43
+ end
44
+ end
45
+
46
+ @record_class = Class.new(BinData::Record) do
47
+
48
+ endian endianism
49
+
50
+ uint32 :ll_time
51
+ string :ll_line, :length => 8, :trim_padding => trim_padding
52
+ string :ll_host, :length => 16, :trim_padding => trim_padding
53
+
54
+ # Return the timestamp of this record as a Time object in the local TZ.
55
+ def localtime
56
+ Time.at(self.ll_time)
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ # Create a new record. Option keys are:
64
+ # * :ll_time
65
+ # * :ll_line
66
+ # * :ll_host
67
+ def create(opts={})
68
+ # BinData silently discards unknown fields so we check.
69
+ unknown_fields = opts.keys - self.record_class.fields.fields.map(&:name)
70
+ raise ArgumentError, "Unknown fields #{unknown_fields.inspect}" unless unknown_fields.empty?
71
+ @record_class.new(opts)
72
+ end
73
+
74
+ # Read a lastlog record from the given IO object.
75
+ def read(io)
76
+ @record_class.read(io)
77
+ end
78
+
79
+ end # Lastlog
80
+
81
+ end # Solaris
82
+
Binary file
Binary file
@@ -0,0 +1,31 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/lastlog'
4
+
5
+ class TestCreate < Test::Unit::TestCase #:nodoc:
6
+
7
+ def test_create
8
+ lastlog = Solaris::Lastlog.new(:endian => :big)
9
+ record = lastlog.create(:ll_time => 1375010633, :ll_host => "neptune", :ll_line => "pts/1")
10
+ assert_equal(1375010633, record.ll_time)
11
+ assert_equal("neptune", record.ll_host)
12
+ assert_equal("pts/1", record.ll_line)
13
+ end
14
+
15
+ def test_create_with_padding
16
+ lastlog = Solaris::Lastlog.new(:endian => :big, :trim_padding => false)
17
+ record = lastlog.create(:ll_time => 1375010633, :ll_host => "neptune", :ll_line => "pts/1")
18
+ assert_equal(1375010633, record.ll_time)
19
+ assert_equal("neptune\x00\x00\x00\x00\x00\x00\x00\x00\x00", record.ll_host)
20
+ assert_equal("pts/1\x00\x00\x00", record.ll_line)
21
+ end
22
+
23
+ def test_create_invalid_fields
24
+ lastlog = Solaris::Lastlog.new(:endian => :big)
25
+ assert_raise(ArgumentError) do
26
+ lastlog.create(:quack => :boom)
27
+ end
28
+ end
29
+
30
+ end # TestCreate
31
+
@@ -0,0 +1,64 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/lastlog'
4
+
5
+ class TestLastlogI386 < Test::Unit::TestCase #:nodoc:
6
+
7
+ def setup
8
+ @reader = Solaris::Lastlog.new(:endian => :little)
9
+ @io = File.open(File.join(File.dirname(__FILE__), 'lastlog.i386'), 'r')
10
+ @root_entry = @reader.read(@io)
11
+ end
12
+
13
+ def teardown
14
+ @io.close
15
+ end
16
+
17
+ def test_read
18
+ assert_equal(1366318982, @root_entry.ll_time)
19
+ assert_equal("console", @root_entry.ll_line)
20
+ assert_equal("jupiter", @root_entry.ll_host)
21
+ assert_equal(Solaris::Lastlog::RECORD_LENGTH, @root_entry.to_binary_s.length)
22
+ end
23
+
24
+ def test_trim_padding
25
+ @reader = Solaris::Lastlog.new(:endian => :little, :trim_padding => false)
26
+ @io.rewind
27
+ @root_entry = @reader.read(@io)
28
+ assert_equal(1366318982, @root_entry.ll_time)
29
+ assert_equal("console\x0", @root_entry.ll_line)
30
+ assert_equal("jupiter\x0\x0\x0\x0\x0\x0\x0\x0\x0", @root_entry.ll_host)
31
+ end
32
+
33
+ def test_host
34
+ assert_equal("jupiter", @root_entry.ll_host)
35
+ @root_entry.ll_host = "host"
36
+ assert_equal("host", @root_entry.ll_host)
37
+ @root_entry.ll_host = "12345678901234567" # too long
38
+ assert_equal("1234567890123456", @root_entry.ll_host)
39
+ end
40
+
41
+ def test_line
42
+ assert_equal("console", @root_entry.ll_line)
43
+ @root_entry.ll_line = "line"
44
+ assert_equal("line", @root_entry.ll_line)
45
+ assert_equal("line", @root_entry.ll_line)
46
+ @root_entry.ll_line = "123456789" # too long
47
+ assert_equal("12345678", @root_entry.ll_line)
48
+ end
49
+
50
+ def test_time
51
+ assert_equal(Time.at(1366318982).to_i, @root_entry.ll_time)
52
+ now = Time.now.to_i
53
+ @root_entry.ll_time = now
54
+ assert_equal(now, @root_entry.ll_time)
55
+ end
56
+
57
+ def test_to_binary_s
58
+ @io.rewind
59
+ raw = @io.read(Solaris::Lastlog::RECORD_LENGTH)
60
+ assert_equal(raw, @root_entry.to_binary_s)
61
+ end
62
+
63
+ end # TestLastlogI386
64
+
@@ -0,0 +1,64 @@
1
+
2
+ require 'test/unit'
3
+ require 'solaris/lastlog'
4
+
5
+ class TestLastlogSparc < Test::Unit::TestCase #:nodoc:
6
+
7
+ def setup
8
+ @reader = Solaris::Lastlog.new(:endian => :big)
9
+ @io = File.open(File.join(File.dirname(__FILE__), 'lastlog.sparc'), 'r')
10
+ @root_entry = @reader.read(@io)
11
+ end
12
+
13
+ def teardown
14
+ @io.close
15
+ end
16
+
17
+ def test_read
18
+ assert_equal(1375005527, @root_entry.ll_time)
19
+ assert_equal("console", @root_entry.ll_line)
20
+ assert_equal("jupiter", @root_entry.ll_host)
21
+ assert_equal(Solaris::Lastlog::RECORD_LENGTH, @root_entry.to_binary_s.length)
22
+ end
23
+
24
+ def test_trim_padding
25
+ @reader = Solaris::Lastlog.new(:endian => :big, :trim_padding => false)
26
+ @io.rewind
27
+ @root_entry = @reader.read(@io)
28
+ assert_equal(1375005527, @root_entry.ll_time)
29
+ assert_equal("console\x0", @root_entry.ll_line)
30
+ assert_equal("jupiter\x0\x0\x0\x0\x0\x0\x0\x0\x0", @root_entry.ll_host)
31
+ end
32
+
33
+ def test_host
34
+ assert_equal("jupiter", @root_entry.ll_host)
35
+ @root_entry.ll_host = "host"
36
+ assert_equal("host", @root_entry.ll_host)
37
+ @root_entry.ll_host = "12345678901234567" # too long
38
+ assert_equal("1234567890123456", @root_entry.ll_host)
39
+ end
40
+
41
+ def test_line
42
+ assert_equal("console", @root_entry.ll_line)
43
+ @root_entry.ll_line = "line"
44
+ assert_equal("line", @root_entry.ll_line)
45
+ assert_equal("line", @root_entry.ll_line)
46
+ @root_entry.ll_line = "123456789" # too long
47
+ assert_equal("12345678", @root_entry.ll_line)
48
+ end
49
+
50
+ def test_time
51
+ assert_equal(Time.at(1375005527).to_i, @root_entry.ll_time)
52
+ now = Time.now.to_i
53
+ @root_entry.ll_time = now
54
+ assert_equal(now, @root_entry.ll_time)
55
+ end
56
+
57
+ def test_to_binary_s
58
+ @io.rewind
59
+ raw = @io.read(Solaris::Lastlog::RECORD_LENGTH)
60
+ assert_equal(raw, @root_entry.to_binary_s)
61
+ end
62
+
63
+ end # TestLastlogSparc
64
+
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solaris-lastlog
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 lastlog 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/lastlog.rb
37
+ - examples/set_root_time.rb
38
+ - lib/solaris.rb
39
+ - lib/solaris/lastlog.rb
40
+ - test/lastlog.i386
41
+ - test/lastlog.sparc
42
+ - test/test_create.rb
43
+ - test/test_lastlog_i386.rb
44
+ - test/test_lastlog_sparc.rb
45
+ - LICENSE
46
+ - Rakefile
47
+ - README.rdoc
48
+ homepage: http://github.com/mcarpenter/solaris-lastlog
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 lastlog files
72
+ test_files:
73
+ - test/test_create.rb
74
+ - test/test_lastlog_i386.rb
75
+ - test/test_lastlog_sparc.rb