linux_stat 0.9.2 → 1.1.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.
@@ -19,28 +19,28 @@ static VALUE getTick(VALUE obj) {
19
19
  }
20
20
 
21
21
  static VALUE getChildMax(VALUE obj) {
22
- short int val = sysconf(_SC_CHILD_MAX) ;
22
+ long long int val = sysconf(_SC_CHILD_MAX) ;
23
23
  if (val < 0) return Qnil ;
24
24
 
25
25
  return INT2FIX(val) ;
26
26
  }
27
27
 
28
28
  static VALUE getHostnameMax(VALUE obj) {
29
- short int val = sysconf(_SC_HOST_NAME_MAX) ;
29
+ int val = sysconf(_SC_HOST_NAME_MAX) ;
30
30
  if (val < 0) return Qnil ;
31
31
 
32
32
  return INT2FIX(val) ;
33
33
  }
34
34
 
35
35
  static VALUE getLoginNameMax(VALUE obj) {
36
- short int val = sysconf(_SC_LOGIN_NAME_MAX) ;
36
+ int val = sysconf(_SC_LOGIN_NAME_MAX) ;
37
37
  if (val < 0) return Qnil ;
38
38
 
39
39
  return INT2FIX(val) ;
40
40
  }
41
41
 
42
42
  static VALUE getOpenMax(VALUE obj) {
43
- short int val = sysconf(_SC_OPEN_MAX) ;
43
+ int val = sysconf(_SC_OPEN_MAX) ;
44
44
  if (val < 0) return Qnil ;
45
45
 
46
46
  return INT2FIX(val) ;
@@ -54,35 +54,35 @@ static VALUE getPageSize(VALUE obj) {
54
54
  }
55
55
 
56
56
  static VALUE getStreamMax(VALUE obj) {
57
- short int val = sysconf(_SC_STREAM_MAX) ;
57
+ int val = sysconf(_SC_STREAM_MAX) ;
58
58
  if (val < 0) return Qnil ;
59
59
 
60
60
  return INT2FIX(val) ;
61
61
  }
62
62
 
63
63
  static VALUE getTTYNameMax(VALUE obj) {
64
- short int val = sysconf(_SC_TTY_NAME_MAX) ;
64
+ int val = sysconf(_SC_TTY_NAME_MAX) ;
65
65
  if (val < 0) return Qnil ;
66
66
 
67
67
  return INT2FIX(val) ;
68
68
  }
69
69
 
70
70
  static VALUE getPosixVersion(VALUE obj) {
71
- short int val = sysconf(_SC_VERSION) ;
71
+ int val = sysconf(_SC_VERSION) ;
72
72
  if (val < 0) return Qnil ;
73
73
 
74
74
  return INT2FIX(val) ;
75
75
  }
76
76
 
77
77
  static VALUE getLineMax(VALUE obj) {
78
- short int val = sysconf(_SC_LINE_MAX) ;
78
+ int val = sysconf(_SC_LINE_MAX) ;
79
79
  if (val < 0) return Qnil ;
80
80
 
81
81
  return INT2FIX(val) ;
82
82
  }
83
83
 
84
84
  static VALUE getExprNestMax(VALUE obj) {
85
- short int val = sysconf(_SC_EXPR_NEST_MAX) ;
85
+ int val = sysconf(_SC_EXPR_NEST_MAX) ;
86
86
  if (val < 0) return Qnil ;
87
87
 
88
88
  return INT2FIX(val) ;
@@ -25,8 +25,10 @@ require "linux_stat/battery"
25
25
  require "linux_stat/bios"
26
26
  require "linux_stat/memory"
27
27
  require "linux_stat/net"
28
+ require "linux_stat/pci"
28
29
  require "linux_stat/process"
29
30
  require "linux_stat/swap"
31
+ require "linux_stat/usb"
30
32
 
31
33
  # Dependent Modules
32
34
  # Modules that can have reverse dependency
@@ -62,7 +62,7 @@ module LinuxStat
62
62
  end
63
63
 
64
64
  ##
65
- # mount_point(dev = root)
65
+ # = mount_point(dev = root)
66
66
  #
67
67
  # Where device = block device.
68
68
  #
@@ -94,7 +94,7 @@ module LinuxStat
94
94
  end
95
95
 
96
96
  ##
97
- # list_devices_mount_point()
97
+ # = list_devices_mount_point()
98
98
  #
99
99
  # It shows all the block devices corresponding to mount points.
100
100
  #
@@ -120,7 +120,7 @@ module LinuxStat
120
120
  end
121
121
 
122
122
  ##
123
- # devices_stat
123
+ # = devices_stat
124
124
  #
125
125
  # [ Not to confuse this method with device_stat(dev) which shows only one device's info ]
126
126
  #
@@ -162,7 +162,7 @@ module LinuxStat
162
162
  end
163
163
 
164
164
  ##
165
- # device_stat(dev = root)
165
+ # = device_stat(dev = root)
166
166
  #
167
167
  # [ Not to confuse this method with devices_stat() which shows all devices ]
168
168
  #
@@ -17,7 +17,9 @@ module LinuxStat
17
17
  # Returns the total bytes received and transmitted as Hash.
18
18
  #
19
19
  # For example:
20
- # {:received=>56602867, :transmitted=>6940922}
20
+ # LinuxStat::Net.usage
21
+ #
22
+ # => {:received=>56602867, :transmitted=>6940922}
21
23
  #
22
24
  # But if the status isn't available it will return an empty Hash.
23
25
  def total_bytes
@@ -68,7 +70,9 @@ module LinuxStat
68
70
  # The return type is a Hash, containg the current internet usage (received, transmit) in B/s.
69
71
  #
70
72
  # For example:
71
- # {:received=>436060.0, :transmitted=>50350.0}
73
+ # LinuxStat::Net.usage
74
+ #
75
+ # => {:received=>436060.0, :transmitted=>50350.0}
72
76
  #
73
77
  # If the system transmits 100 kb in the interval,
74
78
  #
@@ -3,7 +3,9 @@ module LinuxStat
3
3
  class << self
4
4
  ##
5
5
  # Reads /etc/os-release and returns a Hash. For example:
6
- # {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling", :ANSI_COLOR=>"38;2;23;147;209", :HOME_URL=>"https://www.archlinux.org/", :DOCUMENTATION_URL=>"https://wiki.archlinux.org/", :SUPPORT_URL=>"https://bbs.archlinux.org/", :BUG_REPORT_URL=>"https://bugs.archlinux.org/", :LOGO=>"archlinux"}
6
+ # LinuxStat::OS.os_release
7
+ #
8
+ # => {:NAME=>"Arch Linux", :PRETTY_NAME=>"Arch Linux", :ID=>"arch", :BUILD_ID=>"rolling", :ANSI_COLOR=>"38;2;23;147;209", :HOME_URL=>"https://www.archlinux.org/", :DOCUMENTATION_URL=>"https://wiki.archlinux.org/", :SUPPORT_URL=>"https://bbs.archlinux.org/", :BUG_REPORT_URL=>"https://bugs.archlinux.org/", :LOGO=>"archlinux"}
7
9
  #
8
10
  # If the info isn't available, it will return an empty Hash.
9
11
  #
@@ -13,13 +15,14 @@ module LinuxStat
13
15
  # Because changing the /etc/lsb-release
14
16
  # isn't expected in runtime.
15
17
  def os_release
16
- # cached (memoized) ; as changing the value in runtime is unexpected
17
18
  @@os_release ||= File.readable?('/etc/os-release') ? release('/etc/os-release') : {}
18
19
  end
19
20
 
20
21
  ##
21
22
  # Reads /etc/lsb-release and returns a Hash. For example:
22
- # {:LSB_VERSION=>"1.4", :DISTRIB_ID=>"Arch", :DISTRIB_RELEASE=>"rolling", :DISTRIB_DESCRIPTION=>"Arch Linux"}
23
+ # LinuxStat::OS.lsb_release
24
+ #
25
+ # => {:LSB_VERSION=>"1.4", :DISTRIB_ID=>"Arch", :DISTRIB_RELEASE=>"rolling", :DISTRIB_DESCRIPTION=>"Arch Linux"}
23
26
  #
24
27
  # If the info isn't available, it will return an empty Hash.
25
28
  #
@@ -28,7 +31,6 @@ module LinuxStat
28
31
  # The information is also cached, and once loaded, won't change in runtime.
29
32
  # Because changing the /etc/lsb-release isn't expected in runtime.
30
33
  def lsb_release
31
- # cached (memoized) ; as changing the value in runtime is unexpected
32
34
  @@lsb_release ||= File.readable?('/etc/lsb-release') ? release('/etc/lsb-release') : {}
33
35
  end
34
36
 
@@ -104,7 +106,9 @@ module LinuxStat
104
106
 
105
107
  ##
106
108
  # Reads /proc/uptime and returns the system uptime:
107
- # {:hour=>10, :minute=>34, :second=>12.59}
109
+ # LinuxStat::OS.uptime
110
+ #
111
+ # => {:hour=>10, :minute=>34, :second=>12.59}
108
112
  #
109
113
  # If the stat isn't available, an empty hash is returned.
110
114
  def uptime
@@ -0,0 +1,311 @@
1
+ module LinuxStat
2
+ module PCI
3
+ class << self
4
+ ##
5
+ # = devices_info(hwdata: true)
6
+ #
7
+ # [ Not to be confused with devices_stat ]
8
+ #
9
+ # Take a look at system_stat for more results.
10
+ #
11
+ # Returns details about the devices found in /proc/bus/pci/devices file.
12
+ #
13
+ # The details doesn't contain a lot of details, it's short and opens just one file once.
14
+ #
15
+ # The return value is an Array of multiple Hashes. If there's no info available,
16
+ # it will rather return an empty Array.
17
+ #
18
+ # On Android Termux for example, it can not list the directories because they are
19
+ # not readable the the regular user.
20
+ #
21
+ # It can have information like:
22
+ #
23
+ # id, vendor, device, irq, and kernel_driver
24
+ #
25
+ # An example of the returned sample from a test machine is:
26
+ # LinuxStat::PCI.devices_info
27
+ #
28
+ # => [{:id=>"8086:1904", :vendor=>"8086", :device=>"1904", :irq=>0, :kernel_driver=>"skl_uncore", :hwdata=>{:vendor=>"Intel Corporation", :product=>"Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers"}}]
29
+ #
30
+ # Right, it's an Array of Hashes.
31
+ #
32
+ # It also takes one option. The hwdata, which is true by default.
33
+ #
34
+ # Information about usb devices is found inside /usr/share/hwdata/pci.ids
35
+ #
36
+ # The data contains the vendor and the product, the subvendor and the subproduct.
37
+ #
38
+ # If the option is enabled, it will try read /usr/share/hwdata/pci.ids
39
+ #
40
+ # But the file will be read only once. The consecutive calls to this method
41
+ # won't open the hwdata all the times.
42
+ #
43
+ # But if there's no hwdata, the Hash returned by this method will not contain
44
+ # hwdata key.
45
+ #
46
+ # The data is only populated if it's available. For example, if there's no
47
+ # manufacturer available for the product, the returned Hash will not contain the
48
+ # information about the manufacturer.
49
+ #
50
+ # Also note that if there's no info available or no PCI enabled devices, it will return an empty
51
+ # Hash.
52
+ def devices_info(hwdata: true)
53
+ @@proc_pci_readable ||= File.readable?('/proc/bus/pci/devices')
54
+ return {} unless @@proc_pci_readable
55
+
56
+ IO.readlines('/proc/bus/pci/devices'.freeze).map! { |dev|
57
+ x = dev.split
58
+
59
+ vendor = x[1][0..3]
60
+ device = x[1][4..-1]
61
+ irq = x[2].to_i(16)
62
+ kernel_driver = x[-1]
63
+
64
+ query = if hwdata
65
+ query_hwdata(vendor, device)
66
+ else
67
+ {}
68
+ end
69
+
70
+ ret = {
71
+ id: "#{vendor}:#{device}",
72
+ vendor: vendor, device: device,
73
+ irq: irq,
74
+ kernel_driver: kernel_driver
75
+ }
76
+
77
+ ret.merge!(hwdata: query) unless query.empty?
78
+
79
+ ret
80
+ }
81
+ end
82
+
83
+ ##
84
+ # = devices_stat(hwdata: true)
85
+ #
86
+ # Returns details about the devices found in /sys/bus/pci/devices/
87
+ #
88
+ # The return value is an Array of multiple Hashes. If there's no info available,
89
+ # it will rather return an empty Array.
90
+ #
91
+ # On Android Termux for example, it can not list the directories because they are
92
+ # not readable the the regular user.
93
+ #
94
+ # It can have information like:
95
+ #
96
+ # path, id, vendor, device, subvendor, sub_device,
97
+ # kernel_driver, revision, irq, enable, hwdata.
98
+ #
99
+ # An example of the returned sample from a test machine is:
100
+ # LinuxStat::PCI.devices_stat
101
+ #
102
+ # => [{:path=>"/sys/bus/pci/devices/0000:00:00.0/", :id=>"8086:1904", :vendor=>"8086", :device=>"1904", :sub_vendor=>"1028", :sub_device=>"077d", :kernel_driver=>"skl_uncore", :revision=>"0x08", :irq=>0, :enable=>false, :hwdata=>{:vendor=>"Intel Corporation", :product=>"Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers", :sub_system=>nil}}]
103
+ #
104
+ # Right, it's an Array of Hashes.
105
+ #
106
+ # It also takes one option. The hwdata, which is true by default.
107
+ #
108
+ # Information about usb devices is found inside /usr/share/hwdata/pci.ids
109
+ #
110
+ # The data contains the vendor and the product, the subvendor and the subproduct.
111
+ #
112
+ # If the option is enabled, it will try read /usr/share/hwdata/pci.ids
113
+ #
114
+ # But the file will be read only once. The consecutive calls to this method
115
+ # won't open the hwdata all the times.
116
+ #
117
+ # But if there's no hwdata, the Hash returned by this method will not contain
118
+ # hwdata key.
119
+ #
120
+ # The data is only populated if it's available. For example, if there's no
121
+ # manufacturer available for the product, the returned Hash will not contain the
122
+ # information about the manufacturer.
123
+ #
124
+ # If there's no /sys/bus/pci/devices/, it will call LinuxStat::PCI.devices_info
125
+ #
126
+ # Also note that if there's no info available or no PCI enabled devices, it will return an empty
127
+ # Hash.
128
+ def devices_stat(hwdata: true)
129
+ @@sys_pci_readable ||= File.readable?('/sys/bus/pci/devices/')
130
+ return devices_info(hwdata: hwdata) unless @@sys_pci_readable
131
+
132
+ Dir['/sys/bus/pci/devices/*/'.freeze].sort!.map! { |x|
133
+ _vendor_file = File.join(x, 'vendor'.freeze)
134
+ next unless File.readable?(_vendor_file)
135
+ vendor = IO.read(_vendor_file).to_i(16).to_s(16)
136
+ prepend_0(vendor)
137
+
138
+ _device_file = File.join(x, 'device'.freeze)
139
+ next unless File.readable?(_device_file)
140
+ device = IO.read(_device_file).to_i(16).to_s(16)
141
+ prepend_0(device)
142
+
143
+ _sub_vendor_file = File.join(x, 'subsystem_vendor'.freeze)
144
+ sub_vendor = File.readable?(_sub_vendor_file) ? IO.read(_sub_vendor_file).to_i(16).to_s(16) : nil
145
+ prepend_0(sub_vendor) if sub_vendor
146
+
147
+ _sub_device_file = File.join(x, 'subsystem_device'.freeze)
148
+ sub_device = File.readable?(_sub_device_file) ? IO.read(_sub_device_file).to_i(16).to_s(16) : nil
149
+ prepend_0(sub_device) if sub_device
150
+
151
+ _uevent = File.join(x, 'uevent'.freeze)
152
+ uevent = File.readable?(_uevent) ? IO.foreach(_uevent) : nil
153
+
154
+ kernel_driver = if uevent
155
+ uevent.find { |_x|
156
+ _x.split(?=.freeze)[0].to_s.tap(&:strip!) == 'DRIVER'.freeze
157
+ } &.split(?=) &.[](1) &.tap(&:strip!)
158
+ else
159
+ nil
160
+ end
161
+
162
+ _revision_file = File.join(x, 'revision'.freeze)
163
+ revision = File.readable?(_revision_file) ? IO.read(_revision_file).tap(&:strip!) : ''.freeze
164
+
165
+ _irq_file = File.join(x, 'irq'.freeze)
166
+ irq = File.readable?(_irq_file) ? IO.read(_irq_file).to_i : nil
167
+
168
+ _enable_file = File.join(x, 'enable'.freeze)
169
+ enable = File.readable?(_enable_file) ? IO.read(_enable_file).to_i == 1 : nil
170
+
171
+ query = if hwdata && sub_vendor && sub_device
172
+ query_hwdata(vendor, device, sub_vendor, sub_device)
173
+ elsif hwdata && sub_vendor
174
+ query_hwdata(vendor, device, sub_vendor)
175
+ elsif hwdata
176
+ query_hwdata(vendor, device)
177
+ else
178
+ {}
179
+ end
180
+
181
+ ret = {
182
+ path: x, id: "#{vendor}:#{device}",
183
+ vendor: vendor, device: device
184
+ }
185
+
186
+ ret.merge!(sub_vendor: sub_vendor) if sub_vendor
187
+ ret.merge!(sub_device: sub_device) if sub_device
188
+
189
+ ret.merge!(kernel_driver: kernel_driver) if kernel_driver
190
+ ret.merge!(revision: revision) unless revision.empty?
191
+ ret.merge!(irq: irq) if irq
192
+ ret.merge!(enable: enable) unless enable.nil?
193
+ ret.merge!(hwdata: query) unless query.empty?
194
+
195
+ ret
196
+ }
197
+ end
198
+
199
+ ##
200
+ # Reads /proc/bus/pci/devices, counts and returns the total number of lines.
201
+ #
202
+ # But if the information isn't available, it will look into the contents of
203
+ # /sys/bus/pci/devices, and counts the total number of
204
+ # devices connected to the PCI.
205
+ # It checks for devices with vendor and device id files.
206
+ # If there's no such file, it will not count them as a PCI connected device.
207
+ #
208
+ # The return type is an integer.
209
+ #
210
+ # But if the information isn't available, it will return nil.
211
+ def count
212
+ @@proc_pci_readable ||= File.readable?('/proc/bus/pci/devices')
213
+ @@sys_pci_readable ||= File.readable?('/sys/bus/pci/devices/')
214
+
215
+ if @@proc_pci_readable
216
+ IO.readlines('/proc/bus/pci/devices'.freeze).length
217
+
218
+ elsif @@sys_pci_readable
219
+ Dir['/sys/bus/pci/devices/*/'.freeze].count { |x|
220
+ id_vendor_file = File.join(x, 'vendor'.freeze)
221
+ id_product_file = File.join(x, 'device'.freeze)
222
+ File.readable?(id_vendor_file) && File.readable?(id_product_file)
223
+ }
224
+
225
+ else
226
+ nil
227
+ end
228
+ end
229
+
230
+ alias count_devices count
231
+
232
+ private
233
+ def hwdata
234
+ @@hwdata_file ||= "/usr/share/hwdata/pci.ids"
235
+
236
+ @@hwdata ||= if File.readable?(@@hwdata_file)
237
+ ret, vendor_id, device_id, device = {}, nil, nil, nil
238
+ i = -1
239
+
240
+ file_data = IO.readlines(@@hwdata_file, encoding: 'ASCII-8BIT')
241
+ file_data_size = file_data.size
242
+
243
+ while (i += 1) < file_data_size
244
+ x = file_data[i]
245
+
246
+ _lstripped = x.lstrip
247
+ next if _lstripped[0] == ?#.freeze || _lstripped.empty?
248
+
249
+ if x[0..1] == "\t\t".freeze
250
+ next unless device_id
251
+
252
+ x.strip!
253
+ sub_device_id = x[/\A.*?\s/].to_s.strip
254
+ sub_device = x[device_id.length..-1].to_s.strip
255
+
256
+ if ret[vendor_id] &.at(1) &.[](device_id) &.[](1)
257
+ sub_system_id = sub_device[/\A.*?\s/].to_s.strip
258
+ sub_system_device = sub_device[sub_system_id.length..-1].to_s.strip
259
+
260
+ ret[vendor_id][1][device_id][1].merge!(sub_device_id => {sub_system_id => sub_system_device})
261
+ end
262
+
263
+ elsif x[0] == ?\t.freeze
264
+ next unless vendor_id
265
+
266
+ x.strip!
267
+ device_id = x[/\A.*?\s/].to_s.strip
268
+ device = x[device_id.length..-1].to_s.strip
269
+ ret[vendor_id][1][device_id] = [device, {}]
270
+
271
+ else
272
+ x.strip!
273
+ vendor_id = x[/\A.*?\s/].to_s.strip
274
+ vendor = x[vendor_id.length..-1].to_s.strip
275
+ ret[vendor_id] = [vendor, {}]
276
+ end
277
+ end
278
+
279
+ ret.freeze
280
+ else
281
+ {}
282
+ end
283
+ end
284
+
285
+ def prepend_0(n)
286
+ n[0, 0] = ?0.*(4 - n.length).freeze if n.length < 4
287
+ n
288
+ end
289
+
290
+ def query_hwdata(vendor_id, product_id, sub_vendor_id = nil, sub_device_id = nil)
291
+ vendor = hwdata[vendor_id]
292
+
293
+ if vendor
294
+ ret = {
295
+ vendor: vendor[0],
296
+ product: vendor.dig(1, product_id, 0),
297
+ }
298
+
299
+ if sub_vendor_id && sub_device_id
300
+ sub_product = vendor.dig(1, product_id, 1, sub_vendor_id, sub_device_id)
301
+ ret.merge!(sub_system: sub_product) if sub_product
302
+ end
303
+
304
+ ret
305
+ else
306
+ {}
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end