fosl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ module FOSL
2
+ end
@@ -0,0 +1,162 @@
1
+ require "fosl/namespace"
2
+ require "fosl/process"
3
+
4
+ class FOSL::Parser
5
+ # Fields are separated by newlines or null
6
+ # Fields start with a character followed by the data
7
+
8
+ # These are the fields according to the lsof manpage.
9
+ # If you want to implement one, you should write a 'parse_<field letter>'
10
+ # method. It should return a hash of key => value you want to save.
11
+ #
12
+ # # The following copied mostly verbatim from the lsof manpage.
13
+ # - a file access mode
14
+ # - c process command name (all characters from proc or user structure)
15
+ # - C file structure share count
16
+ # - d file's device character code
17
+ # - D file's major/minor device number (0x<hexadecimal>)
18
+ # - f file descriptor
19
+ # - F file structure address (0x<hexadecimal>)
20
+ # - G file flaGs (0x<hexadecimal>; names if +fg follows)
21
+ # - i file's inode number
22
+ # - k link count
23
+ # - l file's lock status
24
+ # - L process login name
25
+ # - m marker between repeated output
26
+ # - n file name, comment, Internet address
27
+ # - N node identifier (ox<hexadecimal>
28
+ # - o file's offset (decimal)
29
+ # - p process ID (always selected)
30
+ # - g process group ID
31
+ # - P protocol name
32
+ # - r raw device number (0x<hexadecimal>)
33
+ # - R parent process ID
34
+ # - s file's size (decimal)
35
+ # - S file's stream identification
36
+ # - t file's type
37
+ # - T TCP/TPI information, identified by prefixes (the
38
+ # - u process user ID
39
+ # - z Solaris 10 and higher zone name
40
+ # - Z SELinux security context (inhibited when SELinux is disabled)
41
+
42
+ # T is various network/tcp/socket information.
43
+ def parse_T(data)
44
+ prefix, value = data.split("=")
45
+ case prefix
46
+ when "ST" ; prefix = :state
47
+ when "QR" ; prefix = :read_queue
48
+ when "QS" ; prefix = :send_queue
49
+
50
+ # (sissel) I don't know the values of these fields. Feel free
51
+ # to implement them and send me patches.
52
+ #when "SO" ; prefix = :socket_options
53
+ #when "SS" ; prefix = :socket_State
54
+ #when "TF" ; prefix = :tcp_flags
55
+ #when "WR" ; prefix = :read_window
56
+ #when "WW" ; prefix = :write_window
57
+ end
58
+ return { prefix => value }
59
+ end # def parse_T
60
+
61
+ # The file's type
62
+ def parse_t(data)
63
+ return { :type => data }
64
+ end
65
+
66
+ # The protocol name
67
+ def parse_P(data)
68
+ return { :protocol => data }
69
+ end
70
+
71
+ # the pid
72
+ def parse_p(data)
73
+ new_pid(data.to_i)
74
+ return :new_pid
75
+ end
76
+
77
+ # the file name or identifier
78
+ def parse_n(data)
79
+ return { :name => data }
80
+ end
81
+
82
+ # file descriptor (or 'cwd' etc...)
83
+ def parse_f(data)
84
+ new_file
85
+
86
+ # Convert to int it looks like a number.
87
+ if data.to_i != 0 or data == "0"
88
+ data = data.to_i
89
+ end
90
+
91
+ return { :fd => data }
92
+ end
93
+
94
+ # The command name
95
+ def parse_c(data)
96
+ @current_process.command = data
97
+ return nil
98
+ end
99
+
100
+ # state helper, creates a new process
101
+ def new_pid(pid)
102
+ new_file # push the last file (if any) onto the last process
103
+ @current_process = FOSL::Process.new(pid)
104
+ end
105
+
106
+ # state helper, creates a new file hash
107
+ def new_file
108
+ if !@current_file.nil? && !@current_file.empty?
109
+ @current_process.files << @current_file
110
+ end
111
+
112
+ @current_file = {}
113
+ end
114
+
115
+ # Parse output from an lsof(1) run. You must run
116
+ # This output must be from lsof run with this flag '-F Pcfnt0'
117
+ def parse(data)
118
+ if data[0..0] != "p"
119
+ raise "Expected first character to be 'p'. Unexpected data input - #{data[0..30]}..."
120
+ end
121
+
122
+ result = Hash.new { |h,k| h[k] = FOSL::Process.new(k) }
123
+
124
+ data.split(/[\n\0]/).each do |field|
125
+ next if field.empty?
126
+ type = field[0 .. 0]
127
+ value = field[1 .. -1]
128
+
129
+ method = "parse_#{type}".to_sym
130
+ if self.respond_to?(method)
131
+ r = self.send(method, value)
132
+ #p field => r
133
+ if r.is_a?(Hash)
134
+ @current_file.merge!(r)
135
+ elsif r == :new_pid
136
+ result[@current_process.pid] = @current_process
137
+ end
138
+ else
139
+ $stderr.puts "Unsupported field type '#{type}': #{field.inspect}"
140
+ end
141
+ end
142
+
143
+ # push last file
144
+ new_file
145
+
146
+ return result
147
+ end # def parse
148
+
149
+ # Helper for running lsof.
150
+ # Returns the same thing as 'parse'
151
+ #
152
+ # Example:
153
+ # lsof("-i :443")
154
+ def lsof(args="")
155
+ output = `lsof -F PcfntT0 #{args}`
156
+ # Should we raise an exception, or just return empty results, on failure?
157
+ if $?.exitstatus != 0
158
+ raise "lsof exited with status #{$?.exitstatus}"
159
+ end
160
+ return self.parse(output)
161
+ end
162
+ end # class FOSL::Parser
@@ -0,0 +1,18 @@
1
+ require "fosl/namespace"
2
+
3
+ class FOSL::Process
4
+ attr_reader :files
5
+ attr_reader :pid
6
+ attr_accessor :command
7
+
8
+ def initialize(pid)
9
+ @command = nil
10
+ @pid = pid
11
+ @files = []
12
+ end
13
+
14
+ # helpers
15
+ def listeners
16
+ @files.find_all { |f| f[:state] == "LISTEN" }
17
+ end
18
+ end # class FOSL::Process
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fosl
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jordan Sissel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-18 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: ""
23
+ email: jls@semicomplete.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/fosl/parser.rb
32
+ - lib/fosl/namespace.rb
33
+ - lib/fosl/process.rb
34
+ has_rdoc: true
35
+ homepage: https://github.com/jordansissel/ruby-lsof
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.5.1
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: fosl - a ruby api for reading lsof(1) output
69
+ test_files: []
70
+